8056926: Improve caching of GuardWithTest combinator
Reviewed-by: vlivanov, psandoz
Contributed-by: john.r.rose@oracle.com
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:51 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Wed Sep 10 19:19:52 2014 +0400
@@ -640,29 +640,66 @@
MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
- MethodType basicType = target.type().basicType();
- MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
- int arity = basicType.parameterCount();
- int extraNames = 3;
+ MethodType type = target.type();
+ assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type));
+ MethodType basicType = type.basicType();
+ LambdaForm form = makeGuardWithTestForm(basicType);
+ BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
+ BoundMethodHandle mh;
+ try {
+ mh = (BoundMethodHandle)
+ data.constructor().invokeBasic(type, form,
+ (Object) test, (Object) target, (Object) fallback);
+ } catch (Throwable ex) {
+ throw uncaughtException(ex);
+ }
+ assert(mh.type() == type);
+ return mh;
+ }
+
+ static
+ LambdaForm makeGuardWithTestForm(MethodType basicType) {
+ LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
+ if (lform != null) return lform;
+ final int THIS_MH = 0; // the BMH_LLL
+ final int ARG_BASE = 1; // start of incoming arguments
+ final int ARG_LIMIT = ARG_BASE + basicType.parameterCount();
+ int nameCursor = ARG_LIMIT;
+ final int GET_TEST = nameCursor++;
+ final int GET_TARGET = nameCursor++;
+ final int GET_FALLBACK = nameCursor++;
+ final int CALL_TEST = nameCursor++;
+ final int SELECT_ALT = nameCursor++;
+ final int CALL_TARGET = nameCursor++;
+ assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative
+
MethodType lambdaType = basicType.invokerType();
- Name[] names = arguments(extraNames, lambdaType);
+ Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
- Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
- Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
+ BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
+ names[THIS_MH] = names[THIS_MH].withConstraint(data);
+ names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
+ names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]);
+ names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
+
+ Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
// call test
- names[arity + 1] = new Name(test, testArgs);
+ MethodType testType = basicType.changeReturnType(boolean.class).basicType();
+ invokeArgs[0] = names[GET_TEST];
+ names[CALL_TEST] = new Name(testType, invokeArgs);
// call selectAlternative
- Object[] selectArgs = { names[arity + 1], target, fallback };
- names[arity + 2] = new Name(Lazy.MH_selectAlternative, selectArgs);
- targetArgs[0] = names[arity + 2];
+ names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST],
+ names[GET_TARGET], names[GET_FALLBACK]);
// call target or fallback
- names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
+ invokeArgs[0] = names[SELECT_ALT];
+ names[CALL_TARGET] = new Name(basicType, invokeArgs);
- LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
- return SimpleMethodHandle.make(target.type(), form);
+ lform = new LambdaForm("guard", lambdaType.parameterCount(), names);
+
+ return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
}
/**
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java Wed Sep 10 19:19:51 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodTypeForm.java Wed Sep 10 19:19:52 2014 +0400
@@ -79,7 +79,8 @@
LF_CS_LINKER = 13, // linkToCallSite_CS
LF_MH_LINKER = 14, // linkToCallSite_MH
LF_GWC = 15, // guardWithCatch (catchException)
- LF_LIMIT = 16;
+ LF_GWT = 16, // guardWithTest
+ LF_LIMIT = 17;
/** Return the type corresponding uniquely (1-1) to this MT-form.
* It might have any primitive returns or arguments, but will have no references except Object.