8164214: [JVMCI] include VarHandle in signature polymorphic method test

Reviewed-by: kvn, twisti, iveresov, psandoz
This commit is contained in:
Doug Simon 2016-08-23 15:16:45 +00:00
parent 913622a641
commit 00979c250a
5 changed files with 81 additions and 75 deletions

View File

@ -244,16 +244,20 @@ final class CompilerToVM {
native void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi); native void resolveInvokeDynamicInPool(HotSpotConstantPool constantPool, int cpi);
/** /**
* Ensures that the type referenced by the entry for a * If {@code cpi} denotes an entry representing a
* <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">signature * <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">signature
* polymorphic</a> method at index {@code cpi} in {@code constantPool} is loaded and * polymorphic</a> method, this method ensures that the type referenced by the entry is loaded
* initialized. * and initialized. It {@code cpi} does not denote a signature polymorphic method, this method
* * does nothing.
* The behavior of this method is undefined if {@code cpi} does not denote an entry representing
* a signature polymorphic method.
*/ */
native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi); native void resolveInvokeHandleInPool(HotSpotConstantPool constantPool, int cpi);
/**
* Gets the list of type names (in the format of {@link JavaType#getName()}) denoting the
* classes that define signature polymorphic methods.
*/
native String[] getSignaturePolymorphicHolders();
/** /**
* Gets the resolved type denoted by the entry at index {@code cpi} in {@code constantPool}. * Gets the resolved type denoted by the entry at index {@code cpi} in {@code constantPool}.
* *
@ -610,4 +614,5 @@ final class CompilerToVM {
* @return the number of bytes required for deoptimization of this frame state * @return the number of bytes required for deoptimization of this frame state
*/ */
native int interpreterFrameSize(BytecodeFrame frame); native int interpreterFrameSize(BytecodeFrame frame);
} }

View File

