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