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 }
--- EOF ---