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 {
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 {
Transformer(MethodType type)58         protected Transformer(MethodType type) {
59             super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type);
60         }
61 
Transformer(MethodType type, int invokeKind)62         protected Transformer(MethodType type, int invokeKind) {
63             super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type);
64         }
65 
66         @Override
clone()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 
AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType)83         public AlwaysThrow(Class<?> nominalReturnType, Class<? extends  Throwable> exType) {
84             super(MethodType.methodType(nominalReturnType, exType));
85             this.exceptionType = exType;
86         }
87 
88         @Override
transform(EmulatedStackFrame emulatedStackFrame)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 
DropArguments(MethodType type, MethodHandle delegate, int startPos, int numDropped)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
transform(EmulatedStackFrame emulatedStackFrame)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 
CatchException(MethodHandle target, MethodHandle handler, Class<?> exType)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
transform(EmulatedStackFrame emulatedStackFrame)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 
GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)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
transform(EmulatedStackFrame emulatedStackFrame)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 
ReferenceArrayElementGetter(Class<?> arrayClass)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
transform(EmulatedStackFrame emulatedStackFrame)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 
ReferenceArrayElementSetter(Class<?> arrayClass)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
transform(EmulatedStackFrame emulatedStackFrame)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 
ReferenceIdentity(Class<?> type)297         public ReferenceIdentity(Class<?> type) {
298             super(MethodType.methodType(type, type));
299             this.type = type;
300         }
301 
302         @Override
transform(EmulatedStackFrame emulatedStackFrame)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 
Constant(Class<?> type, Object value)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
transform(EmulatedStackFrame emulatedStackFrame)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 
Construct(MethodHandle constructorHandle, MethodType returnedType)396         /*package*/ Construct(MethodHandle constructorHandle, MethodType returnedType) {
397             super(returnedType);
398             this.constructorHandle = constructorHandle;
399             this.callerRange = EmulatedStackFrame.Range.all(type());
400         }
401 
getConstructorHandle()402         MethodHandle getConstructorHandle() {
403             return constructorHandle;
404         }
405 
isAbstract(Class<?> klass)406         private static boolean isAbstract(Class<?> klass) {
407             return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
408         }
409 
checkInstantiable(Class<?> klass)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
transform(EmulatedStackFrame emulatedStackFrame)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 
BindTo(MethodHandle delegate, Object receiver)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
transform(EmulatedStackFrame emulatedStackFrame)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 
FilterReturnValue(MethodHandle target, MethodHandle filter)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
transform(EmulatedStackFrame emulatedStackFrame)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 
PermuteArguments(MethodType type, MethodHandle target, int[] reorder)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
transform(EmulatedStackFrame emulatedStackFrame)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 
VarargsCollector(MethodHandle target)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 
lastParameterTypeIsAnArray(Class<?>[] parameterTypes)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
isVarargsCollector()657         public boolean isVarargsCollector() { return true; }
658 
659         @Override
asFixedArity()660         public MethodHandle asFixedArity() { return target; }
661 
662         @Override
transform(EmulatedStackFrame callerFrame)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 
throwWrongMethodTypeException(MethodType from, MethodType to)706         private static void throwWrongMethodTypeException(MethodType from, MethodType to) {
707             throw new WrongMethodTypeException("Cannot convert " + from + " to " + to);
708         }
709 
arityArgumentsConvertible(Class<?>[] ptypes, int arityStart, Class<?> elementType)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 
referenceArray(StackFrameReader reader, Class<?>[] ptypes, Class<?> elementType, int offset, int length)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 
intArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
longArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
byteArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
shortArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
charArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
booleanArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
floatArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
doubleArray(StackFrameReader reader, Class<?> ptypes[], int offset, int length)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 
makeArityArray(MethodType callerFrameType, StackFrameReader callerFrameReader, int indexOfArityArray, Class<?> arityArrayType)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 
collectArguments(char basicComponentType, Class<?> componentType, StackFrameReader reader, Class<?>[] types, int startIdx, int length)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 
copyParameter(StackFrameReader reader, StackFrameWriter writer, Class<?> ptype)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 
prepareFrame(EmulatedStackFrame callerFrame, EmulatedStackFrame targetFrame)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          */
makeTargetFrameType(MethodType callerType, MethodType targetType)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 
Invoker(MethodType targetType, boolean isExactInvoker)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
transform(EmulatedStackFrame emulatedStackFrame)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 
Spreader(MethodHandle target, MethodType spreaderType, int numArrayArgs)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
transform(EmulatedStackFrame callerFrame)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 
spreadArray(Object[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(int[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(long[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(byte[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(short[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(char[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(boolean[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(double[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
spreadArray(float[] array, StackFrameWriter writer, MethodType type, int numArgs, int offset)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 
Collector(MethodHandle delegate, Class<?> arrayType, int length)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
transform(EmulatedStackFrame callerFrame)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 
FilterArguments(MethodHandle target, int pos, MethodHandle[] filters)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 
deriveType(MethodHandle target, int pos, MethodHandle[] filters)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
transform(EmulatedStackFrame stackFrame)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 
CollectArguments(MethodHandle target, MethodHandle collector, int pos, MethodType adapterType)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
transform(EmulatedStackFrame stackFrame)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 
FoldArguments(MethodHandle target, MethodHandle combiner)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
transform(EmulatedStackFrame stackFrame)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 
deriveType(MethodHandle target, MethodHandle combiner)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 
InsertArguments(MethodHandle target, int pos, Object[] values)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
transform(EmulatedStackFrame stackFrame)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 
ExplicitCastArguments(MethodHandle target, MethodType type)1773         public ExplicitCastArguments(MethodHandle target, MethodType type) {
1774             super(type);
1775             this.target = target;
1776         }
1777 
1778         @Override
transform(EmulatedStackFrame callerFrame)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 
explicitCastArguments(final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)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 
explicitCastReturnValue(final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)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 
throwUnexpectedType(final Class<?> unexpectedType)1825         private static void throwUnexpectedType(final Class<?> unexpectedType) {
1826             throw new InternalError("Unexpected type: " + unexpectedType);
1827         }
1828 
explicitCastFromBoolean(boolean fromValue, final StackFrameWriter writer, final Class<?> to)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          */
toBoolean(byte value)1856         private static boolean toBoolean(byte value) {
1857             return (value & 1) == 1;
1858         }
1859 
readPrimitiveAsByte(final StackFrameReader reader, final Class<?> from)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 
readPrimitiveAsChar(final StackFrameReader reader, final Class<?> from)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 
readPrimitiveAsShort(final StackFrameReader reader, final Class<?> from)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 
readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from)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 
readPrimitiveAsLong(final StackFrameReader reader, final Class<?> from)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 
readPrimitiveAsFloat(final StackFrameReader reader, final Class<?> from)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 
readPrimitiveAsDouble(final StackFrameReader reader, final Class<?> from)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 
explicitCastToBoolean(final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer)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 
explicitCastPrimitives(final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)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 
unboxNull(final StackFrameWriter writer, final Class<?> to)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 
unboxNonNull(final Object ref, final Class<?> from, final StackFrameWriter writer, final Class<?> to)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 
unbox(final Object ref, final Class<?> from, final StackFrameWriter writer, final Class<?> to)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 
box(final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)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 
explicitCast(final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)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