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

    1   /*
    2    * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.lang.invoke;
   27   
   28   import sun.invoke.util.VerifyType;
   29   import sun.invoke.util.Wrapper;
   30   import sun.invoke.util.ValueConversions;
   31   import java.util.Arrays;
   32   import java.util.ArrayList;
   33   import java.util.Collections;
   34   import static java.lang.invoke.MethodHandleNatives.Constants.*;
   35   import static java.lang.invoke.MethodHandleStatics.*;
   36   
   37   /**
   38    * This method handle performs simple conversion or checking of a single argument.
   39    * @author jrose
   40    */
   41   class AdapterMethodHandle extends BoundMethodHandle {
   42   
   43       //MethodHandle vmtarget;   // next AMH or BMH in chain or final DMH
   44       //Object       argument;   // parameter to the conversion if needed
   45       //int          vmargslot;  // which argument slot is affected
   46       private final int conversion;  // the type of conversion: RETYPE_ONLY, etc.
   47   
   48       // Constructors in this class *must* be package scoped or private.
   49       private AdapterMethodHandle(MethodHandle target, MethodType newType,
   50                   long conv, Object convArg) {
   51           super(newType, convArg, newType.parameterSlotDepth(1+convArgPos(conv)));
   52           this.conversion = convCode(conv);
   53           // JVM might update VM-specific bits of conversion (ignore)
   54           MethodHandleNatives.init(this, target, convArgPos(conv));
   55       }
   56       private AdapterMethodHandle(MethodHandle target, MethodType newType,
   57                   long conv) {
   58           this(target, newType, conv, null);
   59       }
   60   
   61       int getConversion() { return conversion; }
   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 fixed-arity MethodHandle.asType?
   68        */
   69       static boolean canPairwiseConvert(MethodType newType, MethodType oldType, int level) {
   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.
   76           Class<?> exp = newType.returnType();
   77           Class<?> ret = oldType.returnType();
   78           if (!VerifyType.isNullConversion(ret, exp)) {
   79               if (!convOpSupported(OP_COLLECT_ARGS))
   80                   return false;
   81               if (!canConvertArgument(ret, exp, level))
   82                   return false;
   83           }
   84   
   85           // Check args pairwise.
   86           for (int i = 0; i < len; i++) {
   87               Class<?> src = newType.parameterType(i); // source type
   88               Class<?> dst = oldType.parameterType(i); // destination type
   89               if (!canConvertArgument(src, dst, level))
   90                   return false;
   91           }
   92   
   93           return true;
   94       }
   95   
   96       /** Can a JVM-level adapter directly implement the proposed
   97        *  argument conversion, as if by fixed-arity MethodHandle.asType?
   98        */
   99       static boolean canConvertArgument(Class<?> src, Class<?> dst, int level) {
  100           // ? Retool this logic to use RETYPE_ONLY, CHECK_CAST, etc., as opcodes,
  101           // so we don't need to repeat so much decision making.
  102           if (VerifyType.isNullConversion(src, dst)) {
  103               return true;
  104           } else if (convOpSupported(OP_COLLECT_ARGS)) {
  105               // If we can build filters, we can convert anything to anything.
  106               return true;
  107           } else if (src.isPrimitive()) {
  108               if (dst.isPrimitive())
  109                   return canPrimCast(src, dst);
  110               else
  111                   return canBoxArgument(src, dst);
  112           } else {
  113               if (dst.isPrimitive())
  114                   return canUnboxArgument(src, dst, level);
  115               else
  116                   return true;  // any two refs can be interconverted
  117           }
  118       }
  119   
  120       /**
  121        * Create a JVM-level adapter method handle to conform the given method
  122        * handle to the similar newType, using only pairwise argument conversions.
  123        * For each argument, convert incoming argument to the exact type needed.
  124        * The argument conversions allowed are casting, boxing and unboxing,
  125        * integral widening or narrowing, and floating point widening or narrowing.
  126        * @param newType required call type
  127        * @param target original method handle
  128        * @param level which strength of conversion is allowed
  129        * @return an adapter to the original handle with the desired new type,
  130        *          or the original target if the types are already identical
  131        *          or null if the adaptation cannot be made
  132        */
  133       static MethodHandle makePairwiseConvert(MethodType newType, MethodHandle target, int level) {
  134           MethodType oldType = target.type();
  135           if (newType == oldType)  return target;
  136   
  137           if (!canPairwiseConvert(newType, oldType, level))
  138               return null;
  139           // (after this point, it is an assertion error to fail to convert)
  140   
  141           // Find last non-trivial conversion (if any).
  142           int lastConv = newType.parameterCount()-1;
  143           while (lastConv >= 0) {
  144               Class<?> src = newType.parameterType(lastConv); // source type
  145               Class<?> dst = oldType.parameterType(lastConv); // destination type
  146               if (isTrivialConversion(src, dst, level)) {
  147                   --lastConv;
  148               } else {
  149                   break;
  150               }
  151           }
  152   
  153           Class<?> needReturn = newType.returnType();
  154           Class<?> haveReturn = oldType.returnType();
  155           boolean retConv = !isTrivialConversion(haveReturn, needReturn, level);
  156   
  157           // Now build a chain of one or more adapters.
  158           MethodHandle adapter = target, adapter2;
  159           MethodType midType = oldType;
  160           for (int i = 0; i <= lastConv; i++) {
  161               Class<?> src = newType.parameterType(i); // source type
  162               Class<?> dst = midType.parameterType(i); // destination type
  163               if (isTrivialConversion(src, dst, level)) {
  164                   // do nothing: difference is trivial
  165                   continue;
  166               }
  167               // Work the current type backward toward the desired caller type:
  168               midType = midType.changeParameterType(i, src);
  169               if (i == lastConv) {
  170                   // When doing the last (or only) real conversion,
  171                   // force all remaining null conversions to happen also.
  172                   MethodType lastMidType = newType;
  173                   if (retConv)  lastMidType = lastMidType.changeReturnType(haveReturn);
  174                   assert(VerifyType.isNullConversion(lastMidType, midType));
  175                   midType = lastMidType;
  176               }
  177   
  178               // Tricky case analysis follows.
  179               // It parallels canConvertArgument() above.
  180               if (src.isPrimitive()) {
  181                   if (dst.isPrimitive()) {
  182                       adapter2 = makePrimCast(midType, adapter, i, dst);
  183                   } else {
  184                       adapter2 = makeBoxArgument(midType, adapter, i, src);
  185                   }
  186               } else {
  187                   if (dst.isPrimitive()) {
  188                       // Caller has boxed a primitive.  Unbox it for the target.
  189                       // The box type must correspond exactly to the primitive type.
  190                       // This is simpler than the powerful set of widening
  191                       // conversions supported by reflect.Method.invoke.
  192                       // Those conversions require a big nest of if/then/else logic,
  193                       // which we prefer to make a user responsibility.
  194                       adapter2 = makeUnboxArgument(midType, adapter, i, dst, level);
  195                   } else {
  196                       // Simple reference conversion.
  197                       // Note:  Do not check for a class hierarchy relation
  198                       // between src and dst.  In all cases a 'null' argument
  199                       // will pass the cast conversion.
  200                       adapter2 = makeCheckCast(midType, adapter, i, dst);
  201                   }
  202               }
  203               assert(adapter2 != null) : Arrays.asList(src, dst, midType, adapter, i, target, newType);
  204               assert(adapter2.type() == midType);
  205               adapter = adapter2;
  206           }
  207           if (retConv) {
  208               adapter2 = makeReturnConversion(adapter, haveReturn, needReturn);
  209               assert(adapter2 != null);
  210               adapter = adapter2;
  211           }
  212           if (adapter.type() != newType) {
  213               // Only trivial conversions remain.
  214               adapter2 = makeRetypeOnly(newType, adapter);
  215               assert(adapter2 != null);
  216               adapter = adapter2;
  217               // Actually, that's because there were no non-trivial ones:
  218               assert(lastConv == -1 || retConv);
  219           }
  220           assert(adapter.type() == newType);
  221           return adapter;
  222       }
  223   
  224       private static boolean isTrivialConversion(Class<?> src, Class<?> dst, int level) {
  225           if (src == dst || dst == void.class)  return true;
  226           if (!VerifyType.isNullConversion(src, dst))  return false;
  227           if (level > 1)  return true;  // explicitCastArguments
  228           boolean sp = src.isPrimitive();
  229           boolean dp = dst.isPrimitive();
  230           if (sp != dp)  return false;
  231           if (sp) {
  232               // in addition to being a null conversion, forbid boolean->int etc.
  233               return Wrapper.forPrimitiveType(dst)
  234                       .isConvertibleFrom(Wrapper.forPrimitiveType(src));
  235           } else {
  236               return dst.isAssignableFrom(src);
  237           }
  238       }
  239   
  240       private static MethodHandle makeReturnConversion(MethodHandle target, Class<?> haveReturn, Class<?> needReturn) {
  241           MethodHandle adjustReturn;
  242           if (haveReturn == void.class) {
  243               // synthesize a zero value for the given void
  244               Object zero = Wrapper.forBasicType(needReturn).zero();
  245               adjustReturn = MethodHandles.constant(needReturn, zero);
  246           } else {
  247               MethodType needConversion = MethodType.methodType(needReturn, haveReturn);
  248               adjustReturn = MethodHandles.identity(needReturn).asType(needConversion);
  249           }
  250           if (!canCollectArguments(adjustReturn.type(), target.type(), 0, false)) {
  251               assert(MethodHandleNatives.workaroundWithoutRicochetFrames());  // this code is deprecated
  252               throw new InternalError("NYI");
  253           }
  254           return makeCollectArguments(adjustReturn, target, 0, false);
  255       }
  256   
  257       /**
  258        * Create a JVM-level adapter method handle to permute the arguments
  259        * of the given method.
  260        * @param newType required call type
  261        * @param target original method handle
  262        * @param argumentMap for each target argument, position of its source in newType
  263        * @return an adapter to the original handle with the desired new type,
  264        *          or the original target if the types are already identical
  265        *          and the permutation is null
  266        * @throws IllegalArgumentException if the adaptation cannot be made
  267        *          directly by a JVM-level adapter, without help from Java code
  268        */
  269       static MethodHandle makePermutation(MethodType newType, MethodHandle target,
  270                   int[] argumentMap) {
  271           MethodType oldType = target.type();
  272           boolean nullPermutation = true;
  273           for (int i = 0; i < argumentMap.length; i++) {
  274               int pos = argumentMap[i];
  275               if (pos != i)
  276                   nullPermutation = false;
  277               if (pos < 0 || pos >= newType.parameterCount()) {
  278                   argumentMap = new int[0]; break;
  279               }
  280           }
  281           if (argumentMap.length != oldType.parameterCount())
  282               throw newIllegalArgumentException("bad permutation: "+Arrays.toString(argumentMap));
  283           if (nullPermutation) {
  284               MethodHandle res = makePairwiseConvert(newType, target, 0);
  285               // well, that was easy
  286               if (res == null)
  287                   throw newIllegalArgumentException("cannot convert pairwise: "+newType);
  288               return res;
  289           }
  290   
  291           // Check return type.  (Not much can be done with it.)
  292           Class<?> exp = newType.returnType();
  293           Class<?> ret = oldType.returnType();
  294           if (!VerifyType.isNullConversion(ret, exp))
  295               throw newIllegalArgumentException("bad return conversion for "+newType);
  296   
  297           // See if the argument types match up.
  298           for (int i = 0; i < argumentMap.length; i++) {
  299               int j = argumentMap[i];
  300               Class<?> src = newType.parameterType(j);
  301               Class<?> dst = oldType.parameterType(i);
  302               if (!VerifyType.isNullConversion(src, dst))
  303                   throw newIllegalArgumentException("bad argument #"+j+" conversion for "+newType);
  304           }
  305   
  306           // Now figure out a nice mix of SWAP, ROT, DUP, and DROP adapters.
  307           // A workable greedy algorithm is as follows:
  308           // Drop unused outgoing arguments (right to left: shallowest first).
  309           // Duplicate doubly-used outgoing arguments (left to right: deepest first).
  310           // Then the remaining problem is a true argument permutation.
  311           // Marshal the outgoing arguments as required from left to right.
  312           // That is, find the deepest outgoing stack position that does not yet
  313           // have the correct argument value, and correct at least that position
  314           // by swapping or rotating in the misplaced value (from a shallower place).
  315           // If the misplaced value is followed by one or more consecutive values
  316           // (also misplaced)  issue a rotation which brings as many as possible
  317           // into position.  Otherwise make progress with either a swap or a
  318           // rotation.  Prefer the swap as cheaper, but do not use it if it
  319           // breaks a slot pair.  Prefer the rotation over the swap if it would
  320           // preserve more consecutive values shallower than the target position.
  321           // When more than one rotation will work (because the required value
  322           // is already adjacent to the target position), then use a rotation
  323           // which moves the old value in the target position adjacent to
  324           // one of its consecutive values.  Also, prefer shorter rotation
  325           // spans, since they use fewer memory cycles for shuffling.
  326   
  327           throw new UnsupportedOperationException("NYI");
  328       }
  329   
  330       private static byte basicType(Class<?> type) {
  331           if (type == null)  return T_VOID;
  332           switch (Wrapper.forBasicType(type)) {
  333               case BOOLEAN:  return T_BOOLEAN;
  334               case CHAR:     return T_CHAR;
  335               case FLOAT:    return T_FLOAT;
  336               case DOUBLE:   return T_DOUBLE;
  337               case BYTE:     return T_BYTE;
  338               case SHORT:    return T_SHORT;
  339               case INT:      return T_INT;
  340               case LONG:     return T_LONG;
  341               case OBJECT:   return T_OBJECT;
  342               case VOID:     return T_VOID;
  343           }
  344           return 99; // T_ILLEGAL or some such
  345       }
  346   
  347       /** Number of stack slots for the given type.
  348        *  Two for T_DOUBLE and T_FLOAT, one for the rest.
  349        */
  350       private static int type2size(int type) {
  351           assert(type >= T_BOOLEAN && type <= T_OBJECT);
  352           return (type == T_LONG || type == T_DOUBLE) ? 2 : 1;
  353       }
  354       private static int type2size(Class<?> type) {
  355           return type2size(basicType(type));
  356       }
  357   
  358       /** The given stackMove is the number of slots pushed.
  359        * It might be negative.  Scale it (multiply) by the
  360        * VM's notion of how an address changes with a push,
  361        * to get the raw SP change for stackMove.
  362        * Then shift and mask it into the correct field.
  363        */
  364       private static long insertStackMove(int stackMove) {
  365           // following variable must be long to avoid sign extension after '<<'
  366           long spChange = stackMove * MethodHandleNatives.JVM_STACK_MOVE_UNIT;
  367           return (spChange & CONV_STACK_MOVE_MASK) << CONV_STACK_MOVE_SHIFT;
  368       }
  369   
  370       static int extractStackMove(int convOp) {
  371           int spChange = convOp >> CONV_STACK_MOVE_SHIFT;
  372           return spChange / MethodHandleNatives.JVM_STACK_MOVE_UNIT;
  373       }
  374   
  375       static int extractStackMove(MethodHandle target) {
  376           if (target instanceof AdapterMethodHandle) {
  377               AdapterMethodHandle amh = (AdapterMethodHandle) target;
  378               return extractStackMove(amh.getConversion());
  379           } else {
  380               return 0;
  381           }
  382       }
  383   
  384       /** Construct an adapter conversion descriptor for a single-argument conversion. */
  385       private static long makeConv(int convOp, int argnum, int src, int dest) {
  386           assert(src  == (src  & CONV_TYPE_MASK));
  387           assert(dest == (dest & CONV_TYPE_MASK));
  388           assert(convOp >= OP_CHECK_CAST && convOp <= OP_PRIM_TO_REF || convOp == OP_COLLECT_ARGS);
  389           int stackMove = type2size(dest) - type2size(src);
  390           return ((long) argnum << 32 |
  391                   (long) convOp << CONV_OP_SHIFT |
  392                   (int)  src    << CONV_SRC_TYPE_SHIFT |
  393                   (int)  dest   << CONV_DEST_TYPE_SHIFT |
  394                   insertStackMove(stackMove)
  395                   );
  396       }
  397       private static long makeDupConv(int convOp, int argnum, int stackMove) {
  398           // simple argument motion, requiring one slot to specify
  399           assert(convOp == OP_DUP_ARGS || convOp == OP_DROP_ARGS);
  400           byte src = 0, dest = 0;
  401           return ((long) argnum << 32 |
  402                   (long) convOp << CONV_OP_SHIFT |
  403                   (int)  src    << CONV_SRC_TYPE_SHIFT |
  404                   (int)  dest   << CONV_DEST_TYPE_SHIFT |
  405                   insertStackMove(stackMove)
  406                   );
  407       }
  408       private static long makeSwapConv(int convOp, int srcArg, byte type, int destSlot) {
  409           // more complex argument motion, requiring two slots to specify
  410           assert(convOp == OP_SWAP_ARGS || convOp == OP_ROT_ARGS);
  411           return ((long) srcArg << 32 |
  412                   (long) convOp << CONV_OP_SHIFT |
  413                   (int)  type   << CONV_SRC_TYPE_SHIFT |
  414                   (int)  type   << CONV_DEST_TYPE_SHIFT |
  415                   (int)  destSlot << CONV_VMINFO_SHIFT
  416                   );
  417       }
  418       private static long makeSpreadConv(int convOp, int argnum, int src, int dest, int stackMove) {
  419           // spreading or collecting, at a particular slot location
  420           assert(convOp == OP_SPREAD_ARGS || convOp == OP_COLLECT_ARGS || convOp == OP_FOLD_ARGS);
  421           // src  = spread ? T_OBJECT (for array)  : common type of collected args (else void)
  422           // dest = spread ? element type of array : result type of collector (can be void)
  423           return ((long) argnum << 32 |
  424                   (long) convOp << CONV_OP_SHIFT |
  425                   (int)  src    << CONV_SRC_TYPE_SHIFT |
  426                   (int)  dest   << CONV_DEST_TYPE_SHIFT |
  427                   insertStackMove(stackMove)
  428                   );
  429       }
  430       private static long makeConv(int convOp) {
  431           assert(convOp == OP_RETYPE_ONLY || convOp == OP_RETYPE_RAW);
  432           return ((long)-1 << 32) | (convOp << CONV_OP_SHIFT);   // stackMove, src, dst all zero
  433       }
  434       private static int convCode(long conv) {
  435           return (int)conv;
  436       }
  437       private static int convArgPos(long conv) {
  438           return (int)(conv >>> 32);
  439       }
  440       private static boolean convOpSupported(int convOp) {
  441           assert(convOp >= 0 && convOp <= CONV_OP_LIMIT);
  442           return ((1<<convOp) & MethodHandleNatives.CONV_OP_IMPLEMENTED_MASK) != 0;
  443       }
  444   
  445       /** One of OP_RETYPE_ONLY, etc. */
  446       int conversionOp() { return (conversion & CONV_OP_MASK) >> CONV_OP_SHIFT; }
  447   
  448       /* Return one plus the position of the first non-trivial difference
  449        * between the given types.  This is not a symmetric operation;
  450        * we are considering adapting the targetType to adapterType.
  451        * Trivial differences are those which could be ignored by the JVM
  452        * without subverting the verifier.  Otherwise, adaptable differences
  453        * are ones for which we could create an adapter to make the type change.
  454        * Return zero if there are no differences (other than trivial ones).
  455        * Return 1+N if N is the only adaptable argument difference.
  456        * Return the -2-N where N is the first of several adaptable
  457        * argument differences.
  458        * Return -1 if there there are differences which are not adaptable.
  459        */
  460       private static int diffTypes(MethodType adapterType,
  461                                    MethodType targetType,
  462                                    boolean raw) {
  463           int diff;
  464           diff = diffReturnTypes(adapterType, targetType, raw);
  465           if (diff != 0)  return diff;
  466           int nargs = adapterType.parameterCount();
  467           if (nargs != targetType.parameterCount())
  468               return -1;
  469           diff = diffParamTypes(adapterType, 0, targetType, 0, nargs, raw);
  470           //System.out.println("diff "+adapterType);
  471           //System.out.println("  "+diff+" "+targetType);
  472           return diff;
  473       }
  474       private static int diffReturnTypes(MethodType adapterType,
  475                                          MethodType targetType,
  476                                          boolean raw) {
  477           Class<?> src = targetType.returnType();
  478           Class<?> dst = adapterType.returnType();
  479           if ((!raw
  480                ? VerifyType.canPassUnchecked(src, dst)
  481                : VerifyType.canPassRaw(src, dst)
  482                ) > 0)
  483               return 0;  // no significant difference
  484           if (raw && !src.isPrimitive() && !dst.isPrimitive())
  485               return 0;  // can force a reference return (very carefully!)
  486           //if (false)  return 1;  // never adaptable!
  487           return -1;  // some significant difference
  488       }
  489       private static int diffParamTypes(MethodType adapterType, int astart,
  490                                         MethodType targetType, int tstart,
  491                                         int nargs, boolean raw) {
  492           assert(nargs >= 0);
  493           int res = 0;
  494           for (int i = 0; i < nargs; i++) {
  495               Class<?> src  = adapterType.parameterType(astart+i);
  496               Class<?> dest = targetType.parameterType(tstart+i);
  497               if ((!raw
  498                    ? VerifyType.canPassUnchecked(src, dest)
  499                    : VerifyType.canPassRaw(src, dest)
  500                   ) <= 0) {
  501                   // found a difference; is it the only one so far?
  502                   if (res != 0)
  503                       return -1-res; // return -2-i for prev. i
  504                   res = 1+i;
  505               }
  506           }
  507           return res;
  508       }
  509   
  510       /** Can a retyping adapter (alone) validly convert the target to newType? */
  511       static boolean canRetypeOnly(MethodType newType, MethodType targetType) {
  512           return canRetype(newType, targetType, false);
  513       }
  514       /** Can a retyping adapter (alone) convert the target to newType?
  515        *  It is allowed to widen subword types and void to int, to make bitwise
  516        *  conversions between float/int and double/long, and to perform unchecked
  517        *  reference conversions on return.  This last feature requires that the
  518        *  caller be trusted, and perform explicit cast conversions on return values.
  519        */
  520       static boolean canRetypeRaw(MethodType newType, MethodType targetType) {
  521           return canRetype(newType, targetType, true);
  522       }
  523       static boolean canRetype(MethodType newType, MethodType targetType, boolean raw) {
  524           if (!convOpSupported(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY))  return false;
  525           int diff = diffTypes(newType, targetType, raw);
  526           // %%% This assert is too strong.  Factor diff into VerifyType and reconcile.
  527           assert(raw || (diff == 0) == VerifyType.isNullConversion(newType, targetType));
  528           return diff == 0;
  529       }
  530   
  531       /** Factory method:  Performs no conversions; simply retypes the adapter.
  532        *  Allows unchecked argument conversions pairwise, if they are safe.
  533        *  Returns null if not possible.
  534        */
  535       static MethodHandle makeRetypeOnly(MethodType newType, MethodHandle target) {
  536           return makeRetype(newType, target, false);
  537       }
  538       static MethodHandle makeRetypeRaw(MethodType newType, MethodHandle target) {
  539           return makeRetype(newType, target, true);
  540       }
  541       static MethodHandle makeRetype(MethodType newType, MethodHandle target, boolean raw) {
  542           MethodType oldType = target.type();
  543           if (oldType == newType)  return target;
  544           if (!canRetype(newType, oldType, raw))
  545               return null;
  546           // TO DO:  clone the target guy, whatever he is, with new type.
  547           return new AdapterMethodHandle(target, newType, makeConv(raw ? OP_RETYPE_RAW : OP_RETYPE_ONLY));
  548       }
  549   
  550       static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) {
  551           MethodType type = target.type();
  552           int last = type.parameterCount() - 1;
  553           if (type.parameterType(last) != arrayType)
  554               target = target.asType(type.changeParameterType(last, arrayType));
  555           target = target.asFixedArity();  // make sure this attribute is turned off
  556           return new AsVarargsCollector(target, arrayType);
  557       }
  558   
  559       static class AsVarargsCollector extends AdapterMethodHandle {
  560           final MethodHandle target;
  561           final Class<?> arrayType;
  562           MethodHandle cache;
  563   
  564           AsVarargsCollector(MethodHandle target, Class<?> arrayType) {
  565               super(target, target.type(), makeConv(OP_RETYPE_ONLY));
  566               this.target = target;
  567               this.arrayType = arrayType;
  568               this.cache = target.asCollector(arrayType, 0);
  569           }
  570   
  571           @Override
  572           public boolean isVarargsCollector() {
  573               return true;
  574           }
  575   
  576           @Override
  577           public MethodHandle asFixedArity() {
  578               return target;
  579           }
  580   
  581           @Override
  582           public MethodHandle asType(MethodType newType) {
  583               MethodType type = this.type();
  584               int collectArg = type.parameterCount() - 1;
  585               int newArity = newType.parameterCount();
  586               if (newArity == collectArg+1 &&
  587                   type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) {
  588                   // if arity and trailing parameter are compatible, do normal thing
  589                   return super.asType(newType);
  590               }
  591               // check cache
  592               if (cache.type().parameterCount() == newArity)
  593                   return cache.asType(newType);
  594               // build and cache a collector
  595               int arrayLength = newArity - collectArg;
  596               MethodHandle collector;
  597               try {
  598                   collector = target.asCollector(arrayType, arrayLength);
  599               } catch (IllegalArgumentException ex) {
  600                   throw new WrongMethodTypeException("cannot build collector");
  601               }
  602               cache = collector;
  603               return collector.asType(newType);
  604           }
  605       }
  606   
  607       /** Can a checkcast adapter validly convert the target to newType?
  608        *  The JVM supports all kind of reference casts, even silly ones.
  609        */
  610       static boolean canCheckCast(MethodType newType, MethodType targetType,
  611                   int arg, Class<?> castType) {
  612           if (!convOpSupported(OP_CHECK_CAST))  return false;
  613           Class<?> src = newType.parameterType(arg);
  614           Class<?> dst = targetType.parameterType(arg);
  615           if (!canCheckCast(src, castType)
  616                   || !VerifyType.isNullConversion(castType, dst))
  617               return false;
  618           int diff = diffTypes(newType, targetType, false);
  619           return (diff == arg+1) || (diff == 0);  // arg is sole non-trivial diff
  620       }
  621       /** Can an primitive conversion adapter validly convert src to dst? */
  622       static boolean canCheckCast(Class<?> src, Class<?> dst) {
  623           return (!src.isPrimitive() && !dst.isPrimitive());
  624       }
  625   
  626       /** Factory method:  Forces a cast at the given argument.
  627        *  The castType is the target of the cast, and can be any type
  628        *  with a null conversion to the corresponding target parameter.
  629        *  Return null if this cannot be done.
  630        */
  631       static MethodHandle makeCheckCast(MethodType newType, MethodHandle target,
  632                   int arg, Class<?> castType) {
  633           if (!canCheckCast(newType, target.type(), arg, castType))
  634               return null;
  635           long conv = makeConv(OP_CHECK_CAST, arg, T_OBJECT, T_OBJECT);
  636           return new AdapterMethodHandle(target, newType, conv, castType);
  637       }
  638   
  639       /** Can an primitive conversion adapter validly convert the target to newType?
  640        *  The JVM currently supports all conversions except those between
  641        *  floating and integral types.
  642        */
  643       static boolean canPrimCast(MethodType newType, MethodType targetType,
  644                   int arg, Class<?> convType) {
  645           if (!convOpSupported(OP_PRIM_TO_PRIM))  return false;
  646           Class<?> src = newType.parameterType(arg);
  647           Class<?> dst = targetType.parameterType(arg);
  648           if (!canPrimCast(src, convType)
  649                   || !VerifyType.isNullConversion(convType, dst))
  650               return false;
  651           int diff = diffTypes(newType, targetType, false);
  652           return (diff == arg+1);  // arg is sole non-trivial diff
  653       }
  654       /** Can an primitive conversion adapter validly convert src to dst? */
  655       static boolean canPrimCast(Class<?> src, Class<?> dst) {
  656           if (src == dst || !src.isPrimitive() || !dst.isPrimitive()) {
  657               return false;
  658           } else {
  659               boolean sflt = Wrapper.forPrimitiveType(src).isFloating();
  660               boolean dflt = Wrapper.forPrimitiveType(dst).isFloating();
  661               return !(sflt | dflt);  // no float support at present
  662           }
  663       }
  664   
  665       /** Factory method:  Truncate the given argument with zero or sign extension,
  666        *  and/or convert between single and doubleword versions of integer or float.
  667        *  The convType is the target of the conversion, and can be any type
  668        *  with a null conversion to the corresponding target parameter.
  669        *  Return null if this cannot be done.
  670        */
  671       static MethodHandle makePrimCast(MethodType newType, MethodHandle target,
  672                   int arg, Class<?> convType) {
  673           Class<?> src = newType.parameterType(arg);
  674           if (canPrimCast(src, convType))
  675               return makePrimCastOnly(newType, target, arg, convType);
  676           Class<?> dst = convType;
  677           boolean sflt = Wrapper.forPrimitiveType(src).isFloating();
  678           boolean dflt = Wrapper.forPrimitiveType(dst).isFloating();
  679           if (sflt | dflt) {
  680               MethodHandle convMethod;
  681               if (sflt)
  682                   convMethod = ((src == double.class)
  683                           ? ValueConversions.convertFromDouble(dst)
  684                           : ValueConversions.convertFromFloat(dst));
  685               else
  686                   convMethod = ((dst == double.class)
  687                           ? ValueConversions.convertToDouble(src)
  688                           : ValueConversions.convertToFloat(src));
  689               long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
  690               return new AdapterMethodHandle(target, newType, conv, convMethod);
  691           }
  692           throw new InternalError("makePrimCast");
  693       }
  694       static MethodHandle makePrimCastOnly(MethodType newType, MethodHandle target,
  695                   int arg, Class<?> convType) {
  696           MethodType oldType = target.type();
  697           if (!canPrimCast(newType, oldType, arg, convType))
  698               return null;
  699           Class<?> src = newType.parameterType(arg);
  700           long conv = makeConv(OP_PRIM_TO_PRIM, arg, basicType(src), basicType(convType));
  701           return new AdapterMethodHandle(target, newType, conv);
  702       }
  703   
  704       /** Can an unboxing conversion validly convert src to dst?
  705        *  The JVM currently supports all kinds of casting and unboxing.
  706        *  The convType is the unboxed type; it can be either a primitive or wrapper.
  707        */
  708       static boolean canUnboxArgument(MethodType newType, MethodType targetType,
  709                   int arg, Class<?> convType, int level) {
  710           if (!convOpSupported(OP_REF_TO_PRIM))  return false;
  711           Class<?> src = newType.parameterType(arg);
  712           Class<?> dst = targetType.parameterType(arg);
  713           Class<?> boxType = Wrapper.asWrapperType(convType);
  714           convType = Wrapper.asPrimitiveType(convType);
  715           if (!canCheckCast(src, boxType)
  716                   || boxType == convType
  717                   || !VerifyType.isNullConversion(convType, dst))
  718               return false;
  719           int diff = diffTypes(newType, targetType, false);
  720           return (diff == arg+1);  // arg is sole non-trivial diff
  721       }
  722       /** Can an primitive unboxing adapter validly convert src to dst? */
  723       static boolean canUnboxArgument(Class<?> src, Class<?> dst, int level) {
  724           assert(dst.isPrimitive());
  725           // if we have JVM support for boxing, we can also do complex unboxing
  726           if (convOpSupported(OP_PRIM_TO_REF))  return true;
  727           Wrapper dw = Wrapper.forPrimitiveType(dst);
  728           // Level 0 means cast and unbox.  This works on any reference.
  729           if (level == 0)  return !src.isPrimitive();
  730           assert(level >= 0 && level <= 2);
  731           // Levels 1 and 2 allow widening and/or narrowing conversions.
  732           // These are not supported directly by the JVM.
  733           // But if the input reference is monomorphic, we can do it.
  734           return dw.wrapperType() == src;
  735       }
  736   
  737       /** Factory method:  Unbox the given argument.
  738        *  Return null if this cannot be done.
  739        */
  740       static MethodHandle makeUnboxArgument(MethodType newType, MethodHandle target,
  741                   int arg, Class<?> convType, int level) {
  742           MethodType oldType = target.type();
  743           Class<?> src = newType.parameterType(arg);
  744           Class<?> dst = oldType.parameterType(arg);
  745           Class<?> boxType = Wrapper.asWrapperType(convType);
  746           Class<?> primType = Wrapper.asPrimitiveType(convType);
  747           if (!canUnboxArgument(newType, oldType, arg, convType, level))
  748               return null;
  749           MethodType castDone = newType;
  750           if (!VerifyType.isNullConversion(src, boxType)) {
  751               // Examples:  Object->int, Number->int, Comparable->int; Byte->int, Character->int
  752               if (level != 0) {
  753                   // must include additional conversions
  754                   if (src == Object.class || !Wrapper.isWrapperType(src)) {
  755                       // src must be examined at runtime, to detect Byte, Character, etc.
  756                       MethodHandle unboxMethod = (level == 1
  757                                                   ? ValueConversions.unbox(dst)
  758                                                   : ValueConversions.unboxCast(dst));
  759                       long conv = makeConv(OP_COLLECT_ARGS, arg, basicType(src), basicType(dst));
  760                       return new AdapterMethodHandle(target, newType, conv, unboxMethod);
  761                   }
  762                   // Example: Byte->int
  763                   // Do this by reformulating the problem to Byte->byte.
  764                   Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType();
  765                   MethodType midType = newType.changeParameterType(arg, srcPrim);
  766                   MethodHandle fixPrim; // makePairwiseConvert(midType, target, 0);
  767                   if (canPrimCast(midType, oldType, arg, dst))
  768                       fixPrim = makePrimCast(midType, target, arg, dst);
  769                   else
  770                       fixPrim = target;
  771                   return makeUnboxArgument(newType, fixPrim, arg, srcPrim, 0);
  772               }
  773               castDone = newType.changeParameterType(arg, boxType);
  774           }
  775           long conv = makeConv(OP_REF_TO_PRIM, arg, T_OBJECT, basicType(primType));
  776           MethodHandle adapter = new AdapterMethodHandle(target, castDone, conv, boxType);
  777           if (castDone == newType)
  778               return adapter;
  779           return makeCheckCast(newType, adapter, arg, boxType);
  780       }
  781   
  782       /** Can a boxing conversion validly convert src to dst? */
  783       static boolean canBoxArgument(MethodType newType, MethodType targetType,
  784                   int arg, Class<?> convType) {
  785           if (!convOpSupported(OP_PRIM_TO_REF))  return false;
  786           Class<?> src = newType.parameterType(arg);
  787           Class<?> dst = targetType.parameterType(arg);
  788           Class<?> boxType = Wrapper.asWrapperType(convType);
  789           convType = Wrapper.asPrimitiveType(convType);
  790           if (!canCheckCast(boxType, dst)
  791                   || boxType == convType
  792                   || !VerifyType.isNullConversion(src, convType))
  793               return false;
  794           int diff = diffTypes(newType, targetType, false);
  795           return (diff == arg+1);  // arg is sole non-trivial diff
  796       }
  797   
  798       /** Can an primitive boxing adapter validly convert src to dst? */
  799       static boolean canBoxArgument(Class<?> src, Class<?> dst) {
  800           if (!convOpSupported(OP_PRIM_TO_REF))  return false;
  801           return (src.isPrimitive() && !dst.isPrimitive());
  802       }
  803   
  804       /** Factory method:  Box the given argument.
  805        *  Return null if this cannot be done.
  806        */
  807       static MethodHandle makeBoxArgument(MethodType newType, MethodHandle target,
  808                   int arg, Class<?> convType) {
  809           MethodType oldType = target.type();
  810           Class<?> src = newType.parameterType(arg);
  811           Class<?> dst = oldType.parameterType(arg);
  812           Class<?> boxType = Wrapper.asWrapperType(convType);
  813           Class<?> primType = Wrapper.asPrimitiveType(convType);
  814           if (!canBoxArgument(newType, oldType, arg, convType)) {
  815               return null;
  816           }
  817           if (!VerifyType.isNullConversion(boxType, dst))
  818               target = makeCheckCast(oldType.changeParameterType(arg, boxType), target, arg, dst);
  819           MethodHandle boxerMethod = ValueConversions.box(Wrapper.forPrimitiveType(primType));
  820           long conv = makeConv(OP_PRIM_TO_REF, arg, basicType(primType), T_OBJECT);
  821           return new AdapterMethodHandle(target, newType, conv, boxerMethod);
  822       }
  823   
  824       /** Can an adapter simply drop arguments to convert the target to newType? */
  825       static boolean canDropArguments(MethodType newType, MethodType targetType,
  826                   int dropArgPos, int dropArgCount) {
  827           if (dropArgCount == 0)
  828               return canRetypeOnly(newType, targetType);
  829           if (!convOpSupported(OP_DROP_ARGS))  return false;
  830           if (diffReturnTypes(newType, targetType, false) != 0)
  831               return false;
  832           int nptypes = newType.parameterCount();
  833           // parameter types must be the same up to the drop point
  834           if (dropArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, dropArgPos, false) != 0)
  835               return false;
  836           int afterPos = dropArgPos + dropArgCount;
  837           int afterCount = nptypes - afterPos;
  838           if (dropArgPos < 0 || dropArgPos >= nptypes ||
  839               dropArgCount < 1 || afterPos > nptypes ||
  840               targetType.parameterCount() != nptypes - dropArgCount)
  841               return false;
  842           // parameter types after the drop point must also be the same
  843           if (afterCount != 0 && diffParamTypes(newType, afterPos, targetType, dropArgPos, afterCount, false) != 0)
  844               return false;
  845           return true;
  846       }
  847   
  848       /** Factory method:  Drop selected arguments.
  849        *  Allow unchecked retyping of remaining arguments, pairwise.
  850        *  Return null if this is not possible.
  851        */
  852       static MethodHandle makeDropArguments(MethodType newType, MethodHandle target,
  853                   int dropArgPos, int dropArgCount) {
  854           if (dropArgCount == 0)
  855               return makeRetypeOnly(newType, target);
  856           if (!canDropArguments(newType, target.type(), dropArgPos, dropArgCount))
  857               return null;
  858           // in  arglist: [0: ...keep1 | dpos: drop... | dpos+dcount: keep2... ]
  859           // out arglist: [0: ...keep1 |                        dpos: keep2... ]
  860           int keep2InPos  = dropArgPos + dropArgCount;
  861           int dropSlot    = newType.parameterSlotDepth(keep2InPos);
  862           int keep1InSlot = newType.parameterSlotDepth(dropArgPos);
  863           int slotCount   = keep1InSlot - dropSlot;
  864           assert(slotCount >= dropArgCount);
  865           assert(target.type().parameterSlotCount() + slotCount == newType.parameterSlotCount());
  866           long conv = makeDupConv(OP_DROP_ARGS, dropArgPos + dropArgCount - 1, -slotCount);
  867           return new AdapterMethodHandle(target, newType, conv);
  868       }
  869   
  870       /** Can an adapter duplicate an argument to convert the target to newType? */
  871       static boolean canDupArguments(MethodType newType, MethodType targetType,
  872                   int dupArgPos, int dupArgCount) {
  873           if (!convOpSupported(OP_DUP_ARGS))  return false;
  874           if (diffReturnTypes(newType, targetType, false) != 0)
  875               return false;
  876           int nptypes = newType.parameterCount();
  877           if (dupArgCount < 0 || dupArgPos + dupArgCount > nptypes)
  878               return false;
  879           if (targetType.parameterCount() != nptypes + dupArgCount)
  880               return false;
  881           // parameter types must be the same up to the duplicated arguments
  882           if (diffParamTypes(newType, 0, targetType, 0, nptypes, false) != 0)
  883               return false;
  884           // duplicated types must be, well, duplicates
  885           if (diffParamTypes(newType, dupArgPos, targetType, nptypes, dupArgCount, false) != 0)
  886               return false;
  887           return true;
  888       }
  889   
  890       /** Factory method:  Duplicate the selected argument.
  891        *  Return null if this is not possible.
  892        */
  893       static MethodHandle makeDupArguments(MethodType newType, MethodHandle target,
  894                   int dupArgPos, int dupArgCount) {
  895           if (!canDupArguments(newType, target.type(), dupArgPos, dupArgCount))
  896               return null;
  897           if (dupArgCount == 0)
  898               return target;
  899           // in  arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... ]
  900           // out arglist: [0: ...keep1 | dpos: dup... | dpos+dcount: keep2... | dup... ]
  901           int keep2InPos  = dupArgPos + dupArgCount;
  902           int dupSlot     = newType.parameterSlotDepth(keep2InPos);
  903           int keep1InSlot = newType.parameterSlotDepth(dupArgPos);
  904           int slotCount   = keep1InSlot - dupSlot;
  905           assert(target.type().parameterSlotCount() - slotCount == newType.parameterSlotCount());
  906           long conv = makeDupConv(OP_DUP_ARGS, dupArgPos + dupArgCount - 1, slotCount);
  907           return new AdapterMethodHandle(target, newType, conv);
  908       }
  909   
  910       /** Can an adapter swap two arguments to convert the target to newType? */
  911       static boolean canSwapArguments(MethodType newType, MethodType targetType,
  912                   int swapArg1, int swapArg2) {
  913           if (!convOpSupported(OP_SWAP_ARGS))  return false;
  914           if (diffReturnTypes(newType, targetType, false) != 0)
  915               return false;
  916           if (swapArg1 >= swapArg2)  return false;  // caller resp
  917           int nptypes = newType.parameterCount();
  918           if (targetType.parameterCount() != nptypes)
  919               return false;
  920           if (swapArg1 < 0 || swapArg2 >= nptypes)
  921               return false;
  922           if (diffParamTypes(newType, 0, targetType, 0, swapArg1, false) != 0)
  923               return false;
  924           if (diffParamTypes(newType, swapArg1, targetType, swapArg2, 1, false) != 0)
  925               return false;
  926           if (diffParamTypes(newType, swapArg1+1, targetType, swapArg1+1, swapArg2-swapArg1-1, false) != 0)
  927               return false;
  928           if (diffParamTypes(newType, swapArg2, targetType, swapArg1, 1, false) != 0)
  929               return false;
  930           if (diffParamTypes(newType, swapArg2+1, targetType, swapArg2+1, nptypes-swapArg2-1, false) != 0)
  931               return false;
  932           return true;
  933       }
  934   
  935       /** Factory method:  Swap the selected arguments.
  936        *  Return null if this is not possible.
  937        */
  938       static MethodHandle makeSwapArguments(MethodType newType, MethodHandle target,
  939                   int swapArg1, int swapArg2) {
  940           if (swapArg1 == swapArg2)
  941               return target;
  942           if (swapArg1 > swapArg2) { int t = swapArg1; swapArg1 = swapArg2; swapArg2 = t; }
  943           if (type2size(newType.parameterType(swapArg1)) !=
  944               type2size(newType.parameterType(swapArg2))) {
  945               // turn a swap into a pair of rotates:
  946               // [x a b c y] => [a b c y x] => [y a b c x]
  947               int argc = swapArg2 - swapArg1 + 1;
  948               final int ROT = 1;
  949               ArrayList<Class<?>> rot1Params = new ArrayList<Class<?>>(target.type().parameterList());
  950               Collections.rotate(rot1Params.subList(swapArg1, swapArg1 + argc), -ROT);
  951               MethodType rot1Type = MethodType.methodType(target.type().returnType(), rot1Params);
  952               MethodHandle rot1 = makeRotateArguments(rot1Type, target, swapArg1, argc, +ROT);
  953               if (argc == 2)  return rot1;
  954               MethodHandle rot2 = makeRotateArguments(newType, rot1, swapArg1, argc-1, -ROT);
  955               return rot2;
  956           }
  957           if (!canSwapArguments(newType, target.type(), swapArg1, swapArg2))
  958               return null;
  959           Class<?> swapType = newType.parameterType(swapArg1);
  960           // in  arglist: [0: ...keep1 | pos1: a1 | pos1+1: keep2... | pos2: a2 | pos2+1: keep3... ]
  961           // out arglist: [0: ...keep1 | pos1: a2 | pos1+1: keep2... | pos2: a1 | pos2+1: keep3... ]
  962           int swapSlot2  = newType.parameterSlotDepth(swapArg2 + 1);
  963           long conv = makeSwapConv(OP_SWAP_ARGS, swapArg1, basicType(swapType), swapSlot2);
  964           return new AdapterMethodHandle(target, newType, conv);
  965       }
  966   
  967       static int positiveRotation(int argCount, int rotateBy) {
  968           assert(argCount > 0);
  969           if (rotateBy >= 0) {
  970               if (rotateBy < argCount)
  971                   return rotateBy;
  972               return rotateBy % argCount;
  973           } else if (rotateBy >= -argCount) {
  974               return rotateBy + argCount;
  975           } else {
  976               return (-1-((-1-rotateBy) % argCount)) + argCount;
  977           }
  978       }
  979   
  980       final static int MAX_ARG_ROTATION = 1;
  981   
  982       /** Can an adapter rotate arguments to convert the target to newType? */
  983       static boolean canRotateArguments(MethodType newType, MethodType targetType,
  984                   int firstArg, int argCount, int rotateBy) {
  985           if (!convOpSupported(OP_ROT_ARGS))  return false;
  986           rotateBy = positiveRotation(argCount, rotateBy);
  987           if (rotateBy == 0)  return false;  // no rotation
  988           if (rotateBy > MAX_ARG_ROTATION && rotateBy < argCount - MAX_ARG_ROTATION)
  989               return false;  // too many argument positions
  990           // Rotate incoming args right N to the out args, N in 1..(argCouunt-1).
  991           if (diffReturnTypes(newType, targetType, false) != 0)
  992               return false;
  993           int nptypes = newType.parameterCount();
  994           if (targetType.parameterCount() != nptypes)
  995               return false;
  996           if (firstArg < 0 || firstArg >= nptypes)  return false;
  997           int argLimit = firstArg + argCount;
  998           if (argLimit > nptypes)  return false;
  999           if (diffParamTypes(newType, 0, targetType, 0, firstArg, false) != 0)
 1000               return false;
 1001           int newChunk1 = argCount - rotateBy, newChunk2 = rotateBy;
 1002           // swap new chunk1 with target chunk2
 1003           if (diffParamTypes(newType, firstArg, targetType, argLimit-newChunk1, newChunk1, false) != 0)
 1004               return false;
 1005           // swap new chunk2 with target chunk1
 1006           if (diffParamTypes(newType, firstArg+newChunk1, targetType, firstArg, newChunk2, false) != 0)
 1007               return false;
 1008           return true;
 1009       }
 1010   
 1011       /** Factory method:  Rotate the selected argument range.
 1012        *  Return null if this is not possible.
 1013        */
 1014       static MethodHandle makeRotateArguments(MethodType newType, MethodHandle target,
 1015                   int firstArg, int argCount, int rotateBy) {
 1016           rotateBy = positiveRotation(argCount, rotateBy);
 1017           if (!canRotateArguments(newType, target.type(), firstArg, argCount, rotateBy))
 1018               return null;
 1019           // Decide whether it should be done as a right or left rotation,
 1020           // on the JVM stack.  Return the number of stack slots to rotate by,
 1021           // positive if right, negative if left.
 1022           int limit = firstArg + argCount;
 1023           int depth0 = newType.parameterSlotDepth(firstArg);
 1024           int depth1 = newType.parameterSlotDepth(limit-rotateBy);
 1025           int depth2 = newType.parameterSlotDepth(limit);
 1026           int chunk1Slots = depth0 - depth1; assert(chunk1Slots > 0);
 1027           int chunk2Slots = depth1 - depth2; assert(chunk2Slots > 0);
 1028           // From here on out, it assumes a single-argument shift.
 1029           assert(MAX_ARG_ROTATION == 1);
 1030           int srcArg, dstArg;
 1031           int dstSlot;
 1032           byte basicType;
 1033           if (chunk2Slots <= chunk1Slots) {
 1034               // Rotate right/down N (rotateBy = +N, N small, c2 small):
 1035               // in  arglist: [0: ...keep1 | arg1: c1...  | limit-N: c2 | limit: keep2... ]
 1036               // out arglist: [0: ...keep1 | arg1: c2 | arg1+N: c1...   | limit: keep2... ]
 1037               srcArg = limit-1;
 1038               dstArg = firstArg;
 1039               dstSlot = depth0 - chunk2Slots;
 1040               basicType = basicType(newType.parameterType(srcArg));
 1041               assert(chunk2Slots == type2size(basicType));
 1042           } else {
 1043               // Rotate left/up N (rotateBy = -N, N small, c1 small):
 1044               // in  arglist: [0: ...keep1 | arg1: c1 | arg1+N: c2...   | limit: keep2... ]
 1045               // out arglist: [0: ...keep1 | arg1: c2 ... | limit-N: c1 | limit: keep2... ]
 1046               srcArg = firstArg;
 1047               dstArg = limit-1;
 1048               dstSlot = depth2;
 1049               basicType = basicType(newType.parameterType(srcArg));
 1050               assert(chunk1Slots == type2size(basicType));
 1051           }
 1052           long conv = makeSwapConv(OP_ROT_ARGS, srcArg, basicType, dstSlot);
 1053           return new AdapterMethodHandle(target, newType, conv);
 1054       }
 1055   
 1056       /** Can an adapter spread an argument to convert the target to newType? */
 1057       static boolean canSpreadArguments(MethodType newType, MethodType targetType,
 1058                   Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
 1059           if (!convOpSupported(OP_SPREAD_ARGS))  return false;
 1060           if (diffReturnTypes(newType, targetType, false) != 0)
 1061               return false;
 1062           int nptypes = newType.parameterCount();
 1063           // parameter types must be the same up to the spread point
 1064           if (spreadArgPos != 0 && diffParamTypes(newType, 0, targetType, 0, spreadArgPos, false) != 0)
 1065               return false;
 1066           int afterPos = spreadArgPos + spreadArgCount;
 1067           int afterCount = nptypes - (spreadArgPos + 1);
 1068           if (spreadArgPos < 0 || spreadArgPos >= nptypes ||
 1069               spreadArgCount < 0 ||
 1070               targetType.parameterCount() != afterPos + afterCount)
 1071               return false;
 1072           // parameter types after the spread point must also be the same
 1073           if (afterCount != 0 && diffParamTypes(newType, spreadArgPos+1, targetType, afterPos, afterCount, false) != 0)
 1074               return false;
 1075           // match the array element type to the spread arg types
 1076           Class<?> rawSpreadArgType = newType.parameterType(spreadArgPos);
 1077           if (rawSpreadArgType != spreadArgType && !canCheckCast(rawSpreadArgType, spreadArgType))
 1078               return false;
 1079           for (int i = 0; i < spreadArgCount; i++) {
 1080               Class<?> src = VerifyType.spreadArgElementType(spreadArgType, i);
 1081               Class<?> dst = targetType.parameterType(spreadArgPos + i);
 1082               if (src == null || !canConvertArgument(src, dst, 1))
 1083                   return false;
 1084           }
 1085           return true;
 1086       }
 1087   
 1088   
 1089       /** Factory method:  Spread selected argument. */
 1090       static MethodHandle makeSpreadArguments(MethodType newType, MethodHandle target,
 1091                   Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) {
 1092           // FIXME: Get rid of newType; derive new arguments from structure of spreadArgType
 1093           MethodType targetType = target.type();
 1094           assert(canSpreadArguments(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount))
 1095               : "[newType, targetType, spreadArgType, spreadArgPos, spreadArgCount] = "
 1096                 + Arrays.asList(newType, targetType, spreadArgType, spreadArgPos, spreadArgCount);
 1097           // dest is not significant; remove?
 1098           int dest = T_VOID;
 1099           for (int i = 0; i < spreadArgCount; i++) {
 1100               Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
 1101               if (arg == null)  arg = Object.class;
 1102               int dest2 = basicType(arg);
 1103               if      (dest == T_VOID)  dest = dest2;
 1104               else if (dest != dest2)   dest = T_VOID;
 1105               if (dest == T_VOID)  break;
 1106               targetType = targetType.changeParameterType(spreadArgPos + i, arg);
 1107           }
 1108           target = target.asType(targetType);
 1109           int arrayArgSize = 1;  // always a reference
 1110           // in  arglist: [0: ...keep1 | spos: spreadArg | spos+1:      keep2... ]
 1111           // out arglist: [0: ...keep1 | spos: spread... | spos+scount: keep2... ]
 1112           int keep2OutPos  = spreadArgPos + spreadArgCount;
 1113           int keep1OutSlot = targetType.parameterSlotDepth(spreadArgPos);   // leading edge of |spread...|
 1114           int spreadSlot   = targetType.parameterSlotDepth(keep2OutPos);    // trailing edge of |spread...|
 1115           assert(spreadSlot == newType.parameterSlotDepth(spreadArgPos+arrayArgSize));
 1116           int slotCount    = keep1OutSlot - spreadSlot;                     // slots in |spread...|
 1117           assert(slotCount >= spreadArgCount);
 1118           int stackMove = - arrayArgSize + slotCount;  // pop array, push N slots
 1119           long conv = makeSpreadConv(OP_SPREAD_ARGS, spreadArgPos, T_OBJECT, dest, stackMove);
 1120           MethodHandle res = new AdapterMethodHandle(target, newType, conv, spreadArgType);
 1121           assert(res.type().parameterType(spreadArgPos) == spreadArgType);
 1122           return res;
 1123       }
 1124   
 1125       /** Can an adapter collect a series of arguments, replacing them by zero or one results? */
 1126       static boolean canCollectArguments(MethodType targetType,
 1127                   MethodType collectorType, int collectArgPos, boolean retainOriginalArgs) {
 1128           if (!convOpSupported(retainOriginalArgs ? OP_FOLD_ARGS : OP_COLLECT_ARGS))  return false;
 1129           int collectArgCount = collectorType.parameterCount();
 1130           Class<?> rtype = collectorType.returnType();
 1131           assert(rtype == void.class || targetType.parameterType(collectArgPos) == rtype)
 1132                   // [(Object)Object[], (Object[])Object[], 0, 1]
 1133                   : Arrays.asList(targetType, collectorType, collectArgPos, collectArgCount)
 1134                   ;
 1135           return true;
 1136       }
 1137   
 1138       /** Factory method:  Collect or filter selected argument(s). */
 1139       static MethodHandle makeCollectArguments(MethodHandle target,
 1140                   MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
 1141           assert(canCollectArguments(target.type(), collector.type(), collectArgPos, retainOriginalArgs));
 1142           MethodType targetType = target.type();
 1143           MethodType collectorType = collector.type();
 1144           int collectArgCount = collectorType.parameterCount();
 1145           Class<?> collectValType = collectorType.returnType();
 1146           int collectValCount = (collectValType == void.class ? 0 : 1);
 1147           int collectValSlots = collectorType.returnSlotCount();
 1148           MethodType newType = targetType
 1149                   .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
 1150           if (!retainOriginalArgs) {
 1151               newType = newType
 1152                   .insertParameterTypes(collectArgPos, collectorType.parameterList());
 1153           } else {
 1154               // parameter types at the fold point must be the same
 1155               assert(diffParamTypes(newType, collectArgPos, targetType, collectValCount, collectArgCount, false) == 0)
 1156                   : Arrays.asList(target, collector, collectArgPos, retainOriginalArgs);
 1157           }
 1158           // in  arglist: [0: ...keep1 | cpos: collect...  | cpos+cacount: keep2... ]
 1159           // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
 1160           // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
 1161           int keep2InPos   = collectArgPos + collectArgCount;
 1162           int keep1InSlot  = newType.parameterSlotDepth(collectArgPos);  // leading edge of |collect...|
 1163           int collectSlot  = newType.parameterSlotDepth(keep2InPos);     // trailing edge of |collect...|
 1164           int slotCount    = keep1InSlot - collectSlot;                  // slots in |collect...|
 1165           assert(slotCount >= collectArgCount);
 1166           assert(collectSlot == targetType.parameterSlotDepth(
 1167                   collectArgPos + collectValCount + (retainOriginalArgs ? collectArgCount : 0) ));
 1168           int dest = basicType(collectValType);
 1169           int src = T_VOID;
 1170           // src is not significant; remove?
 1171           for (int i = 0; i < collectArgCount; i++) {
 1172               int src2 = basicType(collectorType.parameterType(i));
 1173               if      (src == T_VOID)  src = src2;
 1174               else if (src != src2)    src = T_VOID;
 1175               if (src == T_VOID)  break;
 1176           }
 1177           int stackMove = collectValSlots;  // push 0..2 results
 1178           if (!retainOriginalArgs)  stackMove -= slotCount; // pop N arguments
 1179           int lastCollectArg = keep2InPos-1;
 1180           long conv = makeSpreadConv(retainOriginalArgs ? OP_FOLD_ARGS : OP_COLLECT_ARGS,
 1181                                      lastCollectArg, src, dest, stackMove);
 1182           MethodHandle res = new AdapterMethodHandle(target, newType, conv, collector);
 1183           assert(res.type().parameterList().subList(collectArgPos, collectArgPos+collectArgCount)
 1184                   .equals(collector.type().parameterList()));
 1185           return res;
 1186       }
 1187   
 1188       @Override
 1189       String debugString() {
 1190           return getNameString(nonAdapter((MethodHandle)vmtarget), this);
 1191       }
 1192   
 1193       private static MethodHandle nonAdapter(MethodHandle mh) {
 1194           while (mh instanceof AdapterMethodHandle) {
 1195               mh = (MethodHandle) mh.vmtarget;
 1196           }
 1197           return mh;
 1198       }
 1199   }

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