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