--- old/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java 2015-01-20 21:59:49.000000000 +0300 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java 2015-01-20 21:59:48.000000000 +0300 @@ -632,7 +632,7 @@ MH_selectAlternative = makeIntrinsic( IMPL_LOOKUP.findStatic(MHI, "selectAlternative", - MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)), + MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class, int[].class)), Intrinsic.SELECT_ALTERNATIVE); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); @@ -696,8 +696,36 @@ @LambdaForm.Hidden static - MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { - return testResult ? target : fallback; + MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback, int[] counters) { + if (counters != null) { + updateCounters(counters, testResult); + } + if (testResult) { + return target; + } else { + return fallback; + } + } + + // Intrinsified by C2. Counters are used during parsing to calculate branch frequencies. + @LambdaForm.Hidden + static + boolean profileBranch(boolean result, int[] counters) { + updateCounters(counters, result); + return result; + } + + @LambdaForm.Hidden + @ForceInline + static + void updateCounters(int[] counters, boolean result) { + int idx = result ? 0 : 1; + try { + counters[idx] = Math.addExact(counters[idx], 1); + } catch (ArithmeticException e) { + // Avoid continuous overflow by halving the problematic count. + counters[idx] = counters[idx] / 2; + } } static @@ -707,14 +735,15 @@ MethodType type = target.type(); assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type)); MethodType basicType = type.basicType(); + int[] counters = PROFILE_GWT ? new int[2] : null; LambdaForm form = makeGuardWithTestForm(basicType); - BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); + BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLL(); BoundMethodHandle mh; try { mh = (BoundMethodHandle) data.constructor().invokeBasic(type, form, - (Object) test, (Object) profile(target), (Object) profile(fallback)); + (Object) test, (Object) profile(target), (Object) profile(fallback), counters); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -856,6 +885,7 @@ final int GET_TEST = nameCursor++; final int GET_TARGET = nameCursor++; final int GET_FALLBACK = nameCursor++; + final int GET_COUNTERS = nameCursor++; final int CALL_TEST = nameCursor++; final int SELECT_ALT = nameCursor++; final int CALL_TARGET = nameCursor++; @@ -864,12 +894,12 @@ MethodType lambdaType = basicType.invokerType(); Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); - BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); + BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLL(); 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]); - + names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]); Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class); // call test @@ -879,13 +909,13 @@ // call selectAlternative names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST], - names[GET_TARGET], names[GET_FALLBACK]); + names[GET_TARGET], names[GET_FALLBACK], names[GET_COUNTERS]); // 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); }