@ -282,7 +282,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return constant pool tag * @return constant pool tag
*/ */
private JVM_CONSTANT getTagAt(int index) { private JVM_CONSTANT getTagAt(int index) {
assertBounds(index); assert checkBounds(index);
HotSpotVMConfig config = config(); HotSpotVMConfig config = config();
final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset); final long metaspaceConstantPoolTags = UNSAFE.getAddress(getMetaspaceConstantPool() + config.constantPoolTagsOffset);
final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); final int tag = UNSAFE.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index);
@ -299,7 +299,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return constant pool entry * @return constant pool entry
*/ */
private long getEntryAt(int index) { private long getEntryAt(int index) {
assertBounds(index); assert checkBounds(index);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
return UNSAFE.getAddress(getMetaspaceConstantPool() + config().constantPoolSize + offset); return UNSAFE.getAddress(getMetaspaceConstantPool() + config().constantPoolSize + offset);
} }
@ -311,7 +311,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return integer constant pool entry at index * @return integer constant pool entry at index
*/ */
private int getIntAt(int index) { private int getIntAt(int index) {
assertTag(index, JVM_CONSTANT.Integer); assert checkTag(index, JVM_CONSTANT.Integer);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset);
} }
@ -323,7 +323,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return long constant pool entry * @return long constant pool entry
*/ */
private long getLongAt(int index) { private long getLongAt(int index) {
assertTag(index, JVM_CONSTANT.Long); assert checkTag(index, JVM_CONSTANT.Long);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + offset); return UNSAFE.getLong(getMetaspaceConstantPool() + config().constantPoolSize + offset);
} }
@ -335,7 +335,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return float constant pool entry * @return float constant pool entry
*/ */
private float getFloatAt(int index) { private float getFloatAt(int index) {
assertTag(index, JVM_CONSTANT.Float); assert checkTag(index, JVM_CONSTANT.Float);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + offset); return UNSAFE.getFloat(getMetaspaceConstantPool() + config().constantPoolSize + offset);
} }
@ -347,7 +347,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return float constant pool entry * @return float constant pool entry
*/ */
private double getDoubleAt(int index) { private double getDoubleAt(int index) {
assertTag(index, JVM_CONSTANT.Double); assert checkTag(index, JVM_CONSTANT.Double);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + offset); return UNSAFE.getDouble(getMetaspaceConstantPool() + config().constantPoolSize + offset);
} }
@ -359,7 +359,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return {@code JVM_CONSTANT_NameAndType} constant pool entry * @return {@code JVM_CONSTANT_NameAndType} constant pool entry
*/ */
private int getNameAndTypeAt(int index) { private int getNameAndTypeAt(int index) {
assertTag(index, JVM_CONSTANT.NameAndType); assert checkTag(index, JVM_CONSTANT.NameAndType);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); return UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset);
} }
@ -441,7 +441,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* @return klass reference index * @return klass reference index
*/ */
private int getUncachedKlassRefIndexAt(int index) { private int getUncachedKlassRefIndexAt(int index) {
assertTagIsFieldOrMethod(index); assert checkTagIsFieldOrMethod(index);
int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize; int offset = index * runtime().getHostJVMCIBackend().getTarget().wordSize;
final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset); final int refIndex = UNSAFE.getInt(getMetaspaceConstantPool() + config().constantPoolSize + offset);
// klass ref index is in the low 16-bits. // klass ref index is in the low 16-bits.
@ -449,23 +449,27 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
} }
/** /**
* Asserts that the constant pool index {@code index} is in the bounds of the constant pool. * Checks that the constant pool index {@code index} is in the bounds of the constant pool.
* *
* @param index constant pool index * @param index constant pool index
* @throws AssertionError if the check fails
*/ */
private void assertBounds(int index) { private boolean checkBounds(int index) {
assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length();
return true;
} }
/** /**
* Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. * Checks that the constant pool tag at index {@code index} is equal to {@code tag}.
* *
* @param index constant pool index * @param index constant pool index
* @param tag expected tag * @param tag expected tag
* @throws AssertionError if the check fails
*/ */
private void assertTag(int index, JVM_CONSTANT tag) { private boolean checkTag(int index, JVM_CONSTANT tag) {
final JVM_CONSTANT tagAt = getTagAt(index); final JVM_CONSTANT tagAt = getTagAt(index);
assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag;
return true;
} }
/** /**
@ -473,10 +477,12 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
* or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}.
* *
* @param index constant pool index * @param index constant pool index
* @throws AssertionError if the check fails
*/ */
private void assertTagIsFieldOrMethod(int index) { private boolean checkTagIsFieldOrMethod(int index) {
final JVM_CONSTANT tagAt = getTagAt(index); final JVM_CONSTANT tagAt = getTagAt(index);
assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt;
return true;
} }
@Override @Override
@ -523,7 +529,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
@Override @Override
public String lookupUtf8(int cpi) { public String lookupUtf8(int cpi) {
assertTag(cpi, JVM_CONSTANT.Utf8); assert checkTag(cpi, JVM_CONSTANT.Utf8);
return compilerToVM().getSymbol(getEntryAt(cpi)); return compilerToVM().getSymbol(getEntryAt(cpi));
} }
@ -690,11 +696,10 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
UNSAFE.ensureClassInitialized(klass); UNSAFE.ensureClassInitialized(klass);
} }
if (tag == JVM_CONSTANT.MethodRef) { if (tag == JVM_CONSTANT.MethodRef) {
if (Bytecodes.isInvokeHandleAlias(opcode)) { if (Bytecodes.isInvokeHandleAlias(opcode) && isSignaturePolymorphicHolder(type)) {
final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode);
if (isInvokeHandle(methodRefCacheIndex, type)) { assert checkTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef);
compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex); compilerToVM().resolveInvokeHandleInPool(this, methodRefCacheIndex);
}
} }
} }
@ -708,11 +713,26 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
// nothing // nothing
break; break;
} }
} }
private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { // Lazily initialized.
assertTag(compilerToVM().constantPoolRemapInstructionOperandFromCache(this, methodRefCacheIndex), JVM_CONSTANT.MethodRef); private static String[] signaturePolymorphicHolders;
return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameOf(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess());
/**
* Determines if {@code type} contains signature polymorphic methods.
*/
private static boolean isSignaturePolymorphicHolder(final HotSpotResolvedObjectTypeImpl type) {
String name = type.getName();
if (signaturePolymorphicHolders == null) {
signaturePolymorphicHolders = compilerToVM().getSignaturePolymorphicHolders();
}
for (String holder : signaturePolymorphicHolders) {
if (name.equals(holder)) {
return true;
}
}
return false;
} }
@Override @Override

View File

@ -23,7 +23,6 @@
package jdk.vm.ci.meta; package jdk.vm.ci.meta;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -330,22 +329,4 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP
} }
SpeculationLog getSpeculationLog(); SpeculationLog getSpeculationLog();
/**
* Determines if the method identified by its holder and name is a
* <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.9">signature
* polymorphic</a> method.
*/
static boolean isSignaturePolymorphic(JavaType holder, String name, MetaAccessProvider metaAccess) {
if (!holder.getName().equals("Ljava/lang/invoke/MethodHandle;")) {
return false;
}
ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class);
Signature signature = metaAccess.parseMethodDescriptor("([Ljava/lang/Object;)Ljava/lang/Object;");
ResolvedJavaMethod method = methodHandleType.findMethod(name, signature);
if (method == null) {
return false;
}
return method.isNative() && method.isVarArgs();
}
} }

