Batch of classes necessary to implement invoke dynamic interfaces. Taken from JDK8 build 132
2 * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
26 package sun.invoke.util;
28 import java.lang.invoke.MethodHandle;
29 import java.lang.invoke.MethodHandles;
30 import java.lang.invoke.MethodHandles.Lookup;
31 import java.lang.invoke.MethodType;
32 import java.security.AccessController;
33 import java.security.PrivilegedAction;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collections;
37 import java.util.EnumMap;
38 import java.util.List;
40 public class ValueConversions {
41 private static final Class<?> THIS_CLASS = ValueConversions.class;
42 // Do not adjust this except for special platforms:
43 private static final int MAX_ARITY;
45 final Object[] values = { 255 };
46 AccessController.doPrivileged(new PrivilegedAction<Void>() {
49 values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
53 MAX_ARITY = (Integer) values[0];
56 private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
58 private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
59 @SuppressWarnings("unchecked") // generic array creation
60 EnumMap<Wrapper, MethodHandle>[] caches
61 = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
62 for (int i = 0; i < n; i++)
63 caches[i] = new EnumMap<>(Wrapper.class);
67 /// Converting references to values.
69 // There are several levels of this unboxing conversions:
70 // no conversions: exactly Integer.valueOf, etc.
71 // implicit conversions sanctioned by JLS 5.1.2, etc.
72 // explicit conversions as allowed by explicitCastArguments
74 static int unboxInteger(Object x, boolean cast) {
75 if (x instanceof Integer)
76 return ((Integer) x).intValue();
77 return primitiveConversion(Wrapper.INT, x, cast).intValue();
80 static byte unboxByte(Object x, boolean cast) {
81 if (x instanceof Byte)
82 return ((Byte) x).byteValue();
83 return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
86 static short unboxShort(Object x, boolean cast) {
87 if (x instanceof Short)
88 return ((Short) x).shortValue();
89 return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
92 static boolean unboxBoolean(Object x, boolean cast) {
93 if (x instanceof Boolean)
94 return ((Boolean) x).booleanValue();
95 return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
98 static char unboxCharacter(Object x, boolean cast) {
99 if (x instanceof Character)
100 return ((Character) x).charValue();
101 return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
104 static long unboxLong(Object x, boolean cast) {
105 if (x instanceof Long)
106 return ((Long) x).longValue();
107 return primitiveConversion(Wrapper.LONG, x, cast).longValue();
110 static float unboxFloat(Object x, boolean cast) {
111 if (x instanceof Float)
112 return ((Float) x).floatValue();
113 return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
116 static double unboxDouble(Object x, boolean cast) {
117 if (x instanceof Double)
118 return ((Double) x).doubleValue();
119 return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
122 private static MethodType unboxType(Wrapper wrap) {
123 return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
126 private static final EnumMap<Wrapper, MethodHandle>[]
127 UNBOX_CONVERSIONS = newWrapperCaches(2);
129 private static MethodHandle unbox(Wrapper wrap, boolean cast) {
130 EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
131 MethodHandle mh = cache.get(wrap);
138 mh = IDENTITY; break;
146 // look up the method
147 String name = "unbox" + wrap.wrapperSimpleName();
148 MethodType type = unboxType(wrap);
150 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
151 } catch (ReflectiveOperationException ex) {
155 mh = MethodHandles.insertArguments(mh, 1, cast);
159 throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
160 + (cast ? " (cast)" : ""));
163 public static MethodHandle unboxCast(Wrapper type) {
164 return unbox(type, true);
167 public static MethodHandle unbox(Class<?> type) {
168 return unbox(Wrapper.forPrimitiveType(type), false);
171 public static MethodHandle unboxCast(Class<?> type) {
172 return unbox(Wrapper.forPrimitiveType(type), true);
175 static private final Integer ZERO_INT = 0, ONE_INT = 1;
177 /// Primitive conversions
179 * Produce a Number which represents the given value {@code x}
180 * according to the primitive type of the given wrapper {@code wrap}.
181 * Caller must invoke intValue, byteValue, longValue (etc.) on the result
182 * to retrieve the desired primitive value.
184 public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
185 // Maybe merge this code with Wrapper.convert/cast.
188 if (!cast) return null;
191 if (x instanceof Number) {
193 } else if (x instanceof Boolean) {
194 res = ((boolean)x ? ONE_INT : ZERO_INT);
195 } else if (x instanceof Character) {
198 // this will fail with the required ClassCastException:
201 Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
202 if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
203 // this will fail with the required ClassCastException:
204 return (Number) wrap.wrapperType().cast(x);
209 * The JVM verifier allows boolean, byte, short, or char to widen to int.
210 * Support exactly this conversion, from a boxed value type Boolean,
211 * Byte, Short, Character, or Integer.
213 public static int widenSubword(Object x) {
214 if (x instanceof Integer)
216 else if (x instanceof Boolean)
217 return fromBoolean((boolean) x);
218 else if (x instanceof Character)
220 else if (x instanceof Short)
222 else if (x instanceof Byte)
225 // Fail with a ClassCastException.
229 /// Converting primitives to references
231 static Integer boxInteger(int x) {
235 static Byte boxByte(byte x) {
239 static Short boxShort(short x) {
243 static Boolean boxBoolean(boolean x) {
247 static Character boxCharacter(char x) {
251 static Long boxLong(long x) {
255 static Float boxFloat(float x) {
259 static Double boxDouble(double x) {
263 private static MethodType boxType(Wrapper wrap) {
264 // be exact, since return casts are hard to compose
265 Class<?> boxType = wrap.wrapperType();
266 return MethodType.methodType(boxType, wrap.primitiveType());
269 private static final EnumMap<Wrapper, MethodHandle>[]
270 BOX_CONVERSIONS = newWrapperCaches(2);
272 private static MethodHandle box(Wrapper wrap, boolean exact) {
273 EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
274 MethodHandle mh = cache.get(wrap);
281 mh = IDENTITY; break;
290 // look up the method
291 String name = "box" + wrap.wrapperSimpleName();
292 MethodType type = boxType(wrap);
295 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
296 } catch (ReflectiveOperationException ex) {
300 mh = box(wrap, !exact).asType(type.erase());
306 throw new IllegalArgumentException("cannot find box adapter for "
307 + wrap + (exact ? " (exact)" : ""));
310 public static MethodHandle box(Class<?> type) {
311 boolean exact = false;
312 // e.g., boxShort(short)Short if exact,
313 // e.g., boxShort(short)Object if !exact
314 return box(Wrapper.forPrimitiveType(type), exact);
317 public static MethodHandle box(Wrapper type) {
318 boolean exact = false;
319 return box(type, exact);
322 /// Constant functions
324 static void ignore(Object x) {
325 // no value to return; this is an unbox of null
328 static void empty() {
331 static Object zeroObject() {
335 static int zeroInteger() {
339 static long zeroLong() {
343 static float zeroFloat() {
347 static double zeroDouble() {
351 private static final EnumMap<Wrapper, MethodHandle>[]
352 CONSTANT_FUNCTIONS = newWrapperCaches(2);
354 public static MethodHandle zeroConstantFunction(Wrapper wrap) {
355 EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
356 MethodHandle mh = cache.get(wrap);
361 MethodType type = MethodType.methodType(wrap.primitiveType());
367 case INT: case LONG: case FLOAT: case DOUBLE:
369 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
370 } catch (ReflectiveOperationException ex) {
380 // use zeroInt and cast the result
381 if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
382 mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
386 throw new IllegalArgumentException("cannot find zero constant for " + wrap);
389 /// Converting references to references.
393 * @param x an arbitrary reference value
394 * @return the same value x
396 static <T> T identity(T x) {
400 static <T> T[] identity(T[] x) {
405 * Identity function on ints.
406 * @param x an arbitrary int value
407 * @return the same value x
409 static int identity(int x) {
413 static byte identity(byte x) {
417 static short identity(short x) {
421 static boolean identity(boolean x) {
425 static char identity(char x) {
430 * Identity function on longs.
431 * @param x an arbitrary long value
432 * @return the same value x
434 static long identity(long x) {
438 static float identity(float x) {
442 static double identity(double x) {
447 * Identity function, with reference cast.
448 * @param t an arbitrary reference type
449 * @param x an arbitrary reference value
450 * @return the same value x
452 @SuppressWarnings("unchecked")
453 static <T,U> T castReference(Class<? extends T> t, U x) {
454 // inlined Class.cast because we can't ForceInline it
455 if (x != null && !t.isInstance(x))
456 throw newClassCastException(t, x);
460 private static ClassCastException newClassCastException(Class<?> t, Object obj) {
461 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
464 private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
465 ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
468 MethodType idType = MethodType.genericMethodType(1);
469 MethodType castType = idType.insertParameterTypes(0, Class.class);
470 MethodType ignoreType = idType.changeReturnType(void.class);
471 MethodType zeroObjectType = MethodType.genericMethodType(0);
472 IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
473 //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
474 CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType);
475 ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
476 IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
477 EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
478 ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
479 FILL_NEW_ARRAY = IMPL_LOOKUP
480 .findStatic(THIS_CLASS, "fillNewArray",
481 MethodType.methodType(Object[].class, Integer.class, Object[].class));
482 FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
483 .findStatic(THIS_CLASS, "fillNewTypedArray",
484 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
485 } catch (NoSuchMethodException | IllegalAccessException ex) {
486 throw newInternalError("uncaught exception", ex);
490 // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
491 static class LazyStatics {
492 private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
495 //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
496 COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
497 COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
498 MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
499 } catch (ReflectiveOperationException ex) {
500 throw newInternalError("uncaught exception", ex);
505 private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
506 = newWrapperCaches(1);
508 /** Return a method that casts its sole argument (an Object) to the given type
509 * and returns it as the given type.
511 public static MethodHandle cast(Class<?> type) {
512 if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type);
515 EnumMap<Wrapper, MethodHandle> cache = null;
516 if (Wrapper.isWrapperType(type)) {
517 wrap = Wrapper.forWrapperType(type);
518 cache = WRAPPER_CASTS[0];
519 mh = cache.get(wrap);
520 if (mh != null) return mh;
522 mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
528 public static MethodHandle identity() {
532 public static MethodHandle identity(Class<?> type) {
533 if (!type.isPrimitive())
534 // Reference identity has been moved into MethodHandles:
535 return MethodHandles.identity(type);
536 return identity(Wrapper.findPrimitiveType(type));
539 public static MethodHandle identity(Wrapper wrap) {
540 EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
541 MethodHandle mh = cache.get(wrap);
546 MethodType type = MethodType.methodType(wrap.primitiveType());
547 if (wrap != Wrapper.VOID)
548 type = type.appendParameterTypes(wrap.primitiveType());
550 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
551 } catch (ReflectiveOperationException ex) {
554 if (mh == null && wrap == Wrapper.VOID) {
555 mh = EMPTY; // #(){} : #()void
566 throw new IllegalArgumentException("cannot find identity for " + wrap);
569 /// Primitive conversions.
570 // These are supported directly by the JVM, usually by a single instruction.
571 // In the case of narrowing to a subword, there may be a pair of instructions.
572 // In the case of booleans, there may be a helper routine to manage a 1-bit value.
573 // This is the full 8x8 matrix (minus the diagonal).
575 // narrow double to all other types:
576 static float doubleToFloat(double x) { // bytecode: d2f
579 static long doubleToLong(double x) { // bytecode: d2l
582 static int doubleToInt(double x) { // bytecode: d2i
585 static short doubleToShort(double x) { // bytecodes: d2i, i2s
588 static char doubleToChar(double x) { // bytecodes: d2i, i2c
591 static byte doubleToByte(double x) { // bytecodes: d2i, i2b
594 static boolean doubleToBoolean(double x) {
595 return toBoolean((byte) x);
599 static double floatToDouble(float x) { // bytecode: f2d
603 static long floatToLong(float x) { // bytecode: f2l
606 static int floatToInt(float x) { // bytecode: f2i
609 static short floatToShort(float x) { // bytecodes: f2i, i2s
612 static char floatToChar(float x) { // bytecodes: f2i, i2c
615 static byte floatToByte(float x) { // bytecodes: f2i, i2b
618 static boolean floatToBoolean(float x) {
619 return toBoolean((byte) x);
623 static double longToDouble(long x) { // bytecode: l2d
626 static float longToFloat(long x) { // bytecode: l2f
630 static int longToInt(long x) { // bytecode: l2i
633 static short longToShort(long x) { // bytecodes: f2i, i2s
636 static char longToChar(long x) { // bytecodes: f2i, i2c
639 static byte longToByte(long x) { // bytecodes: f2i, i2b
642 static boolean longToBoolean(long x) {
643 return toBoolean((byte) x);
647 static double intToDouble(int x) { // bytecode: i2d
650 static float intToFloat(int x) { // bytecode: i2f
653 static long intToLong(int x) { // bytecode: i2l
657 static short intToShort(int x) { // bytecode: i2s
660 static char intToChar(int x) { // bytecode: i2c
663 static byte intToByte(int x) { // bytecode: i2b
666 static boolean intToBoolean(int x) {
667 return toBoolean((byte) x);
671 static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i')
674 static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i')
677 static long shortToLong(short x) { // bytecode: i2l (implicit 's2i')
680 static int shortToInt(short x) { // (implicit 's2i')
684 static char shortToChar(short x) { // bytecode: i2c (implicit 's2i')
687 static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i')
690 static boolean shortToBoolean(short x) {
691 return toBoolean((byte) x);
695 static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i')
698 static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i')
701 static long charToLong(char x) { // bytecode: i2l (implicit 'c2i')
704 static int charToInt(char x) { // (implicit 'c2i')
708 static short charToShort(char x) { // bytecode: i2s (implicit 'c2i')
711 static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i')
714 static boolean charToBoolean(char x) {
715 return toBoolean((byte) x);
719 static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i')
722 static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i')
725 static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i')
728 static int byteToInt(byte x) { // (implicit 'b2i')
731 static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i')
734 static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i')
737 // narrow byte to boolean:
738 static boolean byteToBoolean(byte x) {
742 // widen boolean to all types:
743 static double booleanToDouble(boolean x) {
744 return fromBoolean(x);
746 static float booleanToFloat(boolean x) {
747 return fromBoolean(x);
749 static long booleanToLong(boolean x) {
750 return fromBoolean(x);
752 static int booleanToInt(boolean x) {
753 return fromBoolean(x);
755 static short booleanToShort(boolean x) {
756 return fromBoolean(x);
758 static char booleanToChar(boolean x) {
759 return (char)fromBoolean(x);
761 static byte booleanToByte(boolean x) {
762 return fromBoolean(x);
765 // helpers to force boolean into the conversion scheme:
766 static boolean toBoolean(byte x) {
767 // see javadoc for MethodHandles.explicitCastArguments
768 return ((x & 1) != 0);
770 static byte fromBoolean(boolean x) {
771 // see javadoc for MethodHandles.explicitCastArguments
772 return (x ? (byte)1 : (byte)0);
775 private static final EnumMap<Wrapper, MethodHandle>[]
776 CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
778 public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
779 EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
780 MethodHandle mh = cache.get(wdst);
785 Class<?> src = wsrc.primitiveType();
786 Class<?> dst = wdst.primitiveType();
787 MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
790 } else if (wsrc == Wrapper.VOID) {
791 mh = zeroConstantFunction(wdst);
792 } else if (wdst == Wrapper.VOID) {
793 mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles.
794 } else if (wsrc == Wrapper.OBJECT) {
796 } else if (wdst == Wrapper.OBJECT) {
799 assert(src.isPrimitive() && dst.isPrimitive());
801 mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
802 } catch (ReflectiveOperationException ex) {
807 assert(mh.type() == type) : mh;
812 throw new IllegalArgumentException("cannot find primitive conversion function for " +
813 src.getSimpleName()+" -> "+dst.getSimpleName());
816 public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
817 return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
820 private static String capitalize(String x) {
821 return Character.toUpperCase(x.charAt(0))+x.substring(1);
824 /// Collection of multiple arguments.
826 public static Object convertArrayElements(Class<?> arrayType, Object array) {
827 Class<?> src = array.getClass().getComponentType();
828 Class<?> dst = arrayType.getComponentType();
829 if (src == null || dst == null) throw new IllegalArgumentException("not array type");
830 Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
831 Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
834 Object[] a = (Object[]) array;
837 return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
838 Object res = dw.makeArray(length);
839 dw.copyArrayUnboxing(a, 0, res, 0, length);
842 length = java.lang.reflect.Array.getLength(array);
845 res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
847 res = new Object[length];
849 sw.copyArrayBoxing(array, 0, res, 0, length);
850 if (dw == null) return res;
851 Object a = dw.makeArray(length);
852 dw.copyArrayUnboxing(res, 0, a, 0, length);
856 private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
857 MethodType type = MethodType.genericMethodType(nargs)
858 .changeReturnType(rtype)
859 .insertParameterTypes(0, ptypes);
861 return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
862 } catch (ReflectiveOperationException ex) {
867 private static final Object[] NO_ARGS_ARRAY = {};
868 private static Object[] makeArray(Object... args) { return args; }
869 private static Object[] array() { return NO_ARGS_ARRAY; }
870 private static Object[] array(Object a0)
871 { return makeArray(a0); }
872 private static Object[] array(Object a0, Object a1)
873 { return makeArray(a0, a1); }
874 private static Object[] array(Object a0, Object a1, Object a2)
875 { return makeArray(a0, a1, a2); }
876 private static Object[] array(Object a0, Object a1, Object a2, Object a3)
877 { return makeArray(a0, a1, a2, a3); }
878 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
880 { return makeArray(a0, a1, a2, a3, a4); }
881 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
882 Object a4, Object a5)
883 { return makeArray(a0, a1, a2, a3, a4, a5); }
884 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
885 Object a4, Object a5, Object a6)
886 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
887 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
888 Object a4, Object a5, Object a6, Object a7)
889 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
890 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
891 Object a4, Object a5, Object a6, Object a7,
893 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
894 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
895 Object a4, Object a5, Object a6, Object a7,
896 Object a8, Object a9)
897 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
898 private static MethodHandle[] makeArrays() {
899 ArrayList<MethodHandle> mhs = new ArrayList<>();
901 MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
902 if (mh == null) break;
905 assert(mhs.size() == 11); // current number of methods
906 return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
908 private static final MethodHandle[] ARRAYS = makeArrays();
910 // filling versions of the above:
911 // using Integer len instead of int len and no varargs to avoid bootstrapping problems
912 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
913 Object[] a = new Object[len];
914 fillWithArguments(a, 0, args);
917 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
918 Object[] a = Arrays.copyOf(example, len);
919 fillWithArguments(a, 0, args);
922 private static void fillWithArguments(Object[] a, int pos, Object... args) {
923 System.arraycopy(args, 0, a, pos, args.length);
925 // using Integer pos instead of int pos to avoid bootstrapping problems
926 private static Object[] fillArray(Integer pos, Object[] a, Object a0)
927 { fillWithArguments(a, pos, a0); return a; }
928 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
929 { fillWithArguments(a, pos, a0, a1); return a; }
930 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
931 { fillWithArguments(a, pos, a0, a1, a2); return a; }
932 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
933 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
934 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
936 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
937 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
938 Object a4, Object a5)
939 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
940 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
941 Object a4, Object a5, Object a6)
942 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
943 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
944 Object a4, Object a5, Object a6, Object a7)
945 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
946 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
947 Object a4, Object a5, Object a6, Object a7,
949 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
950 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
951 Object a4, Object a5, Object a6, Object a7,
952 Object a8, Object a9)
953 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
954 private static MethodHandle[] makeFillArrays() {
955 ArrayList<MethodHandle> mhs = new ArrayList<>();
956 mhs.add(null); // there is no empty fill; at least a0 is required
958 MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
959 if (mh == null) break;
962 assert(mhs.size() == 11); // current number of methods
963 return mhs.toArray(new MethodHandle[0]);
965 private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
967 private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
968 return Arrays.copyOf(a, a.length, arrayType);
970 private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
971 Object a = w.makeArray(boxes.length);
972 w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
976 /** Return a method handle that takes the indicated number of Object
977 * arguments and returns an Object array of them, as if for varargs.
979 public static MethodHandle varargsArray(int nargs) {
980 MethodHandle mh = ARRAYS[nargs];
981 if (mh != null) return mh;
982 mh = findCollector("array", nargs, Object[].class);
983 if (mh != null) return ARRAYS[nargs] = mh;
984 mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
985 assert(assertCorrectArity(mh, nargs));
986 return ARRAYS[nargs] = mh;
989 private static boolean assertCorrectArity(MethodHandle mh, int arity) {
990 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
994 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
995 // Build up the result mh as a sequence of fills like this:
996 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
997 // The various fill(_,10*I,___*[J]) are reusable.
998 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately
999 int rightLen = nargs - leftLen;
1000 MethodHandle leftCollector = newArray.bindTo(nargs);
1001 leftCollector = leftCollector.asCollector(Object[].class, leftLen);
1002 MethodHandle mh = finisher;
1004 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
1005 if (mh == ARRAY_IDENTITY)
1008 mh = MethodHandles.collectArguments(mh, 0, rightFiller);
1010 if (mh == ARRAY_IDENTITY)
1013 mh = MethodHandles.collectArguments(mh, 0, leftCollector);
1017 private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
1018 private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
1019 /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
1020 * fills a[L]..a[N-1] with corresponding arguments,
1021 * and then returns a. The value L is a global constant (LEFT_ARGS).
1023 private static MethodHandle fillToRight(int nargs) {
1024 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
1025 if (filler != null) return filler;
1026 filler = buildFiller(nargs);
1027 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
1028 return FILL_ARRAY_TO_RIGHT[nargs] = filler;
1030 private static MethodHandle buildFiller(int nargs) {
1031 if (nargs <= LEFT_ARGS)
1032 return ARRAY_IDENTITY; // no args to fill; return the array unchanged
1033 // we need room for both mh and a in mh.invoke(a, arg*[nargs])
1034 final int CHUNK = LEFT_ARGS;
1035 int rightLen = nargs % CHUNK;
1036 int midLen = nargs - rightLen;
1037 if (rightLen == 0) {
1038 midLen = nargs - (rightLen = CHUNK);
1039 if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
1040 // build some precursors from left to right
1041 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
1042 if (j > LEFT_ARGS) fillToRight(j);
1045 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
1046 assert(rightLen > 0);
1047 MethodHandle midFill = fillToRight(midLen); // recursive fill
1048 MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
1049 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
1050 assert(rightFill.type().parameterCount() == 1 + rightLen);
1052 // Combine the two fills:
1053 // right(mid(a, x10..x19), x20..x23)
1054 // The final product will look like this:
1055 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
1056 if (midLen == LEFT_ARGS)
1059 return MethodHandles.collectArguments(rightFill, 0, midFill);
1062 // Type-polymorphic version of varargs maker.
1063 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
1064 = new ClassValue<MethodHandle[]>() {
1066 protected MethodHandle[] computeValue(Class<?> type) {
1067 return new MethodHandle[256];
1071 static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM
1073 /** Return a method handle that takes the indicated number of
1074 * typed arguments and returns an array of them.
1075 * The type argument is the array type.
1077 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
1078 Class<?> elemType = arrayType.getComponentType();
1079 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType);
1080 // FIXME: Need more special casing and caching here.
1081 if (nargs >= MAX_JVM_ARITY/2 - 1) {
1083 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
1084 if (arrayType == double[].class || arrayType == long[].class)
1086 if (slots > MAX_ARRAY_SLOTS)
1087 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
1089 if (elemType == Object.class)
1090 return varargsArray(nargs);
1091 // other cases: primitive arrays, subtypes of Object[]
1092 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
1093 MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
1094 if (mh != null) return mh;
1095 if (elemType.isPrimitive()) {
1096 MethodHandle builder = FILL_NEW_ARRAY;
1097 MethodHandle producer = buildArrayProducer(arrayType);
1098 mh = buildVarargsArray(builder, producer, nargs);
1100 @SuppressWarnings("unchecked")
1101 Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
1102 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
1103 MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
1104 MethodHandle producer = ARRAY_IDENTITY;
1105 mh = buildVarargsArray(builder, producer, nargs);
1107 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
1108 assert(assertCorrectArity(mh, nargs));
1109 if (nargs < cache.length)
1114 private static MethodHandle buildArrayProducer(Class<?> arrayType) {
1115 Class<?> elemType = arrayType.getComponentType();
1116 if (elemType.isPrimitive())
1117 return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
1119 return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
1122 // List version of varargs maker.
1124 private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
1125 private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
1126 private static List<Object> list() { return NO_ARGS_LIST; }
1127 private static List<Object> list(Object a0)
1128 { return makeList(a0); }
1129 private static List<Object> list(Object a0, Object a1)
1130 { return makeList(a0, a1); }
1131 private static List<Object> list(Object a0, Object a1, Object a2)
1132 { return makeList(a0, a1, a2); }
1133 private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
1134 { return makeList(a0, a1, a2, a3); }
1135 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1137 { return makeList(a0, a1, a2, a3, a4); }
1138 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1139 Object a4, Object a5)
1140 { return makeList(a0, a1, a2, a3, a4, a5); }
1141 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1142 Object a4, Object a5, Object a6)
1143 { return makeList(a0, a1, a2, a3, a4, a5, a6); }
1144 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1145 Object a4, Object a5, Object a6, Object a7)
1146 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
1147 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1148 Object a4, Object a5, Object a6, Object a7,
1150 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1151 private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1152 Object a4, Object a5, Object a6, Object a7,
1153 Object a8, Object a9)
1154 { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1155 private static MethodHandle[] makeLists() {
1156 ArrayList<MethodHandle> mhs = new ArrayList<>();
1158 MethodHandle mh = findCollector("list", mhs.size(), List.class);
1159 if (mh == null) break;
1162 assert(mhs.size() == 11); // current number of methods
1163 return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
1165 private static final MethodHandle[] LISTS = makeLists();
1167 /** Return a method handle that takes the indicated number of Object
1168 * arguments and returns a List.
1170 public static MethodHandle varargsList(int nargs) {
1171 MethodHandle mh = LISTS[nargs];
1172 if (mh != null) return mh;
1173 mh = findCollector("list", nargs, List.class);
1174 if (mh != null) return LISTS[nargs] = mh;
1175 return LISTS[nargs] = buildVarargsList(nargs);
1177 private static MethodHandle buildVarargsList(int nargs) {
1178 return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
1181 // handy shared exception makers (they simplify the common case code)
1182 private static InternalError newInternalError(String message, Throwable cause) {
1183 return new InternalError(message, cause);
1185 private static InternalError newInternalError(Throwable cause) {
1186 return new InternalError(cause);