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