1faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath/*
2faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * Copyright 2016 Google Inc.
3faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath *
4faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * This code is free software; you can redistribute it and/or modify it
5faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * under the terms of the GNU General Public License version 2 only, as
6faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * published by the Free Software Foundation.  Google designates this
7faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * particular file as subject to the "Classpath" exception as provided
8faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * by Google in the LICENSE file that accompanied this code.
9faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath *
10faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * This code is distributed in the hope that it will be useful, but WITHOUT
11faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * version 2 for more details (a copy is included in the LICENSE file that
14faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * accompanied this code).
15faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath *
16faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * You should have received a copy of the GNU General Public License version
17faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * 2 along with this work; if not, write to the Free Software Foundation,
18faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath */
20faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
21faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamathpackage java.lang.invoke;
22faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
23faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamathimport dalvik.system.EmulatedStackFrame;
24378d458718d98d264b58734c87568ee5de9a6781Narayan Kamathimport dalvik.system.EmulatedStackFrame.Range;
25d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodsonimport dalvik.system.EmulatedStackFrame.StackFrameAccessor;
26168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamathimport dalvik.system.EmulatedStackFrame.StackFrameReader;
27168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamathimport dalvik.system.EmulatedStackFrame.StackFrameWriter;
28704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodsonimport java.lang.reflect.Array;
29faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamathimport java.lang.reflect.Method;
30a80d6f85a6e5154300be8552f027916767704b75Orion Hodsonimport java.lang.reflect.Modifier;
31704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodsonimport sun.invoke.util.Wrapper;
32a80d6f85a6e5154300be8552f027916767704b75Orion Hodsonimport sun.misc.Unsafe;
33d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamathimport static dalvik.system.EmulatedStackFrame.StackFrameAccessor.copyNext;
34faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
35faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath/**
36faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath * @hide Public for testing only.
37faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath */
38faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamathpublic class Transformers {
39faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    private Transformers() {}
40faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
41faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    static {
42faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        try {
43faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath            TRANSFORM_INTERNAL = MethodHandle.class.getDeclaredMethod("transformInternal",
44faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath                    EmulatedStackFrame.class);
45faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        } catch (NoSuchMethodException nsme) {
46faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath            throw new AssertionError();
47faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        }
48faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    }
49faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
50faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    /**
51faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     * Method reference to the private {@code MethodHandle.transformInternal} method. This is
52faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     * cached here because it's the point of entry for all transformers.
53faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     */
54faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    private static final Method TRANSFORM_INTERNAL;
55faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
56faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    /** @hide */
57ff28f8512f99a9507f12b9eb600a374414735394Narayan Kamath    public static abstract class Transformer extends MethodHandle implements Cloneable {
58faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        protected Transformer(MethodType type) {
59faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath            super(TRANSFORM_INTERNAL.getArtMethod(), MethodHandle.INVOKE_TRANSFORM, type);
60faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        }
61ff28f8512f99a9507f12b9eb600a374414735394Narayan Kamath
62704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        protected Transformer(MethodType type, int invokeKind) {
63704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            super(TRANSFORM_INTERNAL.getArtMethod(), invokeKind, type);
64704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
65704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
66ff28f8512f99a9507f12b9eb600a374414735394Narayan Kamath        @Override
67ff28f8512f99a9507f12b9eb600a374414735394Narayan Kamath        public Object clone() throws CloneNotSupportedException {
68ff28f8512f99a9507f12b9eb600a374414735394Narayan Kamath            return super.clone();
69ff28f8512f99a9507f12b9eb600a374414735394Narayan Kamath        }
70faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    }
71faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
72faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    /**
73faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     * A method handle that always throws an exception of a specified type.
74faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     *
75faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     * The handle declares a nominal return type, which is immaterial to the execution
76faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     * of the handle because it never returns.
77faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     *
78faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     * @hide
79faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath     */
80faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    public static class AlwaysThrow extends Transformer {
81faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        private final Class<? extends Throwable> exceptionType;
82faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
83faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        public AlwaysThrow(Class<?> nominalReturnType, Class<? extends  Throwable> exType) {
845eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            super(MethodType.methodType(nominalReturnType, exType));
85faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath            this.exceptionType = exType;
86faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        }
87faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath
88faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        @Override
89faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
905eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            throw emulatedStackFrame.getReference(0, exceptionType);
915eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        }
925eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    }
935eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
945eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    /**
955eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath     * Implements {@code MethodHandles.dropArguments}.
965eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath     */
975eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    public static class DropArguments extends Transformer {
985eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final MethodHandle delegate;
995eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1005eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final EmulatedStackFrame.Range range1;
1015eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1025eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        /**
1035eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath         * Note that {@code range2} will be null if the arguments that are being dropped
1045eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath         * are the last {@code n}.
1055eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath         */
1065eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        /* @Nullable */ private final EmulatedStackFrame.Range range2;
1075eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1085eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        public DropArguments(MethodType type, MethodHandle delegate,
1095eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                             int startPos, int numDropped) {
1105eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            super(type);
1115eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1125eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.delegate = delegate;
1135eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1145eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // We pre-calculate the ranges of values we have to copy through to the delegate
1155eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // handle at the time of instantiation so that the actual invoke is performant.
1165eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.range1 = EmulatedStackFrame.Range.of(type, 0, startPos);
1175eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            final int numArgs = type.ptypes().length;
1185eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            if (startPos + numDropped < numArgs) {
1195eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                this.range2 = EmulatedStackFrame.Range.of(type, startPos + numDropped, numArgs);
1205eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            } else {
1215eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                this.range2 = null;
1225eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            }
1235eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        }
1245eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1255eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        @Override
1265eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
1275eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(delegate.type());
1285eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1295eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            emulatedStackFrame.copyRangeTo(calleeFrame, range1,
1305eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    0 /* referencesStart */, 0 /* stackFrameStart */);
1315eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1325eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            if (range2 != null) {
1335eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                final int referencesStart = range1.numReferences;
1345eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                final int stackFrameStart = range1.numBytes;
1355eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1365eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                emulatedStackFrame.copyRangeTo(calleeFrame, range2,
1375eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                        referencesStart, stackFrameStart);
1385eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            }
1395eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1405eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            delegate.invoke(calleeFrame);
1415eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            calleeFrame.copyReturnValueTo(emulatedStackFrame);
1425eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        }
1435eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    }
1445eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1455eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    /**
1465eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath     * Implements {@code MethodHandles.catchException}.
1475eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath     */
1485eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    public static class CatchException extends Transformer {
1495eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final MethodHandle target;
1505eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final MethodHandle handler;
1515eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final Class<?> exType;
1525eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1535eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final EmulatedStackFrame.Range handlerArgsRange;
1545eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1555eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        public CatchException(MethodHandle target, MethodHandle handler, Class<?> exType) {
1565eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            super(target.type());
1575eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1585eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.target = target;
1595eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.handler = handler;
1605eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.exType = exType;
1615eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1625eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // We only copy the first "count" args, dropping others if required. Note that
1635eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // we subtract one because the first handler arg is the exception thrown by the
1645eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // target.
1655eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            handlerArgsRange = EmulatedStackFrame.Range.of(target.type(), 0,
1665eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    (handler.type().parameterCount() - 1));
1675eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        }
1685eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1695eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        @Override
1705eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
1715eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            try {
1725eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                target.invoke(emulatedStackFrame);
1735eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            } catch (Throwable th) {
1745eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                if (th.getClass() == exType) {
1755eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // We've gotten an exception of the appropriate type, so we need to call
1765eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // the handler. Create a new frame of the appropriate size.
1775eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    EmulatedStackFrame fallback = EmulatedStackFrame.create(handler.type());
1785eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1795eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // The first argument to the handler is the actual exception.
1805eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    fallback.setReference(0, th);
1815eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1825eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // We then copy other arguments that need to be passed through to the handler.
1835eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // Note that we might drop arguments at the end, if needed. Note that
1845eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // referencesStart == 1 because the first argument is the exception type.
1855eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    emulatedStackFrame.copyRangeTo(fallback, handlerArgsRange,
1865eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                            1 /* referencesStart */, 0 /* stackFrameStart */);
1875eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1885eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // Perform the invoke and return the appropriate value.
1895eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    handler.invoke(fallback);
1905eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    fallback.copyReturnValueTo(emulatedStackFrame);
1915eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                } else {
1925eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    // The exception is not of the expected type, we throw it.
1935eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                    throw th;
1945eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                }
1955eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            }
1965eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        }
1975eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    }
1985eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
1995eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    /**
2005eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath     * Implements {@code MethodHandles.GuardWithTest}.
2015eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath     */
2025eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath    public static class GuardWithTest extends Transformer {
2035eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final MethodHandle test;
2045eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final MethodHandle target;
2055eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final MethodHandle fallback;
2065eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
2075eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        private final EmulatedStackFrame.Range testArgsRange;
2085eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
2095eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        public GuardWithTest(MethodHandle test, MethodHandle target, MethodHandle fallback) {
2105eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            super(target.type());
2115eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
2125eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.test = test;
2135eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.target = target;
2145eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            this.fallback = fallback;
2155eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
2165eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // The test method might have a subset of the arguments of the handle / target.
2175eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            testArgsRange = EmulatedStackFrame.Range.of(target.type(), 0, test.type().parameterCount());
2185eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        }
2195eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
2205eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        @Override
2215eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
2225eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            EmulatedStackFrame testFrame = EmulatedStackFrame.create(test.type());
2235eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            emulatedStackFrame.copyRangeTo(testFrame, testArgsRange, 0, 0);
2245eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath
2255eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // We know that the return value for test is going to be boolean.class, so we don't have
2265eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            // to do the copyReturnValue dance.
2275eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            final boolean value = (boolean) test.invoke(testFrame);
2285eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            if (value) {
2295eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                target.invoke(emulatedStackFrame);
2305eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            } else {
2315eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath                fallback.invoke(emulatedStackFrame);
2325eeb4739159cda8b5756d9a38dc7b6c36b0cc03aNarayan Kamath            }
233faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath        }
234faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath    }
235168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
236168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    /**
237168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     * Implementation of MethodHandles.arrayElementGetter for reference types.
238168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     */
239168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    public static class ReferenceArrayElementGetter extends Transformer {
240168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private final Class<?> arrayClass;
241168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
242168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public ReferenceArrayElementGetter(Class<?> arrayClass) {
243168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            super(MethodType.methodType(arrayClass.getComponentType(),
244168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                    new Class<?>[]{arrayClass, int.class}));
245168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            this.arrayClass = arrayClass;
246168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
247168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
248168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        @Override
249168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
250906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader reader = new StackFrameReader();
251168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            reader.attach(emulatedStackFrame);
252168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
253168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            // Read the array object and the index from the stack frame.
254168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            final Object[] array = (Object[]) reader.nextReference(arrayClass);
255168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            final int index = reader.nextInt();
256168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
257168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            // Write the array element back to the stack frame.
258906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
259906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            writer.attach(emulatedStackFrame);
260168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.makeReturnValueAccessor();
261168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.putNextReference(array[index], arrayClass.getComponentType());
262168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
263168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    }
264168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
265168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    /**
266168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     * Implementation of MethodHandles.arrayElementSetter for reference types.
267168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     */
268168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    public static class ReferenceArrayElementSetter extends Transformer {
269168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private final Class<?> arrayClass;
270168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
271168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public ReferenceArrayElementSetter(Class<?> arrayClass) {
272168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            super(MethodType.methodType(void.class,
273168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                    new Class<?>[] { arrayClass, int.class, arrayClass.getComponentType() }));
274168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            this.arrayClass = arrayClass;
275168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
276168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
277168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        @Override
278168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
279906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader reader = new StackFrameReader();
280168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            reader.attach(emulatedStackFrame);
281168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
282168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            // Read the array object, index and the value to write from the stack frame.
283168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            final Object[] array = (Object[]) reader.nextReference(arrayClass);
284168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            final int index = reader.nextInt();
285168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            final Object value = reader.nextReference(arrayClass.getComponentType());
286168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
287168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            array[index] = value;
288168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
289168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    }
290168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
291168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    /**
292168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     * Implementation of MethodHandles.identity() for reference types.
293168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     */
294168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    public static class ReferenceIdentity extends Transformer {
295168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private final Class<?> type;
296168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
297168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public ReferenceIdentity(Class<?> type) {
298168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            super(MethodType.methodType(type, type));
299168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            this.type = type;
300168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
301168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
302168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        @Override
303168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
304906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader reader = new StackFrameReader();
305168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            reader.attach(emulatedStackFrame);
306906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson
307906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
308168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.attach(emulatedStackFrame);
309168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.makeReturnValueAccessor();
310168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.putNextReference(reader.nextReference(type), type);
311168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
312168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    }
313168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
314168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    /**
315168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     * Implementation of MethodHandles.constant.
316168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath     */
317168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    public static class Constant extends Transformer {
318168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private final Class<?> type;
319168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
320168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        // NOTE: This implementation turned out to be more awkward than expected becuase
321168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        // of the type system. We could simplify this considerably at the cost of making
322168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        // the emulated stack frame API uglier or by transitioning into JNI.
323168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        //
324168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        // We could consider implementing this in terms of bind() once that's implemented.
325168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        // This would then just become : MethodHandles.identity(type).bind(value).
326168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private int asInt;
327168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private long asLong;
328168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private float asFloat;
329168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private double asDouble;
330168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private Object asReference;
331168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
332168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        private char typeChar;
333168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
334168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public Constant(Class<?> type, Object value) {
335168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            super(MethodType.methodType(type));
336168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            this.type = type;
337168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
338168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            if (!type.isPrimitive()) {
339168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asReference = value;
340168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'L';
341168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == int.class) {
342168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asInt = (int) value;
343168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'I';
344168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == char.class) {
345168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asInt = (int) (char) value;
346168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'C';
347168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == short.class) {
348168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asInt = (int) (short) value;
349168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'S';
350168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == byte.class) {
351168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asInt = (int) (byte) value;
352168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'B';
353168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == boolean.class) {
354168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asInt = ((boolean) value) ? 1 : 0;
355168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'Z';
356168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == long.class) {
357168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asLong = (long) value;
358168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'J';
359168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == float.class) {
360168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asFloat = (float) value;
361168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'F';
362168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else if (type == double.class) {
363168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                asDouble = (double) value;
364168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                typeChar = 'D';
365168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            } else {
366168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                throw new AssertionError("unknown type: " + typeChar);
367168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            }
368168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
369168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
370168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        @Override
371168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
372906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
373168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.attach(emulatedStackFrame);
374168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            writer.makeReturnValueAccessor();
375168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath
376168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            switch (typeChar) {
377168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'L' : { writer.putNextReference(asReference, type); break; }
378168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'I' : { writer.putNextInt(asInt); break; }
379168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'C' : { writer.putNextChar((char) asInt); break; }
380168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'S' : { writer.putNextShort((short) asInt); break; }
381168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'B' : { writer.putNextByte((byte) asInt); break; }
382168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'Z' : { writer.putNextBoolean(asInt == 1); break; }
383168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'J' : { writer.putNextLong(asLong); break; }
384168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'F' : { writer.putNextFloat(asFloat); break; }
385168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                case 'D' : { writer.putNextDouble(asDouble); break; }
386168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                default:
387168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath                    throw new AssertionError("Unexpected typeChar: " + typeChar);
388168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath            }
389168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath        }
390168dfc7fcb7594933af3bd4a66651f1eb2f09f7fNarayan Kamath    }
391a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
392a80d6f85a6e5154300be8552f027916767704b75Orion Hodson    /*package*/ static class Construct extends Transformer {
393a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        private final MethodHandle constructorHandle;
394a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        private final EmulatedStackFrame.Range callerRange;
395a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
396a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        /*package*/ Construct(MethodHandle constructorHandle, MethodType returnedType) {
397a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            super(returnedType);
398a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            this.constructorHandle = constructorHandle;
399704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            this.callerRange = EmulatedStackFrame.Range.all(type());
400a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        }
401a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
402298c0e8f24657f6dc3fe362fe62b12a187b6faf1Narayan Kamath        MethodHandle getConstructorHandle() {
403298c0e8f24657f6dc3fe362fe62b12a187b6faf1Narayan Kamath            return constructorHandle;
404298c0e8f24657f6dc3fe362fe62b12a187b6faf1Narayan Kamath        }
405298c0e8f24657f6dc3fe362fe62b12a187b6faf1Narayan Kamath
406a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        private static boolean isAbstract(Class<?> klass) {
407a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            return (klass.getModifiers() & Modifier.ABSTRACT) == Modifier.ABSTRACT;
408a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        }
409a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
410a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        private static void checkInstantiable(Class<?> klass) throws InstantiationException {
411a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            if (isAbstract(klass)) {
412a80d6f85a6e5154300be8552f027916767704b75Orion Hodson                String s = klass.isInterface() ? "interface " : "abstract class ";
413a80d6f85a6e5154300be8552f027916767704b75Orion Hodson                throw new InstantiationException("Can't instantiate " + s + klass);
414a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            }
415a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        }
416a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
417a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        @Override
418a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
419a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            final Class<?> receiverType = type().rtype();
420a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            checkInstantiable(receiverType);
421a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
422a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // Allocate memory for receiver.
423a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            Object receiver = Unsafe.getUnsafe().allocateInstance(receiverType);
424a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
425a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // The MethodHandle type for the caller has the form of
426a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // {rtype=T,ptypes=A1..An}. The constructor MethodHandle is of
427a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // the form {rtype=void,ptypes=T,A1...An}. So the frame for
428a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // the constructor needs to have a slot with the receiver
429a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // in position 0.
430a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            EmulatedStackFrame constructorFrame =
431a80d6f85a6e5154300be8552f027916767704b75Orion Hodson                    EmulatedStackFrame.create(constructorHandle.type());
432a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            constructorFrame.setReference(0, receiver);
433a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            emulatedStackFrame.copyRangeTo(constructorFrame, callerRange, 1, 0);
434a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            constructorHandle.invoke(constructorFrame);
435a80d6f85a6e5154300be8552f027916767704b75Orion Hodson
436a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            // Set return result for caller.
437a80d6f85a6e5154300be8552f027916767704b75Orion Hodson            emulatedStackFrame.setReturnValueTo(receiver);
438a80d6f85a6e5154300be8552f027916767704b75Orion Hodson        }
439a80d6f85a6e5154300be8552f027916767704b75Orion Hodson    }
4400ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4410ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath    /**
4420ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath     * Implements MethodHandle.bindTo.
4430ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath     *
4440ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath     * @hide
4450ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath     */
4460ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath    public static class BindTo extends Transformer {
4470ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        private final MethodHandle delegate;
4480ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        private final Object receiver;
4490ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4500ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        private final EmulatedStackFrame.Range range;
4510ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4520ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        public BindTo(MethodHandle delegate, Object receiver) {
4530ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            super(delegate.type().dropParameterTypes(0, 1));
4540ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4550ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            this.delegate = delegate;
4560ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            this.receiver = receiver;
4570ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4580ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            this.range = EmulatedStackFrame.Range.all(this.type());
4590ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        }
4600ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4610ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        @Override
4620ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
4630ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            // Create a new emulated stack frame with the full type (including the leading
4640ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            // receiver reference).
4650ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            EmulatedStackFrame stackFrame = EmulatedStackFrame.create(delegate.type());
4660ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4670ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            // The first reference argument must be the receiver.
4680ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            stackFrame.setReference(0, receiver);
4690ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            // Copy all other arguments.
4700ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            emulatedStackFrame.copyRangeTo(stackFrame, range,
4710ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath                    1 /* referencesStart */, 0 /* stackFrameStart */);
4720ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath
4730ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            // Perform the invoke.
4740ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            delegate.invoke(stackFrame);
4750ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath            stackFrame.copyReturnValueTo(emulatedStackFrame);
4760ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath        }
4770ab46853af9f5c16c877e1677d8d27b8fdecc2cdNarayan Kamath    }
47851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
47951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath    /**
48051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath     * Implements MethodHandle.filterReturnValue.
48151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath     */
48251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath    public static class FilterReturnValue extends Transformer {
48351ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        private final MethodHandle target;
48451ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        private final MethodHandle filter;
48551ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
48651ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        private final EmulatedStackFrame.Range allArgs;
48751ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
48851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        public FilterReturnValue(MethodHandle target, MethodHandle filter) {
48951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            super(MethodType.methodType(filter.type().rtype(), target.type().ptypes()));
49051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
49151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            this.target = target;
49251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            this.filter = filter;
49351ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
49451ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            allArgs = EmulatedStackFrame.Range.all(type());
49551ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        }
49651ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
49751ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        @Override
49851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
49951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            // Create a new frame with the target's type and copy all arguments over.
50051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            // This frame differs in return type with |emulatedStackFrame| but will have
50151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            // the same parameter shapes.
50251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
50351ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            emulatedStackFrame.copyRangeTo(targetFrame, allArgs, 0, 0);
50451ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            target.invoke(targetFrame);
50551ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
50651ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            // Perform the invoke.
507906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader returnValueReader = new StackFrameReader();
50851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            returnValueReader.attach(targetFrame);
50951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            returnValueReader.makeReturnValueAccessor();
51051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
51151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            // Create an emulated frame for the filter and copy all its arguments across.
51251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
513906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter filterWriter = new StackFrameWriter();
51451ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            filterWriter.attach(filterFrame);
51551ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
51651ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            final Class<?> returnType = target.type().rtype();
51751ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            if (!returnType.isPrimitive()) {
51851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextReference(returnValueReader.nextReference(returnType),
51951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                        returnType);
52051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == boolean.class) {
52151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextBoolean(returnValueReader.nextBoolean());
52251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == byte.class) {
52351ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextByte(returnValueReader.nextByte());
52451ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == char.class) {
52551ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextChar(returnValueReader.nextChar());
52651ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == short.class) {
52751ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextShort(returnValueReader.nextShort());
52851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == int.class) {
52951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextInt(returnValueReader.nextInt());
53051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == long.class) {
53151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextLong(returnValueReader.nextLong());
53251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == float.class) {
53351ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextFloat(returnValueReader.nextFloat());
53451ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            } else if (returnType == double.class) {
53551ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath                filterWriter.putNextDouble(returnValueReader.nextDouble());
53651ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            }
53751ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath
53851ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            // Invoke the filter and copy its return value back to the original frame.
53951ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            filter.invoke(filterFrame);
54051ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath            filterFrame.copyReturnValueTo(emulatedStackFrame);
54151ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath        }
54251ab4bf8f05d550d5676cfdd1b00b627f25432ccNarayan Kamath    }
543454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
544454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath    /*
545454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath     * Implements MethodHandles.permuteArguments.
546454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath     *
547454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath     * @hide
548454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath     */
549454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath    public static class PermuteArguments extends Transformer {
550454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        private final MethodHandle target;
551454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        private final int[] reorder;
552454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
553454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        public PermuteArguments(MethodType type, MethodHandle target, int[] reorder) {
554454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            super(type);
555454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
556454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            this.target = target;
557454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            this.reorder = reorder;
558454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        }
559454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
560454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        @Override
561454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
562906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader reader = new StackFrameReader();
563454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            reader.attach(emulatedStackFrame);
564454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
565454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            // In the interests of simplicity, we box / unbox arguments while performing
566454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            // the permutation. We first iterate through the incoming stack frame and box
567454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            // each argument. We then unbox and write out the argument to the target frame
568454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            // according to the specified reordering.
569454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            Object[] arguments = new Object[reorder.length];
570906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final Class<?>[] ptypes = type().ptypes();
571454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            for (int i = 0; i < ptypes.length; ++i) {
572454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                final Class<?> ptype = ptypes[i];
573454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                if (!ptype.isPrimitive()) {
574454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextReference(ptype);
575454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == boolean.class) {
576454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextBoolean();
577454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == byte.class) {
578454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextByte();
579454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == char.class) {
580454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextChar();
581454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == short.class) {
582454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextShort();
583454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == int.class) {
584454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextInt();
585454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == long.class) {
586454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextLong();
587454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == float.class) {
588454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextFloat();
589454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == double.class) {
590454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    arguments[i] = reader.nextDouble();
591454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else {
592454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    throw new AssertionError("Unexpected type: " + ptype);
593454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                }
594454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            }
595454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
596454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
597906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
598454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            writer.attach(calleeFrame);
599454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
600454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            for (int i = 0; i < ptypes.length; ++i) {
601454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                int idx = reorder[i];
602454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                final Class<?> ptype = ptypes[idx];
603454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                final Object argument = arguments[idx];
604454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
605454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                if (!ptype.isPrimitive()) {
606454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextReference(argument, ptype);
607454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == boolean.class) {
608454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextBoolean((boolean) argument);
609454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == byte.class) {
610454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextByte((byte) argument);
611454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == char.class) {
612454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextChar((char) argument);
613454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == short.class) {
614454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextShort((short) argument);
615454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == int.class) {
616454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextInt((int) argument);
617454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == long.class) {
618454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextLong((long) argument);
619454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == float.class) {
620454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextFloat((float) argument);
621454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else if (ptype == double.class) {
622454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    writer.putNextDouble((double) argument);
623454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                } else {
624454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                    throw new AssertionError("Unexpected type: " + ptype);
625454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath                }
626454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            }
627454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath
628454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            target.invoke(calleeFrame);
629454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath            calleeFrame.copyReturnValueTo(emulatedStackFrame);
630454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath        }
631454be6f08e83c97ee14aff0fa2e87c30eedb712dNarayan Kamath    }
632704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
633704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson    /**
634704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson     * Converts methods with a trailing array argument to variable arity
635704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson     * methods. So (A,B,C[])R can be invoked with any number of convertible
636704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson     * arguments after B, e.g. (A,B)R or (A, B, C0)R or (A, B, C0...Cn)R.
637704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson     *
638704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson     * @hide
639704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson     */
640704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson    /*package*/ static class VarargsCollector extends Transformer {
641704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        final MethodHandle target;
642704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
643704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        /*package*/ VarargsCollector(MethodHandle target) {
644704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            super(target.type(), MethodHandle.INVOKE_CALLSITE_TRANSFORM);
645704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (!lastParameterTypeIsAnArray(target.type().ptypes())) {
646704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                throw new IllegalArgumentException("target does not have array as last parameter");
647704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
648704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            this.target = target;
649704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
650704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
651704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static boolean lastParameterTypeIsAnArray(Class<?>[] parameterTypes) {
652704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (parameterTypes.length == 0) return false;
653704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return parameterTypes[parameterTypes.length - 1].isArray();
654704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
655704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
656704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        @Override
657704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        public boolean isVarargsCollector() { return true; }
658704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
659704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        @Override
660704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        public MethodHandle asFixedArity() { return target; }
661704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
662704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        @Override
663704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
664704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            MethodType callerFrameType = callerFrame.getMethodType();
665704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Class<?>[] callerPTypes = callerFrameType.ptypes();
666704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Class<?>[] targetPTypes = type().ptypes();
667704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
668704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            int lastTargetIndex = targetPTypes.length - 1;
669704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (callerPTypes.length == targetPTypes.length &&
670704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                targetPTypes[lastTargetIndex].isAssignableFrom(callerPTypes[lastTargetIndex])) {
671704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                // Caller frame matches target frame in the arity array parameter. Invoke
672704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                // immediately, and let the invoke() dispatch perform any necessary conversions
673704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                // on the other parameters present.
674704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                target.invoke(callerFrame);
675704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                return;
676704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
677704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
678704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (callerPTypes.length < targetPTypes.length - 1) {
679704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                // Too few arguments to be compatible with variable arity invocation.
680704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                throwWrongMethodTypeException(callerFrameType, type());
681704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
682704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
683704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (!MethodType.canConvert(type().rtype(), callerFrameType.rtype())) {
684704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                // Incompatible return type.
685704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                throwWrongMethodTypeException(callerFrameType, type());
686704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
687704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
688704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Class<?> elementType = targetPTypes[lastTargetIndex].getComponentType();
689704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (!arityArgumentsConvertible(callerPTypes, lastTargetIndex, elementType)) {
690704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                // Wrong types to be compatible with variable arity invocation.
691704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                throwWrongMethodTypeException(callerFrameType, type());
692704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
693704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
694704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Allocate targetFrame.
695704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            MethodType targetFrameType = makeTargetFrameType(callerFrameType, type());
696704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetFrameType);
697704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            prepareFrame(callerFrame, targetFrame);
698704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
699704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Invoke target.
700704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            target.invoke(targetFrame);
701704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
702704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Copy return value to the caller's frame.
703704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            targetFrame.copyReturnValueTo(callerFrame);
704704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
705704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
706704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static void throwWrongMethodTypeException(MethodType from, MethodType to) {
707704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            throw new WrongMethodTypeException("Cannot convert " + from + " to " + to);
708704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
709704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
710704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static boolean arityArgumentsConvertible(Class<?>[] ptypes, int arityStart,
711704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                                         Class<?> elementType) {
712704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            if (ptypes.length - 1 == arityStart) {
713704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                if (ptypes[arityStart].isArray() &&
714704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    ptypes[arityStart].getComponentType() == elementType) {
715704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    // The last ptype is in the same position as the arity
716704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    // array and has the same type.
717704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    return true;
718704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
719704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
720704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
721704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = arityStart; i < ptypes.length; ++i) {
722704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                if (!MethodType.canConvert(ptypes[i], elementType)) {
723704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    return false;
724704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
725704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
726704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return true;
727704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
728704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
729704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object referenceArray(StackFrameReader reader, Class<?>[] ptypes,
730704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                             Class<?> elementType, int offset, int length) {
731704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Object arityArray = Array.newInstance(elementType, length);
732704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
733704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
734704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Object o = null;
735704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
736704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'L': { o = reader.nextReference(argumentType); break; }
737704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'I': { o = reader.nextInt(); break; }
738704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'J': { o = reader.nextLong(); break; }
739704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { o = reader.nextByte(); break; }
740704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'S': { o = reader.nextShort(); break; }
741704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'C': { o = reader.nextChar(); break; }
742704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'Z': { o = reader.nextBoolean(); break; }
743704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'F': { o = reader.nextFloat(); break; }
744704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'D': { o = reader.nextDouble(); break; }
745704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
746d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                Array.set(arityArray, i, elementType.cast(o));
747704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
748704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
749704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
750704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
751704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object intArray(StackFrameReader reader, Class<?> ptypes[],
752704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                       int offset, int length) {
753704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            int[] arityArray = new int[length];
754704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
755704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
756704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
757704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'I': { arityArray[i] = reader.nextInt(); break; }
758704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'S': { arityArray[i] = reader.nextShort(); break; }
759704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { arityArray[i] = reader.nextByte(); break; }
760704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: {
761704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        arityArray[i] = (Integer) reader.nextReference(argumentType);
762704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        break;
763704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    }
764704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
765704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
766704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
767704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
768704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
769704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object longArray(StackFrameReader reader, Class<?> ptypes[],
770704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
771704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            long[] arityArray = new long[length];
772704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
773704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
774704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
775704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'J': { arityArray[i] = reader.nextLong(); break; }
776704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'I': { arityArray[i] = reader.nextInt(); break; }
777704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'S': { arityArray[i] = reader.nextShort(); break; }
778704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { arityArray[i] = reader.nextByte(); break; }
779704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: { arityArray[i] = (Long) reader.nextReference(argumentType); break; }
780704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
781704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
782704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
783704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
784704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
785704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object byteArray(StackFrameReader reader, Class<?> ptypes[],
786704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
787704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            byte[] arityArray = new byte[length];
788704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
789704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
790704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
791704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { arityArray[i] = reader.nextByte(); break; }
792704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: { arityArray[i] = (Byte) reader.nextReference(argumentType); break; }
793704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
794704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
795704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
796704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
797704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
798704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object shortArray(StackFrameReader reader, Class<?> ptypes[],
799704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
800704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            short[] arityArray = new short[length];
801704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
802704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
803704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
804704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'S': { arityArray[i] = reader.nextShort(); break; }
805704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { arityArray[i] = reader.nextByte(); break; }
806704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: { arityArray[i] = (Short) reader.nextReference(argumentType); break; }
807704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
808704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
809704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
810704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
811704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
812704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object charArray(StackFrameReader reader, Class<?> ptypes[],
813704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
814704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            char[] arityArray = new char[length];
815704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
816704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
817704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
818704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'C': { arityArray[i] = reader.nextChar(); break; }
819704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: {
820704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        arityArray[i] = (Character) reader.nextReference(argumentType);
821704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        break;
822704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    }
823704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
824704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
825704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
826704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
827704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
828704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object booleanArray(StackFrameReader reader, Class<?> ptypes[],
829704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
830704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            boolean[] arityArray = new boolean[length];
831704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
832704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
833704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
834704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'Z': { arityArray[i] = reader.nextBoolean(); break; }
835704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default:
836704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        arityArray[i] = (Boolean) reader.nextReference(argumentType);
837704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        break;
838704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
839704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
840704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
841704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
842704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
843704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object floatArray(StackFrameReader reader, Class<?> ptypes[],
844704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
845704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            float[] arityArray = new float[length];
846704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
847704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
848704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
849704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'F': { arityArray[i] = reader.nextFloat(); break; }
850704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'J': { arityArray[i] = reader.nextLong(); break; }
851704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'I': { arityArray[i] = reader.nextInt(); break; }
852704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'S': { arityArray[i] = reader.nextShort(); break; }
853704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { arityArray[i] = reader.nextByte(); break; }
854704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: {
855704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        arityArray[i] = (Float) reader.nextReference(argumentType);
856704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        break;
857704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    }
858704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
859704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
860704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
861704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
862704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
863704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object doubleArray(StackFrameReader reader, Class<?> ptypes[],
864704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                        int offset, int length) {
865704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            double[] arityArray = new double[length];
866704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < length; ++i) {
867704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> argumentType = ptypes[i + offset];
868704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                switch (Wrapper.basicTypeChar(argumentType)) {
869704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'D': { arityArray[i] = reader.nextDouble(); break; }
870704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'F': { arityArray[i] = reader.nextFloat(); break; }
871704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'J': { arityArray[i] = reader.nextLong(); break; }
872704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'I': { arityArray[i] = reader.nextInt(); break; }
873704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'S': { arityArray[i] = reader.nextShort(); break; }
874704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    case 'B': { arityArray[i] = reader.nextByte(); break; }
875704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    default: {
876704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        arityArray[i] = (Double) reader.nextReference(argumentType);
877704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                        break;
878704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                    }
879704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                }
880704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
881704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return arityArray;
882704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
883704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
884704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static Object makeArityArray(MethodType callerFrameType,
885704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                             StackFrameReader callerFrameReader,
886704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                             int indexOfArityArray,
887704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                             Class<?> arityArrayType) {
888704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            int arityArrayLength = callerFrameType.ptypes().length - indexOfArityArray;
889704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Class<?> elementType = arityArrayType.getComponentType();
890704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Class<?>[] callerPTypes = callerFrameType.ptypes();
891704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
892704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            char elementBasicType = Wrapper.basicTypeChar(elementType);
893704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            switch (elementBasicType) {
894704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'L': return referenceArray(callerFrameReader, callerPTypes, elementType,
895704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                                indexOfArityArray, arityArrayLength);
896704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'I': return intArray(callerFrameReader, callerPTypes,
897704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                          indexOfArityArray, arityArrayLength);
898704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'J': return longArray(callerFrameReader, callerPTypes,
899704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                           indexOfArityArray, arityArrayLength);
900704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'B': return byteArray(callerFrameReader, callerPTypes,
901704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                           indexOfArityArray, arityArrayLength);
902704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'S': return shortArray(callerFrameReader, callerPTypes,
903704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                            indexOfArityArray, arityArrayLength);
904704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'C': return charArray(callerFrameReader, callerPTypes,
905704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                           indexOfArityArray, arityArrayLength);
906704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'Z': return booleanArray(callerFrameReader, callerPTypes,
907704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                              indexOfArityArray, arityArrayLength);
908704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'F': return floatArray(callerFrameReader, callerPTypes,
909704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                            indexOfArityArray, arityArrayLength);
910704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'D': return doubleArray(callerFrameReader, callerPTypes,
911704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                             indexOfArityArray, arityArrayLength);
912704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
913704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            throw new InternalError("Unexpected type: " + elementType);
914704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
915704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
9160e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        public static Object collectArguments(char basicComponentType, Class<?> componentType,
9170e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                                              StackFrameReader reader, Class<?>[] types,
9180e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                                              int startIdx, int length) {
9190e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            switch (basicComponentType) {
9200e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'L': return referenceArray(reader, types, componentType, startIdx, length);
9210e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'I': return intArray(reader, types, startIdx, length);
9220e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'J': return longArray(reader, types, startIdx, length);
9230e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'B': return byteArray(reader, types, startIdx, length);
9240e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'S': return shortArray(reader, types, startIdx, length);
9250e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'C': return charArray(reader, types, startIdx, length);
9260e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'Z': return booleanArray(reader, types, startIdx, length);
9270e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'F': return floatArray(reader, types, startIdx, length);
9280e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'D': return doubleArray(reader, types, startIdx, length);
9290e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            }
9300e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            throw new InternalError("Unexpected type: " + basicComponentType);
9310e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        }
9320e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
933704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static void copyParameter(StackFrameReader reader, StackFrameWriter writer,
934704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                          Class<?> ptype) {
935704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            switch (Wrapper.basicTypeChar(ptype)) {
936704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'L': { writer.putNextReference(reader.nextReference(ptype), ptype); break; }
937704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'I': { writer.putNextInt(reader.nextInt()); break; }
938704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'J': { writer.putNextLong(reader.nextLong()); break; }
939704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'B': { writer.putNextByte(reader.nextByte()); break; }
940704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'S': { writer.putNextShort(reader.nextShort()); break; }
941704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'C': { writer.putNextChar(reader.nextChar()); break; }
942704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'Z': { writer.putNextBoolean(reader.nextBoolean()); break; }
943704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'F': { writer.putNextFloat(reader.nextFloat()); break; }
944704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                case 'D': { writer.putNextDouble(reader.nextDouble()); break; }
945704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                default: throw new InternalError("Unexpected type: " + ptype);
946704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
947704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
948704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
949704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static void prepareFrame(EmulatedStackFrame callerFrame,
950704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                         EmulatedStackFrame targetFrame) {
951704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            StackFrameWriter targetWriter = new StackFrameWriter();
952704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            targetWriter.attach(targetFrame);
953704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            StackFrameReader callerReader = new StackFrameReader();
954704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            callerReader.attach(callerFrame);
955704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
956704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Copy parameters from |callerFrame| to |targetFrame| leaving room for arity array.
957704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            MethodType targetMethodType = targetFrame.getMethodType();
958704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            int indexOfArityArray = targetMethodType.ptypes().length - 1;
959704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            for (int i = 0; i < indexOfArityArray; ++i) {
960704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                Class<?> ptype = targetMethodType.ptypes()[i];
961704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                copyParameter(callerReader, targetWriter, ptype);
962704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            }
963704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
964704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Add arity array as last parameter in |targetFrame|.
965704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Class<?> arityArrayType = targetMethodType.ptypes()[indexOfArityArray];
966704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            Object arityArray = makeArityArray(callerFrame.getMethodType(), callerReader,
967704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                               indexOfArityArray, arityArrayType);
968704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            targetWriter.putNextReference(arityArray, arityArrayType);
969704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
970704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson
971704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        /**
972704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         * Computes the frame type to invoke the target method handle with. This
973704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         * is the same as the caller frame type, but with the trailing argument
974704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         * being the array type that is the trailing argument in the target method
975704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         * handle.
976704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         *
977704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         * Suppose the targetType is (T0, T1, T2[])RT and the callerType is (C0, C1, C2, C3)RC
978704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         * then the constructed type is (C0, C1, T2[])RC.
979704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson         */
980704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        private static MethodType makeTargetFrameType(MethodType callerType,
981704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson                                                      MethodType targetType) {
982704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            final int ptypesLength = targetType.ptypes().length;
983704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            final Class<?>[] ptypes = new Class<?>[ptypesLength];
984704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Copy types from caller types to new methodType.
985704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            System.arraycopy(callerType.ptypes(), 0, ptypes, 0, ptypesLength - 1);
986704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // Set the last element in the type array to be the
987704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            // varargs array of the target.
988704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            ptypes[ptypesLength - 1] = targetType.ptypes()[ptypesLength - 1];
989704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson            return MethodType.methodType(callerType.rtype(), ptypes);
990704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson        }
991704b13a41cc7efd49acf66064109756a248fe0dcOrion Hodson    }
9920a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath
9930a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath    /**
9940a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath     * Implements MethodHandles.invoker & MethodHandles.exactInvoker.
9950a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath     */
9960a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath    static class Invoker extends Transformer {
9970a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        private final MethodType targetType;
9980a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        private final boolean isExactInvoker;
9990a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        private final EmulatedStackFrame.Range copyRange;
10000a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath
10010a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        Invoker(MethodType targetType, boolean isExactInvoker) {
10020a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            super(targetType.insertParameterTypes(0, MethodHandle.class));
10030a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            this.targetType = targetType;
10040a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            this.isExactInvoker = isExactInvoker;
10050a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            copyRange = EmulatedStackFrame.Range.of(type(), 1, type().parameterCount());
10060a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        }
10070a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath
10080a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        @Override
10090a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        public void transform(EmulatedStackFrame emulatedStackFrame) throws Throwable {
10100a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            // We need to artifically throw a WrongMethodTypeException here because we
10110a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            // can't call invokeExact on the target inside the transformer.
10120a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            if (isExactInvoker) {
10130a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                // TODO: We should do the comparison by hand if this new type creation
10140a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                // on every invoke proves too expensive.
10150a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                MethodType callType = emulatedStackFrame.getCallsiteType().dropParameterTypes(0, 1);
10160a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                if (!targetType.equals(callType)) {
10170a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                    throw new WrongMethodTypeException("Wrong type, Expected: " + targetType
10180a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                            + " was: " + callType);
10190a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath                }
10200a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            }
10210a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath
10220a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            // The first argument to the stack frame is the handle that needs to be invoked.
10230a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            MethodHandle target = emulatedStackFrame.getReference(0, MethodHandle.class);
10240a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath
10250a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            // All other arguments must be copied to the target frame.
10260a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(targetType);
10270a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            emulatedStackFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
10280a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath
10290a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            // Finally, invoke the handle and copy the return value.
10300a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            target.invoke(targetFrame);
10310a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath            targetFrame.copyReturnValueTo(emulatedStackFrame);
10320a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath        }
10330a72753297b45d08ca33cf7e87888f5fee87f69eNarayan Kamath    }
1034378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1035378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath    /**
1036378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath     * Implements MethodHandle.asSpreader / MethodHandles.spreadInvoker.
1037378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath     */
1038378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath    static class Spreader extends Transformer {
1039378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        /** The method handle we're delegating to. */
1040378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        private final MethodHandle target;
1041378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1042378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        /**
1043378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * The offset of the trailing array argument in the list of arguments to
1044378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * this transformer. The array argument is always the last argument.
1045378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         */
1046378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        private final int arrayOffset;
1047378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1048378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        /**
1049378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * The type char of the component type of the array.
1050378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         */
1051378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        private final char arrayTypeChar;
1052378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1053378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        /**
1054378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * The number of input arguments that will be present in the array. In other words,
1055378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * this is the expected array length.
1056378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         */
1057378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        private final int numArrayArgs;
1058378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1059378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        /**
1060378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * Range of arguments to copy verbatim from the input frame, This will cover all
1061378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         * arguments that aren't a part of the trailing array.
1062378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath         */
1063378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        private final Range copyRange;
1064378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1065378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        Spreader(MethodHandle target, MethodType spreaderType, int numArrayArgs) {
1066378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            super(spreaderType);
1067378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            this.target = target;
1068378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Copy all arguments except the last argument (which is the trailing array argument
1069378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // that needs to be spread).
1070378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            arrayOffset = spreaderType.parameterCount() - 1;
1071378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1072378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Get and cache the component type of the input array.
1073378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?> componentType = spreaderType.ptypes()[arrayOffset].getComponentType();
1074378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            if (componentType == null) {
1075378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                throw new AssertionError("Trailing argument must be an array.");
1076378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1077378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            arrayTypeChar = Wrapper.basicTypeChar(componentType);
1078378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1079378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            this.numArrayArgs = numArrayArgs;
1080378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Copy all args except for the last argument.
1081378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            this.copyRange = EmulatedStackFrame.Range.of(spreaderType, 0, arrayOffset);
1082378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1083378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1084378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        @Override
1085378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
1086378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Create a new stack frame for the callee.
1087378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1088378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1089378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Copy all arguments except for the trailing array argument.
1090378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
1091378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1092378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Attach the writer, prepare to spread the trailing array arguments into
1093378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // the callee frame.
1094906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            StackFrameWriter writer = new StackFrameWriter();
1095378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            writer.attach(targetFrame,
1096378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    arrayOffset,
1097378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    copyRange.numReferences,
1098378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    copyRange.numBytes);
1099378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1100378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            // Get the array reference and check that its length is as expected.
1101378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            Object arrayObj = callerFrame.getReference(
1102378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    copyRange.numReferences, this.type().ptypes()[arrayOffset]);
1103378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final int arrayLength = Array.getLength(arrayObj);
1104378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            if (arrayLength != numArrayArgs) {
1105378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                throw new IllegalArgumentException("Invalid array length: " + arrayLength);
1106378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1107378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1108378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final MethodType type = target.type();
1109378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            switch (arrayTypeChar) {
1110378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'L':
1111378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((Object[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1112378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1113378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'I':
1114378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((int[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1115378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1116378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'J':
1117378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((long[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1118378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1119378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'B':
1120378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((byte[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1121378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1122378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'S':
1123378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((short[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1124378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1125378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'C':
1126378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((char[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1127378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1128378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'Z':
1129378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((boolean[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1130378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1131378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'F':
1132378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((float[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1133378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1134378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                case 'D':
1135378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    spreadArray((double[]) arrayObj, writer, type, numArrayArgs, arrayOffset);
1136378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    break;
1137378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1138378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1139378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1140378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            target.invoke(targetFrame);
1141378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            targetFrame.copyReturnValueTo(callerFrame);
1142378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1143378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1144378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(Object[] array, StackFrameWriter writer, MethodType type,
1145378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1146378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1147378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1148378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1149378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Object o = array[i];
1150378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1151378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(o, argumentType); break; }
1152378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'I': { writer.putNextInt((int) o); break; }
1153378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'J': { writer.putNextLong((long) o); break; }
1154378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'B': { writer.putNextByte((byte) o); break; }
1155378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'S': { writer.putNextShort((short) o); break; }
1156378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'C': { writer.putNextChar((char) o); break; }
1157378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'Z': { writer.putNextBoolean((boolean) o); break; }
1158378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat((float) o); break; }
1159378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble((double) o); break; }
1160378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1161378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1162378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1163378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1164378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(int[] array, StackFrameWriter writer, MethodType type,
1165378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1166378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1167378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1168378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1169378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                int j = array[i];
1170378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1171378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(j, argumentType); break; }
1172378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'I': { writer.putNextInt(j); break; }
1173378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'J': { writer.putNextLong(j); break; }
1174378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat(j); break; }
1175378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble(j); break; }
1176378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1177378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1178378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1179378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1180378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1181378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(long[] array, StackFrameWriter writer, MethodType type,
1182378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1183378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1184378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1185378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1186378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                long l = array[i];
1187378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1188378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(l, argumentType); break; }
1189378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'J': { writer.putNextLong(l); break; }
1190378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat((float) l); break; }
1191378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble((double) l); break; }
1192378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1193378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1194378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1195378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1196378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1197378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(byte[] array,
1198378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       StackFrameWriter writer, MethodType type,
1199378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1200378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1201378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1202378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1203378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                byte b = array[i];
1204378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1205378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(b, argumentType); break; }
1206378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'I': { writer.putNextInt(b); break; }
1207378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'J': { writer.putNextLong(b); break; }
1208378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'B': { writer.putNextByte(b); break; }
1209378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'S': { writer.putNextShort(b); break; }
1210378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat(b); break; }
1211378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble(b); break; }
1212378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1213378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1214378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1215378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1216378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1217378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(short[] array,
1218378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       StackFrameWriter writer, MethodType type,
1219378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1220378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1221378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1222378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1223378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                short s = array[i];
1224378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1225378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(s, argumentType); break; }
1226378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'I': { writer.putNextInt(s); break; }
1227378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'J': { writer.putNextLong(s); break; }
1228378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'S': { writer.putNextShort(s); break; }
1229378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat(s); break; }
1230378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble(s); break; }
1231378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1232378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1233378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1234378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1235378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1236378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(char[] array,
1237378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       StackFrameWriter writer, MethodType type,
1238378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1239378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1240378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1241378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1242378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                char c = array[i];
1243378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1244378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(c, argumentType); break; }
1245378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'I': { writer.putNextInt(c); break; }
1246378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'J': { writer.putNextLong(c); break; }
1247378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'C': { writer.putNextChar(c); break; }
1248378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat(c); break; }
1249378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble(c); break; }
1250378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1251378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1252378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1253378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1254378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1255378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(boolean[] array,
1256378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       StackFrameWriter writer, MethodType type,
1257378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1258378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1259378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1260378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1261378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                boolean z = array[i];
1262378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1263378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(z, argumentType); break; }
1264378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'Z': { writer.putNextBoolean(z); break; }
1265378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1266378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1267378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1268378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1269378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1270378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(double[] array,
1271378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       StackFrameWriter writer, MethodType type,
1272378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1273378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1274378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1275378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1276378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                double d = array[i];
1277378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1278378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(d, argumentType); break; }
1279378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble(d); break; }
1280378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1281378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1282378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1283378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1284378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath
1285378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        public static void spreadArray(float[] array, StackFrameWriter writer, MethodType type,
1286378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                                       int numArgs, int offset) {
1287378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            final Class<?>[] ptypes = type.ptypes();
1288378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            for (int i = 0; i < numArgs; ++i) {
1289378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                Class<?> argumentType = ptypes[i + offset];
1290378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                float f = array[i];
1291378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                switch (Wrapper.basicTypeChar(argumentType)) {
1292378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'L': { writer.putNextReference(f, argumentType); break; }
1293378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'D': { writer.putNextDouble((double) f); break; }
1294378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    case 'F': { writer.putNextFloat(f); break; }
1295378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                    default : { throw new AssertionError(); }
1296378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath                }
1297378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath            }
1298378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath        }
1299378d458718d98d264b58734c87568ee5de9a6781Narayan Kamath    }
13000e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13010e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath    /**
13020e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath     * Implements MethodHandle.asCollector.
13030e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath     */
13040e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath    static class Collector extends Transformer {
13050e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        private final MethodHandle target;
13060e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13070e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        /**
13080e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * The offset of the trailing array argument in the list of arguments to
13090e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * this transformer. The array argument is always the last argument.
13100e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         */
13110e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        private final int arrayOffset;
13120e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13130e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        /**
13140e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * The number of input arguments that will be present in the array. In other words,
13150e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * this is the expected array length.
13160e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         */
13170e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        private final int numArrayArgs;
13180e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13190e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        /**
13200e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * The type char of the component type of the array.
13210e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         */
13220e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        private final char arrayTypeChar;
13230e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13240e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        /**
13250e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * Range of arguments to copy verbatim from the input frame, This will cover all
13260e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         * arguments that aren't a part of the trailing array.
13270e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath         */
13280e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        private final Range copyRange;
13290e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13300e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        Collector(MethodHandle delegate, Class<?> arrayType, int length) {
13310e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            super(delegate.type().asCollectorType(arrayType, length));
13320e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13330e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            target = delegate;
13340e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // Copy all arguments except the last argument (which is the trailing array argument
13350e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // that needs to be spread).
13360e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            arrayOffset = delegate.type().parameterCount() - 1;
13370e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            arrayTypeChar = Wrapper.basicTypeChar(arrayType.getComponentType());
13380e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            numArrayArgs = length;
13390e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13400e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // Copy all args except for the last argument.
13410e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            copyRange = EmulatedStackFrame.Range.of(delegate.type(), 0, arrayOffset);
13420e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        }
13430e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13440e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        @Override
13450e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
13460e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // Create a new stack frame for the callee.
13470e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
13480e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13490e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // Copy all arguments except for the trailing array argument.
13500e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            callerFrame.copyRangeTo(targetFrame, copyRange, 0, 0);
13510e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13520e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // Attach the writer, prepare to spread the trailing array arguments into
13530e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            // the callee frame.
1354906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
13550e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            writer.attach(targetFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
1356906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader reader = new StackFrameReader();
13570e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            reader.attach(callerFrame, arrayOffset, copyRange.numReferences, copyRange.numBytes);
13580e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13590e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            switch (arrayTypeChar) {
13600e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'L': {
13610e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    // Reference arrays are the only case where the component type of the
13620e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    // array we construct might differ from the type of the reference we read
13630e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    // from the stack frame.
13640e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    final Class<?> targetType = target.type().ptypes()[arrayOffset];
13650e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    final Class<?> targetComponentType = targetType.getComponentType();
13660e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    final Class<?> adapterComponentType = type().lastParameterType();
13670e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13680e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    Object[] arr = (Object[]) Array.newInstance(targetComponentType, numArrayArgs);
13690e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
13700e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        arr[i] = reader.nextReference(adapterComponentType);
13710e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
13720e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
13730e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(arr, targetType);
13740e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
13750e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
13760e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'I': {
13770e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    int[] array = new int[numArrayArgs];
13780e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
13790e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextInt();
13800e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
13810e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, int[].class);
13820e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
13830e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
13840e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'J': {
13850e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    long[] array = new long[numArrayArgs];
13860e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
13870e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextLong();
13880e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
13890e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, long[].class);
13900e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
13910e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
13920e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'B': {
13930e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    byte[] array = new byte[numArrayArgs];
13940e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
13950e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextByte();
13960e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
13970e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, byte[].class);
13980e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
13990e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
14000e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'S': {
14010e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    short[] array = new short[numArrayArgs];
14020e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
14030e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextShort();
14040e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
14050e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, short[].class);
14060e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
14070e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
14080e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'C': {
14090e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    char[] array = new char[numArrayArgs];
14100e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
14110e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextChar();
14120e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
14130e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, char[].class);
14140e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
14150e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
14160e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'Z': {
14170e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    boolean[] array = new boolean[numArrayArgs];
14180e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
14190e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextBoolean();
14200e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
14210e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, boolean[].class);
14220e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
14230e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
14240e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'F': {
14250e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    float[] array = new float[numArrayArgs];
14260e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
14270e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextFloat();
14280e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
14290e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, float[].class);
14300e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
14310e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
14320e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                case 'D': {
14330e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    double[] array = new double[numArrayArgs];
14340e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    for (int i = 0; i < numArrayArgs; ++i) {
14350e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                        array[i] = reader.nextDouble();
14360e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    }
14370e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    writer.putNextReference(array, double[].class);
14380e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                    break;
14390e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath                }
14400e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            }
14410e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath
14420e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            target.invoke(targetFrame);
14430e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath            targetFrame.copyReturnValueTo(callerFrame);
14440e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath        }
14450e8de7372de378e00c429dbf9d55526d433a7a21Narayan Kamath    }
1446d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1447d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    /*
1448d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     * Implements MethodHandles.filterArguments.
1449d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     */
1450d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    static class FilterArguments extends Transformer {
1451d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        /** The target handle. */
1452d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle target;
1453d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        /** Index of the first argument to filter */
1454d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int pos;
1455d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        /** The list of filters to apply */
1456d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle[] filters;
1457d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1458d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        FilterArguments(MethodHandle target, int pos, MethodHandle[] filters) {
1459d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            super(deriveType(target, pos, filters));
1460d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1461d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.target = target;
1462d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.pos = pos;
1463d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.filters = filters;
1464d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1465d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1466d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1467d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private static MethodType deriveType(MethodHandle target, int pos, MethodHandle[] filters) {
1468d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final Class<?>[] filterArgs = new Class<?>[filters.length];
1469d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            for (int i = 0; i < filters.length; ++i) {
1470d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                filterArgs[i] = filters[i].type().parameterType(0);
1471d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1472d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1473d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            return target.type().replaceParameterTypes(pos, pos + filters.length, filterArgs);
1474d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1475d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1476d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        @Override
1477d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1478906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameReader reader = new StackFrameReader();
1479d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            reader.attach(stackFrame);
1480d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1481d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            EmulatedStackFrame transformedFrame = EmulatedStackFrame.create(target.type());
1482906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
1483d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            writer.attach(transformedFrame);
1484d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1485d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final Class<?>[] ptypes = target.type().ptypes();
1486d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            for (int i = 0; i < ptypes.length; ++i) {
1487d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                // Check whether the current argument has a filter associated with it.
1488d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                // If it has no filter, no further action need be taken.
1489d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                final Class<?> ptype = ptypes[i];
1490d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                final MethodHandle filter;
1491d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                if (i < pos) {
1492d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filter = null;
1493d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                } else if (i >= pos + filters.length) {
1494d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filter = null;
1495d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                } else {
1496d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filter = filters[i - pos];
1497d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                }
1498d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1499d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                if (filter != null) {
1500d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    // Note that filter.type() must be (ptype)ptype - this is checked before
1501d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    // this transformer is created.
1502d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    EmulatedStackFrame filterFrame = EmulatedStackFrame.create(filter.type());
1503d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1504d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    //  Copy the next argument from the stack frame to the filter frame.
1505906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson                    final StackFrameWriter filterWriter = new StackFrameWriter();
1506d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filterWriter.attach(filterFrame);
1507d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    copyNext(reader, filterWriter, filter.type().ptypes()[0]);
1508d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1509d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filter.invoke(filterFrame);
1510d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1511d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    // Copy the argument back from the filter frame to the stack frame.
1512906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson                    final StackFrameReader filterReader = new StackFrameReader();
1513d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filterReader.attach(filterFrame);
1514d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    filterReader.makeReturnValueAccessor();
1515d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    copyNext(filterReader, writer, ptype);
1516d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                } else {
1517d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    // There's no filter associated with this frame, just copy the next argument
1518d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    // over.
1519d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    copyNext(reader, writer, ptype);
1520d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                }
1521d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1522d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1523d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            target.invoke(transformedFrame);
1524d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            transformedFrame.copyReturnValueTo(stackFrame);
1525d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1526d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    }
1527d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1528d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    /**
1529d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     * Implements MethodHandles.collectArguments.
1530d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     */
1531d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    static class CollectArguments extends Transformer {
1532d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle target;
1533d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle collector;
1534d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int pos;
1535d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1536d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        /** The range of input arguments we copy to the collector. */
1537d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range collectorRange;
1538d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1539d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        /**
1540d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath         * The first range of arguments we copy to the target. These are arguments
1541d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath         * in the range [0, pos). Note that arg[pos] is the return value of the filter.
1542d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath         */
1543d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range range1;
1544d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1545d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        /**
1546d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath         * The second range of arguments we copy to the target. These are arguments in the range
1547d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath         * (pos, N], where N is the number of target arguments.
1548d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath         */
1549d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range range2;
1550d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1551d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int referencesOffset;
1552d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int stackFrameOffset;
1553d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1554d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        CollectArguments(MethodHandle target, MethodHandle collector, int pos,
1555d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                         MethodType adapterType) {
1556d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            super(adapterType);
1557d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1558d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.target = target;
1559d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.collector = collector;
1560d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.pos = pos;
1561d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1562d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final int numFilterArgs = collector.type().parameterCount();
1563d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final int numAdapterArgs = type().parameterCount();
1564d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            collectorRange = Range.of(type(), pos, pos + numFilterArgs);
1565d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1566d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            range1 = Range.of(type(), 0, pos);
1567d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (pos + numFilterArgs < numAdapterArgs) {
1568d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                this.range2 = Range.of(type(), pos + numFilterArgs, numAdapterArgs);
1569d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            } else {
1570d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                this.range2 = null;
1571d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1572d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1573d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Calculate the number of primitive bytes (or references) we copy to the
1574d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // target frame based on the return value of the combiner.
1575d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final Class<?> collectorRType = collector.type().rtype();
1576d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (collectorRType == void.class) {
1577d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrameOffset = 0;
1578d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                referencesOffset = 0;
1579d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            } else if (collectorRType.isPrimitive()) {
1580d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrameOffset = EmulatedStackFrame.getSize(collectorRType);
1581d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                referencesOffset = 0;
1582d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            } else {
1583d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrameOffset = 0;
1584d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                referencesOffset = 1;
1585d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1586d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1587d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1588d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        @Override
1589d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1590d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // First invoke the collector.
1591d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            EmulatedStackFrame filterFrame = EmulatedStackFrame.create(collector.type());
1592d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            stackFrame.copyRangeTo(filterFrame, collectorRange, 0, 0);
1593d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            collector.invoke(filterFrame);
1594d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1595d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Start constructing the target frame.
1596d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1597d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            stackFrame.copyRangeTo(targetFrame, range1, 0, 0);
1598d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1599d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // If one of these offsets is not zero, we have a return value to copy.
1600d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (referencesOffset != 0 || stackFrameOffset != 0) {
1601906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson                final StackFrameReader reader = new StackFrameReader();
1602d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                reader.attach(filterFrame).makeReturnValueAccessor();
1603906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson                final StackFrameWriter writer = new StackFrameWriter();
1604d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                writer.attach(targetFrame, pos, range1.numReferences, range1.numBytes);
1605d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                copyNext(reader, writer, target.type().ptypes()[0]);
1606d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1607d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1608d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (range2 != null) {
1609d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrame.copyRangeTo(targetFrame, range2,
1610d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        range1.numReferences + referencesOffset,
1611d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        range2.numBytes + stackFrameOffset);
1612d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1613d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1614d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            target.invoke(targetFrame);
1615d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            targetFrame.copyReturnValueTo(stackFrame);
1616d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1617d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    }
1618d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1619d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    /**
1620d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     * Implements MethodHandles.foldArguments.
1621d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     */
1622d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    static class FoldArguments extends Transformer {
1623d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle target;
1624d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle combiner;
1625d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1626d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range combinerArgs;
1627d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range targetArgs;
1628d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1629d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int referencesOffset;
1630d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int stackFrameOffset;
1631d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1632d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        FoldArguments(MethodHandle target, MethodHandle combiner) {
1633d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            super(deriveType(target, combiner));
1634d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1635d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.target = target;
1636d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.combiner = combiner;
1637d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1638d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            combinerArgs = Range.all(combiner.type());
1639d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            targetArgs = Range.all(type());
1640d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1641d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final Class<?> combinerRType = combiner.type().rtype();
1642d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (combinerRType == void.class) {
1643d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrameOffset = 0;
1644d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                referencesOffset = 0;
1645d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            } else if (combinerRType.isPrimitive()) {
1646d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrameOffset = EmulatedStackFrame.getSize(combinerRType);
1647d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                referencesOffset = 0;
1648d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            } else {
1649d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrameOffset = 0;
1650d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                referencesOffset = 1;
1651d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1652d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1653d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1654d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        @Override
1655d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1656d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // First construct the combiner frame and invoke it.
1657d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            EmulatedStackFrame combinerFrame = EmulatedStackFrame.create(combiner.type());
1658d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            stackFrame.copyRangeTo(combinerFrame, combinerArgs, 0, 0);
1659d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            combiner.invoke(combinerFrame);
1660d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1661d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Create the stack frame for the target.
1662d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1663d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1664d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // If one of these offsets is not zero, we have a return value to copy.
1665d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (referencesOffset != 0 || stackFrameOffset != 0) {
1666906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson                final StackFrameReader reader = new StackFrameReader();
1667d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                reader.attach(combinerFrame).makeReturnValueAccessor();
1668906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson                final StackFrameWriter writer = new StackFrameWriter();
1669d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                writer.attach(targetFrame);
1670d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                copyNext(reader, writer, target.type().ptypes()[0]);
1671d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1672d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1673d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            stackFrame.copyRangeTo(targetFrame, targetArgs, referencesOffset, stackFrameOffset);
1674d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            target.invoke(targetFrame);
1675d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1676d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            targetFrame.copyReturnValueTo(stackFrame);
1677d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1678d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1679d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private static MethodType deriveType(MethodHandle target, MethodHandle combiner) {
1680d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (combiner.type().rtype() == void.class) {
1681d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                return target.type();
1682d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1683d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1684d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            return target.type().dropParameterTypes(0, 1);
1685d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1686d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    }
1687d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1688d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    /**
1689d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     * Implements MethodHandles.insertArguments.
1690d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath     */
1691d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    static class InsertArguments extends Transformer {
1692d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final MethodHandle target;
1693d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final int pos;
1694d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Object[] values;
1695d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1696d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range range1;
1697d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        private final Range range2;
1698d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1699d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        InsertArguments(MethodHandle target, int pos, Object[] values) {
1700d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            super(target.type().dropParameterTypes(pos, pos + values.length));
1701d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.target = target;
1702d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.pos = pos;
1703d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            this.values = values;
1704d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1705d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final MethodType type = type();
1706d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            range1 = EmulatedStackFrame.Range.of(type, 0, pos);
1707d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            range2 = Range.of(type, pos, type.parameterCount());
1708d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1709d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1710d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        @Override
1711d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        public void transform(EmulatedStackFrame stackFrame) throws Throwable {
1712d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            EmulatedStackFrame calleeFrame = EmulatedStackFrame.create(target.type());
1713d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1714d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Copy all arguments before |pos|.
1715d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            stackFrame.copyRangeTo(calleeFrame, range1, 0, 0);
1716d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1717d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Attach a stack frame writer so that we can copy the next |values.length|
1718d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // arguments.
1719906e740fc43ed5c4c701986386dfa6659388dd44Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
1720d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            writer.attach(calleeFrame, pos, range1.numReferences, range1.numBytes);
1721d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1722d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Copy all the arguments supplied in |values|.
1723d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            int referencesCopied = 0;
1724d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            int bytesCopied = 0;
1725d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            final Class<?>[] ptypes = target.type().ptypes();
1726d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            for (int i = 0; i < values.length; ++i) {
1727d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                final Class<?> ptype = ptypes[i + pos];
1728d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                if (ptype.isPrimitive()) {
1729d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    if (ptype == boolean.class) {
1730d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextBoolean((boolean) values[i]);
1731d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == byte.class) {
1732d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextByte((byte) values[i]);
1733d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == char.class) {
1734d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextChar((char) values[i]);
1735d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == short.class) {
1736d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextShort((short) values[i]);
1737d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == int.class) {
1738d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextInt((int) values[i]);
1739d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == long.class) {
1740d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextLong((long) values[i]);
1741d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == float.class) {
1742d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextFloat((float) values[i]);
1743d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    } else if (ptype == double.class) {
1744d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        writer.putNextDouble((double) values[i]);
1745d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    }
1746d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1747d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    bytesCopied += EmulatedStackFrame.getSize(ptype);
1748d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                } else {
1749d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    writer.putNextReference(values[i], ptype);
1750d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                    referencesCopied++;
1751d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                }
1752d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1753d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1754d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            // Copy all remaining arguments.
1755d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            if (range2 != null) {
1756d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                stackFrame.copyRangeTo(calleeFrame, range2,
1757d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        range1.numReferences + referencesCopied,
1758d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath                        range1.numBytes + bytesCopied);
1759d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            }
1760d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath
1761d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            target.invoke(calleeFrame);
1762d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath            calleeFrame.copyReturnValueTo(stackFrame);
1763d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath        }
1764d6cb653555a60e070b5fbbdfb48de05b5dc748bcNarayan Kamath    }
1765d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1766d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1767d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson    /**
1768d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson     * Implements {@link java.lang.invokeMethodHandles#explicitCastArguments()}.
1769d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson     */
1770d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson    public static class ExplicitCastArguments extends Transformer {
1771d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private final MethodHandle target;
1772d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1773d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        public ExplicitCastArguments(MethodHandle target, MethodType type) {
1774d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            super(type);
1775d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            this.target = target;
1776d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1777d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1778d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        @Override
1779d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        public void transform(EmulatedStackFrame callerFrame) throws Throwable {
1780d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            // Create a new stack frame for the target.
1781d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            EmulatedStackFrame targetFrame = EmulatedStackFrame.create(target.type());
1782d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1783d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            explicitCastArguments(callerFrame, targetFrame);
1784d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            target.invoke(targetFrame);
1785d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            explicitCastReturnValue(callerFrame, targetFrame);
1786d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1787d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1788d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private void explicitCastArguments(final EmulatedStackFrame callerFrame,
1789d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                           final EmulatedStackFrame targetFrame) {
1790d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            final StackFrameReader reader = new StackFrameReader();
1791d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            reader.attach(callerFrame);
1792d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            final StackFrameWriter writer = new StackFrameWriter();
1793d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            writer.attach(targetFrame);
1794d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1795d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            final Class<?>[] fromTypes = type().ptypes();
1796d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            final Class<?>[] toTypes = target.type().ptypes();
1797d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            for (int i = 0; i < fromTypes.length; ++i) {
1798d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                explicitCast(reader, fromTypes[i], writer, toTypes[i]);
1799d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1800d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1801d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1802d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private void explicitCastReturnValue(final EmulatedStackFrame callerFrame,
1803d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                             final EmulatedStackFrame targetFrame) {
1804d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            Class<?> from = target.type().rtype();
1805d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            Class<?> to = type().rtype();
1806d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (to != void.class) {
1807d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                final StackFrameWriter writer = new StackFrameWriter();
1808d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.attach(callerFrame);
1809d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.makeReturnValueAccessor();
1810d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                if (from == void.class) {
1811d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    if (to.isPrimitive()) {
1812d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                        unboxNull(writer, to);
1813d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    } else {
1814d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                        writer.putNextReference(null, to);
1815d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    }
1816d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else {
1817d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    final StackFrameReader reader = new StackFrameReader();
1818d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    reader.attach(targetFrame);
1819d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    reader.makeReturnValueAccessor();
1820d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    explicitCast(reader, target.type().rtype(), writer, type().rtype());
1821d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                }
1822d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1823d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1824d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1825d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void throwUnexpectedType(final Class<?> unexpectedType) {
1826d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            throw new InternalError("Unexpected type: " + unexpectedType);
1827d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1828d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1829d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void explicitCastFromBoolean(boolean fromValue,
1830d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                    final StackFrameWriter writer,
1831d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                    final Class<?> to) {
1832d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            int value = fromValue ? 1 : 0;
1833d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (to == byte.class) {
1834d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextByte((byte) value);
1835d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == char.class) {
1836d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextChar((char) value);
1837d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == short.class) {
1838d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextShort((short) value);
1839d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == int.class) {
1840d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextInt(value);
1841d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == long.class) {
1842d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextLong(value);
1843d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == float.class) {
1844d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextFloat(value);
1845d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == double.class) {
1846d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextDouble(value);
1847d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1848d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(to);
1849d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1850d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1851d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1852d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        /**
1853d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson         * Converts byte value to boolean according to
1854d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson         * {@link java.lang.invoke.MethodHandles#explicitCast()}
1855d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson         */
1856d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static boolean toBoolean(byte value) {
1857d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            return (value & 1) == 1;
1858d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1859d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1860d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static byte readPrimitiveAsByte(final StackFrameReader reader,
1861d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                final Class<?> from) {
1862d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1863d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextByte();
1864d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1865d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextChar();
1866d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1867d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextShort();
1868d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
1869d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextInt();
1870d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
1871d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextLong();
1872d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
1873d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextFloat();
1874d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
1875d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (byte) reader.nextDouble();
1876d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1877d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
1878d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
1879d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1880d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1881d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1882d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static char readPrimitiveAsChar(final StackFrameReader reader,
1883d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                final Class<?> from) {
1884d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1885d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextByte();
1886d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1887d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextChar();
1888d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1889d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextShort();
1890d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
1891d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextInt();
1892d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
1893d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextLong();
1894d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
1895d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextFloat();
1896d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
1897d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (char) reader.nextDouble();
1898d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1899d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
1900d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
1901d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1902d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1903d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1904d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static short readPrimitiveAsShort(final StackFrameReader reader,
1905d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                  final Class<?> from) {
1906d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1907d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextByte();
1908d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1909d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextChar();
1910d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1911d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextShort();
1912d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
1913d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextInt();
1914d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
1915d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextLong();
1916d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
1917d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextFloat();
1918d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
1919d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (short) reader.nextDouble();
1920d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1921d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
1922d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
1923d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1924d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1925d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1926d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static int readPrimitiveAsInt(final StackFrameReader reader,
1927d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                              final Class<?> from) {
1928d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1929d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextByte();
1930d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1931d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextChar();
1932d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1933d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextShort();
1934d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
1935d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextInt();
1936d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
1937d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextLong();
1938d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
1939d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextFloat();
1940d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
1941d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (int) reader.nextDouble();
1942d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1943d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
1944d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
1945d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1946d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1947d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1948d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static long readPrimitiveAsLong(final StackFrameReader reader,
1949d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                final Class<?> from) {
1950d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1951d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextByte();
1952d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1953d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextChar();
1954d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1955d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextShort();
1956d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
1957d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextInt();
1958d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
1959d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextLong();
1960d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
1961d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextFloat();
1962d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
1963d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (long) reader.nextDouble();
1964d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1965d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
1966d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
1967d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1968d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1969d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1970d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static float readPrimitiveAsFloat(final StackFrameReader reader,
1971d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                  final Class<?> from) {
1972d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1973d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextByte();
1974d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1975d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextChar();
1976d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1977d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextShort();
1978d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
1979d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextInt();
1980d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
1981d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextLong();
1982d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
1983d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextFloat();
1984d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
1985d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (float) reader.nextDouble();
1986d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
1987d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
1988d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
1989d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
1990d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
1991d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
1992d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static double readPrimitiveAsDouble(final StackFrameReader reader,
1993d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                    final Class<?> from) {
1994d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == byte.class) {
1995d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextByte();
1996d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
1997d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextChar();
1998d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
1999d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextShort();
2000d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
2001d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextInt();
2002d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
2003d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextLong();
2004d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
2005d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextFloat();
2006d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
2007d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return (double) reader.nextDouble();
2008d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2009d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
2010d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                return 0;
2011d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2012d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2013d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2014d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void explicitCastToBoolean(final StackFrameReader reader,
2015d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                  final Class<?> from,
2016d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                  final StackFrameWriter writer) {
2017d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            byte byteValue = readPrimitiveAsByte(reader, from);
2018d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            writer.putNextBoolean(toBoolean(byteValue));
2019d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2020d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2021d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void explicitCastPrimitives(final StackFrameReader reader,
2022d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                   final Class<?> from,
2023d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                   final StackFrameWriter writer,
2024d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                                   final Class<?> to) {
2025d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (to == byte.class) {
2026d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                byte value = readPrimitiveAsByte(reader, from);
2027d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextByte(value);
2028d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == char.class) {
2029d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                char value = readPrimitiveAsChar(reader, from);
2030d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextChar(value);
2031d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == short.class) {
2032d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                short value = readPrimitiveAsShort(reader, from);
2033d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextShort(value);
2034d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == int.class) {
2035d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                int value = readPrimitiveAsInt(reader, from);
2036d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextInt(value);
2037d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == long.class) {
2038d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                long value = readPrimitiveAsLong(reader, from);
2039d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextLong(value);
2040d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == float.class) {
2041d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                float value = readPrimitiveAsFloat(reader, from);
2042d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextFloat(value);
2043d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == double.class) {
2044d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                double value = readPrimitiveAsDouble(reader, from);
2045d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextDouble(value);
2046d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2047d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(to);
2048d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2049d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2050d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2051d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void unboxNull(final StackFrameWriter writer, final Class<?> to) {
2052d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (to == boolean.class) {
2053d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextBoolean(false);
2054d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == byte.class) {
2055d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextByte((byte) 0);
2056d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == char.class) {
2057d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextChar((char) 0);
2058d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == short.class) {
2059d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextShort((short) 0);
2060d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == int.class) {
2061d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextInt((int) 0);
2062d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == long.class) {
2063d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextLong((long) 0);
2064d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == float.class) {
2065d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextFloat((float) 0);
2066d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == double.class) {
2067d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextDouble((double) 0);
2068d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2069d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(to);
2070d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2071d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2072d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2073d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void unboxNonNull(final Object ref, final Class<?> from,
2074d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                         final StackFrameWriter writer, final Class<?> to) {
2075d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (to == boolean.class) {
2076d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                if (from == Boolean.class) {
2077d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    writer.putNextBoolean((boolean) ref);
2078d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else if (from == Float.class || from == Double.class) {
2079d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    byte b = (byte) ((double) ref);
2080d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    writer.putNextBoolean(toBoolean(b));
2081d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else {
2082d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    byte b = (byte) ((long) ref);
2083d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    writer.putNextBoolean(toBoolean(b));
2084d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                }
2085d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == byte.class) {
2086d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextByte((byte) ref);
2087d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == char.class) {
2088d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextChar((char) ref);
2089d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == short.class) {
2090d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextShort((short) ref);
2091d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == int.class) {
2092d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextInt((int) ref);
2093d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == long.class) {
2094d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextLong((long) ref);
2095d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == float.class) {
2096d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextFloat((float) ref);
2097d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to == double.class) {
2098d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                writer.putNextDouble((double) ref);
2099d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2100d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(to);
2101d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2102d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2103d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2104d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void unbox(final Object ref, final Class<?> from,
2105d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                  final StackFrameWriter writer, final Class<?> to) {
2106d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (ref == null) {
2107d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                unboxNull(writer, to);
2108d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2109d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                unboxNonNull(ref, from, writer, to);
2110d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2111d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2112d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2113d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void box(final StackFrameReader reader, final Class<?> from,
2114d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                final StackFrameWriter writer, final Class<?> to) {
2115d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            Object boxed = null;
2116d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from == boolean.class) {
2117d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Boolean.valueOf(reader.nextBoolean());
2118d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == byte.class) {
2119d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Byte.valueOf(reader.nextByte());
2120d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == char.class) {
2121d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Character.valueOf(reader.nextChar());
2122d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == short.class) {
2123d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Short.valueOf(reader.nextShort());
2124d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == int.class) {
2125d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Integer.valueOf(reader.nextInt());
2126d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == long.class) {
2127d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Long.valueOf(reader.nextLong());
2128d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == float.class) {
2129d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Float.valueOf(reader.nextFloat());
2130d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (from == double.class) {
2131d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                boxed = Double.valueOf(reader.nextDouble());
2132d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2133d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                throwUnexpectedType(from);
2134d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2135d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            writer.putNextReference(to.cast(boxed), to);
2136d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2137d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson
2138d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        private static void explicitCast(final StackFrameReader reader, final Class<?> from,
2139d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                                         final StackFrameWriter writer, final Class<?> to) {
2140d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            if (from.equals(to)) {
2141d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                StackFrameAccessor.copyNext(reader, writer, from);
2142d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (!from.isPrimitive()) {
2143d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                Object ref = reader.nextReference(from);
2144d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                if (to.isInterface()) {
2145d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    // Pass from without a cast according to description for
2146d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    // {@link java.lang.invoke.MethodHandles#explicitCastArguments()}.
2147d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    writer.putNextReference(ref, to);
2148d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else if (!to.isPrimitive()) {
2149d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    // |to| is a reference type, perform class cast check.
2150d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    writer.putNextReference(to.cast(ref), to);
2151d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else {
2152d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    // |from| is a reference type, |to| is a primitive type,
2153d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    unbox(ref, from, writer, to);
2154d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                }
2155d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else if (to.isPrimitive()) {
2156d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                // |from| and |to| are primitive types.
2157d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                if (from == boolean.class) {
2158d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    explicitCastFromBoolean(reader.nextBoolean(), writer, to);
2159d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else if (to == boolean.class) {
2160d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    explicitCastToBoolean(reader, from, writer);
2161d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                } else {
2162d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                    explicitCastPrimitives(reader, from, writer, to);
2163d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                }
2164d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            } else {
2165d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                // |from| is a primitive type, |to| is a reference type.
2166d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson                box(reader, from, writer, to);
2167d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson            }
2168d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson        }
2169d10faa59eb8935e93d97cd180a7bcf9dd7aa6621Orion Hodson    }
2170faf8883397aed1411590edd1bf5b6681430a10f5Narayan Kamath}
2171