--- old/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java 2014-10-14 22:50:06.000000000 +0400 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java 2014-10-14 22:50:06.000000000 +0400 @@ -707,10 +707,11 @@ LambdaForm form = makeGuardWithTestForm(basicType); BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); BoundMethodHandle mh; + try { mh = (BoundMethodHandle) data.constructor().invokeBasic(type, form, - (Object) test, (Object) target, (Object) fallback); + (Object) test, (Object) profile(target), (Object) profile(fallback)); } catch (Throwable ex) { throw uncaughtException(ex); } @@ -718,6 +719,97 @@ return mh; } + + static + MethodHandle profile(MethodHandle target) { + if (DONT_INLINE_THRESHOLD >= 0) { + return BlockInliningWrapper.make(target); + } else { + return target; + } + } + + /** + * Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times. + * Corresponding LambdaForm has @DontInline when compiled into bytecode. + */ + static class BlockInliningWrapper extends DelegatingMethodHandle { + private final MethodHandle target; + private int count; + private volatile boolean isUnblocked; + + private BlockInliningWrapper(MethodHandle target, LambdaForm lform, int count) { + super(target.type(), lform); + this.target = target; + this.count = count; + this.isUnblocked = (count > 0); + } + + @Hidden + @Override + protected MethodHandle getTarget() { + return target; + } + + @Override + public MethodHandle asTypeUncached(MethodType newType) { + MethodHandle newTarget = target.asType(newType); + return asTypeCache = isUnblocked ? make(newTarget) + : newTarget; // no need for a wrapper anymore + } + + boolean unblock() { + if (count <= 0) { + // Try to limit number of updates. MethodHandle.updateForm() doesn't guarantee LF update visibility. + if (isUnblocked) { + isUnblocked = false; + return true; + } else { + return false; + } + } else { + --count; + return false; + } + } + + static MethodHandle make(MethodHandle target) { + LambdaForm lform; + if (DONT_INLINE_THRESHOLD > 0) { + lform = DelegatingMethodHandle.makeReinvokerForm(target, + MethodTypeForm.LF_DELEGATE_BLOCK_INLINING, BlockInliningWrapper.class, "reinvoker.dontInline", false, + DelegatingMethodHandle.NF_getTarget, NF_maybeUnblock); + } else { + lform = DelegatingMethodHandle.makeReinvokerForm( + target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget); + } + MethodHandle wrapper = new BlockInliningWrapper(target, lform, DONT_INLINE_THRESHOLD); + return wrapper; + } + + @Hidden + static void maybeUnblock(Object o1) { + BlockInliningWrapper wrapper = (BlockInliningWrapper) o1; + if (wrapper.unblock()) { + // Reached invocation threshold. Replace counting/blocking wrapper with a reinvoker. + MethodHandle target = wrapper.getTarget(); + LambdaForm lform = DelegatingMethodHandle.makeReinvokerForm( + target, MethodTypeForm.LF_DELEGATE, DelegatingMethodHandle.class, NF_getTarget); + wrapper.updateForm(lform); + } + } + + static final NamedFunction NF_maybeUnblock; + static { + Class THIS_CLASS = BlockInliningWrapper.class; + try { + NF_maybeUnblock = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeUnblock", Object.class)); + } catch (ReflectiveOperationException ex) { + throw newInternalError(ex); + } + } + } + static LambdaForm makeGuardWithTestForm(MethodType basicType) { LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);