--- /dev/null 2015-09-16 15:20:16.000000000 -0700 +++ new/src/java.base/share/classes/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotResolvedJavaMethodImpl.java 2015-09-16 15:20:15.000000000 -0700 @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jvmci.hotspot; + +import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; +import static jdk.internal.jvmci.hotspot.HotSpotResolvedJavaMethodImpl.Options.*; +import static jdk.internal.jvmci.hotspot.UnsafeAccess.UNSAFE; + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.jvmci.common.*; +import jdk.internal.jvmci.meta.*; +import jdk.internal.jvmci.options.*; + +/** + * Implementation of {@link JavaMethod} for resolved HotSpot methods. + */ +public final class HotSpotResolvedJavaMethodImpl extends HotSpotMethod implements HotSpotResolvedJavaMethod, HotSpotProxified, MetaspaceWrapperObject { + + public static class Options { + // @formatter:off + @Option(help = "", type = OptionType.Debug) + public static final OptionValue UseProfilingInformation = new OptionValue<>(true); + // @formatter:on + } + + /** + * Reference to metaspace Method object. + */ + private final long metaspaceMethod; + + private final HotSpotResolvedObjectTypeImpl holder; + private final HotSpotConstantPool constantPool; + private final HotSpotSignature signature; + private HotSpotMethodData methodData; + private byte[] code; + private Member toJavaCache; + + /** + * Gets the holder of a HotSpot metaspace method native object. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaType} corresponding to the holder of the + * {@code metaspaceMethod} + */ + private static HotSpotResolvedObjectTypeImpl getHolder(long metaspaceMethod) { + HotSpotVMConfig config = runtime().getConfig(); + final long metaspaceConstMethod = UNSAFE.getAddress(metaspaceMethod + config.methodConstMethodOffset); + final long metaspaceConstantPool = UNSAFE.getAddress(metaspaceConstMethod + config.constMethodConstantsOffset); + return runtime().getCompilerToVM().getResolvedJavaType(null, metaspaceConstantPool + config.constantPoolHolderOffset, false); + } + + /** + * Gets the JVMCI mirror from a HotSpot method. The VM is responsible for ensuring that the + * Method* is kept alive for the duration of this call and the + * {@link HotSpotJVMCIMetaAccessContext} keeps it alive after that. + * + * Called from the VM. + * + * @param metaspaceMethod a metaspace Method object + * @return the {@link ResolvedJavaMethod} corresponding to {@code metaspaceMethod} + */ + @SuppressWarnings("unused") + private static HotSpotResolvedJavaMethod fromMetaspace(long metaspaceMethod) { + HotSpotResolvedObjectTypeImpl holder = getHolder(metaspaceMethod); + return holder.createMethod(metaspaceMethod); + } + + HotSpotResolvedJavaMethodImpl(HotSpotResolvedObjectTypeImpl holder, long metaspaceMethod) { + // It would be too much work to get the method name here so we fill it in later. + super(null); + this.metaspaceMethod = metaspaceMethod; + this.holder = holder; + + HotSpotVMConfig config = runtime().getConfig(); + final long constMethod = getConstMethod(); + + /* + * Get the constant pool from the metaspace method. Some methods (e.g. intrinsics for + * signature-polymorphic method handle methods) have their own constant pool instead of the + * one from their holder. + */ + final long metaspaceConstantPool = UNSAFE.getAddress(constMethod + config.constMethodConstantsOffset); + if (metaspaceConstantPool == holder.getConstantPool().getMetaspaceConstantPool()) { + this.constantPool = holder.getConstantPool(); + } else { + this.constantPool = runtime().getCompilerToVM().getConstantPool(null, constMethod + config.constMethodConstantsOffset); + } + + final int nameIndex = UNSAFE.getChar(constMethod + config.constMethodNameIndexOffset); + this.name = constantPool.lookupUtf8(nameIndex); + + final int signatureIndex = UNSAFE.getChar(constMethod + config.constMethodSignatureIndexOffset); + this.signature = (HotSpotSignature) constantPool.lookupSignature(signatureIndex); + } + + /** + * Returns a pointer to this method's constant method data structure ( + * {@code Method::_constMethod}). This pointer isn't wrapped since it should be safe to use it + * within the context of this HotSpotResolvedJavaMethodImpl since the Method* and ConstMethod* + * are kept alive as a pair. + * + * @return pointer to this method's ConstMethod + */ + private long getConstMethod() { + assert metaspaceMethod != 0; + return UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodConstMethodOffset); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof HotSpotResolvedJavaMethodImpl) { + HotSpotResolvedJavaMethodImpl that = (HotSpotResolvedJavaMethodImpl) obj; + return that.metaspaceMethod == metaspaceMethod; + } + return false; + } + + @Override + public int hashCode() { + return (int) metaspaceMethod; + } + + /** + * Returns this method's flags ({@code Method::_flags}). + * + * @return flags of this method + */ + private int getFlags() { + return UNSAFE.getByte(metaspaceMethod + runtime().getConfig().methodFlagsOffset); + } + + /** + * Returns this method's constant method flags ({@code ConstMethod::_flags}). + * + * @return flags of this method's ConstMethod + */ + private int getConstMethodFlags() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodFlagsOffset); + } + + @Override + public HotSpotResolvedObjectTypeImpl getDeclaringClass() { + return holder; + } + + /** + * Gets the address of the C++ Method object for this method. + */ + public JavaConstant getMetaspaceMethodConstant() { + return HotSpotMetaspaceConstantImpl.forMetaspaceObject(getHostWordKind(), metaspaceMethod, this, false); + } + + public long getMetaspaceMethod() { + return metaspaceMethod; + } + + public long getMetaspacePointer() { + return getMetaspaceMethod(); + } + + @Override + public JavaConstant getEncoding() { + return getMetaspaceMethodConstant(); + } + + /** + * Gets the complete set of modifiers for this method which includes the JVM specification + * modifiers as well as the HotSpot internal modifiers. + */ + public int getAllModifiers() { + return UNSAFE.getInt(metaspaceMethod + runtime().getConfig().methodAccessFlagsOffset); + } + + @Override + public int getModifiers() { + return getAllModifiers() & ModifiersProvider.jvmMethodModifiers(); + } + + @Override + public boolean canBeStaticallyBound() { + return (isFinal() || isPrivate() || isStatic() || holder.isLeaf()) && isConcrete(); + } + + @Override + public byte[] getCode() { + if (getCodeSize() == 0) { + return null; + } + if (code == null && holder.isLinked()) { + code = runtime().getCompilerToVM().getBytecode(this); + assert code.length == getCodeSize() : "expected: " + getCodeSize() + ", actual: " + code.length; + } + return code; + } + + @Override + public int getCodeSize() { + return UNSAFE.getChar(getConstMethod() + runtime().getConfig().constMethodCodeSizeOffset); + } + + @Override + public ExceptionHandler[] getExceptionHandlers() { + final boolean hasExceptionTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasExceptionTable) != 0; + if (!hasExceptionTable) { + return new ExceptionHandler[0]; + } + + HotSpotVMConfig config = runtime().getConfig(); + final int exceptionTableLength = runtime().getCompilerToVM().getExceptionTableLength(this); + ExceptionHandler[] handlers = new ExceptionHandler[exceptionTableLength]; + long exceptionTableElement = runtime().getCompilerToVM().getExceptionTableStart(this); + + for (int i = 0; i < exceptionTableLength; i++) { + final int startPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementStartPcOffset); + final int endPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementEndPcOffset); + final int handlerPc = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementHandlerPcOffset); + int catchTypeIndex = UNSAFE.getChar(exceptionTableElement + config.exceptionTableElementCatchTypeIndexOffset); + + JavaType catchType; + if (catchTypeIndex == 0) { + catchType = null; + } else { + final int opcode = -1; // opcode is not used + catchType = constantPool.lookupType(catchTypeIndex, opcode); + + // Check for Throwable which catches everything. + if (catchType instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl resolvedType = (HotSpotResolvedObjectTypeImpl) catchType; + if (resolvedType.mirror() == Throwable.class) { + catchTypeIndex = 0; + catchType = null; + } + } + } + handlers[i] = new ExceptionHandler(startPc, endPc, handlerPc, catchTypeIndex, catchType); + + // Go to the next ExceptionTableElement + exceptionTableElement += config.exceptionTableElementSize; + } + + return handlers; + } + + /** + * Returns true if this method has a {@code CallerSensitive} annotation. + * + * @return true if CallerSensitive annotation present, false otherwise + */ + public boolean isCallerSensitive() { + return (getFlags() & runtime().getConfig().methodFlagsCallerSensitive) != 0; + } + + /** + * Returns true if this method has a {@code ForceInline} annotation. + * + * @return true if ForceInline annotation present, false otherwise + */ + public boolean isForceInline() { + return (getFlags() & runtime().getConfig().methodFlagsForceInline) != 0; + } + + /** + * Returns true if this method has a {@code DontInline} annotation. + * + * @return true if DontInline annotation present, false otherwise + */ + public boolean isDontInline() { + return (getFlags() & runtime().getConfig().methodFlagsDontInline) != 0; + } + + /** + * Manually adds a DontInline annotation to this method. + */ + public void setNotInlineable() { + runtime().getCompilerToVM().doNotInlineOrCompile(this); + } + + /** + * Returns true if this method is one of the special methods that is ignored by security stack + * walks. + * + * @return true if special method ignored by security stack walks, false otherwise + */ + public boolean ignoredBySecurityStackWalk() { + return runtime().getCompilerToVM().methodIsIgnoredBySecurityStackWalk(this); + } + + public boolean hasBalancedMonitors() { + HotSpotVMConfig config = runtime().getConfig(); + final int modifiers = getAllModifiers(); + + // Method has no monitorenter/exit bytecodes. + if ((modifiers & config.jvmAccHasMonitorBytecodes) == 0) { + return false; + } + + // Check to see if a previous compilation computed the monitor-matching analysis. + if ((modifiers & config.jvmAccMonitorMatch) != 0) { + return true; + } + + // This either happens only once if monitors are balanced or very rarely multiple-times. + return runtime().getCompilerToVM().hasBalancedMonitors(this); + } + + @Override + public boolean isClassInitializer() { + return "".equals(name) && isStatic(); + } + + @Override + public boolean isConstructor() { + return "".equals(name) && !isStatic(); + } + + @Override + public int getMaxLocals() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getChar(getConstMethod() + config.methodMaxLocalsOffset); + } + + @Override + public int getMaxStackSize() { + if (isAbstract() || isNative()) { + return 0; + } + HotSpotVMConfig config = runtime().getConfig(); + return config.extraStackEntries + UNSAFE.getChar(getConstMethod() + config.constMethodMaxStackOffset); + } + + @Override + public StackTraceElement asStackTraceElement(int bci) { + if (bci < 0 || bci >= getCodeSize()) { + // HotSpot code can only construct stack trace elements for valid bcis + StackTraceElement ste = runtime().getCompilerToVM().getStackTraceElement(this, 0); + return new StackTraceElement(ste.getClassName(), ste.getMethodName(), ste.getFileName(), -1); + } + return runtime().getCompilerToVM().getStackTraceElement(this, bci); + } + + public ResolvedJavaMethod uniqueConcreteMethod(HotSpotResolvedObjectType receiver) { + if (receiver.isInterface()) { + // Cannot trust interfaces. Because of: + // interface I { void foo(); } + // class A { public void foo() {} } + // class B extends A implements I { } + // class C extends B { public void foo() { } } + // class D extends B { } + // Would lead to identify C.foo() as the unique concrete method for I.foo() without + // seeing A.foo(). + return null; + } + return runtime().getCompilerToVM().findUniqueConcreteMethod(((HotSpotResolvedObjectTypeImpl) receiver), this); + } + + @Override + public HotSpotSignature getSignature() { + return signature; + } + + /** + * Gets the value of {@code Method::_code}. + * + * @return the value of {@code Method::_code} + */ + private long getCompiledCode() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getAddress(metaspaceMethod + config.methodCodeOffset); + } + + /** + * Returns whether this method has compiled code. + * + * @return true if this method has compiled code, false otherwise + */ + public boolean hasCompiledCode() { + return getCompiledCode() != 0L; + } + + /** + * @param level + * @return true if the currently installed code was generated at {@code level}. + */ + public boolean hasCompiledCodeAtLevel(int level) { + long compiledCode = getCompiledCode(); + if (compiledCode != 0) { + return UNSAFE.getInt(compiledCode + runtime().getConfig().nmethodCompLevelOffset) == level; + } + return false; + } + + private static final String TraceMethodDataFilter = System.getProperty("jvmci.traceMethodDataFilter"); + + @Override + public ProfilingInfo getProfilingInfo(boolean includeNormal, boolean includeOSR) { + ProfilingInfo info; + + if (UseProfilingInformation.getValue() && methodData == null) { + long metaspaceMethodData = UNSAFE.getAddress(metaspaceMethod + runtime().getConfig().methodDataOffset); + if (metaspaceMethodData != 0) { + methodData = new HotSpotMethodData(metaspaceMethodData, this); + if (TraceMethodDataFilter != null && this.format("%H.%n").contains(TraceMethodDataFilter)) { + System.out.println("Raw method data for " + this.format("%H.%n(%p)") + ":"); + System.out.println(methodData.toString()); + } + } + } + + if (methodData == null || (!methodData.hasNormalData() && !methodData.hasExtraData())) { + // Be optimistic and return false for exceptionSeen. A methodDataOop is allocated in + // case of a deoptimization. + info = DefaultProfilingInfo.get(TriState.FALSE); + } else { + info = new HotSpotProfilingInfo(methodData, this, includeNormal, includeOSR); + } + return info; + } + + @Override + public void reprofile() { + runtime().getCompilerToVM().reprofile(this); + } + + @Override + public ConstantPool getConstantPool() { + return constantPool; + } + + @Override + public Annotation[][] getParameterAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getParameterAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getParameterAnnotations(); + } + + @Override + public Annotation[] getAnnotations() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? new Annotation[0] : javaConstructor.getAnnotations(); + } + Method javaMethod = toJava(); + return javaMethod == null ? new Annotation[0] : javaMethod.getAnnotations(); + } + + @Override + public T getAnnotation(Class annotationClass) { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getAnnotation(annotationClass); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getAnnotation(annotationClass); + } + + public boolean isDefault() { + if (isConstructor()) { + return false; + } + // Copied from java.lang.Method.isDefault() + int mask = Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC; + return ((getModifiers() & mask) == Modifier.PUBLIC) && getDeclaringClass().isInterface(); + } + + @Override + public Type[] getGenericParameterTypes() { + if (isConstructor()) { + Constructor javaConstructor = toJavaConstructor(); + return javaConstructor == null ? null : javaConstructor.getGenericParameterTypes(); + } + Method javaMethod = toJava(); + return javaMethod == null ? null : javaMethod.getGenericParameterTypes(); + } + + public Class[] signatureToTypes() { + Signature sig = getSignature(); + int count = sig.getParameterCount(false); + Class[] result = new Class[count]; + for (int i = 0; i < result.length; ++i) { + JavaType parameterType = sig.getParameterType(i, holder); + HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder); + result[i] = resolvedParameterType.mirror(); + } + return result; + } + + private Method toJava() { + if (toJavaCache != null) { + return (Method) toJavaCache; + } + try { + Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + private Constructor toJavaConstructor() { + if (toJavaCache != null) { + return (Constructor) toJavaCache; + } + try { + Constructor result = holder.mirror().getDeclaredConstructor(signatureToTypes()); + toJavaCache = result; + return result; + } catch (NoSuchMethodException | NoClassDefFoundError e) { + return null; + } + } + + @Override + public boolean canBeInlined() { + if (isDontInline()) { + return false; + } + return runtime().getCompilerToVM().canInlineMethod(this); + } + + @Override + public boolean shouldBeInlined() { + if (isForceInline()) { + return true; + } + return runtime().getCompilerToVM().shouldInlineMethod(this); + } + + @Override + public LineNumberTable getLineNumberTable() { + final boolean hasLineNumberTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLineNumberTable) != 0; + if (!hasLineNumberTable) { + return null; + } + + long[] values = runtime().getCompilerToVM().getLineNumberTable(this); + if (values == null || values.length == 0) { + // Empty table so treat is as non-existent + return null; + } + assert values.length % 2 == 0; + int[] bci = new int[values.length / 2]; + int[] line = new int[values.length / 2]; + + for (int i = 0; i < values.length / 2; i++) { + bci[i] = (int) values[i * 2]; + line[i] = (int) values[i * 2 + 1]; + } + + return new LineNumberTableImpl(line, bci); + } + + @Override + public LocalVariableTable getLocalVariableTable() { + final boolean hasLocalVariableTable = (getConstMethodFlags() & runtime().getConfig().constMethodHasLocalVariableTable) != 0; + if (!hasLocalVariableTable) { + return null; + } + + HotSpotVMConfig config = runtime().getConfig(); + long localVariableTableElement = runtime().getCompilerToVM().getLocalVariableTableStart(this); + final int localVariableTableLength = runtime().getCompilerToVM().getLocalVariableTableLength(this); + Local[] locals = new Local[localVariableTableLength]; + + for (int i = 0; i < localVariableTableLength; i++) { + final int startBci = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementStartBciOffset); + final int endBci = startBci + UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementLengthOffset); + final int nameCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementNameCpIndexOffset); + final int typeCpIndex = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementDescriptorCpIndexOffset); + final int slot = UNSAFE.getChar(localVariableTableElement + config.localVariableTableElementSlotOffset); + + String localName = getConstantPool().lookupUtf8(nameCpIndex); + String localType = getConstantPool().lookupUtf8(typeCpIndex); + + locals[i] = new LocalImpl(localName, runtime().lookupType(localType, holder, false), startBci, endBci, slot); + + // Go to the next LocalVariableTableElement + localVariableTableElement += config.localVariableTableElementSize; + } + + return new LocalVariableTableImpl(locals); + } + + /** + * Returns the offset of this method into the v-table. The method must have a v-table entry as + * indicated by {@link #isInVirtualMethodTable(ResolvedJavaType)}, otherwise an exception is + * thrown. + * + * @return the offset of this method into the v-table + */ + public int vtableEntryOffset(ResolvedJavaType resolved) { + if (!isInVirtualMethodTable(resolved)) { + throw new JVMCIError("%s does not have a vtable entry in type %s", this, resolved); + } + HotSpotVMConfig config = runtime().getConfig(); + final int vtableIndex = getVtableIndex((HotSpotResolvedObjectTypeImpl) resolved); + return config.instanceKlassVtableStartOffset() + vtableIndex * config.vtableEntrySize + config.vtableEntryMethodOffset; + } + + @Override + public boolean isInVirtualMethodTable(ResolvedJavaType resolved) { + if (resolved instanceof HotSpotResolvedObjectTypeImpl) { + HotSpotResolvedObjectTypeImpl hotspotResolved = (HotSpotResolvedObjectTypeImpl) resolved; + int vtableIndex = getVtableIndex(hotspotResolved); + return vtableIndex >= 0 && vtableIndex < hotspotResolved.getVtableLength(); + } + return false; + } + + private int getVtableIndex(HotSpotResolvedObjectTypeImpl resolved) { + if (!holder.isLinked()) { + return runtime().getConfig().invalidVtableIndex; + } + if (holder.isInterface()) { + if (resolved.isInterface()) { + return runtime().getConfig().invalidVtableIndex; + } + return getVtableIndexForInterface(resolved); + } + return getVtableIndex(); + } + + /** + * Returns this method's virtual table index. + * + * @return virtual table index + */ + private int getVtableIndex() { + assert !holder.isInterface(); + HotSpotVMConfig config = runtime().getConfig(); + int result = UNSAFE.getInt(metaspaceMethod + config.methodVtableIndexOffset); + assert result >= config.nonvirtualVtableIndex : "must be linked"; + return result; + } + + private int getVtableIndexForInterface(ResolvedJavaType resolved) { + HotSpotResolvedObjectTypeImpl hotspotType = (HotSpotResolvedObjectTypeImpl) resolved; + return runtime().getCompilerToVM().getVtableIndexForInterface(hotspotType, this); + } + + /** + * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type + * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is + * never moves and b) we never read from it. + *

+ * One implication is that we will preserve {@link SpeculationLog}s for methods that have been + * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot + * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods + * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal). + */ + private static final ClassValue> SpeculationLogs = new ClassValue>() { + @Override + protected Map computeValue(java.lang.Class type) { + return new HashMap<>(4); + } + }; + + public SpeculationLog getSpeculationLog() { + Map map = SpeculationLogs.get(holder.mirror()); + synchronized (map) { + SpeculationLog log = map.get(this.metaspaceMethod); + if (log == null) { + log = new HotSpotSpeculationLog(); + map.put(metaspaceMethod, log); + } + return log; + } + } + + public int intrinsicId() { + HotSpotVMConfig config = runtime().getConfig(); + return UNSAFE.getByte(metaspaceMethod + config.methodIntrinsicIdOffset) & 0xff; + } + + @Override + public JavaConstant invoke(JavaConstant receiver, JavaConstant[] arguments) { + assert !isConstructor(); + Method javaMethod = toJava(); + javaMethod.setAccessible(true); + + Object[] objArguments = new Object[arguments.length]; + for (int i = 0; i < arguments.length; i++) { + objArguments[i] = HotSpotObjectConstantImpl.asBoxedValue(arguments[i]); + } + Object objReceiver = receiver != null && !receiver.isNull() ? ((HotSpotObjectConstantImpl) receiver).object() : null; + + try { + Object objResult = javaMethod.invoke(objReceiver, objArguments); + return javaMethod.getReturnType() == void.class ? null : HotSpotObjectConstantImpl.forBoxedValue(getSignature().getReturnKind(), objResult); + + } catch (IllegalAccessException | InvocationTargetException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * Allocates a compile id for this method by asking the VM for one. + * + * @param entryBCI entry bci + * @return compile id + */ + public int allocateCompileId(int entryBCI) { + return runtime().getCompilerToVM().allocateCompileId(this, entryBCI); + } + + public boolean hasCodeAtLevel(int entryBCI, int level) { + if (entryBCI == runtime().getConfig().invocationEntryBci) { + return hasCompiledCodeAtLevel(level); + } + return runtime().getCompilerToVM().hasCompiledCodeForOSR(this, entryBCI, level); + } +}