# HG changeset patch # Parent 043c7708b8eb6f711d4b1b1bac91a6249b556aa6 diff --git a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -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; diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -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(); @@ -1063,6 +1055,7 @@ NEW_ARRAY, ARRAY_LOAD, ARRAY_STORE, + IDENTITY, NONE // no intrinsic associated } @@ -1100,6 +1093,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) { diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java --- a/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/share/classes/java/lang/invoke/MethodHandles.java @@ -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; @@ -2192,14 +2193,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; } /** diff --git a/src/share/classes/java/lang/invoke/MethodType.java b/src/share/classes/java/lang/invoke/MethodType.java --- a/src/share/classes/java/lang/invoke/MethodType.java +++ b/src/share/classes/java/lang/invoke/MethodType.java @@ -477,6 +477,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}. diff --git a/src/share/classes/sun/invoke/util/ValueConversions.java b/src/share/classes/sun/invoke/util/ValueConversions.java --- a/src/share/classes/sun/invoke/util/ValueConversions.java +++ b/src/share/classes/sun/invoke/util/ValueConversions.java @@ -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 identity(T x) { - return x; - } - - static 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; diff --git a/test/sun/invoke/util/ValueConversionsTest.java b/test/sun/invoke/util/ValueConversionsTest.java --- a/test/sun/invoke/util/ValueConversionsTest.java +++ b/test/sun/invoke/util/ValueConversionsTest.java @@ -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");