src/share/classes/java/lang/invoke/MethodHandleImpl.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Cdiff src/share/classes/java/lang/invoke/MethodHandleImpl.java

src/share/classes/java/lang/invoke/MethodHandleImpl.java

Print this page
rev 9328 : 8027827: Improve performance of catchException combinator
8034120: MethodHandles.catchException doesn't handle VarargsCollector right
Reviewed-by: lagergren, psandoz, ?

*** 25,35 **** package java.lang.invoke; import java.security.AccessController; import java.security.PrivilegedAction; - import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import sun.invoke.empty.Empty; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyType; --- 25,34 ----
*** 480,495 **** /** * Pre-initialized NamedFunctions for bootstrapping purposes. * Factored in an inner class to delay initialization until first usage. */ private static class Lazy { static final NamedFunction NF_checkSpreadArgument; static { try { ! NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class ! .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); NF_checkSpreadArgument.resolve(); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); } } } --- 479,508 ---- /** * Pre-initialized NamedFunctions for bootstrapping purposes. * Factored in an inner class to delay initialization until first usage. */ private static class Lazy { + private static final Class<?> MHI = MethodHandleImpl.class; + static final NamedFunction NF_checkSpreadArgument; + static final NamedFunction NF_guardWithCatch; + static final NamedFunction NF_selectAlternative; + static final NamedFunction NF_throwException; + static { 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_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class, ! MethodHandle.class)); ! NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class)); ! NF_checkSpreadArgument.resolve(); + NF_guardWithCatch.resolve(); + NF_selectAlternative.resolve(); + NF_throwException.resolve(); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); } } }
*** 546,573 **** LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); return SimpleMethodHandle.make(srcType, form); } static MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { return testResult ? target : fallback; } - static MethodHandle SELECT_ALTERNATIVE; - static MethodHandle selectAlternative() { - if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE; - try { - SELECT_ALTERNATIVE - = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative", - MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)); - } catch (ReflectiveOperationException ex) { - throw new RuntimeException(ex); - } - return SELECT_ALTERNATIVE; - } - static MethodHandle makeGuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) { MethodType basicType = target.type().basicType(); --- 559,574 ---- LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); return SimpleMethodHandle.make(srcType, form); } + @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 basicType = target.type().basicType();
*** 583,789 **** // call test names[arity + 1] = new Name(test, testArgs); // call selectAlternative Object[] selectArgs = { names[arity + 1], target, fallback }; ! names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs); targetArgs[0] = names[arity + 2]; // call target or fallback names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); return SimpleMethodHandle.make(target.type(), form); } ! private static class GuardWithCatch { ! private final MethodHandle target; ! private final Class<? extends Throwable> exType; ! private final MethodHandle catcher; ! // FIXME: Build the control flow out of foldArguments. ! GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) { ! this.target = target; ! this.exType = exType; ! this.catcher = catcher; ! } ! @LambdaForm.Hidden ! private Object invoke_V(Object... av) throws Throwable { ! try { ! return target.invokeExact(av); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, av); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L0() throws Throwable { ! try { ! return target.invokeExact(); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L1(Object a0) throws Throwable { ! try { ! return target.invokeExact(a0); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L2(Object a0, Object a1) throws Throwable { ! try { ! return target.invokeExact(a0, a1); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { ! try { ! return target.invokeExact(a0, a1, a2); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1, a2); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { ! try { ! return target.invokeExact(a0, a1, a2, a3); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1, a2, a3); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { ! try { ! return target.invokeExact(a0, a1, a2, a3, a4); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1, a2, a3, a4); ! } ! } ! @LambdaForm.Hidden ! private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { ! try { ! return target.invokeExact(a0, a1, a2, a3, a4, a5); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5); } } ! @LambdaForm.Hidden ! private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { try { ! return target.invokeExact(a0, a1, a2, a3, a4, a5, a6); ! } catch (Throwable t) { ! if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6); } } @LambdaForm.Hidden ! private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { try { ! return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); } catch (Throwable t) { if (!exType.isInstance(t)) throw t; ! return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7); } } - static MethodHandle[] makeInvokes() { - ArrayList<MethodHandle> invokes = new ArrayList<>(); - MethodHandles.Lookup lookup = IMPL_LOOKUP; - for (;;) { - int nargs = invokes.size(); - String name = "invoke_L"+nargs; - MethodHandle invoke = null; - try { - invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs)); - } catch (ReflectiveOperationException ex) { - } - if (invoke == null) break; - invokes.add(invoke); - } - assert(invokes.size() == 9); // current number of methods - return invokes.toArray(new MethodHandle[0]); - }; - static final MethodHandle[] INVOKES = makeInvokes(); - // For testing use this: - //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2); - static final MethodHandle VARARGS_INVOKE; - static { - try { - VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true)); - } catch (ReflectiveOperationException ex) { - throw uncaughtException(ex); - } - } - } - ! static ! MethodHandle makeGuardWithCatch(MethodHandle target, ! Class<? extends Throwable> exType, ! MethodHandle catcher) { ! MethodType type = target.type(); ! MethodType ctype = catcher.type(); ! int nargs = type.parameterCount(); ! if (nargs < GuardWithCatch.INVOKES.length) { ! MethodType gtype = type.generic(); ! MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); ! // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0) ! MethodHandle gtarget = makePairwiseConvert(target, gtype, 2); ! MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2); ! GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher); ! if (gtarget == null || gcatcher == null) throw new InternalError(); ! MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard); ! return makePairwiseConvert(ginvoker, type, 2); ! } else { ! target = target.asType(type.changeReturnType(Object.class)); ! MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs); ! MethodType catcherType = ctype.changeParameterType(0, Throwable.class) ! .changeReturnType(Object.class); ! catcher = catcher.asType(catcherType); ! MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs); ! GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher); ! if (gtarget == null || gcatcher == null) throw new InternalError(); ! MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard); ! MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false); ! return makePairwiseConvert(gcollect, type, 2); ! } } static MethodHandle throwException(MethodType type) { assert(Throwable.class.isAssignableFrom(type.parameterType(0))); int arity = type.parameterCount(); if (arity > 1) { return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); } ! return makePairwiseConvert(throwException(), type, 2); } - static MethodHandle THROW_EXCEPTION; - static MethodHandle throwException() { - MethodHandle mh = THROW_EXCEPTION; - if (mh != null) return mh; - try { - mh - = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException", - MethodType.methodType(Empty.class, Throwable.class)); - } catch (ReflectiveOperationException ex) { - throw new RuntimeException(ex); - } - THROW_EXCEPTION = mh; - return mh; - } static <T extends Throwable> Empty throwException(T t) throws T { throw t; } static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; static MethodHandle fakeMethodHandleInvoke(MemberName method) { int idx; --- 584,746 ---- // call test names[arity + 1] = new Name(test, testArgs); // call selectAlternative Object[] selectArgs = { names[arity + 1], target, fallback }; ! names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs); targetArgs[0] = names[arity + 2]; // call target or fallback names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); return SimpleMethodHandle.make(target.type(), form); } ! /** ! * The LambaForm shape for catchException combinator is the following: ! * <blockquote><pre>{@code ! * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{ ! * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L); ! * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L); ! * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L); ! * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L); ! * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L); ! * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L); ! * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L); ! * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I} ! * }</pre></blockquote> ! * ! * argL0 and argL2 are target and catcher method handles. argL1 is exception class. ! * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[] ! * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()). ! * ! * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms ! * among catchException combinators with the same basic type. ! */ ! private static LambdaForm makeGuardWithCatchForm(MethodType basicType) { ! MethodType lambdaType = basicType.invokerType(); ! ! LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC); ! if (lform != null) { ! return lform; ! } ! final int THIS_MH = 0; // the BMH_LLLLL ! final int ARG_BASE = 1; // start of incoming arguments ! final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); ! ! int nameCursor = ARG_LIMIT; ! final int GET_TARGET = nameCursor++; ! final int GET_CLASS = nameCursor++; ! final int GET_CATCHER = nameCursor++; ! final int GET_COLLECT_ARGS = nameCursor++; ! final int GET_UNBOX_RESULT = nameCursor++; ! final int BOXED_ARGS = nameCursor++; ! final int TRY_CATCH = nameCursor++; ! final int UNBOX_RESULT = nameCursor++; ! ! Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); ! ! BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); ! names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); ! names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); ! names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); ! names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]); ! names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]); ! ! // FIXME: rework argument boxing/result unboxing logic for LF interpretation ! ! // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...); ! MethodType collectArgsType = basicType.changeReturnType(Object.class); ! MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType); ! Object[] args = new Object[invokeBasic.type().parameterCount()]; ! args[0] = names[GET_COLLECT_ARGS]; ! System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); ! names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args); ! ! // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); ! Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; ! names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs); ! ! // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); ! MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); ! Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; ! names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs); ! ! lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); ! ! basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); ! return lform; } + + static + MethodHandle makeGuardWithCatch(MethodHandle target, + Class<? extends Throwable> exType, + MethodHandle catcher) { + MethodType type = target.type(); + LambdaForm form = makeGuardWithCatchForm(type.basicType()); + + // Prepare auxiliary method handles used during LambdaForm interpreation. + // Box arguments and wrap them into Object[]: ValueConversions.array(). + MethodType varargsType = type.changeReturnType(Object[].class); + MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount()) + .asType(varargsType); + // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore(). + MethodHandle unboxResult; + if (type.returnType().isPrimitive()) { + unboxResult = ValueConversions.unbox(type.returnType()); + } else { + unboxResult = ValueConversions.identity(); } ! ! BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); ! BoundMethodHandle mh; try { ! mh = (BoundMethodHandle) ! data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, ! (Object) collectArgs, (Object) unboxResult); ! } catch (Throwable ex) { ! throw uncaughtException(ex); } + assert(mh.type() == type); + return mh; } + + /** + * Intrinsified during LambdaForm compilation + * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}). + */ @LambdaForm.Hidden ! static Object guardWithCatch(MethodHandle target, Class exType, MethodHandle catcher, ! Object... av) throws Throwable { try { ! return target.invokeWithArguments(av); } catch (Throwable t) { if (!exType.isInstance(t)) throw t; ! Object[] args = prepend(t, av); ! return catcher.invokeWithArguments(args); } } ! /** Prepend an element {@code elem} to an {@code array}. */ ! private static Object[] prepend(Object elem, Object[] array) { ! Object[] newArray = new Object[array.length+1]; ! newArray[0] = elem; ! System.arraycopy(array, 0, newArray, 1, array.length); ! return newArray; } static MethodHandle throwException(MethodType type) { assert(Throwable.class.isAssignableFrom(type.parameterType(0))); int arity = type.parameterCount(); if (arity > 1) { return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); } ! return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2); } static <T extends Throwable> Empty throwException(T t) throws T { throw t; } static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; static MethodHandle fakeMethodHandleInvoke(MemberName method) { int idx;
src/share/classes/java/lang/invoke/MethodHandleImpl.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File