8050884: Intrinsify ValueConversions.identity() functions
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Wed Sep 10 19:19:50 2014 +0400
@@ -664,6 +664,10 @@
case ARRAY_STORE:
emitArrayStore(name);
continue;
+ case IDENTITY:
+ assert(name.arguments.length == 1);
+ emitPushArguments(name);
+ continue;
case NONE:
// no intrinsic associated
break;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:50 2014 +0400
@@ -303,14 +303,6 @@
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,
boolean strict, boolean monobox) {
final int INARG_COUNT = srcType.parameterCount();
@@ -1061,6 +1053,7 @@
NEW_ARRAY,
ARRAY_LOAD,
ARRAY_STORE,
+ IDENTITY,
NONE // no intrinsic associated
}
@@ -1098,6 +1091,16 @@
return super.internalProperties() +
"\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) {
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java Wed Sep 10 19:19:50 2014 +0400
@@ -41,6 +41,7 @@
import java.lang.invoke.LambdaForm.BasicType;
import static java.lang.invoke.LambdaForm.BasicType.*;
import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandleImpl.Intrinsic;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
import java.util.concurrent.ConcurrentHashMap;
@@ -2198,14 +2199,29 @@
*/
public static
MethodHandle identity(Class<?> type) {
- if (type == void.class)
- throw newIllegalArgumentException("void type");
- else if (type == Object.class)
- return ValueConversions.identity();
- else if (type.isPrimitive())
- return ValueConversions.identity(Wrapper.forPrimitiveType(type));
- else
- return MethodHandleImpl.makeReferenceIdentity(type);
+ Wrapper btw = (type.isPrimitive() ? Wrapper.forPrimitiveType(type) : Wrapper.OBJECT);
+ int pos = btw.ordinal();
+ MethodHandle ident = IDENTITY_MHS[pos];
+ if (ident == null) {
+ ident = setCachedMethodHandle(IDENTITY_MHS, pos, makeIdentity(btw.primitiveType()));
+ }
+ if (ident.type().returnType() == 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;
}
/**
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java Wed Sep 10 19:19:50 2014 +0400
@@ -510,6 +510,32 @@
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.
* Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[]) methodType}.
--- a/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java Wed Sep 10 19:19:50 2014 +0400
@@ -395,69 +395,11 @@
throw new IllegalArgumentException("cannot find zero constant for " + wrap);
}
- /// Converting references to references.
-
- /**
- * 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;
+ private static final MethodHandle CAST_REFERENCE, IGNORE, EMPTY;
static {
try {
MethodType idType = MethodType.genericMethodType(1);
MethodType ignoreType = idType.changeReturnType(void.class);
- IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
@@ -470,41 +412,6 @@
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). */
public static MethodHandle cast() {
return CAST_REFERENCE;
--- a/jdk/test/sun/invoke/util/ValueConversionsTest.java Wed Sep 10 19:19:50 2014 +0400
+++ b/jdk/test/sun/invoke/util/ValueConversionsTest.java Wed Sep 10 19:19:50 2014 +0400
@@ -158,14 +158,6 @@
}
@Test
- public void testIdentity() throws Throwable {
- MethodHandle id = ValueConversions.identity();
- Object expResult = "foo";
- Object result = id.invokeExact(expResult);
- assertEquals(expResult, result);
- }
-
- @Test
public void testConvert() throws Throwable {
for (long tval = 0, ctr = 0;;) {
if (++ctr > 99999) throw new AssertionError("too many test values");