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