jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
changeset 13423 17843fff200d
parent 13420 62cedce8afa6
child 13610 28122b96858e
equal deleted inserted replaced
13422:72b63ee33f57 13423:17843fff200d
    24  */
    24  */
    25 
    25 
    26 package java.lang.invoke;
    26 package java.lang.invoke;
    27 
    27 
    28 import sun.invoke.util.VerifyType;
    28 import sun.invoke.util.VerifyType;
    29 import java.security.AccessController;
    29 
    30 import java.security.PrivilegedAction;
       
    31 import java.util.ArrayList;
    30 import java.util.ArrayList;
    32 import java.util.Arrays;
    31 import java.util.Arrays;
    33 import java.util.Collections;
       
    34 import java.util.HashMap;
    32 import java.util.HashMap;
    35 import java.util.List;
       
    36 import sun.invoke.empty.Empty;
    33 import sun.invoke.empty.Empty;
    37 import sun.invoke.util.ValueConversions;
    34 import sun.invoke.util.ValueConversions;
    38 import sun.invoke.util.Wrapper;
    35 import sun.invoke.util.Wrapper;
    39 import sun.misc.Unsafe;
    36 import static java.lang.invoke.LambdaForm.*;
    40 import static java.lang.invoke.MethodHandleStatics.*;
    37 import static java.lang.invoke.MethodHandleStatics.*;
    41 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
    38 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
    42 
    39 
    43 /**
    40 /**
    44  * Trusted implementation code for MethodHandle.
    41  * Trusted implementation code for MethodHandle.
    45  * @author jrose
    42  * @author jrose
    46  */
    43  */
    47 /*non-public*/ abstract class MethodHandleImpl {
    44 /*non-public*/ abstract class MethodHandleImpl {
    48     /// Factory methods to create method handles:
    45     /// Factory methods to create method handles:
    49 
    46 
    50     private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
       
    51 
       
    52     static void initStatics() {
    47     static void initStatics() {
    53         // Trigger preceding sequence.
    48         // Trigger selected static initializations.
    54     }
    49         MemberName.Factory.INSTANCE.getClass();
    55 
    50     }
    56     /** Look up a given method.
    51 
    57      * Callable only from sun.invoke and related packages.
    52     static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) {
    58      * <p>
    53         if (!arrayClass.isArray())
    59      * The resulting method handle type will be of the given type,
    54             throw newIllegalArgumentException("not an array: "+arrayClass);
    60      * with a receiver type {@code rcvc} prepended if the member is not static.
    55         MethodHandle accessor = ArrayAccessor.getAccessor(arrayClass, isSetter);
    61      * <p>
    56         MethodType srcType = accessor.type().erase();
    62      * Access checks are made as of the given lookup class.
    57         MethodType lambdaType = srcType.invokerType();
    63      * In particular, if the method is protected and {@code defc} is in a
    58         Name[] names = arguments(1, lambdaType);
    64      * different package from the lookup class, then {@code rcvc} must be
    59         Name[] args  = Arrays.copyOfRange(names, 1, 1 + srcType.parameterCount());
    65      * the lookup class or a subclass.
    60         names[names.length - 1] = new Name(accessor.asType(srcType), (Object[]) args);
    66      * @param token Proof that the lookup class has access to this package.
    61         LambdaForm form = new LambdaForm("getElement", lambdaType.parameterCount(), names);
    67      * @param member Resolved method or constructor to call.
    62         MethodHandle mh = new SimpleMethodHandle(srcType, form);
    68      * @param name Name of the desired method.
    63         if (ArrayAccessor.needCast(arrayClass)) {
    69      * @param rcvc Receiver type of desired non-static method (else null)
    64             mh = mh.bindTo(arrayClass);
    70      * @param doDispatch whether the method handle will test the receiver type
    65         }
    71      * @param lookupClass access-check relative to this class
    66         mh = mh.asType(ArrayAccessor.correctType(arrayClass, isSetter));
    72      * @return a direct handle to the matching method
    67         return mh;
    73      * @throws IllegalAccessException if the given method cannot be accessed by the lookup class
    68     }
    74      */
    69 
    75     static
    70     static final class ArrayAccessor {
    76     MethodHandle findMethod(MemberName method,
    71         /// Support for array element access
    77                             boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException {
    72         static final HashMap<Class<?>, MethodHandle> GETTER_CACHE = new HashMap<>();  // TODO use it
    78         MethodType mtype = method.getMethodType();
    73         static final HashMap<Class<?>, MethodHandle> SETTER_CACHE = new HashMap<>();  // TODO use it
    79         if (!method.isStatic()) {
    74 
    80             // adjust the advertised receiver type to be exactly the one requested
    75         static int     getElementI(int[]     a, int i)            { return              a[i]; }
    81             // (in the case of invokespecial, this will be the calling class)
    76         static long    getElementJ(long[]    a, int i)            { return              a[i]; }
    82             Class<?> recvType = method.getDeclaringClass();
    77         static float   getElementF(float[]   a, int i)            { return              a[i]; }
    83             mtype = mtype.insertParameterTypes(0, recvType);
    78         static double  getElementD(double[]  a, int i)            { return              a[i]; }
    84         }
    79         static boolean getElementZ(boolean[] a, int i)            { return              a[i]; }
    85         DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
    80         static byte    getElementB(byte[]    a, int i)            { return              a[i]; }
    86         if (!mh.isValid())
    81         static short   getElementS(short[]   a, int i)            { return              a[i]; }
    87             throw method.makeAccessException("no direct method handle", lookupClass);
    82         static char    getElementC(char[]    a, int i)            { return              a[i]; }
    88         assert(mh.type() == mtype);
    83         static Object  getElementL(Object[]  a, int i)            { return              a[i]; }
    89         if (!method.isVarargs())
    84 
    90             return mh;
    85         static void    setElementI(int[]     a, int i, int     x) {              a[i] = x; }
    91         int argc = mtype.parameterCount();
    86         static void    setElementJ(long[]    a, int i, long    x) {              a[i] = x; }
    92         if (argc != 0) {
    87         static void    setElementF(float[]   a, int i, float   x) {              a[i] = x; }
    93             Class<?> arrayType = mtype.parameterType(argc-1);
    88         static void    setElementD(double[]  a, int i, double  x) {              a[i] = x; }
    94             if (arrayType.isArray())
    89         static void    setElementZ(boolean[] a, int i, boolean x) {              a[i] = x; }
    95                 return AdapterMethodHandle.makeVarargsCollector(mh, arrayType);
    90         static void    setElementB(byte[]    a, int i, byte    x) {              a[i] = x; }
    96         }
    91         static void    setElementS(short[]   a, int i, short   x) {              a[i] = x; }
    97         throw method.makeAccessException("cannot make variable arity", null);
    92         static void    setElementC(char[]    a, int i, char    x) {              a[i] = x; }
    98     }
    93         static void    setElementL(Object[]  a, int i, Object  x) {              a[i] = x; }
    99 
    94 
   100     static
    95         static Object  getElementL(Class<?> arrayClass, Object[] a, int i)           { arrayClass.cast(a); return a[i]; }
   101     MethodHandle makeAllocator(MethodHandle rawConstructor) {
    96         static void    setElementL(Class<?> arrayClass, Object[] a, int i, Object x) { arrayClass.cast(a); a[i] = x; }
   102         MethodType rawConType = rawConstructor.type();
    97 
   103         Class<?> allocateClass = rawConType.parameterType(0);
    98         // Weakly typed wrappers of Object[] accessors:
   104         // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
    99         static Object  getElementL(Object    a, int i)            { return getElementL((Object[])a, i); }
   105         assert(AdapterMethodHandle.canCollectArguments(rawConType, MethodType.methodType(allocateClass), 0, true));
   100         static void    setElementL(Object    a, int i, Object  x) {        setElementL((Object[]) a, i, x); }
   106         // allocator(arg...)
   101         static Object  getElementL(Object   arrayClass, Object a, int i)             { return getElementL((Class<?>) arrayClass, (Object[])a, i); }
   107         // [fold]=> cookedConstructor(obj=allocate(C), arg...)
   102         static void    setElementL(Object   arrayClass, Object a, int i, Object x)   {        setElementL((Class<?>) arrayClass, (Object[])a, i, x); }
   108         // [dup,collect]=> identity(obj, void=rawConstructor(obj, arg...))
   103 
   109         MethodHandle returner = MethodHandles.identity(allocateClass);
   104         static boolean needCast(Class<?> arrayClass) {
   110         MethodType ctype = rawConType.insertParameterTypes(0, allocateClass).changeReturnType(allocateClass);
   105             Class<?> elemClass = arrayClass.getComponentType();
   111         MethodHandle  cookedConstructor = AdapterMethodHandle.makeCollectArguments(returner, rawConstructor, 1, false);
   106             return !elemClass.isPrimitive() && elemClass != Object.class;
   112         assert(cookedConstructor.type().equals(ctype));
   107         }
   113         ctype = ctype.dropParameterTypes(0, 1);
   108         static String name(Class<?> arrayClass, boolean isSetter) {
   114         cookedConstructor = AdapterMethodHandle.makeCollectArguments(cookedConstructor, returner, 0, true);
   109             Class<?> elemClass = arrayClass.getComponentType();
   115         AllocateObject allocator = new AllocateObject(allocateClass);
   110             if (elemClass == null)  throw new IllegalArgumentException();
   116         // allocate() => new C(void)
   111             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass);
   117         assert(allocator.type().equals(MethodType.methodType(allocateClass)));
   112         }
   118         ctype = ctype.dropParameterTypes(0, 1);
   113         static final boolean USE_WEAKLY_TYPED_ARRAY_ACCESSORS = false;  // FIXME: decide
   119         MethodHandle fold = foldArguments(cookedConstructor, ctype, 0, allocator);
   114         static MethodType type(Class<?> arrayClass, boolean isSetter) {
   120         return fold;
   115             Class<?> elemClass = arrayClass.getComponentType();
   121     }
   116             Class<?> arrayArgClass = arrayClass;
   122 
   117             if (!elemClass.isPrimitive()) {
   123     static final class AllocateObject /*<C>*/ extends BoundMethodHandle {
   118                 arrayArgClass = Object[].class;
   124         private static final Unsafe unsafe = Unsafe.getUnsafe();
   119                 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
   125 
   120                     arrayArgClass = Object.class;
   126         private final Class<?> /*<C>*/ allocateClass;
   121             }
   127 
   122             if (!needCast(arrayClass)) {
   128         // for allocation only:
   123                 return !isSetter ?
   129         private AllocateObject(Class<?> /*<C>*/ allocateClass) {
   124                     MethodType.methodType(elemClass,  arrayArgClass, int.class) :
   130             super(ALLOCATE.asType(MethodType.methodType(allocateClass, AllocateObject.class)));
   125                     MethodType.methodType(void.class, arrayArgClass, int.class, elemClass);
   131             this.allocateClass = allocateClass;
   126             } else {
   132         }
   127                 Class<?> classArgClass = Class.class;
   133         @SuppressWarnings("unchecked")
   128                 if (USE_WEAKLY_TYPED_ARRAY_ACCESSORS)
   134         private Object /*C*/ allocate() throws InstantiationException {
   129                     classArgClass = Object.class;
   135             return unsafe.allocateInstance(allocateClass);
   130                 return !isSetter ?
   136         }
   131                     MethodType.methodType(Object.class, classArgClass, arrayArgClass, int.class) :
   137         static final MethodHandle ALLOCATE;
   132                     MethodType.methodType(void.class,   classArgClass, arrayArgClass, int.class, Object.class);
   138         static {
   133             }
   139             try {
   134         }
   140                 ALLOCATE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "allocate", MethodType.genericMethodType(0));
   135         static MethodType correctType(Class<?> arrayClass, boolean isSetter) {
       
   136             Class<?> elemClass = arrayClass.getComponentType();
       
   137             return !isSetter ?
       
   138                     MethodType.methodType(elemClass,  arrayClass, int.class) :
       
   139                     MethodType.methodType(void.class, arrayClass, int.class, elemClass);
       
   140         }
       
   141         static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) {
       
   142             String     name = name(arrayClass, isSetter);
       
   143             MethodType type = type(arrayClass, isSetter);
       
   144             try {
       
   145                 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type);
   141             } catch (ReflectiveOperationException ex) {
   146             } catch (ReflectiveOperationException ex) {
   142                 throw uncaughtException(ex);
   147                 throw uncaughtException(ex);
   143             }
   148             }
   144         }
   149         }
   145     }
   150     }
   146 
   151 
   147     static
   152     /**
   148     MethodHandle accessField(MemberName member, boolean isSetter,
   153      * Create a JVM-level adapter method handle to conform the given method
   149                              Class<?> lookupClass) {
   154      * handle to the similar newType, using only pairwise argument conversions.
   150         // Use sun. misc.Unsafe to dig up the dirt on the field.
   155      * For each argument, convert incoming argument to the exact type needed.
   151         FieldAccessor accessor = new FieldAccessor(member, isSetter);
   156      * The argument conversions allowed are casting, boxing and unboxing,
   152         return accessor;
   157      * integral widening or narrowing, and floating point widening or narrowing.
   153     }
   158      * @param srcType required call type
   154 
   159      * @param target original method handle
   155     static
   160      * @param level which strength of conversion is allowed
   156     MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) {
   161      * @return an adapter to the original handle with the desired new type,
   157         if (!arrayClass.isArray())
   162      *          or the original target if the types are already identical
   158             throw newIllegalArgumentException("not an array: "+arrayClass);
   163      *          or null if the adaptation cannot be made
   159         Class<?> elemClass = arrayClass.getComponentType();
   164      */
   160         MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
   165     static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) {
   161         if (mhs == null) {
   166         assert(level >= 0 && level <= 2);
   162             if (!FieldAccessor.doCache(elemClass))
   167         MethodType dstType = target.type();
   163                 return FieldAccessor.ahandle(arrayClass, isSetter);
   168         assert(dstType.parameterCount() == target.type().parameterCount());
   164             mhs = new MethodHandle[] {
   169         if (srcType == dstType)
   165                 FieldAccessor.ahandle(arrayClass, false),
   170             return target;
   166                 FieldAccessor.ahandle(arrayClass, true)
   171 
   167             };
   172         // Calculate extra arguments (temporaries) required in the names array.
   168             if (mhs[0].type().parameterType(0) == Class.class) {
   173         // FIXME: Use an ArrayList<Name>.  Some arguments require more than one conversion step.
   169                 mhs[0] = mhs[0].bindTo(elemClass);
   174         int extra = 0;
   170                 mhs[1] = mhs[1].bindTo(elemClass);
   175         for (int i = 0; i < srcType.parameterCount(); i++) {
   171             }
   176             Class<?> src = srcType.parameterType(i);
   172             synchronized (FieldAccessor.ARRAY_CACHE) {}  // memory barrier
   177             Class<?> dst = dstType.parameterType(i);
   173             FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
   178             if (!VerifyType.isNullConversion(src, dst)) {
   174         }
   179                 extra++;
   175         return mhs[isSetter ? 1 : 0];
   180             }
   176     }
   181         }
   177 
   182 
   178     static final class FieldAccessor /*<C,V>*/ extends BoundMethodHandle {
   183         Class<?> needReturn = srcType.returnType();
   179         private static final Unsafe unsafe = Unsafe.getUnsafe();
   184         Class<?> haveReturn = dstType.returnType();
   180         final Object base;  // for static refs only
   185         boolean retConv = !VerifyType.isNullConversion(haveReturn, needReturn);
   181         final long offset;
   186 
   182         final String name;
   187         // Now build a LambdaForm.
   183 
   188         MethodType lambdaType = srcType.invokerType();
   184         FieldAccessor(MemberName field, boolean isSetter) {
   189         Name[] names = arguments(extra + 1, lambdaType);
   185             super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
   190         int[] indexes = new int[lambdaType.parameterCount()];
   186             this.offset = (long) field.getVMIndex();
   191 
   187             this.name = field.getName();
   192         MethodType midType = dstType;
   188             this.base = staticBase(field);
   193         for (int i = 0, argIndex = 1, tmpIndex = lambdaType.parameterCount(); i < srcType.parameterCount(); i++, argIndex++) {
   189         }
   194             Class<?> src = srcType.parameterType(i);
   190         @Override
   195             Class<?> dst = midType.parameterType(i);
   191         String debugString() { return addTypeString(name, this); }
   196 
   192 
   197             if (VerifyType.isNullConversion(src, dst)) {
   193         private static Object nullCheck(Object obj) {
   198                 // do nothing: difference is trivial
   194             obj.getClass();  // NPE
   199                 indexes[i] = argIndex;
   195             return obj;
   200                 continue;
   196         }
   201             }
   197 
   202 
   198         int getFieldI(Object /*C*/ obj) { return unsafe.getInt(nullCheck(obj), offset); }
   203             // Work the current type backward toward the desired caller type:
   199         void setFieldI(Object /*C*/ obj, int x) { unsafe.putInt(nullCheck(obj), offset, x); }
   204             midType = midType.changeParameterType(i, src);
   200         long getFieldJ(Object /*C*/ obj) { return unsafe.getLong(nullCheck(obj), offset); }
   205 
   201         void setFieldJ(Object /*C*/ obj, long x) { unsafe.putLong(nullCheck(obj), offset, x); }
   206             // Tricky case analysis follows.
   202         float getFieldF(Object /*C*/ obj) { return unsafe.getFloat(nullCheck(obj), offset); }
   207             MethodHandle fn = null;
   203         void setFieldF(Object /*C*/ obj, float x) { unsafe.putFloat(nullCheck(obj), offset, x); }
   208             if (src.isPrimitive()) {
   204         double getFieldD(Object /*C*/ obj) { return unsafe.getDouble(nullCheck(obj), offset); }
   209                 if (dst.isPrimitive()) {
   205         void setFieldD(Object /*C*/ obj, double x) { unsafe.putDouble(nullCheck(obj), offset, x); }
   210                     fn = ValueConversions.convertPrimitive(src, dst);
   206         boolean getFieldZ(Object /*C*/ obj) { return unsafe.getBoolean(nullCheck(obj), offset); }
   211                 } else {
   207         void setFieldZ(Object /*C*/ obj, boolean x) { unsafe.putBoolean(nullCheck(obj), offset, x); }
   212                     Wrapper w = Wrapper.forPrimitiveType(src);
   208         byte getFieldB(Object /*C*/ obj) { return unsafe.getByte(nullCheck(obj), offset); }
   213                     MethodHandle boxMethod = ValueConversions.box(w);
   209         void setFieldB(Object /*C*/ obj, byte x) { unsafe.putByte(nullCheck(obj), offset, x); }
   214                     if (dst == w.wrapperType())
   210         short getFieldS(Object /*C*/ obj) { return unsafe.getShort(nullCheck(obj), offset); }
   215                         fn = boxMethod;
   211         void setFieldS(Object /*C*/ obj, short x) { unsafe.putShort(nullCheck(obj), offset, x); }
   216                     else
   212         char getFieldC(Object /*C*/ obj) { return unsafe.getChar(nullCheck(obj), offset); }
   217                         fn = boxMethod.asType(MethodType.methodType(dst, src));
   213         void setFieldC(Object /*C*/ obj, char x) { unsafe.putChar(nullCheck(obj), offset, x); }
   218                 }
   214         Object /*V*/ getFieldL(Object /*C*/ obj) { return unsafe.getObject(nullCheck(obj), offset); }
       
   215         void setFieldL(Object /*C*/ obj, Object /*V*/ x) { unsafe.putObject(nullCheck(obj), offset, x); }
       
   216 
       
   217         static Object staticBase(final MemberName field) {
       
   218             if (!field.isStatic())  return null;
       
   219             return AccessController.doPrivileged(new PrivilegedAction<Object>() {
       
   220                     public Object run() {
       
   221                         try {
       
   222                             Class<?> c = field.getDeclaringClass();
       
   223                             // FIXME:  Should not have to create 'f' to get this value.
       
   224                             java.lang.reflect.Field f = c.getDeclaredField(field.getName());
       
   225                             return unsafe.staticFieldBase(f);
       
   226                         } catch (NoSuchFieldException ee) {
       
   227                             throw uncaughtException(ee);
       
   228                         }
       
   229                     }
       
   230                 });
       
   231         }
       
   232 
       
   233         int getStaticI() { return unsafe.getInt(base, offset); }
       
   234         void setStaticI(int x) { unsafe.putInt(base, offset, x); }
       
   235         long getStaticJ() { return unsafe.getLong(base, offset); }
       
   236         void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
       
   237         float getStaticF() { return unsafe.getFloat(base, offset); }
       
   238         void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
       
   239         double getStaticD() { return unsafe.getDouble(base, offset); }
       
   240         void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
       
   241         boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
       
   242         void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
       
   243         byte getStaticB() { return unsafe.getByte(base, offset); }
       
   244         void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
       
   245         short getStaticS() { return unsafe.getShort(base, offset); }
       
   246         void setStaticS(short x) { unsafe.putShort(base, offset, x); }
       
   247         char getStaticC() { return unsafe.getChar(base, offset); }
       
   248         void setStaticC(char x) { unsafe.putChar(base, offset, x); }
       
   249         Object /*V*/ getStaticL() { return unsafe.getObject(base, offset); }
       
   250         void setStaticL(Object /*V*/ x) { unsafe.putObject(base, offset, x); }
       
   251 
       
   252         static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
       
   253             String stem;
       
   254             if (!isStatic)
       
   255                 stem = (!isSetter ? "getField" : "setField");
       
   256             else
       
   257                 stem = (!isSetter ? "getStatic" : "setStatic");
       
   258             return stem + Wrapper.basicTypeChar(vclass);
       
   259         }
       
   260         static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
       
   261             MethodType type;
       
   262             if (!isStatic) {
       
   263                 if (!isSetter)
       
   264                     return MethodType.methodType(vclass, cclass);
       
   265                 else
       
   266                     return MethodType.methodType(void.class, cclass, vclass);
       
   267             } else {
   219             } else {
   268                 if (!isSetter)
   220                 if (dst.isPrimitive()) {
   269                     return MethodType.methodType(vclass);
   221                     // Caller has boxed a primitive.  Unbox it for the target.
   270                 else
   222                     Wrapper w = Wrapper.forPrimitiveType(dst);
   271                     return MethodType.methodType(void.class, vclass);
   223                     if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType())) {
   272             }
   224                         fn = ValueConversions.unbox(dst);
   273         }
   225                     } else if (src == Object.class || !Wrapper.isWrapperType(src)) {
   274         static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
   226                         // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
   275             String name = FieldAccessor.fname(vclass, isSetter, isStatic);
   227                         // must include additional conversions
   276             if (cclass.isPrimitive())  throw newIllegalArgumentException("primitive "+cclass);
   228                         // src must be examined at runtime, to detect Byte, Character, etc.
   277             Class<?> ecclass = Object.class;  //erase this type
   229                         MethodHandle unboxMethod = (level == 1
   278             Class<?> evclass = vclass;
   230                                                     ? ValueConversions.unbox(dst)
   279             if (!evclass.isPrimitive())  evclass = Object.class;
   231                                                     : ValueConversions.unboxCast(dst));
   280             MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
   232                         fn = unboxMethod;
   281             MethodHandle mh;
   233                     } else {
   282             try {
   234                         // Example: Byte->int
   283                 mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
   235                         // Do this by reformulating the problem to Byte->byte.
   284             } catch (ReflectiveOperationException ex) {
   236                         Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
   285                 throw uncaughtException(ex);
   237                         MethodHandle unbox = ValueConversions.unbox(srcPrim);
   286             }
   238                         // Compose the two conversions.  FIXME:  should make two Names for this job
   287             if (evclass != vclass || (!isStatic && ecclass != cclass)) {
   239                         fn = unbox.asType(MethodType.methodType(dst, src));
   288                 MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
       
   289                 strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
       
   290                 mh = convertArguments(mh, strongType, 0);
       
   291             }
       
   292             return mh;
       
   293         }
       
   294 
       
   295         /// Support for array element access
       
   296         static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE =
       
   297                 new HashMap<Class<?>, MethodHandle[]>();
       
   298         // FIXME: Cache on the classes themselves, not here.
       
   299         static boolean doCache(Class<?> elemClass) {
       
   300             if (elemClass.isPrimitive())  return true;
       
   301             ClassLoader cl = elemClass.getClassLoader();
       
   302             return cl == null || cl == ClassLoader.getSystemClassLoader();
       
   303         }
       
   304         static int getElementI(int[] a, int i) { return a[i]; }
       
   305         static void setElementI(int[] a, int i, int x) { a[i] = x; }
       
   306         static long getElementJ(long[] a, int i) { return a[i]; }
       
   307         static void setElementJ(long[] a, int i, long x) { a[i] = x; }
       
   308         static float getElementF(float[] a, int i) { return a[i]; }
       
   309         static void setElementF(float[] a, int i, float x) { a[i] = x; }
       
   310         static double getElementD(double[] a, int i) { return a[i]; }
       
   311         static void setElementD(double[] a, int i, double x) { a[i] = x; }
       
   312         static boolean getElementZ(boolean[] a, int i) { return a[i]; }
       
   313         static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
       
   314         static byte getElementB(byte[] a, int i) { return a[i]; }
       
   315         static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
       
   316         static short getElementS(short[] a, int i) { return a[i]; }
       
   317         static void setElementS(short[] a, int i, short x) { a[i] = x; }
       
   318         static char getElementC(char[] a, int i) { return a[i]; }
       
   319         static void setElementC(char[] a, int i, char x) { a[i] = x; }
       
   320         static Object getElementL(Object[] a, int i) { return a[i]; }
       
   321         static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
       
   322         static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; }
       
   323         static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
       
   324 
       
   325         static String aname(Class<?> aclass, boolean isSetter) {
       
   326             Class<?> vclass = aclass.getComponentType();
       
   327             if (vclass == null)  throw new IllegalArgumentException();
       
   328             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
       
   329         }
       
   330         static MethodType atype(Class<?> aclass, boolean isSetter) {
       
   331             Class<?> vclass = aclass.getComponentType();
       
   332             if (!isSetter)
       
   333                 return MethodType.methodType(vclass, aclass, int.class);
       
   334             else
       
   335                 return MethodType.methodType(void.class, aclass, int.class, vclass);
       
   336         }
       
   337         static MethodHandle ahandle(Class<?> aclass, boolean isSetter) {
       
   338             Class<?> vclass = aclass.getComponentType();
       
   339             String name = FieldAccessor.aname(aclass, isSetter);
       
   340             Class<?> caclass = null;
       
   341             if (!vclass.isPrimitive() && vclass != Object.class) {
       
   342                 caclass = aclass;
       
   343                 aclass = Object[].class;
       
   344                 vclass = Object.class;
       
   345             }
       
   346             MethodType type = FieldAccessor.atype(aclass, isSetter);
       
   347             if (caclass != null)
       
   348                 type = type.insertParameterTypes(0, Class.class);
       
   349             MethodHandle mh;
       
   350             try {
       
   351                 mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
       
   352             } catch (ReflectiveOperationException ex) {
       
   353                 throw uncaughtException(ex);
       
   354             }
       
   355             if (caclass != null) {
       
   356                 MethodType strongType = FieldAccessor.atype(caclass, isSetter);
       
   357                 mh = mh.bindTo(caclass);
       
   358                 mh = convertArguments(mh, strongType, 0);
       
   359             }
       
   360             return mh;
       
   361         }
       
   362     }
       
   363 
       
   364     /** Bind a predetermined first argument to the given direct method handle.
       
   365      * Callable only from MethodHandles.
       
   366      * @param token Proof that the caller has access to this package.
       
   367      * @param target Any direct method handle.
       
   368      * @param receiver Receiver (or first static method argument) to pre-bind.
       
   369      * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
       
   370      */
       
   371     static
       
   372     MethodHandle bindReceiver(MethodHandle target, Object receiver) {
       
   373         if (receiver == null)  return null;
       
   374         if (target instanceof AdapterMethodHandle &&
       
   375             ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
       
   376             ) {
       
   377             Object info = MethodHandleNatives.getTargetInfo(target);
       
   378             if (info instanceof DirectMethodHandle) {
       
   379                 DirectMethodHandle dmh = (DirectMethodHandle) info;
       
   380                 if (dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
       
   381                     MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
       
   382                     MethodType newType = target.type().dropParameterTypes(0, 1);
       
   383                     return convertArguments(bmh, newType, bmh.type(), 0);
       
   384                 }
       
   385             }
       
   386         }
       
   387         if (target instanceof DirectMethodHandle)
       
   388             return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
       
   389         return null;   // let caller try something else
       
   390     }
       
   391 
       
   392     /** Bind a predetermined argument to the given arbitrary method handle.
       
   393      * Callable only from MethodHandles.
       
   394      * @param token Proof that the caller has access to this package.
       
   395      * @param target Any method handle.
       
   396      * @param receiver Argument (which can be a boxed primitive) to pre-bind.
       
   397      * @return a suitable BoundMethodHandle
       
   398      */
       
   399     static
       
   400     MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
       
   401         return new BoundMethodHandle(target, receiver, argnum);
       
   402     }
       
   403 
       
   404     static MethodHandle permuteArguments(MethodHandle target,
       
   405                                                 MethodType newType,
       
   406                                                 MethodType oldType,
       
   407                                                 int[] permutationOrNull) {
       
   408         assert(oldType.parameterCount() == target.type().parameterCount());
       
   409         int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
       
   410         if (permutationOrNull.length != outargs)
       
   411             throw newIllegalArgumentException("wrong number of arguments in permutation");
       
   412         // Make the individual outgoing argument types match up first.
       
   413         Class<?>[] callTypeArgs = new Class<?>[outargs];
       
   414         for (int i = 0; i < outargs; i++)
       
   415             callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
       
   416         MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
       
   417         target = convertArguments(target, callType, oldType, 0);
       
   418         assert(target != null);
       
   419         oldType = target.type();
       
   420         List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
       
   421         List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
       
   422         List<Integer> drops = new ArrayList<Integer>(); // not tokens
       
   423         List<Integer> dups = new ArrayList<Integer>();  // not tokens
       
   424         final int TOKEN = 10; // to mark items which are symbolic only
       
   425         // state represents the argument values coming into target
       
   426         for (int i = 0; i < outargs; i++) {
       
   427             state.add(permutationOrNull[i] * TOKEN);
       
   428         }
       
   429         // goal represents the desired state
       
   430         for (int i = 0; i < inargs; i++) {
       
   431             if (state.contains(i * TOKEN)) {
       
   432                 goal.add(i * TOKEN);
       
   433             } else {
       
   434                 // adapter must initially drop all unused arguments
       
   435                 drops.add(i);
       
   436             }
       
   437         }
       
   438         // detect duplications
       
   439         while (state.size() > goal.size()) {
       
   440             for (int i2 = 0; i2 < state.size(); i2++) {
       
   441                 int arg1 = state.get(i2);
       
   442                 int i1 = state.indexOf(arg1);
       
   443                 if (i1 != i2) {
       
   444                     // found duplicate occurrence at i2
       
   445                     int arg2 = (inargs++) * TOKEN;
       
   446                     state.set(i2, arg2);
       
   447                     dups.add(goal.indexOf(arg1));
       
   448                     goal.add(arg2);
       
   449                 }
       
   450             }
       
   451         }
       
   452         assert(state.size() == goal.size());
       
   453         int size = goal.size();
       
   454         while (!state.equals(goal)) {
       
   455             // Look for a maximal sequence of adjacent misplaced arguments,
       
   456             // and try to rotate them into place.
       
   457             int bestRotArg = -10 * TOKEN, bestRotLen = 0;
       
   458             int thisRotArg = -10 * TOKEN, thisRotLen = 0;
       
   459             for (int i = 0; i < size; i++) {
       
   460                 int arg = state.get(i);
       
   461                 // Does this argument match the current run?
       
   462                 if (arg == thisRotArg + TOKEN) {
       
   463                     thisRotArg = arg;
       
   464                     thisRotLen += 1;
       
   465                     if (bestRotLen < thisRotLen) {
       
   466                         bestRotLen = thisRotLen;
       
   467                         bestRotArg = thisRotArg;
       
   468                     }
   240                     }
   469                 } else {
   241                 } else {
   470                     // The old sequence (if any) stops here.
   242                     // Simple reference conversion.
   471                     thisRotLen = 0;
   243                     // Note:  Do not check for a class hierarchy relation
   472                     thisRotArg = -10 * TOKEN;
   244                     // between src and dst.  In all cases a 'null' argument
   473                     // But maybe a new one starts here also.
   245                     // will pass the cast conversion.
   474                     int wantArg = goal.get(i);
   246                     fn = ValueConversions.cast(dst);
   475                     final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
       
   476                     if (arg != wantArg &&
       
   477                         arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
       
   478                         arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
       
   479                         thisRotArg = arg;
       
   480                         thisRotLen = 1;
       
   481                     }
       
   482                 }
   247                 }
   483             }
   248             }
   484             if (bestRotLen >= 2) {
   249             names[tmpIndex] = new Name(fn, names[argIndex]);
   485                 // Do a rotation if it can improve argument positioning
   250             indexes[i] = tmpIndex;
   486                 // by at least 2 arguments.  This is not always optimal,
   251             tmpIndex++;
   487                 // but it seems to catch common cases.
   252         }
   488                 int dstEnd = state.indexOf(bestRotArg);
   253         if (retConv) {
   489                 int srcEnd = goal.indexOf(bestRotArg);
   254             MethodHandle adjustReturn;
   490                 int rotBy = dstEnd - srcEnd;
   255             if (haveReturn == void.class) {
   491                 int dstBeg = dstEnd - (bestRotLen - 1);
   256                 // synthesize a zero value for the given void
   492                 int srcBeg = srcEnd - (bestRotLen - 1);
   257                 Object zero = Wrapper.forBasicType(needReturn).zero();
   493                 assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
   258                 adjustReturn = MethodHandles.constant(needReturn, zero);
   494                 // Make a span which covers both source and destination.
   259             } else {
   495                 int rotBeg = Math.min(dstBeg, srcBeg);
   260                 MethodHandle identity = MethodHandles.identity(needReturn);
   496                 int rotEnd = Math.max(dstEnd, srcEnd);
   261                 MethodType needConversion = identity.type().changeParameterType(0, haveReturn);
   497                 int score = 0;
   262                 adjustReturn = makePairwiseConvert(identity, needConversion, level);
   498                 for (int i = rotBeg; i <= rotEnd; i++) {
   263             }
   499                     if ((int)state.get(i) != (int)goal.get(i))
   264             target = makeCollectArguments(adjustReturn, target, 0, false);
   500                         score += 1;
   265         }
       
   266 
       
   267         // Build argument array for the call.
       
   268         Name[] targetArgs = new Name[dstType.parameterCount()];
       
   269         for (int i = 0; i < dstType.parameterCount(); i++) {
       
   270             int idx = indexes[i];
       
   271             targetArgs[i] = names[idx];
       
   272         }
       
   273         names[names.length - 1] = new Name(target, (Object[]) targetArgs);
       
   274         LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names);
       
   275         return new SimpleMethodHandle(srcType, form);
       
   276     }
       
   277 
       
   278     static MethodHandle makeReferenceIdentity(Class<?> refType) {
       
   279         MethodType lambdaType = MethodType.genericMethodType(1).invokerType();
       
   280         Name[] names = arguments(1, lambdaType);
       
   281         names[names.length - 1] = new Name(ValueConversions.identity(), names[1]);
       
   282         LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names);
       
   283         return new SimpleMethodHandle(MethodType.methodType(refType, refType), form);
       
   284     }
       
   285 
       
   286     static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
       
   287         MethodType type = target.type();
       
   288         int last = type.parameterCount() - 1;
       
   289         if (type.parameterType(last) != arrayType)
       
   290             target = target.asType(type.changeParameterType(last, arrayType));
       
   291         target = target.asFixedArity();  // make sure this attribute is turned off
       
   292         return new AsVarargsCollector(target, target.type(), arrayType);
       
   293     }
       
   294 
       
   295     static class AsVarargsCollector extends MethodHandle {
       
   296         MethodHandle target;
       
   297         final Class<?> arrayType;
       
   298         MethodHandle cache;
       
   299 
       
   300         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
       
   301             super(type, reinvokerForm(type));
       
   302             this.target = target;
       
   303             this.arrayType = arrayType;
       
   304             this.cache = target.asCollector(arrayType, 0);
       
   305         }
       
   306 
       
   307         @Override MethodHandle reinvokerTarget() { return target; }
       
   308 
       
   309         @Override
       
   310         public boolean isVarargsCollector() {
       
   311             return true;
       
   312         }
       
   313 
       
   314         @Override
       
   315         public MethodHandle asFixedArity() {
       
   316             return target;
       
   317         }
       
   318 
       
   319         @Override
       
   320         public MethodHandle asType(MethodType newType) {
       
   321             MethodType type = this.type();
       
   322             int collectArg = type.parameterCount() - 1;
       
   323             int newArity = newType.parameterCount();
       
   324             if (newArity == collectArg+1 &&
       
   325                 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
       
   326                 // if arity and trailing parameter are compatible, do normal thing
       
   327                 return asFixedArity().asType(newType);
       
   328             }
       
   329             // check cache
       
   330             if (cache.type().parameterCount() == newArity)
       
   331                 return cache.asType(newType);
       
   332             // build and cache a collector
       
   333             int arrayLength = newArity - collectArg;
       
   334             MethodHandle collector;
       
   335             try {
       
   336                 collector = asFixedArity().asCollector(arrayType, arrayLength);
       
   337             } catch (IllegalArgumentException ex) {
       
   338                 throw new WrongMethodTypeException("cannot build collector");
       
   339             }
       
   340             cache = collector;
       
   341             return collector.asType(newType);
       
   342         }
       
   343 
       
   344         @Override
       
   345         MethodHandle setVarargs(MemberName member) {
       
   346             if (member.isVarargs())  return this;
       
   347             return asFixedArity();
       
   348         }
       
   349 
       
   350         @Override
       
   351         MethodHandle viewAsType(MethodType newType) {
       
   352             MethodHandle mh = super.viewAsType(newType);
       
   353             // put back the varargs bit:
       
   354             MethodType type = mh.type();
       
   355             int arity = type.parameterCount();
       
   356             return mh.asVarargsCollector(type.parameterType(arity-1));
       
   357         }
       
   358 
       
   359         @Override
       
   360         MemberName internalMemberName() {
       
   361             return asFixedArity().internalMemberName();
       
   362         }
       
   363 
       
   364 
       
   365         @Override
       
   366         MethodHandle bindArgument(int pos, char basicType, Object value) {
       
   367             return asFixedArity().bindArgument(pos, basicType, value);
       
   368         }
       
   369 
       
   370         @Override
       
   371         MethodHandle bindReceiver(Object receiver) {
       
   372             return asFixedArity().bindReceiver(receiver);
       
   373         }
       
   374 
       
   375         @Override
       
   376         MethodHandle dropArguments(MethodType srcType, int pos, int drops) {
       
   377             return asFixedArity().dropArguments(srcType, pos, drops);
       
   378         }
       
   379 
       
   380         @Override
       
   381         MethodHandle permuteArguments(MethodType newType, int[] reorder) {
       
   382             return asFixedArity().permuteArguments(newType, reorder);
       
   383         }
       
   384     }
       
   385 
       
   386     /** Factory method:  Spread selected argument. */
       
   387     static MethodHandle makeSpreadArguments(MethodHandle target,
       
   388                                             Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
       
   389         MethodType targetType = target.type();
       
   390 
       
   391         for (int i = 0; i < spreadArgCount; i++) {
       
   392             Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
       
   393             if (arg == null)  arg = Object.class;
       
   394             targetType = targetType.changeParameterType(spreadArgPos + i, arg);
       
   395         }
       
   396         target = target.asType(targetType);
       
   397 
       
   398         MethodType srcType = targetType
       
   399                 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
       
   400         // Now build a LambdaForm.
       
   401         MethodType lambdaType = srcType.invokerType();
       
   402         Name[] names = arguments(spreadArgCount + 2, lambdaType);
       
   403         int nameCursor = lambdaType.parameterCount();
       
   404         int[] indexes = new int[targetType.parameterCount()];
       
   405 
       
   406         for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
       
   407             Class<?> src = lambdaType.parameterType(i);
       
   408             if (i == spreadArgPos) {
       
   409                 // Spread the array.
       
   410                 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
       
   411                 Name array = names[argIndex];
       
   412                 names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
       
   413                 for (int j = 0; j < spreadArgCount; i++, j++) {
       
   414                     indexes[i] = nameCursor;
       
   415                     names[nameCursor++] = new Name(aload, array, j);
   501                 }
   416                 }
   502                 List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
   417             } else if (i < indexes.length) {
   503                 Collections.rotate(rotSpan, -rotBy);  // reverse direction
   418                 indexes[i] = argIndex;
   504                 for (int i = rotBeg; i <= rotEnd; i++) {
   419             }
   505                     if ((int)state.get(i) != (int)goal.get(i))
   420         }
   506                         score -= 1;
   421         assert(nameCursor == names.length-1);  // leave room for the final call
   507                 }
   422 
   508                 if (score >= 2) {
   423         // Build argument array for the call.
   509                     // Improved at least two argument positions.  Do it.
   424         Name[] targetArgs = new Name[targetType.parameterCount()];
   510                     List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
   425         for (int i = 0; i < targetType.parameterCount(); i++) {
   511                     Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
   426             int idx = indexes[i];
   512                     MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
   427             targetArgs[i] = names[idx];
   513                     MethodHandle nextTarget
   428         }
   514                             = AdapterMethodHandle.makeRotateArguments(rotType, target,
   429         names[names.length - 1] = new Name(target, (Object[]) targetArgs);
   515                                     rotBeg, rotSpan.size(), rotBy);
   430 
   516                     if (nextTarget != null) {
   431         LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
   517                         //System.out.println("Rot: "+rotSpan+" by "+rotBy);
   432         return new SimpleMethodHandle(srcType, form);
   518                         target = nextTarget;
   433     }
   519                         oldType = rotType;
   434 
   520                         continue;
   435     static void checkSpreadArgument(Object av, int n) {
   521                     }
   436         if (av == null) {
   522                 }
   437             if (n == 0)  return;
   523                 // Else de-rotate, and drop through to the swap-fest.
   438         } else if (av instanceof Object[]) {
   524                 Collections.rotate(rotSpan, rotBy);
   439             int len = ((Object[])av).length;
   525             }
   440             if (len == n)  return;
   526 
   441         } else {
   527             // Now swap like the wind!
   442             int len = java.lang.reflect.Array.getLength(av);
   528             List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
   443             if (len == n)  return;
   529             for (int i = 0; i < size; i++) {
   444         }
   530                 // What argument do I want here?
   445         // fall through to error:
   531                 int arg = goal.get(i);
   446         throw newIllegalArgumentException("Array is not of length "+n);
   532                 if (arg != state.get(i)) {
   447     }
   533                     // Where is it now?
   448 
   534                     int j = state.indexOf(arg);
   449     private static final NamedFunction NF_checkSpreadArgument;
   535                     Collections.swap(ptypes, i, j);
   450     static {
   536                     MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
       
   537                     target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
       
   538                     if (target == null)  throw newIllegalArgumentException("cannot swap");
       
   539                     assert(target.type() == swapType);
       
   540                     oldType = swapType;
       
   541                     Collections.swap(state, i, j);
       
   542                 }
       
   543             }
       
   544             // One pass of swapping must finish the job.
       
   545             assert(state.equals(goal));
       
   546         }
       
   547         while (!dups.isEmpty()) {
       
   548             // Grab a contiguous trailing sequence of dups.
       
   549             int grab = dups.size() - 1;
       
   550             int dupArgPos = dups.get(grab), dupArgCount = 1;
       
   551             while (grab - 1 >= 0) {
       
   552                 int dup0 = dups.get(grab - 1);
       
   553                 if (dup0 != dupArgPos - 1)  break;
       
   554                 dupArgPos -= 1;
       
   555                 dupArgCount += 1;
       
   556                 grab -= 1;
       
   557             }
       
   558             //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
       
   559             dups.subList(grab, dups.size()).clear();
       
   560             // In the new target type drop that many args from the tail:
       
   561             List<Class<?>> ptypes = oldType.parameterList();
       
   562             ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
       
   563             MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
       
   564             target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
       
   565             if (target == null)
       
   566                 throw newIllegalArgumentException("cannot dup");
       
   567             oldType = target.type();
       
   568         }
       
   569         while (!drops.isEmpty()) {
       
   570             // Grab a contiguous initial sequence of drops.
       
   571             int dropArgPos = drops.get(0), dropArgCount = 1;
       
   572             while (dropArgCount < drops.size()) {
       
   573                 int drop1 = drops.get(dropArgCount);
       
   574                 if (drop1 != dropArgPos + dropArgCount)  break;
       
   575                 dropArgCount += 1;
       
   576             }
       
   577             //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
       
   578             drops.subList(0, dropArgCount).clear();
       
   579             List<Class<?>> dropTypes = newType.parameterList()
       
   580                     .subList(dropArgPos, dropArgPos + dropArgCount);
       
   581             MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
       
   582             target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
       
   583             if (target == null)  throw newIllegalArgumentException("cannot drop");
       
   584             oldType = target.type();
       
   585         }
       
   586         target = convertArguments(target, newType, oldType, 0);
       
   587         assert(target != null);
       
   588         return target;
       
   589     }
       
   590 
       
   591     /*non-public*/ static
       
   592     MethodHandle convertArguments(MethodHandle target, MethodType newType, int level) {
       
   593         MethodType oldType = target.type();
       
   594         if (oldType.equals(newType))
       
   595             return target;
       
   596         assert(level > 1 || oldType.isConvertibleTo(newType));
       
   597         MethodHandle retFilter = null;
       
   598         Class<?> oldRT = oldType.returnType();
       
   599         Class<?> newRT = newType.returnType();
       
   600         if (!VerifyType.isNullConversion(oldRT, newRT)) {
       
   601             if (oldRT == void.class) {
       
   602                 Wrapper wrap = newRT.isPrimitive() ? Wrapper.forPrimitiveType(newRT) : Wrapper.OBJECT;
       
   603                 retFilter = ValueConversions.zeroConstantFunction(wrap);
       
   604             } else {
       
   605                 retFilter = MethodHandles.identity(newRT);
       
   606                 retFilter = convertArguments(retFilter, retFilter.type().changeParameterType(0, oldRT), level);
       
   607             }
       
   608             newType = newType.changeReturnType(oldRT);
       
   609         }
       
   610         MethodHandle res = null;
       
   611         Exception ex = null;
       
   612         try {
   451         try {
   613             res = convertArguments(target, newType, oldType, level);
   452             NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
   614         } catch (IllegalArgumentException ex1) {
   453                     .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
   615             ex = ex1;
   454             NF_checkSpreadArgument.resolve();
   616         }
   455         } catch (ReflectiveOperationException ex) {
   617         if (res == null) {
   456             throw new InternalError(ex);
   618             WrongMethodTypeException wmt = new WrongMethodTypeException("cannot convert to "+newType+": "+target);
   457         }
   619             wmt.initCause(ex);
   458     }
   620             throw wmt;
   459 
   621         }
   460     /** Factory method:  Collect or filter selected argument(s). */
   622         if (retFilter != null)
   461     static MethodHandle makeCollectArguments(MethodHandle target,
   623             res = MethodHandles.filterReturnValue(res, retFilter);
   462                 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
   624         return res;
   463         MethodType targetType = target.type();          // (a..., c, [b...])=>r
   625     }
   464         MethodType collectorType = collector.type();    // (b...)=>c
   626 
   465         int collectArgCount = collectorType.parameterCount();
   627     static MethodHandle convertArguments(MethodHandle target,
   466         Class<?> collectValType = collectorType.returnType();
   628                                                 MethodType newType,
   467         int collectValCount = (collectValType == void.class ? 0 : 1);
   629                                                 MethodType oldType,
   468         MethodType srcType = targetType                 // (a..., [b...])=>r
   630                                                 int level) {
   469                 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
   631         assert(oldType.parameterCount() == target.type().parameterCount());
   470         if (!retainOriginalArgs) {                      // (a..., b...)=>r
   632         if (newType == oldType)
   471             srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
   633             return target;
   472         }
   634         if (oldType.parameterCount() != newType.parameterCount())
   473         // in  arglist: [0: ...keep1 | cpos: collect...  | cpos+cacount: keep2... ]
   635             throw newIllegalArgumentException("mismatched parameter count", oldType, newType);
   474         // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
   636         return AdapterMethodHandle.makePairwiseConvert(newType, target, level);
   475         // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
   637     }
   476 
   638 
   477         // Now build a LambdaForm.
   639     static MethodHandle spreadArguments(MethodHandle target, Class<?> arrayType, int arrayLength) {
   478         MethodType lambdaType = srcType.invokerType();
   640         MethodType oldType = target.type();
   479         Name[] names = arguments(2, lambdaType);
   641         int nargs = oldType.parameterCount();
   480         final int collectNamePos = names.length - 2;
   642         int keepPosArgs = nargs - arrayLength;
   481         final int targetNamePos  = names.length - 1;
   643         MethodType newType = oldType
   482 
   644                 .dropParameterTypes(keepPosArgs, nargs)
   483         Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount);
   645                 .insertParameterTypes(keepPosArgs, arrayType);
   484         names[collectNamePos] = new Name(collector, (Object[]) collectorArgs);
   646         return spreadArguments(target, newType, keepPosArgs, arrayType, arrayLength);
   485 
   647     }
   486         // Build argument array for the target.
   648     // called internally only
   487         // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ].
   649     static MethodHandle spreadArgumentsFromPos(MethodHandle target, MethodType newType, int spreadArgPos) {
   488         // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ].
   650         int arrayLength = target.type().parameterCount() - spreadArgPos;
   489         Name[] targetArgs = new Name[targetType.parameterCount()];
   651         return spreadArguments(target, newType, spreadArgPos, Object[].class, arrayLength);
   490         int inputArgPos  = 1;  // incoming LF args to copy to target
   652     }
   491         int targetArgPos = 0;  // fill pointer for targetArgs
   653     static MethodHandle spreadArguments(MethodHandle target,
   492         int chunk = collectArgPos;  // |headArgs|
   654                                                MethodType newType,
   493         System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
   655                                                int spreadArgPos,
   494         inputArgPos  += chunk;
   656                                                Class<?> arrayType,
   495         targetArgPos += chunk;
   657                                                int arrayLength) {
   496         if (collectValType != void.class) {
   658         // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
   497             targetArgs[targetArgPos++] = names[collectNamePos];
   659         MethodType oldType = target.type();
   498         }
   660         // spread the last argument of newType to oldType
   499         chunk = collectArgCount;
   661         assert(arrayLength == oldType.parameterCount() - spreadArgPos);
   500         if (retainOriginalArgs) {
   662         assert(newType.parameterType(spreadArgPos) == arrayType);
   501             System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
   663         return AdapterMethodHandle.makeSpreadArguments(newType, target, arrayType, spreadArgPos, arrayLength);
   502             targetArgPos += chunk;   // optionally pass on the collected chunk
   664     }
   503         }
   665 
   504         inputArgPos += chunk;
   666     static MethodHandle collectArguments(MethodHandle target,
   505         chunk = targetArgs.length - targetArgPos;  // all the rest
   667                                                 int collectArg,
   506         System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
   668                                                 MethodHandle collector) {
   507         assert(inputArgPos + chunk == collectNamePos);  // use of rest of input args also
   669         MethodType type = target.type();
   508         names[targetNamePos] = new Name(target, (Object[]) targetArgs);
   670         Class<?> collectType = collector.type().returnType();
   509 
   671         assert(collectType != void.class);  // else use foldArguments
   510         LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
   672         if (collectType != type.parameterType(collectArg))
   511         return new SimpleMethodHandle(srcType, form);
   673             target = target.asType(type.changeParameterType(collectArg, collectType));
       
   674         MethodType newType = type
       
   675                 .dropParameterTypes(collectArg, collectArg+1)
       
   676                 .insertParameterTypes(collectArg, collector.type().parameterArray());
       
   677         return collectArguments(target, newType, collectArg, collector);
       
   678     }
       
   679     static MethodHandle collectArguments(MethodHandle target,
       
   680                                                 MethodType newType,
       
   681                                                 int collectArg,
       
   682                                                 MethodHandle collector) {
       
   683         MethodType oldType = target.type();     // (a...,c)=>r
       
   684         //         newType                      // (a..., b...)=>r
       
   685         MethodType colType = collector.type();  // (b...)=>c
       
   686         //         oldType                      // (a..., b...)=>r
       
   687         assert(newType.parameterCount() == collectArg + colType.parameterCount());
       
   688         assert(oldType.parameterCount() == collectArg + 1);
       
   689         assert(AdapterMethodHandle.canCollectArguments(oldType, colType, collectArg, false));
       
   690         return AdapterMethodHandle.makeCollectArguments(target, collector, collectArg, false);
       
   691     }
       
   692 
       
   693     static MethodHandle filterArgument(MethodHandle target,
       
   694                                        int pos,
       
   695                                        MethodHandle filter) {
       
   696         MethodType ttype = target.type();
       
   697         MethodType ftype = filter.type();
       
   698         assert(ftype.parameterCount() == 1);
       
   699         return AdapterMethodHandle.makeCollectArguments(target, filter, pos, false);
       
   700     }
       
   701 
       
   702     static MethodHandle foldArguments(MethodHandle target,
       
   703                                       MethodType newType,
       
   704                                       int foldPos,
       
   705                                       MethodHandle combiner) {
       
   706         MethodType oldType = target.type();
       
   707         MethodType ctype = combiner.type();
       
   708         assert(AdapterMethodHandle.canCollectArguments(oldType, ctype, foldPos, true));
       
   709         return AdapterMethodHandle.makeCollectArguments(target, combiner, foldPos, true);
       
   710     }
       
   711 
       
   712     static
       
   713     MethodHandle dropArguments(MethodHandle target,
       
   714                                MethodType newType, int argnum) {
       
   715         int drops = newType.parameterCount() - target.type().parameterCount();
       
   716         return AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
       
   717     }
   512     }
   718 
   513 
   719     static
   514     static
   720     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
   515     MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
   721         return testResult ? target : fallback;
   516         return testResult ? target : fallback;
   736 
   531 
   737     static
   532     static
   738     MethodHandle makeGuardWithTest(MethodHandle test,
   533     MethodHandle makeGuardWithTest(MethodHandle test,
   739                                    MethodHandle target,
   534                                    MethodHandle target,
   740                                    MethodHandle fallback) {
   535                                    MethodHandle fallback) {
   741         // gwt(arg...)
   536         MethodType basicType = target.type().basicType();
   742         // [fold]=> continueAfterTest(z=test(arg...), arg...)
   537         MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType);
   743         // [filter]=> (tf=select(z))(arg...)
   538         int arity = basicType.parameterCount();
   744         //    where select(z) = select(z, t, f).bindTo(t, f) => z ? t f
   539         int extraNames = 3;
   745         // [tailcall]=> tf(arg...)
   540         MethodType lambdaType = basicType.invokerType();
   746         assert(test.type().returnType() == boolean.class);
   541         Name[] names = arguments(extraNames, lambdaType);
   747         MethodType targetType = target.type();
   542 
   748         MethodType foldTargetType = targetType.insertParameterTypes(0, boolean.class);
   543         Object[] testArgs   = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class);
   749         assert(AdapterMethodHandle.canCollectArguments(foldTargetType, test.type(), 0, true));
   544         Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class);
   750         // working backwards, as usual:
   545 
   751         assert(target.type().equals(fallback.type()));
   546         // call test
   752         MethodHandle tailcall = MethodHandles.exactInvoker(target.type());
   547         names[arity + 1] = new Name(test, testArgs);
   753         MethodHandle select = selectAlternative();
   548 
   754         select = bindArgument(select, 2, CountingMethodHandle.wrap(fallback));
   549         // call selectAlternative
   755         select = bindArgument(select, 1, CountingMethodHandle.wrap(target));
   550         Object[] selectArgs = { names[arity + 1], target, fallback };
   756         // select(z: boolean) => (z ? target : fallback)
   551         names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs);
   757         MethodHandle filter = filterArgument(tailcall, 0, select);
   552         targetArgs[0] = names[arity + 2];
   758         assert(filter.type().parameterType(0) == boolean.class);
   553 
   759         MethodHandle fold = foldArguments(filter, filter.type().dropParameterTypes(0, 1), 0, test);
   554         // call target or fallback
   760         return fold;
   555         names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs);
   761     }
   556 
   762 
   557         LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names);
   763     private static class GuardWithCatch extends BoundMethodHandle {
   558         return new SimpleMethodHandle(target.type(), form);
       
   559     }
       
   560 
       
   561     private static class GuardWithCatch {
   764         private final MethodHandle target;
   562         private final MethodHandle target;
   765         private final Class<? extends Throwable> exType;
   563         private final Class<? extends Throwable> exType;
   766         private final MethodHandle catcher;
   564         private final MethodHandle catcher;
       
   565         // FIXME: Build the control flow out of foldArguments.
   767         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
   566         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
   768             this(INVOKES[target.type().parameterCount()], target, exType, catcher);
       
   769         }
       
   770         // FIXME: Build the control flow out of foldArguments.
       
   771         GuardWithCatch(MethodHandle invoker,
       
   772                        MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
       
   773             super(invoker);
       
   774             this.target = target;
   567             this.target = target;
   775             this.exType = exType;
   568             this.exType = exType;
   776             this.catcher = catcher;
   569             this.catcher = catcher;
   777         }
   570         }
   778         @Override
   571         @LambdaForm.Hidden
   779         String debugString() {
       
   780             return addTypeString(target, this);
       
   781         }
       
   782         private Object invoke_V(Object... av) throws Throwable {
   572         private Object invoke_V(Object... av) throws Throwable {
   783             try {
   573             try {
   784                 return target.invokeExact(av);
   574                 return target.invokeExact(av);
   785             } catch (Throwable t) {
   575             } catch (Throwable t) {
   786                 if (!exType.isInstance(t))  throw t;
   576                 if (!exType.isInstance(t))  throw t;
   787                 return catcher.invokeExact(t, av);
   577                 return catcher.invokeExact(t, av);
   788             }
   578             }
   789         }
   579         }
       
   580         @LambdaForm.Hidden
   790         private Object invoke_L0() throws Throwable {
   581         private Object invoke_L0() throws Throwable {
   791             try {
   582             try {
   792                 return target.invokeExact();
   583                 return target.invokeExact();
   793             } catch (Throwable t) {
   584             } catch (Throwable t) {
   794                 if (!exType.isInstance(t))  throw t;
   585                 if (!exType.isInstance(t))  throw t;
   795                 return catcher.invokeExact(t);
   586                 return catcher.invokeExact(t);
   796             }
   587             }
   797         }
   588         }
       
   589         @LambdaForm.Hidden
   798         private Object invoke_L1(Object a0) throws Throwable {
   590         private Object invoke_L1(Object a0) throws Throwable {
   799             try {
   591             try {
   800                 return target.invokeExact(a0);
   592                 return target.invokeExact(a0);
   801             } catch (Throwable t) {
   593             } catch (Throwable t) {
   802                 if (!exType.isInstance(t))  throw t;
   594                 if (!exType.isInstance(t))  throw t;
   803                 return catcher.invokeExact(t, a0);
   595                 return catcher.invokeExact(t, a0);
   804             }
   596             }
   805         }
   597         }
       
   598         @LambdaForm.Hidden
   806         private Object invoke_L2(Object a0, Object a1) throws Throwable {
   599         private Object invoke_L2(Object a0, Object a1) throws Throwable {
   807             try {
   600             try {
   808                 return target.invokeExact(a0, a1);
   601                 return target.invokeExact(a0, a1);
   809             } catch (Throwable t) {
   602             } catch (Throwable t) {
   810                 if (!exType.isInstance(t))  throw t;
   603                 if (!exType.isInstance(t))  throw t;
   811                 return catcher.invokeExact(t, a0, a1);
   604                 return catcher.invokeExact(t, a0, a1);
   812             }
   605             }
   813         }
   606         }
       
   607         @LambdaForm.Hidden
   814         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
   608         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
   815             try {
   609             try {
   816                 return target.invokeExact(a0, a1, a2);
   610                 return target.invokeExact(a0, a1, a2);
   817             } catch (Throwable t) {
   611             } catch (Throwable t) {
   818                 if (!exType.isInstance(t))  throw t;
   612                 if (!exType.isInstance(t))  throw t;
   819                 return catcher.invokeExact(t, a0, a1, a2);
   613                 return catcher.invokeExact(t, a0, a1, a2);
   820             }
   614             }
   821         }
   615         }
       
   616         @LambdaForm.Hidden
   822         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
   617         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
   823             try {
   618             try {
   824                 return target.invokeExact(a0, a1, a2, a3);
   619                 return target.invokeExact(a0, a1, a2, a3);
   825             } catch (Throwable t) {
   620             } catch (Throwable t) {
   826                 if (!exType.isInstance(t))  throw t;
   621                 if (!exType.isInstance(t))  throw t;
   827                 return catcher.invokeExact(t, a0, a1, a2, a3);
   622                 return catcher.invokeExact(t, a0, a1, a2, a3);
   828             }
   623             }
   829         }
   624         }
       
   625         @LambdaForm.Hidden
   830         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
   626         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
   831             try {
   627             try {
   832                 return target.invokeExact(a0, a1, a2, a3, a4);
   628                 return target.invokeExact(a0, a1, a2, a3, a4);
   833             } catch (Throwable t) {
   629             } catch (Throwable t) {
   834                 if (!exType.isInstance(t))  throw t;
   630                 if (!exType.isInstance(t))  throw t;
   835                 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
   631                 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
   836             }
   632             }
   837         }
   633         }
       
   634         @LambdaForm.Hidden
   838         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
   635         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
   839             try {
   636             try {
   840                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
   637                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
   841             } catch (Throwable t) {
   638             } catch (Throwable t) {
   842                 if (!exType.isInstance(t))  throw t;
   639                 if (!exType.isInstance(t))  throw t;
   843                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
   640                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
   844             }
   641             }
   845         }
   642         }
       
   643         @LambdaForm.Hidden
   846         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
   644         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
   847             try {
   645             try {
   848                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
   646                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
   849             } catch (Throwable t) {
   647             } catch (Throwable t) {
   850                 if (!exType.isInstance(t))  throw t;
   648                 if (!exType.isInstance(t))  throw t;
   851                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
   649                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
   852             }
   650             }
   853         }
   651         }
       
   652         @LambdaForm.Hidden
   854         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
   653         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
   855             try {
   654             try {
   856                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
   655                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
   857             } catch (Throwable t) {
   656             } catch (Throwable t) {
   858                 if (!exType.isInstance(t))  throw t;
   657                 if (!exType.isInstance(t))  throw t;
   859                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
   658                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
   860             }
   659             }
   861         }
   660         }
   862         static MethodHandle[] makeInvokes() {
   661         static MethodHandle[] makeInvokes() {
   863             ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
   662             ArrayList<MethodHandle> invokes = new ArrayList<>();
   864             MethodHandles.Lookup lookup = IMPL_LOOKUP;
   663             MethodHandles.Lookup lookup = IMPL_LOOKUP;
   865             for (;;) {
   664             for (;;) {
   866                 int nargs = invokes.size();
   665                 int nargs = invokes.size();
   867                 String name = "invoke_L"+nargs;
   666                 String name = "invoke_L"+nargs;
   868                 MethodHandle invoke = null;
   667                 MethodHandle invoke = null;
   899         int nargs = type.parameterCount();
   698         int nargs = type.parameterCount();
   900         if (nargs < GuardWithCatch.INVOKES.length) {
   699         if (nargs < GuardWithCatch.INVOKES.length) {
   901             MethodType gtype = type.generic();
   700             MethodType gtype = type.generic();
   902             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
   701             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
   903             // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
   702             // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0)
   904             MethodHandle gtarget = convertArguments(target, gtype, type, 2);
   703             MethodHandle gtarget = makePairwiseConvert(target, gtype, 2);
   905             MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, 2);
   704             MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2);
   906             MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
   705             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
   907             if (gtarget == null || gcatcher == null || gguard == null)  return null;
   706             if (gtarget == null || gcatcher == null)  throw new InternalError();
   908             return convertArguments(gguard, type, gtype, 2);
   707             MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard);
       
   708             return makePairwiseConvert(ginvoker, type, 2);
   909         } else {
   709         } else {
   910             MethodType gtype = MethodType.genericMethodType(0, true);
   710             MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs);
   911             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
       
   912             MethodHandle gtarget = spreadArgumentsFromPos(target, gtype, 0);
       
   913             catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
   711             catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class));
   914             MethodHandle gcatcher = spreadArgumentsFromPos(catcher, gcatchType, 1);
   712             MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs);
   915             MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
   713             GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher);
   916             if (gtarget == null || gcatcher == null || gguard == null)  return null;
   714             if (gtarget == null || gcatcher == null)  throw new InternalError();
   917             return collectArguments(gguard, type, 0, ValueConversions.varargsArray(nargs)).asType(type);
   715             MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard);
       
   716             return makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false);
   918         }
   717         }
   919     }
   718     }
   920 
   719 
   921     static
   720     static
   922     MethodHandle throwException(MethodType type) {
   721     MethodHandle throwException(MethodType type) {
   923         return AdapterMethodHandle.makeRetypeRaw(type, throwException());
   722         assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
       
   723         int arity = type.parameterCount();
       
   724         if (arity > 1) {
       
   725             return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1);
       
   726         }
       
   727         return makePairwiseConvert(throwException(), type, 2);
   924     }
   728     }
   925 
   729 
   926     static MethodHandle THROW_EXCEPTION;
   730     static MethodHandle THROW_EXCEPTION;
   927     static MethodHandle throwException() {
   731     static MethodHandle throwException() {
   928         if (THROW_EXCEPTION != null)  return THROW_EXCEPTION;
   732         MethodHandle mh = THROW_EXCEPTION;
       
   733         if (mh != null)  return mh;
   929         try {
   734         try {
   930             THROW_EXCEPTION
   735             mh
   931             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
   736             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
   932                     MethodType.methodType(Empty.class, Throwable.class));
   737                     MethodType.methodType(Empty.class, Throwable.class));
   933         } catch (ReflectiveOperationException ex) {
   738         } catch (ReflectiveOperationException ex) {
   934             throw new RuntimeException(ex);
   739             throw new RuntimeException(ex);
   935         }
   740         }
   936         return THROW_EXCEPTION;
   741         THROW_EXCEPTION = mh;
       
   742         return mh;
   937     }
   743     }
   938     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
   744     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
       
   745 
       
   746     static MethodHandle FAKE_METHOD_HANDLE_INVOKE;
       
   747     static
       
   748     MethodHandle fakeMethodHandleInvoke(MemberName method) {
       
   749         MethodType type = method.getInvocationType();
       
   750         assert(type.equals(MethodType.methodType(Object.class, Object[].class)));
       
   751         MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE;
       
   752         if (mh != null)  return mh;
       
   753         mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class));
       
   754         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
       
   755         FAKE_METHOD_HANDLE_INVOKE = mh;
       
   756         return mh;
       
   757     }
       
   758 
   939 }
   759 }