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