8063137: Never-taken branches should be pruned when GWT LambdaForms are shared
Reviewed-by: jrose, kvn
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Mon Jan 26 17:00:39 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Thu Jan 29 10:27:30 2015 -0800
@@ -635,7 +635,6 @@
mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
}
-
// iterate over the form's names, generating bytecode instructions for each
// start iterating at the first name following the arguments
Name onStack = null;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Mon Jan 26 17:00:39 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java Thu Jan 29 10:27:30 2015 -0800
@@ -244,7 +244,7 @@
LambdaForm(String debugName,
int arity, Name[] names, int result) {
- this(debugName, arity, names, result, true);
+ this(debugName, arity, names, result, /*forceInline=*/true);
}
LambdaForm(String debugName,
int arity, Name[] names, int result, boolean forceInline) {
@@ -263,7 +263,7 @@
}
LambdaForm(String debugName,
int arity, Name[] names) {
- this(debugName, arity, names, LAST_RESULT, true);
+ this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true);
}
LambdaForm(String debugName,
int arity, Name[] names, boolean forceInline) {
@@ -272,7 +272,7 @@
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result) {
this(debugName,
- formals.length, buildNames(formals, temps, result), LAST_RESULT, true);
+ formals.length, buildNames(formals, temps, result), LAST_RESULT, /*forceInline=*/true);
}
LambdaForm(String debugName,
Name[] formals, Name[] temps, Name result, boolean forceInline) {
@@ -291,10 +291,6 @@
}
private LambdaForm(String sig) {
- this(sig, true);
- }
-
- private LambdaForm(String sig, boolean forceInline) {
// Make a blank lambda form, which returns a constant zero or null.
// It is used as a template for managing the invocation of similar forms that are non-empty.
// Called only from getPreparedForm.
@@ -303,7 +299,7 @@
this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
this.names = buildEmptyNames(arity, sig);
this.debugName = "LF.zero";
- this.forceInline = forceInline;
+ this.forceInline = true;
assert(nameRefsAreLegal());
assert(isEmpty());
assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Mon Jan 26 17:00:39 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Thu Jan 29 10:27:30 2015 -0800
@@ -597,6 +597,7 @@
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;
@@ -614,10 +615,12 @@
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));
@@ -697,7 +700,26 @@
@LambdaForm.Hidden
static
MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
- return testResult ? target : 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
@@ -708,13 +730,18 @@
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));
+ 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);
}
@@ -856,7 +883,10 @@
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
@@ -864,12 +894,16 @@
MethodType lambdaType = basicType.invokerType();
Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
- BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
+ 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
@@ -877,15 +911,18 @@
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[CALL_TEST],
- names[GET_TARGET], names[GET_FALLBACK]);
+ 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);
+ lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true);
return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
}
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java Mon Jan 26 17:00:39 2015 -0800
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java Thu Jan 29 10:27:30 2015 -0800
@@ -48,9 +48,10 @@
static final int COMPILE_THRESHOLD;
static final int DONT_INLINE_THRESHOLD;
static final int PROFILE_LEVEL;
+ static final boolean PROFILE_GWT;
static {
- final Object[] values = new Object[7];
+ final Object[] values = new Object[8];
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
@@ -60,6 +61,7 @@
values[4] = Integer.getInteger("java.lang.invoke.MethodHandle.COMPILE_THRESHOLD", 0);
values[5] = Integer.getInteger("java.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD", 30);
values[6] = Integer.getInteger("java.lang.invoke.MethodHandle.PROFILE_LEVEL", 0);
+ values[7] = Boolean.parseBoolean(System.getProperty("java.lang.invoke.MethodHandle.PROFILE_GWT", "true"));
return null;
}
});
@@ -70,6 +72,7 @@
COMPILE_THRESHOLD = (Integer) values[4];
DONT_INLINE_THRESHOLD = (Integer) values[5];
PROFILE_LEVEL = (Integer) values[6];
+ PROFILE_GWT = (Boolean) values[7];
}
/** Tell if any of the debugging switches are turned on.