jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 23038 bb8b3b23af3a
parent 21649 1aca56f8780c
child 23039 6ee70bc18809
equal deleted inserted replaced
23037:5d2dbc7106e9 23038:bb8b3b23af3a
    25 
    25 
    26 package java.lang.invoke;
    26 package java.lang.invoke;
    27 
    27 
    28 import java.security.AccessController;
    28 import java.security.AccessController;
    29 import java.security.PrivilegedAction;
    29 import java.security.PrivilegedAction;
    30 import java.util.ArrayList;
       
    31 import java.util.Arrays;
    30 import java.util.Arrays;
    32 import java.util.HashMap;
    31 import java.util.HashMap;
    33 import sun.invoke.empty.Empty;
    32 import sun.invoke.empty.Empty;
    34 import sun.invoke.util.ValueConversions;
    33 import sun.invoke.util.ValueConversions;
    35 import sun.invoke.util.VerifyType;
    34 import sun.invoke.util.VerifyType;
   480     /**
   479     /**
   481      * Pre-initialized NamedFunctions for bootstrapping purposes.
   480      * Pre-initialized NamedFunctions for bootstrapping purposes.
   482      * Factored in an inner class to delay initialization until first usage.
   481      * Factored in an inner class to delay initialization until first usage.
   483      */
   482      */
   484     private static class Lazy {
   483     private static class Lazy {
       
   484         private static final Class<?> MHI = MethodHandleImpl.class;
       
   485 
   485         static final NamedFunction NF_checkSpreadArgument;
   486         static final NamedFunction NF_checkSpreadArgument;
       
   487         static final NamedFunction NF_guardWithCatch;
       
   488         static final NamedFunction NF_selectAlternative;
       
   489         static final NamedFunction NF_throwException;
       
   490 
   486         static {
   491         static {
   487             try {
   492             try {
   488                 NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
   493                 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
   489                         .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
   494                 NF_guardWithCatch      = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
       
   495                                                                                  MethodHandle.class, Object[].class));
       
   496                 NF_selectAlternative   = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class,
       
   497                                                                                  MethodHandle.class));
       
   498                 NF_throwException      = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
       
   499 
   490                 NF_checkSpreadArgument.resolve();
   500                 NF_checkSpreadArgument.resolve();
       
   501                 NF_guardWithCatch.resolve();
       
   502                 NF_selectAlternative.resolve();
       
   503                 NF_throwException.resolve();
   491             } catch (ReflectiveOperationException ex) {
   504             } catch (ReflectiveOperationException ex) {
   492                 throw newInternalError(ex);
   505                 throw newInternalError(ex);
   493             }
   506             }
   494         }
   507         }
   495     }
   508     }
   546 
   559 
   547         LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
   560         LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
   548         return SimpleMethodHandle.make(srcType, form);
   561         return SimpleMethodHandle.make(srcType, form);
   549     }
   562     }
   550 
   563 
       
   564     @LambdaForm.Hidden
   551     static
   565     static
   552     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
   566     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
   553         return testResult ? target : fallback;
   567         return testResult ? target : fallback;
   554     }
       
   555 
       
   556     static MethodHandle SELECT_ALTERNATIVE;
       
   557     static MethodHandle selectAlternative() {
       
   558         if (SELECT_ALTERNATIVE != null)  return SELECT_ALTERNATIVE;
       
   559         try {
       
   560             SELECT_ALTERNATIVE
       
   561             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
       
   562                     MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class));
       
   563         } catch (ReflectiveOperationException ex) {
       
   564             throw new RuntimeException(ex);
       
   565         }
       
   566         return SELECT_ALTERNATIVE;
       
   567     }
   568     }
   568 
   569 
   569     static
   570     static
   570     MethodHandle makeGuardWithTest(MethodHandle test,
   571     MethodHandle makeGuardWithTest(MethodHandle test,
   571                                    MethodHandle target,
   572                                    MethodHandle target,
   583         // call test
   584         // call test
   584         names[arity + 1] = new Name(test, testArgs);
   585         names[arity + 1] = new Name(test, testArgs);
   585 
   586 
   586         // call selectAlternative
   587         // call selectAlternative
   587         Object[] selectArgs = { names[arity + 1], target, fallback };
   588         Object[] selectArgs = { names[arity + 1], target, fallback };
   588         names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
   589         names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs);
   589         targetArgs[0] = names[arity + 2];
   590         targetArgs[0] = names[arity + 2];
   590 
   591 
   591         // call target or fallback
   592         // call target or fallback
   592         names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
   593         names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
   593 
   594 
   594         LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
   595         LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
   595         return SimpleMethodHandle.make(target.type(), form);
   596         return SimpleMethodHandle.make(target.type(), form);
   596     }
   597     }
   597 
   598 
   598     private static class GuardWithCatch {
   599     /**
   599         private final MethodHandle target;
   600      * The LambaForm shape for catchException combinator is the following:
   600         private final Class<? extends Throwable> exType;
   601      * <blockquote><pre>{@code
   601         private final MethodHandle catcher;
   602      *  guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
   602         // FIXME: Build the control flow out of foldArguments.
   603      *    t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
   603         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
   604      *    t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
   604             this.target = target;
   605      *    t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
   605             this.exType = exType;
   606      *    t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
   606             this.catcher = catcher;
   607      *    t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
   607         }
   608      *    t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
   608         @LambdaForm.Hidden
   609      *    t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L);
   609         private Object invoke_V(Object... av) throws Throwable {
   610      *   t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I}
   610             try {
   611      * }</pre></blockquote>
   611                 return target.invokeExact(av);
   612      *
   612             } catch (Throwable t) {
   613      * argL0 and argL2 are target and catcher method handles. argL1 is exception class.
   613                 if (!exType.isInstance(t))  throw t;
   614      * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[]
   614                 return catcher.invokeExact(t, av);
   615      * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()).
   615             }
   616      *
   616         }
   617      * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms
   617         @LambdaForm.Hidden
   618      * among catchException combinators with the same basic type.
   618         private Object invoke_L0() throws Throwable {
   619      */
   619             try {
   620     private static LambdaForm makeGuardWithCatchForm(MethodType basicType) {
   620                 return target.invokeExact();
   621         MethodType lambdaType = basicType.invokerType();
   621             } catch (Throwable t) {
   622 
   622                 if (!exType.isInstance(t))  throw t;
   623         LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC);
   623                 return catcher.invokeExact(t);
   624         if (lform != null) {
   624             }
   625             return lform;
   625         }
   626         }
   626         @LambdaForm.Hidden
   627         final int THIS_MH      = 0;  // the BMH_LLLLL
   627         private Object invoke_L1(Object a0) throws Throwable {
   628         final int ARG_BASE     = 1;  // start of incoming arguments
   628             try {
   629         final int ARG_LIMIT    = ARG_BASE + basicType.parameterCount();
   629                 return target.invokeExact(a0);
   630 
   630             } catch (Throwable t) {
   631         int nameCursor = ARG_LIMIT;
   631                 if (!exType.isInstance(t))  throw t;
   632         final int GET_TARGET       = nameCursor++;
   632                 return catcher.invokeExact(t, a0);
   633         final int GET_CLASS        = nameCursor++;
   633             }
   634         final int GET_CATCHER      = nameCursor++;
   634         }
   635         final int GET_COLLECT_ARGS = nameCursor++;
   635         @LambdaForm.Hidden
   636         final int GET_UNBOX_RESULT = nameCursor++;
   636         private Object invoke_L2(Object a0, Object a1) throws Throwable {
   637         final int BOXED_ARGS       = nameCursor++;
   637             try {
   638         final int TRY_CATCH        = nameCursor++;
   638                 return target.invokeExact(a0, a1);
   639         final int UNBOX_RESULT     = nameCursor++;
   639             } catch (Throwable t) {
   640 
   640                 if (!exType.isInstance(t))  throw t;
   641         Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
   641                 return catcher.invokeExact(t, a0, a1);
   642 
   642             }
   643         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
   643         }
   644         names[GET_TARGET]       = new Name(data.getterFunction(0), names[THIS_MH]);
   644         @LambdaForm.Hidden
   645         names[GET_CLASS]        = new Name(data.getterFunction(1), names[THIS_MH]);
   645         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
   646         names[GET_CATCHER]      = new Name(data.getterFunction(2), names[THIS_MH]);
   646             try {
   647         names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]);
   647                 return target.invokeExact(a0, a1, a2);
   648         names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]);
   648             } catch (Throwable t) {
   649 
   649                 if (!exType.isInstance(t))  throw t;
   650         // FIXME: rework argument boxing/result unboxing logic for LF interpretation
   650                 return catcher.invokeExact(t, a0, a1, a2);
   651 
   651             }
   652         // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...);
   652         }
   653         MethodType collectArgsType = basicType.changeReturnType(Object.class);
   653         @LambdaForm.Hidden
   654         MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType);
   654         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
   655         Object[] args = new Object[invokeBasic.type().parameterCount()];
   655             try {
   656         args[0] = names[GET_COLLECT_ARGS];
   656                 return target.invokeExact(a0, a1, a2, a3);
   657         System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
   657             } catch (Throwable t) {
   658         names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args);
   658                 if (!exType.isInstance(t))  throw t;
   659 
   659                 return catcher.invokeExact(t, a0, a1, a2, a3);
   660         // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
   660             }
   661         Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
   661         }
   662         names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs);
   662         @LambdaForm.Hidden
   663 
   663         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
   664         // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
   664             try {
   665         MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
   665                 return target.invokeExact(a0, a1, a2, a3, a4);
   666         Object[] unboxArgs  = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
   666             } catch (Throwable t) {
   667         names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs);
   667                 if (!exType.isInstance(t))  throw t;
   668 
   668                 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
   669         lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
   669             }
   670 
   670         }
   671         basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
   671         @LambdaForm.Hidden
   672         return lform;
   672         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
   673     }
   673             try {
       
   674                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
       
   675             } catch (Throwable t) {
       
   676                 if (!exType.isInstance(t))  throw t;
       
   677                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
       
   678             }
       
   679         }
       
   680         @LambdaForm.Hidden
       
   681         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
       
   682             try {
       
   683                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
       
   684             } catch (Throwable t) {
       
   685                 if (!exType.isInstance(t))  throw t;
       
   686                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
       
   687             }
       
   688         }
       
   689         @LambdaForm.Hidden
       
   690         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
       
   691             try {
       
   692                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
       
   693             } catch (Throwable t) {
       
   694                 if (!exType.isInstance(t))  throw t;
       
   695                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
       
   696             }
       
   697         }
       
   698         static MethodHandle[] makeInvokes() {
       
   699             ArrayList<MethodHandle> invokes = new ArrayList<>();
       
   700             MethodHandles.Lookup lookup = IMPL_LOOKUP;
       
   701             for (;;) {
       
   702                 int nargs = invokes.size();
       
   703                 String name = "invoke_L"+nargs;
       
   704                 MethodHandle invoke = null;
       
   705                 try {
       
   706                     invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
       
   707                 } catch (ReflectiveOperationException ex) {
       
   708                 }
       
   709                 if (invoke == null)  break;
       
   710                 invokes.add(invoke);
       
   711             }
       
   712             assert(invokes.size() == 9);  // current number of methods
       
   713             return invokes.toArray(new MethodHandle[0]);
       
   714         };
       
   715         static final MethodHandle[] INVOKES = makeInvokes();
       
   716         // For testing use this:
       
   717         //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
       
   718         static final MethodHandle VARARGS_INVOKE;
       
   719         static {
       
   720             try {
       
   721                 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
       
   722             } catch (ReflectiveOperationException ex) {
       
   723                 throw uncaughtException(ex);
       
   724             }
       
   725         }
       
   726     }
       
   727 
       
   728 
   674 
   729     static
   675     static
   730     MethodHandle makeGuardWithCatch(MethodHandle target,
   676     MethodHandle makeGuardWithCatch(MethodHandle target,
   731                                     Class<? extends Throwable> exType,
   677                                     Class<? extends Throwable> exType,
   732                                     MethodHandle catcher) {
   678                                     MethodHandle catcher) {
   733         MethodType type = target.type();
   679         MethodType type = target.type();
   734         MethodType ctype = catcher.type();
   680         LambdaForm form = makeGuardWithCatchForm(type.basicType());
   735         int nargs = type.parameterCount();
   681 
   736         if (nargs < GuardWithCatch.INVOKES.length) {
   682         // Prepare auxiliary method handles used during LambdaForm interpreation.
   737             MethodType gtype = type.generic();
   683         // Box arguments and wrap them into Object[]: ValueConversions.array().
   738             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
   684         MethodType varargsType = type.changeReturnType(Object[].class);
   739             // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
   685         MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount())
   740             MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
   686                                                    .asType(varargsType);
   741             MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
   687         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
   742             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
   688         MethodHandle unboxResult;
   743             if (gtarget == null || gcatcher == null)  throw new InternalError();
   689         if (type.returnType().isPrimitive()) {
   744             MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
   690             unboxResult = ValueConversions.unbox(type.returnType());
   745             return makePairwiseConvert(ginvoker, type, 2);
       
   746         } else {
   691         } else {
   747             target = target.asType(type.changeReturnType(Object.class));
   692             unboxResult = ValueConversions.identity();
   748             MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
   693         }
   749             MethodType catcherType = ctype.changeParameterType(0, Throwable.class)
   694 
   750                                           .changeReturnType(Object.class);
   695         BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
   751             catcher = catcher.asType(catcherType);
   696         BoundMethodHandle mh;
   752             MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
   697         try {
   753             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
   698             mh = (BoundMethodHandle)
   754             if (gtarget == null || gcatcher == null)  throw new InternalError();
   699                     data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher,
   755             MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
   700                                                     (Object) collectArgs, (Object) unboxResult);
   756             MethodHandle gcollect = makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
   701         } catch (Throwable ex) {
   757             return makePairwiseConvert(gcollect, type, 2);
   702             throw uncaughtException(ex);
   758         }
   703         }
       
   704         assert(mh.type() == type);
       
   705         return mh;
       
   706     }
       
   707 
       
   708     /**
       
   709      * Intrinsified during LambdaForm compilation
       
   710      * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}).
       
   711      */
       
   712     @LambdaForm.Hidden
       
   713     static Object guardWithCatch(MethodHandle target, Class exType, MethodHandle catcher,
       
   714                                  Object... av) throws Throwable {
       
   715         try {
       
   716             return target.invokeWithArguments(av);
       
   717         } catch (Throwable t) {
       
   718             if (!exType.isInstance(t)) throw t;
       
   719             Object[] args = prepend(t, av);
       
   720             return catcher.invokeWithArguments(args);
       
   721         }
       
   722     }
       
   723 
       
   724     /** Prepend an element {@code elem} to an {@code array}. */
       
   725     private static Object[] prepend(Object elem, Object[] array) {
       
   726         Object[] newArray = new Object[array.length+1];
       
   727         newArray[0] = elem;
       
   728         System.arraycopy(array, 0, newArray, 1, array.length);
       
   729         return newArray;
   759     }
   730     }
   760 
   731 
   761     static
   732     static
   762     MethodHandle throwException(MethodType type) {
   733     MethodHandle throwException(MethodType type) {
   763         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
   734         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
   764         int arity = type.parameterCount();
   735         int arity = type.parameterCount();
   765         if (arity > 1) {
   736         if (arity > 1) {
   766             return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
   737             return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
   767         }
   738         }
   768         return makePairwiseConvert(throwException(), type, 2);
   739         return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2);
   769     }
   740     }
   770 
   741 
   771     static MethodHandle THROW_EXCEPTION;
       
   772     static MethodHandle throwException() {
       
   773         MethodHandle mh = THROW_EXCEPTION;
       
   774         if (mh != null)  return mh;
       
   775         try {
       
   776             mh
       
   777             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
       
   778                     MethodType.methodType(Empty.class, Throwable.class));
       
   779         } catch (ReflectiveOperationException ex) {
       
   780             throw new RuntimeException(ex);
       
   781         }
       
   782         THROW_EXCEPTION = mh;
       
   783         return mh;
       
   784     }
       
   785     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
   742     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
   786 
   743 
   787     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
   744     static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
   788     static MethodHandle fakeMethodHandleInvoke(MemberName method) {
   745     static MethodHandle fakeMethodHandleInvoke(MemberName method) {
   789         int idx;
   746         int idx;