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