Home | History | Annotate | Download | only in invoke
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * This code is free software; you can redistribute it and/or modify it
      5  * under the terms of the GNU General Public License version 2 only, as
      6  * published by the Free Software Foundation.  Google designates this
      7  * particular file as subject to the "Classpath" exception as provided
      8  * by Google in the LICENSE file that accompanied this code.
      9  *
     10  * This code is distributed in the hope that it will be useful, but WITHOUT
     11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     13  * version 2 for more details (a copy is included in the LICENSE file that
     14  * accompanied this code).
     15  *
     16  * You should have received a copy of the GNU General Public License version
     17  * 2 along with this work; if not, write to the Free Software Foundation,
     18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     19  */
     20 
     21 package java.lang.invoke;
     22 
     23 import dalvik.system.EmulatedStackFrame;
     24 import dalvik.system.EmulatedStackFrame.Range;
     25 import dalvik.system.EmulatedStackFrame.StackFrameAccessor;
     26 import dalvik.system.EmulatedStackFrame.StackFrameReader;
     27 import dalvik.system.EmulatedStackFrame.StackFrameWriter;
     28 import java.lang.reflect.Array;
     29 import java.lang.reflect.Method;
     30 import java.lang.reflect.Modifier;
     31 import sun.invoke.util.Wrapper;
     32 import sun.misc.Unsafe;
     33 import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext;
     34 
     35 /**
     36  * @hide Public for testing only.
     37  */
     38 public class Transformers {
     39     private Transformers() {}
     40 
     41     static {
     42         try {
     43             TRANSFORM_INTERNAL = MethodHandle.class.getDeclaredMethod("transformInternal",
     44                     EmulatedStackFrame.class);
     45         } catch (NoSuchMethodException nsme) {
     46             throw new AssertionError();
     47         }
     48     }
     49 
     50     /**
     51      * Method reference to the private {@code MethodHandle.transformInternal} method. This is
     52      * cached here because it's the point of entry for all transformers.
     53      */
     54     private static final Method TRANSFORM_INTERNAL;
     55 
     56     /** @hide */
     57     public static abstract class Transformer extends MethodHandle implements Cloneable {
     58         protected Transformer(MethodType type) {
     59             super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type);
     60         }
     61 
     62         protected Transformer(MethodType type, int invokeKind) {
     63             super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type);
     64         }
     65 
     66         @Override
     67         public Object clone() throws CloneNotSupportedException {
     68             return super.clone();
     69         }
     70     }
     71 
     72     /**
     73      * A method handle that always throws an exception of a specified type.
     74      *
     75      * The handle declares a nominal return type, which is immaterial to the execution
     76      * of the handle because it never returns.
     77      *
     78      * @hide
     79      */
     80     public static class AlwaysThrow extends Transformer {
     81         private final Class<? extends Throwable> exceptionType;
     82 
     83         public AlwaysThrow(Class<?> nominalReturnType, Class<? extends  Throwable> exType) {
     84             super(MethodType.methodType(nominalReturnType, exType));
     85             this.exceptionType = exType;
     86         }
     87 
     88         @Override
     89         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
     90             throw emulatedStackFrame.getReference(0, exceptionType);
     91         }
     92     }
     93 
     94     /**
     95      * Implements {@code MethodHandles.dropArguments}.
     96      */
     97     public static class DropArguments extends Transformer {
     98         private final MethodHandle delegate;
     99 
    100         private final EmulatedStackFrame.Range range1;
    101 
    102         /**
    103          * Note that {@code range2} will be null if the arguments that are being dropped
    104          * are the last {@code n}.
    105          */
    106         /* @Nullable */ private final EmulatedStackFrame.Range range2;
    107 
    108         public DropArguments(MethodType type, MethodHandle delegate,
    109                              int startPos, int numDropped) {
    110             super(type);
    111 
    112             this.delegate = delegate;
    113 
    114             // We pre-calculate the ranges of values we have to copy through to the delegate
    115             // handle at the time of instantiation so that the actual invoke is performant.
    116             this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos);
    117             final int numArgs = type.ptypes().length;
    118             if (startPos + numDropped < numArgs) {
    119                 this.range2 = EmulatedStackFrame.Range.of(type, startPos + numDropped, numArgs);
    120             } else {
    121                 this.range2 = null;
    122             }
    123         }
    124 
    125         @Override
    126         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    127             EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type());
    128 
    129             emulatedStackFrame.copyRangeTo(calleeFrame, range1,
    130                     0 /* referencesStart */, 0 /* stackFrameStart */);
    131 
    132             if (range2 != null) {
    133                 final int referencesStart = range1.numReferences;
    134                 final int stackFrameStart = range1.numBytes;
    135 
    136                 emulatedStackFrame.copyRangeTo(calleeFrame, range2,
    137                         referencesStart, stackFrameStart);
    138             }
    139 
    140             delegate.invoke(calleeFrame);
    141             calleeFrame.copyReturnValueTo(emulatedStackFrame);
    142         }
    143     }
    144 
    145     /**
    146      * Implements {@code MethodHandles.catchException}.
    147      */
    148     public static class CatchException extends Transformer {
    149         private final MethodHandle target;
    150         private final MethodHandle handler;
    151         private final Class<?> exType;
    152 
    153         private final EmulatedStackFrame.Range handlerArgsRange;
    154 
    155         public CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) {
    156             super(target.type());
    157 
    158             this.target = target;
    159             this.handler = handler;
    160             this.exType = exType;
    161 
    162             // We only copy the first "count" args, dropping others if required. Note that
    163             // we subtract one because the first handler arg is the exception thrown by the
    164             // target.
    165             handlerArgsRange = EmulatedStackFrame.Range.of(target.type(), 0,
    166                     (handler.type().parameterCount() - 1));
    167         }
    168 
    169         @Override
    170         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    171             try {
    172                 target.invoke(emulatedStackFrame);
    173             } catch (Throwable th) {
    174                 if (th.getClass() == exType) {
    175                     // We've gotten an exception of the appropriate type, so we need to call
    176                     // the handler. Create a new frame of the appropriate size.
    177                     EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type());
    178 
    179                     // The first argument to the handler is the actual exception.
    180                     fallback.setReference(0, th);
    181 
    182                     // We then copy other arguments that need to be passed through to the handler.
    183                     // Note that we might drop arguments at the end, if needed. Note that
    184                     // referencesStart == 1 because the first argument is the exception type.
    185                     emulatedStackFrame.copyRangeTo(fallback, handlerArgsRange,
    186                             1 /* referencesStart */, 0 /* stackFrameStart */);
    187 
    188                     // Perform the invoke and return the appropriate value.
    189                     handler.invoke(fallback);
    190                     fallback.copyReturnValueTo(emulatedStackFrame);
    191                 } else {
    192                     // The exception is not of the expected type, we throw it.
    193                     throw th;
    194                 }
    195             }
    196         }
    197     }
    198 
    199     /**
    200      * Implements {@code MethodHandles.GuardWithTest}.
    201      */
    202     public static class GuardWithTest extends Transformer {
    203         private final MethodHandle test;
    204         private final MethodHandle target;
    205         private final MethodHandle fallback;
    206 
    207         private final EmulatedStackFrame.Range testArgsRange;
    208 
    209         public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
    210             super(target.type());
    211 
    212             this.test = test;
    213             this.target = target;
    214             this.fallback = fallback;
    215 
    216             // The test method might have a subset of the arguments of the handle / target.
    217             testArgsRange = EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount());
    218         }
    219 
    220         @Override
    221         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    222             EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type());
    223             emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0);
    224 
    225             // We know that the return value for test is going to be boolean.class, so we don't have
    226             // to do the copyReturnValue dance.
    227             final boolean value = (boolean) test.invoke(testFrame);
    228             if (value) {
    229                 target.invoke(emulatedStackFrame);
    230             } else {
    231                 fallback.invoke(emulatedStackFrame);
    232             }
    233         }
    234     }
    235 
    236     /**
    237      * Implementation of MethodHandles.arrayElementGetter for reference types.
    238      */
    239     public static class ReferenceArrayElementGetter extends Transformer {
    240         private final Class<?> arrayClass;
    241 
    242         public ReferenceArrayElementGetter(Class<?> arrayClass) {
    243             super(MethodType.methodType(arrayClass.getComponentType(),
    244                     new Class<?>[]{arrayClass, int.class}));
    245             this.arrayClass = arrayClass;
    246         }
    247 
    248         @Override
    249         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    250             final StackFrameReader reader = new StackFrameReader();
    251             reader.attach(emulatedStackFrame);
    252 
    253             // Read the array object and the index from the stack frame.
    254             final Object[] array = (Object[]) reader.nextReference(arrayClass);
    255             final int index = reader.nextInt();
    256 
    257             // Write the array element back to the stack frame.
    258             final StackFrameWriter writer = new StackFrameWriter();
    259             writer.attach(emulatedStackFrame);
    260             writer.makeReturnValueAccessor();
    261             writer.putNextReference(array[index], arrayClass.getComponentType());
    262         }
    263     }
    264 
    265     /**
    266      * Implementation of MethodHandles.arrayElementSetter for reference types.
    267      */
    268     public static class ReferenceArrayElementSetter extends Transformer {
    269         private final Class<?> arrayClass;
    270 
    271         public ReferenceArrayElementSetter(Class<?> arrayClass) {
    272             super(MethodType.methodType(void.class,
    273                     new Class<?>[] { arrayClass, int.class, arrayClass.getComponentType() }));
    274             this.arrayClass = arrayClass;
    275         }
    276 
    277         @Override
    278         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    279             final StackFrameReader reader = new StackFrameReader();
    280             reader.attach(emulatedStackFrame);
    281 
    282             // Read the array object, index and the value to write from the stack frame.
    283             final Object[] array = (Object[]) reader.nextReference(arrayClass);
    284             final int index = reader.nextInt();
    285             final Object value = reader.nextReference(arrayClass.getComponentType());
    286 
    287             array[index] = value;
    288         }
    289     }
    290 
    291     /**
    292      * Implementation of MethodHandles.identity() for reference types.
    293      */
    294     public static class ReferenceIdentity extends Transformer {
    295         private final Class<?> type;
    296 
    297         public ReferenceIdentity(Class<?> type) {
    298             super(MethodType.methodType(type, type));
    299             this.type = type;
    300         }
    301 
    302         @Override
    303         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    304             final StackFrameReader reader = new StackFrameReader();
    305             reader.attach(emulatedStackFrame);
    306 
    307             final StackFrameWriter writer = new StackFrameWriter();
    308             writer.attach(emulatedStackFrame);
    309             writer.makeReturnValueAccessor();
    310             writer.putNextReference(reader.nextReference(type), type);
    311         }
    312     }
    313 
    314     /**
    315      * Implementation of MethodHandles.constant.
    316      */
    317     public static class Constant extends Transformer {
    318         private final Class<?> type;
    319 
    320         // NOTE: This implementation turned out to be more awkward than expected becuase
    321         // of the type system. We could simplify this considerably at the cost of making
    322         // the emulated stack frame API uglier or by transitioning into JNI.
    323         //
    324         // We could consider implementing this in terms of bind() once that's implemented.
    325         // This would then just become : MethodHandles.identity(type).bind(value).
    326         private int asInt;
    327         private long asLong;
    328         private float asFloat;
    329         private double asDouble;
    330         private Object asReference;
    331 
    332         private char typeChar;
    333 
    334         public Constant(Class<?> type, Object value) {
    335             super(MethodType.methodType(type));
    336             this.type = type;
    337 
    338             if (!type.isPrimitive()) {
    339                 asReference = value;
    340                 typeChar = 'L';
    341             } else if (type == int.class) {
    342                 asInt = (int) value;
    343                 typeChar = 'I';
    344             } else if (type == char.class) {
    345                 asInt = (int) (char) value;
    346                 typeChar = 'C';
    347             } else if (type == short.class) {
    348                 asInt = (int) (short) value;
    349                 typeChar = 'S';
    350             } else if (type == byte.class) {
    351                 asInt = (int) (byte) value;
    352                 typeChar = 'B';
    353             } else if (type == boolean.class) {
    354                 asInt = ((boolean) value) ? 1 : 0;
    355                 typeChar = 'Z';
    356             } else if (type == long.class) {
    357                 asLong = (long) value;
    358                 typeChar = 'J';
    359             } else if (type == float.class) {
    360                 asFloat = (float) value;
    361                 typeChar = 'F';
    362             } else if (type == double.class) {
    363                 asDouble = (double) value;
    364                 typeChar = 'D';
    365             } else {
    366                 throw new AssertionError("unknown type: " + typeChar);
    367             }
    368         }
    369 
    370         @Override
    371         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    372             final StackFrameWriter writer = new StackFrameWriter();
    373             writer.attach(emulatedStackFrame);
    374             writer.makeReturnValueAccessor();
    375 
    376             switch (typeChar) {
    377                 case 'L' : { writer.putNextReference(asReference, type); break; }
    378                 case 'I' : { writer.putNextInt(asInt); break; }
    379                 case 'C' : { writer.putNextChar((char) asInt); break; }
    380                 case 'S' : { writer.putNextShort((short) asInt); break; }
    381                 case 'B' : { writer.putNextByte((byte) asInt); break; }
    382                 case 'Z' : { writer.putNextBoolean(asInt == 1); break; }
    383                 case 'J' : { writer.putNextLong(asLong); break; }
    384                 case 'F' : { writer.putNextFloat(asFloat); break; }
    385                 case 'D' : { writer.putNextDouble(asDouble); break; }
    386                 default:
    387                     throw new AssertionError("Unexpected typeChar: " + typeChar);
    388             }
    389         }
    390     }
    391 
    392     /*package*/ static class Construct extends Transformer {
    393         private final MethodHandle constructorHandle;
    394         private final EmulatedStackFrame.Range callerRange;
    395 
    396         /*package*/ Construct(MethodHandle constructorHandle, MethodType returnedType) {
    397             super(returnedType);
    398             this.constructorHandle = constructorHandle;
    399             this.callerRange = EmulatedStackFrame.Range.all(type());
    400         }
    401 
    402         MethodHandle getConstructorHandle() {
    403             return constructorHandle;
    404         }
    405 
    406         private static boolean isAbstract(Class<?> klass) {
    407             return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
    408         }
    409 
    410         private static void checkInstantiable(Class<?> klass) throws InstantiationException {
    411             if (isAbstract(klass)) {
    412                 String s = klass.isInterface() ? "interface " : "abstract class ";
    413                 throw new InstantiationException("Can't instantiate " + s + klass);
    414             }
    415         }
    416 
    417         @Override
    418         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    419             final Class<?> receiverType = type().rtype();
    420             checkInstantiable(receiverType);
    421 
    422             // Allocate memory for receiver.
    423             Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType);
    424 
    425             // The MethodHandle type for the caller has the form of
    426             // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of
    427             // the form {rtype=void,ptypes=T,A1...An}. So the frame for
    428             // the constructor needs to have a slot with the receiver
    429             // in position 0.
    430             EmulatedStackFrame constructorFrame =
    431                     EmulatedStackFrame.create(constructorHandle.type());
    432             constructorFrame.setReference(0, receiver);
    433             emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0);
    434             constructorHandle.invoke(constructorFrame);
    435 
    436             // Set return result for caller.
    437             emulatedStackFrame.setReturnValueTo(receiver);
    438         }
    439     }
    440 
    441     /**
    442      * Implements MethodHandle.bindTo.
    443      *
    444      * @hide
    445      */
    446     public static class BindTo extends Transformer {
    447         private final MethodHandle delegate;
    448         private final Object receiver;
    449 
    450         private final EmulatedStackFrame.Range range;
    451 
    452         public BindTo(MethodHandle delegate, Object receiver) {
    453             super(delegate.type().dropParameterTypes(0, 1));
    454 
    455             this.delegate = delegate;
    456             this.receiver = receiver;
    457 
    458             this.range = EmulatedStackFrame.Range.all(this.type());
    459         }
    460 
    461         @Override
    462         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    463             // Create a new emulated stack frame with the full type (including the leading
    464             // receiver reference).
    465             EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type());
    466 
    467             // The first reference argument must be the receiver.
    468             stackFrame.setReference(0, receiver);
    469             // Copy all other arguments.
    470             emulatedStackFrame.copyRangeTo(stackFrame, range,
    471                     1 /* referencesStart */, 0 /* stackFrameStart */);
    472 
    473             // Perform the invoke.
    474             delegate.invoke(stackFrame);
    475             stackFrame.copyReturnValueTo(emulatedStackFrame);
    476         }
    477     }
    478 
    479     /**
    480      * Implements MethodHandle.filterReturnValue.
    481      */
    482     public static class FilterReturnValue extends Transformer {
    483         private final MethodHandle target;
    484         private final MethodHandle filter;
    485 
    486         private final EmulatedStackFrame.Range allArgs;
    487 
    488         public FilterReturnValue(MethodHandle target, MethodHandle filter) {
    489             super(MethodType.methodType(filter.type().rtype(), target.type().ptypes()));
    490 
    491             this.target = target;
    492             this.filter = filter;
    493 
    494             allArgs = EmulatedStackFrame.Range.all(type());
    495         }
    496 
    497         @Override
    498         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    499             // Create a new frame with the target's type and copy all arguments over.
    500             // This frame differs in return type with |emulatedStackFrame| but will have
    501             // the same parameter shapes.
    502             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
    503             emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0);
    504             target.invoke(targetFrame);
    505 
    506             // Perform the invoke.
    507             final StackFrameReader returnValueReader = new StackFrameReader();
    508             returnValueReader.attach(targetFrame);
    509             returnValueReader.makeReturnValueAccessor();
    510 
    511             // Create an emulated frame for the filter and copy all its arguments across.
    512             EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
    513             final StackFrameWriter filterWriter = new StackFrameWriter();
    514             filterWriter.attach(filterFrame);
    515 
    516             final Class<?> returnType = target.type().rtype();
    517             if (!returnType.isPrimitive()) {
    518                 filterWriter.putNextReference(returnValueReader.nextReference(returnType),
    519                         returnType);
    520             } else if (returnType == boolean.class) {
    521                 filterWriter.putNextBoolean(returnValueReader.nextBoolean());
    522             } else if (returnType == byte.class) {
    523                 filterWriter.putNextByte(returnValueReader.nextByte());
    524             } else if (returnType == char.class) {
    525                 filterWriter.putNextChar(returnValueReader.nextChar());
    526             } else if (returnType == short.class) {
    527                 filterWriter.putNextShort(returnValueReader.nextShort());
    528             } else if (returnType == int.class) {
    529                 filterWriter.putNextInt(returnValueReader.nextInt());
    530             } else if (returnType == long.class) {
    531                 filterWriter.putNextLong(returnValueReader.nextLong());
    532             } else if (returnType == float.class) {
    533                 filterWriter.putNextFloat(returnValueReader.nextFloat());
    534             } else if (returnType == double.class) {
    535                 filterWriter.putNextDouble(returnValueReader.nextDouble());
    536             }
    537 
    538             // Invoke the filter and copy its return value back to the original frame.
    539             filter.invoke(filterFrame);
    540             filterFrame.copyReturnValueTo(emulatedStackFrame);
    541         }
    542     }
    543 
    544     /*
    545      * Implements MethodHandles.permuteArguments.
    546      *
    547      * @hide
    548      */
    549     public static class PermuteArguments extends Transformer {
    550         private final MethodHandle target;
    551         private final int[] reorder;
    552 
    553         public PermuteArguments(MethodType type, MethodHandle target, int[] reorder) {
    554             super(type);
    555 
    556             this.target = target;
    557             this.reorder = reorder;
    558         }
    559 
    560         @Override
    561         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
    562             final StackFrameReader reader = new StackFrameReader();
    563             reader.attach(emulatedStackFrame);
    564 
    565             // In the interests of simplicity, we box / unbox arguments while performing
    566             // the permutation. We first iterate through the incoming stack frame and box
    567             // each argument. We then unbox and write out the argument to the target frame
    568             // according to the specified reordering.
    569             Object[] arguments = new Object[reorder.length];
    570             final Class<?>[] ptypes = type().ptypes();
    571             for (int i = 0; i < ptypes.length; ++i) {
    572                 final Class<?> ptype = ptypes[i];
    573                 if (!ptype.isPrimitive()) {
    574                     arguments[i] = reader.nextReference(ptype);
    575                 } else if (ptype == boolean.class) {
    576                     arguments[i] = reader.nextBoolean();
    577                 } else if (ptype == byte.class) {
    578                     arguments[i] = reader.nextByte();
    579                 } else if (ptype == char.class) {
    580                     arguments[i] = reader.nextChar();
    581                 } else if (ptype == short.class) {
    582                     arguments[i] = reader.nextShort();
    583                 } else if (ptype == int.class) {
    584                     arguments[i] = reader.nextInt();
    585                 } else if (ptype == long.class) {
    586                     arguments[i] = reader.nextLong();
    587                 } else if (ptype == float.class) {
    588                     arguments[i] = reader.nextFloat();
    589                 } else if (ptype == double.class) {
    590                     arguments[i] = reader.nextDouble();
    591                 } else {
    592                     throw new AssertionError("Unexpected type: " + ptype);
    593                 }
    594             }
    595 
    596             EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
    597             final StackFrameWriter writer = new StackFrameWriter();
    598             writer.attach(calleeFrame);
    599 
    600             for (int i = 0; i < ptypes.length; ++i) {
    601                 int idx = reorder[i];
    602                 final Class<?> ptype = ptypes[idx];
    603                 final Object argument = arguments[idx];
    604 
    605                 if (!ptype.isPrimitive()) {
    606                     writer.putNextReference(argument, ptype);
    607                 } else if (ptype == boolean.class) {
    608                     writer.putNextBoolean((boolean) argument);
    609                 } else if (ptype == byte.class) {
    610                     writer.putNextByte((byte) argument);
    611                 } else if (ptype == char.class) {
    612                     writer.putNextChar((char) argument);
    613                 } else if (ptype == short.class) {
    614                     writer.putNextShort((short) argument);
    615                 } else if (ptype == int.class) {
    616                     writer.putNextInt((int) argument);
    617                 } else if (ptype == long.class) {
    618                     writer.putNextLong((long) argument);
    619                 } else if (ptype == float.class) {
    620                     writer.putNextFloat((float) argument);
    621                 } else if (ptype == double.class) {
    622                     writer.putNextDouble((double) argument);
    623                 } else {
    624                     throw new AssertionError("Unexpected type: " + ptype);
    625                 }
    626             }
    627 
    628             target.invoke(calleeFrame);
    629             calleeFrame.copyReturnValueTo(emulatedStackFrame);
    630         }
    631     }
    632 
    633     /**
    634      * Converts methods with a trailing array argument to variable arity
    635      * methods. So (A,B,C[])R can be invoked with any number of convertible
    636      * arguments after B, e.g. (A,B)R or (A, B, C0)R or (A, B, C0...Cn)R.
    637      *
    638      * @hide
    639      */
    640     /*package*/ static class VarargsCollector extends Transformer {
    641         final MethodHandle target;
    642 
    643         /*package*/ VarargsCollector(MethodHandle target) {
    644             super(target.type(), MethodHandle.INVOKE_CALLSITE_TRANSFORM);
    645             if (!lastParameterTypeIsAnArray(target.type().ptypes())) {
    646                 throw new IllegalArgumentException("target does not have array as last parameter");
    647             }
    648             this.target = target;
    649         }
    650 
    651         private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) {
    652             if (parameterTypes.length == 0) return false;
    653             return parameterTypes[parameterTypes.length - 1].isArray();
    654         }
    655 
    656         @Override
    657         public boolean isVarargsCollector() { return true; }
    658 
    659         @Override
    660         public MethodHandle asFixedArity() { return target; }
    661 
    662         @Override
    663         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
    664             MethodType callerFrameType = callerFrame.getMethodType();
    665             Class<?>[] callerPTypes = callerFrameType.ptypes();
    666             Class<?>[] targetPTypes = type().ptypes();
    667 
    668             int lastTargetIndex = targetPTypes.length - 1;
    669             if (callerPTypes.length == targetPTypes.length &&
    670                 targetPTypes[lastTargetIndex].isAssignableFrom(callerPTypes[lastTargetIndex])) {
    671                 // Caller frame matches target frame in the arity array parameter. Invoke
    672                 // immediately, and let the invoke() dispatch perform any necessary conversions
    673                 // on the other parameters present.
    674                 target.invoke(callerFrame);
    675                 return;
    676             }
    677 
    678             if (callerPTypes.length < targetPTypes.length - 1) {
    679                 // Too few arguments to be compatible with variable arity invocation.
    680                 throwWrongMethodTypeException(callerFrameType, type());
    681             }
    682 
    683             if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) {
    684                 // Incompatible return type.
    685                 throwWrongMethodTypeException(callerFrameType, type());
    686             }
    687 
    688             Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType();
    689             if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) {
    690                 // Wrong types to be compatible with variable arity invocation.
    691                 throwWrongMethodTypeException(callerFrameType, type());
    692             }
    693 
    694             // Allocate targetFrame.
    695             MethodType targetFrameType = makeTargetFrameType(callerFrameType, type());
    696             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType);
    697             prepareFrame(callerFrame, targetFrame);
    698 
    699             // Invoke target.
    700             target.invoke(targetFrame);
    701 
    702             // Copy return value to the caller's frame.
    703             targetFrame.copyReturnValueTo(callerFrame);
    704         }
    705 
    706         private static void throwWrongMethodTypeException(MethodType from, MethodType to) {
    707             throw new WrongMethodTypeException("Cannot convert " + from + " to " + to);
    708         }
    709 
    710         private static boolean arityArgumentsConvertible(Class<?>[] ptypes, int arityStart,
    711                                                          Class<?> elementType) {
    712             if (ptypes.length - 1 == arityStart) {
    713                 if (ptypes[arityStart].isArray() &&
    714                     ptypes[arityStart].getComponentType() == elementType) {
    715                     // The last ptype is in the same position as the arity
    716                     // array and has the same type.
    717                     return true;
    718                 }
    719             }
    720 
    721             for (int i = arityStart; i < ptypes.length; ++i) {
    722                 if (!MethodType.canConvert(ptypes[i], elementType)) {
    723                     return false;
    724                 }
    725             }
    726             return true;
    727         }
    728 
    729         private static Object referenceArray(StackFrameReader reader, Class<?>[] ptypes,
    730                                              Class<?> elementType, int offset, int length) {
    731             Object arityArray = Array.newInstance(elementType, length);
    732             for (int i = 0; i < length; ++i) {
    733                 Class<?> argumentType = ptypes[i + offset];
    734                 Object o = null;
    735                 switch (Wrapper.basicTypeChar(argumentType)) {
    736                     case 'L': { o = reader.nextReference(argumentType); break; }
    737                     case 'I': { o = reader.nextInt(); break; }
    738                     case 'J': { o = reader.nextLong(); break; }
    739                     case 'B': { o = reader.nextByte(); break; }
    740                     case 'S': { o = reader.nextShort(); break; }
    741                     case 'C': { o = reader.nextChar(); break; }
    742                     case 'Z': { o = reader.nextBoolean(); break; }
    743                     case 'F': { o = reader.nextFloat(); break; }
    744                     case 'D': { o = reader.nextDouble(); break; }
    745                 }
    746                 Array.set(arityArray, i, elementType.cast(o));
    747             }
    748             return arityArray;
    749         }
    750 
    751         private static Object intArray(StackFrameReader reader, Class<?> ptypes[],
    752                                        int offset, int length) {
    753             int[] arityArray = new int[length];
    754             for (int i = 0; i < length; ++i) {
    755                 Class<?> argumentType = ptypes[i + offset];
    756                 switch (Wrapper.basicTypeChar(argumentType)) {
    757                     case 'I': { arityArray[i] = reader.nextInt(); break; }
    758                     case 'S': { arityArray[i] = reader.nextShort(); break; }
    759                     case 'B': { arityArray[i] = reader.nextByte(); break; }
    760                     default: {
    761                         arityArray[i] = (Integer) reader.nextReference(argumentType);
    762                         break;
    763                     }
    764                 }
    765             }
    766             return arityArray;
    767         }
    768 
    769         private static Object longArray(StackFrameReader reader, Class<?> ptypes[],
    770                                         int offset, int length) {
    771             long[] arityArray = new long[length];
    772             for (int i = 0; i < length; ++i) {
    773                 Class<?> argumentType = ptypes[i + offset];
    774                 switch (Wrapper.basicTypeChar(argumentType)) {
    775                     case 'J': { arityArray[i] = reader.nextLong(); break; }
    776                     case 'I': { arityArray[i] = reader.nextInt(); break; }
    777                     case 'S': { arityArray[i] = reader.nextShort(); break; }
    778                     case 'B': { arityArray[i] = reader.nextByte(); break; }
    779                     default: { arityArray[i] = (Long) reader.nextReference(argumentType); break; }
    780                 }
    781             }
    782             return arityArray;
    783         }
    784 
    785         private static Object byteArray(StackFrameReader reader, Class<?> ptypes[],
    786                                         int offset, int length) {
    787             byte[] arityArray = new byte[length];
    788             for (int i = 0; i < length; ++i) {
    789                 Class<?> argumentType = ptypes[i + offset];
    790                 switch (Wrapper.basicTypeChar(argumentType)) {
    791                     case 'B': { arityArray[i] = reader.nextByte(); break; }
    792                     default: { arityArray[i] = (Byte) reader.nextReference(argumentType); break; }
    793                 }
    794             }
    795             return arityArray;
    796         }
    797 
    798         private static Object shortArray(StackFrameReader reader, Class<?> ptypes[],
    799                                         int offset, int length) {
    800             short[] arityArray = new short[length];
    801             for (int i = 0; i < length; ++i) {
    802                 Class<?> argumentType = ptypes[i + offset];
    803                 switch (Wrapper.basicTypeChar(argumentType)) {
    804                     case 'S': { arityArray[i] = reader.nextShort(); break; }
    805                     case 'B': { arityArray[i] = reader.nextByte(); break; }
    806                     default: { arityArray[i] = (Short) reader.nextReference(argumentType); break; }
    807                 }
    808             }
    809             return arityArray;
    810         }
    811 
    812         private static Object charArray(StackFrameReader reader, Class<?> ptypes[],
    813                                         int offset, int length) {
    814             char[] arityArray = new char[length];
    815             for (int i = 0; i < length; ++i) {
    816                 Class<?> argumentType = ptypes[i + offset];
    817                 switch (Wrapper.basicTypeChar(argumentType)) {
    818                     case 'C': { arityArray[i] = reader.nextChar(); break; }
    819                     default: {
    820                         arityArray[i] = (Character) reader.nextReference(argumentType);
    821                         break;
    822                     }
    823                 }
    824             }
    825             return arityArray;
    826         }
    827 
    828         private static Object booleanArray(StackFrameReader reader, Class<?> ptypes[],
    829                                         int offset, int length) {
    830             boolean[] arityArray = new boolean[length];
    831             for (int i = 0; i < length; ++i) {
    832                 Class<?> argumentType = ptypes[i + offset];
    833                 switch (Wrapper.basicTypeChar(argumentType)) {
    834                     case 'Z': { arityArray[i] = reader.nextBoolean(); break; }
    835                     default:
    836                         arityArray[i] = (Boolean) reader.nextReference(argumentType);
    837                         break;
    838                 }
    839             }
    840             return arityArray;
    841         }
    842 
    843         private static Object floatArray(StackFrameReader reader, Class<?> ptypes[],
    844                                         int offset, int length) {
    845             float[] arityArray = new float[length];
    846             for (int i = 0; i < length; ++i) {
    847                 Class<?> argumentType = ptypes[i + offset];
    848                 switch (Wrapper.basicTypeChar(argumentType)) {
    849                     case 'F': { arityArray[i] = reader.nextFloat(); break; }
    850                     case 'J': { arityArray[i] = reader.nextLong(); break; }
    851                     case 'I': { arityArray[i] = reader.nextInt(); break; }
    852                     case 'S': { arityArray[i] = reader.nextShort(); break; }
    853                     case 'B': { arityArray[i] = reader.nextByte(); break; }
    854                     default: {
    855                         arityArray[i] = (Float) reader.nextReference(argumentType);
    856                         break;
    857                     }
    858                 }
    859             }
    860             return arityArray;
    861         }
    862 
    863         private static Object doubleArray(StackFrameReader reader, Class<?> ptypes[],
    864                                         int offset, int length) {
    865             double[] arityArray = new double[length];
    866             for (int i = 0; i < length; ++i) {
    867                 Class<?> argumentType = ptypes[i + offset];
    868                 switch (Wrapper.basicTypeChar(argumentType)) {
    869                     case 'D': { arityArray[i] = reader.nextDouble(); break; }
    870                     case 'F': { arityArray[i] = reader.nextFloat(); break; }
    871                     case 'J': { arityArray[i] = reader.nextLong(); break; }
    872                     case 'I': { arityArray[i] = reader.nextInt(); break; }
    873                     case 'S': { arityArray[i] = reader.nextShort(); break; }
    874                     case 'B': { arityArray[i] = reader.nextByte(); break; }
    875                     default: {
    876                         arityArray[i] = (Double) reader.nextReference(argumentType);
    877                         break;
    878                     }
    879                 }
    880             }
    881             return arityArray;
    882         }
    883 
    884         private static Object makeArityArray(MethodType callerFrameType,
    885                                              StackFrameReader callerFrameReader,
    886                                              int indexOfArityArray,
    887                                              Class<?> arityArrayType) {
    888             int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray;
    889             Class<?> elementType = arityArrayType.getComponentType();
    890             Class<?>[] callerPTypes = callerFrameType.ptypes();
    891 
    892             char elementBasicType = Wrapper.basicTypeChar(elementType);
    893             switch (elementBasicType) {
    894                 case 'L': return referenceArray(callerFrameReader, callerPTypes, elementType,
    895                                                 indexOfArityArray, arityArrayLength);
    896                 case 'I': return intArray(callerFrameReader, callerPTypes,
    897                                           indexOfArityArray, arityArrayLength);
    898                 case 'J': return longArray(callerFrameReader, callerPTypes,
    899                                            indexOfArityArray, arityArrayLength);
    900                 case 'B': return byteArray(callerFrameReader, callerPTypes,
    901                                            indexOfArityArray, arityArrayLength);
    902                 case 'S': return shortArray(callerFrameReader, callerPTypes,
    903                                             indexOfArityArray, arityArrayLength);
    904                 case 'C': return charArray(callerFrameReader, callerPTypes,
    905                                            indexOfArityArray, arityArrayLength);
    906                 case 'Z': return booleanArray(callerFrameReader, callerPTypes,
    907                                               indexOfArityArray, arityArrayLength);
    908                 case 'F': return floatArray(callerFrameReader, callerPTypes,
    909                                             indexOfArityArray, arityArrayLength);
    910                 case 'D': return doubleArray(callerFrameReader, callerPTypes,
    911                                              indexOfArityArray, arityArrayLength);
    912             }
    913             throw new InternalError("Unexpected type: " + elementType);
    914         }
    915 
    916         public static Object collectArguments(char basicComponentType, Class<?> componentType,
    917                                               StackFrameReader reader, Class<?>[] types,
    918                                               int startIdx, int length) {
    919             switch (basicComponentType) {
    920                 case 'L': return referenceArray(reader, types, componentType, startIdx, length);
    921                 case 'I': return intArray(reader, types, startIdx, length);
    922                 case 'J': return longArray(reader, types, startIdx, length);
    923                 case 'B': return byteArray(reader, types, startIdx, length);
    924                 case 'S': return shortArray(reader, types, startIdx, length);
    925                 case 'C': return charArray(reader, types, startIdx, length);
    926                 case 'Z': return booleanArray(reader, types, startIdx, length);
    927                 case 'F': return floatArray(reader, types, startIdx, length);
    928                 case 'D': return doubleArray(reader, types, startIdx, length);
    929             }
    930             throw new InternalError("Unexpected type: " + basicComponentType);
    931         }
    932 
    933         private static void copyParameter(StackFrameReader reader, StackFrameWriter writer,
    934                                           Class<?> ptype) {
    935             switch (Wrapper.basicTypeChar(ptype)) {
    936                 case 'L': { writer.putNextReference(reader.nextReference(ptype), ptype); break; }
    937                 case 'I': { writer.putNextInt(reader.nextInt()); break; }
    938                 case 'J': { writer.putNextLong(reader.nextLong()); break; }
    939                 case 'B': { writer.putNextByte(reader.nextByte()); break; }
    940                 case 'S': { writer.putNextShort(reader.nextShort()); break; }
    941                 case 'C': { writer.putNextChar(reader.nextChar()); break; }
    942                 case 'Z': { writer.putNextBoolean(reader.nextBoolean()); break; }
    943                 case 'F': { writer.putNextFloat(reader.nextFloat()); break; }
    944                 case 'D': { writer.putNextDouble(reader.nextDouble()); break; }
    945                 default: throw new InternalError("Unexpected type: " + ptype);
    946             }
    947         }
    948 
    949         private static void prepareFrame(EmulatedStackFrame callerFrame,
    950                                          EmulatedStackFrame targetFrame) {
    951             StackFrameWriter targetWriter = new StackFrameWriter();
    952             targetWriter.attach(targetFrame);
    953             StackFrameReader callerReader = new StackFrameReader();
    954             callerReader.attach(callerFrame);
    955 
    956             // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array.
    957             MethodType targetMethodType = targetFrame.getMethodType();
    958             int indexOfArityArray = targetMethodType.ptypes().length - 1;
    959             for (int i = 0; i < indexOfArityArray; ++i) {
    960                 Class<?> ptype = targetMethodType.ptypes()[i];
    961                 copyParameter(callerReader, targetWriter, ptype);
    962             }
    963 
    964             // Add arity array as last parameter in |targetFrame|.
    965             Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray];
    966             Object arityArray = makeArityArray(callerFrame.getMethodType(), callerReader,
    967                                                indexOfArityArray, arityArrayType);
    968             targetWriter.putNextReference(arityArray, arityArrayType);
    969         }
    970 
    971         /**
    972          * Computes the frame type to invoke the target method handle with. This
    973          * is the same as the caller frame type, but with the trailing argument
    974          * being the array type that is the trailing argument in the target method
    975          * handle.
    976          *
    977          * Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC
    978          * then the constructed type is (C0, C1, T2[])RC.
    979          */
    980         private static MethodType makeTargetFrameType(MethodType callerType,
    981                                                       MethodType targetType) {
    982             final int ptypesLength = targetType.ptypes().length;
    983             final Class<?>[] ptypes = new Class<?>[ptypesLength];
    984             // Copy types from caller types to new methodType.
    985             System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1);
    986             // Set the last element in the type array to be the
    987             // varargs array of the target.
    988             ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1];
    989             return MethodType.methodType(callerType.rtype(), ptypes);
    990         }
    991     }
    992 
    993     /**
    994      * Implements MethodHandles.invoker & MethodHandles.exactInvoker.
    995      */
    996     static class Invoker extends Transformer {
    997         private final MethodType targetType;
    998         private final boolean isExactInvoker;
    999         private final EmulatedStackFrame.Range copyRange;
   1000 
   1001         Invoker(MethodType targetType, boolean isExactInvoker) {
   1002             super(targetType.insertParameterTypes(0, MethodHandle.class));
   1003             this.targetType = targetType;
   1004             this.isExactInvoker = isExactInvoker;
   1005             copyRange = EmulatedStackFrame.Range.of(type(), 1, type().parameterCount());
   1006         }
   1007 
   1008         @Override
   1009         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
   1010             // We need to artifically throw a WrongMethodTypeException here because we
   1011             // can't call invokeExact on the target inside the transformer.
   1012             if (isExactInvoker) {
   1013                 // TODO: We should do the comparison by hand if this new type creation
   1014                 // on every invoke proves too expensive.
   1015                 MethodType callType = emulatedStackFrame.getCallsiteType().dropParameterTypes(0, 1);
   1016                 if (!targetType.equals(callType)) {
   1017                     throw new WrongMethodTypeException("Wrong type, Expected: " + targetType
   1018                             + " was: " + callType);
   1019                 }
   1020             }
   1021 
   1022             // The first argument to the stack frame is the handle that needs to be invoked.
   1023             MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class);
   1024 
   1025             // All other arguments must be copied to the target frame.
   1026             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType);
   1027             emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
   1028 
   1029             // Finally, invoke the handle and copy the return value.
   1030             target.invoke(targetFrame);
   1031             targetFrame.copyReturnValueTo(emulatedStackFrame);
   1032         }
   1033     }
   1034 
   1035     /**
   1036      * Implements MethodHandle.asSpreader / MethodHandles.spreadInvoker.
   1037      */
   1038     static class Spreader extends Transformer {
   1039         /** The method handle we're delegating to. */
   1040         private final MethodHandle target;
   1041 
   1042         /**
   1043          * The offset of the trailing array argument in the list of arguments to
   1044          * this transformer. The array argument is always the last argument.
   1045          */
   1046         private final int arrayOffset;
   1047 
   1048         /**
   1049          * The type char of the component type of the array.
   1050          */
   1051         private final char arrayTypeChar;
   1052 
   1053         /**
   1054          * The number of input arguments that will be present in the array. In other words,
   1055          * this is the expected array length.
   1056          */
   1057         private final int numArrayArgs;
   1058 
   1059         /**
   1060          * Range of arguments to copy verbatim from the input frame, This will cover all
   1061          * arguments that aren't a part of the trailing array.
   1062          */
   1063         private final Range copyRange;
   1064 
   1065         Spreader(MethodHandle target, MethodType spreaderType, int numArrayArgs) {
   1066             super(spreaderType);
   1067             this.target = target;
   1068             // Copy all arguments except the last argument (which is the trailing array argument
   1069             // that needs to be spread).
   1070             arrayOffset = spreaderType.parameterCount() - 1;
   1071 
   1072             // Get and cache the component type of the input array.
   1073             final Class<?> componentType = spreaderType.ptypes()[arrayOffset].getComponentType();
   1074             if (componentType == null) {
   1075                 throw new AssertionError("Trailing argument must be an array.");
   1076             }
   1077             arrayTypeChar = Wrapper.basicTypeChar(componentType);
   1078 
   1079             this.numArrayArgs = numArrayArgs;
   1080             // Copy all args except for the last argument.
   1081             this.copyRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset);
   1082         }
   1083 
   1084         @Override
   1085         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
   1086             // Create a new stack frame for the callee.
   1087             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
   1088 
   1089             // Copy all arguments except for the trailing array argument.
   1090             callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
   1091 
   1092             // Attach the writer, prepare to spread the trailing array arguments into
   1093             // the callee frame.
   1094             StackFrameWriter writer = new StackFrameWriter();
   1095             writer.attach(targetFrame,
   1096                     arrayOffset,
   1097                     copyRange.numReferences,
   1098                     copyRange.numBytes);
   1099 
   1100             // Get the array reference and check that its length is as expected.
   1101             Object arrayObj = callerFrame.getReference(
   1102                     copyRange.numReferences, this.type().ptypes()[arrayOffset]);
   1103             final int arrayLength = Array.getLength(arrayObj);
   1104             if (arrayLength != numArrayArgs) {
   1105                 throw new IllegalArgumentException("Invalid array length: " + arrayLength);
   1106             }
   1107 
   1108             final MethodType type = target.type();
   1109             switch (arrayTypeChar) {
   1110                 case 'L':
   1111                     spreadArray((Object[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1112                     break;
   1113                 case 'I':
   1114                     spreadArray((int[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1115                     break;
   1116                 case 'J':
   1117                     spreadArray((long[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1118                     break;
   1119                 case 'B':
   1120                     spreadArray((byte[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1121                     break;
   1122                 case 'S':
   1123                     spreadArray((short[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1124                     break;
   1125                 case 'C':
   1126                     spreadArray((char[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1127                     break;
   1128                 case 'Z':
   1129                     spreadArray((boolean[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1130                     break;
   1131                 case 'F':
   1132                     spreadArray((float[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1133                     break;
   1134                 case 'D':
   1135                     spreadArray((double[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
   1136                     break;
   1137 
   1138             }
   1139 
   1140             target.invoke(targetFrame);
   1141             targetFrame.copyReturnValueTo(callerFrame);
   1142         }
   1143 
   1144         public static void spreadArray(Object[] array, StackFrameWriter writer, MethodType type,
   1145                                        int numArgs, int offset) {
   1146             final Class<?>[] ptypes = type.ptypes();
   1147             for (int i = 0; i < numArgs; ++i) {
   1148                 Class<?> argumentType = ptypes[i + offset];
   1149                 Object o = array[i];
   1150                 switch (Wrapper.basicTypeChar(argumentType)) {
   1151                     case 'L': { writer.putNextReference(o, argumentType); break; }
   1152                     case 'I': { writer.putNextInt((int) o); break; }
   1153                     case 'J': { writer.putNextLong((long) o); break; }
   1154                     case 'B': { writer.putNextByte((byte) o); break; }
   1155                     case 'S': { writer.putNextShort((short) o); break; }
   1156                     case 'C': { writer.putNextChar((char) o); break; }
   1157                     case 'Z': { writer.putNextBoolean((boolean) o); break; }
   1158                     case 'F': { writer.putNextFloat((float) o); break; }
   1159                     case 'D': { writer.putNextDouble((double) o); break; }
   1160                 }
   1161             }
   1162         }
   1163 
   1164         public static void spreadArray(int[] array, StackFrameWriter writer, MethodType type,
   1165                                        int numArgs, int offset) {
   1166             final Class<?>[] ptypes = type.ptypes();
   1167             for (int i = 0; i < numArgs; ++i) {
   1168                 Class<?> argumentType = ptypes[i + offset];
   1169                 int j = array[i];
   1170                 switch (Wrapper.basicTypeChar(argumentType)) {
   1171                     case 'L': { writer.putNextReference(j, argumentType); break; }
   1172                     case 'I': { writer.putNextInt(j); break; }
   1173                     case 'J': { writer.putNextLong(j); break; }
   1174                     case 'F': { writer.putNextFloat(j); break; }
   1175                     case 'D': { writer.putNextDouble(j); break; }
   1176                     default : { throw new AssertionError(); }
   1177                 }
   1178             }
   1179         }
   1180 
   1181         public static void spreadArray(long[] array, StackFrameWriter writer, MethodType type,
   1182                                        int numArgs, int offset) {
   1183             final Class<?>[] ptypes = type.ptypes();
   1184             for (int i = 0; i < numArgs; ++i) {
   1185                 Class<?> argumentType = ptypes[i + offset];
   1186                 long l = array[i];
   1187                 switch (Wrapper.basicTypeChar(argumentType)) {
   1188                     case 'L': { writer.putNextReference(l, argumentType); break; }
   1189                     case 'J': { writer.putNextLong(l); break; }
   1190                     case 'F': { writer.putNextFloat((float) l); break; }
   1191                     case 'D': { writer.putNextDouble((double) l); break; }
   1192                     default : { throw new AssertionError(); }
   1193                 }
   1194             }
   1195         }
   1196 
   1197         public static void spreadArray(byte[] array,
   1198                                        StackFrameWriter writer, MethodType type,
   1199                                        int numArgs, int offset) {
   1200             final Class<?>[] ptypes = type.ptypes();
   1201             for (int i = 0; i < numArgs; ++i) {
   1202                 Class<?> argumentType = ptypes[i + offset];
   1203                 byte b = array[i];
   1204                 switch (Wrapper.basicTypeChar(argumentType)) {
   1205                     case 'L': { writer.putNextReference(b, argumentType); break; }
   1206                     case 'I': { writer.putNextInt(b); break; }
   1207                     case 'J': { writer.putNextLong(b); break; }
   1208                     case 'B': { writer.putNextByte(b); break; }
   1209                     case 'S': { writer.putNextShort(b); break; }
   1210                     case 'F': { writer.putNextFloat(b); break; }
   1211                     case 'D': { writer.putNextDouble(b); break; }
   1212                     default : { throw new AssertionError(); }
   1213                 }
   1214             }
   1215         }
   1216 
   1217         public static void spreadArray(short[] array,
   1218                                        StackFrameWriter writer, MethodType type,
   1219                                        int numArgs, int offset) {
   1220             final Class<?>[] ptypes = type.ptypes();
   1221             for (int i = 0; i < numArgs; ++i) {
   1222                 Class<?> argumentType = ptypes[i + offset];
   1223                 short s = array[i];
   1224                 switch (Wrapper.basicTypeChar(argumentType)) {
   1225                     case 'L': { writer.putNextReference(s, argumentType); break; }
   1226                     case 'I': { writer.putNextInt(s); break; }
   1227                     case 'J': { writer.putNextLong(s); break; }
   1228                     case 'S': { writer.putNextShort(s); break; }
   1229                     case 'F': { writer.putNextFloat(s); break; }
   1230                     case 'D': { writer.putNextDouble(s); break; }
   1231                     default : { throw new AssertionError(); }
   1232                 }
   1233             }
   1234         }
   1235 
   1236         public static void spreadArray(char[] array,
   1237                                        StackFrameWriter writer, MethodType type,
   1238                                        int numArgs, int offset) {
   1239             final Class<?>[] ptypes = type.ptypes();
   1240             for (int i = 0; i < numArgs; ++i) {
   1241                 Class<?> argumentType = ptypes[i + offset];
   1242                 char c = array[i];
   1243                 switch (Wrapper.basicTypeChar(argumentType)) {
   1244                     case 'L': { writer.putNextReference(c, argumentType); break; }
   1245                     case 'I': { writer.putNextInt(c); break; }
   1246                     case 'J': { writer.putNextLong(c); break; }
   1247                     case 'C': { writer.putNextChar(c); break; }
   1248                     case 'F': { writer.putNextFloat(c); break; }
   1249                     case 'D': { writer.putNextDouble(c); break; }
   1250                     default : { throw new AssertionError(); }
   1251                 }
   1252             }
   1253         }
   1254 
   1255         public static void spreadArray(boolean[] array,
   1256                                        StackFrameWriter writer, MethodType type,
   1257                                        int numArgs, int offset) {
   1258             final Class<?>[] ptypes = type.ptypes();
   1259             for (int i = 0; i < numArgs; ++i) {
   1260                 Class<?> argumentType = ptypes[i + offset];
   1261                 boolean z = array[i];
   1262                 switch (Wrapper.basicTypeChar(argumentType)) {
   1263                     case 'L': { writer.putNextReference(z, argumentType); break; }
   1264                     case 'Z': { writer.putNextBoolean(z); break; }
   1265                     default : { throw new AssertionError(); }
   1266                 }
   1267             }
   1268         }
   1269 
   1270         public static void spreadArray(double[] array,
   1271                                        StackFrameWriter writer, MethodType type,
   1272                                        int numArgs, int offset) {
   1273             final Class<?>[] ptypes = type.ptypes();
   1274             for (int i = 0; i < numArgs; ++i) {
   1275                 Class<?> argumentType = ptypes[i + offset];
   1276                 double d = array[i];
   1277                 switch (Wrapper.basicTypeChar(argumentType)) {
   1278                     case 'L': { writer.putNextReference(d, argumentType); break; }
   1279                     case 'D': { writer.putNextDouble(d); break; }
   1280                     default : { throw new AssertionError(); }
   1281                 }
   1282             }
   1283         }
   1284 
   1285         public static void spreadArray(float[] array, StackFrameWriter writer, MethodType type,
   1286                                        int numArgs, int offset) {
   1287             final Class<?>[] ptypes = type.ptypes();
   1288             for (int i = 0; i < numArgs; ++i) {
   1289                 Class<?> argumentType = ptypes[i + offset];
   1290                 float f = array[i];
   1291                 switch (Wrapper.basicTypeChar(argumentType)) {
   1292                     case 'L': { writer.putNextReference(f, argumentType); break; }
   1293                     case 'D': { writer.putNextDouble((double) f); break; }
   1294                     case 'F': { writer.putNextFloat(f); break; }
   1295                     default : { throw new AssertionError(); }
   1296                 }
   1297             }
   1298         }
   1299     }
   1300 
   1301     /**
   1302      * Implements MethodHandle.asCollector.
   1303      */
   1304     static class Collector extends Transformer {
   1305         private final MethodHandle target;
   1306 
   1307         /**
   1308          * The offset of the trailing array argument in the list of arguments to
   1309          * this transformer. The array argument is always the last argument.
   1310          */
   1311         private final int arrayOffset;
   1312 
   1313         /**
   1314          * The number of input arguments that will be present in the array. In other words,
   1315          * this is the expected array length.
   1316          */
   1317         private final int numArrayArgs;
   1318 
   1319         /**
   1320          * The type char of the component type of the array.
   1321          */
   1322         private final char arrayTypeChar;
   1323 
   1324         /**
   1325          * Range of arguments to copy verbatim from the input frame, This will cover all
   1326          * arguments that aren't a part of the trailing array.
   1327          */
   1328         private final Range copyRange;
   1329 
   1330         Collector(MethodHandle delegate, Class<?> arrayType, int length) {
   1331             super(delegate.type().asCollectorType(arrayType, length));
   1332 
   1333             target = delegate;
   1334             // Copy all arguments except the last argument (which is the trailing array argument
   1335             // that needs to be spread).
   1336             arrayOffset = delegate.type().parameterCount() - 1;
   1337             arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType());
   1338             numArrayArgs = length;
   1339 
   1340             // Copy all args except for the last argument.
   1341             copyRange = EmulatedStackFrame.Range.of(delegate.type(), 0, arrayOffset);
   1342         }
   1343 
   1344         @Override
   1345         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
   1346             // Create a new stack frame for the callee.
   1347             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
   1348 
   1349             // Copy all arguments except for the trailing array argument.
   1350             callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
   1351 
   1352             // Attach the writer, prepare to spread the trailing array arguments into
   1353             // the callee frame.
   1354             final StackFrameWriter writer = new StackFrameWriter();
   1355             writer.attach(targetFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
   1356             final StackFrameReader reader = new StackFrameReader();
   1357             reader.attach(callerFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
   1358 
   1359             switch (arrayTypeChar) {
   1360                 case 'L': {
   1361                     // Reference arrays are the only case where the component type of the
   1362                     // array we construct might differ from the type of the reference we read
   1363                     // from the stack frame.
   1364                     final Class<?> targetType = target.type().ptypes()[arrayOffset];
   1365                     final Class<?> targetComponentType = targetType.getComponentType();
   1366                     final Class<?> adapterComponentType = type().lastParameterType();
   1367 
   1368                     Object[] arr = (Object[]) Array.newInstance(targetComponentType, numArrayArgs);
   1369                     for (int i = 0; i < numArrayArgs; ++i) {
   1370                         arr[i] = reader.nextReference(adapterComponentType);
   1371                     }
   1372 
   1373                     writer.putNextReference(arr, targetType);
   1374                     break;
   1375                 }
   1376                 case 'I': {
   1377                     int[] array = new int[numArrayArgs];
   1378                     for (int i = 0; i < numArrayArgs; ++i) {
   1379                         array[i] = reader.nextInt();
   1380                     }
   1381                     writer.putNextReference(array, int[].class);
   1382                     break;
   1383                 }
   1384                 case 'J': {
   1385                     long[] array = new long[numArrayArgs];
   1386                     for (int i = 0; i < numArrayArgs; ++i) {
   1387                         array[i] = reader.nextLong();
   1388                     }
   1389                     writer.putNextReference(array, long[].class);
   1390                     break;
   1391                 }
   1392                 case 'B': {
   1393                     byte[] array = new byte[numArrayArgs];
   1394                     for (int i = 0; i < numArrayArgs; ++i) {
   1395                         array[i] = reader.nextByte();
   1396                     }
   1397                     writer.putNextReference(array, byte[].class);
   1398                     break;
   1399                 }
   1400                 case 'S': {
   1401                     short[] array = new short[numArrayArgs];
   1402                     for (int i = 0; i < numArrayArgs; ++i) {
   1403                         array[i] = reader.nextShort();
   1404                     }
   1405                     writer.putNextReference(array, short[].class);
   1406                     break;
   1407                 }
   1408                 case 'C': {
   1409                     char[] array = new char[numArrayArgs];
   1410                     for (int i = 0; i < numArrayArgs; ++i) {
   1411                         array[i] = reader.nextChar();
   1412                     }
   1413                     writer.putNextReference(array, char[].class);
   1414                     break;
   1415                 }
   1416                 case 'Z': {
   1417                     boolean[] array = new boolean[numArrayArgs];
   1418                     for (int i = 0; i < numArrayArgs; ++i) {
   1419                         array[i] = reader.nextBoolean();
   1420                     }
   1421                     writer.putNextReference(array, boolean[].class);
   1422                     break;
   1423                 }
   1424                 case 'F': {
   1425                     float[] array = new float[numArrayArgs];
   1426                     for (int i = 0; i < numArrayArgs; ++i) {
   1427                         array[i] = reader.nextFloat();
   1428                     }
   1429                     writer.putNextReference(array, float[].class);
   1430                     break;
   1431                 }
   1432                 case 'D': {
   1433                     double[] array = new double[numArrayArgs];
   1434                     for (int i = 0; i < numArrayArgs; ++i) {
   1435                         array[i] = reader.nextDouble();
   1436                     }
   1437                     writer.putNextReference(array, double[].class);
   1438                     break;
   1439                 }
   1440             }
   1441 
   1442             target.invoke(targetFrame);
   1443             targetFrame.copyReturnValueTo(callerFrame);
   1444         }
   1445     }
   1446 
   1447     /*
   1448      * Implements MethodHandles.filterArguments.
   1449      */
   1450     static class FilterArguments extends Transformer {
   1451         /** The target handle. */
   1452         private final MethodHandle target;
   1453         /** Index of the first argument to filter */
   1454         private final int pos;
   1455         /** The list of filters to apply */
   1456         private final MethodHandle[] filters;
   1457 
   1458         FilterArguments(MethodHandle target, int pos, MethodHandle[] filters) {
   1459             super(deriveType(target, pos, filters));
   1460 
   1461             this.target = target;
   1462             this.pos = pos;
   1463             this.filters = filters;
   1464 
   1465         }
   1466 
   1467         private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
   1468             final Class<?>[] filterArgs = new Class<?>[filters.length];
   1469             for (int i = 0; i < filters.length; ++i) {
   1470                 filterArgs[i] = filters[i].type().parameterType(0);
   1471             }
   1472 
   1473             return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs);
   1474         }
   1475 
   1476         @Override
   1477         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
   1478             final StackFrameReader reader = new StackFrameReader();
   1479             reader.attach(stackFrame);
   1480 
   1481             EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
   1482             final StackFrameWriter writer = new StackFrameWriter();
   1483             writer.attach(transformedFrame);
   1484 
   1485             final Class<?>[] ptypes = target.type().ptypes();
   1486             for (int i = 0; i < ptypes.length; ++i) {
   1487                 // Check whether the current argument has a filter associated with it.
   1488                 // If it has no filter, no further action need be taken.
   1489                 final Class<?> ptype = ptypes[i];
   1490                 final MethodHandle filter;
   1491                 if (i < pos) {
   1492                     filter = null;
   1493                 } else if (i >= pos + filters.length) {
   1494                     filter = null;
   1495                 } else {
   1496                     filter = filters[i - pos];
   1497                 }
   1498 
   1499                 if (filter != null) {
   1500                     // Note that filter.type() must be (ptype)ptype - this is checked before
   1501                     // this transformer is created.
   1502                     EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
   1503 
   1504                     //  Copy the next argument from the stack frame to the filter frame.
   1505                     final StackFrameWriter filterWriter = new StackFrameWriter();
   1506                     filterWriter.attach(filterFrame);
   1507                     copyNext(reader, filterWriter, filter.type().ptypes()[0]);
   1508 
   1509                     filter.invoke(filterFrame);
   1510 
   1511                     // Copy the argument back from the filter frame to the stack frame.
   1512                     final StackFrameReader filterReader = new StackFrameReader();
   1513                     filterReader.attach(filterFrame);
   1514                     filterReader.makeReturnValueAccessor();
   1515                     copyNext(filterReader, writer, ptype);
   1516                 } else {
   1517                     // There's no filter associated with this frame, just copy the next argument
   1518                     // over.
   1519                     copyNext(reader, writer, ptype);
   1520                 }
   1521             }
   1522 
   1523             target.invoke(transformedFrame);
   1524             transformedFrame.copyReturnValueTo(stackFrame);
   1525         }
   1526     }
   1527 
   1528     /**
   1529      * Implements MethodHandles.collectArguments.
   1530      */
   1531     static class CollectArguments extends Transformer {
   1532         private final MethodHandle target;
   1533         private final MethodHandle collector;
   1534         private final int pos;
   1535 
   1536         /** The range of input arguments we copy to the collector. */
   1537         private final Range collectorRange;
   1538 
   1539         /**
   1540          * The first range of arguments we copy to the target. These are arguments
   1541          * in the range [0, pos). Note that arg[pos] is the return value of the filter.
   1542          */
   1543         private final Range range1;
   1544 
   1545         /**
   1546          * The second range of arguments we copy to the target. These are arguments in the range
   1547          * (pos, N], where N is the number of target arguments.
   1548          */
   1549         private final Range range2;
   1550 
   1551         private final int referencesOffset;
   1552         private final int stackFrameOffset;
   1553 
   1554         CollectArguments(MethodHandle target, MethodHandle collector, int pos,
   1555                          MethodType adapterType) {
   1556             super(adapterType);
   1557 
   1558             this.target = target;
   1559             this.collector = collector;
   1560             this.pos = pos;
   1561 
   1562             final int numFilterArgs = collector.type().parameterCount();
   1563             final int numAdapterArgs = type().parameterCount();
   1564             collectorRange = Range.of(type(), pos, pos + numFilterArgs);
   1565 
   1566             range1 = Range.of(type(), 0, pos);
   1567             if (pos + numFilterArgs < numAdapterArgs) {
   1568                 this.range2 = Range.of(type(), pos + numFilterArgs, numAdapterArgs);
   1569             } else {
   1570                 this.range2 = null;
   1571             }
   1572 
   1573             // Calculate the number of primitive bytes (or references) we copy to the
   1574             // target frame based on the return value of the combiner.
   1575             final Class<?> collectorRType = collector.type().rtype();
   1576             if (collectorRType == void.class) {
   1577                 stackFrameOffset = 0;
   1578                 referencesOffset = 0;
   1579             } else if (collectorRType.isPrimitive()) {
   1580                 stackFrameOffset = EmulatedStackFrame.getSize(collectorRType);
   1581                 referencesOffset = 0;
   1582             } else {
   1583                 stackFrameOffset = 0;
   1584                 referencesOffset = 1;
   1585             }
   1586         }
   1587 
   1588         @Override
   1589         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
   1590             // First invoke the collector.
   1591             EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type());
   1592             stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0);
   1593             collector.invoke(filterFrame);
   1594 
   1595             // Start constructing the target frame.
   1596             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
   1597             stackFrame.copyRangeTo(targetFrame, range1, 0, 0);
   1598 
   1599             // If one of these offsets is not zero, we have a return value to copy.
   1600             if (referencesOffset != 0 || stackFrameOffset != 0) {
   1601                 final StackFrameReader reader = new StackFrameReader();
   1602                 reader.attach(filterFrame).makeReturnValueAccessor();
   1603                 final StackFrameWriter writer = new StackFrameWriter();
   1604                 writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
   1605                 copyNext(reader, writer, target.type().ptypes()[0]);
   1606             }
   1607 
   1608             if (range2 != null) {
   1609                 stackFrame.copyRangeTo(targetFrame, range2,
   1610                         range1.numReferences + referencesOffset,
   1611                         range2.numBytes + stackFrameOffset);
   1612             }
   1613 
   1614             target.invoke(targetFrame);
   1615             targetFrame.copyReturnValueTo(stackFrame);
   1616         }
   1617     }
   1618 
   1619     /**
   1620      * Implements MethodHandles.foldArguments.
   1621      */
   1622     static class FoldArguments extends Transformer {
   1623         private final MethodHandle target;
   1624         private final MethodHandle combiner;
   1625 
   1626         private final Range combinerArgs;
   1627         private final Range targetArgs;
   1628 
   1629         private final int referencesOffset;
   1630         private final int stackFrameOffset;
   1631 
   1632         FoldArguments(MethodHandle target, MethodHandle combiner) {
   1633             super(deriveType(target, combiner));
   1634 
   1635             this.target = target;
   1636             this.combiner = combiner;
   1637 
   1638             combinerArgs = Range.all(combiner.type());
   1639             targetArgs = Range.all(type());
   1640 
   1641             final Class<?> combinerRType = combiner.type().rtype();
   1642             if (combinerRType == void.class) {
   1643                 stackFrameOffset = 0;
   1644                 referencesOffset = 0;
   1645             } else if (combinerRType.isPrimitive()) {
   1646                 stackFrameOffset = EmulatedStackFrame.getSize(combinerRType);
   1647                 referencesOffset = 0;
   1648             } else {
   1649                 stackFrameOffset = 0;
   1650                 referencesOffset = 1;
   1651             }
   1652         }
   1653 
   1654         @Override
   1655         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
   1656             // First construct the combiner frame and invoke it.
   1657             EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type());
   1658             stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0);
   1659             combiner.invoke(combinerFrame);
   1660 
   1661             // Create the stack frame for the target.
   1662             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
   1663 
   1664             // If one of these offsets is not zero, we have a return value to copy.
   1665             if (referencesOffset != 0 || stackFrameOffset != 0) {
   1666                 final StackFrameReader reader = new StackFrameReader();
   1667                 reader.attach(combinerFrame).makeReturnValueAccessor();
   1668                 final StackFrameWriter writer = new StackFrameWriter();
   1669                 writer.attach(targetFrame);
   1670                 copyNext(reader, writer, target.type().ptypes()[0]);
   1671             }
   1672 
   1673             stackFrame.copyRangeTo(targetFrame, targetArgs, referencesOffset, stackFrameOffset);
   1674             target.invoke(targetFrame);
   1675 
   1676             targetFrame.copyReturnValueTo(stackFrame);
   1677         }
   1678 
   1679         private static MethodType deriveType(MethodHandle target, MethodHandle combiner) {
   1680             if (combiner.type().rtype() == void.class) {
   1681                 return target.type();
   1682             }
   1683 
   1684             return target.type().dropParameterTypes(0, 1);
   1685         }
   1686     }
   1687 
   1688     /**
   1689      * Implements MethodHandles.insertArguments.
   1690      */
   1691     static class InsertArguments extends Transformer {
   1692         private final MethodHandle target;
   1693         private final int pos;
   1694         private final Object[] values;
   1695 
   1696         private final Range range1;
   1697         private final Range range2;
   1698 
   1699         InsertArguments(MethodHandle target, int pos, Object[] values) {
   1700             super(target.type().dropParameterTypes(pos, pos + values.length));
   1701             this.target = target;
   1702             this.pos = pos;
   1703             this.values = values;
   1704 
   1705             final MethodType type = type();
   1706             range1 = EmulatedStackFrame.Range.of(type, 0, pos);
   1707             range2 = Range.of(type, pos, type.parameterCount());
   1708         }
   1709 
   1710         @Override
   1711         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
   1712             EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
   1713 
   1714             // Copy all arguments before |pos|.
   1715             stackFrame.copyRangeTo(calleeFrame, range1, 0, 0);
   1716 
   1717             // Attach a stack frame writer so that we can copy the next |values.length|
   1718             // arguments.
   1719             final StackFrameWriter writer = new StackFrameWriter();
   1720             writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
   1721 
   1722             // Copy all the arguments supplied in |values|.
   1723             int referencesCopied = 0;
   1724             int bytesCopied = 0;
   1725             final Class<?>[] ptypes = target.type().ptypes();
   1726             for (int i = 0; i < values.length; ++i) {
   1727                 final Class<?> ptype = ptypes[i + pos];
   1728                 if (ptype.isPrimitive()) {
   1729                     if (ptype == boolean.class) {
   1730                         writer.putNextBoolean((boolean) values[i]);
   1731                     } else if (ptype == byte.class) {
   1732                         writer.putNextByte((byte) values[i]);
   1733                     } else if (ptype == char.class) {
   1734                         writer.putNextChar((char) values[i]);
   1735                     } else if (ptype == short.class) {
   1736                         writer.putNextShort((short) values[i]);
   1737                     } else if (ptype == int.class) {
   1738                         writer.putNextInt((int) values[i]);
   1739                     } else if (ptype == long.class) {
   1740                         writer.putNextLong((long) values[i]);
   1741                     } else if (ptype == float.class) {
   1742                         writer.putNextFloat((float) values[i]);
   1743                     } else if (ptype == double.class) {
   1744                         writer.putNextDouble((double) values[i]);
   1745                     }
   1746 
   1747                     bytesCopied += EmulatedStackFrame.getSize(ptype);
   1748                 } else {
   1749                     writer.putNextReference(values[i], ptype);
   1750                     referencesCopied++;
   1751                 }
   1752             }
   1753 
   1754             // Copy all remaining arguments.
   1755             if (range2 != null) {
   1756                 stackFrame.copyRangeTo(calleeFrame, range2,
   1757                         range1.numReferences + referencesCopied,
   1758                         range1.numBytes + bytesCopied);
   1759             }
   1760 
   1761             target.invoke(calleeFrame);
   1762             calleeFrame.copyReturnValueTo(stackFrame);
   1763         }
   1764     }
   1765 
   1766 
   1767     /**
   1768      * Implements {@link java.lang.invokeMethodHandles#explicitCastArguments()}.
   1769      */
   1770     public static class ExplicitCastArguments extends Transformer {
   1771         private final MethodHandle target;
   1772 
   1773         public ExplicitCastArguments(MethodHandle target, MethodType type) {
   1774             super(type);
   1775             this.target = target;
   1776         }
   1777 
   1778         @Override
   1779         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
   1780             // Create a new stack frame for the target.
   1781             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
   1782 
   1783             explicitCastArguments(callerFrame, targetFrame);
   1784             target.invoke(targetFrame);
   1785             explicitCastReturnValue(callerFrame, targetFrame);
   1786         }
   1787 
   1788         private void explicitCastArguments(final EmulatedStackFrame callerFrame,
   1789                                            final EmulatedStackFrame targetFrame) {
   1790             final StackFrameReader reader = new StackFrameReader();
   1791             reader.attach(callerFrame);
   1792             final StackFrameWriter writer = new StackFrameWriter();
   1793             writer.attach(targetFrame);
   1794 
   1795             final Class<?>[] fromTypes = type().ptypes();
   1796             final Class<?>[] toTypes = target.type().ptypes();
   1797             for (int i = 0; i < fromTypes.length; ++i) {
   1798                 explicitCast(reader, fromTypes[i], writer, toTypes[i]);
   1799             }
   1800         }
   1801 
   1802         private void explicitCastReturnValue(final EmulatedStackFrame callerFrame,
   1803                                              final EmulatedStackFrame targetFrame) {
   1804             Class<?> from = target.type().rtype();
   1805             Class<?> to = type().rtype();
   1806             if (to != void.class) {
   1807                 final StackFrameWriter writer = new StackFrameWriter();
   1808                 writer.attach(callerFrame);
   1809                 writer.makeReturnValueAccessor();
   1810                 if (from == void.class) {
   1811                     if (to.isPrimitive()) {
   1812                         unboxNull(writer, to);
   1813                     } else {
   1814                         writer.putNextReference(null, to);
   1815                     }
   1816                 } else {
   1817                     final StackFrameReader reader = new StackFrameReader();
   1818                     reader.attach(targetFrame);
   1819                     reader.makeReturnValueAccessor();
   1820                     explicitCast(reader, target.type().rtype(), writer, type().rtype());
   1821                 }
   1822             }
   1823         }
   1824 
   1825         private static void throwUnexpectedType(final Class<?> unexpectedType) {
   1826             throw new InternalError("Unexpected type: " + unexpectedType);
   1827         }
   1828 
   1829         private static void explicitCastFromBoolean(boolean fromValue,
   1830                                                     final StackFrameWriter writer,
   1831                                                     final Class<?> to) {
   1832             int value = fromValue ? 1 : 0;
   1833             if (to == byte.class) {
   1834                 writer.putNextByte((byte) value);
   1835             } else if (to == char.class) {
   1836                 writer.putNextChar((char) value);
   1837             } else if (to == short.class) {
   1838                 writer.putNextShort((short) value);
   1839             } else if (to == int.class) {
   1840                 writer.putNextInt(value);
   1841             } else if (to == long.class) {
   1842                 writer.putNextLong(value);
   1843             } else if (to == float.class) {
   1844                 writer.putNextFloat(value);
   1845             } else if (to == double.class) {
   1846                 writer.putNextDouble(value);
   1847             } else {
   1848                 throwUnexpectedType(to);
   1849             }
   1850         }
   1851 
   1852         /**
   1853          * Converts byte value to boolean according to
   1854          * {@link java.lang.invoke.MethodHandles#explicitCast()}
   1855          */
   1856         private static boolean toBoolean(byte value) {
   1857             return (value & 1) == 1;
   1858         }
   1859 
   1860         private static byte readPrimitiveAsByte(final StackFrameReader reader,
   1861                                                 final Class<?> from) {
   1862             if (from == byte.class) {
   1863                 return (byte) reader.nextByte();
   1864             } else if (from == char.class) {
   1865                 return (byte) reader.nextChar();
   1866             } else if (from == short.class) {
   1867                 return (byte) reader.nextShort();
   1868             } else if (from == int.class) {
   1869                 return (byte) reader.nextInt();
   1870             } else if (from == long.class) {
   1871                 return (byte) reader.nextLong();
   1872             } else if (from == float.class) {
   1873                 return (byte) reader.nextFloat();
   1874             } else if (from == double.class) {
   1875                 return (byte) reader.nextDouble();
   1876             } else {
   1877                 throwUnexpectedType(from);
   1878                 return 0;
   1879             }
   1880         }
   1881 
   1882         private static char readPrimitiveAsChar(final StackFrameReader reader,
   1883                                                 final Class<?> from) {
   1884             if (from == byte.class) {
   1885                 return (char) reader.nextByte();
   1886             } else if (from == char.class) {
   1887                 return (char) reader.nextChar();
   1888             } else if (from == short.class) {
   1889                 return (char) reader.nextShort();
   1890             } else if (from == int.class) {
   1891                 return (char) reader.nextInt();
   1892             } else if (from == long.class) {
   1893                 return (char) reader.nextLong();
   1894             } else if (from == float.class) {
   1895                 return (char) reader.nextFloat();
   1896             } else if (from == double.class) {
   1897                 return (char) reader.nextDouble();
   1898             } else {
   1899                 throwUnexpectedType(from);
   1900                 return 0;
   1901             }
   1902         }
   1903 
   1904         private static short readPrimitiveAsShort(final StackFrameReader reader,
   1905                                                   final Class<?> from) {
   1906             if (from == byte.class) {
   1907                 return (short) reader.nextByte();
   1908             } else if (from == char.class) {
   1909                 return (short) reader.nextChar();
   1910             } else if (from == short.class) {
   1911                 return (short) reader.nextShort();
   1912             } else if (from == int.class) {
   1913                 return (short) reader.nextInt();
   1914             } else if (from == long.class) {
   1915                 return (short) reader.nextLong();
   1916             } else if (from == float.class) {
   1917                 return (short) reader.nextFloat();
   1918             } else if (from == double.class) {
   1919                 return (short) reader.nextDouble();
   1920             } else {
   1921                 throwUnexpectedType(from);
   1922                 return 0;
   1923             }
   1924         }
   1925 
   1926         private static int readPrimitiveAsInt(final StackFrameReader reader,
   1927                                               final Class<?> from) {
   1928             if (from == byte.class) {
   1929                 return (int) reader.nextByte();
   1930             } else if (from == char.class) {
   1931                 return (int) reader.nextChar();
   1932             } else if (from == short.class) {
   1933                 return (int) reader.nextShort();
   1934             } else if (from == int.class) {
   1935                 return (int) reader.nextInt();
   1936             } else if (from == long.class) {
   1937                 return (int) reader.nextLong();
   1938             } else if (from == float.class) {
   1939                 return (int) reader.nextFloat();
   1940             } else if (from == double.class) {
   1941                 return (int) reader.nextDouble();
   1942             } else {
   1943                 throwUnexpectedType(from);
   1944                 return 0;
   1945             }
   1946         }
   1947 
   1948         private static long readPrimitiveAsLong(final StackFrameReader reader,
   1949                                                 final Class<?> from) {
   1950             if (from == byte.class) {
   1951                 return (long) reader.nextByte();
   1952             } else if (from == char.class) {
   1953                 return (long) reader.nextChar();
   1954             } else if (from == short.class) {
   1955                 return (long) reader.nextShort();
   1956             } else if (from == int.class) {
   1957                 return (long) reader.nextInt();
   1958             } else if (from == long.class) {
   1959                 return (long) reader.nextLong();
   1960             } else if (from == float.class) {
   1961                 return (long) reader.nextFloat();
   1962             } else if (from == double.class) {
   1963                 return (long) reader.nextDouble();
   1964             } else {
   1965                 throwUnexpectedType(from);
   1966                 return 0;
   1967             }
   1968         }
   1969 
   1970         private static float readPrimitiveAsFloat(final StackFrameReader reader,
   1971                                                   final Class<?> from) {
   1972             if (from == byte.class) {
   1973                 return (float) reader.nextByte();
   1974             } else if (from == char.class) {
   1975                 return (float) reader.nextChar();
   1976             } else if (from == short.class) {
   1977                 return (float) reader.nextShort();
   1978             } else if (from == int.class) {
   1979                 return (float) reader.nextInt();
   1980             } else if (from == long.class) {
   1981                 return (float) reader.nextLong();
   1982             } else if (from == float.class) {
   1983                 return (float) reader.nextFloat();
   1984             } else if (from == double.class) {
   1985                 return (float) reader.nextDouble();
   1986             } else {
   1987                 throwUnexpectedType(from);
   1988                 return 0;
   1989             }
   1990         }
   1991 
   1992         private static double readPrimitiveAsDouble(final StackFrameReader reader,
   1993                                                     final Class<?> from) {
   1994             if (from == byte.class) {
   1995                 return (double) reader.nextByte();
   1996             } else if (from == char.class) {
   1997                 return (double) reader.nextChar();
   1998             } else if (from == short.class) {
   1999                 return (double) reader.nextShort();
   2000             } else if (from == int.class) {
   2001                 return (double) reader.nextInt();
   2002             } else if (from == long.class) {
   2003                 return (double) reader.nextLong();
   2004             } else if (from == float.class) {
   2005                 return (double) reader.nextFloat();
   2006             } else if (from == double.class) {
   2007                 return (double) reader.nextDouble();
   2008             } else {
   2009                 throwUnexpectedType(from);
   2010                 return 0;
   2011             }
   2012         }
   2013 
   2014         private static void explicitCastToBoolean(final StackFrameReader reader,
   2015                                                   final Class<?> from,
   2016                                                   final StackFrameWriter writer) {
   2017             byte byteValue = readPrimitiveAsByte(reader, from);
   2018             writer.putNextBoolean(toBoolean(byteValue));
   2019         }
   2020 
   2021         private static void explicitCastPrimitives(final StackFrameReader reader,
   2022                                                    final Class<?> from,
   2023                                                    final StackFrameWriter writer,
   2024                                                    final Class<?> to) {
   2025             if (to == byte.class) {
   2026                 byte value = readPrimitiveAsByte(reader, from);
   2027                 writer.putNextByte(value);
   2028             } else if (to == char.class) {
   2029                 char value = readPrimitiveAsChar(reader, from);
   2030                 writer.putNextChar(value);
   2031             } else if (to == short.class) {
   2032                 short value = readPrimitiveAsShort(reader, from);
   2033                 writer.putNextShort(value);
   2034             } else if (to == int.class) {
   2035                 int value = readPrimitiveAsInt(reader, from);
   2036                 writer.putNextInt(value);
   2037             } else if (to == long.class) {
   2038                 long value = readPrimitiveAsLong(reader, from);
   2039                 writer.putNextLong(value);
   2040             } else if (to == float.class) {
   2041                 float value = readPrimitiveAsFloat(reader, from);
   2042                 writer.putNextFloat(value);
   2043             } else if (to == double.class) {
   2044                 double value = readPrimitiveAsDouble(reader, from);
   2045                 writer.putNextDouble(value);
   2046             } else {
   2047                 throwUnexpectedType(to);
   2048             }
   2049         }
   2050 
   2051         private static void unboxNull(final StackFrameWriter writer, final Class<?> to) {
   2052             if (to == boolean.class) {
   2053                 writer.putNextBoolean(false);
   2054             } else if (to == byte.class) {
   2055                 writer.putNextByte((byte) 0);
   2056             } else if (to == char.class) {
   2057                 writer.putNextChar((char) 0);
   2058             } else if (to == short.class) {
   2059                 writer.putNextShort((short) 0);
   2060             } else if (to == int.class) {
   2061                 writer.putNextInt((int) 0);
   2062             } else if (to == long.class) {
   2063                 writer.putNextLong((long) 0);
   2064             } else if (to == float.class) {
   2065                 writer.putNextFloat((float) 0);
   2066             } else if (to == double.class) {
   2067                 writer.putNextDouble((double) 0);
   2068             } else {
   2069                 throwUnexpectedType(to);
   2070             }
   2071         }
   2072 
   2073         private static void unboxNonNull(final Object ref, final Class<?> from,
   2074                                          final StackFrameWriter writer, final Class<?> to) {
   2075             if (to == boolean.class) {
   2076                 if (from == Boolean.class) {
   2077                     writer.putNextBoolean((boolean) ref);
   2078                 } else if (from == Float.class || from == Double.class) {
   2079                     byte b = (byte) ((double) ref);
   2080                     writer.putNextBoolean(toBoolean(b));
   2081                 } else {
   2082                     byte b = (byte) ((long) ref);
   2083                     writer.putNextBoolean(toBoolean(b));
   2084                 }
   2085             } else if (to == byte.class) {
   2086                 writer.putNextByte((byte) ref);
   2087             } else if (to == char.class) {
   2088                 writer.putNextChar((char) ref);
   2089             } else if (to == short.class) {
   2090                 writer.putNextShort((short) ref);
   2091             } else if (to == int.class) {
   2092                 writer.putNextInt((int) ref);
   2093             } else if (to == long.class) {
   2094                 writer.putNextLong((long) ref);
   2095             } else if (to == float.class) {
   2096                 writer.putNextFloat((float) ref);
   2097             } else if (to == double.class) {
   2098                 writer.putNextDouble((double) ref);
   2099             } else {
   2100                 throwUnexpectedType(to);
   2101             }
   2102         }
   2103 
   2104         private static void unbox(final Object ref, final Class<?> from,
   2105                                   final StackFrameWriter writer, final Class<?> to) {
   2106             if (ref == null) {
   2107                 unboxNull(writer, to);
   2108             } else {
   2109                 unboxNonNull(ref, from, writer, to);
   2110             }
   2111         }
   2112 
   2113         private static void box(final StackFrameReader reader, final Class<?> from,
   2114                                 final StackFrameWriter writer, final Class<?> to) {
   2115             Object boxed = null;
   2116             if (from == boolean.class) {
   2117                 boxed = Boolean.valueOf(reader.nextBoolean());
   2118             } else if (from == byte.class) {
   2119                 boxed = Byte.valueOf(reader.nextByte());
   2120             } else if (from == char.class) {
   2121                 boxed = Character.valueOf(reader.nextChar());
   2122             } else if (from == short.class) {
   2123                 boxed = Short.valueOf(reader.nextShort());
   2124             } else if (from == int.class) {
   2125                 boxed = Integer.valueOf(reader.nextInt());
   2126             } else if (from == long.class) {
   2127                 boxed = Long.valueOf(reader.nextLong());
   2128             } else if (from == float.class) {
   2129                 boxed = Float.valueOf(reader.nextFloat());
   2130             } else if (from == double.class) {
   2131                 boxed = Double.valueOf(reader.nextDouble());
   2132             } else {
   2133                 throwUnexpectedType(from);
   2134             }
   2135             writer.putNextReference(to.cast(boxed), to);
   2136         }
   2137 
   2138         private static void explicitCast(final StackFrameReader reader, final Class<?> from,
   2139                                          final StackFrameWriter writer, final Class<?> to) {
   2140             if (from.equals(to)) {
   2141                 StackFrameAccessor.copyNext(reader, writer, from);
   2142             } else if (!from.isPrimitive()) {
   2143                 Object ref = reader.nextReference(from);
   2144                 if (to.isInterface()) {
   2145                     // Pass from without a cast according to description for
   2146                     // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
   2147                     writer.putNextReference(ref, to);
   2148                 } else if (!to.isPrimitive()) {
   2149                     // |to| is a reference type, perform class cast check.
   2150                     writer.putNextReference(to.cast(ref), to);
   2151                 } else {
   2152                     // |from| is a reference type, |to| is a primitive type,
   2153                     unbox(ref, from, writer, to);
   2154                 }
   2155             } else if (to.isPrimitive()) {
   2156                 // |from| and |to| are primitive types.
   2157                 if (from == boolean.class) {
   2158                     explicitCastFromBoolean(reader.nextBoolean(), writer, to);
   2159                 } else if (to == boolean.class) {
   2160                     explicitCastToBoolean(reader, from, writer);
   2161                 } else {
   2162                     explicitCastPrimitives(reader, from, writer, to);
   2163                 }
   2164             } else {
   2165                 // |from| is a primitive type, |to| is a reference type.
   2166                 box(reader, from, writer, to);
   2167             }
   2168         }
   2169     }
   2170 }
   2171