1 /* 2 * Copyright (c) 1998, 2011, 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; 38 abstract int argSlotCount() throws AbsentInformationException; 39 40 abstract List<Location> allLineLocations(SDE.Stratum stratum, 41 String sourceName) 42 throws AbsentInformationException; 43 44 abstract List<Location> locationsOfLine(SDE.Stratum stratum, 45 String sourceName, 46 int lineNumber) 47 throws AbsentInformationException; 48 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 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 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 90 public int hashCode() { 91 return (int)ref(); 92 } 93 94 public final List<Location> allLineLocations() 95 throws AbsentInformationException { 96 return allLineLocations(vm.getDefaultStratum(), null); 97 } 98 99 public List<Location> allLineLocations(String stratumID, 100 String sourceName) 101 throws AbsentInformationException { 102 return allLineLocations(declaringType.stratum(stratumID), 103 sourceName); 104 } 105 106 public final List<Location> locationsOfLine(int lineNumber) 107 throws AbsentInformationException { 108 return locationsOfLine(vm.getDefaultStratum(), 109 null, lineNumber); 110 } 111 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 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 */ 134 public String returnTypeName() { 135 return signatureParser.typeName(); 136 } 137 138 private String returnSignature() { 139 return signatureParser.signature(); 140 } 141 142 public Type returnType() throws ClassNotLoadedException { 143 return findType(returnSignature()); 144 } 145 146 public Type findType(String signature) throws ClassNotLoadedException { 147 ReferenceTypeImpl enclosing = (ReferenceTypeImpl)declaringType(); 148 return enclosing.findType(signature); 149 } 150 151 public List<String> argumentTypeNames() { 152 return signatureParser.argumentTypeNames(); 153 } 154 155 public List<String> argumentSignatures() { 156 return signatureParser.argumentSignatures(); 157 } 158 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 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 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 186 public boolean isAbstract() { 187 return isModifierSet(VMModifiers.ABSTRACT); 188 } 189 190 public boolean isDefault() { 191 return !isModifierSet(VMModifiers.ABSTRACT) && 192 !isModifierSet(VMModifiers.STATIC) && 193 !isModifierSet(VMModifiers.PRIVATE) && 194 declaringType() instanceof InterfaceType; 195 } 196 197 public boolean isSynchronized() { 198 return isModifierSet(VMModifiers.SYNCHRONIZED); 199 } 200 201 public boolean isNative() { 202 return isModifierSet(VMModifiers.NATIVE); 203 } 204 205 public boolean isVarArgs() { 206 return isModifierSet(VMModifiers.VARARGS); 207 } 208 209 public boolean isBridge() { 210 return isModifierSet(VMModifiers.BRIDGE); 211 } 212 213 public boolean isConstructor() { 214 return name().equals("<init>"); 215 } 216 217 public boolean isStaticInitializer() { 218 return name().equals("<clinit>"); 219 } 220 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 { 236 ReturnContainer() { 237 } 238 public Type type() throws ClassNotLoadedException { 239 return returnType(); 240 } 241 public String typeName(){ 242 return returnTypeName(); 243 } 244 public String signature() { 245 return returnSignature(); //type().signature(); 246 } 247 public Type findType(String signature) throws ClassNotLoadedException { 248 return MethodImpl.this.findType(signature); 249 } 250 } 251 ReturnContainer retValContainer = null; 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 266 ArgumentContainer(int index) { 267 this.index = index; 268 } 269 public Type type() throws ClassNotLoadedException { 270 return argumentType(index); 271 } 272 public String typeName(){ 273 return argumentTypeNames().get(index); 274 } 275 public String signature() { 276 return argumentSignatures().get(index); 277 } 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 */ 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) { 319 return; 320 } 321 Type nthArgType = nthArgValue.type(); 322 if (nthArgType instanceof ArrayTypeImpl) { 323 if (argCount == paramCount && 324 ((ArrayTypeImpl)nthArgType).isAssignableTo(lastParamType)) { 325 /* 326 * This is case 1. A compatible array is being passed to the 327 * var args array param. We don't have to do anything. 328 */ 329 return; 330 } 331 } 332 333 /* 334 * Case 2. We have to verify that the n, n+1, ... args are compatible 335 * with componentType, and do conversions if necessary and create 336 * an array of componentType to hold these possibly converted values. 337 */ 338 int count = argCount - paramCount + 1; 339 ArrayReference argArray = lastParamType.newInstance(count); 340 341 /* 342 * This will copy arguments(paramCount - 1) ... to argArray(0) ... 343 * doing whatever conversions are needed! It will throw an 344 * exception if an incompatible arg is encountered 345 */ 346 argArray.setValues(0, arguments, paramCount - 1, count); 347 arguments.set(paramCount - 1, argArray); 348 349 /* 350 * Remove the excess args 351 */ 352 for (int ii = paramCount; ii < argCount; ii++) { 353 arguments.remove(paramCount); 354 } 355 return; 356 } 357 358 /* 359 * The output list will be different than the input list. 360 */ 361 List<Value> validateAndPrepareArgumentsForInvoke(List<? extends Value> origArguments) 362 throws ClassNotLoadedException, InvalidTypeException { 363 364 List<Value> arguments = new ArrayList<Value>(origArguments); 365 if (isVarArgs()) { 366 handleVarArgs(arguments); 367 } 368 369 int argSize = arguments.size(); 370 371 JNITypeParser parser = new JNITypeParser(signature()); 372 List<String> signatures = parser.argumentSignatures(); 373 374 if (signatures.size() != argSize) { 375 throw new IllegalArgumentException("Invalid argument count: expected " + 376 signatures.size() + ", received " + 377 arguments.size()); 378 } 379 380 for (int i = 0; i < argSize; i++) { 381 Value value = arguments.get(i); 382 value = ValueImpl.prepareForAssignment(value, 383 new ArgumentContainer(i)); 384 arguments.set(i, value); 385 } 386 return arguments; 387 } 388 389 public String toString() { 390 StringBuilder sb = new StringBuilder(); 391 sb.append(declaringType().name()); 392 sb.append("."); 393 sb.append(name()); 394 sb.append("("); 395 boolean first = true; 396 for (String name : argumentTypeNames()) { 397 if (!first) { 398 sb.append(", "); 399 } 400 sb.append(name); 401 first = false; 402 } 403 sb.append(")"); 404 return sb.toString(); 405 } 406 }