Home » openjdk-7 » java.lang.invoke » [javadoc | source]

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

Home » openjdk-7 » java.lang.invoke » [javadoc | source]