1 /* 2 * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package jdk.vm.ci.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.HotSpotModifiers.BRIDGE; 28 import static jdk.vm.ci.hotspot.HotSpotModifiers.SYNTHETIC; 29 import static jdk.vm.ci.hotspot.HotSpotModifiers.VARARGS; 30 import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmMethodModifiers; 31 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; 32 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 33 34 import java.lang.annotation.Annotation; 35 import java.lang.reflect.Executable; 36 import java.lang.reflect.Modifier; 37 import java.lang.reflect.Type; 38 39 import jdk.vm.ci.common.JVMCIError; 40 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option; 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.JavaMethod; 46 import jdk.vm.ci.meta.JavaType; 47 import jdk.vm.ci.meta.LineNumberTable; 48 import jdk.vm.ci.meta.Local; 49 import jdk.vm.ci.meta.LocalVariableTable; 50 import jdk.vm.ci.meta.ProfilingInfo; 51 import jdk.vm.ci.meta.ResolvedJavaMethod; 52 import jdk.vm.ci.meta.ResolvedJavaType; 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, MetaspaceHandleObject { 60 61 /** 62 * Handle to the metaspace {@code Method} object. The handle is in 63 * {@code JVMCI::_metadata_handles}. 64 */ 65 private final long metadataHandle; 66 67 private final HotSpotResolvedObjectTypeImpl holder; 68 private final HotSpotConstantPool constantPool; 69 final HotSpotSignature signature; 70 private HotSpotMethodData methodData; 71 private byte[] code; 72 73 /** 74 * Cache for {@link HotSpotJDKReflection#getMethod}. 75 */ 76 volatile Executable toJavaCache; 77 78 /** 79 * Only 30% of {@link HotSpotResolvedJavaMethodImpl}s have their name accessed so compute it 80 * lazily and cache it. 81 */ 82 private String nameCache; 83 84 /** 85 * Gets the holder of a HotSpot metaspace method native object. 86 * 87 * @param metaspaceHandle a handle to a metaspace Method object 88 * @return the {@link ResolvedJavaType} corresponding to the holder of the 89 * {@code metaspaceMethod} 90 */ 91 private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceHandle) { 92 HotSpotVMConfig config = config(); 93 long metaspaceMethod = UNSAFE.getLong(metaspaceHandle); 94 assert metaspaceMethod != 0 : metaspaceHandle; 95 final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); 96 final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); 97 HotSpotResolvedObjectTypeImpl result = compilerToVM().getResolvedJavaType(metaspaceConstantPool + config.constantPoolHolderOffset, false); 98 assert result != null; 99 return result; 100 } 101 102 /** 103 * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the 104 * Method* is kept alive for the duration of this call and the {@link HotSpotJVMCIRuntime} keeps 105 * it alive after that. 106 * <p> 107 * Called from the VM. 108 * 109 * @param metaspaceHandle a handle to metaspace Method object 110 * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} 111 */ 112 @SuppressWarnings("unused") 113 @VMEntryPoint 114 private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceHandle) { 115 HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceHandle); 116 return holder.createMethod(metaspaceHandle); 117 } 118 119 HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceHandle) { 120 this.metadataHandle = metaspaceHandle; 121 this.holder = holder; 122 123 HotSpotVMConfig config = config(); 124 final long constMethod = getConstMethod(); 125 126 /* 127 * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for 128 * signature-polymorphic method handle methods) have their own constant pool instead of the 129 * one from their holder. 130 */ 131 final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset); 132 if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) { 133 this.constantPool = holder.getConstantPool(); 134 } else { 135 this.constantPool = compilerToVM().getConstantPool(this); 136 } 137 138 final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); 139 this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); 140 HandleCleaner.create(this, metaspaceHandle); 141 } 142 143 /** 144 * Returns a pointer to this method's constant method data structure ( 145 * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it 146 * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod* 147 * are kept alive as a pair. 148 * 149 * @return pointer to this method's ConstMethod 150 */ 151 private long getConstMethod() { 152 return UNSAFE.getAddress(getMetaspaceMethod() + config().methodConstMethodOffset); 153 } 154 155 @Override 156 public String getName() { 157 if (nameCache == null) { 158 final int nameIndex = UNSAFE.getChar(getConstMethod() + config().constMethodNameIndexOffset); 159 nameCache = constantPool.lookupUtf8(nameIndex); 160 } 161 return nameCache; 162 } 163 164 @Override 165 public boolean equals(Object obj) { 166 if (this == obj) { 167 return true; 168 } 169 if (obj instanceof HotSpotResolvedJavaMethodImpl) { 170 HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; 171 return that.getMetaspaceMethod() == getMetaspaceMethod(); 172 } 173 return false; 174 } 175 176 @Override 177 public int hashCode() { 178 return (int) getMetaspaceMethod(); 179 } 180 181 /** 182 * Returns this method's flags ({@code Method::_flags}). 183 * 184 * @return flags of this method 185 */ 186 private int getFlags() { 187 return UNSAFE.getShort(getMetaspaceMethod() + config().methodFlagsOffset); 188 } 189 190 /** 191 * Returns this method's constant method flags ({@code ConstMethod::_flags}). 192 * 193 * @return flags of this method's ConstMethod 194 */ 195 private int getConstMethodFlags() { 196 return UNSAFE.getChar(getConstMethod() + config().constMethodFlagsOffset); 197 } 198 199 @Override 200 public HotSpotResolvedObjectTypeImpl getDeclaringClass() { 201 return holder; 202 } 203 204 /** 205 * Gets the address of the C++ Method object for this method. 206 */ 207 public Constant getMetaspaceMethodConstant() { 208 return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false); 209 } 210 211 long getMetaspaceMethod() { 212 long metaspacePointer = getMetaspacePointer(); 213 if (metaspacePointer == 0) { 214 throw new NullPointerException("Method* is null"); 215 } 216 return metaspacePointer; 217 } 218 219 @Override 220 public long getMetadataHandle() { 221 return metadataHandle; 222 } 223 224 @Override 225 public Constant getEncoding() { 226 return getMetaspaceMethodConstant(); 227 } 228 229 /** 230 * Gets the complete set of modifiers for this method which includes the JVM specification 231 * modifiers as well as the HotSpot internal modifiers. 232 */ 233 public int getAllModifiers() { 234 return UNSAFE.getInt(getMetaspaceMethod() + config().methodAccessFlagsOffset); 235 } 236 237 @Override 238 public int getModifiers() { 239 return getAllModifiers() & jvmMethodModifiers(); 240 } 241 242 @Override 243 public boolean canBeStaticallyBound() { 244 return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete(); 245 } 246 247 @Override 248 public byte[] getCode() { 249 if (getCodeSize() == 0) { 250 return null; 251 } 252 if (code == null && holder.isLinked()) { 253 code = compilerToVM().getBytecode(this); 254 assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length; 255 } 256 return code; 257 } 258 259 @Override 260 public int getCodeSize() { 261 return UNSAFE.getChar(getConstMethod() + config().constMethodCodeSizeOffset); 262 } 263 264 @Override 265 public ExceptionHandler[] getExceptionHandlers() { 266 final boolean hasExceptionTable = (getConstMethodFlags() & config().constMethodHasExceptionTable) != 0; 267 if (!hasExceptionTable) { 268 return new ExceptionHandler[0]; 269 } 270 271 HotSpotVMConfig config = config(); 272 final int exceptionTableLength = compilerToVM().getExceptionTableLength(this); 273 ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength]; 274 long exceptionTableElement = compilerToVM().getExceptionTableStart(this); 275 276 for (int i = 0; i < exceptionTableLength; i++) { 277 final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset); 278 final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset); 279 final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset); 280 int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset); 281 282 JavaType catchType; 283 if (catchTypeIndex == 0) { 284 catchType = null; 285 } else { 286 final int opcode = -1; // opcode is not used 287 catchType = constantPool.lookupType(catchTypeIndex, opcode); 288 289 // Check for Throwable which catches everything. 290 if (catchType instanceof HotSpotResolvedObjectTypeImpl) { 291 HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; 292 if (resolvedType.equals(runtime().getJavaLangThrowable())) { 293 catchTypeIndex = 0; 294 catchType = null; 295 } 296 } 297 } 298 handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); 299 300 // Go to the next ExceptionTableElement 301 exceptionTableElement += config.exceptionTableElementSize; 302 } 303 304 return handlers; 305 } 306 307 /** 308 * Returns true if this method has a {@code CallerSensitive} annotation. 309 * 310 * @return true if CallerSensitive annotation present, false otherwise 311 */ 312 @Override 313 public boolean isCallerSensitive() { 314 return (getFlags() & config().methodFlagsCallerSensitive) != 0; 315 } 316 317 /** 318 * Returns true if this method has a {@code ForceInline} annotation. 319 * 320 * @return true if ForceInline annotation present, false otherwise 321 */ 322 @Override 323 public boolean isForceInline() { 324 return (getFlags() & config().methodFlagsForceInline) != 0; 325 } 326 327 /** 328 * Returns true if this method has a {@code ReservedStackAccess} annotation. 329 * 330 * @return true if ReservedStackAccess annotation present, false otherwise 331 */ 332 @Override 333 public boolean hasReservedStackAccess() { 334 return (getFlags() & config().methodFlagsReservedStackAccess) != 0; 335 } 336 337 /** 338 * Sets flags on {@code method} indicating that it should never be inlined or compiled by the 339 * VM. 340 */ 341 @Override 342 public void setNotInlinableOrCompilable() { 343 compilerToVM().setNotInlinableOrCompilable(this); 344 } 345 346 /** 347 * Returns true if this method is one of the special methods that is ignored by security stack 348 * walks. 349 * 350 * @return true if special method ignored by security stack walks, false otherwise 351 */ 352 @Override 353 public boolean ignoredBySecurityStackWalk() { 354 return compilerToVM().methodIsIgnoredBySecurityStackWalk(this); 355 } 356 357 @Override 358 public boolean isClassInitializer() { 359 if (isStatic()) { 360 final int nameIndex = UNSAFE.getChar(getConstMethod() + config().constMethodNameIndexOffset); 361 long nameSymbol = constantPool.getEntryAt(nameIndex); 362 long clinitSymbol = config().symbolClinit; 363 return nameSymbol == clinitSymbol; 364 } 365 return false; 366 } 367 368 @Override 369 public boolean isConstructor() { 370 if (!isStatic()) { 371 final int nameIndex = UNSAFE.getChar(getConstMethod() + config().constMethodNameIndexOffset); 372 long nameSymbol = constantPool.getEntryAt(nameIndex); 373 long initSymbol = config().symbolInit; 374 return nameSymbol == initSymbol; 375 } 376 return false; 377 } 378 379 @Override 380 public int getMaxLocals() { 381 if (isAbstract() || isNative()) { 382 return 0; 383 } 384 HotSpotVMConfig config = config(); 385 return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); 386 } 387 388 @Override 389 public int getMaxStackSize() { 390 if (isAbstract() || isNative()) { 391 return 0; 392 } 393 HotSpotVMConfig config = config(); 394 return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); 395 } 396 397 @Override 398 public StackTraceElement asStackTraceElement(int bci) { 399 if (bci < 0 || bci >= getCodeSize()) { 400 // HotSpot code can only construct stack trace elements for valid bcis 401 StackTraceElement ste = compilerToVM().getStackTraceElement(this, 0); 402 return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); 403 } 404 return compilerToVM().getStackTraceElement(this, bci); 405 } 406 407 @Override 408 public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { 409 if (receiver.isInterface()) { 410 // Cannot trust interfaces. Because of: 411 // interface I { void foo(); } 412 // class A { public void foo() {} } 413 // class B extends A implements I { } 414 // class C extends B { public void foo() { } } 415 // class D extends B { } 416 // Would lead to identify C.foo() as the unique concrete method for I.foo() without 417 // seeing A.foo(). 418 return null; 419 } 420 if (this.isDefault()) { 421 // CHA for default methods doesn't work and may crash the VM 422 return null; 423 } 424 return compilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); 425 } 426 427 @Override 428 public HotSpotSignature getSignature() { 429 return signature; 430 } 431 432 /** 433 * Gets the value of {@code Method::_code}. 434 * 435 * @return the value of {@code Method::_code} 436 */ 437 private long getCompiledCode() { 438 HotSpotVMConfig config = config(); 439 return UNSAFE.getAddress(getMetaspaceMethod() + config.methodCodeOffset); 440 } 441 442 /** 443 * Returns whether this method has compiled code. 444 * 445 * @return true if this method has compiled code, false otherwise 446 */ 447 @Override 448 public boolean hasCompiledCode() { 449 return getCompiledCode() != 0L; 450 } 451 452 /** 453 * @param level 454 * @return true if the currently installed code was generated at {@code level}. 455 */ 456 @Override 457 public boolean hasCompiledCodeAtLevel(int level) { 458 long compiledCode = getCompiledCode(); 459 if (compiledCode != 0) { 460 return UNSAFE.getInt(compiledCode + config().nmethodCompLevelOffset) == level; 461 } 462 return false; 463 } 464 465 @Override 466 public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { 467 ProfilingInfo info; 468 469 if (Option.UseProfilingInformation.getBoolean() && methodData == null) { 470 long metaspaceMethodData = UNSAFE.getAddress(getMetaspaceMethod() + config().methodDataOffset); 471 if (metaspaceMethodData != 0) { 472 methodData = new HotSpotMethodData(metaspaceMethodData, this); 473 String methodDataFilter = Option.TraceMethodDataFilter.getString(); 474 if (methodDataFilter != null && this.format("%H.%n").contains(methodDataFilter)) { 475 System.out.println(methodData.toString()); 476 } 477 } 478 } 479 480 if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { 481 // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in 482 // case of a deoptimization. 483 info = DefaultProfilingInfo.get(TriState.FALSE); 484 } else { 485 info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); 486 } 487 return info; 488 } 489 490 @Override 491 public void reprofile() { 492 compilerToVM().reprofile(this); 493 } 494 495 @Override 496 public ConstantPool getConstantPool() { 497 return constantPool; 498 } 499 500 @Override 501 public Parameter[] getParameters() { 502 if (signature.getParameterCount(false) == 0) { 503 return new ResolvedJavaMethod.Parameter[0]; 504 } 505 return runtime().reflection.getParameters(this); 506 } 507 508 @Override 509 public Annotation[][] getParameterAnnotations() { 510 if ((getConstMethodFlags() & config().constMethodHasParameterAnnotations) == 0) { 511 return new Annotation[signature.getParameterCount(false)][0]; 512 } 513 return runtime().reflection.getParameterAnnotations(this); 514 } 515 516 @Override 517 public Annotation[] getAnnotations() { 518 if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) { 519 return new Annotation[0]; 520 } 521 return runtime().reflection.getMethodAnnotations(this); 522 } 523 524 @Override 525 public Annotation[] getDeclaredAnnotations() { 526 if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) { 527 return new Annotation[0]; 528 } 529 return runtime().reflection.getMethodDeclaredAnnotations(this); 530 } 531 532 @Override 533 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 534 if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) { 535 return null; 536 } 537 return runtime().reflection.getMethodAnnotation(this, annotationClass); 538 } 539 540 @Override 541 public boolean isBridge() { 542 return (BRIDGE & getModifiers()) != 0; 543 } 544 545 @Override 546 public boolean isSynthetic() { 547 return (SYNTHETIC & getModifiers()) != 0; 548 } 549 550 @Override 551 public boolean isVarArgs() { 552 return (VARARGS & getModifiers()) != 0; 553 } 554 555 @Override 556 public boolean isDefault() { 557 // Copied from java.lang.Method.isDefault() 558 int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; 559 return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); 560 } 561 562 @Override 563 public Type[] getGenericParameterTypes() { 564 if (isClassInitializer()) { 565 return new Type[0]; 566 } 567 return runtime().reflection.getGenericParameterTypes(this); 568 } 569 570 @Override 571 public boolean canBeInlined() { 572 if (hasNeverInlineDirective()) { 573 return false; 574 } 575 return compilerToVM().isCompilable(this); 576 } 577 578 @Override 579 public boolean hasNeverInlineDirective() { 580 return compilerToVM().hasNeverInlineDirective(this); 581 } 582 583 @Override 584 public boolean shouldBeInlined() { 585 if (isForceInline()) { 586 return true; 587 } 588 return compilerToVM().shouldInlineMethod(this); 589 } 590 591 @Override 592 public LineNumberTable getLineNumberTable() { 593 final boolean hasLineNumberTable = (getConstMethodFlags() & config().constMethodHasLineNumberTable) != 0; 594 if (!hasLineNumberTable) { 595 return null; 596 } 597 598 long[] values = compilerToVM().getLineNumberTable(this); 599 if (values == null || values.length == 0) { 600 // Empty table so treat is as non-existent 601 return null; 602 } 603 assert values.length % 2 == 0; 604 int[] bci = new int[values.length / 2]; 605 int[] line = new int[values.length / 2]; 606 607 for (int i = 0; i < values.length / 2; i++) { 608 bci[i] = (int) values[i * 2]; 609 line[i] = (int) values[i * 2 + 1]; 610 } 611 612 return new LineNumberTable(line, bci); 613 } 614 615 @Override 616 public LocalVariableTable getLocalVariableTable() { 617 final boolean hasLocalVariableTable = (getConstMethodFlags() & config().constMethodHasLocalVariableTable) != 0; 618 if (!hasLocalVariableTable) { 619 return null; 620 } 621 622 HotSpotVMConfig config = config(); 623 long localVariableTableElement = compilerToVM().getLocalVariableTableStart(this); 624 final int localVariableTableLength = compilerToVM().getLocalVariableTableLength(this); 625 Local[] locals = new Local[localVariableTableLength]; 626 627 for (int i = 0; i < localVariableTableLength; i++) { 628 final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); 629 final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); 630 final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); 631 final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); 632 final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); 633 634 String localName = getConstantPool().lookupUtf8(nameCpIndex); 635 String localType = getConstantPool().lookupUtf8(typeCpIndex); 636 637 locals[i] = new Local(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); 638 639 // Go to the next LocalVariableTableElement 640 localVariableTableElement += config.localVariableTableElementSize; 641 } 642 643 return new LocalVariableTable(locals); 644 } 645 646 /** 647 * Returns the offset of this method into the v-table. The method must have a v-table entry as 648 * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is 649 * thrown. 650 * 651 * @return the offset of this method into the v-table 652 */ 653 @Override 654 public int vtableEntryOffset(ResolvedJavaType resolved) { 655 if (!isInVirtualMethodTable(resolved)) { 656 throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); 657 } 658 HotSpotVMConfig config = config(); 659 final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); 660 return config.klassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; 661 } 662 663 @Override 664 public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { 665 if (resolved instanceof HotSpotResolvedObjectTypeImpl) { 666 HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; 667 int vtableIndex = getVtableIndex(hotspotResolved); 668 return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); 669 } 670 return false; 671 } 672 673 private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { 674 if (!holder.isLinked()) { 675 return config().invalidVtableIndex; 676 } 677 if (holder.isInterface()) { 678 if (resolved.isInterface() || !resolved.isLinked()) { 679 return config().invalidVtableIndex; 680 } 681 return getVtableIndexForInterfaceMethod(resolved); 682 } 683 return getVtableIndex(); 684 } 685 686 /** 687 * Returns this method's virtual table index. 688 * 689 * @return virtual table index 690 */ 691 private int getVtableIndex() { 692 assert !holder.isInterface(); 693 HotSpotVMConfig config = config(); 694 int result = UNSAFE.getInt(getMetaspaceMethod() + config.methodVtableIndexOffset); 695 assert result >= config.nonvirtualVtableIndex : "must be linked"; 696 return result; 697 } 698 699 private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) { 700 HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; 701 return compilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this); 702 } 703 704 @Override 705 public SpeculationLog getSpeculationLog() { 706 long address = compilerToVM().getFailedSpeculationsAddress(this); 707 return new HotSpotSpeculationLog(address); 708 } 709 710 @Override 711 public int intrinsicId() { 712 HotSpotVMConfig config = config(); 713 return UNSAFE.getChar(getMetaspaceMethod() + config.methodIntrinsicIdOffset); 714 } 715 716 @Override 717 public boolean isIntrinsicCandidate() { 718 return (getFlags() & config().methodFlagsIntrinsicCandidate) != 0; 719 } 720 721 /** 722 * Allocates a compile id for this method by asking the VM for one. 723 * 724 * @param entryBCI entry bci 725 * @return compile id 726 */ 727 @Override 728 public int allocateCompileId(int entryBCI) { 729 return compilerToVM().allocateCompileId(this, entryBCI); 730 } 731 732 @Override 733 public boolean hasCodeAtLevel(int entryBCI, int level) { 734 if (entryBCI == config().invocationEntryBci) { 735 return hasCompiledCodeAtLevel(level); 736 } 737 return compilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); 738 } 739 740 @Override 741 public int methodIdnum() { 742 return UNSAFE.getChar(getConstMethod() + config().constMethodMethodIdnumOffset); 743 } 744 }