< 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 >