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