1 /*
2 * Copyright (c) 2009, 2022, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package jdk.vm.ci.meta;
24
25 import java.lang.annotation.Annotation;
26 import java.lang.reflect.AnnotatedElement;
27 import java.lang.reflect.Array;
28 import java.lang.reflect.Method;
29 import java.lang.reflect.Modifier;
30 import java.lang.reflect.Type;
31
32 /**
33 * Represents a resolved Java method. Methods, like fields and types, are resolved through
34 * {@link ConstantPool constant pools}.
35 */
36 public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersProvider, AnnotatedElement, Annotated {
37
38 /**
39 * Returns the method's bytecode. The returned bytecode does not contain breakpoints or non-Java
40 * bytecodes. This will return {@code null} if {@link #getCodeSize()} returns {@code <= 0} or if
41 * {@link #hasBytecodes()} returns {@code false}.
42 *
43 * The contained constant pool indexes may not be the ones found in the original class file but
44 * they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}).
45 *
46 * @return {@code null} if {@code getLinkedCodeSize() <= 0} otherwise the bytecode of the method
47 * whose length is guaranteed to be {@code > 0}
48 */
49 byte[] getCode();
50
51 /**
52 * Returns the size of the method's bytecode. If this method returns a value {@code > 0} then
53 * {@link #getCode()} will not return {@code null}.
54 *
55 * @return 0 if the method has no bytecode, {@code -1} if the method does have bytecode but its
56 * {@linkplain #getDeclaringClass() declaring class} is not
57 * {@linkplain ResolvedJavaType#isLinked() linked} otherwise the size of the bytecode in
58 * bytes (guaranteed to be {@code > 0})
59 */
60 int getCodeSize();
61
62 /**
63 * Returns the {@link ResolvedJavaType} object representing the class or interface that declares
64 * this method.
65 */
66 @Override
67 ResolvedJavaType getDeclaringClass();
68
69 /**
70 * Returns the maximum number of locals used in this method's bytecodes.
71 */
72 int getMaxLocals();
73
74 /**
75 * Returns the maximum number of stack slots used in this method's bytecodes.
76 */
77 int getMaxStackSize();
78
79 default boolean isFinal() {
80 return ModifiersProvider.super.isFinalFlagSet();
81 }
82
83 /**
84 * Determines if this method is a synthetic method as defined by the Java Language
85 * Specification.
86 */
87 boolean isSynthetic();
88
89 /**
90 * Checks if the method is a varargs method.
91 *
92 * @return whether the method is a varargs method
93 * @jvms 4.6
94 */
95 boolean isVarArgs();
96
97 /**
98 * Checks if the method is a bridge method.
99 *
100 * @return whether the method is a bridge method
101 * @jvms 4.6
102 */
103 boolean isBridge();
104
105 /**
106 * Returns {@code true} if this method is a default method; returns {@code false} otherwise.
107 *
108 * A default method is a public non-abstract instance method, that is, a non-static method with
109 * a body, declared in an interface type.
110 *
111 * @return true if and only if this method is a default method as defined by the Java Language
112 * Specification.
113 */
114 boolean isDefault();
115
116 /**
117 * Checks whether this method is a class initializer.
118 *
119 * @return {@code true} if the method is a class initializer
120 */
121 boolean isClassInitializer();
122
123 /**
124 * Checks whether this method is a constructor.
125 *
126 * @return {@code true} if the method is a constructor
127 */
128 boolean isConstructor();
129
130 /**
131 * Checks whether this method can be statically bound (usually, that means it is final or
132 * private or static, but not abstract, or the declaring class is final).
133 *
134 * @return {@code true} if this method can be statically bound
135 */
136 boolean canBeStaticallyBound();
137
138 /**
139 * Returns the list of exception handlers for this method.
140 */
141 ExceptionHandler[] getExceptionHandlers();
142
143 /**
144 * Returns a stack trace element for this method and a given bytecode index.
145 */
146 StackTraceElement asStackTraceElement(int bci);
147
148 /**
149 * Returns an object that provides access to the profiling information recorded for this method.
150 */
151 default ProfilingInfo getProfilingInfo() {
152 return getProfilingInfo(true, true);
153 }
154
155 /**
156 * Returns an object that provides access to the profiling information recorded for this method.
157 *
158 * @param includeNormal if true,
159 * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason)
160 * deoptimization counts} will include deoptimization that happened during execution
161 * of standard non-osr methods.
162 * @param includeOSR if true,
163 * {@linkplain ProfilingInfo#getDeoptimizationCount(DeoptimizationReason)
164 * deoptimization counts} will include deoptimization that happened during execution
165 * of on-stack-replacement methods.
166 */
167 ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR);
168
169 /**
170 * Invalidates the profiling information and restarts profiling upon the next invocation.
171 */
172 void reprofile();
173
174 /**
175 * Returns the constant pool of this method.
176 */
177 ConstantPool getConstantPool();
178
179 /**
180 * A {@code Parameter} provides information about method parameters.
181 */
182 class Parameter implements AnnotatedElement {
183 private final String name;
184 private final ResolvedJavaMethod method;
185 private final int modifiers;
186 private final int index;
187
188 /**
189 * Constructor for {@code Parameter}.
190 *
191 * @param name the name of the parameter or {@code null} if there is no
192 * {@literal MethodParameters} class file attribute providing a non-empty name
193 * for the parameter
194 * @param modifiers the modifier flags for the parameter
195 * @param method the method which defines this parameter
196 * @param index the index of the parameter
197 */
198 public Parameter(String name,
199 int modifiers,
200 ResolvedJavaMethod method,
201 int index) {
202 assert name == null || !name.isEmpty();
203 this.name = name;
204 this.modifiers = modifiers;
205 this.method = method;
206 this.index = index;
207 }
208
209 /**
210 * Gets the name of the parameter. If the parameter's name is {@linkplain #isNamePresent()
211 * present}, then this method returns the name provided by the class file. Otherwise, this
212 * method synthesizes a name of the form argN, where N is the index of the parameter in the
213 * descriptor of the method which declares the parameter.
214 *
215 * @return the name of the parameter, either provided by the class file or synthesized if
216 * the class file does not provide a name
217 */
218 public String getName() {
219 if (name == null) {
220 return "arg" + index;
221 } else {
222 return name;
223 }
224 }
225
226 /**
227 * Gets the method declaring the parameter.
228 */
229 public ResolvedJavaMethod getDeclaringMethod() {
230 return method;
231 }
232
233 /**
234 * Get the modifier flags for the parameter.
235 */
236 public int getModifiers() {
237 return modifiers;
238 }
239
240 /**
241 * Gets the kind of the parameter.
242 */
243 public JavaKind getKind() {
244 return method.getSignature().getParameterKind(index);
245 }
246
247 /**
248 * Gets the formal type of the parameter.
249 */
250 public Type getParameterizedType() {
251 return method.getGenericParameterTypes()[index];
252 }
253
254 /**
255 * Gets the type of the parameter.
256 */
257 public JavaType getType() {
258 return method.getSignature().getParameterType(index, method.getDeclaringClass());
259 }
260
261 /**
262 * Determines if the parameter has a name according to a {@literal MethodParameters} class
263 * file attribute.
264 *
265 * @return true if and only if the parameter has a name according to the class file.
266 */
267 public boolean isNamePresent() {
268 return name != null;
269 }
270
271 /**
272 * Determines if the parameter represents a variable argument list.
273 */
274 public boolean isVarArgs() {
275 return method.isVarArgs() && index == method.getSignature().getParameterCount(false) - 1;
276 }
277
278 @Override
279 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
280 return method.getParameterAnnotations(annotationClass)[index];
281 }
282
283 @Override
284 public Annotation[] getAnnotations() {
285 return method.getParameterAnnotations()[index];
286 }
287
288 @Override
289 public Annotation[] getDeclaredAnnotations() {
290 return getAnnotations();
291 }
292
293 @Override
294 public String toString() {
295 Type type = getParameterizedType();
296 String typename = type.getTypeName();
297 if (isVarArgs()) {
298 typename = typename.replaceFirst("\\[\\]$", "...");
299 }
300
301 final StringBuilder sb = new StringBuilder(Modifier.toString(getModifiers()));
302 if (sb.length() != 0) {
303 sb.append(' ');
304 }
305 return sb.append(typename).append(' ').append(getName()).toString();
306 }
307
308 @Override
309 public boolean equals(Object obj) {
310 if (obj instanceof Parameter) {
311 Parameter other = (Parameter) obj;
312 return (other.method.equals(method) && other.index == index);
313 }
314 return false;
315 }
316
317 @Override
318 public int hashCode() {
319 return method.hashCode() ^ index;
320 }
321 }
322
323 /**
324 * Returns an array of {@code Parameter} objects that represent all the parameters to this
325 * method. Returns an array of length 0 if this method has no parameters. Returns {@code null}
326 * if the parameter information is unavailable.
327 */
328 default Parameter[] getParameters() {
329 return null;
330 }
331
332 /**
333 * Returns an array of arrays that represent the annotations on the formal parameters, in
334 * declaration order, of this method.
335 *
336 * @see Method#getParameterAnnotations()
337 */
338 Annotation[][] getParameterAnnotations();
339
340 /**
341 * Returns an array of {@link Type} objects that represent the formal parameter types, in
342 * declaration order, of this method.
343 *
344 * @see Method#getGenericParameterTypes()
345 */
346 Type[] getGenericParameterTypes();
347
348 /**
349 * Returns {@code true} if this method is not excluded from inlining and has associated Java
350 * bytecodes (@see {@link ResolvedJavaMethod#hasBytecodes()}).
351 */
352 boolean canBeInlined();
353
354 /**
355 * Determines if this method is targeted by a VM directive (e.g.,
356 * {@code -XX:CompileCommand=dontinline,<pattern>}) or VM recognized annotation (e.g.,
357 * {@code jdk.internal.vm.annotation.DontInline}) that specifies it should not be inlined.
358 */
359 boolean hasNeverInlineDirective();
360
361 /**
362 * Returns {@code true} if the inlining of this method should be forced.
363 */
364 boolean shouldBeInlined();
365
366 /**
367 * Returns the LineNumberTable of this method or null if this method does not have a line
368 * numbers table.
369 */
370 LineNumberTable getLineNumberTable();
371
372 /**
373 * Returns the local variable table of this method or null if this method does not have a local
374 * variable table.
375 */
376 LocalVariableTable getLocalVariableTable();
377
378 /**
379 * Gets the encoding of (that is, a constant representing the value of) this method.
380 *
381 * @return a constant representing a reference to this method
382 */
383 Constant getEncoding();
384
385 /**
386 * Checks if this method is present in the virtual table for subtypes of the specified
387 * {@linkplain ResolvedJavaType type}.
388 *
389 * @return true is this method is present in the virtual table for subtypes of this type.
390 */
391 boolean isInVirtualMethodTable(ResolvedJavaType resolved);
392
393 /**
394 * Gets the annotation of a particular type for a formal parameter of this method.
395 *
396 * @param annotationClass the Class object corresponding to the annotation type
397 * @param parameterIndex the index of a formal parameter of {@code method}
398 * @return the annotation of type {@code annotationClass} for the formal parameter present, else
399 * null
400 * @throws IndexOutOfBoundsException if {@code parameterIndex} does not denote a formal
401 * parameter
402 */
403 default <T extends Annotation> T getParameterAnnotation(Class<T> annotationClass, int parameterIndex) {
404 if (parameterIndex >= 0) {
405 Annotation[][] parameterAnnotations = getParameterAnnotations();
406 for (Annotation a : parameterAnnotations[parameterIndex]) {
407 if (a.annotationType() == annotationClass) {
408 return annotationClass.cast(a);
409 }
410 }
411 }
412 return null;
413 }
414
415 default JavaType[] toParameterTypes() {
416 JavaType receiver = isStatic() || isConstructor() ? null : getDeclaringClass();
417 return getSignature().toParameterTypes(receiver);
418 }
419
420 /**
421 * Gets the annotations of a particular type for the formal parameters of this method.
422 *
423 * @param annotationClass the Class object corresponding to the annotation type
424 * @return the annotation of type {@code annotationClass} (if any) for each formal parameter
425 * present
426 */
427 @SuppressWarnings("unchecked")
428 default <T extends Annotation> T[] getParameterAnnotations(Class<T> annotationClass) {
429 Annotation[][] parameterAnnotations = getParameterAnnotations();
430 T[] result = (T[]) Array.newInstance(annotationClass, parameterAnnotations.length);
431 for (int i = 0; i < parameterAnnotations.length; i++) {
432 for (Annotation a : parameterAnnotations[i]) {
433 if (a.annotationType() == annotationClass) {
434 result[i] = annotationClass.cast(a);
435 }
436 }
437 }
438 return result;
439 }
440
441 /**
442 * @see #getCodeSize()
443 * @return {@code getCodeSize() > 0}
444 */
445 default boolean hasBytecodes() {
446 return getCodeSize() > 0;
447 }
448
449 /**
450 * Checks whether the method has a receiver parameter - i.e., whether it is not static.
451 *
452 * @return whether the method has a receiver parameter
453 */
454 default boolean hasReceiver() {
455 return !isStatic();
456 }
457
458 /**
459 * Determines if this method is {@link java.lang.Object#Object()}.
460 */
461 default boolean isJavaLangObjectInit() {
462 return getDeclaringClass().isJavaLangObject() && (getName().equals("<init>") || getName().equals("<vnew>"));
463 }
464
465 /**
466 * Gets a speculation log that can be used when compiling this method to make new speculations
467 * and query previously failed speculations. The implementation may return a new
468 * {@link SpeculationLog} object each time this method is called so its the caller's
469 * responsibility to ensure the same speculation log is used throughout a compilation.
470 */
471 SpeculationLog getSpeculationLog();
472 }
--- EOF ---