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