jdk/src/share/classes/java/dyn/MethodHandleImpl.java
changeset 8821 2836ee97ee27
parent 8347 e5daa5772ffd
equal deleted inserted replaced
8693:2173b8120b13 8821:2836ee97ee27
       
     1 /*
       
     2  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package java.dyn;
       
    27 
       
    28 import sun.dyn.util.VerifyType;
       
    29 import java.util.ArrayList;
       
    30 import java.util.Arrays;
       
    31 import java.util.Collections;
       
    32 import java.util.HashMap;
       
    33 import java.util.List;
       
    34 import sun.dyn.empty.Empty;
       
    35 import sun.dyn.util.ValueConversions;
       
    36 import sun.dyn.util.Wrapper;
       
    37 import sun.misc.Unsafe;
       
    38 import static java.dyn.MethodHandleStatics.*;
       
    39 import static java.dyn.MethodHandles.Lookup.IMPL_LOOKUP;
       
    40 
       
    41 /**
       
    42  * Trusted implementation code for MethodHandle.
       
    43  * @author jrose
       
    44  */
       
    45 /*non-public*/ abstract class MethodHandleImpl {
       
    46     /// Factory methods to create method handles:
       
    47 
       
    48     private static final MemberName.Factory LOOKUP = MemberName.Factory.INSTANCE;
       
    49 
       
    50     static void initStatics() {
       
    51         // Trigger preceding sequence.
       
    52     }
       
    53 
       
    54     /** Look up a given method.
       
    55      * Callable only from java.dyn and related packages.
       
    56      * <p>
       
    57      * The resulting method handle type will be of the given type,
       
    58      * with a receiver type {@code rcvc} prepended if the member is not static.
       
    59      * <p>
       
    60      * Access checks are made as of the given lookup class.
       
    61      * In particular, if the method is protected and {@code defc} is in a
       
    62      * different package from the lookup class, then {@code rcvc} must be
       
    63      * the lookup class or a subclass.
       
    64      * @param token Proof that the lookup class has access to this package.
       
    65      * @param member Resolved method or constructor to call.
       
    66      * @param name Name of the desired method.
       
    67      * @param rcvc Receiver type of desired non-static method (else null)
       
    68      * @param doDispatch whether the method handle will test the receiver type
       
    69      * @param lookupClass access-check relative to this class
       
    70      * @return a direct handle to the matching method
       
    71      * @throws IllegalAccessException if the given method cannot be accessed by the lookup class
       
    72      */
       
    73     static
       
    74     MethodHandle findMethod(MemberName method,
       
    75                             boolean doDispatch, Class<?> lookupClass) throws IllegalAccessException {
       
    76         MethodType mtype = method.getMethodType();
       
    77         if (!method.isStatic()) {
       
    78             // adjust the advertised receiver type to be exactly the one requested
       
    79             // (in the case of invokespecial, this will be the calling class)
       
    80             Class<?> recvType = method.getDeclaringClass();
       
    81             mtype = mtype.insertParameterTypes(0, recvType);
       
    82         }
       
    83         DirectMethodHandle mh = new DirectMethodHandle(mtype, method, doDispatch, lookupClass);
       
    84         if (!mh.isValid())
       
    85             throw method.makeAccessException("no access", lookupClass);
       
    86         assert(mh.type() == mtype);
       
    87         if (!method.isVarargs())
       
    88             return mh;
       
    89         else
       
    90             return mh.asVarargsCollector(mtype.parameterType(mtype.parameterCount()-1));
       
    91     }
       
    92 
       
    93     static
       
    94     MethodHandle makeAllocator(MethodHandle rawConstructor) {
       
    95         MethodType rawConType = rawConstructor.type();
       
    96         // Wrap the raw (unsafe) constructor with the allocation of a suitable object.
       
    97         MethodHandle allocator
       
    98             = AllocateObject.make(rawConType.parameterType(0), rawConstructor);
       
    99         assert(allocator.type()
       
   100                .equals(rawConType.dropParameterTypes(0, 1).changeReturnType(rawConType.parameterType(0))));
       
   101         return allocator;
       
   102     }
       
   103 
       
   104     static final class AllocateObject<C> extends BoundMethodHandle {
       
   105         private static final Unsafe unsafe = Unsafe.getUnsafe();
       
   106 
       
   107         private final Class<C> allocateClass;
       
   108         private final MethodHandle rawConstructor;
       
   109 
       
   110         private AllocateObject(MethodHandle invoker,
       
   111                                Class<C> allocateClass, MethodHandle rawConstructor) {
       
   112             super(invoker);
       
   113             this.allocateClass = allocateClass;
       
   114             this.rawConstructor = rawConstructor;
       
   115         }
       
   116         static MethodHandle make(Class<?> allocateClass, MethodHandle rawConstructor) {
       
   117             MethodType rawConType = rawConstructor.type();
       
   118             assert(rawConType.parameterType(0) == allocateClass);
       
   119             MethodType newType = rawConType.dropParameterTypes(0, 1).changeReturnType(allocateClass);
       
   120             int nargs = rawConType.parameterCount() - 1;
       
   121             if (nargs < INVOKES.length) {
       
   122                 MethodHandle invoke = INVOKES[nargs];
       
   123                 MethodType conType = CON_TYPES[nargs];
       
   124                 MethodHandle gcon = convertArguments(rawConstructor, conType, rawConType, null);
       
   125                 if (gcon == null)  return null;
       
   126                 MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
       
   127                 assert(galloc.type() == newType.generic());
       
   128                 return convertArguments(galloc, newType, galloc.type(), null);
       
   129             } else {
       
   130                 MethodHandle invoke = VARARGS_INVOKE;
       
   131                 MethodType conType = CON_TYPES[nargs];
       
   132                 MethodHandle gcon = spreadArguments(rawConstructor, conType, 1);
       
   133                 if (gcon == null)  return null;
       
   134                 MethodHandle galloc = new AllocateObject(invoke, allocateClass, gcon);
       
   135                 return collectArguments(galloc, newType, 1, null);
       
   136             }
       
   137         }
       
   138         @Override
       
   139         public String toString() {
       
   140             return addTypeString(allocateClass.getSimpleName(), this);
       
   141         }
       
   142         @SuppressWarnings("unchecked")
       
   143         private C allocate() throws InstantiationException {
       
   144             return (C) unsafe.allocateInstance(allocateClass);
       
   145         }
       
   146         private C invoke_V(Object... av) throws Throwable {
       
   147             C obj = allocate();
       
   148             rawConstructor.invokeExact((Object)obj, av);
       
   149             return obj;
       
   150         }
       
   151         private C invoke_L0() throws Throwable {
       
   152             C obj = allocate();
       
   153             rawConstructor.invokeExact((Object)obj);
       
   154             return obj;
       
   155         }
       
   156         private C invoke_L1(Object a0) throws Throwable {
       
   157             C obj = allocate();
       
   158             rawConstructor.invokeExact((Object)obj, a0);
       
   159             return obj;
       
   160         }
       
   161         private C invoke_L2(Object a0, Object a1) throws Throwable {
       
   162             C obj = allocate();
       
   163             rawConstructor.invokeExact((Object)obj, a0, a1);
       
   164             return obj;
       
   165         }
       
   166         private C invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
       
   167             C obj = allocate();
       
   168             rawConstructor.invokeExact((Object)obj, a0, a1, a2);
       
   169             return obj;
       
   170         }
       
   171         private C invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
       
   172             C obj = allocate();
       
   173             rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3);
       
   174             return obj;
       
   175         }
       
   176         private C invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
       
   177             C obj = allocate();
       
   178             rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4);
       
   179             return obj;
       
   180         }
       
   181         private C invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
       
   182             C obj = allocate();
       
   183             rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5);
       
   184             return obj;
       
   185         }
       
   186         private C invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
       
   187             C obj = allocate();
       
   188             rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6);
       
   189             return obj;
       
   190         }
       
   191         private C invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
       
   192             C obj = allocate();
       
   193             rawConstructor.invokeExact((Object)obj, a0, a1, a2, a3, a4, a5, a6, a7);
       
   194             return obj;
       
   195         }
       
   196         static MethodHandle[] makeInvokes() {
       
   197             ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
       
   198             MethodHandles.Lookup lookup = IMPL_LOOKUP;
       
   199             for (;;) {
       
   200                 int nargs = invokes.size();
       
   201                 String name = "invoke_L"+nargs;
       
   202                 MethodHandle invoke = null;
       
   203                 try {
       
   204                     invoke = lookup.findVirtual(AllocateObject.class, name, MethodType.genericMethodType(nargs));
       
   205                 } catch (ReflectiveOperationException ex) {
       
   206                 }
       
   207                 if (invoke == null)  break;
       
   208                 invokes.add(invoke);
       
   209             }
       
   210             assert(invokes.size() == 9);  // current number of methods
       
   211             return invokes.toArray(new MethodHandle[0]);
       
   212         };
       
   213         static final MethodHandle[] INVOKES = makeInvokes();
       
   214         // For testing use this:
       
   215         //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
       
   216         static final MethodHandle VARARGS_INVOKE;
       
   217         static {
       
   218             try {
       
   219                 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
       
   220             } catch (ReflectiveOperationException ex) {
       
   221                 throw uncaughtException(ex);
       
   222             }
       
   223         }
       
   224         // Corresponding generic constructor types:
       
   225         static final MethodType[] CON_TYPES = new MethodType[INVOKES.length];
       
   226         static {
       
   227             for (int i = 0; i < INVOKES.length; i++)
       
   228                 CON_TYPES[i] = makeConType(INVOKES[i]);
       
   229         }
       
   230         static final MethodType VARARGS_CON_TYPE = makeConType(VARARGS_INVOKE);
       
   231         static MethodType makeConType(MethodHandle invoke) {
       
   232             MethodType invType = invoke.type();
       
   233             return invType.changeParameterType(0, Object.class).changeReturnType(void.class);
       
   234         }
       
   235     }
       
   236 
       
   237     static
       
   238     MethodHandle accessField(MemberName member, boolean isSetter,
       
   239                              Class<?> lookupClass) {
       
   240         // Use sun. misc.Unsafe to dig up the dirt on the field.
       
   241         MethodHandle mh = new FieldAccessor(member, isSetter);
       
   242         return mh;
       
   243     }
       
   244 
       
   245     static
       
   246     MethodHandle accessArrayElement(Class<?> arrayClass, boolean isSetter) {
       
   247         if (!arrayClass.isArray())
       
   248             throw newIllegalArgumentException("not an array: "+arrayClass);
       
   249         Class<?> elemClass = arrayClass.getComponentType();
       
   250         MethodHandle[] mhs = FieldAccessor.ARRAY_CACHE.get(elemClass);
       
   251         if (mhs == null) {
       
   252             if (!FieldAccessor.doCache(elemClass))
       
   253                 return FieldAccessor.ahandle(arrayClass, isSetter);
       
   254             mhs = new MethodHandle[] {
       
   255                 FieldAccessor.ahandle(arrayClass, false),
       
   256                 FieldAccessor.ahandle(arrayClass, true)
       
   257             };
       
   258             if (mhs[0].type().parameterType(0) == Class.class) {
       
   259                 mhs[0] = MethodHandles.insertArguments(mhs[0], 0, elemClass);
       
   260                 mhs[1] = MethodHandles.insertArguments(mhs[1], 0, elemClass);
       
   261             }
       
   262             synchronized (FieldAccessor.ARRAY_CACHE) {}  // memory barrier
       
   263             FieldAccessor.ARRAY_CACHE.put(elemClass, mhs);
       
   264         }
       
   265         return mhs[isSetter ? 1 : 0];
       
   266     }
       
   267 
       
   268     static final class FieldAccessor<C,V> extends BoundMethodHandle {
       
   269         private static final Unsafe unsafe = Unsafe.getUnsafe();
       
   270         final Object base;  // for static refs only
       
   271         final long offset;
       
   272         final String name;
       
   273 
       
   274         FieldAccessor(MemberName field, boolean isSetter) {
       
   275             super(fhandle(field.getDeclaringClass(), field.getFieldType(), isSetter, field.isStatic()));
       
   276             this.offset = (long) field.getVMIndex();
       
   277             this.name = field.getName();
       
   278             this.base = staticBase(field);
       
   279         }
       
   280         @Override
       
   281         public String toString() { return addTypeString(name, this); }
       
   282 
       
   283         int getFieldI(C obj) { return unsafe.getInt(obj, offset); }
       
   284         void setFieldI(C obj, int x) { unsafe.putInt(obj, offset, x); }
       
   285         long getFieldJ(C obj) { return unsafe.getLong(obj, offset); }
       
   286         void setFieldJ(C obj, long x) { unsafe.putLong(obj, offset, x); }
       
   287         float getFieldF(C obj) { return unsafe.getFloat(obj, offset); }
       
   288         void setFieldF(C obj, float x) { unsafe.putFloat(obj, offset, x); }
       
   289         double getFieldD(C obj) { return unsafe.getDouble(obj, offset); }
       
   290         void setFieldD(C obj, double x) { unsafe.putDouble(obj, offset, x); }
       
   291         boolean getFieldZ(C obj) { return unsafe.getBoolean(obj, offset); }
       
   292         void setFieldZ(C obj, boolean x) { unsafe.putBoolean(obj, offset, x); }
       
   293         byte getFieldB(C obj) { return unsafe.getByte(obj, offset); }
       
   294         void setFieldB(C obj, byte x) { unsafe.putByte(obj, offset, x); }
       
   295         short getFieldS(C obj) { return unsafe.getShort(obj, offset); }
       
   296         void setFieldS(C obj, short x) { unsafe.putShort(obj, offset, x); }
       
   297         char getFieldC(C obj) { return unsafe.getChar(obj, offset); }
       
   298         void setFieldC(C obj, char x) { unsafe.putChar(obj, offset, x); }
       
   299         @SuppressWarnings("unchecked")
       
   300         V getFieldL(C obj) { return (V) unsafe.getObject(obj, offset); }
       
   301         @SuppressWarnings("unchecked")
       
   302         void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
       
   303         // cast (V) is OK here, since we wrap convertArguments around the MH.
       
   304 
       
   305         static Object staticBase(MemberName field) {
       
   306             if (!field.isStatic())  return null;
       
   307             Class c = field.getDeclaringClass();
       
   308             java.lang.reflect.Field f;
       
   309             try {
       
   310                 // FIXME:  Should not have to create 'f' to get this value.
       
   311                 f = c.getDeclaredField(field.getName());
       
   312                 return unsafe.staticFieldBase(f);
       
   313             } catch (Exception ee) {
       
   314                 throw uncaughtException(ee);
       
   315             }
       
   316         }
       
   317 
       
   318         int getStaticI() { return unsafe.getInt(base, offset); }
       
   319         void setStaticI(int x) { unsafe.putInt(base, offset, x); }
       
   320         long getStaticJ() { return unsafe.getLong(base, offset); }
       
   321         void setStaticJ(long x) { unsafe.putLong(base, offset, x); }
       
   322         float getStaticF() { return unsafe.getFloat(base, offset); }
       
   323         void setStaticF(float x) { unsafe.putFloat(base, offset, x); }
       
   324         double getStaticD() { return unsafe.getDouble(base, offset); }
       
   325         void setStaticD(double x) { unsafe.putDouble(base, offset, x); }
       
   326         boolean getStaticZ() { return unsafe.getBoolean(base, offset); }
       
   327         void setStaticZ(boolean x) { unsafe.putBoolean(base, offset, x); }
       
   328         byte getStaticB() { return unsafe.getByte(base, offset); }
       
   329         void setStaticB(byte x) { unsafe.putByte(base, offset, x); }
       
   330         short getStaticS() { return unsafe.getShort(base, offset); }
       
   331         void setStaticS(short x) { unsafe.putShort(base, offset, x); }
       
   332         char getStaticC() { return unsafe.getChar(base, offset); }
       
   333         void setStaticC(char x) { unsafe.putChar(base, offset, x); }
       
   334         V getStaticL() { return (V) unsafe.getObject(base, offset); }
       
   335         void setStaticL(V x) { unsafe.putObject(base, offset, x); }
       
   336 
       
   337         static String fname(Class<?> vclass, boolean isSetter, boolean isStatic) {
       
   338             String stem;
       
   339             if (!isStatic)
       
   340                 stem = (!isSetter ? "getField" : "setField");
       
   341             else
       
   342                 stem = (!isSetter ? "getStatic" : "setStatic");
       
   343             return stem + Wrapper.basicTypeChar(vclass);
       
   344         }
       
   345         static MethodType ftype(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
       
   346             MethodType type;
       
   347             if (!isStatic) {
       
   348                 if (!isSetter)
       
   349                     return MethodType.methodType(vclass, cclass);
       
   350                 else
       
   351                     return MethodType.methodType(void.class, cclass, vclass);
       
   352             } else {
       
   353                 if (!isSetter)
       
   354                     return MethodType.methodType(vclass);
       
   355                 else
       
   356                     return MethodType.methodType(void.class, vclass);
       
   357             }
       
   358         }
       
   359         static MethodHandle fhandle(Class<?> cclass, Class<?> vclass, boolean isSetter, boolean isStatic) {
       
   360             String name = FieldAccessor.fname(vclass, isSetter, isStatic);
       
   361             if (cclass.isPrimitive())  throw newIllegalArgumentException("primitive "+cclass);
       
   362             Class<?> ecclass = Object.class;  //erase this type
       
   363             Class<?> evclass = vclass;
       
   364             if (!evclass.isPrimitive())  evclass = Object.class;
       
   365             MethodType type = FieldAccessor.ftype(ecclass, evclass, isSetter, isStatic);
       
   366             MethodHandle mh;
       
   367             try {
       
   368                 mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
       
   369             } catch (ReflectiveOperationException ex) {
       
   370                 throw uncaughtException(ex);
       
   371             }
       
   372             if (evclass != vclass || (!isStatic && ecclass != cclass)) {
       
   373                 MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
       
   374                 strongType = strongType.insertParameterTypes(0, FieldAccessor.class);
       
   375                 mh = MethodHandles.convertArguments(mh, strongType);
       
   376             }
       
   377             return mh;
       
   378         }
       
   379 
       
   380         /// Support for array element access
       
   381         static final HashMap<Class<?>, MethodHandle[]> ARRAY_CACHE =
       
   382                 new HashMap<Class<?>, MethodHandle[]>();
       
   383         // FIXME: Cache on the classes themselves, not here.
       
   384         static boolean doCache(Class<?> elemClass) {
       
   385             if (elemClass.isPrimitive())  return true;
       
   386             ClassLoader cl = elemClass.getClassLoader();
       
   387             return cl == null || cl == ClassLoader.getSystemClassLoader();
       
   388         }
       
   389         static int getElementI(int[] a, int i) { return a[i]; }
       
   390         static void setElementI(int[] a, int i, int x) { a[i] = x; }
       
   391         static long getElementJ(long[] a, int i) { return a[i]; }
       
   392         static void setElementJ(long[] a, int i, long x) { a[i] = x; }
       
   393         static float getElementF(float[] a, int i) { return a[i]; }
       
   394         static void setElementF(float[] a, int i, float x) { a[i] = x; }
       
   395         static double getElementD(double[] a, int i) { return a[i]; }
       
   396         static void setElementD(double[] a, int i, double x) { a[i] = x; }
       
   397         static boolean getElementZ(boolean[] a, int i) { return a[i]; }
       
   398         static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; }
       
   399         static byte getElementB(byte[] a, int i) { return a[i]; }
       
   400         static void setElementB(byte[] a, int i, byte x) { a[i] = x; }
       
   401         static short getElementS(short[] a, int i) { return a[i]; }
       
   402         static void setElementS(short[] a, int i, short x) { a[i] = x; }
       
   403         static char getElementC(char[] a, int i) { return a[i]; }
       
   404         static void setElementC(char[] a, int i, char x) { a[i] = x; }
       
   405         static Object getElementL(Object[] a, int i) { return a[i]; }
       
   406         static void setElementL(Object[] a, int i, Object x) { a[i] = x; }
       
   407         static <V> V getElementL(Class<V[]> aclass, V[] a, int i) { return aclass.cast(a)[i]; }
       
   408         static <V> void setElementL(Class<V[]> aclass, V[] a, int i, V x) { aclass.cast(a)[i] = x; }
       
   409 
       
   410         static String aname(Class<?> aclass, boolean isSetter) {
       
   411             Class<?> vclass = aclass.getComponentType();
       
   412             if (vclass == null)  throw new IllegalArgumentException();
       
   413             return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(vclass);
       
   414         }
       
   415         static MethodType atype(Class<?> aclass, boolean isSetter) {
       
   416             Class<?> vclass = aclass.getComponentType();
       
   417             if (!isSetter)
       
   418                 return MethodType.methodType(vclass, aclass, int.class);
       
   419             else
       
   420                 return MethodType.methodType(void.class, aclass, int.class, vclass);
       
   421         }
       
   422         static MethodHandle ahandle(Class<?> aclass, boolean isSetter) {
       
   423             Class<?> vclass = aclass.getComponentType();
       
   424             String name = FieldAccessor.aname(aclass, isSetter);
       
   425             Class<?> caclass = null;
       
   426             if (!vclass.isPrimitive() && vclass != Object.class) {
       
   427                 caclass = aclass;
       
   428                 aclass = Object[].class;
       
   429                 vclass = Object.class;
       
   430             }
       
   431             MethodType type = FieldAccessor.atype(aclass, isSetter);
       
   432             if (caclass != null)
       
   433                 type = type.insertParameterTypes(0, Class.class);
       
   434             MethodHandle mh;
       
   435             try {
       
   436                 mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
       
   437             } catch (ReflectiveOperationException ex) {
       
   438                 throw uncaughtException(ex);
       
   439             }
       
   440             if (caclass != null) {
       
   441                 MethodType strongType = FieldAccessor.atype(caclass, isSetter);
       
   442                 mh = MethodHandles.insertArguments(mh, 0, caclass);
       
   443                 mh = MethodHandles.convertArguments(mh, strongType);
       
   444             }
       
   445             return mh;
       
   446         }
       
   447     }
       
   448 
       
   449     /** Bind a predetermined first argument to the given direct method handle.
       
   450      * Callable only from MethodHandles.
       
   451      * @param token Proof that the caller has access to this package.
       
   452      * @param target Any direct method handle.
       
   453      * @param receiver Receiver (or first static method argument) to pre-bind.
       
   454      * @return a BoundMethodHandle for the given DirectMethodHandle, or null if it does not exist
       
   455      */
       
   456     static
       
   457     MethodHandle bindReceiver(MethodHandle target, Object receiver) {
       
   458         if (target instanceof AdapterMethodHandle &&
       
   459             ((AdapterMethodHandle)target).conversionOp() == MethodHandleNatives.Constants.OP_RETYPE_ONLY
       
   460             ) {
       
   461             Object info = MethodHandleNatives.getTargetInfo(target);
       
   462             if (info instanceof DirectMethodHandle) {
       
   463                 DirectMethodHandle dmh = (DirectMethodHandle) info;
       
   464                 if (receiver == null ||
       
   465                     dmh.type().parameterType(0).isAssignableFrom(receiver.getClass())) {
       
   466                     MethodHandle bmh = new BoundMethodHandle(dmh, receiver, 0);
       
   467                     MethodType newType = target.type().dropParameterTypes(0, 1);
       
   468                     return convertArguments(bmh, newType, bmh.type(), null);
       
   469                 }
       
   470             }
       
   471         }
       
   472         if (target instanceof DirectMethodHandle)
       
   473             return new BoundMethodHandle((DirectMethodHandle)target, receiver, 0);
       
   474         return null;   // let caller try something else
       
   475     }
       
   476 
       
   477     /** Bind a predetermined argument to the given arbitrary method handle.
       
   478      * Callable only from MethodHandles.
       
   479      * @param token Proof that the caller has access to this package.
       
   480      * @param target Any method handle.
       
   481      * @param receiver Argument (which can be a boxed primitive) to pre-bind.
       
   482      * @return a suitable BoundMethodHandle
       
   483      */
       
   484     static
       
   485     MethodHandle bindArgument(MethodHandle target, int argnum, Object receiver) {
       
   486         return new BoundMethodHandle(target, receiver, argnum);
       
   487     }
       
   488 
       
   489     static MethodHandle convertArguments(MethodHandle target,
       
   490                                                 MethodType newType,
       
   491                                                 MethodType oldType,
       
   492                                                 int[] permutationOrNull) {
       
   493         assert(oldType.parameterCount() == target.type().parameterCount());
       
   494         if (permutationOrNull != null) {
       
   495             int outargs = oldType.parameterCount(), inargs = newType.parameterCount();
       
   496             if (permutationOrNull.length != outargs)
       
   497                 throw newIllegalArgumentException("wrong number of arguments in permutation");
       
   498             // Make the individual outgoing argument types match up first.
       
   499             Class<?>[] callTypeArgs = new Class<?>[outargs];
       
   500             for (int i = 0; i < outargs; i++)
       
   501                 callTypeArgs[i] = newType.parameterType(permutationOrNull[i]);
       
   502             MethodType callType = MethodType.methodType(oldType.returnType(), callTypeArgs);
       
   503             target = convertArguments(target, callType, oldType, null);
       
   504             assert(target != null);
       
   505             oldType = target.type();
       
   506             List<Integer> goal = new ArrayList<Integer>();  // i*TOKEN
       
   507             List<Integer> state = new ArrayList<Integer>(); // i*TOKEN
       
   508             List<Integer> drops = new ArrayList<Integer>(); // not tokens
       
   509             List<Integer> dups = new ArrayList<Integer>();  // not tokens
       
   510             final int TOKEN = 10; // to mark items which are symbolic only
       
   511             // state represents the argument values coming into target
       
   512             for (int i = 0; i < outargs; i++) {
       
   513                 state.add(permutationOrNull[i] * TOKEN);
       
   514             }
       
   515             // goal represents the desired state
       
   516             for (int i = 0; i < inargs; i++) {
       
   517                 if (state.contains(i * TOKEN)) {
       
   518                     goal.add(i * TOKEN);
       
   519                 } else {
       
   520                     // adapter must initially drop all unused arguments
       
   521                     drops.add(i);
       
   522                 }
       
   523             }
       
   524             // detect duplications
       
   525             while (state.size() > goal.size()) {
       
   526                 for (int i2 = 0; i2 < state.size(); i2++) {
       
   527                     int arg1 = state.get(i2);
       
   528                     int i1 = state.indexOf(arg1);
       
   529                     if (i1 != i2) {
       
   530                         // found duplicate occurrence at i2
       
   531                         int arg2 = (inargs++) * TOKEN;
       
   532                         state.set(i2, arg2);
       
   533                         dups.add(goal.indexOf(arg1));
       
   534                         goal.add(arg2);
       
   535                     }
       
   536                 }
       
   537             }
       
   538             assert(state.size() == goal.size());
       
   539             int size = goal.size();
       
   540             while (!state.equals(goal)) {
       
   541                 // Look for a maximal sequence of adjacent misplaced arguments,
       
   542                 // and try to rotate them into place.
       
   543                 int bestRotArg = -10 * TOKEN, bestRotLen = 0;
       
   544                 int thisRotArg = -10 * TOKEN, thisRotLen = 0;
       
   545                 for (int i = 0; i < size; i++) {
       
   546                     int arg = state.get(i);
       
   547                     // Does this argument match the current run?
       
   548                     if (arg == thisRotArg + TOKEN) {
       
   549                         thisRotArg = arg;
       
   550                         thisRotLen += 1;
       
   551                         if (bestRotLen < thisRotLen) {
       
   552                             bestRotLen = thisRotLen;
       
   553                             bestRotArg = thisRotArg;
       
   554                         }
       
   555                     } else {
       
   556                         // The old sequence (if any) stops here.
       
   557                         thisRotLen = 0;
       
   558                         thisRotArg = -10 * TOKEN;
       
   559                         // But maybe a new one starts here also.
       
   560                         int wantArg = goal.get(i);
       
   561                         final int MAX_ARG_ROTATION = AdapterMethodHandle.MAX_ARG_ROTATION;
       
   562                         if (arg != wantArg &&
       
   563                             arg >= wantArg - TOKEN * MAX_ARG_ROTATION &&
       
   564                             arg <= wantArg + TOKEN * MAX_ARG_ROTATION) {
       
   565                             thisRotArg = arg;
       
   566                             thisRotLen = 1;
       
   567                         }
       
   568                     }
       
   569                 }
       
   570                 if (bestRotLen >= 2) {
       
   571                     // Do a rotation if it can improve argument positioning
       
   572                     // by at least 2 arguments.  This is not always optimal,
       
   573                     // but it seems to catch common cases.
       
   574                     int dstEnd = state.indexOf(bestRotArg);
       
   575                     int srcEnd = goal.indexOf(bestRotArg);
       
   576                     int rotBy = dstEnd - srcEnd;
       
   577                     int dstBeg = dstEnd - (bestRotLen - 1);
       
   578                     int srcBeg = srcEnd - (bestRotLen - 1);
       
   579                     assert((dstEnd | dstBeg | srcEnd | srcBeg) >= 0); // no negs
       
   580                     // Make a span which covers both source and destination.
       
   581                     int rotBeg = Math.min(dstBeg, srcBeg);
       
   582                     int rotEnd = Math.max(dstEnd, srcEnd);
       
   583                     int score = 0;
       
   584                     for (int i = rotBeg; i <= rotEnd; i++) {
       
   585                         if ((int)state.get(i) != (int)goal.get(i))
       
   586                             score += 1;
       
   587                     }
       
   588                     List<Integer> rotSpan = state.subList(rotBeg, rotEnd+1);
       
   589                     Collections.rotate(rotSpan, -rotBy);  // reverse direction
       
   590                     for (int i = rotBeg; i <= rotEnd; i++) {
       
   591                         if ((int)state.get(i) != (int)goal.get(i))
       
   592                             score -= 1;
       
   593                     }
       
   594                     if (score >= 2) {
       
   595                         // Improved at least two argument positions.  Do it.
       
   596                         List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
       
   597                         Collections.rotate(ptypes.subList(rotBeg, rotEnd+1), -rotBy);
       
   598                         MethodType rotType = MethodType.methodType(oldType.returnType(), ptypes);
       
   599                         MethodHandle nextTarget
       
   600                                 = AdapterMethodHandle.makeRotateArguments(rotType, target,
       
   601                                         rotBeg, rotSpan.size(), rotBy);
       
   602                         if (nextTarget != null) {
       
   603                             //System.out.println("Rot: "+rotSpan+" by "+rotBy);
       
   604                             target = nextTarget;
       
   605                             oldType = rotType;
       
   606                             continue;
       
   607                         }
       
   608                     }
       
   609                     // Else de-rotate, and drop through to the swap-fest.
       
   610                     Collections.rotate(rotSpan, rotBy);
       
   611                 }
       
   612 
       
   613                 // Now swap like the wind!
       
   614                 List<Class<?>> ptypes = Arrays.asList(oldType.parameterArray());
       
   615                 for (int i = 0; i < size; i++) {
       
   616                     // What argument do I want here?
       
   617                     int arg = goal.get(i);
       
   618                     if (arg != state.get(i)) {
       
   619                         // Where is it now?
       
   620                         int j = state.indexOf(arg);
       
   621                         Collections.swap(ptypes, i, j);
       
   622                         MethodType swapType = MethodType.methodType(oldType.returnType(), ptypes);
       
   623                         target = AdapterMethodHandle.makeSwapArguments(swapType, target, i, j);
       
   624                         if (target == null)  throw newIllegalArgumentException("cannot swap");
       
   625                         assert(target.type() == swapType);
       
   626                         oldType = swapType;
       
   627                         Collections.swap(state, i, j);
       
   628                     }
       
   629                 }
       
   630                 // One pass of swapping must finish the job.
       
   631                 assert(state.equals(goal));
       
   632             }
       
   633             while (!dups.isEmpty()) {
       
   634                 // Grab a contiguous trailing sequence of dups.
       
   635                 int grab = dups.size() - 1;
       
   636                 int dupArgPos = dups.get(grab), dupArgCount = 1;
       
   637                 while (grab - 1 >= 0) {
       
   638                     int dup0 = dups.get(grab - 1);
       
   639                     if (dup0 != dupArgPos - 1)  break;
       
   640                     dupArgPos -= 1;
       
   641                     dupArgCount += 1;
       
   642                     grab -= 1;
       
   643                 }
       
   644                 //if (dupArgCount > 1)  System.out.println("Dup: "+dups.subList(grab, dups.size()));
       
   645                 dups.subList(grab, dups.size()).clear();
       
   646                 // In the new target type drop that many args from the tail:
       
   647                 List<Class<?>> ptypes = oldType.parameterList();
       
   648                 ptypes = ptypes.subList(0, ptypes.size() - dupArgCount);
       
   649                 MethodType dupType = MethodType.methodType(oldType.returnType(), ptypes);
       
   650                 target = AdapterMethodHandle.makeDupArguments(dupType, target, dupArgPos, dupArgCount);
       
   651                 if (target == null)
       
   652                     throw newIllegalArgumentException("cannot dup");
       
   653                 oldType = target.type();
       
   654             }
       
   655             while (!drops.isEmpty()) {
       
   656                 // Grab a contiguous initial sequence of drops.
       
   657                 int dropArgPos = drops.get(0), dropArgCount = 1;
       
   658                 while (dropArgCount < drops.size()) {
       
   659                     int drop1 = drops.get(dropArgCount);
       
   660                     if (drop1 != dropArgPos + dropArgCount)  break;
       
   661                     dropArgCount += 1;
       
   662                 }
       
   663                 //if (dropArgCount > 1)  System.out.println("Drop: "+drops.subList(0, dropArgCount));
       
   664                 drops.subList(0, dropArgCount).clear();
       
   665                 List<Class<?>> dropTypes = newType.parameterList()
       
   666                         .subList(dropArgPos, dropArgPos + dropArgCount);
       
   667                 MethodType dropType = oldType.insertParameterTypes(dropArgPos, dropTypes);
       
   668                 target = AdapterMethodHandle.makeDropArguments(dropType, target, dropArgPos, dropArgCount);
       
   669                 if (target == null)  throw newIllegalArgumentException("cannot drop");
       
   670                 oldType = target.type();
       
   671             }
       
   672         }
       
   673         if (newType == oldType)
       
   674             return target;
       
   675         if (oldType.parameterCount() != newType.parameterCount())
       
   676             throw newIllegalArgumentException("mismatched parameter count");
       
   677         MethodHandle res = AdapterMethodHandle.makePairwiseConvert(newType, target);
       
   678         if (res != null)
       
   679             return res;
       
   680         int argc = oldType.parameterCount();
       
   681         // The JVM can't do it directly, so fill in the gap with a Java adapter.
       
   682         // TO DO: figure out what to put here from case-by-case experience
       
   683         // Use a heavier method:  Convert all the arguments to Object,
       
   684         // then back to the desired types.  We might have to use Java-based
       
   685         // method handles to do this.
       
   686         MethodType objType = MethodType.genericMethodType(argc);
       
   687         MethodHandle objTarget = AdapterMethodHandle.makePairwiseConvert(objType, target);
       
   688         if (objTarget == null)
       
   689             objTarget = FromGeneric.make(target);
       
   690         res = AdapterMethodHandle.makePairwiseConvert(newType, objTarget);
       
   691         if (res != null)
       
   692             return res;
       
   693         return ToGeneric.make(newType, objTarget);
       
   694     }
       
   695 
       
   696     static MethodHandle spreadArguments(MethodHandle target,
       
   697                                                MethodType newType,
       
   698                                                int spreadArg) {
       
   699         // TO DO: maybe allow the restarg to be Object and implicitly cast to Object[]
       
   700         MethodType oldType = target.type();
       
   701         // spread the last argument of newType to oldType
       
   702         int spreadCount = oldType.parameterCount() - spreadArg;
       
   703         Class<Object[]> spreadArgType = Object[].class;
       
   704         MethodHandle res = AdapterMethodHandle.makeSpreadArguments(newType, target, spreadArgType, spreadArg, spreadCount);
       
   705         if (res != null)
       
   706             return res;
       
   707         // try an intermediate adapter
       
   708         Class<?> spreadType = null;
       
   709         if (spreadArg < 0 || spreadArg >= newType.parameterCount()
       
   710             || !VerifyType.isSpreadArgType(spreadType = newType.parameterType(spreadArg)))
       
   711             throw newIllegalArgumentException("no restarg in "+newType);
       
   712         Class<?>[] ptypes = oldType.parameterArray();
       
   713         for (int i = 0; i < spreadCount; i++)
       
   714             ptypes[spreadArg + i] = VerifyType.spreadArgElementType(spreadType, i);
       
   715         MethodType midType = MethodType.methodType(newType.returnType(), ptypes);
       
   716         // after spreading, some arguments may need further conversion
       
   717         MethodHandle target2 = convertArguments(target, midType, oldType, null);
       
   718         if (target2 == null)
       
   719             throw new UnsupportedOperationException("NYI: convert "+midType+" =calls=> "+oldType);
       
   720         res = AdapterMethodHandle.makeSpreadArguments(newType, target2, spreadArgType, spreadArg, spreadCount);
       
   721         if (res != null)
       
   722             return res;
       
   723         res = SpreadGeneric.make(target2, spreadCount);
       
   724         if (res != null)
       
   725             res = convertArguments(res, newType, res.type(), null);
       
   726         return res;
       
   727     }
       
   728 
       
   729     static MethodHandle collectArguments(MethodHandle target,
       
   730                                                 MethodType newType,
       
   731                                                 int collectArg,
       
   732                                                 MethodHandle collector) {
       
   733         MethodType oldType = target.type();     // (a...,c)=>r
       
   734         if (collector == null) {
       
   735             int numCollect = newType.parameterCount() - oldType.parameterCount() + 1;
       
   736             collector = ValueConversions.varargsArray(numCollect);
       
   737         }
       
   738         //         newType                      // (a..., b...)=>r
       
   739         MethodType colType = collector.type();  // (b...)=>c
       
   740         //         oldType                      // (a..., b...)=>r
       
   741         assert(newType.parameterCount() == collectArg + colType.parameterCount());
       
   742         assert(oldType.parameterCount() == collectArg + 1);
       
   743         MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
       
   744         MethodHandle gcollector = convertArguments(collector, colType.generic(), colType, null);
       
   745         if (gtarget == null || gcollector == null)  return null;
       
   746         MethodHandle gresult = FilterGeneric.makeArgumentCollector(gcollector, gtarget);
       
   747         MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
       
   748         return result;
       
   749     }
       
   750 
       
   751     static MethodHandle filterArgument(MethodHandle target,
       
   752                                               int pos,
       
   753                                               MethodHandle filter) {
       
   754         MethodType ttype = target.type(), gttype = ttype.generic();
       
   755         if (ttype != gttype) {
       
   756             target = convertArguments(target, gttype, ttype, null);
       
   757             ttype = gttype;
       
   758         }
       
   759         MethodType ftype = filter.type(), gftype = ftype.generic();
       
   760         if (ftype.parameterCount() != 1)
       
   761             throw new InternalError();
       
   762         if (ftype != gftype) {
       
   763             filter = convertArguments(filter, gftype, ftype, null);
       
   764             ftype = gftype;
       
   765         }
       
   766         if (ftype == ttype) {
       
   767             // simple unary case
       
   768             return FilterOneArgument.make(filter, target);
       
   769         }
       
   770         return FilterGeneric.makeArgumentFilter(pos, filter, target);
       
   771     }
       
   772 
       
   773     static MethodHandle foldArguments(MethodHandle target,
       
   774                                              MethodType newType,
       
   775                                              MethodHandle combiner) {
       
   776         MethodType oldType = target.type();
       
   777         MethodType ctype = combiner.type();
       
   778         MethodHandle gtarget = convertArguments(target, oldType.generic(), oldType, null);
       
   779         MethodHandle gcombiner = convertArguments(combiner, ctype.generic(), ctype, null);
       
   780         if (gtarget == null || gcombiner == null)  return null;
       
   781         MethodHandle gresult = FilterGeneric.makeArgumentFolder(gcombiner, gtarget);
       
   782         MethodHandle result = convertArguments(gresult, newType, gresult.type(), null);
       
   783         return result;
       
   784     }
       
   785 
       
   786     static
       
   787     MethodHandle dropArguments(MethodHandle target,
       
   788                                MethodType newType, int argnum) {
       
   789         int drops = newType.parameterCount() - target.type().parameterCount();
       
   790         MethodHandle res = AdapterMethodHandle.makeDropArguments(newType, target, argnum, drops);
       
   791         if (res != null)
       
   792             return res;
       
   793         throw new UnsupportedOperationException("NYI");
       
   794     }
       
   795 
       
   796     private static class GuardWithTest extends BoundMethodHandle {
       
   797         private final MethodHandle test, target, fallback;
       
   798         private GuardWithTest(MethodHandle invoker,
       
   799                               MethodHandle test, MethodHandle target, MethodHandle fallback) {
       
   800             super(invoker);
       
   801             this.test = test;
       
   802             this.target = target;
       
   803             this.fallback = fallback;
       
   804         }
       
   805         static MethodHandle make(MethodHandle test, MethodHandle target, MethodHandle fallback) {
       
   806             MethodType type = target.type();
       
   807             int nargs = type.parameterCount();
       
   808             if (nargs < INVOKES.length) {
       
   809                 MethodHandle invoke = INVOKES[nargs];
       
   810                 MethodType gtype = type.generic();
       
   811                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
       
   812                 MethodHandle gtest = convertArguments(test, gtype.changeReturnType(boolean.class), test.type(), null);
       
   813                 MethodHandle gtarget = convertArguments(target, gtype, type, null);
       
   814                 MethodHandle gfallback = convertArguments(fallback, gtype, type, null);
       
   815                 if (gtest == null || gtarget == null || gfallback == null)  return null;
       
   816                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
       
   817                 return convertArguments(gguard, type, gtype, null);
       
   818             } else {
       
   819                 MethodHandle invoke = VARARGS_INVOKE;
       
   820                 MethodType gtype = MethodType.genericMethodType(1);
       
   821                 assert(invoke.type().dropParameterTypes(0,1) == gtype);
       
   822                 MethodHandle gtest = spreadArguments(test, gtype.changeReturnType(boolean.class), 0);
       
   823                 MethodHandle gtarget = spreadArguments(target, gtype, 0);
       
   824                 MethodHandle gfallback = spreadArguments(fallback, gtype, 0);
       
   825                 MethodHandle gguard = new GuardWithTest(invoke, gtest, gtarget, gfallback);
       
   826                 if (gtest == null || gtarget == null || gfallback == null)  return null;
       
   827                 return collectArguments(gguard, type, 0, null);
       
   828             }
       
   829         }
       
   830         @Override
       
   831         public String toString() {
       
   832             return addTypeString(target, this);
       
   833         }
       
   834         private Object invoke_V(Object... av) throws Throwable {
       
   835             if ((boolean) test.invokeExact(av))
       
   836                 return target.invokeExact(av);
       
   837             return fallback.invokeExact(av);
       
   838         }
       
   839         private Object invoke_L0() throws Throwable {
       
   840             if ((boolean) test.invokeExact())
       
   841                 return target.invokeExact();
       
   842             return fallback.invokeExact();
       
   843         }
       
   844         private Object invoke_L1(Object a0) throws Throwable {
       
   845             if ((boolean) test.invokeExact(a0))
       
   846                 return target.invokeExact(a0);
       
   847             return fallback.invokeExact(a0);
       
   848         }
       
   849         private Object invoke_L2(Object a0, Object a1) throws Throwable {
       
   850             if ((boolean) test.invokeExact(a0, a1))
       
   851                 return target.invokeExact(a0, a1);
       
   852             return fallback.invokeExact(a0, a1);
       
   853         }
       
   854         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
       
   855             if ((boolean) test.invokeExact(a0, a1, a2))
       
   856                 return target.invokeExact(a0, a1, a2);
       
   857             return fallback.invokeExact(a0, a1, a2);
       
   858         }
       
   859         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
       
   860             if ((boolean) test.invokeExact(a0, a1, a2, a3))
       
   861                 return target.invokeExact(a0, a1, a2, a3);
       
   862             return fallback.invokeExact(a0, a1, a2, a3);
       
   863         }
       
   864         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
       
   865             if ((boolean) test.invokeExact(a0, a1, a2, a3, a4))
       
   866                 return target.invokeExact(a0, a1, a2, a3, a4);
       
   867             return fallback.invokeExact(a0, a1, a2, a3, a4);
       
   868         }
       
   869         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
       
   870             if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5))
       
   871                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
       
   872             return fallback.invokeExact(a0, a1, a2, a3, a4, a5);
       
   873         }
       
   874         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
       
   875             if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6))
       
   876                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
       
   877             return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6);
       
   878         }
       
   879         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
       
   880             if ((boolean) test.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7))
       
   881                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
       
   882             return fallback.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
       
   883         }
       
   884         static MethodHandle[] makeInvokes() {
       
   885             ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
       
   886             MethodHandles.Lookup lookup = IMPL_LOOKUP;
       
   887             for (;;) {
       
   888                 int nargs = invokes.size();
       
   889                 String name = "invoke_L"+nargs;
       
   890                 MethodHandle invoke = null;
       
   891                 try {
       
   892                     invoke = lookup.findVirtual(GuardWithTest.class, name, MethodType.genericMethodType(nargs));
       
   893                 } catch (ReflectiveOperationException ex) {
       
   894                 }
       
   895                 if (invoke == null)  break;
       
   896                 invokes.add(invoke);
       
   897             }
       
   898             assert(invokes.size() == 9);  // current number of methods
       
   899             return invokes.toArray(new MethodHandle[0]);
       
   900         };
       
   901         static final MethodHandle[] INVOKES = makeInvokes();
       
   902         // For testing use this:
       
   903         //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
       
   904         static final MethodHandle VARARGS_INVOKE;
       
   905         static {
       
   906             try {
       
   907                 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithTest.class, "invoke_V", MethodType.genericMethodType(0, true));
       
   908             } catch (ReflectiveOperationException ex) {
       
   909                 throw uncaughtException(ex);
       
   910             }
       
   911         }
       
   912     }
       
   913 
       
   914     static
       
   915     MethodHandle makeGuardWithTest(MethodHandle test,
       
   916                                    MethodHandle target,
       
   917                                    MethodHandle fallback) {
       
   918         return GuardWithTest.make(test, target, fallback);
       
   919     }
       
   920 
       
   921     private static class GuardWithCatch extends BoundMethodHandle {
       
   922         private final MethodHandle target;
       
   923         private final Class<? extends Throwable> exType;
       
   924         private final MethodHandle catcher;
       
   925         GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
       
   926             this(INVOKES[target.type().parameterCount()], target, exType, catcher);
       
   927         }
       
   928        GuardWithCatch(MethodHandle invoker,
       
   929                       MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) {
       
   930             super(invoker);
       
   931             this.target = target;
       
   932             this.exType = exType;
       
   933             this.catcher = catcher;
       
   934         }
       
   935         @Override
       
   936         public String toString() {
       
   937             return addTypeString(target, this);
       
   938         }
       
   939         private Object invoke_V(Object... av) throws Throwable {
       
   940             try {
       
   941                 return target.invokeExact(av);
       
   942             } catch (Throwable t) {
       
   943                 if (!exType.isInstance(t))  throw t;
       
   944                 return catcher.invokeExact(t, av);
       
   945             }
       
   946         }
       
   947         private Object invoke_L0() throws Throwable {
       
   948             try {
       
   949                 return target.invokeExact();
       
   950             } catch (Throwable t) {
       
   951                 if (!exType.isInstance(t))  throw t;
       
   952                 return catcher.invokeExact(t);
       
   953             }
       
   954         }
       
   955         private Object invoke_L1(Object a0) throws Throwable {
       
   956             try {
       
   957                 return target.invokeExact(a0);
       
   958             } catch (Throwable t) {
       
   959                 if (!exType.isInstance(t))  throw t;
       
   960                 return catcher.invokeExact(t, a0);
       
   961             }
       
   962         }
       
   963         private Object invoke_L2(Object a0, Object a1) throws Throwable {
       
   964             try {
       
   965                 return target.invokeExact(a0, a1);
       
   966             } catch (Throwable t) {
       
   967                 if (!exType.isInstance(t))  throw t;
       
   968                 return catcher.invokeExact(t, a0, a1);
       
   969             }
       
   970         }
       
   971         private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable {
       
   972             try {
       
   973                 return target.invokeExact(a0, a1, a2);
       
   974             } catch (Throwable t) {
       
   975                 if (!exType.isInstance(t))  throw t;
       
   976                 return catcher.invokeExact(t, a0, a1, a2);
       
   977             }
       
   978         }
       
   979         private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable {
       
   980             try {
       
   981                 return target.invokeExact(a0, a1, a2, a3);
       
   982             } catch (Throwable t) {
       
   983                 if (!exType.isInstance(t))  throw t;
       
   984                 return catcher.invokeExact(t, a0, a1, a2, a3);
       
   985             }
       
   986         }
       
   987         private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable {
       
   988             try {
       
   989                 return target.invokeExact(a0, a1, a2, a3, a4);
       
   990             } catch (Throwable t) {
       
   991                 if (!exType.isInstance(t))  throw t;
       
   992                 return catcher.invokeExact(t, a0, a1, a2, a3, a4);
       
   993             }
       
   994         }
       
   995         private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable {
       
   996             try {
       
   997                 return target.invokeExact(a0, a1, a2, a3, a4, a5);
       
   998             } catch (Throwable t) {
       
   999                 if (!exType.isInstance(t))  throw t;
       
  1000                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5);
       
  1001             }
       
  1002         }
       
  1003         private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable {
       
  1004             try {
       
  1005                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6);
       
  1006             } catch (Throwable t) {
       
  1007                 if (!exType.isInstance(t))  throw t;
       
  1008                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6);
       
  1009             }
       
  1010         }
       
  1011         private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable {
       
  1012             try {
       
  1013                 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7);
       
  1014             } catch (Throwable t) {
       
  1015                 if (!exType.isInstance(t))  throw t;
       
  1016                 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7);
       
  1017             }
       
  1018         }
       
  1019         static MethodHandle[] makeInvokes() {
       
  1020             ArrayList<MethodHandle> invokes = new ArrayList<MethodHandle>();
       
  1021             MethodHandles.Lookup lookup = IMPL_LOOKUP;
       
  1022             for (;;) {
       
  1023                 int nargs = invokes.size();
       
  1024                 String name = "invoke_L"+nargs;
       
  1025                 MethodHandle invoke = null;
       
  1026                 try {
       
  1027                     invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs));
       
  1028                 } catch (ReflectiveOperationException ex) {
       
  1029                 }
       
  1030                 if (invoke == null)  break;
       
  1031                 invokes.add(invoke);
       
  1032             }
       
  1033             assert(invokes.size() == 9);  // current number of methods
       
  1034             return invokes.toArray(new MethodHandle[0]);
       
  1035         };
       
  1036         static final MethodHandle[] INVOKES = makeInvokes();
       
  1037         // For testing use this:
       
  1038         //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2);
       
  1039         static final MethodHandle VARARGS_INVOKE;
       
  1040         static {
       
  1041             try {
       
  1042                 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
       
  1043             } catch (ReflectiveOperationException ex) {
       
  1044                 throw uncaughtException(ex);
       
  1045             }
       
  1046         }
       
  1047     }
       
  1048 
       
  1049 
       
  1050     static
       
  1051     MethodHandle makeGuardWithCatch(MethodHandle target,
       
  1052                                     Class<? extends Throwable> exType,
       
  1053                                     MethodHandle catcher) {
       
  1054         MethodType type = target.type();
       
  1055         MethodType ctype = catcher.type();
       
  1056         int nargs = type.parameterCount();
       
  1057         if (nargs < GuardWithCatch.INVOKES.length) {
       
  1058             MethodType gtype = type.generic();
       
  1059             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
       
  1060             MethodHandle gtarget = convertArguments(target, gtype, type, null);
       
  1061             MethodHandle gcatcher = convertArguments(catcher, gcatchType, ctype, null);
       
  1062             MethodHandle gguard = new GuardWithCatch(gtarget, exType, gcatcher);
       
  1063             if (gtarget == null || gcatcher == null || gguard == null)  return null;
       
  1064             return convertArguments(gguard, type, gtype, null);
       
  1065         } else {
       
  1066             MethodType gtype = MethodType.genericMethodType(0, true);
       
  1067             MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class);
       
  1068             MethodHandle gtarget = spreadArguments(target, gtype, 0);
       
  1069             MethodHandle gcatcher = spreadArguments(catcher, gcatchType, 1);
       
  1070             MethodHandle gguard = new GuardWithCatch(GuardWithCatch.VARARGS_INVOKE, gtarget, exType, gcatcher);
       
  1071             if (gtarget == null || gcatcher == null || gguard == null)  return null;
       
  1072             return collectArguments(gguard, type, 0, null);
       
  1073         }
       
  1074     }
       
  1075 
       
  1076     static
       
  1077     MethodHandle throwException(MethodType type) {
       
  1078         return AdapterMethodHandle.makeRetypeRaw(type, throwException());
       
  1079     }
       
  1080 
       
  1081     static MethodHandle THROW_EXCEPTION;
       
  1082     static MethodHandle throwException() {
       
  1083         if (THROW_EXCEPTION != null)  return THROW_EXCEPTION;
       
  1084         try {
       
  1085             THROW_EXCEPTION
       
  1086             = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
       
  1087                     MethodType.methodType(Empty.class, Throwable.class));
       
  1088         } catch (ReflectiveOperationException ex) {
       
  1089             throw new RuntimeException(ex);
       
  1090         }
       
  1091         return THROW_EXCEPTION;
       
  1092     }
       
  1093     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
       
  1094 
       
  1095     // Linkage support:
       
  1096     static void registerBootstrap(Class<?> callerClass, MethodHandle bootstrapMethod) {
       
  1097         MethodHandleNatives.registerBootstrap(callerClass, bootstrapMethod);
       
  1098     }
       
  1099     static MethodHandle getBootstrap(Class<?> callerClass) {
       
  1100         return MethodHandleNatives.getBootstrap(callerClass);
       
  1101     }
       
  1102 
       
  1103     static MethodHandle asVarargsCollector(MethodHandle target, Class<?> arrayType) {
       
  1104         return AdapterMethodHandle.makeVarargsCollector(target, arrayType);
       
  1105     }
       
  1106 }