< prev index next >

src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

Print this page
rev 15669 : 8161211: better inlining support for loop bytecode intrinsics

@@ -37,18 +37,18 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.lang.reflect.Modifier;
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 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.*;
 
 /**
  * Code generation backend for LambdaForm.

@@ -59,18 +59,21 @@
     /** Define class names for convenience. */
     private static final String MH      = "java/lang/invoke/MethodHandle";
     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
     private static final String LF      = "java/lang/invoke/LambdaForm";
     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
+    private static final String BMH     = "java/lang/invoke/BoundMethodHandle";
     private static final String CLS     = "java/lang/Class";
     private static final String OBJ     = "java/lang/Object";
     private static final String OBJARY  = "[Ljava/lang/Object;";
 
     private static final String LF_SIG  = "L" + LF + ";";
     private static final String LFN_SIG = "L" + LFN + ";";
+    private static final String OBJ_SIG = "L" + OBJ + ";";
     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
     private static final String LLV_SIG = "(L" + OBJ + ";L" + OBJ + ";)V";
+    private static final String IL_SIG  = "(I)L" + OBJ + ";";
     private static final String CLASS_PREFIX = LF + "$";
 
     /** Name of its super class*/
     static final String INVOKER_SUPER_NAME = OBJ;
 

@@ -1327,12 +1330,12 @@
      *   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
      * }</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
-     * will be used for local state storage. Instead, the local state will be mapped to actual stack slots.
+     * BoundMethodHandle, BoundMethodHandle, BoundMethodHandle, BoundMethodHandle, 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

@@ -1348,41 +1351,41 @@
      * <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[]
-     *              ICONST x
-     *              AALOAD      // load the init handle for clause x
+     *              CHECKCAST BoundMethodHandle$Species_LC
+     *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the init handle for clause x
+     *              CHECKCAST MethodHandle
      *              load args
      *              INVOKEVIRTUAL MethodHandle.invokeBasic
      *              store vx
      * }</pre></blockquote>
      * <p>
      * 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[]
-     *              ICONST x
-     *              AALOAD              // load the step handle for clause x
+     *              CHECKCAST BoundMethodHandle$Species_LC
+     *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the step handle for clause x
+     *              CHECKCAST MethodHandle
      *              load locals
      *              load args
      *              INVOKEVIRTUAL MethodHandle.invokeBasic
      *              store vx
      *              ALOAD preds
-     *              CHECKCAST MethodHandle[]
-     *              ICONST x
-     *              AALOAD              // load the pred handle for clause x
+     *              CHECKCAST BoundMethodHandle$Species_LC
+     *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the pred handle for clause x
+     *              CHECKCAST MethodHandle
      *              load locals
      *              load args
      *              INVOKEVIRTUAL MethodHandle.invokeBasic
      *              IFNE LOOP_SEQ_x+1   // predicate returned false -> jump to next clause
      *              ALOAD finis
-     *              CHECKCAST MethodHandle[]
-     *              ICONST x
-     *              AALOAD              // load the fini handle for clause x
+     *              CHECKCAST BoundMethodHandle$Species_LC
+     *              GETFIELD BoundMethodHandle$Species_LC.argx // extract the fini handle for clause x
+     *              CHECKCAST MethodHandle
      *              load locals
      *              load args
      *              INVOKEVIRTUAL MethodHandle.invokeBasic
      *              GOTO DONE           // jump beyond end of clauses to return from loop
      * }</pre></blockquote>

@@ -1418,14 +1421,18 @@
 
         Label lLoop = new Label();
         Label lDone = new Label();
         Label lNext;
 
+        final String speciesType = new StringBuilder("java/lang/invoke/BoundMethodHandle$Species_").
+                append(nClauses == 1 ? "L" : nClauses == 2 ? "LL" : "L" + nClauses).toString();
+
         // 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, speciesType, inits, c, args, false, cInitType, loopLocalStateTypes,
+                    firstLoopStateIndex);
             if (cInitType.returnType() != void.class) {
                 emitStoreInsn(BasicType.basicType(cInitType.returnType()), firstLoopStateIndex + state);
                 ++state;
             }
         }

@@ -1438,22 +1445,25 @@
 
             MethodType stepType = loopHandleType.changeReturnType(loopClauseTypes[c].basicTypeClass());
             boolean isVoid = stepType.returnType() == void.class;
 
             // invoke loop step
-            emitLoopHandleInvoke(invoker, steps, c, args, true, stepType, loopLocalStateTypes, firstLoopStateIndex);
+            emitLoopHandleInvoke(invoker, speciesType, steps, c, args, true, stepType, loopLocalStateTypes,
+                    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, speciesType, preds, c, args, true, predType, loopLocalStateTypes,
+                    firstLoopStateIndex);
             mv.visitJumpInsn(Opcodes.IFNE, lNext);
 
             // invoke fini
-            emitLoopHandleInvoke(invoker, finis, c, args, true, finiType, loopLocalStateTypes, firstLoopStateIndex);
+            emitLoopHandleInvoke(invoker, speciesType, finis, c, args, true, finiType, loopLocalStateTypes,
+                    firstLoopStateIndex);
             mv.visitJumpInsn(Opcodes.GOTO, lDone);
 
             // this is the beginning of the next loop clause
             mv.visitLabel(lNext);
         }

@@ -1480,16 +1490,19 @@
         }
         localsMap[localsMap.length - 1] = index - lastSlots;
         return firstSlot;
     }
 
-    private void emitLoopHandleInvoke(Name holder, int handles, int clause, Name args, boolean pushLocalState,
-                                      MethodType type, Class<?>[] loopLocalStateTypes, int firstLoopStateSlot) {
+    private void emitLoopHandleInvoke(Name holder, String speciesType, int handles, int clause, Name args,
+                                      boolean pushLocalState, MethodType type, Class<?>[] loopLocalStateTypes,
+                                      int firstLoopStateSlot) {
         // load handle for clause
-        emitPushArgument(holder, handles);
-        emitIconstInsn(clause);
-        mv.visitInsn(Opcodes.AALOAD);
+        Name hname = (Name) holder.arguments[handles];
+        emitLoadInsn(hname.type, hname.index());
+        mv.visitTypeInsn(Opcodes.CHECKCAST, speciesType);
+        mv.visitFieldInsn(Opcodes.GETFIELD, speciesType, "argL" + clause, OBJ_SIG);
+        mv.visitTypeInsn(Opcodes.CHECKCAST, MH);
         // load loop state (preceding the other arguments)
         if (pushLocalState) {
             for (int s = 0; s < loopLocalStateTypes.length; ++s) {
                 emitLoadInsn(BasicType.basicType(loopLocalStateTypes[s]), firstLoopStateSlot + s);
             }
< prev index next >