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