jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
changeset 41125 88d76c8db1fa
parent 40559 e727ba540ee6
child 42105 d04ede5f10e7
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Fri Sep 23 03:15:00 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Fri Sep 23 15:20:49 2016 +0200
@@ -39,14 +39,14 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.lang.reflect.Modifier;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.stream.Stream;
 
-import static java.lang.invoke.LambdaForm.*;
+import static java.lang.invoke.LambdaForm.BasicType;
 import static java.lang.invoke.LambdaForm.BasicType.*;
-import static java.lang.invoke.LambdaForm.Kind.*;
+import static java.lang.invoke.LambdaForm.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import static java.lang.invoke.MethodHandleStatics.*;
 
@@ -65,6 +65,9 @@
     private static final String OBJ     = "java/lang/Object";
     private static final String OBJARY  = "[Ljava/lang/Object;";
 
+    private static final String LOOP_CLAUSES = MHI + "$LoopClauses";
+    private static final String MHARY2       = "[[L" + MH + ";";
+
     private static final String LF_SIG  = "L" + LF + ";";
     private static final String LFN_SIG = "L" + LFN + ";";
     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
@@ -1319,38 +1322,43 @@
      * The pattern looks like (Cf. MethodHandleImpl.loop):
      * <blockquote><pre>{@code
      * // a0: BMH
-     * // a1: inits, a2: steps, a3: preds, a4: finis
-     * // a5: box, a6: unbox
-     * // a7 (and following): arguments
-     * loop=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{
-     *   t8:L=MethodHandle.invokeBasic(a5:L,a7:L);                  // box the arguments into an Object[]
-     *   t9:L=MethodHandleImpl.loop(bt:L,a1:L,a2:L,a3:L,a4:L,t8:L); // call the loop executor (with supplied types in bt)
-     *   t10:L=MethodHandle.invokeBasic(a6:L,t9:L);t10:L}           // unbox the result; return the result
+     * // a1: LoopClauses (containing an array of arrays: inits, steps, preds, finis)
+     * // a2: box, a3: unbox
+     * // a4 (and following): arguments
+     * loop=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L)=>{
+     *   t5:L=MethodHandle.invokeBasic(a2:L,a4:L);          // box the arguments into an Object[]
+     *   t6:L=MethodHandleImpl.loop(bt:L,a1:L,t5:L);        // call the loop executor (with supplied types in bt)
+     *   t7:L=MethodHandle.invokeBasic(a3:L,t6:L);t7:L}     // unbox the result; return the result
      * }</pre></blockquote>
      * <p>
      * It is compiled into bytecode equivalent to the code seen in {@link MethodHandleImpl#loop(BasicType[],
-     * MethodHandle[], MethodHandle[], MethodHandle[], MethodHandle[], Object...)}, with the difference that no arrays
+     * MethodHandleImpl.LoopClauses, Object...)}, with the difference that no arrays
      * will be used for local state storage. Instead, the local state will be mapped to actual stack slots.
      * <p>
      * Bytecode generation applies an unrolling scheme to enable better bytecode generation regarding local state type
      * handling. The generated bytecode will have the following form ({@code void} types are ignored for convenience).
      * Assume there are {@code C} clauses in the loop.
      * <blockquote><pre>{@code
-     * INIT: (INIT_SEQ for clause 1)
-     *       ...
-     *       (INIT_SEQ for clause C)
-     * LOOP: (LOOP_SEQ for clause 1)
-     *       ...
-     *       (LOOP_SEQ for clause C)
-     *       GOTO LOOP
-     * DONE: ...
+     * PREINIT: ALOAD_1
+     *          CHECKCAST LoopClauses
+     *          GETFIELD LoopClauses.clauses
+     *          ASTORE clauseDataIndex          // place the clauses 2-dimensional array on the stack
+     * INIT:    (INIT_SEQ for clause 1)
+     *          ...
+     *          (INIT_SEQ for clause C)
+     * LOOP:    (LOOP_SEQ for clause 1)
+     *          ...
+     *          (LOOP_SEQ for clause C)
+     *          GOTO LOOP
+     * DONE:    ...
      * }</pre></blockquote>
      * <p>
      * The {@code INIT_SEQ_x} sequence for clause {@code x} (with {@code x} ranging from {@code 0} to {@code C-1}) has
      * the following shape. Assume slot {@code vx} is used to hold the state for clause {@code x}.
      * <blockquote><pre>{@code
-     * INIT_SEQ_x:  ALOAD inits
-     *              CHECKCAST MethodHandle[]
+     * INIT_SEQ_x:  ALOAD clauseDataIndex
+     *              ICONST_0
+     *              AALOAD      // load the inits array
      *              ICONST x
      *              AALOAD      // load the init handle for clause x
      *              load args
@@ -1361,24 +1369,27 @@
      * The {@code LOOP_SEQ_x} sequence for clause {@code x} (with {@code x} ranging from {@code 0} to {@code C-1}) has
      * the following shape. Again, assume slot {@code vx} is used to hold the state for clause {@code x}.
      * <blockquote><pre>{@code
-     * LOOP_SEQ_x:  ALOAD steps
-     *              CHECKCAST MethodHandle[]
+     * LOOP_SEQ_x:  ALOAD clauseDataIndex
+     *              ICONST_1
+     *              AALOAD              // load the steps array
      *              ICONST x
      *              AALOAD              // load the step handle for clause x
      *              load locals
      *              load args
      *              INVOKEVIRTUAL MethodHandle.invokeBasic
      *              store vx
-     *              ALOAD preds
-     *              CHECKCAST MethodHandle[]
+     *              ALOAD clauseDataIndex
+     *              ICONST_2
+     *              AALOAD              // load the preds array
      *              ICONST x
      *              AALOAD              // load the pred handle for clause x
      *              load locals
      *              load args
      *              INVOKEVIRTUAL MethodHandle.invokeBasic
      *              IFNE LOOP_SEQ_x+1   // predicate returned false -> jump to next clause
-     *              ALOAD finis
-     *              CHECKCAST MethodHandle[]
+     *              ALOAD clauseDataIndex
+     *              ICONST_3
+     *              AALOAD              // load the finis array
      *              ICONST x
      *              AALOAD              // load the fini handle for clause x
      *              load locals
@@ -1397,8 +1408,12 @@
         BasicType[] loopClauseTypes = (BasicType[]) invoker.arguments[0];
         Class<?>[] loopLocalStateTypes = Stream.of(loopClauseTypes).
                 filter(bt -> bt != BasicType.V_TYPE).map(BasicType::basicTypeClass).toArray(Class<?>[]::new);
+        Class<?>[] localTypes = new Class<?>[loopLocalStateTypes.length + 1];
+        localTypes[0] = MethodHandleImpl.LoopClauses.class;
+        System.arraycopy(loopLocalStateTypes, 0, localTypes, 1, loopLocalStateTypes.length);
 
-        final int firstLoopStateIndex = extendLocalsMap(loopLocalStateTypes);
+        final int clauseDataIndex = extendLocalsMap(localTypes);
+        final int firstLoopStateIndex = clauseDataIndex + 1;
 
         Class<?> returnType = result.function.resolvedHandle().type().returnType();
         MethodType loopType = args.function.resolvedHandle().type()
@@ -1420,10 +1435,16 @@
         Label lDone = new Label();
         Label lNext;
 
+        // PREINIT:
+        emitPushArgument(MethodHandleImpl.LoopClauses.class, invoker.arguments[1]);
+        mv.visitFieldInsn(Opcodes.GETFIELD, LOOP_CLAUSES, "clauses", MHARY2);
+        emitAstoreInsn(clauseDataIndex);
+
         // INIT:
         for (int c = 0, state = 0; c < nClauses; ++c) {
             MethodType cInitType = loopType.changeReturnType(loopClauseTypes[c].basicTypeClass());
-            emitLoopHandleInvoke(invoker, inits, c, args, false, cInitType, loopLocalStateTypes, firstLoopStateIndex);
+            emitLoopHandleInvoke(invoker, inits, c, args, false, cInitType, loopLocalStateTypes, clauseDataIndex,
+                    firstLoopStateIndex);
             if (cInitType.returnType() != void.class) {
                 emitStoreInsn(BasicType.basicType(cInitType.returnType()), firstLoopStateIndex + state);
                 ++state;
@@ -1440,18 +1461,21 @@
             boolean isVoid = stepType.returnType() == void.class;
 
             // invoke loop step
-            emitLoopHandleInvoke(invoker, steps, c, args, true, stepType, loopLocalStateTypes, firstLoopStateIndex);
+            emitLoopHandleInvoke(invoker, steps, c, args, true, stepType, loopLocalStateTypes, clauseDataIndex,
+                    firstLoopStateIndex);
             if (!isVoid) {
                 emitStoreInsn(BasicType.basicType(stepType.returnType()), firstLoopStateIndex + state);
                 ++state;
             }
 
             // invoke loop predicate
-            emitLoopHandleInvoke(invoker, preds, c, args, true, predType, loopLocalStateTypes, firstLoopStateIndex);
+            emitLoopHandleInvoke(invoker, preds, c, args, true, predType, loopLocalStateTypes, clauseDataIndex,
+                    firstLoopStateIndex);
             mv.visitJumpInsn(Opcodes.IFNE, lNext);
 
             // invoke fini
-            emitLoopHandleInvoke(invoker, finis, c, args, true, finiType, loopLocalStateTypes, firstLoopStateIndex);
+            emitLoopHandleInvoke(invoker, finis, c, args, true, finiType, loopLocalStateTypes, clauseDataIndex,
+                    firstLoopStateIndex);
             mv.visitJumpInsn(Opcodes.GOTO, lDone);
 
             // this is the beginning of the next loop clause
@@ -1483,9 +1507,10 @@
     }
 
     private void emitLoopHandleInvoke(Name holder, int handles, int clause, Name args, boolean pushLocalState,
-                                      MethodType type, Class<?>[] loopLocalStateTypes, int firstLoopStateSlot) {
+                                      MethodType type, Class<?>[] loopLocalStateTypes, int clauseDataSlot,
+                                      int firstLoopStateSlot) {
         // load handle for clause
-        emitPushArgument(holder, handles);
+        emitPushClauseArray(clauseDataSlot, handles);
         emitIconstInsn(clause);
         mv.visitInsn(Opcodes.AALOAD);
         // load loop state (preceding the other arguments)
@@ -1499,6 +1524,12 @@
         mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.toMethodDescriptorString(), false);
     }
 
+    private void emitPushClauseArray(int clauseDataSlot, int which) {
+        emitAloadInsn(clauseDataSlot);
+        emitIconstInsn(which - 1);
+        mv.visitInsn(Opcodes.AALOAD);
+    }
+
     private void emitZero(BasicType type) {
         switch (type) {
             case I_TYPE: mv.visitInsn(Opcodes.ICONST_0); break;