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