1 /* 2 * Copyright (c) 2011, 2016, 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.HotSpotVMConfig.config; 28 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 29 30 import java.lang.annotation.Annotation; 31 import java.lang.reflect.Executable; 32 import java.lang.reflect.Modifier; 33 import java.lang.reflect.Type; 34 import java.util.HashMap; 35 import java.util.Map; 36 37 import jdk.vm.ci.common.JVMCIError; 38 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; 39 import jdk.vm.ci.meta.Constant; 40 import jdk.vm.ci.meta.ConstantPool; 41 import jdk.vm.ci.meta.DefaultProfilingInfo; 42 import jdk.vm.ci.meta.ExceptionHandler; 43 import jdk.vm.ci.meta.JavaMethod; 44 import jdk.vm.ci.meta.JavaType; 45 import jdk.vm.ci.meta.LineNumberTable; 46 import jdk.vm.ci.meta.Local; 47 import jdk.vm.ci.meta.LocalVariableTable; 48 import jdk.vm.ci.meta.ModifiersProvider; 49 import jdk.vm.ci.meta.ProfilingInfo; 50 import jdk.vm.ci.meta.ResolvedJavaMethod; 51 import jdk.vm.ci.meta.ResolvedJavaType; 52 import jdk.vm.ci.meta.Signature; 53 import jdk.vm.ci.meta.SpeculationLog; 54 import jdk.vm.ci.meta.TriState; 55 56 /** 57 * Implementation of {@link JavaMethod} for resolved HotSpot methods. 58 */ 59 final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, MetaspaceWrapperObject { 60 61 /** 62 * Reference to metaspace Method object. 63 */ 64 private final long metaspaceMethod; 65 66 private final HotSpotResolvedObjectTypeImpl holder; 67 private final HotSpotConstantPool constantPool; 68 private final HotSpotSignature signature; 69 private HotSpotMethodData methodData; 70 private byte[] code; 71 private Executable toJavaCache; 72 73 /** 74 * Gets the holder of a HotSpot metaspace method native object. 75 * 76 * @param metaspaceMethod a metaspace Method object 77 * @return the {@link ResolvedJavaType} corresponding to the holder of the 78 * {@code metaspaceMethod} 79 */ 80 private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) { 81 HotSpotVMConfig config = config(); 82 final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); 83 final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); 84 return compilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false); 85 } 86 87 /** 88 * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the 89 * Method* is kept alive for the duration of this call and the 90 * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. 91 * 92 * Called from the VM. 93 * 94 * @param metaspaceMethod a metaspace Method object 95 * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} 96 */ 97 @SuppressWarnings("unused") 98 private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) { 99 HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod); 100 return holder.createMethod(metaspaceMethod); 101 } 102 103 HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) { 104 // It would be too much work to get the method name here so we fill it in later. 105 super(null); 106 this.metaspaceMethod = metaspaceMethod; 107 this.holder = holder; 108 109 HotSpotVMConfig config = config(); 110 final long constMethod = getConstMethod(); 111 112 /* 113 * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for 114 * signature-polymorphic method handle methods) have their own constant pool instead of the 115 * one from their holder. 116 */ 117 final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset); 118 if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) { 119 this.constantPool = holder.getConstantPool(); 120 } else { 121 this.constantPool = compilerToVM().getConstantPool(this); 122 } 123 124 final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset); 125 this.name = constantPool.lookupUtf8(nameIndex); 126 127 final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); 128 this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); 129 } 130 131 /** 132 * Returns a pointer to this method's constant method data structure ( 133 * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it 134 * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod* 135 * are kept alive as a pair. 136 * 137 * @return pointer to this method's ConstMethod 138 */ 139 private long getConstMethod() { 140 assert metaspaceMethod != 0; 141 return UNSAFE.getAddress(metaspaceMethod + config().methodConstMethodOffset); 142 } 143 144 @Override 145 public boolean equals(Object obj) { 146 if (this == obj) { 147 return true; 148 } 149 if (obj instanceof HotSpotResolvedJavaMethodImpl) { 150 HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; 151 return that.metaspaceMethod == metaspaceMethod; 152 } 153 return false; 154 } 155 156 @Override 157 public int hashCode() { 158 return (int) metaspaceMethod; 159 } 160 161 /** 162 * Returns this method's flags ({@code Method::_flags}). 163 * 164 * @return flags of this method 165 */ 166 private int getFlags() { 167 return UNSAFE.getShort(metaspaceMethod + config().methodFlagsOffset); 168 } 169 170 /** 171 * Returns this method's constant method flags ({@code ConstMethod::_flags}). 172 * 173 * @return flags of this method's ConstMethod 174 */ 175 private int getConstMethodFlags() { 176 return UNSAFE.getChar(getConstMethod() + config().constMethodFlagsOffset); 177 } 178 179 @Override 180 public HotSpotResolvedObjectTypeImpl getDeclaringClass() { 181 return holder; 182 } 183 184 /** 185 * Gets the address of the C++ Method object for this method. 186 */ 187 public Constant getMetaspaceMethodConstant() { 188 return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false); 189 } 190 191 public long getMetaspacePointer() { 192 return metaspaceMethod; 193 } 194 195 @Override 196 public Constant getEncoding() { 197 return getMetaspaceMethodConstant(); 198 } 199 200 /** 201 * Gets the complete set of modifiers for this method which includes the JVM specification 202 * modifiers as well as the HotSpot internal modifiers. 203 */ 204 public int getAllModifiers() { 205 return UNSAFE.getInt(metaspaceMethod + config().methodAccessFlagsOffset); 206 } 207 208 @Override 209 public int getModifiers() { 210 return getAllModifiers() & ModifiersProvider.jvmMethodModifiers(); 211 } 212 213 @Override 214 public boolean canBeStaticallyBound() { 215 return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete(); 216 } 217 218 @Override 219 public byte[] getCode() { 220 if (getCodeSize() == 0) { 221 return null; 222 } 223 if (code == null && holder.isLinked()) { 224 code = compilerToVM().getBytecode(this); 225 assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length; 226 } 227 return code; 228 } 229 230 @Override 231 public int getCodeSize() { 232 return UNSAFE.getChar(getConstMethod() + config().constMethodCodeSizeOffset); 233 } 234 235 @Override 236 public ExceptionHandler[] getExceptionHandlers() { 237 final boolean hasExceptionTable = (getConstMethodFlags() & config().constMethodHasExceptionTable) != 0; 238 if (!hasExceptionTable) { 239 return new ExceptionHandler[0]; 240 } 241 242 HotSpotVMConfig config = config(); 243 final int exceptionTableLength = compilerToVM().getExceptionTableLength(this); 244 ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength]; 245 long exceptionTableElement = compilerToVM().getExceptionTableStart(this); 246 247 for (int i = 0; i < exceptionTableLength; i++) { 248 final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset); 249 final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset); 250 final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset); 251 int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset); 252 253 JavaType catchType; 254 if (catchTypeIndex == 0) { 255 catchType = null; 256 } else { 257 final int opcode = -1; // opcode is not used 258 catchType = constantPool.lookupType(catchTypeIndex, opcode); 259 260 // Check for Throwable which catches everything. 261 if (catchType instanceof HotSpotResolvedObjectTypeImpl) { 262 HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; 263 if (resolvedType.mirror() == Throwable.class) { 264 catchTypeIndex = 0; 265 catchType = null; 266 } 267 } 268 } 269 handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); 270 271 // Go to the next ExceptionTableElement 272 exceptionTableElement += config.exceptionTableElementSize; 273 } 274 275 return handlers; 276 } 277 278 /** 279 * Returns true if this method has a {@code CallerSensitive} annotation. 280 * 281 * @return true if CallerSensitive annotation present, false otherwise 282 */ 283 public boolean isCallerSensitive() { 284 return (getFlags() & config().methodFlagsCallerSensitive) != 0; 285 } 286 287 /** 288 * Returns true if this method has a {@code ForceInline} annotation. 289 * 290 * @return true if ForceInline annotation present, false otherwise 291 */ 292 public boolean isForceInline() { 293 return (getFlags() & config().methodFlagsForceInline) != 0; 294 } 295 296 /** 297 * Returns true if this method has a {@code DontInline} annotation. 298 * 299 * @return true if DontInline annotation present, false otherwise 300 */ 301 public boolean isDontInline() { 302 return (getFlags() & config().methodFlagsDontInline) != 0; 303 } 304 305 /** 306 * Returns true if this method has a {@code ReservedStackAccess} annotation. 307 * 308 * @return true if ReservedStackAccess annotation present, false otherwise 309 */ 310 public boolean hasReservedStackAccess() { 311 return (getFlags() & config().methodFlagsReservedStackAccess) != 0; 312 } 313 314 /** 315 * Manually adds a DontInline annotation to this method. 316 */ 317 public void setNotInlineable() { 318 compilerToVM().doNotInlineOrCompile(this); 319 } 320 321 /** 322 * Returns true if this method is one of the special methods that is ignored by security stack 323 * walks. 324 * 325 * @return true if special method ignored by security stack walks, false otherwise 326 */ 327 public boolean ignoredBySecurityStackWalk() { 328 return compilerToVM().methodIsIgnoredBySecurityStackWalk(this); 329 } 330 331 @Override 332 public boolean isClassInitializer() { 333 return "<clinit>".equals(name) && isStatic(); 334 } 335 336 @Override 337 public boolean isConstructor() { 338 return "<init>".equals(name) && !isStatic(); 339 } 340 341 @Override 342 public int getMaxLocals() { 343 if (isAbstract() || isNative()) { 344 return 0; 345 } 346 HotSpotVMConfig config = config(); 347 return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); 348 } 349 350 @Override 351 public int getMaxStackSize() { 352 if (isAbstract() || isNative()) { 353 return 0; 354 } 355 HotSpotVMConfig config = config(); 356 return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); 357 } 358 359 @Override 360 public StackTraceElement asStackTraceElement(int bci) { 361 if (bci < 0 || bci >= getCodeSize()) { 362 // HotSpot code can only construct stack trace elements for valid bcis 363 StackTraceElement ste = compilerToVM().getStackTraceElement(this, 0); 364 return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); 365 } 366 return compilerToVM().getStackTraceElement(this, bci); 367 } 368 369 public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { 370 if (receiver.isInterface()) { 371 // Cannot trust interfaces. Because of: 372 // interface I { void foo(); } 373 // class A { public void foo() {} } 374 // class B extends A implements I { } 375 // class C extends B { public void foo() { } } 376 // class D extends B { } 377 // Would lead to identify C.foo() as the unique concrete method for I.foo() without 378 // seeing A.foo(). 379 return null; 380 } 381 if (this.isDefault()) { 382 // CHA for default methods doesn't work and may crash the VM 383 return null; 384 } 385 return compilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); 386 } 387 388 @Override 389 public HotSpotSignature getSignature() { 390 return signature; 391 } 392 393 /** 394 * Gets the value of {@code Method::_code}. 395 * 396 * @return the value of {@code Method::_code} 397 */ 398 private long getCompiledCode() { 399 HotSpotVMConfig config = config(); 400 return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); 401 } 402 403 /** 404 * Returns whether this method has compiled code. 405 * 406 * @return true if this method has compiled code, false otherwise 407 */ 408 public boolean hasCompiledCode() { 409 return getCompiledCode() != 0L; 410 } 411 412 /** 413 * @param level 414 * @return true if the currently installed code was generated at {@code level}. 415 */ 416 public boolean hasCompiledCodeAtLevel(int level) { 417 long compiledCode = getCompiledCode(); 418 if (compiledCode != 0) { 419 return UNSAFE.getInt(compiledCode + config().nmethodCompLevelOffset) == level; 420 } 421 return false; 422 } 423 424 @Override 425 public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { 426 ProfilingInfo info; 427 428 if (methodData == null) { 429 long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset); 430 if (metaspaceMethodData != 0) { 431 methodData = new HotSpotMethodData(metaspaceMethodData, this); 432 String methodDataFilter = Option.TraceMethodDataFilter.getString(); 433 if (methodDataFilter != null && this.format("%H.%n").contains(methodDataFilter)) { 434 System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":"); 435 System.out.println(methodData.toString()); 436 } 437 } 438 } 439 440 if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { 441 // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in 442 // case of a deoptimization. 443 info = DefaultProfilingInfo.get(TriState.FALSE); 444 } else { 445 info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); 446 } 447 return info; 448 } 449 450 @Override 451 public void reprofile() { 452 compilerToVM().reprofile(this); 453 } 454 455 @Override 456 public ConstantPool getConstantPool() { 457 return constantPool; 458 } 459 460 @Override 461 public Annotation[][] getParameterAnnotations() { 462 Executable javaMethod = toJava(); 463 return javaMethod == null ? null : javaMethod.getParameterAnnotations(); 464 } 465 466 @Override 467 public Annotation[] getAnnotations() { 468 Executable javaMethod = toJava(); 469 if (javaMethod != null) { 470 return javaMethod.getAnnotations(); 471 } 472 return new Annotation[0]; 473 } 474 475 @Override 476 public Annotation[] getDeclaredAnnotations() { 477 Executable javaMethod = toJava(); 478 if (javaMethod != null) { 479 return javaMethod.getDeclaredAnnotations(); 480 } 481 return new Annotation[0]; 482 } 483 484 @Override 485 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 486 Executable javaMethod = toJava(); 487 return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass); 488 } 489 490 public boolean isDefault() { 491 if (isConstructor()) { 492 return false; 493 } 494 // Copied from java.lang.Method.isDefault() 495 int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; 496 return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); 497 } 498 499 @Override 500 public Type[] getGenericParameterTypes() { 501 Executable javaMethod = toJava(); 502 return javaMethod == null ? null : javaMethod.getGenericParameterTypes(); 503 } 504 505 public Class<?>[] signatureToTypes() { 506 Signature sig = getSignature(); 507 int count = sig.getParameterCount(false); 508 Class<?>[] result = new Class<?>[count]; 509 for (int i = 0; i < result.length; ++i) { 510 JavaType parameterType = sig.getParameterType(i, holder); 511 HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder); 512 result[i] = resolvedParameterType.mirror(); 513 } 514 return result; 515 } 516 517 private Executable toJava() { 518 if (toJavaCache != null) { 519 return toJavaCache; 520 } 521 try { 522 Class<?>[] parameterTypes = signatureToTypes(); 523 Executable result = isConstructor() ? holder.mirror().getDeclaredConstructor(parameterTypes) : holder.mirror().getDeclaredMethod(name, parameterTypes); 524 toJavaCache = result; 525 return result; 526 } catch (NoSuchMethodException | NoClassDefFoundError e) { 527 return null; 528 } 529 } 530 531 @Override 532 public boolean canBeInlined() { 533 if (isDontInline()) { 534 return false; 535 } 536 return compilerToVM().canInlineMethod(this); 537 } 538 539 @Override 540 public boolean shouldBeInlined() { 541 if (isForceInline()) { 542 return true; 543 } 544 return compilerToVM().shouldInlineMethod(this); 545 } 546 547 @Override 548 public LineNumberTable getLineNumberTable() { 549 final boolean hasLineNumberTable = (getConstMethodFlags() & config().constMethodHasLineNumberTable) != 0; 550 if (!hasLineNumberTable) { 551 return null; 552 } 553 554 long[] values = compilerToVM().getLineNumberTable(this); 555 if (values == null || values.length == 0) { 556 // Empty table so treat is as non-existent 557 return null; 558 } 559 assert values.length % 2 == 0; 560 int[] bci = new int[values.length / 2]; 561 int[] line = new int[values.length / 2]; 562 563 for (int i = 0; i < values.length / 2; i++) { 564 bci[i] = (int) values[i * 2]; 565 line[i] = (int) values[i * 2 + 1]; 566 } 567 568 return new LineNumberTable(line, bci); 569 } 570 571 @Override 572 public LocalVariableTable getLocalVariableTable() { 573 final boolean hasLocalVariableTable = (getConstMethodFlags() & config().constMethodHasLocalVariableTable) != 0; 574 if (!hasLocalVariableTable) { 575 return null; 576 } 577 578 HotSpotVMConfig config = config(); 579 long localVariableTableElement = compilerToVM().getLocalVariableTableStart(this); 580 final int localVariableTableLength = compilerToVM().getLocalVariableTableLength(this); 581 Local[] locals = new Local[localVariableTableLength]; 582 583 for (int i = 0; i < localVariableTableLength; i++) { 584 final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); 585 final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); 586 final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); 587 final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); 588 final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); 589 590 String localName = getConstantPool().lookupUtf8(nameCpIndex); 591 String localType = getConstantPool().lookupUtf8(typeCpIndex); 592 593 locals[i] = new Local(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); 594 595 // Go to the next LocalVariableTableElement 596 localVariableTableElement += config.localVariableTableElementSize; 597 } 598 599 return new LocalVariableTable(locals); 600 } 601 602 /** 603 * Returns the offset of this method into the v-table. The method must have a v-table entry as 604 * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is 605 * thrown. 606 * 607 * @return the offset of this method into the v-table 608 */ 609 public int vtableEntryOffset(ResolvedJavaType resolved) { 610 if (!isInVirtualMethodTable(resolved)) { 611 throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); 612 } 613 HotSpotVMConfig config = config(); 614 final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); 615 return config.klassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; 616 } 617 618 @Override 619 public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { 620 if (resolved instanceof HotSpotResolvedObjectTypeImpl) { 621 HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; 622 int vtableIndex = getVtableIndex(hotspotResolved); 623 return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); 624 } 625 return false; 626 } 627 628 private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { 629 if (!holder.isLinked()) { 630 return config().invalidVtableIndex; 631 } 632 if (holder.isInterface()) { 633 if (resolved.isInterface()) { 634 return config().invalidVtableIndex; 635 } 636 return getVtableIndexForInterfaceMethod(resolved); 637 } 638 return getVtableIndex(); 639 } 640 641 /** 642 * Returns this method's virtual table index. 643 * 644 * @return virtual table index 645 */ 646 private int getVtableIndex() { 647 assert !holder.isInterface(); 648 HotSpotVMConfig config = config(); 649 int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); 650 assert result >= config.nonvirtualVtableIndex : "must be linked"; 651 return result; 652 } 653 654 private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) { 655 HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; 656 return compilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this); 657 } 658 659 /** 660 * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type 661 * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is 662 * never moves and b) we never read from it. 663 * <p> 664 * One implication is that we will preserve {@link SpeculationLog}s for methods that have been 665 * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot 666 * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods 667 * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). 668 */ 669 private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() { 670 @Override 671 protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) { 672 return new HashMap<>(4); 673 } 674 }; 675 676 public SpeculationLog getSpeculationLog() { 677 Map<Long, SpeculationLog> map = SpeculationLogs.get(holder.mirror()); 678 synchronized (map) { 679 SpeculationLog log = map.get(this.metaspaceMethod); 680 if (log == null) { 681 log = new HotSpotSpeculationLog(); 682 map.put(metaspaceMethod, log); 683 } 684 return log; 685 } 686 } 687 688 public int intrinsicId() { 689 HotSpotVMConfig config = config(); 690 return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset); 691 } 692 693 public boolean isIntrinsicCandidate() { 694 return (getFlags() & config().methodFlagsIntrinsicCandidate) != 0; 695 } 696 697 /** 698 * Allocates a compile id for this method by asking the VM for one. 699 * 700 * @param entryBCI entry bci 701 * @return compile id 702 */ 703 public int allocateCompileId(int entryBCI) { 704 return compilerToVM().allocateCompileId(this, entryBCI); 705 } 706 707 public boolean hasCodeAtLevel(int entryBCI, int level) { 708 if (entryBCI == config().invocationEntryBci) { 709 return hasCompiledCodeAtLevel(level); 710 } 711 return compilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); 712 } 713 }