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