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

@ -314,6 +314,7 @@ class LambdaForm {
GET_DOUBLE_VOLATILE("getDoubleVolatile"),
PUT_DOUBLE_VOLATILE("putDoubleVolatile"),
TRY_FINALLY("tryFinally"),
TABLE_SWITCH("tableSwitch"),
COLLECT("collect"),
COLLECTOR("collector"),
CONVERT("convert"),
@ -707,6 +708,32 @@ class LambdaForm {
return isMatchingIdiom(pos, "tryFinally", 2);
}
/**
* Check if i-th name is a start of the tableSwitch idiom.
*/
boolean isTableSwitch(int pos) {
// tableSwitch idiom:
// t_{n}:L=MethodHandle.invokeBasic(...) // args
// t_{n+1}:L=MethodHandleImpl.tableSwitch(*, *, *, t_{n})
// t_{n+2}:?=MethodHandle.invokeBasic(*, t_{n+1})
if (pos + 2 >= names.length) return false;
final int POS_COLLECT_ARGS = pos;
final int POS_TABLE_SWITCH = pos + 1;
final int POS_UNBOX_RESULT = pos + 2;
Name collectArgs = names[POS_COLLECT_ARGS];
Name tableSwitch = names[POS_TABLE_SWITCH];
Name unboxResult = names[POS_UNBOX_RESULT];
return tableSwitch.refersTo(MethodHandleImpl.class, "tableSwitch") &&
collectArgs.isInvokeBasic() &&
unboxResult.isInvokeBasic() &&
tableSwitch.lastUseIndex(collectArgs) == 3 && // t_{n+1}:L=MethodHandleImpl.<invoker>(*, *, *, t_{n});
lastUseIndex(collectArgs) == POS_TABLE_SWITCH && // t_{n} is local: used only in t_{n+1}
unboxResult.lastUseIndex(tableSwitch) == 1 && // t_{n+2}:?=MethodHandle.invokeBasic(*, t_{n+1})
lastUseIndex(tableSwitch) == POS_UNBOX_RESULT; // t_{n+1} is local: used only in t_{n+2}
}
/**
* Check if i-th name is a start of the loop idiom.
*/
@ -1067,24 +1094,13 @@ class LambdaForm {
final MemberName member;
private @Stable MethodHandle resolvedHandle;
@Stable MethodHandle invoker;
private final MethodHandleImpl.Intrinsic intrinsicName;
NamedFunction(MethodHandle resolvedHandle) {
this(resolvedHandle.internalMemberName(), resolvedHandle, MethodHandleImpl.Intrinsic.NONE);
}
NamedFunction(MethodHandle resolvedHandle, MethodHandleImpl.Intrinsic intrinsic) {
this(resolvedHandle.internalMemberName(), resolvedHandle, intrinsic);
this(resolvedHandle.internalMemberName(), resolvedHandle);
}
NamedFunction(MemberName member, MethodHandle resolvedHandle) {
this(member, resolvedHandle, MethodHandleImpl.Intrinsic.NONE);
}
NamedFunction(MemberName member, MethodHandle resolvedHandle, MethodHandleImpl.Intrinsic intrinsic) {
this.member = member;
this.resolvedHandle = resolvedHandle;
this.intrinsicName = intrinsic;
assert(resolvedHandle == null ||
resolvedHandle.intrinsicName() == MethodHandleImpl.Intrinsic.NONE ||
resolvedHandle.intrinsicName() == intrinsic) : resolvedHandle.intrinsicName() + " != " + intrinsic;
// The following assert is almost always correct, but will fail for corner cases, such as PrivateInvokeTest.
//assert(!isInvokeBasic(member));
}
@ -1097,7 +1113,6 @@ class LambdaForm {
// necessary to pass BigArityTest
this.member = Invokers.invokeBasicMethod(basicInvokerType);
}
this.intrinsicName = MethodHandleImpl.Intrinsic.NONE;
assert(isInvokeBasic(member));
}
@ -1250,7 +1265,15 @@ class LambdaForm {
}
public MethodHandleImpl.Intrinsic intrinsicName() {
return intrinsicName;
return resolvedHandle != null
? resolvedHandle.intrinsicName()
: MethodHandleImpl.Intrinsic.NONE;
}
public Object intrinsicData() {
return resolvedHandle != null
? resolvedHandle.intrinsicData()
: null;
}
}
@ -1732,15 +1755,15 @@ class LambdaForm {
Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
idForm = new LambdaForm(2, idNames, 1, Kind.IDENTITY);
idForm.compileToBytecode();
idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm),
MethodHandleImpl.Intrinsic.IDENTITY);
idFun = new NamedFunction(idMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(idMem.getInvocationType(), idForm),
MethodHandleImpl.Intrinsic.IDENTITY));
Object zeValue = Wrapper.forBasicType(btChar).zero();
Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
zeForm = new LambdaForm(1, zeNames, 1, Kind.ZERO);
zeForm.compileToBytecode();
zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm),
MethodHandleImpl.Intrinsic.ZERO);
zeFun = new NamedFunction(zeMem, MethodHandleImpl.makeIntrinsic(SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm),
MethodHandleImpl.Intrinsic.ZERO));
}
LF_zero[ord] = zeForm;