# HG changeset patch # User vlivanov # Date 1422556050 28800 # Node ID a859b806c8bdc6acff7fbd6e18e37fb8eca34f3c # Parent 343c4ddd1520e7929b1ad165722593a4c07e38b0 8063137: Never-taken branches should be pruned when GWT LambdaForms are shared Reviewed-by: jrose, kvn diff -r 343c4ddd1520 -r a859b806c8bd jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- 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; diff -r 343c4ddd1520 -r a859b806c8bd jdk/src/java.base/share/classes/java/lang/invoke/LambdaForm.java --- 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(); diff -r 343c4ddd1520 -r a859b806c8bd jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java --- 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); } diff -r 343c4ddd1520 -r a859b806c8bd jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java --- 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() { 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.