1 /* 2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.tools.jdi; 27 28 import com.sun.jdi.*; 29 30 import java.util.List; 31 import java.util.Iterator; 32 import java.util.ArrayList; 33 import java.util.Comparator; 34 35 public abstract class MethodImpl extends TypeComponentImpl 36 implements Method { 37 private JNITypeParser signatureParser; argSlotCount()38 abstract int argSlotCount() throws AbsentInformationException; 39 allLineLocations(SDE.Stratum stratum, String sourceName)40 abstract List<Location> allLineLocations(SDE.Stratum stratum, 41 String sourceName) 42 throws AbsentInformationException; 43 locationsOfLine(SDE.Stratum stratum, String sourceName, int lineNumber)44 abstract List<Location> locationsOfLine(SDE.Stratum stratum, 45 String sourceName, 46 int lineNumber) 47 throws AbsentInformationException; 48 MethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType, long ref, String name, String signature, String genericSignature, int modifiers)49 MethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType, 50 long ref, 51 String name, String signature, 52 String genericSignature, int modifiers) { 53 super(vm, declaringType, ref, name, signature, 54 genericSignature, modifiers); 55 signatureParser = new JNITypeParser(signature); 56 } 57 createMethodImpl(VirtualMachine vm, ReferenceTypeImpl declaringType, long ref, String name, String signature, String genericSignature, int modifiers)58 static MethodImpl createMethodImpl(VirtualMachine vm, 59 ReferenceTypeImpl declaringType, 60 long ref, 61 String name, 62 String signature, 63 String genericSignature, 64 int modifiers) { 65 if ((modifiers & 66 (VMModifiers.NATIVE | VMModifiers.ABSTRACT)) != 0) { 67 return new NonConcreteMethodImpl(vm, declaringType, ref, 68 name, signature, 69 genericSignature, 70 modifiers); 71 } else { 72 return new ConcreteMethodImpl(vm, declaringType, ref, 73 name, signature, 74 genericSignature, 75 modifiers); 76 } 77 } 78 equals(Object obj)79 public boolean equals(Object obj) { 80 if ((obj != null) && (obj instanceof MethodImpl)) { 81 MethodImpl other = (MethodImpl)obj; 82 return (declaringType().equals(other.declaringType())) && 83 (ref() == other.ref()) && 84 super.equals(obj); 85 } else { 86 return false; 87 } 88 } 89 hashCode()90 public int hashCode() { 91 return (int)ref(); 92 } 93 allLineLocations()94 public final List<Location> allLineLocations() 95 throws AbsentInformationException { 96 return allLineLocations(vm.getDefaultStratum(), null); 97 } 98 allLineLocations(String stratumID, String sourceName)99 public List<Location> allLineLocations(String stratumID, 100 String sourceName) 101 throws AbsentInformationException { 102 return allLineLocations(declaringType.stratum(stratumID), 103 sourceName); 104 } 105 locationsOfLine(int lineNumber)106 public final List<Location> locationsOfLine(int lineNumber) 107 throws AbsentInformationException { 108 return locationsOfLine(vm.getDefaultStratum(), 109 null, lineNumber); 110 } 111 locationsOfLine(String stratumID, String sourceName, int lineNumber)112 public List<Location> locationsOfLine(String stratumID, 113 String sourceName, 114 int lineNumber) 115 throws AbsentInformationException { 116 return locationsOfLine(declaringType.stratum(stratumID), 117 sourceName, lineNumber); 118 } 119 codeIndexToLineInfo(SDE.Stratum stratum, long codeIndex)120 LineInfo codeIndexToLineInfo(SDE.Stratum stratum, 121 long codeIndex) { 122 if (stratum.isJava()) { 123 return new BaseLineInfo(-1, declaringType); 124 } else { 125 return new StratumLineInfo(stratum.id(), -1, 126 null, null); 127 } 128 } 129 130 /** 131 * @return a text representation of the declared return type 132 * of this method. 133 */ returnTypeName()134 public String returnTypeName() { 135 return signatureParser.typeName(); 136 } 137 returnSignature()138 private String returnSignature() { 139 return signatureParser.signature(); 140 } 141 returnType()142 public Type returnType() throws ClassNotLoadedException { 143 return findType(returnSignature()); 144 } 145 findType(String signature)146 public Type findType(String signature) throws ClassNotLoadedException { 147 ReferenceTypeImpl enclosing = (ReferenceTypeImpl)declaringType(); 148 return enclosing.findType(signature); 149 } 150 argumentTypeNames()151 public List<String> argumentTypeNames() { 152 return signatureParser.argumentTypeNames(); 153 } 154 argumentSignatures()155 public List<String> argumentSignatures() { 156 return signatureParser.argumentSignatures(); 157 } 158 argumentType(int index)159 Type argumentType(int index) throws ClassNotLoadedException { 160 ReferenceTypeImpl enclosing = (ReferenceTypeImpl)declaringType(); 161 String signature = argumentSignatures().get(index); 162 return enclosing.findType(signature); 163 } 164 argumentTypes()165 public List<Type> argumentTypes() throws ClassNotLoadedException { 166 int size = argumentSignatures().size(); 167 ArrayList<Type> types = new ArrayList<Type>(size); 168 for (int i = 0; i < size; i++) { 169 Type type = argumentType(i); 170 types.add(type); 171 } 172 173 return types; 174 } 175 compareTo(Method method)176 public int compareTo(Method method) { 177 ReferenceTypeImpl declaringType = (ReferenceTypeImpl)declaringType(); 178 int rc = declaringType.compareTo(method.declaringType()); 179 if (rc == 0) { 180 rc = declaringType.indexOf(this) - 181 declaringType.indexOf(method); 182 } 183 return rc; 184 } 185 isAbstract()186 public boolean isAbstract() { 187 return isModifierSet(VMModifiers.ABSTRACT); 188 } 189 isDefault()190 public boolean isDefault() { 191 return !isModifierSet(VMModifiers.ABSTRACT) && 192 !isModifierSet(VMModifiers.STATIC) && 193 !isModifierSet(VMModifiers.PRIVATE) && 194 declaringType() instanceof InterfaceType; 195 } 196 isSynchronized()197 public boolean isSynchronized() { 198 return isModifierSet(VMModifiers.SYNCHRONIZED); 199 } 200 isNative()201 public boolean isNative() { 202 return isModifierSet(VMModifiers.NATIVE); 203 } 204 isVarArgs()205 public boolean isVarArgs() { 206 return isModifierSet(VMModifiers.VARARGS); 207 } 208 isBridge()209 public boolean isBridge() { 210 return isModifierSet(VMModifiers.BRIDGE); 211 } 212 isConstructor()213 public boolean isConstructor() { 214 return name().equals("<init>"); 215 } 216 isStaticInitializer()217 public boolean isStaticInitializer() { 218 return name().equals("<clinit>"); 219 } 220 isObsolete()221 public boolean isObsolete() { 222 try { 223 return JDWP.Method.IsObsolete.process(vm, 224 declaringType, ref).isObsolete; 225 } catch (JDWPException exc) { 226 throw exc.toJDIException(); 227 } 228 } 229 230 231 /* 232 * A container class for the return value to allow 233 * proper type-checking. 234 */ 235 class ReturnContainer implements ValueContainer { ReturnContainer()236 ReturnContainer() { 237 } type()238 public Type type() throws ClassNotLoadedException { 239 return returnType(); 240 } typeName()241 public String typeName(){ 242 return returnTypeName(); 243 } signature()244 public String signature() { 245 return returnSignature(); //type().signature(); 246 } findType(String signature)247 public Type findType(String signature) throws ClassNotLoadedException { 248 return MethodImpl.this.findType(signature); 249 } 250 } 251 ReturnContainer retValContainer = null; getReturnValueContainer()252 ReturnContainer getReturnValueContainer() { 253 if (retValContainer == null) { 254 retValContainer = new ReturnContainer(); 255 } 256 return retValContainer; 257 } 258 259 /* 260 * A container class for the argument to allow 261 * proper type-checking. 262 */ 263 class ArgumentContainer implements ValueContainer { 264 int index; 265 ArgumentContainer(int index)266 ArgumentContainer(int index) { 267 this.index = index; 268 } type()269 public Type type() throws ClassNotLoadedException { 270 return argumentType(index); 271 } typeName()272 public String typeName(){ 273 return argumentTypeNames().get(index); 274 } signature()275 public String signature() { 276 return argumentSignatures().get(index); 277 } findType(String signature)278 public Type findType(String signature) throws ClassNotLoadedException { 279 return MethodImpl.this.findType(signature); 280 } 281 } 282 283 /* 284 * This is a var args method. Thus, its last param is an 285 * array. If the method has n params, then: 286 * 1. If there are n args and the last is the same type as the type of 287 * the last param, do nothing. IE, a String[] 288 * can be passed to a String... 289 * 2. If there are >= n arguments and for each arg whose number is >= n, 290 * the arg type is 'compatible' with the component type of 291 * the last param, then do 292 * - create an array of the type of the last param 293 * - put the n, ... args into this array. 294 * We might have to do conversions here. 295 * - put this array into arguments(n) 296 * - delete arguments(n+1), ... 297 * NOTE that this might modify the input list. 298 */ handleVarArgs(List<Value> arguments)299 void handleVarArgs(List<Value> arguments) 300 throws ClassNotLoadedException, InvalidTypeException { 301 List<Type> paramTypes = this.argumentTypes(); 302 ArrayType lastParamType = (ArrayType)paramTypes.get(paramTypes.size() - 1); 303 Type componentType = lastParamType.componentType(); 304 int argCount = arguments.size(); 305 int paramCount = paramTypes.size(); 306 if (argCount < paramCount - 1) { 307 // Error; will be caught later. 308 return; 309 } 310 if (argCount == paramCount - 1) { 311 // It is ok to pass 0 args to the var arg. 312 // We have to gen a 0 length array. 313 ArrayReference argArray = lastParamType.newInstance(0); 314 arguments.add(argArray); 315 return; 316 } 317 Value nthArgValue = arguments.get(paramCount - 1); 318 if (nthArgValue == null && argCount == paramCount) { 319 // We have one varargs parameter and it is null 320 // so we don't have to do anything. 321 return; 322 } 323 // If the first varargs parameter is null, then don't 324 // access its type since it can't be an array. 325 Type nthArgType = (nthArgValue == null) ? null : nthArgValue.type(); 326 if (nthArgType instanceof ArrayTypeImpl) { 327 if (argCount == paramCount && 328 ((ArrayTypeImpl)nthArgType).isAssignableTo(lastParamType)) { 329 /* 330 * This is case 1. A compatible array is being passed to the 331 * var args array param. We don't have to do anything. 332 */ 333 return; 334 } 335 } 336 337 /* 338 * Case 2. We have to verify that the n, n+1, ... args are compatible 339 * with componentType, and do conversions if necessary and create 340 * an array of componentType to hold these possibly converted values. 341 */ 342 int count = argCount - paramCount + 1; 343 ArrayReference argArray = lastParamType.newInstance(count); 344 345 /* 346 * This will copy arguments(paramCount - 1) ... to argArray(0) ... 347 * doing whatever conversions are needed! It will throw an 348 * exception if an incompatible arg is encountered 349 */ 350 argArray.setValues(0, arguments, paramCount - 1, count); 351 arguments.set(paramCount - 1, argArray); 352 353 /* 354 * Remove the excess args 355 */ 356 for (int ii = paramCount; ii < argCount; ii++) { 357 arguments.remove(paramCount); 358 } 359 return; 360 } 361 362 /* 363 * The output list will be different than the input list. 364 */ validateAndPrepareArgumentsForInvoke(List<? extends Value> origArguments)365 List<Value> validateAndPrepareArgumentsForInvoke(List<? extends Value> origArguments) 366 throws ClassNotLoadedException, InvalidTypeException { 367 368 List<Value> arguments = new ArrayList<Value>(origArguments); 369 if (isVarArgs()) { 370 handleVarArgs(arguments); 371 } 372 373 int argSize = arguments.size(); 374 375 JNITypeParser parser = new JNITypeParser(signature()); 376 List<String> signatures = parser.argumentSignatures(); 377 378 if (signatures.size() != argSize) { 379 throw new IllegalArgumentException("Invalid argument count: expected " + 380 signatures.size() + ", received " + 381 arguments.size()); 382 } 383 384 for (int i = 0; i < argSize; i++) { 385 Value value = arguments.get(i); 386 value = ValueImpl.prepareForAssignment(value, 387 new ArgumentContainer(i)); 388 arguments.set(i, value); 389 } 390 return arguments; 391 } 392 toString()393 public String toString() { 394 StringBuffer sb = new StringBuffer(); 395 sb.append(declaringType().name()); 396 sb.append("."); 397 sb.append(name()); 398 sb.append("("); 399 boolean first = true; 400 for (String name : argumentTypeNames()) { 401 if (!first) { 402 sb.append(", "); 403 } 404 sb.append(name); 405 first = false; 406 } 407 sb.append(")"); 408 return sb.toString(); 409 } 410 } 411