提交 2d125391 编写于 作者: V vlivanov

8050884: Intrinsify ValueConversions.identity() functions

Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
上级 b1cb58f0
...@@ -664,6 +664,10 @@ class InvokerBytecodeGenerator { ...@@ -664,6 +664,10 @@ class InvokerBytecodeGenerator {
case ARRAY_STORE: case ARRAY_STORE:
emitArrayStore(name); emitArrayStore(name);
continue; continue;
case IDENTITY:
assert(name.arguments.length == 1);
emitPushArguments(name);
continue;
case NONE: case NONE:
// no intrinsic associated // no intrinsic associated
break; break;
......
...@@ -303,14 +303,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -303,14 +303,6 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
} }
static MethodHandle makeReferenceIdentity(Class<?> refType) {
MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
Name[] names = arguments(1, lambdaType);
names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form);
}
static Object[] computeValueConversions(MethodType srcType, MethodType dstType, static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
boolean strict, boolean monobox) { boolean strict, boolean monobox) {
final int INARG_COUNT = srcType.parameterCount(); final int INARG_COUNT = srcType.parameterCount();
...@@ -1061,6 +1053,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1061,6 +1053,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
NEW_ARRAY, NEW_ARRAY,
ARRAY_LOAD, ARRAY_LOAD,
ARRAY_STORE, ARRAY_STORE,
IDENTITY,
NONE // no intrinsic associated NONE // no intrinsic associated
} }
...@@ -1098,6 +1091,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -1098,6 +1091,16 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return super.internalProperties() + return super.internalProperties() +
"\n& Intrinsic="+intrinsicName; "\n& Intrinsic="+intrinsicName;
} }
@Override
public MethodHandle asCollector(Class<?> arrayType, int arrayLength) {
if (intrinsicName == Intrinsic.IDENTITY) {
MethodType resultType = type().asCollectorType(arrayType, arrayLength);
MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength);
return newArray.asType(resultType);
}
return super.asCollector(arrayType, arrayLength);
}
} }
static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) { static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) {
......
...@@ -41,6 +41,7 @@ import sun.security.util.SecurityConstants; ...@@ -41,6 +41,7 @@ import sun.security.util.SecurityConstants;
import java.lang.invoke.LambdaForm.BasicType; import java.lang.invoke.LambdaForm.BasicType;
import static java.lang.invoke.LambdaForm.BasicType.*; import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleImpl.Intrinsic;
import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleNatives.Constants.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
...@@ -2199,14 +2200,29 @@ assert((int)twice.invokeExact(21) == 42); ...@@ -2199,14 +2200,29 @@ assert((int)twice.invokeExact(21) == 42);
*/ */
public static public static
MethodHandle identity(Class<?> type) { MethodHandle identity(Class<?> type) {
if (type == void.class) Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
throw newIllegalArgumentException("void type"); int pos = btw.ordinal();
else if (type == Object.class) MethodHandle ident = IDENTITY_MHS[pos];
return ValueConversions.identity(); if (ident == null) {
else if (type.isPrimitive()) ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
return ValueConversions.identity(Wrapper.forPrimitiveType(type)); }
else if (ident.type().returnType() == type)
return MethodHandleImpl.makeReferenceIdentity(type); return ident;
// something like identity(Foo.class); do not bother to intern these
assert(btw == Wrapper.OBJECT);
return makeIdentity(type);
}
private static final MethodHandle[] IDENTITY_MHS = new MethodHandle[Wrapper.values().length];
private static MethodHandle makeIdentity(Class<?> ptype) {
MethodType mtype = MethodType.methodType(ptype, ptype);
LambdaForm lform = LambdaForm.identityForm(BasicType.basicType(ptype));
return MethodHandleImpl.makeIntrinsic(mtype, lform, Intrinsic.IDENTITY);
}
synchronized private static MethodHandle setCachedMethodHandle(MethodHandle[] cache, int pos, MethodHandle value) {
// Simulate a CAS, to avoid racy duplication of results.
MethodHandle prev = cache[pos];
if (prev != null) return prev;
return cache[pos] = value;
} }
/** /**
......
...@@ -509,6 +509,32 @@ class MethodType implements java.io.Serializable { ...@@ -509,6 +509,32 @@ class MethodType implements java.io.Serializable {
return ptype; return ptype;
} }
/** Delete the last parameter type and replace it with arrayLength copies of the component type of arrayType.
* @param arrayType any array type
* @param arrayLength the number of parameter types to insert
* @return the resulting type
*/
/*non-public*/ MethodType asCollectorType(Class<?> arrayType, int arrayLength) {
assert(parameterCount() >= 1);
assert(lastParameterType().isAssignableFrom(arrayType));
MethodType res;
if (arrayType == Object[].class) {
res = genericMethodType(arrayLength);
if (rtype != Object.class) {
res = res.changeReturnType(rtype);
}
} else {
Class<?> elemType = arrayType.getComponentType();
assert(elemType != null);
res = methodType(rtype, Collections.nCopies(arrayLength, elemType));
}
if (ptypes.length == 1) {
return res;
} else {
return res.insertParameterTypes(0, parameterList().subList(0, ptypes.length-1));
}
}
/** /**
* Finds or creates a method type with some parameter types omitted. * Finds or creates a method type with some parameter types omitted.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}. * Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
......
...@@ -395,69 +395,11 @@ public class ValueConversions { ...@@ -395,69 +395,11 @@ public class ValueConversions {
throw new IllegalArgumentException("cannot find zero constant for " + wrap); throw new IllegalArgumentException("cannot find zero constant for " + wrap);
} }
/// Converting references to references. private static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY;
/**
* Identity function.
* @param x an arbitrary reference value
* @return the same value x
*/
static <T> T identity(T x) {
return x;
}
static <T> T[] identity(T[] x) {
return x;
}
/**
* Identity function on ints.
* @param x an arbitrary int value
* @return the same value x
*/
static int identity(int x) {
return x;
}
static byte identity(byte x) {
return x;
}
static short identity(short x) {
return x;
}
static boolean identity(boolean x) {
return x;
}
static char identity(char x) {
return x;
}
/**
* Identity function on longs.
* @param x an arbitrary long value
* @return the same value x
*/
static long identity(long x) {
return x;
}
static float identity(float x) {
return x;
}
static double identity(double x) {
return x;
}
private static final MethodHandle IDENTITY, CAST_REFERENCE, IGNORE, EMPTY;
static { static {
try { try {
MethodType idType = MethodType.genericMethodType(1); MethodType idType = MethodType.genericMethodType(1);
MethodType ignoreType = idType.changeReturnType(void.class); MethodType ignoreType = idType.changeReturnType(void.class);
IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType); CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType); IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1)); EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
...@@ -470,41 +412,6 @@ public class ValueConversions { ...@@ -470,41 +412,6 @@ public class ValueConversions {
return IGNORE; return IGNORE;
} }
public static MethodHandle identity() {
return IDENTITY;
}
public static MethodHandle identity(Class<?> type) {
if (!type.isPrimitive())
// Reference identity has been moved into MethodHandles:
return MethodHandles.identity(type);
return identity(Wrapper.findPrimitiveType(type));
}
public static MethodHandle identity(Wrapper wrap) {
WrapperCache cache = CONSTANT_FUNCTIONS[1];
MethodHandle mh = cache.get(wrap);
if (mh != null) {
return mh;
}
// slow path
MethodType type = MethodType.methodType(wrap.primitiveType());
if (wrap != Wrapper.VOID)
type = type.appendParameterTypes(wrap.primitiveType());
try {
mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
} catch (ReflectiveOperationException ex) {
mh = null;
}
if (mh == null && wrap == Wrapper.VOID) {
mh = EMPTY; // #(){} : #()void
}
if (mh != null) {
return cache.put(wrap, mh);
}
throw new IllegalArgumentException("cannot find identity for " + wrap);
}
/** Return a method that casts its second argument (an Object) to the given type (a Class). */ /** Return a method that casts its second argument (an Object) to the given type (a Class). */
public static MethodHandle cast() { public static MethodHandle cast() {
return CAST_REFERENCE; return CAST_REFERENCE;
......
...@@ -157,14 +157,6 @@ public class ValueConversionsTest { ...@@ -157,14 +157,6 @@ public class ValueConversionsTest {
} }
} }
@Test
public void testIdentity() throws Throwable {
MethodHandle id = ValueConversions.identity();
Object expResult = "foo";
Object result = id.invokeExact(expResult);
assertEquals(expResult, result);
}
@Test @Test
public void testConvert() throws Throwable { public void testConvert() throws Throwable {
for (long tval = 0, ctr = 0;;) { for (long tval = 0, ctr = 0;;) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册