< prev index next >

src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java

Print this page


   1 /*
   2  * Copyright (c) 2011, 2014, 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.hotspot;
  24 
  25 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.*;
  26 import static jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl.Options.*;


  27 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
  28 
  29 import java.lang.annotation.*;
  30 import java.lang.reflect.*;
  31 import java.util.*;
  32 
  33 import jdk.vm.ci.common.*;
  34 import jdk.vm.ci.meta.*;
  35 import jdk.vm.ci.options.*;























  36 
  37 /**
  38  * Implementation of {@link JavaMethod} for resolved HotSpot methods.
  39  */
  40 public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MetaspaceWrapperObject {
  41 
  42     public static class Options {
  43         // @formatter:off
  44         @Option(help = "", type = OptionType.Debug)
  45         public static final OptionValue<Boolean> UseProfilingInformation = new OptionValue<>(true);
  46         // @formatter:on
  47     }
  48 
  49     /**
  50      * Reference to metaspace Method object.
  51      */
  52     private final long metaspaceMethod;
  53 
  54     private final HotSpotResolvedObjectTypeImpl holder;
  55     private final HotSpotConstantPool constantPool;
  56     private final HotSpotSignature signature;
  57     private HotSpotMethodData methodData;
  58     private byte[] code;
  59     private Member toJavaCache;
  60 
  61     /**
  62      * Gets the holder of a HotSpot metaspace method native object.
  63      *
  64      * @param metaspaceMethod a metaspace Method object
  65      * @return the {@link ResolvedJavaType} corresponding to the holder of the
  66      *         {@code metaspaceMethod}
  67      */
  68     private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) {
  69         HotSpotVMConfig config = runtime().getConfig();
  70         final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset);
  71         final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset);
  72         return runtime().getCompilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false);
  73     }
  74 
  75     /**
  76      * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the
  77      * Method* is kept alive for the duration of this call and the
  78      * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that.
  79      *
  80      * Called from the VM.
  81      *
  82      * @param metaspaceMethod a metaspace Method object
  83      * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod}
  84      */
  85     @SuppressWarnings("unused")
  86     private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) {
  87         HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod);
  88         return holder.createMethod(metaspaceMethod);
  89     }
  90 
  91     HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) {
  92         // It would be too much work to get the method name here so we fill it in later.
  93         super(null);
  94         this.metaspaceMethod = metaspaceMethod;
  95         this.holder = holder;
  96 
  97         HotSpotVMConfig config = runtime().getConfig();
  98         final long constMethod = getConstMethod();
  99 
 100         /*
 101          * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for
 102          * signature-polymorphic method handle methods) have their own constant pool instead of the
 103          * one from their holder.
 104          */
 105         final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset);
 106         if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) {
 107             this.constantPool = holder.getConstantPool();
 108         } else {
 109             this.constantPool = runtime().getCompilerToVM().getConstantPool(null, constMethod + config.constMethodConstantsOffset);
 110         }
 111 
 112         final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset);
 113         this.name = constantPool.lookupUtf8(nameIndex);
 114 
 115         final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset);
 116         this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex);
 117     }
 118 
 119     /**
 120      * Returns a pointer to this method's constant method data structure (
 121      * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it
 122      * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod*
 123      * are kept alive as a pair.
 124      *
 125      * @return pointer to this method's ConstMethod
 126      */
 127     private long getConstMethod() {
 128         assert metaspaceMethod != 0;
 129         return UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodConstMethodOffset);
 130     }
 131 
 132     @Override
 133     public boolean equals(Object obj) {
 134         if (this == obj) {
 135             return true;
 136         }
 137         if (obj instanceof HotSpotResolvedJavaMethodImpl) {
 138             HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj;
 139             return that.metaspaceMethod == metaspaceMethod;
 140         }
 141         return false;
 142     }
 143 
 144     @Override
 145     public int hashCode() {
 146         return (int) metaspaceMethod;
 147     }
 148 
 149     /**
 150      * Returns this method's flags ({@code Method::_flags}).
 151      *
 152      * @return flags of this method
 153      */
 154     private int getFlags() {
 155         return UNSAFE.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset);
 156     }
 157 
 158     /**
 159      * Returns this method's constant method flags ({@code ConstMethod::_flags}).
 160      *
 161      * @return flags of this method's ConstMethod
 162      */
 163     private int getConstMethodFlags() {
 164         return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset);
 165     }
 166 
 167     @Override
 168     public HotSpotResolvedObjectTypeImpl getDeclaringClass() {
 169         return holder;
 170     }
 171 
 172     /**
 173      * Gets the address of the C++ Method object for this method.
 174      */
 175     public JavaConstant getMetaspaceMethodConstant() {
 176         return HotSpotMetaspaceConstantImpl.forMetaspaceObject(getHostWordKind(), metaspaceMethod, this, false);
 177     }
 178 
 179     public long getMetaspaceMethod() {
 180         return metaspaceMethod;
 181     }
 182 
 183     public long getMetaspacePointer() {
 184         return getMetaspaceMethod();
 185     }
 186 
 187     @Override
 188     public JavaConstant getEncoding() {
 189         return getMetaspaceMethodConstant();
 190     }
 191 
 192     /**
 193      * Gets the complete set of modifiers for this method which includes the JVM specification
 194      * modifiers as well as the HotSpot internal modifiers.
 195      */
 196     public int getAllModifiers() {
 197         return UNSAFE.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset);
 198     }
 199 
 200     @Override
 201     public int getModifiers() {
 202         return getAllModifiers() & ModifiersProvider.jvmMethodModifiers();
 203     }
 204 
 205     @Override
 206     public boolean canBeStaticallyBound() {
 207         return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete();
 208     }
 209 
 210     @Override
 211     public byte[] getCode() {
 212         if (getCodeSize() == 0) {
 213             return null;
 214         }
 215         if (code == null && holder.isLinked()) {
 216             code = runtime().getCompilerToVM().getBytecode(this);
 217             assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length;
 218         }
 219         return code;
 220     }
 221 
 222     @Override
 223     public int getCodeSize() {
 224         return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodCodeSizeOffset);
 225     }
 226 
 227     @Override
 228     public ExceptionHandler[] getExceptionHandlers() {
 229         final boolean hasExceptionTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasExceptionTable) != 0;
 230         if (!hasExceptionTable) {
 231             return new ExceptionHandler[0];
 232         }
 233 
 234         HotSpotVMConfig config = runtime().getConfig();
 235         final int exceptionTableLength = runtime().getCompilerToVM().getExceptionTableLength(this);
 236         ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength];
 237         long exceptionTableElement = runtime().getCompilerToVM().getExceptionTableStart(this);
 238 
 239         for (int i = 0; i < exceptionTableLength; i++) {
 240             final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset);
 241             final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset);
 242             final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset);
 243             int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset);
 244 
 245             JavaType catchType;
 246             if (catchTypeIndex == 0) {
 247                 catchType = null;
 248             } else {
 249                 final int opcode = -1;  // opcode is not used
 250                 catchType = constantPool.lookupType(catchTypeIndex, opcode);
 251 
 252                 // Check for Throwable which catches everything.
 253                 if (catchType instanceof HotSpotResolvedObjectTypeImpl) {
 254                     HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType;
 255                     if (resolvedType.mirror() == Throwable.class) {
 256                         catchTypeIndex = 0;
 257                         catchType = null;
 258                     }
 259                 }
 260             }
 261             handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType);
 262 
 263             // Go to the next ExceptionTableElement
 264             exceptionTableElement += config.exceptionTableElementSize;
 265         }
 266 
 267         return handlers;
 268     }
 269 
 270     /**
 271      * Returns true if this method has a {@code CallerSensitive} annotation.
 272      *
 273      * @return true if CallerSensitive annotation present, false otherwise
 274      */
 275     public boolean isCallerSensitive() {
 276         return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0;
 277     }
 278 
 279     /**
 280      * Returns true if this method has a {@code ForceInline} annotation.
 281      *
 282      * @return true if ForceInline annotation present, false otherwise
 283      */
 284     public boolean isForceInline() {
 285         return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0;
 286     }
 287 
 288     /**
 289      * Returns true if this method has a {@code DontInline} annotation.
 290      *
 291      * @return true if DontInline annotation present, false otherwise
 292      */
 293     public boolean isDontInline() {
 294         return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0;
 295     }
 296 
 297     /**
 298      * Manually adds a DontInline annotation to this method.
 299      */
 300     public void setNotInlineable() {
 301         runtime().getCompilerToVM().doNotInlineOrCompile(this);
 302     }
 303 
 304     /**
 305      * Returns true if this method is one of the special methods that is ignored by security stack
 306      * walks.
 307      *
 308      * @return true if special method ignored by security stack walks, false otherwise
 309      */
 310     public boolean ignoredBySecurityStackWalk() {
 311         return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(this);
 312     }
 313 
 314     @Override
 315     public boolean isClassInitializer() {
 316         return "<clinit>".equals(name) && isStatic();
 317     }
 318 
 319     @Override
 320     public boolean isConstructor() {
 321         return "<init>".equals(name) && !isStatic();
 322     }
 323 
 324     @Override
 325     public int getMaxLocals() {
 326         if (isAbstract() || isNative()) {
 327             return 0;
 328         }
 329         HotSpotVMConfig config = runtime().getConfig();
 330         return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset);
 331     }
 332 
 333     @Override
 334     public int getMaxStackSize() {
 335         if (isAbstract() || isNative()) {
 336             return 0;
 337         }
 338         HotSpotVMConfig config = runtime().getConfig();
 339         return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset);
 340     }
 341 
 342     @Override
 343     public StackTraceElement asStackTraceElement(int bci) {
 344         if (bci < 0 || bci >= getCodeSize()) {
 345             // HotSpot code can only construct stack trace elements for valid bcis
 346             StackTraceElement ste = runtime().getCompilerToVM().getStackTraceElement(this, 0);
 347             return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1);
 348         }
 349         return runtime().getCompilerToVM().getStackTraceElement(this, bci);
 350     }
 351 
 352     public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) {
 353         if (receiver.isInterface()) {
 354             // Cannot trust interfaces. Because of:
 355             // interface I { void foo(); }
 356             // class A { public void foo() {} }
 357             // class B extends A implements I { }
 358             // class C extends B { public void foo() { } }
 359             // class D extends B { }
 360             // Would lead to identify C.foo() as the unique concrete method for I.foo() without
 361             // seeing A.foo().
 362             return null;
 363         }
 364         return runtime().getCompilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this);




 365     }
 366 
 367     @Override
 368     public HotSpotSignature getSignature() {
 369         return signature;
 370     }
 371 
 372     /**
 373      * Gets the value of {@code Method::_code}.
 374      *
 375      * @return the value of {@code Method::_code}
 376      */
 377     private long getCompiledCode() {
 378         HotSpotVMConfig config = runtime().getConfig();
 379         return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset);
 380     }
 381 
 382     /**
 383      * Returns whether this method has compiled code.
 384      *
 385      * @return true if this method has compiled code, false otherwise
 386      */
 387     public boolean hasCompiledCode() {
 388         return getCompiledCode() != 0L;
 389     }
 390 
 391     /**
 392      * @param level
 393      * @return true if the currently installed code was generated at {@code level}.
 394      */
 395     public boolean hasCompiledCodeAtLevel(int level) {
 396         long compiledCode = getCompiledCode();
 397         if (compiledCode != 0) {
 398             return UNSAFE.getInt(compiledCode + runtime().getConfig().nmethodCompLevelOffset) == level;
 399         }
 400         return false;
 401     }
 402 
 403     private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter");
 404 
 405     @Override
 406     public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
 407         ProfilingInfo info;
 408 
 409         if (UseProfilingInformation.getValue() && methodData == null) {
 410             long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodDataOffset);
 411             if (metaspaceMethodData != 0) {
 412                 methodData = new HotSpotMethodData(metaspaceMethodData, this);
 413                 if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) {
 414                     System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":");
 415                     System.out.println(methodData.toString());
 416                 }
 417             }
 418         }
 419 
 420         if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) {
 421             // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in
 422             // case of a deoptimization.
 423             info = DefaultProfilingInfo.get(TriState.FALSE);
 424         } else {
 425             info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR);
 426         }
 427         return info;
 428     }
 429 
 430     @Override
 431     public void reprofile() {
 432         runtime().getCompilerToVM().reprofile(this);
 433     }
 434 
 435     @Override
 436     public ConstantPool getConstantPool() {
 437         return constantPool;
 438     }
 439 
 440     @Override
 441     public Annotation[][] getParameterAnnotations() {
 442         if (isConstructor()) {
 443             Constructor<?> javaConstructor = toJavaConstructor();
 444             return javaConstructor == null ? null : javaConstructor.getParameterAnnotations();
 445         }
 446         Method javaMethod = toJava();
 447         return javaMethod == null ? null : javaMethod.getParameterAnnotations();
 448     }
 449 
 450     @Override
 451     public Annotation[] getAnnotations() {
 452         if (isConstructor()) {
 453             Constructor<?> javaConstructor = toJavaConstructor();
 454             return javaConstructor == null ? new Annotation[0] : javaConstructor.getAnnotations();
 455         }
 456         Method javaMethod = toJava();
 457         return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations();
 458     }
 459 
 460     @Override
 461     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 462         if (isConstructor()) {
 463             Constructor<?> javaConstructor = toJavaConstructor();
 464             return javaConstructor == null ? null : javaConstructor.getAnnotation(annotationClass);
 465         }
 466         Method javaMethod = toJava();
 467         return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass);
 468     }
 469 
 470     public boolean isDefault() {
 471         if (isConstructor()) {
 472             return false;
 473         }
 474         // Copied from java.lang.Method.isDefault()
 475         int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC;
 476         return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
 477     }
 478 
 479     @Override
 480     public Type[] getGenericParameterTypes() {
 481         if (isConstructor()) {
 482             Constructor<?> javaConstructor = toJavaConstructor();
 483             return javaConstructor == null ? null : javaConstructor.getGenericParameterTypes();
 484         }
 485         Method javaMethod = toJava();
 486         return javaMethod == null ? null : javaMethod.getGenericParameterTypes();
 487     }
 488 
 489     public Class<?>[] signatureToTypes() {
 490         Signature sig = getSignature();
 491         int count = sig.getParameterCount(false);
 492         Class<?>[] result = new Class<?>[count];
 493         for (int i = 0; i < result.length; ++i) {
 494             JavaType parameterType = sig.getParameterType(i, holder);
 495             HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder);
 496             result[i] = resolvedParameterType.mirror();
 497         }
 498         return result;
 499     }
 500 
 501     private Method toJava() {
 502         if (toJavaCache != null) {
 503             return (Method) toJavaCache;
 504         }
 505         try {
 506             Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes());
 507             toJavaCache = result;
 508             return result;
 509         } catch (NoSuchMethodException | NoClassDefFoundError e) {
 510             return null;
 511         }
 512     }
 513 
 514     private Constructor<?> toJavaConstructor() {
 515         if (toJavaCache != null) {
 516             return (Constructor<?>) toJavaCache;
 517         }
 518         try {
 519             Constructor<?> result = holder.mirror().getDeclaredConstructor(signatureToTypes());

 520             toJavaCache = result;
 521             return result;
 522         } catch (NoSuchMethodException | NoClassDefFoundError e) {
 523             return null;
 524         }
 525     }
 526 
 527     @Override
 528     public boolean canBeInlined() {
 529         if (isDontInline()) {
 530             return false;
 531         }
 532         return runtime().getCompilerToVM().canInlineMethod(this);
 533     }
 534 
 535     @Override
 536     public boolean shouldBeInlined() {
 537         if (isForceInline()) {
 538             return true;
 539         }
 540         return runtime().getCompilerToVM().shouldInlineMethod(this);
 541     }
 542 
 543     @Override
 544     public LineNumberTable getLineNumberTable() {
 545         final boolean hasLineNumberTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLineNumberTable) != 0;
 546         if (!hasLineNumberTable) {
 547             return null;
 548         }
 549 
 550         long[] values = runtime().getCompilerToVM().getLineNumberTable(this);
 551         if (values == null || values.length == 0) {
 552             // Empty table so treat is as non-existent
 553             return null;
 554         }
 555         assert values.length % 2 == 0;
 556         int[] bci = new int[values.length / 2];
 557         int[] line = new int[values.length / 2];
 558 
 559         for (int i = 0; i < values.length / 2; i++) {
 560             bci[i] = (int) values[i * 2];
 561             line[i] = (int) values[i * 2 + 1];
 562         }
 563 
 564         return new LineNumberTableImpl(line, bci);
 565     }
 566 
 567     @Override
 568     public LocalVariableTable getLocalVariableTable() {
 569         final boolean hasLocalVariableTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLocalVariableTable) != 0;
 570         if (!hasLocalVariableTable) {
 571             return null;
 572         }
 573 
 574         HotSpotVMConfig config = runtime().getConfig();
 575         long localVariableTableElement = runtime().getCompilerToVM().getLocalVariableTableStart(this);
 576         final int localVariableTableLength = runtime().getCompilerToVM().getLocalVariableTableLength(this);
 577         Local[] locals = new Local[localVariableTableLength];
 578 
 579         for (int i = 0; i < localVariableTableLength; i++) {
 580             final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset);
 581             final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset);
 582             final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset);
 583             final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset);
 584             final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset);
 585 
 586             String localName = getConstantPool().lookupUtf8(nameCpIndex);
 587             String localType = getConstantPool().lookupUtf8(typeCpIndex);
 588 
 589             locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot);
 590 
 591             // Go to the next LocalVariableTableElement
 592             localVariableTableElement += config.localVariableTableElementSize;
 593         }
 594 
 595         return new LocalVariableTableImpl(locals);
 596     }
 597 
 598     /**
 599      * Returns the offset of this method into the v-table. The method must have a v-table entry as
 600      * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is
 601      * thrown.
 602      *
 603      * @return the offset of this method into the v-table
 604      */
 605     public int vtableEntryOffset(ResolvedJavaType resolved) {
 606         if (!isInVirtualMethodTable(resolved)) {
 607             throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved);
 608         }
 609         HotSpotVMConfig config = runtime().getConfig();
 610         final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved);
 611         return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
 612     }
 613 
 614     @Override
 615     public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
 616         if (resolved instanceof HotSpotResolvedObjectTypeImpl) {
 617             HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved;
 618             int vtableIndex = getVtableIndex(hotspotResolved);
 619             return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength();
 620         }
 621         return false;
 622     }
 623 
 624     private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) {
 625         if (!holder.isLinked()) {
 626             return runtime().getConfig().invalidVtableIndex;
 627         }
 628         if (holder.isInterface()) {
 629             if (resolved.isInterface()) {
 630                 return runtime().getConfig().invalidVtableIndex;
 631             }
 632             return getVtableIndexForInterfaceMethod(resolved);
 633         }
 634         return getVtableIndex();
 635     }
 636 
 637     /**
 638      * Returns this method's virtual table index.
 639      *
 640      * @return virtual table index
 641      */
 642     private int getVtableIndex() {
 643         assert!holder.isInterface();
 644         HotSpotVMConfig config = runtime().getConfig();
 645         int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset);
 646         assert result >= config.nonvirtualVtableIndex : "must be linked";
 647         return result;
 648     }
 649 
 650     private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) {
 651         HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved;
 652         return runtime().getCompilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this);
 653     }
 654 
 655     /**
 656      * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type
 657      * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
 658      * never moves and b) we never read from it.
 659      * <p>
 660      * One implication is that we will preserve {@link SpeculationLog}s for methods that have been
 661      * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot
 662      * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods
 663      * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal).
 664      */
 665     private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() {
 666         @Override
 667         protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) {
 668             return new HashMap<>(4);
 669         }
 670     };
 671 
 672     public SpeculationLog getSpeculationLog() {
 673         Map<Long, SpeculationLog> map = SpeculationLogs.get(holder.mirror());
 674         synchronized (map) {
 675             SpeculationLog log = map.get(this.metaspaceMethod);
 676             if (log == null) {
 677                 log = new HotSpotSpeculationLog();
 678                 map.put(metaspaceMethod, log);
 679             }
 680             return log;
 681         }
 682     }
 683 
 684     public int intrinsicId() {
 685         HotSpotVMConfig config = runtime().getConfig();
 686         return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset);
 687     }
 688 
 689     @Override
 690     public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) {
 691         assert!isConstructor();
 692         Method javaMethod = toJava();
 693         javaMethod.setAccessible(true);
 694 
 695         Object[] objArguments = new Object[arguments.length];
 696         for (int i = 0; i < arguments.length; i++) {
 697             objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]);
 698         }
 699         Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null;
 700 
 701         try {
 702             Object objResult = javaMethod.invoke(objReceiver, objArguments);
 703             return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult);
 704 
 705         } catch (IllegalAccessException | InvocationTargetException ex) {
 706             throw new IllegalArgumentException(ex);
 707         }
 708     }
 709 
 710     /**
 711      * Allocates a compile id for this method by asking the VM for one.
 712      *
 713      * @param entryBCI entry bci
 714      * @return compile id
 715      */
 716     public int allocateCompileId(int entryBCI) {
 717         return runtime().getCompilerToVM().allocateCompileId(this, entryBCI);
 718     }
 719 
 720     public boolean hasCodeAtLevel(int entryBCI, int level) {
 721         if (entryBCI == runtime().getConfig().invocationEntryBci) {
 722             return hasCompiledCodeAtLevel(level);
 723         }
 724         return runtime().getCompilerToVM().hasCompiledCodeForOSR(this, entryBCI, level);
 725     }
 726 }
   1 /*
   2  * Copyright (c) 2011, 2015, 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.hotspot;
  24 
  25 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
  26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
  27 import static jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod.Options.UseProfilingInformation;
  28 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
  29 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
  30 
  31 import java.lang.annotation.Annotation;
  32 import java.lang.reflect.Executable;
  33 import java.lang.reflect.InvocationTargetException;
  34 import java.lang.reflect.Method;
  35 import java.lang.reflect.Modifier;
  36 import java.lang.reflect.Type;
  37 import java.util.HashMap;
  38 import java.util.Map;
  39 
  40 import jdk.vm.ci.common.JVMCIError;
  41 import jdk.vm.ci.meta.Constant;
  42 import jdk.vm.ci.meta.ConstantPool;
  43 import jdk.vm.ci.meta.DefaultProfilingInfo;
  44 import jdk.vm.ci.meta.ExceptionHandler;
  45 import jdk.vm.ci.meta.JavaConstant;
  46 import jdk.vm.ci.meta.JavaMethod;
  47 import jdk.vm.ci.meta.JavaType;
  48 import jdk.vm.ci.meta.LineNumberTable;
  49 import jdk.vm.ci.meta.LineNumberTableImpl;
  50 import jdk.vm.ci.meta.Local;
  51 import jdk.vm.ci.meta.LocalImpl;
  52 import jdk.vm.ci.meta.LocalVariableTable;
  53 import jdk.vm.ci.meta.LocalVariableTableImpl;
  54 import jdk.vm.ci.meta.ModifiersProvider;
  55 import jdk.vm.ci.meta.ProfilingInfo;
  56 import jdk.vm.ci.meta.ResolvedJavaMethod;
  57 import jdk.vm.ci.meta.ResolvedJavaType;
  58 import jdk.vm.ci.meta.Signature;
  59 import jdk.vm.ci.meta.SpeculationLog;
  60 import jdk.vm.ci.meta.TriState;
  61 
  62 /**
  63  * Implementation of {@link JavaMethod} for resolved HotSpot methods.
  64  */
  65 final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MetaspaceWrapperObject {







  66 
  67     /**
  68      * Reference to metaspace Method object.
  69      */
  70     private final long metaspaceMethod;
  71 
  72     private final HotSpotResolvedObjectTypeImpl holder;
  73     private final HotSpotConstantPool constantPool;
  74     private final HotSpotSignature signature;
  75     private HotSpotMethodData methodData;
  76     private byte[] code;
  77     private Executable toJavaCache;
  78 
  79     /**
  80      * Gets the holder of a HotSpot metaspace method native object.
  81      *
  82      * @param metaspaceMethod a metaspace Method object
  83      * @return the {@link ResolvedJavaType} corresponding to the holder of the
  84      *         {@code metaspaceMethod}
  85      */
  86     private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) {
  87         HotSpotVMConfig config = config();
  88         final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset);
  89         final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset);
  90         return compilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false);
  91     }
  92 
  93     /**
  94      * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the
  95      * Method* is kept alive for the duration of this call and the
  96      * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that.
  97      *
  98      * Called from the VM.
  99      *
 100      * @param metaspaceMethod a metaspace Method object
 101      * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod}
 102      */
 103     @SuppressWarnings("unused")
 104     private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) {
 105         HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod);
 106         return holder.createMethod(metaspaceMethod);
 107     }
 108 
 109     HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) {
 110         // It would be too much work to get the method name here so we fill it in later.
 111         super(null);
 112         this.metaspaceMethod = metaspaceMethod;
 113         this.holder = holder;
 114 
 115         HotSpotVMConfig config = config();
 116         final long constMethod = getConstMethod();
 117 
 118         /*
 119          * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for
 120          * signature-polymorphic method handle methods) have their own constant pool instead of the
 121          * one from their holder.
 122          */
 123         final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset);
 124         if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) {
 125             this.constantPool = holder.getConstantPool();
 126         } else {
 127             this.constantPool = compilerToVM().getConstantPool(null, constMethod + config.constMethodConstantsOffset);
 128         }
 129 
 130         final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset);
 131         this.name = constantPool.lookupUtf8(nameIndex);
 132 
 133         final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset);
 134         this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex);
 135     }
 136 
 137     /**
 138      * Returns a pointer to this method's constant method data structure (
 139      * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it
 140      * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod*
 141      * are kept alive as a pair.
 142      *
 143      * @return pointer to this method's ConstMethod
 144      */
 145     private long getConstMethod() {
 146         assert metaspaceMethod != 0;
 147         return UNSAFE.getAddress(metaspaceMethod + config().methodConstMethodOffset);
 148     }
 149 
 150     @Override
 151     public boolean equals(Object obj) {
 152         if (this == obj) {
 153             return true;
 154         }
 155         if (obj instanceof HotSpotResolvedJavaMethodImpl) {
 156             HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj;
 157             return that.metaspaceMethod == metaspaceMethod;
 158         }
 159         return false;
 160     }
 161 
 162     @Override
 163     public int hashCode() {
 164         return (int) metaspaceMethod;
 165     }
 166 
 167     /**
 168      * Returns this method's flags ({@code Method::_flags}).
 169      *
 170      * @return flags of this method
 171      */
 172     private int getFlags() {
 173         return UNSAFE.getByte(metaspaceMethod + config().methodFlagsOffset);
 174     }
 175 
 176     /**
 177      * Returns this method's constant method flags ({@code ConstMethod::_flags}).
 178      *
 179      * @return flags of this method's ConstMethod
 180      */
 181     private int getConstMethodFlags() {
 182         return UNSAFE.getChar(getConstMethod() + config().constMethodFlagsOffset);
 183     }
 184 
 185     @Override
 186     public HotSpotResolvedObjectTypeImpl getDeclaringClass() {
 187         return holder;
 188     }
 189 
 190     /**
 191      * Gets the address of the C++ Method object for this method.
 192      */
 193     public Constant getMetaspaceMethodConstant() {
 194         return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false);




 195     }
 196 
 197     public long getMetaspacePointer() {
 198         return metaspaceMethod;
 199     }
 200 
 201     @Override
 202     public Constant getEncoding() {
 203         return getMetaspaceMethodConstant();
 204     }
 205 
 206     /**
 207      * Gets the complete set of modifiers for this method which includes the JVM specification
 208      * modifiers as well as the HotSpot internal modifiers.
 209      */
 210     public int getAllModifiers() {
 211         return UNSAFE.getInt(metaspaceMethod + config().methodAccessFlagsOffset);
 212     }
 213 
 214     @Override
 215     public int getModifiers() {
 216         return getAllModifiers() & ModifiersProvider.jvmMethodModifiers();
 217     }
 218 
 219     @Override
 220     public boolean canBeStaticallyBound() {
 221         return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete();
 222     }
 223 
 224     @Override
 225     public byte[] getCode() {
 226         if (getCodeSize() == 0) {
 227             return null;
 228         }
 229         if (code == null && holder.isLinked()) {
 230             code = compilerToVM().getBytecode(this);
 231             assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length;
 232         }
 233         return code;
 234     }
 235 
 236     @Override
 237     public int getCodeSize() {
 238         return UNSAFE.getChar(getConstMethod() + config().constMethodCodeSizeOffset);
 239     }
 240 
 241     @Override
 242     public ExceptionHandler[] getExceptionHandlers() {
 243         final boolean hasExceptionTable = (getConstMethodFlags() & config().constMethodHasExceptionTable) != 0;
 244         if (!hasExceptionTable) {
 245             return new ExceptionHandler[0];
 246         }
 247 
 248         HotSpotVMConfig config = config();
 249         final int exceptionTableLength = compilerToVM().getExceptionTableLength(this);
 250         ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength];
 251         long exceptionTableElement = compilerToVM().getExceptionTableStart(this);
 252 
 253         for (int i = 0; i < exceptionTableLength; i++) {
 254             final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset);
 255             final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset);
 256             final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset);
 257             int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset);
 258 
 259             JavaType catchType;
 260             if (catchTypeIndex == 0) {
 261                 catchType = null;
 262             } else {
 263                 final int opcode = -1;  // opcode is not used
 264                 catchType = constantPool.lookupType(catchTypeIndex, opcode);
 265 
 266                 // Check for Throwable which catches everything.
 267                 if (catchType instanceof HotSpotResolvedObjectTypeImpl) {
 268                     HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType;
 269                     if (resolvedType.mirror() == Throwable.class) {
 270                         catchTypeIndex = 0;
 271                         catchType = null;
 272                     }
 273                 }
 274             }
 275             handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType);
 276 
 277             // Go to the next ExceptionTableElement
 278             exceptionTableElement += config.exceptionTableElementSize;
 279         }
 280 
 281         return handlers;
 282     }
 283 
 284     /**
 285      * Returns true if this method has a {@code CallerSensitive} annotation.
 286      *
 287      * @return true if CallerSensitive annotation present, false otherwise
 288      */
 289     public boolean isCallerSensitive() {
 290         return (getFlags() & config().methodFlagsCallerSensitive) != 0;
 291     }
 292 
 293     /**
 294      * Returns true if this method has a {@code ForceInline} annotation.
 295      *
 296      * @return true if ForceInline annotation present, false otherwise
 297      */
 298     public boolean isForceInline() {
 299         return (getFlags() & config().methodFlagsForceInline) != 0;
 300     }
 301 
 302     /**
 303      * Returns true if this method has a {@code DontInline} annotation.
 304      *
 305      * @return true if DontInline annotation present, false otherwise
 306      */
 307     public boolean isDontInline() {
 308         return (getFlags() & config().methodFlagsDontInline) != 0;
 309     }
 310 
 311     /**
 312      * Manually adds a DontInline annotation to this method.
 313      */
 314     public void setNotInlineable() {
 315         compilerToVM().doNotInlineOrCompile(this);
 316     }
 317 
 318     /**
 319      * Returns true if this method is one of the special methods that is ignored by security stack
 320      * walks.
 321      *
 322      * @return true if special method ignored by security stack walks, false otherwise
 323      */
 324     public boolean ignoredBySecurityStackWalk() {
 325         return compilerToVM().methodIsIgnoredBySecurityStackWalk(this);
 326     }
 327 
 328     @Override
 329     public boolean isClassInitializer() {
 330         return "<clinit>".equals(name) && isStatic();
 331     }
 332 
 333     @Override
 334     public boolean isConstructor() {
 335         return "<init>".equals(name) && !isStatic();
 336     }
 337 
 338     @Override
 339     public int getMaxLocals() {
 340         if (isAbstract() || isNative()) {
 341             return 0;
 342         }
 343         HotSpotVMConfig config = config();
 344         return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset);
 345     }
 346 
 347     @Override
 348     public int getMaxStackSize() {
 349         if (isAbstract() || isNative()) {
 350             return 0;
 351         }
 352         HotSpotVMConfig config = config();
 353         return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset);
 354     }
 355 
 356     @Override
 357     public StackTraceElement asStackTraceElement(int bci) {
 358         if (bci < 0 || bci >= getCodeSize()) {
 359             // HotSpot code can only construct stack trace elements for valid bcis
 360             StackTraceElement ste = compilerToVM().getStackTraceElement(this, 0);
 361             return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1);
 362         }
 363         return compilerToVM().getStackTraceElement(this, bci);
 364     }
 365 
 366     public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) {
 367         if (receiver.isInterface()) {
 368             // Cannot trust interfaces. Because of:
 369             // interface I { void foo(); }
 370             // class A { public void foo() {} }
 371             // class B extends A implements I { }
 372             // class C extends B { public void foo() { } }
 373             // class D extends B { }
 374             // Would lead to identify C.foo() as the unique concrete method for I.foo() without
 375             // seeing A.foo().
 376             return null;
 377         }
 378         if (this.isDefault()) {
 379             // CHA for default methods doesn't work and may crash the VM
 380             return null;
 381         }
 382         return compilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this);
 383     }
 384 
 385     @Override
 386     public HotSpotSignature getSignature() {
 387         return signature;
 388     }
 389 
 390     /**
 391      * Gets the value of {@code Method::_code}.
 392      *
 393      * @return the value of {@code Method::_code}
 394      */
 395     private long getCompiledCode() {
 396         HotSpotVMConfig config = config();
 397         return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset);
 398     }
 399 
 400     /**
 401      * Returns whether this method has compiled code.
 402      *
 403      * @return true if this method has compiled code, false otherwise
 404      */
 405     public boolean hasCompiledCode() {
 406         return getCompiledCode() != 0L;
 407     }
 408 
 409     /**
 410      * @param level
 411      * @return true if the currently installed code was generated at {@code level}.
 412      */
 413     public boolean hasCompiledCodeAtLevel(int level) {
 414         long compiledCode = getCompiledCode();
 415         if (compiledCode != 0) {
 416             return UNSAFE.getInt(compiledCode + config().nmethodCompLevelOffset) == level;
 417         }
 418         return false;
 419     }
 420 
 421     private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter");
 422 
 423     @Override
 424     public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) {
 425         ProfilingInfo info;
 426 
 427         if (UseProfilingInformation.getValue() && methodData == null) {
 428             long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset);
 429             if (metaspaceMethodData != 0) {
 430                 methodData = new HotSpotMethodData(metaspaceMethodData, this);
 431                 if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) {
 432                     System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":");
 433                     System.out.println(methodData.toString());
 434                 }
 435             }
 436         }
 437 
 438         if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) {
 439             // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in
 440             // case of a deoptimization.
 441             info = DefaultProfilingInfo.get(TriState.FALSE);
 442         } else {
 443             info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR);
 444         }
 445         return info;
 446     }
 447 
 448     @Override
 449     public void reprofile() {
 450         compilerToVM().reprofile(this);
 451     }
 452 
 453     @Override
 454     public ConstantPool getConstantPool() {
 455         return constantPool;
 456     }
 457 
 458     @Override
 459     public Annotation[][] getParameterAnnotations() {
 460         Executable javaMethod = toJava();




 461         return javaMethod == null ? null : javaMethod.getParameterAnnotations();
 462     }
 463 
 464     @Override
 465     public Annotation[] getAnnotations() {
 466         Executable javaMethod = toJava();




 467         return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations();
 468     }
 469 
 470     @Override
 471     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
 472         Executable javaMethod = toJava();




 473         return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass);
 474     }
 475 
 476     public boolean isDefault() {
 477         if (isConstructor()) {
 478             return false;
 479         }
 480         // Copied from java.lang.Method.isDefault()
 481         int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC;
 482         return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface();
 483     }
 484 
 485     @Override
 486     public Type[] getGenericParameterTypes() {
 487         Executable javaMethod = toJava();




 488         return javaMethod == null ? null : javaMethod.getGenericParameterTypes();
 489     }
 490 
 491     public Class<?>[] signatureToTypes() {
 492         Signature sig = getSignature();
 493         int count = sig.getParameterCount(false);
 494         Class<?>[] result = new Class<?>[count];
 495         for (int i = 0; i < result.length; ++i) {
 496             JavaType parameterType = sig.getParameterType(i, holder);
 497             HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder);
 498             result[i] = resolvedParameterType.mirror();
 499         }
 500         return result;
 501     }
 502 
 503     private Executable toJava() {













 504         if (toJavaCache != null) {
 505             return toJavaCache;
 506         }
 507         try {
 508             Class<?>[] parameterTypes = signatureToTypes();
 509             Executable result = isConstructor() ? holder.mirror().getDeclaredConstructor(parameterTypes) : holder.mirror().getDeclaredMethod(name, parameterTypes);
 510             toJavaCache = result;
 511             return result;
 512         } catch (NoSuchMethodException | NoClassDefFoundError e) {
 513             return null;
 514         }
 515     }
 516 
 517     @Override
 518     public boolean canBeInlined() {
 519         if (isDontInline()) {
 520             return false;
 521         }
 522         return compilerToVM().canInlineMethod(this);
 523     }
 524 
 525     @Override
 526     public boolean shouldBeInlined() {
 527         if (isForceInline()) {
 528             return true;
 529         }
 530         return compilerToVM().shouldInlineMethod(this);
 531     }
 532 
 533     @Override
 534     public LineNumberTable getLineNumberTable() {
 535         final boolean hasLineNumberTable = (getConstMethodFlags() & config().constMethodHasLineNumberTable) != 0;
 536         if (!hasLineNumberTable) {
 537             return null;
 538         }
 539 
 540         long[] values = compilerToVM().getLineNumberTable(this);
 541         if (values == null || values.length == 0) {
 542             // Empty table so treat is as non-existent
 543             return null;
 544         }
 545         assert values.length % 2 == 0;
 546         int[] bci = new int[values.length / 2];
 547         int[] line = new int[values.length / 2];
 548 
 549         for (int i = 0; i < values.length / 2; i++) {
 550             bci[i] = (int) values[i * 2];
 551             line[i] = (int) values[i * 2 + 1];
 552         }
 553 
 554         return new LineNumberTableImpl(line, bci);
 555     }
 556 
 557     @Override
 558     public LocalVariableTable getLocalVariableTable() {
 559         final boolean hasLocalVariableTable = (getConstMethodFlags() & config().constMethodHasLocalVariableTable) != 0;
 560         if (!hasLocalVariableTable) {
 561             return null;
 562         }
 563 
 564         HotSpotVMConfig config = config();
 565         long localVariableTableElement = compilerToVM().getLocalVariableTableStart(this);
 566         final int localVariableTableLength = compilerToVM().getLocalVariableTableLength(this);
 567         Local[] locals = new Local[localVariableTableLength];
 568 
 569         for (int i = 0; i < localVariableTableLength; i++) {
 570             final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset);
 571             final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset);
 572             final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset);
 573             final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset);
 574             final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset);
 575 
 576             String localName = getConstantPool().lookupUtf8(nameCpIndex);
 577             String localType = getConstantPool().lookupUtf8(typeCpIndex);
 578 
 579             locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot);
 580 
 581             // Go to the next LocalVariableTableElement
 582             localVariableTableElement += config.localVariableTableElementSize;
 583         }
 584 
 585         return new LocalVariableTableImpl(locals);
 586     }
 587 
 588     /**
 589      * Returns the offset of this method into the v-table. The method must have a v-table entry as
 590      * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is
 591      * thrown.
 592      *
 593      * @return the offset of this method into the v-table
 594      */
 595     public int vtableEntryOffset(ResolvedJavaType resolved) {
 596         if (!isInVirtualMethodTable(resolved)) {
 597             throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved);
 598         }
 599         HotSpotVMConfig config = config();
 600         final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved);
 601         return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset;
 602     }
 603 
 604     @Override
 605     public boolean isInVirtualMethodTable(ResolvedJavaType resolved) {
 606         if (resolved instanceof HotSpotResolvedObjectTypeImpl) {
 607             HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved;
 608             int vtableIndex = getVtableIndex(hotspotResolved);
 609             return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength();
 610         }
 611         return false;
 612     }
 613 
 614     private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) {
 615         if (!holder.isLinked()) {
 616             return config().invalidVtableIndex;
 617         }
 618         if (holder.isInterface()) {
 619             if (resolved.isInterface()) {
 620                 return config().invalidVtableIndex;
 621             }
 622             return getVtableIndexForInterfaceMethod(resolved);
 623         }
 624         return getVtableIndex();
 625     }
 626 
 627     /**
 628      * Returns this method's virtual table index.
 629      *
 630      * @return virtual table index
 631      */
 632     private int getVtableIndex() {
 633         assert !holder.isInterface();
 634         HotSpotVMConfig config = config();
 635         int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset);
 636         assert result >= config.nonvirtualVtableIndex : "must be linked";
 637         return result;
 638     }
 639 
 640     private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) {
 641         HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved;
 642         return compilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this);
 643     }
 644 
 645     /**
 646      * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type
 647      * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
 648      * never moves and b) we never read from it.
 649      * <p>
 650      * One implication is that we will preserve {@link SpeculationLog}s for methods that have been
 651      * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot
 652      * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods
 653      * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal).
 654      */
 655     private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() {
 656         @Override
 657         protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) {
 658             return new HashMap<>(4);
 659         }
 660     };
 661 
 662     public SpeculationLog getSpeculationLog() {
 663         Map<Long, SpeculationLog> map = SpeculationLogs.get(holder.mirror());
 664         synchronized (map) {
 665             SpeculationLog log = map.get(this.metaspaceMethod);
 666             if (log == null) {
 667                 log = new HotSpotSpeculationLog();
 668                 map.put(metaspaceMethod, log);
 669             }
 670             return log;
 671         }
 672     }
 673 
 674     public int intrinsicId() {
 675         HotSpotVMConfig config = config();
 676         return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset);
 677     }
 678 
 679     @Override
 680     public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) {
 681         assert !isConstructor();
 682         Method javaMethod = (Method) toJava();
 683         javaMethod.setAccessible(true);
 684 
 685         Object[] objArguments = new Object[arguments.length];
 686         for (int i = 0; i < arguments.length; i++) {
 687             objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]);
 688         }
 689         Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null;
 690 
 691         try {
 692             Object objResult = javaMethod.invoke(objReceiver, objArguments);
 693             return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult);
 694 
 695         } catch (IllegalAccessException | InvocationTargetException ex) {
 696             throw new IllegalArgumentException(ex);
 697         }
 698     }
 699 
 700     /**
 701      * Allocates a compile id for this method by asking the VM for one.
 702      *
 703      * @param entryBCI entry bci
 704      * @return compile id
 705      */
 706     public int allocateCompileId(int entryBCI) {
 707         return compilerToVM().allocateCompileId(this, entryBCI);
 708     }
 709 
 710     public boolean hasCodeAtLevel(int entryBCI, int level) {
 711         if (entryBCI == config().invocationEntryBci) {
 712             return hasCompiledCodeAtLevel(level);
 713         }
 714         return compilerToVM().hasCompiledCodeForOSR(this, entryBCI, level);
 715     }
 716 }
< prev index next >