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 }