1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  The Android Open Source
9  * Project designates this particular file as subject to the "Classpath"
10  * exception as provided by The Android Open Source Project in the LICENSE
11  * file that accompanied this code.
12  *
13  * This code is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  * version 2 for more details (a copy is included in the LICENSE file that
17  * accompanied this code).
18  *
19  * You should have received a copy of the GNU General Public License version
20  * 2 along with this work; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 package java.lang.invoke;
25 
26 import static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext;
27 
28 import dalvik.system.EmulatedStackFrame;
29 import dalvik.system.EmulatedStackFrame.Range;
30 import dalvik.system.EmulatedStackFrame.RandomOrderStackFrameReader;
31 import dalvik.system.EmulatedStackFrame.StackFrameAccessor;
32 import dalvik.system.EmulatedStackFrame.StackFrameReader;
33 import dalvik.system.EmulatedStackFrame.StackFrameWriter;
34 
35 import sun.invoke.util.Wrapper;
36 import sun.misc.Unsafe;
37 
38 import java.lang.reflect.Array;
39 import java.lang.reflect.Method;
40 import java.lang.reflect.Modifier;
41 import java.util.ArrayList;
42 import java.util.List;
43 
44 /** @hide Public for testing only. */
45 public class Transformers {
Transformers()46     private Transformers() {}
47 
48     static {
49         try {
50             TRANSFORM_INTERNAL =
51                     MethodHandle.class.getDeclaredMethod(
52                             "transformInternal", EmulatedStackFrame.class);
53         } catch (NoSuchMethodException nsme) {
54             throw new AssertionError();
55         }
56     }
57 
58     /**
59      * Method reference to the private {@code MethodHandle.transformInternal} method. This is cached
60      * here because it's the point of entry for all transformers.
61      */
62     private static final Method TRANSFORM_INTERNAL;
63 
64     /** @hide */
65     public abstract static class Transformer extends MethodHandle implements Cloneable {
Transformer(MethodType type)66         protected Transformer(MethodType type) {
67             super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type);
68         }
69 
Transformer(MethodType type, int invokeKind)70         protected Transformer(MethodType type, int invokeKind) {
71             super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type);
72         }
73 
74         @Override
clone()75         public Object clone() throws CloneNotSupportedException {
76             return super.clone();
77         }
78 
79         /**
80          * Performs a MethodHandle.invoke() call with arguments held in an
81          * EmulatedStackFrame.
82          * @param target the method handle to invoke
83          * @param stackFrame the stack frame containing arguments for the invocation
84          */
invokeFromTransform(MethodHandle target, EmulatedStackFrame stackFrame)85         protected static void invokeFromTransform(MethodHandle target,
86                                                   EmulatedStackFrame stackFrame) throws Throwable {
87             if (target instanceof Transformer) {
88                 ((Transformer) target).transform(stackFrame);
89             } else {
90                 final MethodHandle adaptedTarget = target.asType(stackFrame.getMethodType());
91                 adaptedTarget.invokeExactWithFrame(stackFrame);
92             }
93         }
94 
95         /**
96          * Performs a MethodHandle.invokeExact() call with arguments held in an
97          * EmulatedStackFrame.
98          * @param target the method handle to invoke
99          * @param stackFrame the stack frame containing arguments for the invocation
100          */
invokeExactFromTransform(MethodHandle target, EmulatedStackFrame stackFrame)101         protected void invokeExactFromTransform(MethodHandle target,
102                                                 EmulatedStackFrame stackFrame) throws Throwable {
103             if (target instanceof Transformer) {
104                 ((Transformer) target).transform(stackFrame);
105             } else {
106                 target.invokeExactWithFrame(stackFrame);
107             }
108         }
109     }
110 
111     /** Implements {@code MethodHandles.throwException}. */
112     static class AlwaysThrow extends Transformer {
113         private final Class<? extends Throwable> exceptionType;
114 
AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType)115         AlwaysThrow(Class<?> nominalReturnType, Class<? extends Throwable> exType) {
116             super(MethodType.methodType(nominalReturnType, exType));
117             this.exceptionType = exType;
118         }
119 
120         @Override
transform(EmulatedStackFrame emulatedStackFrame)121         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
122             throw emulatedStackFrame.getReference(0, exceptionType);
123         }
124     }
125 
126     /** Implements {@code MethodHandles.dropArguments}. */
127     static class DropArguments extends Transformer {
128         private final MethodHandle delegate;
129         private final EmulatedStackFrame.Range range1;
130         private final EmulatedStackFrame.Range range2;
131 
DropArguments(MethodType type, MethodHandle delegate, int startPos, int numDropped)132         DropArguments(MethodType type, MethodHandle delegate, int startPos, int numDropped) {
133             super(type);
134 
135             this.delegate = delegate;
136 
137             // We pre-calculate the ranges of values we have to copy through to the delegate
138             // handle at the time of instantiation so that the actual invoke is performant.
139             this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos);
140             this.range2 = EmulatedStackFrame.Range.from(type, startPos + numDropped);
141         }
142 
143         @Override
transform(EmulatedStackFrame emulatedStackFrame)144         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
145             EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type());
146 
147             emulatedStackFrame.copyRangeTo(
148                     calleeFrame, range1, 0 /* referencesStart */, 0 /* stackFrameStart */);
149             emulatedStackFrame.copyRangeTo(
150                     calleeFrame, range2, range1.numReferences, range1.numBytes);
151 
152             invokeFromTransform(delegate, calleeFrame);
153             calleeFrame.copyReturnValueTo(emulatedStackFrame);
154         }
155     }
156 
157     /** Implements {@code MethodHandles.catchException}. */
158     static class CatchException extends Transformer {
159         private final MethodHandle target;
160         private final MethodHandle handler;
161         private final Class<?> exType;
162 
163         private final EmulatedStackFrame.Range handlerArgsRange;
164 
CatchException(MethodHandle target, MethodHandle handler, Class<?> exType)165         CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) {
166             super(target.type());
167 
168             this.target = target;
169             this.handler = handler;
170             this.exType = exType;
171 
172             // We only copy the first "count" args, dropping others if required. Note that
173             // we subtract one because the first handler arg is the exception thrown by the
174             // target.
175             handlerArgsRange =
176                     EmulatedStackFrame.Range.of(
177                             target.type(), 0, (handler.type().parameterCount() - 1));
178         }
179 
180         @Override
transform(EmulatedStackFrame emulatedStackFrame)181         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
182             try {
183                 invokeFromTransform(target, emulatedStackFrame);
184             } catch (Throwable th) {
185                 if (th.getClass() == exType) {
186                     // We've gotten an exception of the appropriate type, so we need to call
187                     // the handler. Create a new frame of the appropriate size.
188                     EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type());
189 
190                     // The first argument to the handler is the actual exception.
191                     fallback.setReference(0, th);
192 
193                     // We then copy other arguments that need to be passed through to the handler.
194                     // Note that we might drop arguments at the end, if needed. Note that
195                     // referencesStart == 1 because the first argument is the exception type.
196                     emulatedStackFrame.copyRangeTo(
197                             fallback,
198                             handlerArgsRange,
199                             1 /* referencesStart */,
200                             0 /* stackFrameStart */);
201 
202                     // Perform the invoke and return the appropriate value.
203                     invokeFromTransform(handler, fallback);
204                     fallback.copyReturnValueTo(emulatedStackFrame);
205                 } else {
206                     // The exception is not of the expected type, we throw it.
207                     throw th;
208                 }
209             }
210         }
211     }
212 
213     /** Implements {@code MethodHandles.tryFinally}. */
214     static class TryFinally extends Transformer {
215         /** The target handle to try. */
216         private final MethodHandle target;
217 
218         /** The cleanup handle to invoke after the target. */
219         private final MethodHandle cleanup;
220 
TryFinally(MethodHandle target, MethodHandle cleanup)221         TryFinally(MethodHandle target, MethodHandle cleanup) {
222             super(target.type());
223             this.target = target;
224             this.cleanup = cleanup;
225         }
226 
227         @Override
transform(EmulatedStackFrame callerFrame)228         protected void transform(EmulatedStackFrame callerFrame) throws Throwable {
229             Throwable throwable = null;
230             try {
231                 invokeExactFromTransform(target, callerFrame);
232             } catch (Throwable t) {
233                 throwable = t;
234                 throw t;
235             } finally {
236                 final EmulatedStackFrame cleanupFrame = prepareCleanupFrame(callerFrame, throwable);
237                 invokeExactFromTransform(cleanup, cleanupFrame);
238                 if (cleanup.type().returnType() != void.class) {
239                     cleanupFrame.copyReturnValueTo(callerFrame);
240                 }
241             }
242         }
243 
244         /** Prepares the frame used to invoke the cleanup handle. */
prepareCleanupFrame(final EmulatedStackFrame callerFrame, final Throwable throwable)245         private EmulatedStackFrame prepareCleanupFrame(final EmulatedStackFrame callerFrame,
246                                                        final Throwable throwable) {
247             final EmulatedStackFrame cleanupFrame = EmulatedStackFrame.create(cleanup.type());
248             final StackFrameWriter cleanupWriter = new StackFrameWriter();
249             cleanupWriter.attach(cleanupFrame);
250 
251             // The first argument to `cleanup` is (any) pending exception kind.
252             cleanupWriter.putNextReference(throwable, Throwable.class);
253             int added = 1;
254 
255             // The second argument to `cleanup` is the result from `target` (if not void).
256             Class<?> targetReturnType = target.type().returnType();
257             StackFrameReader targetReader = new StackFrameReader();
258             targetReader.attach(callerFrame);
259             if (targetReturnType != void.class) {
260                 targetReader.makeReturnValueAccessor();
261                 copyNext(targetReader, cleanupWriter, targetReturnType);
262                 added += 1;
263                 // Reset `targetReader` to reference the arguments in `callerFrame`.
264                 targetReader.attach(callerFrame);
265             }
266 
267             // The final arguments from the invocation of target. As many are copied as the cleanup
268             // handle expects (it may be fewer than the arguments provided to target).
269             Class<?> [] cleanupTypes = cleanup.type().parameterArray();
270             for (; added != cleanupTypes.length; ++added) {
271                 copyNext(targetReader, cleanupWriter, cleanupTypes[added]);
272             }
273             return cleanupFrame;
274         }
275     }
276 
277     /** Implements {@code MethodHandles.GuardWithTest}. */
278     static class GuardWithTest extends Transformer {
279         private final MethodHandle test;
280         private final MethodHandle target;
281         private final MethodHandle fallback;
282 
283         private final EmulatedStackFrame.Range testArgsRange;
284 
GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback)285         GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
286             super(target.type());
287 
288             this.test = test;
289             this.target = target;
290             this.fallback = fallback;
291 
292             // The test method might have a subset of the arguments of the handle / target.
293             testArgsRange =
294                     EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount());
295         }
296 
297         @Override
transform(EmulatedStackFrame emulatedStackFrame)298         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
299             EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type());
300             emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0);
301 
302             // We know that the return value for test is going to be boolean.class.
303             StackFrameReader reader = new StackFrameReader();
304             reader.attach(testFrame);
305             reader.makeReturnValueAccessor();
306             invokeFromTransform(test, testFrame);
307             final boolean testResult = (boolean) reader.nextBoolean();
308             if (testResult) {
309                 invokeFromTransform(target, emulatedStackFrame);
310             } else {
311                 invokeFromTransform(fallback, emulatedStackFrame);
312             }
313         }
314     }
315 
316     /** Implements {@code MethodHandles.arrayElementGetter}. */
317     static class ReferenceArrayElementGetter extends Transformer {
318         private final Class<?> arrayClass;
319 
ReferenceArrayElementGetter(Class<?> arrayClass)320         ReferenceArrayElementGetter(Class<?> arrayClass) {
321             super(
322                     MethodType.methodType(
323                             arrayClass.getComponentType(), new Class<?>[] {arrayClass, int.class}));
324             this.arrayClass = arrayClass;
325         }
326 
327         @Override
transform(EmulatedStackFrame emulatedStackFrame)328         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
329             final StackFrameReader reader = new StackFrameReader();
330             reader.attach(emulatedStackFrame);
331 
332             // Read the array object and the index from the stack frame.
333             final Object[] array = (Object[]) reader.nextReference(arrayClass);
334             final int index = reader.nextInt();
335 
336             // Write the array element back to the stack frame.
337             final StackFrameWriter writer = new StackFrameWriter();
338             writer.attach(emulatedStackFrame);
339             writer.makeReturnValueAccessor();
340             writer.putNextReference(array[index], arrayClass.getComponentType());
341         }
342     }
343 
344     /** Implements {@code MethodHandles.arrayElementSetter}. */
345     static class ReferenceArrayElementSetter extends Transformer {
346         private final Class<?> arrayClass;
347 
ReferenceArrayElementSetter(Class<?> arrayClass)348         ReferenceArrayElementSetter(Class<?> arrayClass) {
349             super(
350                     MethodType.methodType(
351                             void.class,
352                             new Class<?>[] {arrayClass, int.class, arrayClass.getComponentType()}));
353             this.arrayClass = arrayClass;
354         }
355 
356         @Override
transform(EmulatedStackFrame emulatedStackFrame)357         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
358             final StackFrameReader reader = new StackFrameReader();
359             reader.attach(emulatedStackFrame);
360 
361             // Read the array object, index and the value to write from the stack frame.
362             final Object[] array = (Object[]) reader.nextReference(arrayClass);
363             final int index = reader.nextInt();
364             final Object value = reader.nextReference(arrayClass.getComponentType());
365 
366             array[index] = value;
367         }
368     }
369 
370     /** Implements {@code MethodHandles.identity}. */
371     static class ReferenceIdentity extends Transformer {
372         private final Class<?> type;
373 
ReferenceIdentity(Class<?> type)374         ReferenceIdentity(Class<?> type) {
375             super(MethodType.methodType(type, type));
376             this.type = type;
377         }
378 
379         @Override
transform(EmulatedStackFrame emulatedStackFrame)380         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
381             final StackFrameReader reader = new StackFrameReader();
382             reader.attach(emulatedStackFrame);
383 
384             final StackFrameWriter writer = new StackFrameWriter();
385             writer.attach(emulatedStackFrame);
386             writer.makeReturnValueAccessor();
387             writer.putNextReference(reader.nextReference(type), type);
388         }
389     }
390 
391     /** Implements {@code MethodHandles.makeZero}. */
392     static class ZeroValue extends Transformer {
ZeroValue(Class<?> type)393         public ZeroValue(Class<?> type) {
394             super(MethodType.methodType(type));
395         }
396 
397         @Override
transform(EmulatedStackFrame emulatedStackFrame)398         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
399             // Return-value is zero-initialized in emulatedStackFrame.
400         }
401     }
402 
403     /** Implements {@code MethodHandles.arrayConstructor}. */
404     static class ArrayConstructor extends Transformer {
405         private final Class<?> componentType;
406 
ArrayConstructor(Class<?> arrayType)407         ArrayConstructor(Class<?> arrayType) {
408             super(MethodType.methodType(arrayType, int.class));
409             componentType = arrayType.getComponentType();
410         }
411 
412         @Override
transform(EmulatedStackFrame emulatedStackFrame)413         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
414             final StackFrameReader reader = new StackFrameReader();
415             reader.attach(emulatedStackFrame);
416             final int length = reader.nextInt();
417             final Object array = Array.newInstance(componentType, length);
418             emulatedStackFrame.setReturnValueTo(array);
419         }
420     }
421 
422     /** Implements {@code MethodHandles.arrayLength}. */
423     static class ArrayLength extends Transformer {
424         private final Class<?> arrayType;
425 
ArrayLength(Class<?> arrayType)426         ArrayLength(Class<?> arrayType) {
427             super(MethodType.methodType(int.class, arrayType));
428             this.arrayType = arrayType;
429         }
430 
431         @Override
transform(EmulatedStackFrame emulatedStackFrame)432         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
433             final StackFrameReader reader = new StackFrameReader();
434             reader.attach(emulatedStackFrame);
435             final Object arrayObject = reader.nextReference(arrayType);
436 
437             int length;
438             switch (Wrapper.basicTypeChar(arrayType.getComponentType())) {
439                 case 'L':
440                     length = ((Object[]) arrayObject).length;
441                     break;
442                 case 'Z':
443                     length = ((boolean[]) arrayObject).length;
444                     break;
445                 case 'B':
446                     length = ((byte[]) arrayObject).length;
447                     break;
448                 case 'C':
449                     length = ((char[]) arrayObject).length;
450                     break;
451                 case 'S':
452                     length = ((short[]) arrayObject).length;
453                     break;
454                 case 'I':
455                     length = ((int[]) arrayObject).length;
456                     break;
457                 case 'J':
458                     length = ((long[]) arrayObject).length;
459                     break;
460                 case 'F':
461                     length = ((float[]) arrayObject).length;
462                     break;
463                 case 'D':
464                     length = ((double[]) arrayObject).length;
465                     break;
466                 default:
467                     throw new IllegalStateException("Unsupported type: " + arrayType);
468             }
469 
470             final StackFrameWriter writer = new StackFrameWriter();
471             writer.attach(emulatedStackFrame).makeReturnValueAccessor();
472             writer.putNextInt(length);
473         }
474     }
475 
476     /** Implements {@code MethodHandles.createMethodHandleForConstructor}. */
477     static class Construct extends Transformer {
478         private final MethodHandle constructorHandle;
479         private final EmulatedStackFrame.Range callerRange;
480 
Construct(MethodHandle constructorHandle, MethodType returnedType)481         Construct(MethodHandle constructorHandle, MethodType returnedType) {
482             super(returnedType);
483             this.constructorHandle = constructorHandle;
484             this.callerRange = EmulatedStackFrame.Range.all(type());
485         }
486 
getConstructorHandle()487         MethodHandle getConstructorHandle() {
488             return constructorHandle;
489         }
490 
isAbstract(Class<?> klass)491         private static boolean isAbstract(Class<?> klass) {
492             return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
493         }
494 
checkInstantiable(Class<?> klass)495         private static void checkInstantiable(Class<?> klass) throws InstantiationException {
496             if (isAbstract(klass)) {
497                 String s = klass.isInterface() ? "interface " : "abstract class ";
498                 throw new InstantiationException("Can't instantiate " + s + klass);
499             }
500         }
501 
502         @Override
transform(EmulatedStackFrame emulatedStackFrame)503         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
504             final Class<?> receiverType = constructorHandle.type().parameterType(0);
505             checkInstantiable(receiverType);
506 
507             // Allocate memory for receiver.
508             Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType);
509 
510             // The MethodHandle type for the caller has the form of
511             // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of
512             // the form {rtype=void,ptypes=T,A1...An}. So the frame for
513             // the constructor needs to have a slot with the receiver
514             // in position 0.
515             EmulatedStackFrame constructorFrame =
516                     EmulatedStackFrame.create(constructorHandle.type());
517             constructorFrame.setReference(0, receiver);
518             emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0);
519             invokeExactFromTransform(constructorHandle, constructorFrame);
520 
521             // Set return result for caller.
522             emulatedStackFrame.setReturnValueTo(receiver);
523         }
524     }
525 
526     /** Implements {@code MethodHandle.bindTo}. */
527     static class BindTo extends Transformer {
528         private final MethodHandle delegate;
529         private final Object receiver;
530 
531         private final EmulatedStackFrame.Range range;
532 
BindTo(MethodHandle delegate, Object receiver)533         BindTo(MethodHandle delegate, Object receiver) {
534             super(delegate.type().dropParameterTypes(0, 1));
535 
536             this.delegate = delegate;
537             this.receiver = receiver;
538 
539             this.range = EmulatedStackFrame.Range.all(this.type());
540         }
541 
542         @Override
transform(EmulatedStackFrame emulatedStackFrame)543         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
544             // Create a new emulated stack frame with the full type (including the leading
545             // receiver reference).
546             EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type());
547 
548             // The first reference argument must be the receiver.
549             stackFrame.setReference(0, receiver);
550             // Copy all other arguments.
551             emulatedStackFrame.copyRangeTo(
552                     stackFrame, range, 1 /* referencesStart */, 0 /* stackFrameStart */);
553 
554             // Perform the invoke.
555             invokeFromTransform(delegate, stackFrame);
556             stackFrame.copyReturnValueTo(emulatedStackFrame);
557         }
558     }
559 
560     /** Implements {@code MethodHandle.filterReturnValue}. */
561     static class FilterReturnValue extends Transformer {
562         private final MethodHandle target;
563         private final MethodHandle filter;
564 
565         private final EmulatedStackFrame.Range allArgs;
566 
FilterReturnValue(MethodHandle target, MethodHandle filter)567         FilterReturnValue(MethodHandle target, MethodHandle filter) {
568             super(MethodType.methodType(filter.type().rtype(), target.type().ptypes()));
569 
570             this.target = target;
571             this.filter = filter;
572 
573             allArgs = EmulatedStackFrame.Range.all(type());
574         }
575 
576         @Override
transform(EmulatedStackFrame emulatedStackFrame)577         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
578             // Create a new frame with the target's type and copy all arguments over.
579             // This frame differs in return type with |emulatedStackFrame| but will have
580             // the same parameter shapes.
581             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
582             emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0);
583             invokeFromTransform(target, targetFrame);
584 
585             // Create an emulated frame for the filter and move the return value from
586             // target to the argument of the filter.
587             final EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
588             final Class<?> filterArgumentType = target.type().rtype();
589             if (filterArgumentType != void.class) {
590                 final StackFrameReader returnValueReader = new StackFrameReader();
591                 returnValueReader.attach(targetFrame).makeReturnValueAccessor();
592 
593                 final StackFrameWriter filterWriter = new StackFrameWriter();
594                 filterWriter.attach(filterFrame);
595                 StackFrameAccessor.copyNext(returnValueReader, filterWriter, filterArgumentType);
596             }
597 
598             // Invoke the filter and copy its return value back to the original frame.
599             invokeExactFromTransform(filter, filterFrame);
600             filterFrame.copyReturnValueTo(emulatedStackFrame);
601         }
602     }
603 
604     /** Implements {@code MethodHandles.permuteArguments}. */
605     static class PermuteArguments extends Transformer {
606         private final MethodHandle target;
607         private final int[] reorder;
608 
PermuteArguments(MethodType type, MethodHandle target, int[] reorder)609         PermuteArguments(MethodType type, MethodHandle target, int[] reorder) {
610             super(type);
611 
612             this.target = target;
613             this.reorder = reorder;
614         }
615 
616         @Override
transform(EmulatedStackFrame emulatedStackFrame)617         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
618             final RandomOrderStackFrameReader reader = new RandomOrderStackFrameReader();
619             reader.attach(emulatedStackFrame);
620 
621             final EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
622             final StackFrameWriter writer = new StackFrameWriter();
623             writer.attach(calleeFrame);
624 
625             final Class<?> [] ptypes = emulatedStackFrame.getMethodType().parameterArray();
626             for (int i = 0; i < reorder.length; ++i) {
627                 final int readerIndex = reorder[i];
628                 reader.moveTo(readerIndex);
629                 StackFrameAccessor.copyNext(reader, writer, ptypes[readerIndex]);
630             }
631 
632             invokeFromTransform(target, calleeFrame);
633             calleeFrame.copyReturnValueTo(emulatedStackFrame);
634         }
635     }
636 
637     /** Implements {@code MethodHandle.asVarargsCollector}. */
638     static class VarargsCollector extends Transformer {
639         final MethodHandle target;
640         private final Class<?> arrayType;
641 
VarargsCollector(MethodHandle target)642         VarargsCollector(MethodHandle target) {
643             super(target.type());
644 
645             Class<?>[] parameterTypes = target.type().ptypes();
646             if (!lastParameterTypeIsAnArray(parameterTypes)) {
647                 throw new IllegalArgumentException("target does not have array as last parameter");
648             }
649             this.target = target;
650             this.arrayType = parameterTypes[parameterTypes.length - 1];
651         }
652 
lastParameterTypeIsAnArray(Class<?>[] parameterTypes)653         private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) {
654             if (parameterTypes.length == 0) return false;
655             return parameterTypes[parameterTypes.length - 1].isArray();
656         }
657 
658         @Override
isVarargsCollector()659         public boolean isVarargsCollector() {
660             return true;
661         }
662 
663         @Override
asFixedArity()664         public MethodHandle asFixedArity() {
665             return target;
666         }
667 
668         @Override
asTypeUncached(MethodType newType)669         MethodHandle asTypeUncached(MethodType newType) {
670             // asType() behavior is specialized per:
671             //
672             // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/invoke/MethodHandle.html#asVarargsCollector(java.lang.Class)
673             //
674             // "The behavior of asType is also specialized for variable arity adapters, to maintain
675             //  the invariant that plain, inexact invoke is always equivalent to an asType call to
676             //  adjust the target type, followed by invokeExact. Therefore, a variable arity
677             //  adapter responds to an asType request by building a fixed arity collector, if and
678             //  only if the adapter and requested type differ either in arity or trailing argument
679             //  type. The resulting fixed arity collector has its type further adjusted
680             //  (if necessary) to the requested type by pairwise conversion, as if by another
681             //  application of asType."
682             final MethodType currentType = type();
683             final MethodHandle currentFixedArity = asFixedArity();
684             if (currentType.parameterCount() == newType.parameterCount()
685                     && currentType
686                             .lastParameterType()
687                             .isAssignableFrom(newType.lastParameterType())) {
688                 return asTypeCache = currentFixedArity.asType(newType);
689             }
690 
691             final int arrayLength = newType.parameterCount() - currentType.parameterCount() + 1;
692             if (arrayLength < 0) {
693                 // arrayType is definitely array per VarargsCollector constructor.
694                 throwWrongMethodTypeException(currentType, newType);
695             }
696 
697             MethodHandle collector = null;
698             try {
699                 collector = currentFixedArity.asCollector(arrayType, arrayLength).asType(newType);
700             } catch (IllegalArgumentException ex) {
701                 throwWrongMethodTypeException(currentType, newType);
702             }
703             return asTypeCache = collector;
704         }
705 
706         @Override
transform(EmulatedStackFrame callerFrame)707         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
708             MethodType callerFrameType = callerFrame.getMethodType();
709             Class<?>[] callerPTypes = callerFrameType.ptypes();
710             Class<?>[] targetPTypes = type().ptypes();
711 
712             int lastTargetIndex = targetPTypes.length - 1;
713             if (callerPTypes.length == targetPTypes.length
714                     && targetPTypes[lastTargetIndex].isAssignableFrom(
715                             callerPTypes[lastTargetIndex])) {
716                 // Caller frame matches target frame in the arity array parameter. Invoke
717                 // immediately, and let the invoke() dispatch perform any necessary conversions
718                 // on the other parameters present.
719                 invokeFromTransform(target, callerFrame);
720                 return;
721             }
722 
723             if (callerPTypes.length < targetPTypes.length - 1) {
724                 // Too few arguments to be compatible with variable arity invocation.
725                 throwWrongMethodTypeException(callerFrameType, type());
726             }
727 
728             if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) {
729                 // Incompatible return type.
730                 throwWrongMethodTypeException(callerFrameType, type());
731             }
732 
733             Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType();
734             if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) {
735                 // Wrong types to be compatible with variable arity invocation.
736                 throwWrongMethodTypeException(callerFrameType, type());
737             }
738 
739             // Allocate targetFrame.
740             MethodType targetFrameType = makeTargetFrameType(callerFrameType, type());
741             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType);
742             prepareFrame(callerFrame, targetFrame);
743 
744             // Invoke target.
745             invokeExactFromTransform(target, targetFrame);
746 
747             // Copy return value to the caller's frame.
748             targetFrame.copyReturnValueTo(callerFrame);
749         }
750 
751         @Override
withVarargs(boolean makeVarargs)752         public MethodHandle withVarargs(boolean makeVarargs) {
753             return makeVarargs ? this : target;
754         }
755 
throwWrongMethodTypeException(MethodType from, MethodType to)756         private static void throwWrongMethodTypeException(MethodType from, MethodType to) {
757             throw new WrongMethodTypeException("Cannot convert " + from + " to " + to);
758         }
759 
arityArgumentsConvertible( Class<?>[] ptypes, int arityStart, Class<?> elementType)760         private static boolean arityArgumentsConvertible(
761                 Class<?>[] ptypes, int arityStart, Class<?> elementType) {
762             if (ptypes.length - 1 == arityStart) {
763                 if (ptypes[arityStart].isArray()
764                         && ptypes[arityStart].getComponentType() == elementType) {
765                     // The last ptype is in the same position as the arity
766                     // array and has the same type.
767                     return true;
768                 }
769             }
770 
771             for (int i = arityStart; i < ptypes.length; ++i) {
772                 if (!MethodType.canConvert(ptypes[i], elementType)) {
773                     return false;
774                 }
775             }
776             return true;
777         }
778 
referenceArray( StackFrameReader reader, Class<?>[] ptypes, Class<?> elementType, int offset, int length)779         private static Object referenceArray(
780                 StackFrameReader reader,
781                 Class<?>[] ptypes,
782                 Class<?> elementType,
783                 int offset,
784                 int length) {
785             Object arityArray = Array.newInstance(elementType, length);
786             for (int i = 0; i < length; ++i) {
787                 Class<?> argumentType = ptypes[i + offset];
788                 Object o = null;
789                 switch (Wrapper.basicTypeChar(argumentType)) {
790                     case 'L':
791                         o = reader.nextReference(argumentType);
792                         break;
793                     case 'I':
794                         o = reader.nextInt();
795                         break;
796                     case 'J':
797                         o = reader.nextLong();
798                         break;
799                     case 'B':
800                         o = reader.nextByte();
801                         break;
802                     case 'S':
803                         o = reader.nextShort();
804                         break;
805                     case 'C':
806                         o = reader.nextChar();
807                         break;
808                     case 'Z':
809                         o = reader.nextBoolean();
810                         break;
811                     case 'F':
812                         o = reader.nextFloat();
813                         break;
814                     case 'D':
815                         o = reader.nextDouble();
816                         break;
817                 }
818                 Array.set(arityArray, i, elementType.cast(o));
819             }
820             return arityArray;
821         }
822 
intArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)823         private static Object intArray(
824                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
825             int[] arityArray = new int[length];
826             for (int i = 0; i < length; ++i) {
827                 Class<?> argumentType = ptypes[i + offset];
828                 switch (Wrapper.basicTypeChar(argumentType)) {
829                     case 'I':
830                         arityArray[i] = reader.nextInt();
831                         break;
832                     case 'S':
833                         arityArray[i] = reader.nextShort();
834                         break;
835                     case 'B':
836                         arityArray[i] = reader.nextByte();
837                         break;
838                     default:
839                         arityArray[i] = (Integer) reader.nextReference(argumentType);
840                         break;
841                 }
842             }
843             return arityArray;
844         }
845 
longArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)846         private static Object longArray(
847                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
848             long[] arityArray = new long[length];
849             for (int i = 0; i < length; ++i) {
850                 Class<?> argumentType = ptypes[i + offset];
851                 switch (Wrapper.basicTypeChar(argumentType)) {
852                     case 'J':
853                         arityArray[i] = reader.nextLong();
854                         break;
855                     case 'I':
856                         arityArray[i] = reader.nextInt();
857                         break;
858                     case 'S':
859                         arityArray[i] = reader.nextShort();
860                         break;
861                     case 'B':
862                         arityArray[i] = reader.nextByte();
863                         break;
864                     default:
865                         arityArray[i] = (Long) reader.nextReference(argumentType);
866                         break;
867                 }
868             }
869             return arityArray;
870         }
871 
byteArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)872         private static Object byteArray(
873                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
874             byte[] arityArray = new byte[length];
875             for (int i = 0; i < length; ++i) {
876                 Class<?> argumentType = ptypes[i + offset];
877                 switch (Wrapper.basicTypeChar(argumentType)) {
878                     case 'B':
879                         arityArray[i] = reader.nextByte();
880                         break;
881                     default:
882                         arityArray[i] = (Byte) reader.nextReference(argumentType);
883                         break;
884                 }
885             }
886             return arityArray;
887         }
888 
shortArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)889         private static Object shortArray(
890                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
891             short[] arityArray = new short[length];
892             for (int i = 0; i < length; ++i) {
893                 Class<?> argumentType = ptypes[i + offset];
894                 switch (Wrapper.basicTypeChar(argumentType)) {
895                     case 'S':
896                         arityArray[i] = reader.nextShort();
897                         break;
898                     case 'B':
899                         arityArray[i] = reader.nextByte();
900                         break;
901                     default:
902                         arityArray[i] = (Short) reader.nextReference(argumentType);
903                         break;
904                 }
905             }
906             return arityArray;
907         }
908 
charArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)909         private static Object charArray(
910                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
911             char[] arityArray = new char[length];
912             for (int i = 0; i < length; ++i) {
913                 Class<?> argumentType = ptypes[i + offset];
914                 switch (Wrapper.basicTypeChar(argumentType)) {
915                     case 'C':
916                         arityArray[i] = reader.nextChar();
917                         break;
918                     default:
919                         arityArray[i] = (Character) reader.nextReference(argumentType);
920                         break;
921                 }
922             }
923             return arityArray;
924         }
925 
booleanArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)926         private static Object booleanArray(
927                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
928             boolean[] arityArray = new boolean[length];
929             for (int i = 0; i < length; ++i) {
930                 Class<?> argumentType = ptypes[i + offset];
931                 switch (Wrapper.basicTypeChar(argumentType)) {
932                     case 'Z':
933                         arityArray[i] = reader.nextBoolean();
934                         break;
935                     default:
936                         arityArray[i] = (Boolean) reader.nextReference(argumentType);
937                         break;
938                 }
939             }
940             return arityArray;
941         }
942 
floatArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)943         private static Object floatArray(
944                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
945             float[] arityArray = new float[length];
946             for (int i = 0; i < length; ++i) {
947                 Class<?> argumentType = ptypes[i + offset];
948                 switch (Wrapper.basicTypeChar(argumentType)) {
949                     case 'F':
950                         arityArray[i] = reader.nextFloat();
951                         break;
952                     case 'J':
953                         arityArray[i] = reader.nextLong();
954                         break;
955                     case 'I':
956                         arityArray[i] = reader.nextInt();
957                         break;
958                     case 'S':
959                         arityArray[i] = reader.nextShort();
960                         break;
961                     case 'B':
962                         arityArray[i] = reader.nextByte();
963                         break;
964                     default:
965                         arityArray[i] = (Float) reader.nextReference(argumentType);
966                         break;
967                 }
968             }
969             return arityArray;
970         }
971 
doubleArray( StackFrameReader reader, Class<?> ptypes[], int offset, int length)972         private static Object doubleArray(
973                 StackFrameReader reader, Class<?> ptypes[], int offset, int length) {
974             double[] arityArray = new double[length];
975             for (int i = 0; i < length; ++i) {
976                 Class<?> argumentType = ptypes[i + offset];
977                 switch (Wrapper.basicTypeChar(argumentType)) {
978                     case 'D':
979                         arityArray[i] = reader.nextDouble();
980                         break;
981                     case 'F':
982                         arityArray[i] = reader.nextFloat();
983                         break;
984                     case 'J':
985                         arityArray[i] = reader.nextLong();
986                         break;
987                     case 'I':
988                         arityArray[i] = reader.nextInt();
989                         break;
990                     case 'S':
991                         arityArray[i] = reader.nextShort();
992                         break;
993                     case 'B':
994                         arityArray[i] = reader.nextByte();
995                         break;
996                     default:
997                         arityArray[i] = (Double) reader.nextReference(argumentType);
998                         break;
999                 }
1000             }
1001             return arityArray;
1002         }
1003 
makeArityArray( MethodType callerFrameType, StackFrameReader callerFrameReader, int indexOfArityArray, Class<?> arityArrayType)1004         private static Object makeArityArray(
1005                 MethodType callerFrameType,
1006                 StackFrameReader callerFrameReader,
1007                 int indexOfArityArray,
1008                 Class<?> arityArrayType) {
1009             int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray;
1010             Class<?> elementType = arityArrayType.getComponentType();
1011             Class<?>[] callerPTypes = callerFrameType.ptypes();
1012 
1013             char elementBasicType = Wrapper.basicTypeChar(elementType);
1014             switch (elementBasicType) {
1015                 case 'L':
1016                     return referenceArray(
1017                             callerFrameReader,
1018                             callerPTypes,
1019                             elementType,
1020                             indexOfArityArray,
1021                             arityArrayLength);
1022                 case 'I':
1023                     return intArray(
1024                             callerFrameReader, callerPTypes,
1025                             indexOfArityArray, arityArrayLength);
1026                 case 'J':
1027                     return longArray(
1028                             callerFrameReader, callerPTypes,
1029                             indexOfArityArray, arityArrayLength);
1030                 case 'B':
1031                     return byteArray(
1032                             callerFrameReader, callerPTypes,
1033                             indexOfArityArray, arityArrayLength);
1034                 case 'S':
1035                     return shortArray(
1036                             callerFrameReader, callerPTypes,
1037                             indexOfArityArray, arityArrayLength);
1038                 case 'C':
1039                     return charArray(
1040                             callerFrameReader, callerPTypes,
1041                             indexOfArityArray, arityArrayLength);
1042                 case 'Z':
1043                     return booleanArray(
1044                             callerFrameReader, callerPTypes,
1045                             indexOfArityArray, arityArrayLength);
1046                 case 'F':
1047                     return floatArray(
1048                             callerFrameReader, callerPTypes,
1049                             indexOfArityArray, arityArrayLength);
1050                 case 'D':
1051                     return doubleArray(
1052                             callerFrameReader, callerPTypes,
1053                             indexOfArityArray, arityArrayLength);
1054             }
1055             throw new InternalError("Unexpected type: " + elementType);
1056         }
1057 
collectArguments( char basicComponentType, Class<?> componentType, StackFrameReader reader, Class<?>[] types, int startIdx, int length)1058         public static Object collectArguments(
1059                 char basicComponentType,
1060                 Class<?> componentType,
1061                 StackFrameReader reader,
1062                 Class<?>[] types,
1063                 int startIdx,
1064                 int length) {
1065             switch (basicComponentType) {
1066                 case 'L':
1067                     return referenceArray(reader, types, componentType, startIdx, length);
1068                 case 'I':
1069                     return intArray(reader, types, startIdx, length);
1070                 case 'J':
1071                     return longArray(reader, types, startIdx, length);
1072                 case 'B':
1073                     return byteArray(reader, types, startIdx, length);
1074                 case 'S':
1075                     return shortArray(reader, types, startIdx, length);
1076                 case 'C':
1077                     return charArray(reader, types, startIdx, length);
1078                 case 'Z':
1079                     return booleanArray(reader, types, startIdx, length);
1080                 case 'F':
1081                     return floatArray(reader, types, startIdx, length);
1082                 case 'D':
1083                     return doubleArray(reader, types, startIdx, length);
1084             }
1085             throw new InternalError("Unexpected type: " + basicComponentType);
1086         }
1087 
copyParameter( StackFrameReader reader, StackFrameWriter writer, Class<?> ptype)1088         private static void copyParameter(
1089                 StackFrameReader reader, StackFrameWriter writer, Class<?> ptype) {
1090             switch (Wrapper.basicTypeChar(ptype)) {
1091                 case 'L':
1092                     writer.putNextReference(reader.nextReference(ptype), ptype);
1093                     break;
1094                 case 'I':
1095                     writer.putNextInt(reader.nextInt());
1096                     break;
1097                 case 'J':
1098                     writer.putNextLong(reader.nextLong());
1099                     break;
1100                 case 'B':
1101                     writer.putNextByte(reader.nextByte());
1102                     break;
1103                 case 'S':
1104                     writer.putNextShort(reader.nextShort());
1105                     break;
1106                 case 'C':
1107                     writer.putNextChar(reader.nextChar());
1108                     break;
1109                 case 'Z':
1110                     writer.putNextBoolean(reader.nextBoolean());
1111                     break;
1112                 case 'F':
1113                     writer.putNextFloat(reader.nextFloat());
1114                     break;
1115                 case 'D':
1116                     writer.putNextDouble(reader.nextDouble());
1117                     break;
1118                 default:
1119                     throw new InternalError("Unexpected type: " + ptype);
1120             }
1121         }
1122 
prepareFrame( EmulatedStackFrame callerFrame, EmulatedStackFrame targetFrame)1123         private static void prepareFrame(
1124                 EmulatedStackFrame callerFrame, EmulatedStackFrame targetFrame) {
1125             StackFrameWriter targetWriter = new StackFrameWriter();
1126             targetWriter.attach(targetFrame);
1127             StackFrameReader callerReader = new StackFrameReader();
1128             callerReader.attach(callerFrame);
1129 
1130             // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array.
1131             MethodType targetMethodType = targetFrame.getMethodType();
1132             int indexOfArityArray = targetMethodType.ptypes().length - 1;
1133             for (int i = 0; i < indexOfArityArray; ++i) {
1134                 Class<?> ptype = targetMethodType.ptypes()[i];
1135                 copyParameter(callerReader, targetWriter, ptype);
1136             }
1137 
1138             // Add arity array as last parameter in |targetFrame|.
1139             Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray];
1140             Object arityArray =
1141                     makeArityArray(
1142                             callerFrame.getMethodType(),
1143                             callerReader,
1144                             indexOfArityArray,
1145                             arityArrayType);
1146             targetWriter.putNextReference(arityArray, arityArrayType);
1147         }
1148 
1149         /**
1150          * Computes the frame type to invoke the target method handle with. This is the same as the
1151          * caller frame type, but with the trailing argument being the array type that is the
1152          * trailing argument in the target method handle.
1153          *
1154          * <p>Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC
1155          * then the constructed type is (C0, C1, T2[])RC.
1156          */
makeTargetFrameType( MethodType callerType, MethodType targetType)1157         private static MethodType makeTargetFrameType(
1158                 MethodType callerType, MethodType targetType) {
1159             final int ptypesLength = targetType.ptypes().length;
1160             final Class<?>[] ptypes = new Class<?>[ptypesLength];
1161             // Copy types from caller types to new methodType.
1162             System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1);
1163             // Set the last element in the type array to be the
1164             // varargs array of the target.
1165             ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1];
1166             return MethodType.methodType(callerType.rtype(), ptypes);
1167         }
1168     }
1169 
1170     /** Implements {@code MethodHandles.invoker} and {@code MethodHandles.exactInvoker}. */
1171     static class Invoker extends Transformer {
1172         private final MethodType targetType;
1173         private final boolean isExactInvoker;
1174         private final EmulatedStackFrame.Range copyRange;
1175 
Invoker(MethodType targetType, boolean isExactInvoker)1176         Invoker(MethodType targetType, boolean isExactInvoker) {
1177             super(targetType.insertParameterTypes(0, MethodHandle.class));
1178             this.targetType = targetType;
1179             this.isExactInvoker = isExactInvoker;
1180             copyRange = EmulatedStackFrame.Range.from(type(), 1);
1181         }
1182 
1183         @Override
transform(EmulatedStackFrame emulatedStackFrame)1184         public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
1185             // The first argument to the stack frame is the handle that needs to be invoked.
1186             MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class);
1187 
1188             // All other arguments must be copied to the target frame.
1189             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType);
1190             emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
1191 
1192             // Finally, invoke the handle and copy the return value.
1193             if (isExactInvoker) {
1194                 invokeExactFromTransform(target, targetFrame);
1195             } else {
1196                 invokeFromTransform(target, targetFrame);
1197             }
1198             targetFrame.copyReturnValueTo(emulatedStackFrame);
1199         }
1200 
1201         /**
1202          * Checks whether two method types are compatible as an exact match. The exact match is
1203          * based on the erased form (all reference types treated as Object).
1204          *
1205          * @param callsiteType the MethodType associated with the invocation.
1206          * @param targetType the MethodType of the MethodHandle being invoked.
1207          * @return true if {@code callsiteType} and {@code targetType} are an exact match.
1208          */
exactMatch(MethodType callsiteType, MethodType targetType)1209         private static boolean exactMatch(MethodType callsiteType, MethodType targetType) {
1210             final int parameterCount = callsiteType.parameterCount();
1211             if (callsiteType.parameterCount() != targetType.parameterCount()) {
1212                 return false;
1213             }
1214 
1215             for (int i = 0; i < parameterCount; ++i) {
1216                 Class argumentType = callsiteType.parameterType(i);
1217                 Class parameterType = targetType.parameterType(i);
1218                 if (!exactMatch(argumentType, parameterType)) {
1219                     return false;
1220                 }
1221             }
1222             // Check return type, noting it's always okay to discard the return value.
1223             return callsiteType.returnType() == Void.TYPE
1224                     || exactMatch(callsiteType.returnType(), targetType.returnType());
1225         }
1226 
1227         /**
1228          * Checks whether two types are an exact match. The exact match is based on the erased types
1229          * so any two reference types match, but primitive types must be the same.
1230          *
1231          * @param lhs first class to compare.
1232          * @param rhs second class to compare.
1233          * @return true if both classes satisfy the exact match criteria.
1234          */
exactMatch(Class lhs, Class rhs)1235         private static boolean exactMatch(Class lhs, Class rhs) {
1236             if (lhs.isPrimitive() || rhs.isPrimitive()) {
1237                 return lhs == rhs;
1238             }
1239             return true; // Both types are references, compatibility is checked at the point of use.
1240         }
1241     }
1242 
1243     /** Implements {@code MethodHandle.asSpreader}. */
1244     static class Spreader extends Transformer {
1245         /** The method handle we're delegating to. */
1246         private final MethodHandle target;
1247 
1248         /**
1249          * The offset of the trailing array argument in the list of arguments to this transformer.
1250          * The array argument is always the last argument.
1251          */
1252         private final int arrayOffset;
1253 
1254         /** The component type of the array. */
1255         private final Class<?> componentType;
1256 
1257         /**
1258          * The number of input arguments that will be present in the array. In other words, this is
1259          * the expected array length.
1260          */
1261         private final int numArrayArgs;
1262 
1263         /**
1264          * Range of arguments to copy verbatim from the input frame, This will cover all arguments
1265          * that aren't a part of the trailing array.
1266          */
1267         private final Range leadingRange;
1268         private final Range trailingRange;
1269 
Spreader(MethodHandle target, MethodType spreaderType, int spreadArgPos, int numArrayArgs)1270         Spreader(MethodHandle target, MethodType spreaderType, int spreadArgPos, int numArrayArgs) {
1271             super(spreaderType);
1272             this.target = target;
1273             arrayOffset = spreadArgPos;
1274             componentType = spreaderType.ptypes()[arrayOffset].getComponentType();
1275             if (componentType == null) {
1276                 throw new AssertionError("Argument " + spreadArgPos + " must be an array.");
1277             }
1278             this.numArrayArgs = numArrayArgs;
1279             // Copy all args except the spreader array.
1280             leadingRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset);
1281             trailingRange = EmulatedStackFrame.Range.from(spreaderType, arrayOffset + 1);
1282         }
1283 
1284         @Override
transform(EmulatedStackFrame callerFrame)1285         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
1286             // Get the array reference and check that its length is as expected.
1287             final Class<?> arrayType = type().parameterType(arrayOffset);
1288             final Object arrayObj = callerFrame.getReference(arrayOffset, arrayType);
1289 
1290             // The incoming array may be null if the expected number of array arguments is zero.
1291             final int arrayLength =
1292                 (numArrayArgs == 0 && arrayObj == null) ? 0 : Array.getLength(arrayObj);
1293             if (arrayLength != numArrayArgs) {
1294                 throw new IllegalArgumentException(
1295                         "Invalid array length " + arrayLength + " expected " + numArrayArgs);
1296             }
1297 
1298             // Create a new stack frame for the callee.
1299             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1300 
1301             // Copy ranges not affected by the spreading.
1302             callerFrame.copyRangeTo(targetFrame, leadingRange, 0, 0);
1303             if (componentType.isPrimitive()) {
1304                 final int elementBytes = EmulatedStackFrame.getSize(componentType);
1305                 final int spreadBytes = elementBytes * arrayLength;
1306                 callerFrame.copyRangeTo(targetFrame, trailingRange,
1307                     leadingRange.numReferences, leadingRange.numBytes + spreadBytes);
1308             } else {
1309                 callerFrame.copyRangeTo(targetFrame, trailingRange,
1310                     leadingRange.numReferences + numArrayArgs, leadingRange.numBytes);
1311             }
1312 
1313             if (arrayLength != 0) {
1314                 StackFrameWriter writer = new StackFrameWriter();
1315                 writer.attach(targetFrame,
1316                               arrayOffset,
1317                               leadingRange.numReferences,
1318                               leadingRange.numBytes);
1319                 spreadArray(arrayType, arrayObj, writer);
1320             }
1321 
1322             invokeExactFromTransform(target, targetFrame);
1323             targetFrame.copyReturnValueTo(callerFrame);
1324         }
1325 
spreadArray(Class<?> arrayType, Object arrayObj, StackFrameWriter writer)1326         private void spreadArray(Class<?> arrayType, Object arrayObj, StackFrameWriter writer) {
1327             final Class<?> componentType = arrayType.getComponentType();
1328             switch (Wrapper.basicTypeChar(componentType)) {
1329                 case 'L':
1330                 {
1331                     final Object[] array = (Object[]) arrayObj;
1332                     for (int i = 0; i < array.length; ++i) {
1333                         writer.putNextReference(array[i], componentType);
1334                     }
1335                     break;
1336                 }
1337                 case 'I':
1338                 {
1339                     final int[] array = (int[]) arrayObj;
1340                     for (int i = 0; i < array.length; ++i) {
1341                         writer.putNextInt(array[i]);
1342                     }
1343                     break;
1344                 }
1345                 case 'J':
1346                 {
1347                     final long[] array = (long[]) arrayObj;
1348                     for (int i = 0; i < array.length; ++i) {
1349                         writer.putNextLong(array[i]);
1350                     }
1351                     break;
1352                 }
1353                 case 'B':
1354                 {
1355                     final byte[] array = (byte[]) arrayObj;
1356                     for (int i = 0; i < array.length; ++i) {
1357                         writer.putNextByte(array[i]);
1358                     }
1359                     break;
1360                 }
1361                 case 'S':
1362                 {
1363                     final short[] array = (short[]) arrayObj;
1364                     for (int i = 0; i < array.length; ++i) {
1365                         writer.putNextShort(array[i]);
1366                     }
1367                     break;
1368                 }
1369                 case 'C':
1370                 {
1371                     final char[] array = (char[]) arrayObj;
1372                     for (int i = 0; i < array.length; ++i) {
1373                         writer.putNextChar(array[i]);
1374                     }
1375                     break;
1376                 }
1377                 case 'Z':
1378                 {
1379                     final boolean[] array = (boolean[]) arrayObj;
1380                     for (int i = 0; i < array.length; ++i) {
1381                         writer.putNextBoolean(array[i]);
1382                     }
1383                     break;
1384                 }
1385                 case 'F':
1386                 {
1387                     final float[] array = (float[]) arrayObj;
1388                     for (int i = 0; i < array.length; ++i) {
1389                         writer.putNextFloat(array[i]);
1390                     }
1391                     break;
1392                 }
1393                 case 'D':
1394                 {
1395                     final double[] array = (double[]) arrayObj;
1396                     for (int i = 0; i < array.length; ++i) {
1397                         writer.putNextDouble(array[i]);
1398                     }
1399                     break;
1400                 }
1401             }
1402         }
1403     }
1404 
1405     /** Implements {@code MethodHandle.asCollector}. */
1406     static class Collector extends Transformer {
1407         private final MethodHandle target;
1408 
1409         /**
1410          * The array start is the position in the target outputs of the array collecting arguments
1411          * and the position in the source inputs where collection starts.
1412          */
1413         private final int arrayOffset;
1414 
1415         /**
1416          * The array length is the number of arguments to be collected.
1417          */
1418         private final int arrayLength;
1419 
1420         /** The type of the array. */
1421         private final Class arrayType;
1422 
1423         /**
1424          * Range of arguments to copy verbatim from the start of the input frame.
1425          */
1426         private final Range leadingRange;
1427 
1428         /**
1429          * Range of arguments to copy verbatim from the end of the input frame.
1430          */
1431         private final Range trailingRange;
1432 
Collector(MethodHandle delegate, Class<?> arrayType, int start, int length)1433         Collector(MethodHandle delegate, Class<?> arrayType, int start, int length) {
1434             super(delegate.type().asCollectorType(arrayType, start, length));
1435             this.target = delegate;
1436             this.arrayOffset = start;
1437             this.arrayLength = length;
1438             this.arrayType = arrayType;
1439 
1440             // Build ranges of arguments to be copied.
1441             leadingRange = EmulatedStackFrame.Range.of(type(), 0, arrayOffset);
1442             trailingRange = EmulatedStackFrame.Range.from(type(), arrayOffset + arrayLength);
1443         }
1444 
1445         @Override
transform(EmulatedStackFrame callerFrame)1446         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
1447             // Create a new stack frame for the callee.
1448             final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1449 
1450             // Copy arguments before the collector array.
1451             callerFrame.copyRangeTo(targetFrame, leadingRange, 0, 0);
1452 
1453             // Copy arguments after the collector array.
1454             callerFrame.copyRangeTo(targetFrame, trailingRange,
1455                 leadingRange.numReferences + 1, leadingRange.numBytes);
1456 
1457             // Collect arguments between arrayOffset and arrayOffset + arrayLength.
1458             final StackFrameWriter writer = new StackFrameWriter();
1459             writer.attach(targetFrame, arrayOffset, leadingRange.numReferences, leadingRange.numBytes);
1460             final StackFrameReader reader = new StackFrameReader();
1461             reader.attach(callerFrame, arrayOffset, leadingRange.numReferences, leadingRange.numBytes);
1462 
1463             final char arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType());
1464             switch (arrayTypeChar) {
1465                 case 'L':
1466                     {
1467                         // Reference arrays are the only case where the component type of the
1468                         // array we construct might differ from the type of the reference we read
1469                         // from the stack frame.
1470                         final Class<?> targetType = target.type().ptypes()[arrayOffset];
1471                         final Class<?> arrayComponentType = arrayType.getComponentType();
1472                         Object[] arr =
1473                                 (Object[]) Array.newInstance(arrayComponentType, arrayLength);
1474                         for (int i = 0; i < arrayLength; ++i) {
1475                             arr[i] = reader.nextReference(arrayComponentType);
1476                         }
1477                         writer.putNextReference(arr, targetType);
1478                         break;
1479                     }
1480                 case 'I':
1481                     {
1482                         int[] array = new int[arrayLength];
1483                         for (int i = 0; i < arrayLength; ++i) {
1484                             array[i] = reader.nextInt();
1485                         }
1486                         writer.putNextReference(array, int[].class);
1487                         break;
1488                     }
1489                 case 'J':
1490                     {
1491                         long[] array = new long[arrayLength];
1492                         for (int i = 0; i < arrayLength; ++i) {
1493                             array[i] = reader.nextLong();
1494                         }
1495                         writer.putNextReference(array, long[].class);
1496                         break;
1497                     }
1498                 case 'B':
1499                     {
1500                         byte[] array = new byte[arrayLength];
1501                         for (int i = 0; i < arrayLength; ++i) {
1502                             array[i] = reader.nextByte();
1503                         }
1504                         writer.putNextReference(array, byte[].class);
1505                         break;
1506                     }
1507                 case 'S':
1508                     {
1509                         short[] array = new short[arrayLength];
1510                         for (int i = 0; i < arrayLength; ++i) {
1511                             array[i] = reader.nextShort();
1512                         }
1513                         writer.putNextReference(array, short[].class);
1514                         break;
1515                     }
1516                 case 'C':
1517                     {
1518                         char[] array = new char[arrayLength];
1519                         for (int i = 0; i < arrayLength; ++i) {
1520                             array[i] = reader.nextChar();
1521                         }
1522                         writer.putNextReference(array, char[].class);
1523                         break;
1524                     }
1525                 case 'Z':
1526                     {
1527                         boolean[] array = new boolean[arrayLength];
1528                         for (int i = 0; i < arrayLength; ++i) {
1529                             array[i] = reader.nextBoolean();
1530                         }
1531                         writer.putNextReference(array, boolean[].class);
1532                         break;
1533                     }
1534                 case 'F':
1535                     {
1536                         float[] array = new float[arrayLength];
1537                         for (int i = 0; i < arrayLength; ++i) {
1538                             array[i] = reader.nextFloat();
1539                         }
1540                         writer.putNextReference(array, float[].class);
1541                         break;
1542                     }
1543                 case 'D':
1544                     {
1545                         double[] array = new double[arrayLength];
1546                         for (int i = 0; i < arrayLength; ++i) {
1547                             array[i] = reader.nextDouble();
1548                         }
1549                         writer.putNextReference(array, double[].class);
1550                         break;
1551                     }
1552             }
1553 
1554             invokeFromTransform(target, targetFrame);
1555             targetFrame.copyReturnValueTo(callerFrame);
1556         }
1557     }
1558 
1559     /** Implements {@code MethodHandles.filterArguments}. */
1560     static class FilterArguments extends Transformer {
1561         /** The target handle. */
1562         private final MethodHandle target;
1563         /** Index of the first argument to filter */
1564         private final int pos;
1565         /** The list of filters to apply */
1566         private final MethodHandle[] filters;
1567 
FilterArguments(MethodHandle target, int pos, MethodHandle... filters)1568         FilterArguments(MethodHandle target, int pos, MethodHandle... filters) {
1569             super(deriveType(target, pos, filters));
1570 
1571             this.target = target;
1572             this.pos = pos;
1573             this.filters = filters;
1574         }
1575 
deriveType(MethodHandle target, int pos, MethodHandle[] filters)1576         private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
1577             final Class<?>[] filterArgs = new Class<?>[filters.length];
1578             for (int i = 0; i < filters.length; ++i) {
1579                 MethodHandle filter = filters[i];
1580                 if (filter != null) {
1581                     filterArgs[i] = filter.type().parameterType(0);
1582                 } else {
1583                     // null filters are treated as identity functions.
1584                     filterArgs[i] = target.type().parameterType(i);
1585                 }
1586             }
1587 
1588             return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs);
1589         }
1590 
1591         @Override
transform(EmulatedStackFrame stackFrame)1592         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1593             final StackFrameReader reader = new StackFrameReader();
1594             reader.attach(stackFrame);
1595 
1596             EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
1597             final StackFrameWriter writer = new StackFrameWriter();
1598             writer.attach(transformedFrame);
1599 
1600             final Class<?>[] ptypes = target.type().ptypes();
1601             for (int i = 0; i < ptypes.length; ++i) {
1602                 // Check whether the current argument has a filter associated with it.
1603                 // If it has no filter, no further action need be taken.
1604                 final Class<?> ptype = ptypes[i];
1605                 final MethodHandle filter;
1606                 if (i < pos) {
1607                     filter = null;
1608                 } else if (i >= pos + filters.length) {
1609                     filter = null;
1610                 } else {
1611                     filter = filters[i - pos];
1612                 }
1613 
1614                 if (filter != null) {
1615                     // Note that filter.type() must be (ptype)ptype - this is checked before
1616                     // this transformer is created.
1617                     EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
1618 
1619                     //  Copy the next argument from the stack frame to the filter frame.
1620                     final StackFrameWriter filterWriter = new StackFrameWriter();
1621                     filterWriter.attach(filterFrame);
1622                     copyNext(reader, filterWriter, filter.type().ptypes()[0]);
1623 
1624                     invokeFromTransform(filter, filterFrame);
1625 
1626                     // Copy the argument back from the filter frame to the stack frame.
1627                     final StackFrameReader filterReader = new StackFrameReader();
1628                     filterReader.attach(filterFrame);
1629                     filterReader.makeReturnValueAccessor();
1630                     copyNext(filterReader, writer, ptype);
1631                 } else {
1632                     // There's no filter associated with this frame, just copy the next argument
1633                     // over.
1634                     copyNext(reader, writer, ptype);
1635                 }
1636             }
1637 
1638             invokeFromTransform(target, transformedFrame);
1639             transformedFrame.copyReturnValueTo(stackFrame);
1640         }
1641     }
1642 
1643     /** Implements {@code MethodHandles.collectArguments}. */
1644     static class CollectArguments extends Transformer {
1645         private final MethodHandle target;
1646         private final MethodHandle collector;
1647         private final int pos;
1648 
1649         /** The range of input arguments we copy to the collector. */
1650         private final Range collectorRange;
1651 
1652         /**
1653          * The first range of arguments we copy to the target. These are arguments in the range [0,
1654          * pos). Note that arg[pos] is the return value of the filter.
1655          */
1656         private final Range range1;
1657 
1658         /**
1659          * The second range of arguments we copy to the target. These are arguments in the range
1660          * (pos, N], where N is the number of target arguments.
1661          */
1662         private final Range range2;
1663 
1664         private final int referencesOffset;
1665         private final int stackFrameOffset;
1666 
CollectArguments( MethodHandle target, MethodHandle collector, int pos, MethodType adapterType)1667         CollectArguments(
1668                 MethodHandle target, MethodHandle collector, int pos, MethodType adapterType) {
1669             super(adapterType);
1670 
1671             this.target = target;
1672             this.collector = collector;
1673             this.pos = pos;
1674 
1675             final int numFilterArgs = collector.type().parameterCount();
1676             collectorRange = Range.of(type(), pos, pos + numFilterArgs);
1677 
1678             range1 = Range.of(type(), 0, pos);
1679             this.range2 = Range.from(type(), pos + numFilterArgs);
1680 
1681             // Calculate the number of primitive bytes (or references) we copy to the
1682             // target frame based on the return value of the combiner.
1683             final Class<?> collectorRType = collector.type().rtype();
1684             if (collectorRType == void.class) {
1685                 stackFrameOffset = 0;
1686                 referencesOffset = 0;
1687             } else if (collectorRType.isPrimitive()) {
1688                 stackFrameOffset = EmulatedStackFrame.getSize(collectorRType);
1689                 referencesOffset = 0;
1690             } else {
1691                 stackFrameOffset = 0;
1692                 referencesOffset = 1;
1693             }
1694         }
1695 
1696         @Override
transform(EmulatedStackFrame stackFrame)1697         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1698             // First invoke the collector.
1699             EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type());
1700             stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0);
1701             invokeFromTransform(collector, filterFrame);
1702 
1703             // Start constructing the target frame.
1704             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1705             stackFrame.copyRangeTo(targetFrame, range1, 0, 0);
1706 
1707             // If one of these offsets is not zero, we have a return value to copy.
1708             if (referencesOffset != 0 || stackFrameOffset != 0) {
1709                 final StackFrameReader reader = new StackFrameReader();
1710                 reader.attach(filterFrame).makeReturnValueAccessor();
1711                 final StackFrameWriter writer = new StackFrameWriter();
1712                 writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
1713                 copyNext(reader, writer, target.type().ptypes()[pos]);
1714             }
1715 
1716             stackFrame.copyRangeTo(
1717                     targetFrame,
1718                     range2,
1719                     range1.numReferences + referencesOffset,
1720                     range1.numBytes + stackFrameOffset);
1721 
1722             invokeFromTransform(target, targetFrame);
1723             targetFrame.copyReturnValueTo(stackFrame);
1724         }
1725     }
1726 
1727     /** Implements {@code MethodHandles.foldArguments}. */
1728     static class FoldArguments extends Transformer {
1729         private final MethodHandle target;
1730         private final MethodHandle combiner;
1731         private final int position;
1732 
1733         /** The range of arguments in our frame passed to the combiner. */
1734         private final Range combinerArgs;
1735 
1736         /** The range of arguments in our frame copied to the start of the target frame. */
1737         private final Range leadingArgs;
1738 
1739         /** The range of arguments in our frame copied to the end of the target frame. */
1740         private final Range trailingArgs;
1741 
1742         private final int referencesOffset;
1743         private final int stackFrameOffset;
1744 
FoldArguments(MethodHandle target, int position, MethodHandle combiner)1745         FoldArguments(MethodHandle target, int position, MethodHandle combiner) {
1746             super(deriveType(target, position, combiner));
1747 
1748             this.target = target;
1749             this.combiner = combiner;
1750             this.position = position;
1751 
1752             this.combinerArgs =
1753                     Range.of(type(), position, position + combiner.type().parameterCount());
1754             this.leadingArgs = Range.of(type(), 0, position);
1755             this.trailingArgs = Range.from(type(), position);
1756 
1757             final Class<?> combinerRType = combiner.type().rtype();
1758             if (combinerRType == void.class) {
1759                 stackFrameOffset = 0;
1760                 referencesOffset = 0;
1761             } else if (combinerRType.isPrimitive()) {
1762                 stackFrameOffset = EmulatedStackFrame.getSize(combinerRType);
1763                 referencesOffset = 0;
1764             } else {
1765                 // combinerRType is a reference.
1766                 stackFrameOffset = 0;
1767                 referencesOffset = 1;
1768             }
1769         }
1770 
1771         @Override
transform(EmulatedStackFrame stackFrame)1772         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1773             // First construct the combiner frame and invoke the combiner.
1774             EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type());
1775             stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0);
1776             invokeExactFromTransform(combiner, combinerFrame);
1777 
1778             // Create the stack frame for the target and copy leading arguments to it.
1779             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1780             stackFrame.copyRangeTo(targetFrame, leadingArgs, 0, 0);
1781 
1782             // If one of these offsets is not zero, we have to slot the return value from the
1783             // combiner into the target frame.
1784             if (referencesOffset != 0 || stackFrameOffset != 0) {
1785                 final StackFrameReader reader = new StackFrameReader();
1786                 reader.attach(combinerFrame).makeReturnValueAccessor();
1787                 final StackFrameWriter writer = new StackFrameWriter();
1788                 writer.attach(targetFrame,
1789                               position,
1790                               leadingArgs.numReferences,
1791                               leadingArgs.numBytes);
1792                 copyNext(reader, writer, target.type().ptypes()[position]);
1793             }
1794 
1795             // Copy the arguments provided to the combiner to the tail of the target frame.
1796             stackFrame.copyRangeTo(
1797                 targetFrame,
1798                 trailingArgs,
1799                 leadingArgs.numReferences + referencesOffset,
1800                 leadingArgs.numBytes + stackFrameOffset);
1801 
1802             // Call the target and propagate return value.
1803             invokeExactFromTransform(target, targetFrame);
1804             targetFrame.copyReturnValueTo(stackFrame);
1805         }
1806 
deriveType(MethodHandle target, int position, MethodHandle combiner)1807         private static MethodType deriveType(MethodHandle target,
1808                                              int position,
1809                                              MethodHandle combiner) {
1810             if (combiner.type().rtype() == void.class) {
1811                 return target.type();
1812             }
1813             return target.type().dropParameterTypes(position, position + 1);
1814         }
1815     }
1816 
1817     /** Implements {@code MethodHandles.insertArguments}. */
1818     static class InsertArguments extends Transformer {
1819         private final MethodHandle target;
1820         private final int pos;
1821         private final Object[] values;
1822 
1823         private final Range range1;
1824         private final Range range2;
1825 
InsertArguments(MethodHandle target, int pos, Object[] values)1826         InsertArguments(MethodHandle target, int pos, Object[] values) {
1827             super(target.type().dropParameterTypes(pos, pos + values.length));
1828             this.target = target;
1829             this.pos = pos;
1830             this.values = values;
1831 
1832             final MethodType type = type();
1833             range1 = EmulatedStackFrame.Range.of(type, 0, pos);
1834             range2 = Range.of(type, pos, type.parameterCount());
1835         }
1836 
1837         @Override
transform(EmulatedStackFrame stackFrame)1838         public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1839             EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
1840 
1841             // Copy all arguments before |pos|.
1842             stackFrame.copyRangeTo(calleeFrame, range1, 0, 0);
1843 
1844             // Attach a stack frame writer so that we can copy the next |values.length|
1845             // arguments.
1846             final StackFrameWriter writer = new StackFrameWriter();
1847             writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
1848 
1849             // Copy all the arguments supplied in |values|.
1850             int referencesCopied = 0;
1851             int bytesCopied = 0;
1852             final Class<?>[] ptypes = target.type().ptypes();
1853             for (int i = 0; i < values.length; ++i) {
1854                 final Class<?> ptype = ptypes[i + pos];
1855                 final char typeChar = Wrapper.basicTypeChar(ptype);
1856                 if (typeChar == 'L') {
1857                     writer.putNextReference(values[i], ptype);
1858                     referencesCopied++;
1859                 } else {
1860                     switch (typeChar) {
1861                         case 'Z':
1862                             writer.putNextBoolean((boolean) values[i]);
1863                             break;
1864                         case 'B':
1865                             writer.putNextByte((byte) values[i]);
1866                             break;
1867                         case 'C':
1868                             writer.putNextChar((char) values[i]);
1869                             break;
1870                         case 'S':
1871                             writer.putNextShort((short) values[i]);
1872                             break;
1873                         case 'I':
1874                             writer.putNextInt((int) values[i]);
1875                             break;
1876                         case 'J':
1877                             writer.putNextLong((long) values[i]);
1878                             break;
1879                         case 'F':
1880                             writer.putNextFloat((float) values[i]);
1881                             break;
1882                         case 'D':
1883                             writer.putNextDouble((double) values[i]);
1884                             break;
1885                     }
1886                     bytesCopied += EmulatedStackFrame.getSize(ptype);
1887                 }
1888             }
1889 
1890             // Copy all remaining arguments.
1891             if (range2 != null) {
1892                 stackFrame.copyRangeTo(
1893                         calleeFrame,
1894                         range2,
1895                         range1.numReferences + referencesCopied,
1896                         range1.numBytes + bytesCopied);
1897             }
1898 
1899             invokeFromTransform(target, calleeFrame);
1900             calleeFrame.copyReturnValueTo(stackFrame);
1901         }
1902     }
1903 
1904     /** Implements {@code MethodHandle.asType}. */
1905     static class AsTypeAdapter extends Transformer {
1906         private final MethodHandle target;
1907 
AsTypeAdapter(MethodHandle target, MethodType type)1908         AsTypeAdapter(MethodHandle target, MethodType type) {
1909             super(type);
1910             this.target = target;
1911         }
1912 
1913         @Override
transform(EmulatedStackFrame callerFrame)1914         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
1915             final EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1916             final StackFrameReader reader = new StackFrameReader();
1917             final StackFrameWriter writer = new StackFrameWriter();
1918 
1919             // Adapt arguments
1920             reader.attach(callerFrame);
1921             writer.attach(targetFrame);
1922             adaptArguments(reader, writer);
1923 
1924             // Invoke target
1925             invokeFromTransform(target, targetFrame);
1926 
1927             if (callerFrame.getMethodType().rtype() != void.class) {
1928                 // Adapt return value
1929                 reader.attach(targetFrame).makeReturnValueAccessor();
1930                 writer.attach(callerFrame).makeReturnValueAccessor();
1931                 adaptReturnValue(reader, writer);
1932             }
1933         }
1934 
adaptArguments(final StackFrameReader reader, final StackFrameWriter writer)1935         private void adaptArguments(final StackFrameReader reader, final StackFrameWriter writer) {
1936             final Class<?>[] fromTypes = type().ptypes();
1937             final Class<?>[] toTypes = target.type().ptypes();
1938             for (int i = 0; i < fromTypes.length; ++i) {
1939                 adaptArgument(reader, fromTypes[i], writer, toTypes[i]);
1940             }
1941         }
1942 
adaptReturnValue( final StackFrameReader reader, final StackFrameWriter writer)1943         private void adaptReturnValue(
1944                 final StackFrameReader reader, final StackFrameWriter writer) {
1945             final Class<?> fromType = target.type().rtype();
1946             final Class<?> toType = type().rtype();
1947             adaptArgument(reader, fromType, writer, toType);
1948         }
1949 
throwWrongMethodTypeException()1950         private void throwWrongMethodTypeException() throws WrongMethodTypeException {
1951             throw new WrongMethodTypeException(
1952                     "Cannot convert from " + type() + " to " + target.type());
1953         }
1954 
throwClassCastException(Class from, Class to)1955         private static void throwClassCastException(Class from, Class to)
1956                 throws ClassCastException {
1957             throw new ClassCastException("Cannot cast from " + from + " to " + to);
1958         }
1959 
writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value)1960         private void writePrimitiveByteAs(final StackFrameWriter writer, char baseType, byte value)
1961                 throws WrongMethodTypeException {
1962             switch (baseType) {
1963                 case 'B':
1964                     writer.putNextByte(value);
1965                     return;
1966                 case 'S':
1967                     writer.putNextShort((short) value);
1968                     return;
1969                 case 'I':
1970                     writer.putNextInt((int) value);
1971                     return;
1972                 case 'J':
1973                     writer.putNextLong((long) value);
1974                     return;
1975                 case 'F':
1976                     writer.putNextFloat((float) value);
1977                     return;
1978                 case 'D':
1979                     writer.putNextDouble((double) value);
1980                     return;
1981                 default:
1982                     throwWrongMethodTypeException();
1983             }
1984         }
1985 
writePrimitiveShortAs( final StackFrameWriter writer, char baseType, short value)1986         private void writePrimitiveShortAs(
1987                 final StackFrameWriter writer, char baseType, short value)
1988                 throws WrongMethodTypeException {
1989             switch (baseType) {
1990                 case 'S':
1991                     writer.putNextShort(value);
1992                     return;
1993                 case 'I':
1994                     writer.putNextInt((int) value);
1995                     return;
1996                 case 'J':
1997                     writer.putNextLong((long) value);
1998                     return;
1999                 case 'F':
2000                     writer.putNextFloat((float) value);
2001                     return;
2002                 case 'D':
2003                     writer.putNextDouble((double) value);
2004                     return;
2005                 default:
2006                     throwWrongMethodTypeException();
2007             }
2008         }
2009 
writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value)2010         private void writePrimitiveCharAs(final StackFrameWriter writer, char baseType, char value)
2011                 throws WrongMethodTypeException {
2012             switch (baseType) {
2013                 case 'C':
2014                     writer.putNextChar(value);
2015                     return;
2016                 case 'I':
2017                     writer.putNextInt((int) value);
2018                     return;
2019                 case 'J':
2020                     writer.putNextLong((long) value);
2021                     return;
2022                 case 'F':
2023                     writer.putNextFloat((float) value);
2024                     return;
2025                 case 'D':
2026                     writer.putNextDouble((double) value);
2027                     return;
2028                 default:
2029                     throwWrongMethodTypeException();
2030             }
2031         }
2032 
writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value)2033         private void writePrimitiveIntAs(final StackFrameWriter writer, char baseType, int value)
2034                 throws WrongMethodTypeException {
2035             switch (baseType) {
2036                 case 'I':
2037                     writer.putNextInt(value);
2038                     return;
2039                 case 'J':
2040                     writer.putNextLong((long) value);
2041                     return;
2042                 case 'F':
2043                     writer.putNextFloat((float) value);
2044                     return;
2045                 case 'D':
2046                     writer.putNextDouble((double) value);
2047                     return;
2048                 default:
2049                     throwWrongMethodTypeException();
2050             }
2051             throwWrongMethodTypeException();
2052         }
2053 
writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value)2054         private void writePrimitiveLongAs(final StackFrameWriter writer, char baseType, long value)
2055                 throws WrongMethodTypeException {
2056             switch (baseType) {
2057                 case 'J':
2058                     writer.putNextLong(value);
2059                     return;
2060                 case 'F':
2061                     writer.putNextFloat((float) value);
2062                     return;
2063                 case 'D':
2064                     writer.putNextDouble((double) value);
2065                     return;
2066                 default:
2067                     throwWrongMethodTypeException();
2068             }
2069         }
2070 
writePrimitiveFloatAs( final StackFrameWriter writer, char baseType, float value)2071         private void writePrimitiveFloatAs(
2072                 final StackFrameWriter writer, char baseType, float value)
2073                 throws WrongMethodTypeException {
2074             switch (baseType) {
2075                 case 'F':
2076                     writer.putNextFloat(value);
2077                     return;
2078                 case 'D':
2079                     writer.putNextDouble((double) value);
2080                     return;
2081                 default:
2082                     throwWrongMethodTypeException();
2083             }
2084         }
2085 
writePrimitiveDoubleAs( final StackFrameWriter writer, char baseType, double value)2086         private void writePrimitiveDoubleAs(
2087                 final StackFrameWriter writer, char baseType, double value)
2088                 throws WrongMethodTypeException {
2089             switch (baseType) {
2090                 case 'D':
2091                     writer.putNextDouble(value);
2092                     return;
2093                 default:
2094                     throwWrongMethodTypeException();
2095             }
2096         }
2097 
writePrimitiveVoidAs(final StackFrameWriter writer, char baseType)2098         private void writePrimitiveVoidAs(final StackFrameWriter writer, char baseType) {
2099             switch (baseType) {
2100                 case 'Z':
2101                     writer.putNextBoolean(false);
2102                     return;
2103                 case 'B':
2104                     writer.putNextByte((byte) 0);
2105                     return;
2106                 case 'S':
2107                     writer.putNextShort((short) 0);
2108                     return;
2109                 case 'C':
2110                     writer.putNextChar((char) 0);
2111                     return;
2112                 case 'I':
2113                     writer.putNextInt(0);
2114                     return;
2115                 case 'J':
2116                     writer.putNextLong(0L);
2117                     return;
2118                 case 'F':
2119                     writer.putNextFloat(0.0f);
2120                     return;
2121                 case 'D':
2122                     writer.putNextDouble(0.0);
2123                     return;
2124                 default:
2125                     throwWrongMethodTypeException();
2126             }
2127         }
2128 
getBoxedPrimitiveClass(char baseType)2129         private static Class getBoxedPrimitiveClass(char baseType) {
2130             switch (baseType) {
2131                 case 'Z':
2132                     return Boolean.class;
2133                 case 'B':
2134                     return Byte.class;
2135                 case 'S':
2136                     return Short.class;
2137                 case 'C':
2138                     return Character.class;
2139                 case 'I':
2140                     return Integer.class;
2141                 case 'J':
2142                     return Long.class;
2143                 case 'F':
2144                     return Float.class;
2145                 case 'D':
2146                     return Double.class;
2147                 default:
2148                     return null;
2149             }
2150         }
2151 
adaptArgument( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2152         private void adaptArgument(
2153                 final StackFrameReader reader,
2154                 final Class<?> from,
2155                 final StackFrameWriter writer,
2156                 final Class<?> to) {
2157             if (from.equals(to)) {
2158                 StackFrameAccessor.copyNext(reader, writer, from);
2159                 return;
2160             }
2161 
2162             if (to.isPrimitive()) {
2163                 if (from.isPrimitive()) {
2164                     final char fromBaseType = Wrapper.basicTypeChar(from);
2165                     final char toBaseType = Wrapper.basicTypeChar(to);
2166                     switch (fromBaseType) {
2167                         case 'B':
2168                             writePrimitiveByteAs(writer, toBaseType, reader.nextByte());
2169                             return;
2170                         case 'S':
2171                             writePrimitiveShortAs(writer, toBaseType, reader.nextShort());
2172                             return;
2173                         case 'C':
2174                             writePrimitiveCharAs(writer, toBaseType, reader.nextChar());
2175                             return;
2176                         case 'I':
2177                             writePrimitiveIntAs(writer, toBaseType, reader.nextInt());
2178                             return;
2179                         case 'J':
2180                             writePrimitiveLongAs(writer, toBaseType, reader.nextLong());
2181                             return;
2182                         case 'F':
2183                             writePrimitiveFloatAs(writer, toBaseType, reader.nextFloat());
2184                             return;
2185                         case 'V':
2186                             writePrimitiveVoidAs(writer, toBaseType);
2187                             return;
2188                         default:
2189                             throwWrongMethodTypeException();
2190                     }
2191                 } else {
2192                     final Object value = reader.nextReference(Object.class);
2193                     if (to == void.class) {
2194                         return;
2195                     }
2196                     if (value == null) {
2197                         throw new NullPointerException();
2198                     }
2199                     if (!Wrapper.isWrapperType(value.getClass())) {
2200                         throwClassCastException(value.getClass(), to);
2201                     }
2202                     final Wrapper fromWrapper = Wrapper.forWrapperType(value.getClass());
2203                     final Wrapper toWrapper = Wrapper.forPrimitiveType(to);
2204                     if (!toWrapper.isConvertibleFrom(fromWrapper)) {
2205                         throwClassCastException(from, to);
2206                     }
2207 
2208                     final char toChar = toWrapper.basicTypeChar();
2209                     switch (fromWrapper.basicTypeChar()) {
2210                         case 'Z':
2211                             writer.putNextBoolean(((Boolean) value).booleanValue());
2212                             return;
2213                         case 'B':
2214                             writePrimitiveByteAs(writer, toChar, ((Byte) value).byteValue());
2215                             return;
2216                         case 'S':
2217                             writePrimitiveShortAs(writer, toChar, ((Short) value).shortValue());
2218                             return;
2219                         case 'C':
2220                             writePrimitiveCharAs(writer, toChar, ((Character) value).charValue());
2221                             return;
2222                         case 'I':
2223                             writePrimitiveIntAs(writer, toChar, ((Integer) value).intValue());
2224                             return;
2225                         case 'J':
2226                             writePrimitiveLongAs(writer, toChar, ((Long) value).longValue());
2227                             return;
2228                         case 'F':
2229                             writePrimitiveFloatAs(writer, toChar, ((Float) value).floatValue());
2230                             return;
2231                         case 'D':
2232                             writePrimitiveDoubleAs(writer, toChar, ((Double) value).doubleValue());
2233                             return;
2234                         default:
2235                             throw new IllegalStateException();
2236                     }
2237                 }
2238             } else {
2239                 if (from.isPrimitive()) {
2240                     // Boxing conversion
2241                     final char fromBaseType = Wrapper.basicTypeChar(from);
2242                     final Class fromBoxed = getBoxedPrimitiveClass(fromBaseType);
2243                     // 'to' maybe a super class of the boxed `from` type, e.g. Number.
2244                     if (fromBoxed != null && !to.isAssignableFrom(fromBoxed)) {
2245                         throwWrongMethodTypeException();
2246                     }
2247 
2248                     Object boxed;
2249                     switch (fromBaseType) {
2250                         case 'Z':
2251                             boxed = Boolean.valueOf(reader.nextBoolean());
2252                             break;
2253                         case 'B':
2254                             boxed = Byte.valueOf(reader.nextByte());
2255                             break;
2256                         case 'S':
2257                             boxed = Short.valueOf(reader.nextShort());
2258                             break;
2259                         case 'C':
2260                             boxed = Character.valueOf(reader.nextChar());
2261                             break;
2262                         case 'I':
2263                             boxed = Integer.valueOf(reader.nextInt());
2264                             break;
2265                         case 'J':
2266                             boxed = Long.valueOf(reader.nextLong());
2267                             break;
2268                         case 'F':
2269                             boxed = Float.valueOf(reader.nextFloat());
2270                             break;
2271                         case 'D':
2272                             boxed = Double.valueOf(reader.nextDouble());
2273                             break;
2274                         case 'V':
2275                             boxed = null;
2276                             break;
2277                         default:
2278                             throw new IllegalStateException();
2279                     }
2280                     writer.putNextReference(boxed, to);
2281                     return;
2282                 } else {
2283                     // Cast
2284                     Object value = reader.nextReference(Object.class);
2285                     if (value != null && !to.isAssignableFrom(value.getClass())) {
2286                         throwClassCastException(value.getClass(), to);
2287                     }
2288                     writer.putNextReference(value, to);
2289                 }
2290             }
2291         }
2292     }
2293 
2294     /** Implements {@code MethodHandles.explicitCastArguments}. */
2295     static class ExplicitCastArguments extends Transformer {
2296         private final MethodHandle target;
2297 
ExplicitCastArguments(MethodHandle target, MethodType type)2298         ExplicitCastArguments(MethodHandle target, MethodType type) {
2299             super(type);
2300             this.target = target;
2301         }
2302 
2303         @Override
transform(EmulatedStackFrame callerFrame)2304         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
2305             // Create a new stack frame for the target.
2306             EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
2307 
2308             explicitCastArguments(callerFrame, targetFrame);
2309             invokeFromTransform(target, targetFrame);
2310             explicitCastReturnValue(callerFrame, targetFrame);
2311         }
2312 
explicitCastArguments( final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)2313         private void explicitCastArguments(
2314                 final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) {
2315             final StackFrameReader reader = new StackFrameReader();
2316             reader.attach(callerFrame);
2317             final StackFrameWriter writer = new StackFrameWriter();
2318             writer.attach(targetFrame);
2319 
2320             final Class<?>[] fromTypes = type().ptypes();
2321             final Class<?>[] toTypes = target.type().ptypes();
2322             for (int i = 0; i < fromTypes.length; ++i) {
2323                 explicitCast(reader, fromTypes[i], writer, toTypes[i]);
2324             }
2325         }
2326 
explicitCastReturnValue( final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame)2327         private void explicitCastReturnValue(
2328                 final EmulatedStackFrame callerFrame, final EmulatedStackFrame targetFrame) {
2329             Class<?> from = target.type().rtype();
2330             Class<?> to = type().rtype();
2331             if (to != void.class) {
2332                 final StackFrameWriter writer = new StackFrameWriter();
2333                 writer.attach(callerFrame);
2334                 writer.makeReturnValueAccessor();
2335                 if (from == void.class) {
2336                     if (to.isPrimitive()) {
2337                         unboxNull(writer, to);
2338                     } else {
2339                         writer.putNextReference(null, to);
2340                     }
2341                 } else {
2342                     final StackFrameReader reader = new StackFrameReader();
2343                     reader.attach(targetFrame);
2344                     reader.makeReturnValueAccessor();
2345                     explicitCast(reader, target.type().rtype(), writer, type().rtype());
2346                 }
2347             }
2348         }
2349 
throwUnexpectedType(final Class<?> unexpectedType)2350         private static void throwUnexpectedType(final Class<?> unexpectedType) {
2351             throw new InternalError("Unexpected type: " + unexpectedType);
2352         }
2353 
2354         @SuppressWarnings("unchecked")
badCast(final Class<?> from, final Class<?> to)2355         private static void badCast(final Class<?> from, final Class<?> to) {
2356             throw new ClassCastException("Cannot cast " + from.getName() + " to " + to.getName());
2357         }
2358 
2359         /**
2360          * Converts byte value to boolean according to {@link
2361          * java.lang.invoke.MethodHandles#explicitCast()}
2362          */
toBoolean(byte value)2363         private static boolean toBoolean(byte value) {
2364             return (value & 1) == 1;
2365         }
2366 
readPrimitiveAsByte( final StackFrameReader reader, final Class<?> from)2367         private static byte readPrimitiveAsByte(
2368                 final StackFrameReader reader, final Class<?> from) {
2369             switch (Wrapper.basicTypeChar(from)) {
2370                 case 'B':
2371                     return (byte) reader.nextByte();
2372                 case 'C':
2373                     return (byte) reader.nextChar();
2374                 case 'S':
2375                     return (byte) reader.nextShort();
2376                 case 'I':
2377                     return (byte) reader.nextInt();
2378                 case 'J':
2379                     return (byte) reader.nextLong();
2380                 case 'F':
2381                     return (byte) reader.nextFloat();
2382                 case 'D':
2383                     return (byte) reader.nextDouble();
2384                 case 'Z':
2385                     return reader.nextBoolean() ? (byte) 1 : (byte) 0;
2386                 default:
2387                     throwUnexpectedType(from);
2388                     return 0;
2389             }
2390         }
2391 
readPrimitiveAsChar( final StackFrameReader reader, final Class<?> from)2392         private static char readPrimitiveAsChar(
2393                 final StackFrameReader reader, final Class<?> from) {
2394             switch (Wrapper.basicTypeChar(from)) {
2395                 case 'B':
2396                     return (char) reader.nextByte();
2397                 case 'C':
2398                     return (char) reader.nextChar();
2399                 case 'S':
2400                     return (char) reader.nextShort();
2401                 case 'I':
2402                     return (char) reader.nextInt();
2403                 case 'J':
2404                     return (char) reader.nextLong();
2405                 case 'F':
2406                     return (char) reader.nextFloat();
2407                 case 'D':
2408                     return (char) reader.nextDouble();
2409                 case 'Z':
2410                     return reader.nextBoolean() ? (char) 1 : (char) 0;
2411                 default:
2412                     throwUnexpectedType(from);
2413                     return 0;
2414             }
2415         }
2416 
readPrimitiveAsShort( final StackFrameReader reader, final Class<?> from)2417         private static short readPrimitiveAsShort(
2418                 final StackFrameReader reader, final Class<?> from) {
2419             switch (Wrapper.basicTypeChar(from)) {
2420                 case 'B':
2421                     return (short) reader.nextByte();
2422                 case 'C':
2423                     return (short) reader.nextChar();
2424                 case 'S':
2425                     return (short) reader.nextShort();
2426                 case 'I':
2427                     return (short) reader.nextInt();
2428                 case 'J':
2429                     return (short) reader.nextLong();
2430                 case 'F':
2431                     return (short) reader.nextFloat();
2432                 case 'D':
2433                     return (short) reader.nextDouble();
2434                 case 'Z':
2435                     return reader.nextBoolean() ? (short) 1 : (short) 0;
2436                 default:
2437                     throwUnexpectedType(from);
2438                     return 0;
2439             }
2440         }
2441 
readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from)2442         private static int readPrimitiveAsInt(final StackFrameReader reader, final Class<?> from) {
2443             switch (Wrapper.basicTypeChar(from)) {
2444                 case 'B':
2445                     return (int) reader.nextByte();
2446                 case 'C':
2447                     return (int) reader.nextChar();
2448                 case 'S':
2449                     return (int) reader.nextShort();
2450                 case 'I':
2451                     return (int) reader.nextInt();
2452                 case 'J':
2453                     return (int) reader.nextLong();
2454                 case 'F':
2455                     return (int) reader.nextFloat();
2456                 case 'D':
2457                     return (int) reader.nextDouble();
2458                 case 'Z':
2459                     return reader.nextBoolean() ? 1 : 0;
2460                 default:
2461                     throwUnexpectedType(from);
2462                     return 0;
2463             }
2464         }
2465 
readPrimitiveAsLong( final StackFrameReader reader, final Class<?> from)2466         private static long readPrimitiveAsLong(
2467                 final StackFrameReader reader, final Class<?> from) {
2468             switch (Wrapper.basicTypeChar(from)) {
2469                 case 'B':
2470                     return (long) reader.nextByte();
2471                 case 'C':
2472                     return (long) reader.nextChar();
2473                 case 'S':
2474                     return (long) reader.nextShort();
2475                 case 'I':
2476                     return (long) reader.nextInt();
2477                 case 'J':
2478                     return (long) reader.nextLong();
2479                 case 'F':
2480                     return (long) reader.nextFloat();
2481                 case 'D':
2482                     return (long) reader.nextDouble();
2483                 case 'Z':
2484                     return reader.nextBoolean() ? 1L : 0L;
2485                 default:
2486                     throwUnexpectedType(from);
2487                     return 0;
2488             }
2489         }
2490 
readPrimitiveAsFloat( final StackFrameReader reader, final Class<?> from)2491         private static float readPrimitiveAsFloat(
2492                 final StackFrameReader reader, final Class<?> from) {
2493             switch (Wrapper.basicTypeChar(from)) {
2494                 case 'B':
2495                     return (float) reader.nextByte();
2496                 case 'C':
2497                     return (float) reader.nextChar();
2498                 case 'S':
2499                     return (float) reader.nextShort();
2500                 case 'I':
2501                     return (float) reader.nextInt();
2502                 case 'J':
2503                     return (float) reader.nextLong();
2504                 case 'F':
2505                     return (float) reader.nextFloat();
2506                 case 'D':
2507                     return (float) reader.nextDouble();
2508                 case 'Z':
2509                     return reader.nextBoolean() ? 1.0f : 0.0f;
2510                 default:
2511                     throwUnexpectedType(from);
2512                     return 0;
2513             }
2514         }
2515 
readPrimitiveAsDouble( final StackFrameReader reader, final Class<?> from)2516         private static double readPrimitiveAsDouble(
2517                 final StackFrameReader reader, final Class<?> from) {
2518             switch (Wrapper.basicTypeChar(from)) {
2519                 case 'B':
2520                     return (double) reader.nextByte();
2521                 case 'C':
2522                     return (double) reader.nextChar();
2523                 case 'S':
2524                     return (double) reader.nextShort();
2525                 case 'I':
2526                     return (double) reader.nextInt();
2527                 case 'J':
2528                     return (double) reader.nextLong();
2529                 case 'F':
2530                     return (double) reader.nextFloat();
2531                 case 'D':
2532                     return (double) reader.nextDouble();
2533                 case 'Z':
2534                     return reader.nextBoolean() ? 1.0 : 0.0;
2535                 default:
2536                     throwUnexpectedType(from);
2537                     return 0;
2538             }
2539         }
2540 
explicitCastPrimitives( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2541         private static void explicitCastPrimitives(
2542                 final StackFrameReader reader,
2543                 final Class<?> from,
2544                 final StackFrameWriter writer,
2545                 final Class<?> to) {
2546             switch (Wrapper.basicTypeChar(to)) {
2547                 case 'B':
2548                     writer.putNextByte(readPrimitiveAsByte(reader, from));
2549                     break;
2550                 case 'C':
2551                     writer.putNextChar(readPrimitiveAsChar(reader, from));
2552                     break;
2553                 case 'S':
2554                     writer.putNextShort(readPrimitiveAsShort(reader, from));
2555                     break;
2556                 case 'I':
2557                     writer.putNextInt(readPrimitiveAsInt(reader, from));
2558                     break;
2559                 case 'J':
2560                     writer.putNextLong(readPrimitiveAsLong(reader, from));
2561                     break;
2562                 case 'F':
2563                     writer.putNextFloat(readPrimitiveAsFloat(reader, from));
2564                     break;
2565                 case 'D':
2566                     writer.putNextDouble(readPrimitiveAsDouble(reader, from));
2567                     break;
2568                 case 'Z':
2569                     writer.putNextBoolean(toBoolean(readPrimitiveAsByte(reader, from)));
2570                     break;
2571                 default:
2572                     throwUnexpectedType(to);
2573                     break;
2574             }
2575         }
2576 
unboxNull(final StackFrameWriter writer, final Class<?> to)2577         private static void unboxNull(final StackFrameWriter writer, final Class<?> to) {
2578             switch (Wrapper.basicTypeChar(to)) {
2579                 case 'Z':
2580                     writer.putNextBoolean(false);
2581                     break;
2582                 case 'B':
2583                     writer.putNextByte((byte) 0);
2584                     break;
2585                 case 'C':
2586                     writer.putNextChar((char) 0);
2587                     break;
2588                 case 'S':
2589                     writer.putNextShort((short) 0);
2590                     break;
2591                 case 'I':
2592                     writer.putNextInt((int) 0);
2593                     break;
2594                 case 'J':
2595                     writer.putNextLong((long) 0);
2596                     break;
2597                 case 'F':
2598                     writer.putNextFloat((float) 0);
2599                     break;
2600                 case 'D':
2601                     writer.putNextDouble((double) 0);
2602                     break;
2603                 default:
2604                     throwUnexpectedType(to);
2605                     break;
2606             }
2607         }
2608 
unboxNonNull( final Object ref, final StackFrameWriter writer, final Class<?> to)2609         private static void unboxNonNull(
2610                 final Object ref,
2611                 final StackFrameWriter writer,
2612                 final Class<?> to) {
2613             final Class<?> from = ref.getClass();
2614             final Class<?> unboxedFromType = Wrapper.asPrimitiveType(from);
2615             switch (Wrapper.basicTypeChar(unboxedFromType)) {
2616                 case 'Z':
2617                     boolean z = (boolean) ref;
2618                     switch (Wrapper.basicTypeChar(to)) {
2619                         case 'Z':
2620                             writer.putNextBoolean(z);
2621                             break;
2622                         case 'B':
2623                             writer.putNextByte(z ? (byte) 1 : (byte) 0);
2624                             break;
2625                         case 'S':
2626                             writer.putNextShort(z ? (short) 1 : (short) 0);
2627                             break;
2628                         case 'C':
2629                             writer.putNextChar(z ? (char) 1 : (char) 0);
2630                             break;
2631                         case 'I':
2632                             writer.putNextInt(z ? 1 : 0);
2633                             break;
2634                         case 'J':
2635                             writer.putNextLong(z ? 1l : 0l);
2636                             break;
2637                         case 'F':
2638                             writer.putNextFloat(z ? 1.0f : 0.0f);
2639                             break;
2640                         case 'D':
2641                             writer.putNextDouble(z ? 1.0 : 0.0);
2642                             break;
2643                         default:
2644                             badCast(from, to);
2645                             break;
2646                     }
2647                     break;
2648                 case 'B':
2649                     byte b = (byte) ref;
2650                     switch (Wrapper.basicTypeChar(to)) {
2651                         case 'B':
2652                             writer.putNextByte(b);
2653                             break;
2654                         case 'Z':
2655                             writer.putNextBoolean(toBoolean(b));
2656                             break;
2657                         case 'S':
2658                             writer.putNextShort((short) b);
2659                             break;
2660                         case 'C':
2661                             writer.putNextChar((char) b);
2662                             break;
2663                         case 'I':
2664                             writer.putNextInt((int) b);
2665                             break;
2666                         case 'J':
2667                             writer.putNextLong((long) b);
2668                             break;
2669                         case 'F':
2670                             writer.putNextFloat((float) b);
2671                             break;
2672                         case 'D':
2673                             writer.putNextDouble((double) b);
2674                             break;
2675                         default:
2676                             badCast(from, to);
2677                             break;
2678                     }
2679                     break;
2680                 case 'S':
2681                     short s = (short) ref;
2682                     switch (Wrapper.basicTypeChar(to)) {
2683                         case 'Z':
2684                             writer.putNextBoolean((s & 1) == 1);
2685                             break;
2686                         case 'B':
2687                             writer.putNextByte((byte) s);
2688                             break;
2689                         case 'S':
2690                             writer.putNextShort(s);
2691                             break;
2692                         case 'C':
2693                             writer.putNextChar((char) s);
2694                             break;
2695                         case 'I':
2696                             writer.putNextInt((int) s);
2697                             break;
2698                         case 'J':
2699                             writer.putNextLong((long) s);
2700                             break;
2701                         case 'F':
2702                             writer.putNextFloat((float) s);
2703                             break;
2704                         case 'D':
2705                             writer.putNextDouble((double) s);
2706                             break;
2707                         default:
2708                             badCast(from, to);
2709                             break;
2710                     }
2711                     break;
2712                 case 'C':
2713                     char c = (char) ref;
2714                     switch (Wrapper.basicTypeChar(to)) {
2715                         case 'Z':
2716                             writer.putNextBoolean((c & (char) 1) == (char) 1);
2717                             break;
2718                         case 'B':
2719                             writer.putNextByte((byte) c);
2720                             break;
2721                         case 'S':
2722                             writer.putNextShort((short) c);
2723                             break;
2724                         case 'C':
2725                             writer.putNextChar(c);
2726                             break;
2727                         case 'I':
2728                             writer.putNextInt((int) c);
2729                             break;
2730                         case 'J':
2731                             writer.putNextLong((long) c);
2732                             break;
2733                         case 'F':
2734                             writer.putNextFloat((float) c);
2735                             break;
2736                         case 'D':
2737                             writer.putNextDouble((double) c);
2738                             break;
2739                         default:
2740                             badCast(from, to);
2741                             break;
2742                     }
2743                     break;
2744                 case 'I':
2745                     int i = (int) ref;
2746                     switch (Wrapper.basicTypeChar(to)) {
2747                         case 'Z':
2748                             writer.putNextBoolean((i & 1) == 1);
2749                             break;
2750                         case 'B':
2751                             writer.putNextByte((byte) i);
2752                             break;
2753                         case 'S':
2754                             writer.putNextShort((short) i);
2755                             break;
2756                         case 'C':
2757                             writer.putNextChar((char) i);
2758                             break;
2759                         case 'I':
2760                             writer.putNextInt(i);
2761                             break;
2762                         case 'J':
2763                             writer.putNextLong((long) i);
2764                             break;
2765                         case 'F':
2766                             writer.putNextFloat((float) i);
2767                             break;
2768                         case 'D':
2769                             writer.putNextDouble((double) i);
2770                             break;
2771                         default:
2772                             badCast(from, to);
2773                     }
2774                     break;
2775                 case 'J':
2776                     long j = (long) ref;
2777                     switch (Wrapper.basicTypeChar(to)) {
2778                         case 'Z':
2779                             writer.putNextBoolean((j & 1l) == 1l);
2780                             break;
2781                         case 'B':
2782                             writer.putNextByte((byte) j);
2783                             break;
2784                         case 'S':
2785                             writer.putNextShort((short) j);
2786                             break;
2787                         case 'C':
2788                             writer.putNextChar((char) j);
2789                             break;
2790                         case 'I':
2791                             writer.putNextInt((int) j);
2792                             break;
2793                         case 'J':
2794                             writer.putNextLong(j);
2795                             break;
2796                         case 'F':
2797                             writer.putNextFloat((float) j);
2798                             break;
2799                         case 'D':
2800                             writer.putNextDouble((double) j);
2801                             break;
2802                         default:
2803                             badCast(from, to);
2804                             break;
2805                     }
2806                     break;
2807                 case 'F':
2808                     float f = (float) ref;
2809                     switch (Wrapper.basicTypeChar(to)) {
2810                         case 'Z':
2811                             writer.putNextBoolean(((byte) f & 1) != 0);
2812                             break;
2813                         case 'B':
2814                             writer.putNextByte((byte) f);
2815                             break;
2816                         case 'S':
2817                             writer.putNextShort((short) f);
2818                             break;
2819                         case 'C':
2820                             writer.putNextChar((char) f);
2821                             break;
2822                         case 'I':
2823                             writer.putNextInt((int) f);
2824                             break;
2825                         case 'J':
2826                             writer.putNextLong((long) f);
2827                             break;
2828                         case 'F':
2829                             writer.putNextFloat(f);
2830                             break;
2831                         case 'D':
2832                             writer.putNextDouble((double) f);
2833                             break;
2834                         default:
2835                             badCast(from, to);
2836                             break;
2837                     }
2838                     break;
2839                 case 'D':
2840                     double d = (double) ref;
2841                     switch (Wrapper.basicTypeChar(to)) {
2842                         case 'Z':
2843                             writer.putNextBoolean(((byte) d & 1) != 0);
2844                             break;
2845                         case 'B':
2846                             writer.putNextByte((byte) d);
2847                             break;
2848                         case 'S':
2849                             writer.putNextShort((short) d);
2850                             break;
2851                         case 'C':
2852                             writer.putNextChar((char) d);
2853                             break;
2854                         case 'I':
2855                             writer.putNextInt((int) d);
2856                             break;
2857                         case 'J':
2858                             writer.putNextLong((long) d);
2859                             break;
2860                         case 'F':
2861                             writer.putNextFloat((float) d);
2862                             break;
2863                         case 'D':
2864                             writer.putNextDouble(d);
2865                             break;
2866                         default:
2867                             badCast(from, to);
2868                             break;
2869                     }
2870                     break;
2871                 default:
2872                     badCast(from, to);
2873                     break;
2874             }
2875         }
2876 
unbox( final Object ref, final StackFrameWriter writer, final Class<?> to)2877         private static void unbox(
2878                 final Object ref,
2879                 final StackFrameWriter writer,
2880                 final Class<?> to) {
2881             if (ref == null) {
2882                 unboxNull(writer, to);
2883             } else {
2884                 unboxNonNull(ref, writer, to);
2885             }
2886         }
2887 
box( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2888         private static void box(
2889                 final StackFrameReader reader,
2890                 final Class<?> from,
2891                 final StackFrameWriter writer,
2892                 final Class<?> to) {
2893             Object boxed = null;
2894             switch (Wrapper.basicTypeChar(from)) {
2895                 case 'Z':
2896                     boxed = Boolean.valueOf(reader.nextBoolean());
2897                     break;
2898                 case 'B':
2899                     boxed = Byte.valueOf(reader.nextByte());
2900                     break;
2901                 case 'C':
2902                     boxed = Character.valueOf(reader.nextChar());
2903                     break;
2904                 case 'S':
2905                     boxed = Short.valueOf(reader.nextShort());
2906                     break;
2907                 case 'I':
2908                     boxed = Integer.valueOf(reader.nextInt());
2909                     break;
2910                 case 'J':
2911                     boxed = Long.valueOf(reader.nextLong());
2912                     break;
2913                 case 'F':
2914                     boxed = Float.valueOf(reader.nextFloat());
2915                     break;
2916                 case 'D':
2917                     boxed = Double.valueOf(reader.nextDouble());
2918                     break;
2919                 default:
2920                     throwUnexpectedType(from);
2921                     break;
2922             }
2923             writer.putNextReference(to.cast(boxed), to);
2924         }
2925 
explicitCast( final StackFrameReader reader, final Class<?> from, final StackFrameWriter writer, final Class<?> to)2926         private static void explicitCast(
2927                 final StackFrameReader reader,
2928                 final Class<?> from,
2929                 final StackFrameWriter writer,
2930                 final Class<?> to) {
2931             if (from.equals(to)) {
2932                 StackFrameAccessor.copyNext(reader, writer, from);
2933                 return;
2934             }
2935 
2936             if (from.isPrimitive()) {
2937                 if (to.isPrimitive()) {
2938                     // |from| and |to| are primitive types.
2939                     explicitCastPrimitives(reader, from, writer, to);
2940                 } else {
2941                     // |from| is a primitive type, |to| is a reference type.
2942                     box(reader, from, writer, to);
2943                 }
2944             } else {
2945                 // |from| is a reference type.
2946                 Object ref = reader.nextReference(from);
2947                 if (to.isPrimitive()) {
2948                     // |from| is a reference type, |to| is a primitive type,
2949                     unbox(ref, writer, to);
2950                 } else if (to.isInterface()) {
2951                     // Pass from without a cast according to description for
2952                     // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
2953                     writer.putNextReference(ref, to);
2954                 } else {
2955                     // |to| and from |from| are reference types, perform class cast check.
2956                     writer.putNextReference(to.cast(ref), to);
2957                 }
2958             }
2959         }
2960     }
2961 
2962     /** Implements {@code MethodHandles.loop}. */
2963     static class Loop extends Transformer {
2964 
2965         /** Loop variable initialization methods. */
2966         final MethodHandle[] inits;
2967 
2968         /** Loop variable step methods. */
2969         final MethodHandle[] steps;
2970 
2971         /** Loop variable predicate methods. */
2972         final MethodHandle[] preds;
2973 
2974         /** Loop return value calculating methods. */
2975         final MethodHandle[] finis;
2976 
2977         /** Synthetic method type for frame used to hold loop variables. */
2978         final MethodType loopVarsType;
2979 
2980         /** Range of loop variables in the frame used for loop variables. */
2981         final Range loopVarsRange;
2982 
2983         /** Range of suffix variables in the caller frame. */
2984         final Range suffixRange;
2985 
Loop(Class<?> loopReturnType, List<Class<?>> commonSuffix, MethodHandle[] finit, MethodHandle[] fstep, MethodHandle[] fpred, MethodHandle[] ffini)2986         public Loop(Class<?> loopReturnType,
2987                     List<Class<?>> commonSuffix,
2988                     MethodHandle[] finit,
2989                     MethodHandle[] fstep,
2990                     MethodHandle[] fpred,
2991                     MethodHandle[] ffini) {
2992             super(MethodType.methodType(loopReturnType, commonSuffix));
2993 
2994             inits = finit;
2995             steps = fstep;
2996             preds = fpred;
2997             finis = ffini;
2998 
2999             loopVarsType = deduceLoopVarsType(finit);
3000             loopVarsRange = EmulatedStackFrame.Range.all(loopVarsType);
3001             suffixRange = EmulatedStackFrame.Range.all(type());
3002         }
3003 
3004         @Override
transform(EmulatedStackFrame callerFrame)3005         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
3006             final EmulatedStackFrame loopVarsFrame = EmulatedStackFrame.create(loopVarsType);
3007             final StackFrameWriter loopVarsWriter = new StackFrameWriter();
3008 
3009             init(callerFrame, loopVarsFrame, loopVarsWriter);
3010 
3011             for (;;) {
3012                 loopVarsWriter.attach(loopVarsFrame);
3013                 for (int i = 0; i < steps.length; ++i) {
3014                     // Future optimization opportunity: there is a good deal of StackFrame
3015                     // allocation here, one is allocated per MH invocation. Consider caching
3016                     // frames <method-type:stack-frame> and passing the cache on the stack.
3017                     doStep(steps[i], callerFrame, loopVarsFrame, loopVarsWriter);
3018                     boolean keepGoing = doPredicate(preds[i], callerFrame, loopVarsFrame);
3019                     if (!keepGoing) {
3020                         doFinish(finis[i], callerFrame, loopVarsFrame);
3021                         return;
3022                     }
3023                 }
3024             }
3025         }
3026 
deduceLoopVarsType(final MethodHandle[] inits)3027         private static MethodType deduceLoopVarsType(final MethodHandle[] inits) {
3028             List<Class<?>> loopVarTypes = new ArrayList(inits.length);
3029             for (MethodHandle init : inits) {
3030                 Class<?> returnType = init.type().returnType();
3031                 if (returnType != void.class) {
3032                     loopVarTypes.add(returnType);
3033                 }
3034             }
3035             return MethodType.methodType(void.class, loopVarTypes);
3036         }
3037 
init(final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame, final StackFrameWriter loopVarsWriter)3038         private void init(final EmulatedStackFrame callerFrame,
3039                           final EmulatedStackFrame loopVarsFrame,
3040                           final StackFrameWriter loopVarsWriter) throws Throwable {
3041             loopVarsWriter.attach(loopVarsFrame);
3042             for (MethodHandle init : inits) {
3043                 EmulatedStackFrame initFrame = EmulatedStackFrame.create(init.type());
3044                 callerFrame.copyRangeTo(initFrame, suffixRange, 0, 0);
3045 
3046                 invokeExactFromTransform(init, initFrame);
3047 
3048                 final Class<?> loopVarType = init.type().returnType();
3049                 if (loopVarType != void.class) {
3050                     StackFrameReader initReader = new StackFrameReader();
3051                     initReader.attach(initFrame).makeReturnValueAccessor();
3052                     copyNext(initReader, loopVarsWriter, loopVarType);
3053                 }
3054             }
3055         }
3056 
3057         /**
3058          * Creates a frame for invoking a method of specified type.
3059          *
3060          * The frame arguments are the loop variables followed by the arguments provided to the
3061          * loop MethodHandle.
3062          *
3063          * @param mt the type of the method to be invoked.
3064          * @param callerFrame the frame invoking the loop MethodHandle.
3065          * @param loopVarsFrame the frame holding loop variables.
3066          * @return an EmulatedStackFrame initialized with the required arguments.
3067          */
prepareFrame(final MethodType mt, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3068         private EmulatedStackFrame prepareFrame(final MethodType mt,
3069                                                 final EmulatedStackFrame callerFrame,
3070                                                 final EmulatedStackFrame loopVarsFrame) {
3071             EmulatedStackFrame frame = EmulatedStackFrame.create(mt);
3072 
3073             // Copy loop variables.
3074             loopVarsFrame.copyRangeTo(frame, loopVarsRange, 0, 0);
3075 
3076             // Copy arguments provided in the loop invoke().
3077             callerFrame.copyRangeTo(frame,
3078                                     suffixRange,
3079                                     loopVarsRange.numReferences,
3080                                     loopVarsRange.numBytes);
3081             return frame;
3082         }
3083 
doStep(final MethodHandle step, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame, final StackFrameWriter loopVarsWriter)3084         private void doStep(final MethodHandle step,
3085                             final EmulatedStackFrame callerFrame,
3086                             final EmulatedStackFrame loopVarsFrame,
3087                             final StackFrameWriter loopVarsWriter) throws Throwable {
3088             final EmulatedStackFrame stepFrame =
3089                 prepareFrame(step.type(), callerFrame, loopVarsFrame);
3090             invokeExactFromTransform(step, stepFrame);
3091 
3092             final Class<?> loopVarType = step.type().returnType();
3093             if (loopVarType != void.class) {
3094                 final StackFrameReader stepReader = new StackFrameReader();
3095                 stepReader.attach(stepFrame).makeReturnValueAccessor();
3096                 copyNext(stepReader, loopVarsWriter, loopVarType);
3097             }
3098         }
3099 
doPredicate(final MethodHandle pred, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3100         private boolean doPredicate(final MethodHandle pred,
3101                                     final EmulatedStackFrame callerFrame,
3102                                     final EmulatedStackFrame loopVarsFrame) throws Throwable {
3103             final EmulatedStackFrame predFrame =
3104                     prepareFrame(pred.type(), callerFrame, loopVarsFrame);
3105             invokeExactFromTransform(pred, predFrame);
3106 
3107             final StackFrameReader predReader = new StackFrameReader();
3108             predReader.attach(predFrame).makeReturnValueAccessor();
3109             return predReader.nextBoolean();
3110         }
3111 
doFinish(final MethodHandle fini, final EmulatedStackFrame callerFrame, final EmulatedStackFrame loopVarsFrame)3112         private void doFinish(final MethodHandle fini,
3113                               final EmulatedStackFrame callerFrame,
3114                               final EmulatedStackFrame loopVarsFrame) throws Throwable {
3115             final EmulatedStackFrame finiFrame =
3116                     prepareFrame(fini.type(), callerFrame, loopVarsFrame);
3117             invokeExactFromTransform(fini, finiFrame);
3118             finiFrame.copyReturnValueTo(callerFrame);
3119         }
3120     }
3121 
3122     /** Implements {@code MethodHandles.tableSwitch}. */
3123     static class TableSwitch extends Transformer {
3124         private final MethodHandle fallback;
3125         private final MethodHandle[] targets;
3126 
TableSwitch(MethodType type, MethodHandle fallback, MethodHandle[] targets)3127         TableSwitch(MethodType type, MethodHandle fallback, MethodHandle[] targets) {
3128             super(type);
3129             this.fallback = fallback;
3130             this.targets = targets;
3131         }
3132 
3133         @Override
transform(EmulatedStackFrame callerFrame)3134         public void transform(EmulatedStackFrame callerFrame) throws Throwable {
3135             final MethodHandle selected = selectMethodHandle(callerFrame);
3136             invokeExactFromTransform(selected, callerFrame);
3137         }
3138 
selectMethodHandle(EmulatedStackFrame callerFrame)3139         private MethodHandle selectMethodHandle(EmulatedStackFrame callerFrame) {
3140             StackFrameReader reader = new StackFrameReader();
3141             reader.attach(callerFrame);
3142             final int index = reader.nextInt();
3143 
3144             if (index >= 0 && index < targets.length) {
3145                 return targets[index];
3146             } else {
3147                 return fallback;
3148             }
3149         }
3150     }
3151 }
3152