View File

@ -1266,10 +1266,23 @@ C2V_END
C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index)) C2V_VMENTRY(void, resolveInvokeHandleInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index))
constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool); constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool);
CallInfo callInfo; KlassHandle holder = cp->klass_ref_at(index, CHECK);
LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokehandle, CHECK); Symbol* name = cp->name_ref_at(index);
ConstantPoolCacheEntry* cp_cache_entry = cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index)); if (MethodHandles::is_signature_polymorphic_name(holder(), name)) {
cp_cache_entry->set_method_handle(cp, callInfo); CallInfo callInfo;
LinkResolver::resolve_invoke(callInfo, Handle(), cp, index, Bytecodes::_invokehandle, CHECK);
ConstantPoolCacheEntry* cp_cache_entry = cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index));
cp_cache_entry->set_method_handle(cp, callInfo);
}
C2V_END
C2V_VMENTRY(jobject, getSignaturePolymorphicHolders, (JNIEnv*, jobject))
objArrayHandle holders = oopFactory::new_objArray(SystemDictionary::String_klass(), 2, CHECK_NULL);
Handle mh = java_lang_String::create_from_str("Ljava/lang/invoke/MethodHandle;", CHECK_NULL);
Handle vh = java_lang_String::create_from_str("Ljava/lang/invoke/VarHandle;", CHECK_NULL);
holders->obj_at_put(0, mh());
holders->obj_at_put(1, vh());
return JNIHandles::make_local(THREAD, holders());
C2V_END C2V_END
C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject)) C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv*, jobject))
@ -1511,6 +1524,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)}, {CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)},
{CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeHandleInPool)}, {CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeHandleInPool)},
{CC "resolveMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(resolveMethod)}, {CC "resolveMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(resolveMethod)},
{CC "getSignaturePolymorphicHolders", CC "()[" STRING, FN_PTR(getSignaturePolymorphicHolders)},
{CC "getVtableIndexForInterfaceMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD ")I", FN_PTR(getVtableIndexForInterfaceMethod)}, {CC "getVtableIndexForInterfaceMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD ")I", FN_PTR(getVtableIndexForInterfaceMethod)},
{CC "getClassInitializer", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)}, {CC "getClassInitializer", CC "(" HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(getClassInitializer)},
{CC "hasFinalizableSubclass", CC "(" HS_RESOLVED_KLASS ")Z", FN_PTR(hasFinalizableSubclass)}, {CC "hasFinalizableSubclass", CC "(" HS_RESOLVED_KLASS ")Z", FN_PTR(hasFinalizableSubclass)},

View File

@ -33,19 +33,16 @@
package jdk.vm.ci.runtime.test; package jdk.vm.ci.runtime.test;
import jdk.vm.ci.meta.ConstantPool; import static org.junit.Assert.assertEquals;
import jdk.vm.ci.meta.ExceptionHandler; import static org.junit.Assert.assertFalse;
import jdk.vm.ci.meta.ResolvedJavaMethod; import static org.junit.Assert.assertNotNull;
import jdk.vm.ci.meta.ResolvedJavaType; import static org.junit.Assert.assertTrue;
import org.junit.Assert;
import org.junit.Test;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -57,10 +54,13 @@ import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.junit.Assert.assertEquals; import org.junit.Assert;
import static org.junit.Assert.assertFalse; import org.junit.Test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ExceptionHandler;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
/** /**
* Tests for {@link ResolvedJavaMethod}. * Tests for {@link ResolvedJavaMethod}.
@ -407,20 +407,6 @@ public class TestResolvedJavaMethod extends MethodUniverse {
} }
} }
@Test
public void isSignaturePolymorphicTest() {
ResolvedJavaType methodHandleType = metaAccess.lookupJavaType(MethodHandle.class);
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeExact", metaAccess));
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invoke", metaAccess));
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "invokeBasic", metaAccess));
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToVirtual", metaAccess));
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToStatic", metaAccess));
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToSpecial", metaAccess));
assertTrue(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "linkToInterface", metaAccess));
assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(methodHandleType, "type", metaAccess));
assertFalse(ResolvedJavaMethod.isSignaturePolymorphic(metaAccess.lookupJavaType(Object.class), "toString", metaAccess));
}
/** /**
* All public non-final methods should be available in the vtable. * All public non-final methods should be available in the vtable.
*/ */