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