jdk/src/share/classes/sun/dyn/AdapterMethodHandle.java
changeset 8823 7cd28219a1e4
parent 8717 f75a1efb1412
parent 8822 8145ab9f5f86
child 8824 0762fa26f813
child 9033 a88f5656f05d
equal deleted inserted replaced
8717:f75a1efb1412 8823:7cd28219a1e4
     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 sun.dyn;
       
    27 
       
    28 import sun.dyn.util.VerifyType;
       
    29 import sun.dyn.util.Wrapper;
       
    30 import java.dyn.*;
       
    31 import java.util.Arrays;
       
    32 import static sun.dyn.MethodHandleNatives.Constants.*;
       
    33 import static sun.dyn.MemberName.newIllegalArgumentException;
       
    34 
       
    35 /**
       
    36  * This method handle performs simple conversion or checking of a single argument.
       
    37  * @author jrose
       
    38  */
       
    39 public class AdapterMethodHandle extends BoundMethodHandle {
       
    40 
       
    41     //MethodHandle vmtarget;   // next AMH or BMH in chain or final DMH
       
    42     //Object       argument;   // parameter to the conversion if needed
       
    43     //int          vmargslot;  // which argument slot is affected
       
    44     private final int conversion;  // the type of conversion: RETYPE_ONLY, etc.
       
    45 
       
    46     // Constructors in this class *must* be package scoped or private.
       
    47     private AdapterMethodHandle(MethodHandle target, MethodType newType,
       
    48                 long conv, Object convArg) {
       
    49         super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
       
    50         this.conversion = convCode(conv);
       
    51         if (MethodHandleNatives.JVM_SUPPORT) {
       
    52             // JVM might update VM-specific bits of conversion (ignore)
       
    53             MethodHandleNatives.init(this, target, convArgPos(conv));
       
    54         }
       
    55     }
       
    56     private AdapterMethodHandle(MethodHandle target, MethodType newType,
       
    57                 long conv) {
       
    58         this(target, newType, conv, null);
       
    59     }
       
    60 
       
    61     private static final Access IMPL_TOKEN = Access.getToken();
       
    62 
       
    63     // TO DO:  When adapting another MH with a null conversion, clone
       
    64     // the target and change its type, instead of adding another layer.
       
    65 
       
    66     /** Can a JVM-level adapter directly implement the proposed
       
    67      *  argument conversions, as if by MethodHandles.convertArguments?
       
    68      */
       
    69     public static boolean canPairwiseConvert(MethodType newType, MethodType oldType) {
       
    70         // same number of args, of course
       
    71         int len = newType.parameterCount();
       
    72         if (len != oldType.parameterCount())
       
    73             return false;
       
    74 
       
    75         // Check return type.  (Not much can be done with it.)
       
    76         Class<?> exp = newType.returnType();
       
    77         Class<?> ret = oldType.returnType();
       
    78         if (!VerifyType.isNullConversion(ret, exp))
       
    79             return false;
       
    80 
       
    81         // Check args pairwise.
       
    82         for (int i = 0; i < len; i++) {
       
    83             Class<?> src = newType.parameterType(i); // source type
       
    84             Class<?> dst = oldType.parameterType(i); // destination type
       
    85             if (!canConvertArgument(src, dst))
       
    86                 return false;
       
    87         }
       
    88 
       
    89         return true;
       
    90     }
       
    91 
       
    92     /** Can a JVM-level adapter directly implement the proposed
       
    93      *  argument conversion, as if by MethodHandles.convertArguments?
       
    94      */
       
    95     public static boolean canConvertArgument(Class<?> src, Class<?> dst) {
       
    96         // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
       
    97         // so we don't need to repeat so much decision making.
       
    98         if (VerifyType.isNullConversion(src, dst)) {
       
    99             return true;
       
   100         } else if (src.isPrimitive()) {
       
   101             if (dst.isPrimitive())
       
   102                 return canPrimCast(src, dst);
       
   103             else
       
   104                 return canBoxArgument(src, dst);
       
   105         } else {
       
   106             if (dst.isPrimitive())
       
   107                 return canUnboxArgument(src, dst);
       
   108             else
       
   109                 return true;  // any two refs can be interconverted
       
   110         }
       
   111     }
       
   112 
       
   113     /**
       
   114      * Create a JVM-level adapter method handle to conform the given method
       
   115      * handle to the similar newType, using only pairwise argument conversions.
       
   116      * For each argument, convert incoming argument to the exact type needed.
       
   117      * Only null conversions are allowed on the return value (until
       
   118      * the JVM supports ricochet adapters).
       
   119      * The argument conversions allowed are casting, unboxing,
       
   120      * integral widening or narrowing, and floating point widening or narrowing.
       
   121      * @param token access check
       
   122      * @param newType required call type
       
   123      * @param target original method handle
       
   124      * @return an adapter to the original handle with the desired new type,
       
   125      *          or the original target if the types are already identical
       
   126      *          or null if the adaptation cannot be made
       
   127      */
       
   128     public static MethodHandle makePairwiseConvert(Access token,
       
   129                 MethodType newType, MethodHandle target) {
       
   130         Access.check(token);
       
   131         MethodType oldType = target.type();
       
   132         if (newType == oldType)  return target;
       
   133 
       
   134         if (!canPairwiseConvert(newType, oldType))
       
   135             return null;
       
   136         // (after this point, it is an assertion error to fail to convert)
       
   137 
       
   138         // Find last non-trivial conversion (if any).
       
   139         int lastConv = newType.parameterCount()-1;
       
   140         while (lastConv >= 0) {
       
   141             Class<?> src = newType.parameterType(lastConv); // source type
       
   142             Class<?> dst = oldType.parameterType(lastConv); // destination type
       
   143             if (VerifyType.isNullConversion(src, dst)) {
       
   144                 --lastConv;
       
   145             } else {
       
   146                 break;
       
   147             }
       
   148         }
       
   149         // Now build a chain of one or more adapters.
       
   150         MethodHandle adapter = target;
       
   151         MethodType midType = oldType.changeReturnType(newType.returnType());
       
   152         for (int i = 0; i <= lastConv; i++) {
       
   153             Class<?> src = newType.parameterType(i); // source type
       
   154             Class<?> dst = midType.parameterType(i); // destination type
       
   155             if (VerifyType.isNullConversion(src, dst)) {
       
   156                 // do nothing: difference is trivial
       
   157                 continue;
       
   158             }
       
   159             // Work the current type backward toward the desired caller type:
       
   160             if (i != lastConv) {
       
   161                 midType = midType.changeParameterType(i, src);
       
   162             } else {
       
   163                 // When doing the last (or only) real conversion,
       
   164                 // force all remaining null conversions to happen also.
       
   165                 assert(VerifyType.isNullConversion(newType, midType.changeParameterType(i, src)));
       
   166                 midType = newType;
       
   167             }
       
   168 
       
   169             // Tricky case analysis follows.
       
   170             // It parallels canConvertArgument() above.
       
   171             if (src.isPrimitive()) {
       
   172                 if (dst.isPrimitive()) {
       
   173                     adapter = makePrimCast(token, midType, adapter, i, dst);
       
   174                 } else {
       
   175                     adapter = makeBoxArgument(token, midType, adapter, i, dst);
       
   176                 }
       
   177             } else {
       
   178                 if (dst.isPrimitive()) {
       
   179                     // Caller has boxed a primitive.  Unbox it for the target.
       
   180                     // The box type must correspond exactly to the primitive type.
       
   181                     // This is simpler than the powerful set of widening
       
   182                     // conversions supported by reflect.Method.invoke.
       
   183                     // Those conversions require a big nest of if/then/else logic,
       
   184                     // which we prefer to make a user responsibility.
       
   185                     adapter = makeUnboxArgument(token, midType, adapter, i, dst);
       
   186                 } else {
       
   187                     // Simple reference conversion.
       
   188                     // Note:  Do not check for a class hierarchy relation
       
   189                     // between src and dst.  In all cases a 'null' argument
       
   190                     // will pass the cast conversion.
       
   191                     adapter = makeCheckCast(token, midType, adapter, i, dst);
       
   192                 }
       
   193             }
       
   194             assert(adapter != null);
       
   195             assert(adapter.type() == midType);
       
   196         }
       
   197         if (adapter.type() != newType) {
       
   198             // Only trivial conversions remain.
       
   199             adapter = makeRetypeOnly(IMPL_TOKEN, newType, adapter);
       
   200             assert(adapter != null);
       
   201             // Actually, that's because there were no non-trivial ones:
       
   202             assert(lastConv == -1);
       
   203         }
       
   204         assert(adapter.type() == newType);
       
   205         return adapter;
       
   206     }
       
   207 
       
   208     /**
       
   209      * Create a JVM-level adapter method handle to permute the arguments
       
   210      * of the given method.
       
   211      * @param token access check
       
   212      * @param newType required call type
       
   213      * @param target original method handle
       
   214      * @param argumentMap for each target argument, position of its source in newType
       
   215      * @return an adapter to the original handle with the desired new type,
       
   216      *          or the original target if the types are already identical
       
   217      *          and the permutation is null
       
   218      * @throws IllegalArgumentException if the adaptation cannot be made
       
   219      *          directly by a JVM-level adapter, without help from Java code
       
   220      */
       
   221     public static MethodHandle makePermutation(Access token,
       
   222                 MethodType newType, MethodHandle target,
       
   223                 int[] argumentMap) {
       
   224         MethodType oldType = target.type();
       
   225         boolean nullPermutation = true;
       
   226         for (int i = 0; i < argumentMap.length; i++) {
       
   227             int pos = argumentMap[i];
       
   228             if (pos != i)
       
   229                 nullPermutation = false;
       
   230             if (pos < 0 || pos >= newType.parameterCount()) {
       
   231                 argumentMap = new int[0]; break;
       
   232             }
       
   233         }
       
   234         if (argumentMap.length != oldType.parameterCount())
       
   235             throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
       
   236         if (nullPermutation) {
       
   237             MethodHandle res = makePairwiseConvert(token, newType, target);
       
   238             // well, that was easy
       
   239             if (res == null)
       
   240                 throw newIllegalArgumentException("cannot convert pairwise: "+newType);
       
   241             return res;
       
   242         }
       
   243 
       
   244         // Check return type.  (Not much can be done with it.)
       
   245         Class<?> exp = newType.returnType();
       
   246         Class<?> ret = oldType.returnType();
       
   247         if (!VerifyType.isNullConversion(ret, exp))
       
   248             throw newIllegalArgumentException("bad return conversion for "+newType);
       
   249 
       
   250         // See if the argument types match up.
       
   251         for (int i = 0; i < argumentMap.length; i++) {
       
   252             int j = argumentMap[i];
       
   253             Class<?> src = newType.parameterType(j);
       
   254             Class<?> dst = oldType.parameterType(i);
       
   255             if (!VerifyType.isNullConversion(src, dst))
       
   256                 throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
       
   257         }
       
   258 
       
   259         // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
       
   260         // A workable greedy algorithm is as follows:
       
   261         // Drop unused outgoing arguments (right to left: shallowest first).
       
   262         // Duplicate doubly-used outgoing arguments (left to right: deepest first).
       
   263         // Then the remaining problem is a true argument permutation.
       
   264         // Marshal the outgoing arguments as required from left to right.
       
   265         // That is, find the deepest outgoing stack position that does not yet
       
   266         // have the correct argument value, and correct at least that position
       
   267         // by swapping or rotating in the misplaced value (from a shallower place).
       
   268         // If the misplaced value is followed by one or more consecutive values
       
   269         // (also misplaced)  issue a rotation which brings as many as possible
       
   270         // into position.  Otherwise make progress with either a swap or a
       
   271         // rotation.  Prefer the swap as cheaper, but do not use it if it
       
   272         // breaks a slot pair.  Prefer the rotation over the swap if it would
       
   273         // preserve more consecutive values shallower than the target position.
       
   274         // When more than one rotation will work (because the required value
       
   275         // is already adjacent to the target position), then use a rotation
       
   276         // which moves the old value in the target position adjacent to
       
   277         // one of its consecutive values.  Also, prefer shorter rotation
       
   278         // spans, since they use fewer memory cycles for shuffling.
       
   279 
       
   280         throw new UnsupportedOperationException("NYI");
       
   281     }
       
   282 
       
   283     private static byte basicType(Class<?> type) {
       
   284         if (type == null)  return T_VOID;
       
   285         switch (Wrapper.forBasicType(type)) {
       
   286             case BOOLEAN:  return T_BOOLEAN;
       
   287             case CHAR:     return T_CHAR;
       
   288             case FLOAT:    return T_FLOAT;
       
   289             case DOUBLE:   return T_DOUBLE;
       
   290             case BYTE:     return T_BYTE;
       
   291             case SHORT:    return T_SHORT;
       
   292             case INT:      return T_INT;
       
   293             case LONG:     return T_LONG;
       
   294             case OBJECT:   return T_OBJECT;
       
   295             case VOID:     return T_VOID;
       
   296         }
       
   297         return 99; // T_ILLEGAL or some such
       
   298     }
       
   299 
       
   300     /** Number of stack slots for the given type.
       
   301      *  Two for T_DOUBLE and T_FLOAT, one for the rest.
       
   302      */
       
   303     private static int type2size(int type) {
       
   304         assert(type >= T_BOOLEAN && type <= T_OBJECT);
       
   305         return (type == T_LONG || type == T_DOUBLE) ? 2 : 1;
       
   306     }
       
   307     private static int type2size(Class<?> type) {
       
   308         return type2size(basicType(type));
       
   309     }
       
   310 
       
   311     /** The given stackMove is the number of slots pushed.
       
   312      * It might be negative.  Scale it (multiply) by the
       
   313      * VM's notion of how an address changes with a push,
       
   314      * to get the raw SP change for stackMove.
       
   315      * Then shift and mask it into the correct field.
       
   316      */
       
   317     private static long insertStackMove(int stackMove) {
       
   318         // following variable must be long to avoid sign extension after '<<'
       
   319         long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT;
       
   320         return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT;
       
   321     }
       
   322 
       
   323     /** Construct an adapter conversion descriptor for a single-argument conversion. */
       
   324     private static long makeConv(int convOp, int argnum, int src, int dest) {
       
   325         assert(src  == (src  & 0xF));
       
   326         assert(dest == (dest & 0xF));
       
   327         assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF);
       
   328         int stackMove = type2size(dest) - type2size(src);
       
   329         return ((long) argnum << 32 |
       
   330                 (long) convOp << CONV_OP_SHIFT |
       
   331                 (int)  src    << CONV_SRC_TYPE_SHIFT |
       
   332                 (int)  dest   << CONV_DEST_TYPE_SHIFT |
       
   333                 insertStackMove(stackMove)
       
   334                 );
       
   335     }
       
   336     private static long makeConv(int convOp, int argnum, int stackMove) {
       
   337         assert(convOp >= OP_DUP_ARGS && convOp <= OP_SPREAD_ARGS);
       
   338         byte src = 0, dest = 0;
       
   339         if (convOp >= OP_COLLECT_ARGS && convOp <= OP_SPREAD_ARGS)
       
   340             src = dest = T_OBJECT;
       
   341         return ((long) argnum << 32 |
       
   342                 (long) convOp << CONV_OP_SHIFT |
       
   343                 (int)  src    << CONV_SRC_TYPE_SHIFT |
       
   344                 (int)  dest   << CONV_DEST_TYPE_SHIFT |
       
   345                 insertStackMove(stackMove)
       
   346                 );
       
   347     }
       
   348     private static long makeSwapConv(int convOp, int srcArg, byte type, int destSlot) {
       
   349         assert(convOp >= OP_SWAP_ARGS && convOp <= OP_ROT_ARGS);
       
   350         return ((long) srcArg << 32 |
       
   351                 (long) convOp << CONV_OP_SHIFT |
       
   352                 (int)  type   << CONV_SRC_TYPE_SHIFT |
       
   353                 (int)  type   << CONV_DEST_TYPE_SHIFT |
       
   354                 (int)  destSlot << CONV_VMINFO_SHIFT
       
   355                 );
       
   356     }
       
   357     private static long makeConv(int convOp) {
       
   358         assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW);
       
   359         return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT);   // stackMove, src, dst all zero
       
   360     }
       
   361     private static int convCode(long conv) {
       
   362         return (int)conv;
       
   363     }
       
   364     private static int convArgPos(long conv) {
       
   365         return (int)(conv >>> 32);
       
   366     }
       
   367     private static boolean convOpSupported(int convOp) {
       
   368         assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
       
   369         return ((1<<convOp) & MethodHandleNatives.CONV_OP_IMPLEMENTED_MASK) != 0;
       
   370     }
       
   371 
       
   372     /** One of OP_RETYPE_ONLY, etc. */
       
   373     int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
       
   374 
       
   375     /* Return one plus the position of the first non-trivial difference
       
   376      * between the given types.  This is not a symmetric operation;
       
   377      * we are considering adapting the targetType to adapterType.
       
   378      * Trivial differences are those which could be ignored by the JVM
       
   379      * without subverting the verifier.  Otherwise, adaptable differences
       
   380      * are ones for which we could create an adapter to make the type change.
       
   381      * Return zero if there are no differences (other than trivial ones).
       
   382      * Return 1+N if N is the only adaptable argument difference.
       
   383      * Return the -2-N where N is the first of several adaptable
       
   384      * argument differences.
       
   385      * Return -1 if there there are differences which are not adaptable.
       
   386      */
       
   387     private static int diffTypes(MethodType adapterType,
       
   388                                  MethodType targetType,
       
   389                                  boolean raw) {
       
   390         int diff;
       
   391         diff = diffReturnTypes(adapterType, targetType, raw);
       
   392         if (diff != 0)  return diff;
       
   393         int nargs = adapterType.parameterCount();
       
   394         if (nargs != targetType.parameterCount())
       
   395             return -1;
       
   396         diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
       
   397         //System.out.println("diff "+adapterType);
       
   398         //System.out.println("  "+diff+" "+targetType);
       
   399         return diff;
       
   400     }
       
   401     private static int diffReturnTypes(MethodType adapterType,
       
   402                                        MethodType targetType,
       
   403                                        boolean raw) {
       
   404         Class<?> src = targetType.returnType();
       
   405         Class<?> dst = adapterType.returnType();
       
   406         if ((!raw
       
   407              ? VerifyType.canPassUnchecked(src, dst)
       
   408              : VerifyType.canPassRaw(src, dst)
       
   409              ) > 0)
       
   410             return 0;  // no significant difference
       
   411         if (raw && !src.isPrimitive() && !dst.isPrimitive())
       
   412             return 0;  // can force a reference return (very carefully!)
       
   413         //if (false)  return 1;  // never adaptable!
       
   414         return -1;  // some significant difference
       
   415     }
       
   416     private static int diffParamTypes(MethodType adapterType, int astart,
       
   417                                       MethodType targetType, int tstart,
       
   418                                       int nargs, boolean raw) {
       
   419         assert(nargs >= 0);
       
   420         int res = 0;
       
   421         for (int i = 0; i < nargs; i++) {
       
   422             Class<?> src  = adapterType.parameterType(astart+i);
       
   423             Class<?> dest = targetType.parameterType(tstart+i);
       
   424             if ((!raw
       
   425                  ? VerifyType.canPassUnchecked(src, dest)
       
   426                  : VerifyType.canPassRaw(src, dest)
       
   427                 ) <= 0) {
       
   428                 // found a difference; is it the only one so far?
       
   429                 if (res != 0)
       
   430                     return -1-res; // return -2-i for prev. i
       
   431                 res = 1+i;
       
   432             }
       
   433         }
       
   434         return res;
       
   435     }
       
   436 
       
   437     /** Can a retyping adapter (alone) validly convert the target to newType? */
       
   438     public static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
       
   439         return canRetype(newType, targetType, false);
       
   440     }
       
   441     /** Can a retyping adapter (alone) convert the target to newType?
       
   442      *  It is allowed to widen subword types and void to int, to make bitwise
       
   443      *  conversions between float/int and double/long, and to perform unchecked
       
   444      *  reference conversions on return.  This last feature requires that the
       
   445      *  caller be trusted, and perform explicit cast conversions on return values.
       
   446      */
       
   447     public static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
       
   448         return canRetype(newType, targetType, true);
       
   449     }
       
   450     static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
       
   451         if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY))  return false;
       
   452         int diff = diffTypes(newType, targetType, raw);
       
   453         // %%% This assert is too strong.  Factor diff into VerifyType and reconcile.
       
   454         assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType));
       
   455         return diff == 0;
       
   456     }
       
   457 
       
   458     /** Factory method:  Performs no conversions; simply retypes the adapter.
       
   459      *  Allows unchecked argument conversions pairwise, if they are safe.
       
   460      *  Returns null if not possible.
       
   461      */
       
   462     public static MethodHandle makeRetypeOnly(Access token,
       
   463                 MethodType newType, MethodHandle target) {
       
   464         return makeRetype(token, newType, target, false);
       
   465     }
       
   466     public static MethodHandle makeRetypeRaw(Access token,
       
   467                 MethodType newType, MethodHandle target) {
       
   468         return makeRetype(token, newType, target, true);
       
   469     }
       
   470     static MethodHandle makeRetype(Access token,
       
   471                 MethodType newType, MethodHandle target, boolean raw) {
       
   472         Access.check(token);
       
   473         MethodType oldType = target.type();
       
   474         if (oldType == newType)  return target;
       
   475         if (!canRetype(newType, oldType, raw))
       
   476             return null;
       
   477         // TO DO:  clone the target guy, whatever he is, with new type.
       
   478         return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
       
   479     }
       
   480 
       
   481     static MethodHandle makeVarargsCollector(Access token,
       
   482                 MethodHandle target, Class<?> arrayType) {
       
   483         Access.check(token);
       
   484         return new AsVarargsCollector(target, arrayType);
       
   485     }
       
   486 
       
   487     static class AsVarargsCollector extends AdapterMethodHandle {
       
   488         final MethodHandle target;
       
   489         final Class<?> arrayType;
       
   490         MethodHandle cache;
       
   491 
       
   492         AsVarargsCollector(MethodHandle target, Class<?> arrayType) {
       
   493             super(target, target.type(), makeConv(OP_RETYPE_ONLY));
       
   494             this.target = target;
       
   495             this.arrayType = arrayType;
       
   496             this.cache = target.asCollector(arrayType, 0);
       
   497         }
       
   498 
       
   499         @Override
       
   500         public boolean isVarargsCollector() {
       
   501             return true;
       
   502         }
       
   503 
       
   504         @Override
       
   505         public MethodHandle asType(MethodType newType) {
       
   506             MethodType type = this.type();
       
   507             int collectArg = type.parameterCount() - 1;
       
   508             int newArity = newType.parameterCount();
       
   509             if (newArity == collectArg+1 &&
       
   510                 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
       
   511                 // if arity and trailing parameter are compatible, do normal thing
       
   512                 return super.asType(newType);
       
   513             }
       
   514             // check cache
       
   515             if (cache.type().parameterCount() == newArity)
       
   516                 return cache.asType(newType);
       
   517             // build and cache a collector
       
   518             int arrayLength = newArity - collectArg;
       
   519             MethodHandle collector;
       
   520             try {
       
   521                 collector = target.asCollector(arrayType, arrayLength);
       
   522             } catch (IllegalArgumentException ex) {
       
   523                 throw new WrongMethodTypeException("cannot build collector");
       
   524             }
       
   525             cache = collector;
       
   526             return collector.asType(newType);
       
   527         }
       
   528 
       
   529         public MethodHandle asVarargsCollector(Class<?> arrayType) {
       
   530             MethodType type = this.type();
       
   531             if (type.parameterType(type.parameterCount()-1) == arrayType)
       
   532                 return this;
       
   533             return super.asVarargsCollector(arrayType);
       
   534         }
       
   535     }
       
   536 
       
   537     /** Can a checkcast adapter validly convert the target to newType?
       
   538      *  The JVM supports all kind of reference casts, even silly ones.
       
   539      */
       
   540     public static boolean canCheckCast(MethodType newType, MethodType targetType,
       
   541                 int arg, Class<?> castType) {
       
   542         if (!convOpSupported(OP_CHECK_CAST))  return false;
       
   543         Class<?> src = newType.parameterType(arg);
       
   544         Class<?> dst = targetType.parameterType(arg);
       
   545         if (!canCheckCast(src, castType)
       
   546                 || !VerifyType.isNullConversion(castType, dst))
       
   547             return false;
       
   548         int diff = diffTypes(newType, targetType, false);
       
   549         return (diff == arg+1);  // arg is sole non-trivial diff
       
   550     }
       
   551     /** Can an primitive conversion adapter validly convert src to dst? */
       
   552     public static boolean canCheckCast(Class<?> src, Class<?> dst) {
       
   553         return (!src.isPrimitive() && !dst.isPrimitive());
       
   554     }
       
   555 
       
   556     /** Factory method:  Forces a cast at the given argument.
       
   557      *  The castType is the target of the cast, and can be any type
       
   558      *  with a null conversion to the corresponding target parameter.
       
   559      *  Return null if this cannot be done.
       
   560      */
       
   561     public static MethodHandle makeCheckCast(Access token,
       
   562                 MethodType newType, MethodHandle target,
       
   563                 int arg, Class<?> castType) {
       
   564         Access.check(token);
       
   565         if (!canCheckCast(newType, target.type(), arg, castType))
       
   566             return null;
       
   567         long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
       
   568         return new AdapterMethodHandle(target, newType, conv, castType);
       
   569     }
       
   570 
       
   571     /** Can an primitive conversion adapter validly convert the target to newType?
       
   572      *  The JVM currently supports all conversions except those between
       
   573      *  floating and integral types.
       
   574      */
       
   575     public static boolean canPrimCast(MethodType newType, MethodType targetType,
       
   576                 int arg, Class<?> convType) {
       
   577         if (!convOpSupported(OP_PRIM_TO_PRIM))  return false;
       
   578         Class<?> src = newType.parameterType(arg);
       
   579         Class<?> dst = targetType.parameterType(arg);
       
   580         if (!canPrimCast(src, convType)
       
   581                 || !VerifyType.isNullConversion(convType, dst))
       
   582             return false;
       
   583         int diff = diffTypes(newType, targetType, false);
       
   584         return (diff == arg+1);  // arg is sole non-trivial diff
       
   585     }
       
   586     /** Can an primitive conversion adapter validly convert src to dst? */
       
   587     public static boolean canPrimCast(Class<?> src, Class<?> dst) {
       
   588         if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
       
   589             return false;
       
   590         } else if (Wrapper.forPrimitiveType(dst).isFloating()) {
       
   591             // both must be floating types
       
   592             return Wrapper.forPrimitiveType(src).isFloating();
       
   593         } else {
       
   594             // both are integral, and all combinations work fine
       
   595             assert(Wrapper.forPrimitiveType(src).isIntegral() &&
       
   596                    Wrapper.forPrimitiveType(dst).isIntegral());
       
   597             return true;
       
   598         }
       
   599     }
       
   600 
       
   601     /** Factory method:  Truncate the given argument with zero or sign extension,
       
   602      *  and/or convert between single and doubleword versions of integer or float.
       
   603      *  The convType is the target of the conversion, and can be any type
       
   604      *  with a null conversion to the corresponding target parameter.
       
   605      *  Return null if this cannot be done.
       
   606      */
       
   607     public static MethodHandle makePrimCast(Access token,
       
   608                 MethodType newType, MethodHandle target,
       
   609                 int arg, Class<?> convType) {
       
   610         Access.check(token);
       
   611         MethodType oldType = target.type();
       
   612         if (!canPrimCast(newType, oldType, arg, convType))
       
   613             return null;
       
   614         Class<?> src = newType.parameterType(arg);
       
   615         long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
       
   616         return new AdapterMethodHandle(target, newType, conv);
       
   617     }
       
   618 
       
   619     /** Can an unboxing conversion validly convert src to dst?
       
   620      *  The JVM currently supports all kinds of casting and unboxing.
       
   621      *  The convType is the unboxed type; it can be either a primitive or wrapper.
       
   622      */
       
   623     public static boolean canUnboxArgument(MethodType newType, MethodType targetType,
       
   624                 int arg, Class<?> convType) {
       
   625         if (!convOpSupported(OP_REF_TO_PRIM))  return false;
       
   626         Class<?> src = newType.parameterType(arg);
       
   627         Class<?> dst = targetType.parameterType(arg);
       
   628         Class<?> boxType = Wrapper.asWrapperType(convType);
       
   629         convType = Wrapper.asPrimitiveType(convType);
       
   630         if (!canCheckCast(src, boxType)
       
   631                 || boxType == convType
       
   632                 || !VerifyType.isNullConversion(convType, dst))
       
   633             return false;
       
   634         int diff = diffTypes(newType, targetType, false);
       
   635         return (diff == arg+1);  // arg is sole non-trivial diff
       
   636     }
       
   637     /** Can an primitive unboxing adapter validly convert src to dst? */
       
   638     public static boolean canUnboxArgument(Class<?> src, Class<?> dst) {
       
   639         return (!src.isPrimitive() && Wrapper.asPrimitiveType(dst).isPrimitive());
       
   640     }
       
   641 
       
   642     /** Factory method:  Unbox the given argument.
       
   643      *  Return null if this cannot be done.
       
   644      */
       
   645     public static MethodHandle makeUnboxArgument(Access token,
       
   646                 MethodType newType, MethodHandle target,
       
   647                 int arg, Class<?> convType) {
       
   648         MethodType oldType = target.type();
       
   649         Class<?> src = newType.parameterType(arg);
       
   650         Class<?> dst = oldType.parameterType(arg);
       
   651         Class<?> boxType = Wrapper.asWrapperType(convType);
       
   652         Class<?> primType = Wrapper.asPrimitiveType(convType);
       
   653         if (!canUnboxArgument(newType, oldType, arg, convType))
       
   654             return null;
       
   655         MethodType castDone = newType;
       
   656         if (!VerifyType.isNullConversion(src, boxType))
       
   657             castDone = newType.changeParameterType(arg, boxType);
       
   658         long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
       
   659         MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
       
   660         if (castDone == newType)
       
   661             return adapter;
       
   662         return makeCheckCast(token, newType, adapter, arg, boxType);
       
   663     }
       
   664 
       
   665     /** Can an primitive boxing adapter validly convert src to dst? */
       
   666     public static boolean canBoxArgument(Class<?> src, Class<?> dst) {
       
   667         if (!convOpSupported(OP_PRIM_TO_REF))  return false;
       
   668         throw new UnsupportedOperationException("NYI");
       
   669     }
       
   670 
       
   671     /** Factory method:  Unbox the given argument.
       
   672      *  Return null if this cannot be done.
       
   673      */
       
   674     public static MethodHandle makeBoxArgument(Access token,
       
   675                 MethodType newType, MethodHandle target,
       
   676                 int arg, Class<?> convType) {
       
   677         // this is difficult to do in the JVM because it must GC
       
   678         return null;
       
   679     }
       
   680 
       
   681     /** Can an adapter simply drop arguments to convert the target to newType? */
       
   682     public static boolean canDropArguments(MethodType newType, MethodType targetType,
       
   683                 int dropArgPos, int dropArgCount) {
       
   684         if (dropArgCount == 0)
       
   685             return canRetypeOnly(newType, targetType);
       
   686         if (!convOpSupported(OP_DROP_ARGS))  return false;
       
   687         if (diffReturnTypes(newType, targetType, false) != 0)
       
   688             return false;
       
   689         int nptypes = newType.parameterCount();
       
   690         // parameter types must be the same up to the drop point
       
   691         if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0)
       
   692             return false;
       
   693         int afterPos = dropArgPos + dropArgCount;
       
   694         int afterCount = nptypes - afterPos;
       
   695         if (dropArgPos < 0 || dropArgPos >= nptypes ||
       
   696             dropArgCount < 1 || afterPos > nptypes ||
       
   697             targetType.parameterCount() != nptypes - dropArgCount)
       
   698             return false;
       
   699         // parameter types after the drop point must also be the same
       
   700         if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0)
       
   701             return false;
       
   702         return true;
       
   703     }
       
   704 
       
   705     /** Factory method:  Drop selected arguments.
       
   706      *  Allow unchecked retyping of remaining arguments, pairwise.
       
   707      *  Return null if this is not possible.
       
   708      */
       
   709     public static MethodHandle makeDropArguments(Access token,
       
   710                 MethodType newType, MethodHandle target,
       
   711                 int dropArgPos, int dropArgCount) {
       
   712         Access.check(token);
       
   713         if (dropArgCount == 0)
       
   714             return makeRetypeOnly(IMPL_TOKEN, newType, target);
       
   715         if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
       
   716             return null;
       
   717         // in  arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
       
   718         // out arglist: [0: ...keep1 |                        dpos: keep2... ]
       
   719         int keep2InPos  = dropArgPos + dropArgCount;
       
   720         int dropSlot    = newType.parameterSlotDepth(keep2InPos);
       
   721         int keep1InSlot = newType.parameterSlotDepth(dropArgPos);
       
   722         int slotCount   = keep1InSlot - dropSlot;
       
   723         assert(slotCount >= dropArgCount);
       
   724         assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount());
       
   725         long conv = makeConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount);
       
   726         return new AdapterMethodHandle(target, newType, conv);
       
   727     }
       
   728 
       
   729     /** Can an adapter duplicate an argument to convert the target to newType? */
       
   730     public static boolean canDupArguments(MethodType newType, MethodType targetType,
       
   731                 int dupArgPos, int dupArgCount) {
       
   732         if (!convOpSupported(OP_DUP_ARGS))  return false;
       
   733         if (diffReturnTypes(newType, targetType, false) != 0)
       
   734             return false;
       
   735         int nptypes = newType.parameterCount();
       
   736         if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes)
       
   737             return false;
       
   738         if (targetType.parameterCount() != nptypes + dupArgCount)
       
   739             return false;
       
   740         // parameter types must be the same up to the duplicated arguments
       
   741         if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0)
       
   742             return false;
       
   743         // duplicated types must be, well, duplicates
       
   744         if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0)
       
   745             return false;
       
   746         return true;
       
   747     }
       
   748 
       
   749     /** Factory method:  Duplicate the selected argument.
       
   750      *  Return null if this is not possible.
       
   751      */
       
   752     public static MethodHandle makeDupArguments(Access token,
       
   753                 MethodType newType, MethodHandle target,
       
   754                 int dupArgPos, int dupArgCount) {
       
   755         Access.check(token);
       
   756         if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
       
   757             return null;
       
   758         if (dupArgCount == 0)
       
   759             return target;
       
   760         // in  arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ]
       
   761         // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ]
       
   762         int keep2InPos  = dupArgPos + dupArgCount;
       
   763         int dupSlot     = newType.parameterSlotDepth(keep2InPos);
       
   764         int keep1InSlot = newType.parameterSlotDepth(dupArgPos);
       
   765         int slotCount   = keep1InSlot - dupSlot;
       
   766         assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount());
       
   767         long conv = makeConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount);
       
   768         return new AdapterMethodHandle(target, newType, conv);
       
   769     }
       
   770 
       
   771     /** Can an adapter swap two arguments to convert the target to newType? */
       
   772     public static boolean canSwapArguments(MethodType newType, MethodType targetType,
       
   773                 int swapArg1, int swapArg2) {
       
   774         if (!convOpSupported(OP_SWAP_ARGS))  return false;
       
   775         if (diffReturnTypes(newType, targetType, false) != 0)
       
   776             return false;
       
   777         if (swapArg1 >= swapArg2)  return false;  // caller resp
       
   778         int nptypes = newType.parameterCount();
       
   779         if (targetType.parameterCount() != nptypes)
       
   780             return false;
       
   781         if (swapArg1 < 0 || swapArg2 >= nptypes)
       
   782             return false;
       
   783         if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0)
       
   784             return false;
       
   785         if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0)
       
   786             return false;
       
   787         if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0)
       
   788             return false;
       
   789         if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0)
       
   790             return false;
       
   791         if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0)
       
   792             return false;
       
   793         return true;
       
   794     }
       
   795 
       
   796     /** Factory method:  Swap the selected arguments.
       
   797      *  Return null if this is not possible.
       
   798      */
       
   799     public static MethodHandle makeSwapArguments(Access token,
       
   800                 MethodType newType, MethodHandle target,
       
   801                 int swapArg1, int swapArg2) {
       
   802         Access.check(token);
       
   803         if (swapArg1 == swapArg2)
       
   804             return target;
       
   805         if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
       
   806         if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
       
   807             return null;
       
   808         Class<?> swapType = newType.parameterType(swapArg1);
       
   809         // in  arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
       
   810         // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
       
   811         int swapSlot2  = newType.parameterSlotDepth(swapArg2 + 1);
       
   812         long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2);
       
   813         return new AdapterMethodHandle(target, newType, conv);
       
   814     }
       
   815 
       
   816     static int positiveRotation(int argCount, int rotateBy) {
       
   817         assert(argCount > 0);
       
   818         if (rotateBy >= 0) {
       
   819             if (rotateBy < argCount)
       
   820                 return rotateBy;
       
   821             return rotateBy % argCount;
       
   822         } else if (rotateBy >= -argCount) {
       
   823             return rotateBy + argCount;
       
   824         } else {
       
   825             return (-1-((-1-rotateBy) % argCount)) + argCount;
       
   826         }
       
   827     }
       
   828 
       
   829     final static int MAX_ARG_ROTATION = 1;
       
   830 
       
   831     /** Can an adapter rotate arguments to convert the target to newType? */
       
   832     public static boolean canRotateArguments(MethodType newType, MethodType targetType,
       
   833                 int firstArg, int argCount, int rotateBy) {
       
   834         if (!convOpSupported(OP_ROT_ARGS))  return false;
       
   835         if (argCount <= 2)  return false;  // must be a swap, not a rotate
       
   836         rotateBy = positiveRotation(argCount, rotateBy);
       
   837         if (rotateBy == 0)  return false;  // no rotation
       
   838         if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
       
   839             return false;  // too many argument positions
       
   840         // Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
       
   841         if (diffReturnTypes(newType, targetType, false) != 0)
       
   842             return false;
       
   843         int nptypes = newType.parameterCount();
       
   844         if (targetType.parameterCount() != nptypes)
       
   845             return false;
       
   846         if (firstArg < 0 || firstArg >= nptypes)  return false;
       
   847         int argLimit = firstArg + argCount;
       
   848         if (argLimit > nptypes)  return false;
       
   849         if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0)
       
   850             return false;
       
   851         int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy;
       
   852         // swap new chunk1 with target chunk2
       
   853         if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0)
       
   854             return false;
       
   855         // swap new chunk2 with target chunk1
       
   856         if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0)
       
   857             return false;
       
   858         return true;
       
   859     }
       
   860 
       
   861     /** Factory method:  Rotate the selected argument range.
       
   862      *  Return null if this is not possible.
       
   863      */
       
   864     public static MethodHandle makeRotateArguments(Access token,
       
   865                 MethodType newType, MethodHandle target,
       
   866                 int firstArg, int argCount, int rotateBy) {
       
   867         Access.check(token);
       
   868         rotateBy = positiveRotation(argCount, rotateBy);
       
   869         if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
       
   870             return null;
       
   871         // Decide whether it should be done as a right or left rotation,
       
   872         // on the JVM stack.  Return the number of stack slots to rotate by,
       
   873         // positive if right, negative if left.
       
   874         int limit = firstArg + argCount;
       
   875         int depth0 = newType.parameterSlotDepth(firstArg);
       
   876         int depth1 = newType.parameterSlotDepth(limit-rotateBy);
       
   877         int depth2 = newType.parameterSlotDepth(limit);
       
   878         int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
       
   879         int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
       
   880         // From here on out, it assumes a single-argument shift.
       
   881         assert(MAX_ARG_ROTATION == 1);
       
   882         int srcArg, dstArg;
       
   883         byte basicType;
       
   884         if (chunk2Slots <= chunk1Slots) {
       
   885             // Rotate right/down N (rotateBy = +N, N small, c2 small):
       
   886             // in  arglist: [0: ...keep1 | arg1: c1...  | limit-N: c2 | limit: keep2... ]
       
   887             // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1...   | limit: keep2... ]
       
   888             srcArg = limit-1;
       
   889             dstArg = firstArg;
       
   890             basicType = basicType(newType.parameterType(srcArg));
       
   891             assert(chunk2Slots == type2size(basicType));
       
   892         } else {
       
   893             // Rotate left/up N (rotateBy = -N, N small, c1 small):
       
   894             // in  arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2...   | limit: keep2... ]
       
   895             // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
       
   896             srcArg = firstArg;
       
   897             dstArg = limit-1;
       
   898             basicType = basicType(newType.parameterType(srcArg));
       
   899             assert(chunk1Slots == type2size(basicType));
       
   900         }
       
   901         int dstSlot = newType.parameterSlotDepth(dstArg + 1);
       
   902         long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
       
   903         return new AdapterMethodHandle(target, newType, conv);
       
   904     }
       
   905 
       
   906     /** Can an adapter spread an argument to convert the target to newType? */
       
   907     public static boolean canSpreadArguments(MethodType newType, MethodType targetType,
       
   908                 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
       
   909         if (!convOpSupported(OP_SPREAD_ARGS))  return false;
       
   910         if (diffReturnTypes(newType, targetType, false) != 0)
       
   911             return false;
       
   912         int nptypes = newType.parameterCount();
       
   913         // parameter types must be the same up to the spread point
       
   914         if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
       
   915             return false;
       
   916         int afterPos = spreadArgPos + spreadArgCount;
       
   917         int afterCount = nptypes - (spreadArgPos + 1);
       
   918         if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
       
   919             spreadArgCount < 0 ||
       
   920             targetType.parameterCount() != afterPos + afterCount)
       
   921             return false;
       
   922         // parameter types after the spread point must also be the same
       
   923         if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
       
   924             return false;
       
   925         // match the array element type to the spread arg types
       
   926         Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos);
       
   927         if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType))
       
   928             return false;
       
   929         for (int i = 0; i < spreadArgCount; i++) {
       
   930             Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i);
       
   931             Class<?> dst = targetType.parameterType(spreadArgPos + i);
       
   932             if (src == null || !VerifyType.isNullConversion(src, dst))
       
   933                 return false;
       
   934         }
       
   935         return true;
       
   936     }
       
   937 
       
   938 
       
   939     /** Factory method:  Spread selected argument. */
       
   940     public static MethodHandle makeSpreadArguments(Access token,
       
   941                 MethodType newType, MethodHandle target,
       
   942                 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
       
   943         Access.check(token);
       
   944         MethodType targetType = target.type();
       
   945         if (!canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
       
   946             return null;
       
   947         // in  arglist: [0: ...keep1 | spos: spreadArg | spos+1:      keep2... ]
       
   948         // out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
       
   949         int keep2OutPos  = spreadArgPos + spreadArgCount;
       
   950         int spreadSlot   = targetType.parameterSlotDepth(keep2OutPos);
       
   951         int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos);
       
   952         int slotCount    = keep1OutSlot - spreadSlot;
       
   953         assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+1));
       
   954         assert(slotCount >= spreadArgCount);
       
   955         long conv = makeConv(OP_SPREAD_ARGS, spreadArgPos, slotCount-1);
       
   956         MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType);
       
   957         assert(res.type().parameterType(spreadArgPos) == spreadArgType);
       
   958         return res;
       
   959     }
       
   960 
       
   961     // TO DO: makeCollectArguments, makeFlyby, makeRicochet
       
   962 
       
   963     @Override
       
   964     public String toString() {
       
   965         return MethodHandleImpl.getNameString(IMPL_TOKEN, nonAdapter((MethodHandle)vmtarget), this);
       
   966     }
       
   967 
       
   968     private static MethodHandle nonAdapter(MethodHandle mh) {
       
   969         while (mh instanceof AdapterMethodHandle) {
       
   970             mh = (MethodHandle) mh.vmtarget;
       
   971         }
       
   972         return mh;
       
   973     }
       
   974 }