src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
jdk Cdiff src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
Print this page
rev 11254 : 8063137: Never-taken branches should be pruned when GWT LambdaForms are shared
Reviewed-by: ?
rev 11255 : [mq]: gwt.profile.1
rev 11256 : [mq]: gwt.profile.2
rev 11257 : [mq]: gwt.profile.3
rev 11258 : [mq]: gwt.profile.4
*** 595,604 ****
--- 595,605 ----
private static final MethodHandle[] FILL_ARRAYS;
static final NamedFunction NF_checkSpreadArgument;
static final NamedFunction NF_guardWithCatch;
static final NamedFunction NF_throwException;
+ static final NamedFunction NF_profileBoolean;
static final MethodHandle MH_castReference;
static final MethodHandle MH_selectAlternative;
static final MethodHandle MH_copyAsPrimitiveArray;
static final MethodHandle MH_fillNewTypedArray;
*** 612,625 ****
--- 613,628 ----
try {
NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
MethodHandle.class, Object[].class));
NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
+ NF_profileBoolean = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
NF_checkSpreadArgument.resolve();
NF_guardWithCatch.resolve();
NF_throwException.resolve();
+ NF_profileBoolean.resolve();
MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
MethodType.methodType(Object.class, Class.class, Object.class));
MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
MethodType.methodType(Object.class, Wrapper.class, Object[].class));
*** 695,722 ****
}
@LambdaForm.Hidden
static
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
! return testResult ? target : fallback;
}
static
MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
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) profile(target), (Object) profile(fallback));
} catch (Throwable ex) {
throw uncaughtException(ex);
}
assert(mh.type() == type);
return mh;
--- 698,749 ----
}
@LambdaForm.Hidden
static
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
! if (testResult) {
! return target;
! } else {
! return fallback;
! }
! }
!
! // Intrinsified by C2. Counters are used during parsing to calculate branch frequencies.
! @LambdaForm.Hidden
! static
! boolean profileBoolean(boolean result, int[] counters) {
! // Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively.
! int idx = result ? 1 : 0;
! try {
! counters[idx] = Math.addExact(counters[idx], 1);
! } catch (ArithmeticException e) {
! // Avoid continuous overflow by halving the problematic count.
! counters[idx] = counters[idx] / 2;
! }
! return result;
}
static
MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,
MethodHandle fallback) {
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 mh;
try {
+ if (PROFILE_GWT) {
+ int[] counts = new int[2];
+ mh = (BoundMethodHandle)
+ BoundMethodHandle.speciesData_LLLL().constructor().invokeBasic(type, form,
+ (Object) test, (Object) profile(target), (Object) profile(fallback), counts);
+ } else {
mh = (BoundMethodHandle)
! BoundMethodHandle.speciesData_LLL().constructor().invokeBasic(type, form,
(Object) test, (Object) profile(target), (Object) profile(fallback));
+ }
} catch (Throwable ex) {
throw uncaughtException(ex);
}
assert(mh.type() == type);
return mh;
*** 854,893 ****
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(nameCursor - ARG_LIMIT, lambdaType);
! 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
MethodType testType = basicType.changeReturnType(boolean.class).basicType();
invokeArgs[0] = names[GET_TEST];
names[CALL_TEST] = new Name(testType, invokeArgs);
// call selectAlternative
! names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST],
! names[GET_TARGET], names[GET_FALLBACK]);
// call target or fallback
invokeArgs[0] = names[SELECT_ALT];
names[CALL_TARGET] = new Name(basicType, invokeArgs);
! lform = new LambdaForm("guard", lambdaType.parameterCount(), names);
return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
}
/**
--- 881,930 ----
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 GET_COUNTERS = PROFILE_GWT ? nameCursor++ : -1;
final int CALL_TEST = nameCursor++;
+ final int PROFILE = (GET_COUNTERS != -1) ? nameCursor++ : -1;
+ final int TEST = nameCursor-1; // previous statement: either PROFILE or CALL_TEST
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(nameCursor - ARG_LIMIT, lambdaType);
! BoundMethodHandle.SpeciesData data =
! (GET_COUNTERS != -1) ? BoundMethodHandle.speciesData_LLLL()
! : 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]);
! if (GET_COUNTERS != -1) {
! names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]);
! }
Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
// call test
MethodType testType = basicType.changeReturnType(boolean.class).basicType();
invokeArgs[0] = names[GET_TEST];
names[CALL_TEST] = new Name(testType, invokeArgs);
+ // profile branch
+ if (PROFILE != -1) {
+ names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
+ }
// call selectAlternative
! names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
// call target or fallback
invokeArgs[0] = names[SELECT_ALT];
names[CALL_TARGET] = new Name(basicType, invokeArgs);
! lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true);
return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
}
/**
src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File