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 that the method is a
  89      * <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6">varargs</a>
  90      * method.
  91      *
  92      * @return whether the method is a varargs method
  93      */
  94     boolean isVarArgs();
  95 
  96     /**
  97      * Checks that the method is a
  98      * <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.6">bridge</a>
  99      * method.
 100      *
 101      * @return whether the method is a bridge method
 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      * Checks whether the method has bytecodes associated with it. Note that even if this method
 443      * returns {@code true}, {@link #getCode} can return {@code null} if
 444      * {@linkplain #getDeclaringClass() declaring class} is not
 445      * {@linkplain ResolvedJavaType#isLinked() linked}.
 446      *
 447      * @return {@code this.getCodeSize() != 0}
 448      */
 449     default boolean hasBytecodes() {
 450         return getCodeSize() != 0;
 451     }
 452 
 453     /**
 454      * Checks whether the method has a receiver parameter - i.e., whether it is not static.
 455      *
 456      * @return whether the method has a receiver parameter
 457      */
 458     default boolean hasReceiver() {
 459         return !isStatic();
 460     }
 461 
 462     /**
 463      * Determines if this method is {@link java.lang.Object#Object()}.
 464      */
 465     default boolean isJavaLangObjectInit() {
 466         return getDeclaringClass().isJavaLangObject() && getName().equals("<init>");
 467     }
 468 
 469     /**
 470      * Gets a speculation log that can be used when compiling this method to make new speculations
 471      * and query previously failed speculations. The implementation may return a new
 472      * {@link SpeculationLog} object each time this method is called so its the caller's
 473      * responsibility to ensure the same speculation log is used throughout a compilation.
 474      */
 475     SpeculationLog getSpeculationLog();
 476 }