jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 23038 bb8b3b23af3a
parent 21649 1aca56f8780c
child 23039 6ee70bc18809
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Feb 28 17:01:12 2014 -0500
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Sat Mar 01 02:05:53 2014 +0400
@@ -27,7 +27,6 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import sun.invoke.empty.Empty;
@@ -482,12 +481,26 @@
      * Factored in an inner class to delay initialization until first usage.
      */
     private static class Lazy {
+        private static final Class<?> MHI = MethodHandleImpl.class;
+
         static final NamedFunction NF_checkSpreadArgument;
+        static final NamedFunction NF_guardWithCatch;
+        static final NamedFunction NF_selectAlternative;
+        static final NamedFunction NF_throwException;
+
         static {
             try {
-                NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
-                        .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
+                NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
+                NF_guardWithCatch      = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
+                                                                                 MethodHandle.class, Object[].class));
+                NF_selectAlternative   = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
+                                                                                 MethodHandle.class));
+                NF_throwException      = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
+
                 NF_checkSpreadArgument.resolve();
+                NF_guardWithCatch.resolve();
+                NF_selectAlternative.resolve();
+                NF_throwException.resolve();
             } catch (ReflectiveOperationException ex) {
                 throw newInternalError(ex);
             }
@@ -548,24 +561,12 @@
         return SimpleMethodHandle.make(srcType, form);
     }
 
+    @LambdaForm.Hidden
     static
     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
         return testResult ? target : fallback;
     }
 
-    static MethodHandle SELECT_ALTERNATIVE;
-    static MethodHandle selectAlternative() {
-        if (SELECT_ALTERNATIVE != null)  return SELECT_ALTERNATIVE;
-        try {
-            SELECT_ALTERNATIVE
-            = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
-                    MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
-        } catch (ReflectiveOperationException ex) {
-            throw new RuntimeException(ex);
-        }
-        return SELECT_ALTERNATIVE;
-    }
-
     static
     MethodHandle makeGuardWithTest(MethodHandle test,
                                    MethodHandle target,
@@ -585,7 +586,7 @@
 
         // call selectAlternative
         Object[] selectArgs = { names[arity + 1], target, fallback };
-        names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
+        names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs);
         targetArgs[0] = names[arity + 2];
 
         // call target or fallback
@@ -595,167 +596,137 @@
         return SimpleMethodHandle.make(target.type(), form);
     }
 
-    private static class GuardWithCatch {
-        private final MethodHandle target;
-        private final Class<? extends Throwable> exType;
-        private final MethodHandle catcher;
-        // FIXME: Build the control flow out of foldArguments.
-        GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
-            this.target = target;
-            this.exType = exType;
-            this.catcher = catcher;
-        }
-        @LambdaForm.Hidden
-        private Object invoke_V(Object... av) throws Throwable {
-            try {
-                return target.invokeExact(av);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, av);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L0() throws Throwable {
-            try {
-                return target.invokeExact();
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L1(Object a0) throws Throwable {
-            try {
-                return target.invokeExact(a0);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L2(Object a0, Object a1) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1, a2);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1, a2);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1, a2, a3);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1, a2, a3);
-            }
+    /**
+     * The LambaForm shape for catchException combinator is the following:
+     * <blockquote><pre>{@code
+     *  guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
+     *    t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
+     *    t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
+     *    t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
+     *    t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
+     *    t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
+     *    t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
+     *    t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L);
+     *   t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I}
+     * }</pre></blockquote>
+     *
+     * argL0 and argL2 are target and catcher method handles. argL1 is exception class.
+     * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[]
+     * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()).
+     *
+     * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms
+     * among catchException combinators with the same basic type.
+     */
+    private static LambdaForm makeGuardWithCatchForm(MethodType basicType) {
+        MethodType lambdaType = basicType.invokerType();
+
+        LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC);
+        if (lform != null) {
+            return lform;
         }
