8263087: Add a MethodHandle combinator that switches over a set of MethodHandles

Reviewed-by: redestad
This commit is contained in:
Jorn Vernee 2021-05-27 12:28:10 +00:00
parent 85f616522b
commit 3623abb7f6
10 changed files with 974 additions and 26 deletions

View file

@ -864,6 +864,12 @@ class InvokerBytecodeGenerator {
onStack = emitTryFinally(i);
i += 2; // jump to the end of the TF idiom
continue;
case TABLE_SWITCH:
assert lambdaForm.isTableSwitch(i);
int numCases = (Integer) name.function.intrinsicData();
onStack = emitTableSwitch(i, numCases);
i += 2; // jump to the end of the TS idiom
continue;
case LOOP:
assert lambdaForm.isLoop(i);
onStack = emitLoop(i);
@ -1389,6 +1395,58 @@ class InvokerBytecodeGenerator {
}
}
private Name emitTableSwitch(int pos, int numCases) {
Name args = lambdaForm.names[pos];
Name invoker = lambdaForm.names[pos + 1];
Name result = lambdaForm.names[pos + 2];
Class<?> returnType = result.function.resolvedHandle().type().returnType();
MethodType caseType = args.function.resolvedHandle().type()
.dropParameterTypes(0, 1) // drop collector
.changeReturnType(returnType);
String caseDescriptor = caseType.basicType().toMethodDescriptorString();
emitPushArgument(invoker, 2); // push cases
mv.visitFieldInsn(Opcodes.GETFIELD, "java/lang/invoke/MethodHandleImpl$CasesHolder", "cases",
"[Ljava/lang/invoke/MethodHandle;");
int casesLocal = extendLocalsMap(new Class<?>[] { MethodHandle[].class });
emitStoreInsn(L_TYPE, casesLocal);
Label endLabel = new Label();
Label defaultLabel = new Label();
Label[] caseLabels = new Label[numCases];
for (int i = 0; i < caseLabels.length; i++) {
caseLabels[i] = new Label();
}
emitPushArgument(invoker, 0); // push switch input
mv.visitTableSwitchInsn(0, numCases - 1, defaultLabel, caseLabels);
mv.visitLabel(defaultLabel);
emitPushArgument(invoker, 1); // push default handle
emitPushArguments(args, 1); // again, skip collector
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", caseDescriptor, false);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
for (int i = 0; i < numCases; i++) {
mv.visitLabel(caseLabels[i]);
// Load the particular case:
emitLoadInsn(L_TYPE, casesLocal);
emitIconstInsn(i);
mv.visitInsn(Opcodes.AALOAD);
// invoke it:
emitPushArguments(args, 1); // again, skip collector
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", caseDescriptor, false);
mv.visitJumpInsn(Opcodes.GOTO, endLabel);
}
mv.visitLabel(endLabel);
return result;
}
/**
* Emit bytecode for the loop idiom.
* <p>