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.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.getShort(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 * Returns true if this method has a {@code ReservedStackAccess} annotation. 313 * 314 * @return true if ReservedStackAccess annotation present, false otherwise 315 */ 316 public boolean hasReservedStackAccess() { 317 return (getFlags() & config().methodFlagsReservedStackAccess) != 0; 318 } 319 320 /** 321 * Manually adds a DontInline annotation to this method. 322 */ 323 public void setNotInlineable() { 324 compilerToVM().doNotInlineOrCompile(this); 325 } 326 327 /** 328 * Returns true if this method is one of the special methods that is ignored by security stack 329 * walks. 330 * 331 * @return true if special method ignored by security stack walks, false otherwise 332 */ 333 public boolean ignoredBySecurityStackWalk() { 334 return compilerToVM().methodIsIgnoredBySecurityStackWalk(this); 335 } 336 337 @Override 338 public boolean isClassInitializer() { 339 return "<clinit>".equals(name) && isStatic(); 340 } 341 342 @Override 343 public boolean isConstructor() { 344 return "<init>".equals(name) && !isStatic(); 345 } 346 347 @Override 348 public int getMaxLocals() { 349 if (isAbstract() || isNative()) { 350 return 0; 351 } 352 HotSpotVMConfig config = config(); 353 return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); 354 } 355 356 @Override 357 public int getMaxStackSize() { 358 if (isAbstract() || isNative()) { 359 return 0; 360 } 361 HotSpotVMConfig config = config(); 362 return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); 363 } 364 365 @Override 366 public StackTraceElement asStackTraceElement(int bci) { 367 if (bci < 0 || bci >= getCodeSize()) { 368 // HotSpot code can only construct stack trace elements for valid bcis 369 StackTraceElement ste = compilerToVM().getStackTraceElement(this, 0); 370 return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); 371 } 372 return compilerToVM().getStackTraceElement(this, bci); 373 } 374 375 public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { 376 if (receiver.isInterface()) { 377 // Cannot trust interfaces. Because of: 378 // interface I { void foo(); } 379 // class A { public void foo() {} } 380 // class B extends A implements I { } 381 // class C extends B { public void foo() { } } 382 // class D extends B { } 383 // Would lead to identify C.foo() as the unique concrete method for I.foo() without 384 // seeing A.foo(). 385 return null; 386 } 387 if (this.isDefault()) { 388 // CHA for default methods doesn't work and may crash the VM 389 return null; 390 } 391 return compilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); 392 } 393 394 @Override 395 public HotSpotSignature getSignature() { 396 return signature; 397 } 398 399 /** 400 * Gets the value of {@code Method::_code}. 401 * 402 * @return the value of {@code Method::_code} 403 */ 404 private long getCompiledCode() { 405 HotSpotVMConfig config = config(); 406 return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); 407 } 408 409 /** 410 * Returns whether this method has compiled code. 411 * 412 * @return true if this method has compiled code, false otherwise 413 */ 414 public boolean hasCompiledCode() { 415 return getCompiledCode() != 0L; 416 } 417 418 /** 419 * @param level 420 * @return true if the currently installed code was generated at {@code level}. 421 */ 422 public boolean hasCompiledCodeAtLevel(int level) { 423 long compiledCode = getCompiledCode(); 424 if (compiledCode != 0) { 425 return UNSAFE.getInt(compiledCode + config().nmethodCompLevelOffset) == level; 426 } 427 return false; 428 } 429 430 @Override 431 public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { 432 ProfilingInfo info; 433 434 if (methodData == null) { 435 long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + config().methodDataOffset); 436 if (metaspaceMethodData != 0) { 437 methodData = new HotSpotMethodData(metaspaceMethodData, this); 438 String methodDataFilter = Option.TraceMethodDataFilter.getString(); 439 if (methodDataFilter != null && this.format("%H.%n").contains(methodDataFilter)) { 440 System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":"); 441 System.out.println(methodData.toString()); 442 } 443 } 444 } 445 446 if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { 447 // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in 448 // case of a deoptimization. 449 info = DefaultProfilingInfo.get(TriState.FALSE); 450 } else { 451 info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); 452 } 453 return info; 454 } 455 456 @Override 457 public void reprofile() { 458 compilerToVM().reprofile(this); 459 } 460 461 @Override 462 public ConstantPool getConstantPool() { 463 return constantPool; 464 } 465 466 @Override 467 public Annotation[][] getParameterAnnotations() { 468 Executable javaMethod = toJava(); 469 return javaMethod == null ? null : javaMethod.getParameterAnnotations(); 470 } 471 472 @Override 473 public Annotation[] getAnnotations() { 474 Executable javaMethod = toJava(); 475 return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations(); 476 } 477 478 @Override 479 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 480 Executable javaMethod = toJava(); 481 return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass); 482 } 483 484 public boolean isDefault() { 485 if (isConstructor()) { 486 return false; 487 } 488 // Copied from java.lang.Method.isDefault() 489 int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; 490 return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); 491 } 492 493 @Override 494 public Type[] getGenericParameterTypes() { 495 Executable javaMethod = toJava(); 496 return javaMethod == null ? null : javaMethod.getGenericParameterTypes(); 497 } 498 499 public Class<?>[] signatureToTypes() { 500 Signature sig = getSignature(); 501 int count = sig.getParameterCount(false); 502 Class<?>[] result = new Class<?>[count]; 503 for (int i = 0; i < result.length; ++i) { 504 JavaType parameterType = sig.getParameterType(i, holder); 505 HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder); 506 result[i] = resolvedParameterType.mirror(); 507 } 508 return result; 509 } 510 511 private Executable toJava() { 512 if (toJavaCache != null) { 513 return toJavaCache; 514 } 515 try { 516 Class<?>[] parameterTypes = signatureToTypes(); 517 Executable result = isConstructor() ? holder.mirror().getDeclaredConstructor(parameterTypes) : holder.mirror().getDeclaredMethod(name, parameterTypes); 518 toJavaCache = result; 519 return result; 520 } catch (NoSuchMethodException | NoClassDefFoundError e) { 521 return null; 522 } 523 } 524 525 @Override 526 public boolean canBeInlined() { 527 if (isDontInline()) { 528 return false; 529 } 530 return compilerToVM().canInlineMethod(this); 531 } 532 533 @Override 534 public boolean shouldBeInlined() { 535 if (isForceInline()) { 536 return true; 537 } 538 return compilerToVM().shouldInlineMethod(this); 539 } 540 541 @Override 542 public LineNumberTable getLineNumberTable() { 543 final boolean hasLineNumberTable = (getConstMethodFlags() & config().constMethodHasLineNumberTable) != 0; 544 if (!hasLineNumberTable) { 545 return null; 546 } 547 548 long[] values = compilerToVM().getLineNumberTable(this); 549 if (values == null || values.length == 0) { 550 // Empty table so treat is as non-existent 551 return null; 552 } 553 assert values.length % 2 == 0; 554 int[] bci = new int[values.length / 2]; 555 int[] line = new int[values.length / 2]; 556 557 for (int i = 0; i < values.length / 2; i++) { 558 bci[i] = (int) values[i * 2]; 559 line[i] = (int) values[i * 2 + 1]; 560 } 561 562 return new LineNumberTableImpl(line, bci); 563 } 564 565 @Override 566 public LocalVariableTable getLocalVariableTable() { 567 final boolean hasLocalVariableTable = (getConstMethodFlags() & config().constMethodHasLocalVariableTable) != 0; 568 if (!hasLocalVariableTable) { 569 return null; 570 } 571 572 HotSpotVMConfig config = config(); 573 long localVariableTableElement = compilerToVM().getLocalVariableTableStart(this); 574 final int localVariableTableLength = compilerToVM().getLocalVariableTableLength(this); 575 Local[] locals = new Local[localVariableTableLength]; 576 577 for (int i = 0; i < localVariableTableLength; i++) { 578 final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); 579 final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); 580 final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); 581 final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); 582 final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); 583 584 String localName = getConstantPool().lookupUtf8(nameCpIndex); 585 String localType = getConstantPool().lookupUtf8(typeCpIndex); 586 587 locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); 588 589 // Go to the next LocalVariableTableElement 590 localVariableTableElement += config.localVariableTableElementSize; 591 } 592 593 return new LocalVariableTableImpl(locals); 594 } 595 596 /** 597 * Returns the offset of this method into the v-table. The method must have a v-table entry as 598 * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is 599 * thrown. 600 * 601 * @return the offset of this method into the v-table 602 */ 603 public int vtableEntryOffset(ResolvedJavaType resolved) { 604 if (!isInVirtualMethodTable(resolved)) { 605 throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); 606 } 607 HotSpotVMConfig config = config(); 608 final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); 609 return config.klassVtableStartOffset + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; 610 } 611 612 @Override 613 public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { 614 if (resolved instanceof HotSpotResolvedObjectTypeImpl) { 615 HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; 616 int vtableIndex = getVtableIndex(hotspotResolved); 617 return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); 618 } 619 return false; 620 } 621 622 private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { 623 if (!holder.isLinked()) { 624 return config().invalidVtableIndex; 625 } 626 if (holder.isInterface()) { 627 if (resolved.isInterface()) { 628 return config().invalidVtableIndex; 629 } 630 return getVtableIndexForInterfaceMethod(resolved); 631 } 632 return getVtableIndex(); 633 } 634 635 /** 636 * Returns this method's virtual table index. 637 * 638 * @return virtual table index 639 */ 640 private int getVtableIndex() { 641 assert !holder.isInterface(); 642 HotSpotVMConfig config = config(); 643 int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); 644 assert result >= config.nonvirtualVtableIndex : "must be linked"; 645 return result; 646 } 647 648 private int getVtableIndexForInterfaceMethod(ResolvedJavaType resolved) { 649 HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; 650 return compilerToVM().getVtableIndexForInterfaceMethod(hotspotType, this); 651 } 652 653 /** 654 * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type 655 * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is 656 * never moves and b) we never read from it. 657 * <p> 658 * One implication is that we will preserve {@link SpeculationLog}s for methods that have been 659 * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot 660 * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods 661 * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). 662 */ 663 private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() { 664 @Override 665 protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) { 666 return new HashMap<>(4); 667 } 668 }; 669 670 public SpeculationLog getSpeculationLog() { 671 Map<Long, SpeculationLog> map = SpeculationLogs.get(holder.mirror()); 672 synchronized (map) { 673 SpeculationLog log = map.get(this.metaspaceMethod); 674 if (log == null) { 675 log = new HotSpotSpeculationLog(); 676 map.put(metaspaceMethod, log); 677 } 678 return log; 679 } 680 } 681 682 public int intrinsicId() { 683 HotSpotVMConfig config = config(); 684 return UNSAFE.getChar(metaspaceMethod + config.methodIntrinsicIdOffset); 685 } 686 687 @Override 688 public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) { 689 assert !isConstructor(); 690 Method javaMethod = (Method) toJava(); 691 javaMethod.setAccessible(true); 692 693 Object[] objArguments = new Object[arguments.length]; 694 for (int i = 0; i < arguments.length; i++) { 695 objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]); 696 } 697 Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null; 698 699 try { 700 Object objResult = javaMethod.invoke(objReceiver, objArguments); 701 return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult); 702 703 } catch (IllegalAccessException | InvocationTargetException ex) { 704 throw new IllegalArgumentException(ex); 705 } 706 } 707 708 /** 709 * Allocates a compile id for this method by asking the VM for one. 710 * 711 * @param entryBCI entry bci 712 * @return compile id 713 */ 714 public int allocateCompileId(int entryBCI) { 715 return compilerToVM().allocateCompileId(this, entryBCI); 716 } 717 718 public boolean hasCodeAtLevel(int entryBCI, int level) { 719 if (entryBCI == config().invocationEntryBci) { 720 return hasCompiledCodeAtLevel(level); 721 } 722 return compilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); 723 } 724 }