-        @LambdaForm.Hidden
-        private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1, a2, a3, a4);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1, a2, a3, a4);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1, a2, a3, a4, a5);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
-            }
-        }
-        @LambdaForm.Hidden
-        private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
-            try {
-                return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
-            } catch (Throwable t) {
-                if (!exType.isInstance(t))  throw t;
-                return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
-            }
-        }
-        static MethodHandle[] makeInvokes() {
-            ArrayList<MethodHandle> invokes = new ArrayList<>();
-            MethodHandles.Lookup lookup = IMPL_LOOKUP;
-            for (;;) {
-                int nargs = invokes.size();
-                String name = "invoke_L"+nargs;
-                MethodHandle invoke = null;
-                try {
-                    invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
-                } catch (ReflectiveOperationException ex) {
-                }
-                if (invoke == null)  break;
-                invokes.add(invoke);
-            }
-            assert(invokes.size() == 9);  // current number of methods
-            return invokes.toArray(new MethodHandle[0]);
-        };
-        static final MethodHandle[] INVOKES = makeInvokes();
-        // For testing use this:
-        //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
-        static final MethodHandle VARARGS_INVOKE;
-        static {
-            try {
-                VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
-            } catch (ReflectiveOperationException ex) {
-                throw uncaughtException(ex);
-            }
-        }
+        final int THIS_MH      = 0;  // the BMH_LLLLL
+        final int ARG_BASE     = 1;  // start of incoming arguments
+        final int ARG_LIMIT    = ARG_BASE + basicType.parameterCount();
+
+        int nameCursor = ARG_LIMIT;
+        final int GET_TARGET       = nameCursor++;
+        final int GET_CLASS        = nameCursor++;
+        final int GET_CATCHER      = nameCursor++;
+        final int GET_COLLECT_ARGS = nameCursor++;
+        final int GET_UNBOX_RESULT = nameCursor++;
+        final int BOXED_ARGS       = nameCursor++;
+        final int TRY_CATCH        = nameCursor++;
+        final int UNBOX_RESULT     = nameCursor++;
+
+        Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
+
+        BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
+        names[GET_TARGET]       = new Name(data.getterFunction(0), names[THIS_MH]);
+        names[GET_CLASS]        = new Name(data.getterFunction(1), names[THIS_MH]);
+        names[GET_CATCHER]      = new Name(data.getterFunction(2), names[THIS_MH]);
+        names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]);
+        names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]);
+
+        // FIXME: rework argument boxing/result unboxing logic for LF interpretation
+
+        // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...);
+        MethodType collectArgsType = basicType.changeReturnType(Object.class);
+        MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType);
+        Object[] args = new Object[invokeBasic.type().parameterCount()];
+        args[0] = names[GET_COLLECT_ARGS];
+        System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
+        names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args);
+
+        // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
+        Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
+        names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs);
+
+        // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
+        MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
+        Object[] unboxArgs  = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
+        names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs);
+
+        lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
+
+        basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
+        return lform;
     }
 
-
     static
     MethodHandle makeGuardWithCatch(MethodHandle target,
                                     Class<? extends Throwable> exType,
                                     MethodHandle catcher) {
         MethodType type = target.type();
-        MethodType ctype = catcher.type();
-        int nargs = type.parameterCount();
-        if (nargs < GuardWithCatch.INVOKES.length) {
-            MethodType gtype = type.generic();
-            MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
-            // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
-            MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
-            MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
-            GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
-            if (gtarget == null || gcatcher == null)  throw new InternalError();
-            MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
-            return makePairwiseConvert(ginvoker, type, 2);
+        LambdaForm form = makeGuardWithCatchForm(type.basicType());
+
+        // Prepare auxiliary method handles used during LambdaForm interpreation.
+        // Box arguments and wrap them into Object[]: ValueConversions.array().
+        MethodType varargsType = type.changeReturnType(Object[].class);
+        MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount())
+                                                   .asType(varargsType);
+        // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
+        MethodHandle unboxResult;
+        if (type.returnType().isPrimitive()) {
+            unboxResult = ValueConversions.unbox(type.returnType());
         } else {
-            target = target.asType(type.changeReturnType(Object.class));
-            MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
-            MethodType catcherType = ctype.changeParameterType(0, Throwable.class)
-                                          .changeReturnType(Object.class);
-            catcher = catcher.asType(catcherType);
-            MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
-            GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
-            if (gtarget == null || gcatcher == null)  throw new InternalError();
-            MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
-            MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
-            return makePairwiseConvert(gcollect, type, 2);
+            unboxResult = ValueConversions.identity();
+        }
+
+        BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
+        BoundMethodHandle mh;
+        try {
+            mh = (BoundMethodHandle)
+                    data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
+                                                    (Object) collectArgs, (Object) unboxResult);
+        } catch (Throwable ex) {
+            throw uncaughtException(ex);
         }
+        assert(mh.type() == type);
+        return mh;
+    }
+
+    /**
+     * Intrinsified during LambdaForm compilation
+     * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}).
+     */
+    @LambdaForm.Hidden
+    static Object guardWithCatch(MethodHandle target, Class exType, MethodHandle catcher,
+                                 Object... av) throws Throwable {
+        try {
+            return target.invokeWithArguments(av);
+        } catch (Throwable t) {
+            if (!exType.isInstance(t)) throw t;
+            Object[] args = prepend(t, av);
+            return catcher.invokeWithArguments(args);
+        }
+    }
+
+    /** Prepend an element {@code elem} to an {@code array}. */
+    private static Object[] prepend(Object elem, Object[] array) {
+        Object[] newArray = new Object[array.length+1];
+        newArray[0] = elem;
+        System.arraycopy(array, 0, newArray, 1, array.length);
+        return newArray;
     }
 
     static
@@ -765,23 +736,9 @@
         if (arity > 1) {
             return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
         }
-        return makePairwiseConvert(throwException(), type, 2);
+        return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2);
     }
 
-    static MethodHandle THROW_EXCEPTION;
-    static MethodHandle throwException() {
-        MethodHandle mh = THROW_EXCEPTION;
-        if (mh != null)  return mh;
-        try {
-            mh
-            = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
-                    MethodType.methodType(Empty.class, Throwable.class));
-        } catch (ReflectiveOperationException ex) {
-            throw new RuntimeException(ex);
-        }
-        THROW_EXCEPTION = mh;
-        return mh;
-    }
     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
 
     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];