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