History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/invoke/util/ValueConversions.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/invoke/util/ValueConversions.java+1237−0
@@ -0,0 +1,1237 @@
1+/*
2+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
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.
10+ *
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).
16+ *
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.
20+ *
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
23+ * questions.
24+ */
25+
26+package sun.invoke.util;
27+
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;
39+
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;
44+ static {
45+ final Object[] values = { 255 };
46+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
47+ public Void run() {
48+ values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
49+ return null;
50+ }
51+ });
52+ MAX_ARITY = (Integer) values[0];
53+ }
54+
55+ private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
56+
57+ private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
58+ @SuppressWarnings("unchecked")
59+ EnumMap<Wrapper, MethodHandle>[] caches
60+ = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap[n]; // unchecked warning expected here
61+ for (int i = 0; i < n; i++)
62+ caches[i] = new EnumMap<>(Wrapper.class);
63+ return caches;
64+ }
65+
66+ /// Converting references to values.
67+
68+ // There are several levels of this unboxing conversions:
69+ // no conversions: exactly Integer.valueOf, etc.
70+ // implicit conversions sanctioned by JLS 5.1.2, etc.
71+ // explicit conversions as allowed by explicitCastArguments
72+
73+ static int unboxInteger(Object x, boolean cast) {
74+ if (x instanceof Integer)
75+ return ((Integer) x).intValue();
76+ return primitiveConversion(Wrapper.INT, x, cast).intValue();
77+ }
78+
79+ static byte unboxByte(Object x, boolean cast) {
80+ if (x instanceof Byte)
81+ return ((Byte) x).byteValue();
82+ return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
83+ }
84+
85+ static short unboxShort(Object x, boolean cast) {
86+ if (x instanceof Short)
87+ return ((Short) x).shortValue();
88+ return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
89+ }
90+
91+ static boolean unboxBoolean(Object x, boolean cast) {
92+ if (x instanceof Boolean)
93+ return ((Boolean) x).booleanValue();
94+ return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
95+ }
96+
97+ static char unboxCharacter(Object x, boolean cast) {
98+ if (x instanceof Character)
99+ return ((Character) x).charValue();
100+ return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
101+ }
102+
103+ static long unboxLong(Object x, boolean cast) {
104+ if (x instanceof Long)
105+ return ((Long) x).longValue();
106+ return primitiveConversion(Wrapper.LONG, x, cast).longValue();
107+ }
108+
109+ static float unboxFloat(Object x, boolean cast) {
110+ if (x instanceof Float)
111+ return ((Float) x).floatValue();
112+ return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
113+ }
114+
115+ static double unboxDouble(Object x, boolean cast) {
116+ if (x instanceof Double)
117+ return ((Double) x).doubleValue();
118+ return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
119+ }
120+
121+ /// Converting references to "raw" values.
122+ /// A raw primitive value is always an int or long.
123+
124+ static int unboxByteRaw(Object x, boolean cast) {
125+ return unboxByte(x, cast);
126+ }
127+
128+ static int unboxShortRaw(Object x, boolean cast) {
129+ return unboxShort(x, cast);
130+ }
131+
132+ static int unboxBooleanRaw(Object x, boolean cast) {
133+ return unboxBoolean(x, cast) ? 1 : 0;
134+ }
135+
136+ static int unboxCharacterRaw(Object x, boolean cast) {
137+ return unboxCharacter(x, cast);
138+ }
139+
140+ static int unboxFloatRaw(Object x, boolean cast) {
141+ return Float.floatToIntBits(unboxFloat(x, cast));
142+ }
143+
144+ static long unboxDoubleRaw(Object x, boolean cast) {
145+ return Double.doubleToRawLongBits(unboxDouble(x, cast));
146+ }
147+
148+ private static MethodType unboxType(Wrapper wrap, boolean raw) {
149+ return MethodType.methodType(rawWrapper(wrap, raw).primitiveType(), Object.class, boolean.class);
150+ }
151+
152+ private static final EnumMap<Wrapper, MethodHandle>[]
153+ UNBOX_CONVERSIONS = newWrapperCaches(4);
154+
155+ private static MethodHandle unbox(Wrapper wrap, boolean raw, boolean cast) {
156+ EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)+(raw?2:0)];
157+ MethodHandle mh = cache.get(wrap);
158+ if (mh != null) {
159+ return mh;
160+ }
161+ // slow path
162+ switch (wrap) {
163+ case OBJECT:
164+ mh = IDENTITY; break;
165+ case VOID:
166+ mh = raw ? ALWAYS_ZERO : IGNORE; break;
167+ case INT: case LONG:
168+ // these guys don't need separate raw channels
169+ if (raw) mh = unbox(wrap, false, cast);
170+ break;
171+ }
172+ if (mh != null) {
173+ cache.put(wrap, mh);
174+ return mh;
175+ }
176+ // look up the method
177+ String name = "unbox" + wrap.simpleName() + (raw ? "Raw" : "");
178+ MethodType type = unboxType(wrap, raw);
179+ try {
180+ mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
181+ } catch (ReflectiveOperationException ex) {
182+ mh = null;
183+ }
184+ if (mh != null) {
185+ mh = MethodHandles.insertArguments(mh, 1, cast);
186+ cache.put(wrap, mh);
187+ return mh;
188+ }
189+ throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
190+ + (cast ? " (cast)" : "") + (raw ? " (raw)" : ""));
191+ }
192+
193+ public static MethodHandle unboxCast(Wrapper type) {
194+ return unbox(type, false, true);
195+ }
196+
197+ public static MethodHandle unboxRaw(Wrapper type) {
198+ return unbox(type, true, false);
199+ }
200+
201+ public static MethodHandle unbox(Class<?> type) {
202+ return unbox(Wrapper.forPrimitiveType(type), false, false);
203+ }
204+
205+ public static MethodHandle unboxCast(Class<?> type) {
206+ return unbox(Wrapper.forPrimitiveType(type), false, true);
207+ }
208+
209+ public static MethodHandle unboxRaw(Class<?> type) {
210+ return unbox(Wrapper.forPrimitiveType(type), true, false);
211+ }
212+
213+ static private final Integer ZERO_INT = 0, ONE_INT = 1;
214+
215+ /// Primitive conversions
216+ public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
217+ // Maybe merge this code with Wrapper.convert/cast.
218+ Number res = null;
219+ if (x == null) {
220+ if (!cast) return null;
221+ return ZERO_INT;
222+ }
223+ if (x instanceof Number) {
224+ res = (Number) x;
225+ } else if (x instanceof Boolean) {
226+ res = ((boolean)x ? ONE_INT : ZERO_INT);
227+ } else if (x instanceof Character) {
228+ res = (int)(char)x;
229+ } else {
230+ // this will fail with the required ClassCastException:
231+ res = (Number) x;
232+ }
233+ Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
234+ if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
235+ // this will fail with the required ClassCastException:
236+ return (Number) wrap.wrapperType().cast(x);
237+ return res;
238+ }
239+
240+ /// Converting primitives to references
241+
242+ static Integer boxInteger(int x) {
243+ return x;
244+ }
245+
246+ static Byte boxByte(byte x) {
247+ return x;
248+ }
249+
250+ static Short boxShort(short x) {
251+ return x;
252+ }
253+
254+ static Boolean boxBoolean(boolean x) {
255+ return x;
256+ }
257+
258+ static Character boxCharacter(char x) {
259+ return x;
260+ }
261+
262+ static Long boxLong(long x) {
263+ return x;
264+ }
265+
266+ static Float boxFloat(float x) {
267+ return x;
268+ }
269+
270+ static Double boxDouble(double x) {
271+ return x;
272+ }
273+
274+ /// Converting raw primitives to references
275+
276+ static Byte boxByteRaw(int x) {
277+ return boxByte((byte)x);
278+ }
279+
280+ static Short boxShortRaw(int x) {
281+ return boxShort((short)x);
282+ }
283+
284+ static Boolean boxBooleanRaw(int x) {
285+ return boxBoolean(x != 0);
286+ }
287+
288+ static Character boxCharacterRaw(int x) {
289+ return boxCharacter((char)x);
290+ }
291+
292+ static Float boxFloatRaw(int x) {
293+ return boxFloat(Float.intBitsToFloat(x));
294+ }
295+
296+ static Double boxDoubleRaw(long x) {
297+ return boxDouble(Double.longBitsToDouble(x));
298+ }
299+
300+ // a raw void value is (arbitrarily) a garbage int
301+ static Void boxVoidRaw(int x) {
302+ return null;
303+ }
304+
305+ private static MethodType boxType(Wrapper wrap, boolean raw) {
306+ // be exact, since return casts are hard to compose
307+ Class<?> boxType = wrap.wrapperType();
308+ return MethodType.methodType(boxType, rawWrapper(wrap, raw).primitiveType());
309+ }
310+
311+ private static Wrapper rawWrapper(Wrapper wrap, boolean raw) {
312+ if (raw) return wrap.isDoubleWord() ? Wrapper.LONG : Wrapper.INT;
313+ return wrap;
314+ }
315+
316+ private static final EnumMap<Wrapper, MethodHandle>[]
317+ BOX_CONVERSIONS = newWrapperCaches(4);
318+
319+ private static MethodHandle box(Wrapper wrap, boolean exact, boolean raw) {
320+ EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)+(raw?2:0)];
321+ MethodHandle mh = cache.get(wrap);
322+ if (mh != null) {
323+ return mh;
324+ }
325+ // slow path
326+ switch (wrap) {
327+ case OBJECT:
328+ mh = IDENTITY; break;
329+ case VOID:
330+ if (!raw) mh = ZERO_OBJECT;
331+ break;
332+ case INT: case LONG:
333+ // these guys don't need separate raw channels
334+ if (raw) mh = box(wrap, exact, false);
335+ break;
336+ }
337+ if (mh != null) {
338+ cache.put(wrap, mh);
339+ return mh;
340+ }
341+ // look up the method
342+ String name = "box" + wrap.simpleName() + (raw ? "Raw" : "");
343+ MethodType type = boxType(wrap, raw);
344+ if (exact) {
345+ try {
346+ mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
347+ } catch (ReflectiveOperationException ex) {
348+ mh = null;
349+ }
350+ } else {
351+ mh = box(wrap, !exact, raw).asType(type.erase());
352+ }
353+ if (mh != null) {
354+ cache.put(wrap, mh);
355+ return mh;
356+ }
357+ throw new IllegalArgumentException("cannot find box adapter for "
358+ + wrap + (exact ? " (exact)" : "") + (raw ? " (raw)" : ""));
359+ }
360+
361+ public static MethodHandle box(Class<?> type) {
362+ boolean exact = false;
363+ // e.g., boxShort(short)Short if exact,
364+ // e.g., boxShort(short)Object if !exact
365+ return box(Wrapper.forPrimitiveType(type), exact, false);
366+ }
367+
368+ public static MethodHandle boxRaw(Class<?> type) {
369+ boolean exact = false;
370+ // e.g., boxShortRaw(int)Short if exact
371+ // e.g., boxShortRaw(int)Object if !exact
372+ return box(Wrapper.forPrimitiveType(type), exact, true);
373+ }
374+
375+ public static MethodHandle box(Wrapper type) {
376+ boolean exact = false;
377+ return box(type, exact, false);
378+ }
379+
380+ public static MethodHandle boxRaw(Wrapper type) {
381+ boolean exact = false;
382+ return box(type, exact, true);
383+ }
384+
385+ /// Kludges for when raw values get accidentally boxed.
386+
387+ static int unboxRawInteger(Object x) {
388+ if (x instanceof Integer)
389+ return (int) x;
390+ else
391+ return (int) unboxLong(x, false);
392+ }
393+
394+ static Integer reboxRawInteger(Object x) {
395+ if (x instanceof Integer)
396+ return (Integer) x;
397+ else
398+ return (int) unboxLong(x, false);
399+ }
400+
401+ static Byte reboxRawByte(Object x) {
402+ if (x instanceof Byte) return (Byte) x;
403+ return boxByteRaw(unboxRawInteger(x));
404+ }
405+
406+ static Short reboxRawShort(Object x) {
407+ if (x instanceof Short) return (Short) x;
408+ return boxShortRaw(unboxRawInteger(x));
409+ }
410+
411+ static Boolean reboxRawBoolean(Object x) {
412+ if (x instanceof Boolean) return (Boolean) x;
413+ return boxBooleanRaw(unboxRawInteger(x));
414+ }
415+
416+ static Character reboxRawCharacter(Object x) {
417+ if (x instanceof Character) return (Character) x;
418+ return boxCharacterRaw(unboxRawInteger(x));
419+ }
420+
421+ static Float reboxRawFloat(Object x) {
422+ if (x instanceof Float) return (Float) x;
423+ return boxFloatRaw(unboxRawInteger(x));
424+ }
425+
426+ static Long reboxRawLong(Object x) {
427+ return (Long) x; //never a rebox
428+ }
429+
430+ static Double reboxRawDouble(Object x) {
431+ if (x instanceof Double) return (Double) x;
432+ return boxDoubleRaw(unboxLong(x, true));
433+ }
434+
435+ private static MethodType reboxType(Wrapper wrap) {
436+ Class<?> boxType = wrap.wrapperType();
437+ return MethodType.methodType(boxType, Object.class);
438+ }
439+
440+ private static final EnumMap<Wrapper, MethodHandle>[]
441+ REBOX_CONVERSIONS = newWrapperCaches(1);
442+
443+ /**
444+ * Because we normalize primitive types to reduce the number of signatures,
445+ * primitives are sometimes manipulated under an "erased" type,
446+ * either int (for types other than long/double) or long (for all types).
447+ * When the erased primitive value is then boxed into an Integer or Long,
448+ * the final boxed primitive is sometimes required. This transformation
449+ * is called a "rebox". It takes an Integer or Long and produces some
450+ * other boxed value, typed (inexactly) as an Object
451+ */
452+ public static MethodHandle rebox(Wrapper wrap) {
453+ EnumMap<Wrapper, MethodHandle> cache = REBOX_CONVERSIONS[0];
454+ MethodHandle mh = cache.get(wrap);
455+ if (mh != null) {
456+ return mh;
457+ }
458+ // slow path
459+ switch (wrap) {
460+ case OBJECT:
461+ mh = IDENTITY; break;
462+ case VOID:
463+ throw new IllegalArgumentException("cannot rebox a void");
464+ }
465+ if (mh != null) {
466+ cache.put(wrap, mh);
467+ return mh;
468+ }
469+ // look up the method
470+ String name = "reboxRaw" + wrap.simpleName();
471+ MethodType type = reboxType(wrap);
472+ try {
473+ mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
474+ mh = mh.asType(IDENTITY.type());
475+ } catch (ReflectiveOperationException ex) {
476+ mh = null;
477+ }
478+ if (mh != null) {
479+ cache.put(wrap, mh);
480+ return mh;
481+ }
482+ throw new IllegalArgumentException("cannot find rebox adapter for " + wrap);
483+ }
484+
485+ public static MethodHandle rebox(Class<?> type) {
486+ return rebox(Wrapper.forPrimitiveType(type));
487+ }
488+
489+ /// Width-changing conversions between int and long.
490+
491+ static long widenInt(int x) {
492+ return (long) x;
493+ }
494+
495+ static Long widenBoxedInt(Integer x) {
496+ return (long)(int)x;
497+ }
498+
499+ static int narrowLong(long x) {
500+ return (int) x;
501+ }
502+
503+ static Integer narrowBoxedLong(Long x) {
504+ return (int)(long) x;
505+ }
506+
507+ /// Constant functions
508+
509+ static void ignore(Object x) {
510+ // no value to return; this is an unbox of null
511+ return;
512+ }
513+
514+ static void empty() {
515+ return;
516+ }
517+
518+ static Object zeroObject() {
519+ return null;
520+ }
521+
522+ static int zeroInteger() {
523+ return 0;
524+ }
525+
526+ static long zeroLong() {
527+ return 0;
528+ }
529+
530+ static float zeroFloat() {
531+ return 0;
532+ }
533+
534+ static double zeroDouble() {
535+ return 0;
536+ }
537+
538+ private static final EnumMap<Wrapper, MethodHandle>[]
539+ CONSTANT_FUNCTIONS = newWrapperCaches(2);
540+
541+ public static MethodHandle zeroConstantFunction(Wrapper wrap) {
542+ EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
543+ MethodHandle mh = cache.get(wrap);
544+ if (mh != null) {
545+ return mh;
546+ }
547+ // slow path
548+ MethodType type = MethodType.methodType(wrap.primitiveType());
549+ switch (wrap) {
550+ case VOID:
551+ mh = EMPTY;
552+ break;
553+ case OBJECT:
554+ case INT: case LONG: case FLOAT: case DOUBLE:
555+ try {
556+ mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.simpleName(), type);
557+ } catch (ReflectiveOperationException ex) {
558+ mh = null;
559+ }
560+ break;
561+ }
562+ if (mh != null) {
563+ cache.put(wrap, mh);
564+ return mh;
565+ }
566+
567+ // use the raw method
568+ Wrapper rawWrap = wrap.rawPrimitive();
569+ if (mh == null && rawWrap != wrap) {
570+ mh = MethodHandles.explicitCastArguments(zeroConstantFunction(rawWrap), type);
571+ }
572+ if (mh != null) {
573+ cache.put(wrap, mh);
574+ return mh;
575+ }
576+ throw new IllegalArgumentException("cannot find zero constant for " + wrap);
577+ }
578+
579+ /// Converting references to references.
580+
581+ /**
582+ * Value-killing function.
583+ * @param x an arbitrary reference value
584+ * @return a null
585+ */
586+ static Object alwaysNull(Object x) {
587+ return null;
588+ }
589+
590+ /**
591+ * Value-killing function.
592+ * @param x an arbitrary reference value
593+ * @return a zero
594+ */
595+ static int alwaysZero(Object x) {
596+ return 0;
597+ }
598+
599+ /**
600+ * Identity function.
601+ * @param x an arbitrary reference value
602+ * @return the same value x
603+ */
604+ static <T> T identity(T x) {
605+ return x;
606+ }
607+
608+ /**
609+ * Identity function on ints.
610+ * @param x an arbitrary int value
611+ * @return the same value x
612+ */
613+ static int identity(int x) {
614+ return x;
615+ }
616+
617+ static byte identity(byte x) {
618+ return x;
619+ }
620+
621+ static short identity(short x) {
622+ return x;
623+ }
624+
625+ static boolean identity(boolean x) {
626+ return x;
627+ }
628+
629+ static char identity(char x) {
630+ return x;
631+ }
632+
633+ /**
634+ * Identity function on longs.
635+ * @param x an arbitrary long value
636+ * @return the same value x
637+ */
638+ static long identity(long x) {
639+ return x;
640+ }
641+
642+ static float identity(float x) {
643+ return x;
644+ }
645+
646+ static double identity(double x) {
647+ return x;
648+ }
649+
650+ /**
651+ * Identity function, with reference cast.
652+ * @param t an arbitrary reference type
653+ * @param x an arbitrary reference value
654+ * @return the same value x
655+ */
656+ static <T,U> T castReference(Class<? extends T> t, U x) {
657+ return t.cast(x);
658+ }
659+
660+ private static final MethodHandle IDENTITY, IDENTITY_I, IDENTITY_J, CAST_REFERENCE, ALWAYS_NULL, ALWAYS_ZERO, ZERO_OBJECT, IGNORE, EMPTY, NEW_ARRAY;
661+ static {
662+ try {
663+ MethodType idType = MethodType.genericMethodType(1);
664+ MethodType castType = idType.insertParameterTypes(0, Class.class);
665+ MethodType alwaysZeroType = idType.changeReturnType(int.class);
666+ MethodType ignoreType = idType.changeReturnType(void.class);
667+ MethodType zeroObjectType = MethodType.genericMethodType(0);
668+ IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
669+ IDENTITY_I = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(int.class, int.class));
670+ IDENTITY_J = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(long.class, long.class));
671+ //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
672+ CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType);
673+ ALWAYS_NULL = IMPL_LOOKUP.findStatic(THIS_CLASS, "alwaysNull", idType);
674+ ALWAYS_ZERO = IMPL_LOOKUP.findStatic(THIS_CLASS, "alwaysZero", alwaysZeroType);
675+ ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
676+ IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
677+ EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
678+ NEW_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "newArray", MethodType.methodType(Object[].class, int.class));
679+ } catch (NoSuchMethodException | IllegalAccessException ex) {
680+ Error err = new InternalError("uncaught exception");
681+ err.initCause(ex);
682+ throw err;
683+ }
684+ }
685+
686+ // Varargs methods need to be in a separately initialized class, to bootstrapping problems.
687+ static class LazyStatics {
688+ private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
689+ static {
690+ try {
691+ //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
692+ COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
693+ COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
694+ MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
695+ } catch (ReflectiveOperationException ex) {
696+ Error err = new InternalError("uncaught exception");
697+ err.initCause(ex);
698+ throw err;
699+ }
700+ }
701+ }
702+
703+ private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
704+ = newWrapperCaches(2);
705+
706+ /** Return a method that casts its sole argument (an Object) to the given type
707+ * and returns it as the given type (if exact is true), or as plain Object (if erase is true).
708+ */
709+ public static MethodHandle cast(Class<?> type) {
710+ boolean exact = false;
711+ if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type);
712+ MethodHandle mh = null;
713+ Wrapper wrap = null;
714+ EnumMap<Wrapper, MethodHandle> cache = null;
715+ if (Wrapper.isWrapperType(type)) {
716+ wrap = Wrapper.forWrapperType(type);
717+ cache = WRAPPER_CASTS[exact?1:0];
718+ mh = cache.get(wrap);
719+ if (mh != null) return mh;
720+ }
721+ if (VerifyType.isNullReferenceConversion(Object.class, type))
722+ mh = IDENTITY;
723+ else if (VerifyType.isNullType(type))
724+ mh = ALWAYS_NULL;
725+ else
726+ mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
727+ if (exact) {
728+ MethodType xmt = MethodType.methodType(type, Object.class);
729+ mh = MethodHandles.explicitCastArguments(mh, xmt);
730+ //mh = AdapterMethodHandle.makeRetypeRaw(IMPL_TOKEN, xmt, mh);
731+ }
732+ if (cache != null)
733+ cache.put(wrap, mh);
734+ return mh;
735+ }
736+
737+ public static MethodHandle identity() {
738+ return IDENTITY;
739+ }
740+
741+ public static MethodHandle identity(Class<?> type) {
742+ // This stuff has been moved into MethodHandles:
743+ return MethodHandles.identity(type);
744+ }
745+
746+ public static MethodHandle identity(Wrapper wrap) {
747+ EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
748+ MethodHandle mh = cache.get(wrap);
749+ if (mh != null) {
750+ return mh;
751+ }
752+ // slow path
753+ MethodType type = MethodType.methodType(wrap.primitiveType());
754+ if (wrap != Wrapper.VOID)
755+ type = type.appendParameterTypes(wrap.primitiveType());
756+ try {
757+ mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
758+ } catch (ReflectiveOperationException ex) {
759+ mh = null;
760+ }
761+ if (mh == null && wrap == Wrapper.VOID) {
762+ mh = EMPTY; // #(){} : #()void
763+ }
764+ if (mh != null) {
765+ cache.put(wrap, mh);
766+ return mh;
767+ }
768+
769+ if (mh != null) {
770+ cache.put(wrap, mh);
771+ return mh;
772+ }
773+ throw new IllegalArgumentException("cannot find identity for " + wrap);
774+ }
775+
776+ /// Float/non-float conversions.
777+
778+ static float doubleToFloat(double x) {
779+ return (float) x;
780+ }
781+ static double floatToDouble(float x) {
782+ return x;
783+ }
784+
785+ // narrow double to integral type
786+ static long doubleToLong(double x) {
787+ return (long) x;
788+ }
789+ static int doubleToInt(double x) {
790+ return (int) x;
791+ }
792+ static short doubleToShort(double x) {
793+ return (short) x;
794+ }
795+ static char doubleToChar(double x) {
796+ return (char) x;
797+ }
798+ static byte doubleToByte(double x) {
799+ return (byte) x;
800+ }
801+ static boolean doubleToBoolean(double x) {
802+ return toBoolean((byte) x);
803+ }
804+
805+ // narrow float to integral type
806+ static long floatToLong(float x) {
807+ return (long) x;
808+ }
809+ static int floatToInt(float x) {
810+ return (int) x;
811+ }
812+ static short floatToShort(float x) {
813+ return (short) x;
814+ }
815+ static char floatToChar(float x) {
816+ return (char) x;
817+ }
818+ static byte floatToByte(float x) {
819+ return (byte) x;
820+ }
821+ static boolean floatToBoolean(float x) {
822+ return toBoolean((byte) x);
823+ }
824+
825+ // widen integral type to double
826+ static double longToDouble(long x) {
827+ return x;
828+ }
829+ static double intToDouble(int x) {
830+ return x;
831+ }
832+ static double shortToDouble(short x) {
833+ return x;
834+ }
835+ static double charToDouble(char x) {
836+ return x;
837+ }
838+ static double byteToDouble(byte x) {
839+ return x;
840+ }
841+ static double booleanToDouble(boolean x) {
842+ return fromBoolean(x);
843+ }
844+
845+ // widen integral type to float
846+ static float longToFloat(long x) {
847+ return x;
848+ }
849+ static float intToFloat(int x) {
850+ return x;
851+ }
852+ static float shortToFloat(short x) {
853+ return x;
854+ }
855+ static float charToFloat(char x) {
856+ return x;
857+ }
858+ static float byteToFloat(byte x) {
859+ return x;
860+ }
861+ static float booleanToFloat(boolean x) {
862+ return fromBoolean(x);
863+ }
864+
865+ static boolean toBoolean(byte x) {
866+ // see javadoc for MethodHandles.explicitCastArguments
867+ return ((x & 1) != 0);
868+ }
869+ static byte fromBoolean(boolean x) {
870+ // see javadoc for MethodHandles.explicitCastArguments
871+ return (x ? (byte)1 : (byte)0);
872+ }
873+
874+ private static final EnumMap<Wrapper, MethodHandle>[]
875+ CONVERT_FLOAT_FUNCTIONS = newWrapperCaches(4);
876+
877+ static MethodHandle convertFloatFunction(Wrapper wrap, boolean toFloat, boolean doubleSize) {
878+ EnumMap<Wrapper, MethodHandle> cache = CONVERT_FLOAT_FUNCTIONS[(toFloat?1:0)+(doubleSize?2:0)];
879+ MethodHandle mh = cache.get(wrap);
880+ if (mh != null) {
881+ return mh;
882+ }
883+ // slow path
884+ Wrapper fwrap = (doubleSize ? Wrapper.DOUBLE : Wrapper.FLOAT);
885+ Class<?> fix = wrap.primitiveType();
886+ Class<?> flt = (doubleSize ? double.class : float.class);
887+ Class<?> src = toFloat ? fix : flt;
888+ Class<?> dst = toFloat ? flt : fix;
889+ if (src == dst) return identity(wrap);
890+ MethodType type = MethodType.methodType(dst, src);
891+ switch (wrap) {
892+ case VOID:
893+ mh = toFloat ? zeroConstantFunction(fwrap) : MethodHandles.dropArguments(EMPTY, 0, flt);
894+ break;
895+ case OBJECT:
896+ mh = toFloat ? unbox(flt) : box(flt);
897+ break;
898+ default:
899+ try {
900+ mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
901+ } catch (ReflectiveOperationException ex) {
902+ mh = null;
903+ }
904+ break;
905+ }
906+ if (mh != null) {
907+ assert(mh.type() == type) : mh;
908+ cache.put(wrap, mh);
909+ return mh;
910+ }
911+
912+ throw new IllegalArgumentException("cannot find float conversion constant for " +
913+ src.getSimpleName()+" -> "+dst.getSimpleName());
914+ }
915+
916+ public static MethodHandle convertFromFloat(Class<?> fixType) {
917+ Wrapper wrap = Wrapper.forPrimitiveType(fixType);
918+ return convertFloatFunction(wrap, false, false);
919+ }
920+ public static MethodHandle convertFromDouble(Class<?> fixType) {
921+ Wrapper wrap = Wrapper.forPrimitiveType(fixType);
922+ return convertFloatFunction(wrap, false, true);
923+ }
924+ public static MethodHandle convertToFloat(Class<?> fixType) {
925+ Wrapper wrap = Wrapper.forPrimitiveType(fixType);
926+ return convertFloatFunction(wrap, true, false);
927+ }
928+ public static MethodHandle convertToDouble(Class<?> fixType) {
929+ Wrapper wrap = Wrapper.forPrimitiveType(fixType);
930+ return convertFloatFunction(wrap, true, true);
931+ }
932+
933+ private static String capitalize(String x) {
934+ return Character.toUpperCase(x.charAt(0))+x.substring(1);
935+ }
936+
937+ /// Collection of multiple arguments.
938+
939+ public static Object convertArrayElements(Class<?> arrayType, Object array) {
940+ Class<?> src = array.getClass().getComponentType();
941+ Class<?> dst = arrayType.getComponentType();
942+ if (src == null || dst == null) throw new IllegalArgumentException("not array type");
943+ Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
944+ Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
945+ int length;
946+ if (sw == null) {
947+ Object[] a = (Object[]) array;
948+ length = a.length;
949+ if (dw == null)
950+ return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
951+ Object res = dw.makeArray(length);
952+ dw.copyArrayUnboxing(a, 0, res, 0, length);
953+ return res;
954+ }
955+ length = java.lang.reflect.Array.getLength(array);
956+ Object[] res;
957+ if (dw == null) {
958+ res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
959+ } else {
960+ res = new Object[length];
961+ }
962+ sw.copyArrayBoxing(array, 0, res, 0, length);
963+ if (dw == null) return res;
964+ Object a = dw.makeArray(length);
965+ dw.copyArrayUnboxing(res, 0, a, 0, length);
966+ return a;
967+ }
968+
969+ private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
970+ MethodType type = MethodType.genericMethodType(nargs)
971+ .changeReturnType(rtype)
972+ .insertParameterTypes(0, ptypes);
973+ try {
974+ return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
975+ } catch (ReflectiveOperationException ex) {
976+ return null;
977+ }
978+ }
979+
980+ private static final Object[] NO_ARGS_ARRAY = {};
981+ private static Object[] makeArray(Object... args) { return args; }
982+ private static Object[] array() { return NO_ARGS_ARRAY; }
983+ private static Object[] array(Object a0)
984+ { return makeArray(a0); }
985+ private static Object[] array(Object a0, Object a1)
986+ { return makeArray(a0, a1); }
987+ private static Object[] array(Object a0, Object a1, Object a2)
988+ { return makeArray(a0, a1, a2); }
989+ private static Object[] array(Object a0, Object a1, Object a2, Object a3)
990+ { return makeArray(a0, a1, a2, a3); }
991+ private static Object[] array(Object a0, Object a1, Object a2, Object a3,
992+ Object a4)
993+ { return makeArray(a0, a1, a2, a3, a4); }
994+ private static Object[] array(Object a0, Object a1, Object a2, Object a3,
995+ Object a4, Object a5)
996+ { return makeArray(a0, a1, a2, a3, a4, a5); }
997+ private static Object[] array(Object a0, Object a1, Object a2, Object a3,
998+ Object a4, Object a5, Object a6)
999+ { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
1000+ private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1001+ Object a4, Object a5, Object a6, Object a7)
1002+ { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
1003+ private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1004+ Object a4, Object a5, Object a6, Object a7,
1005+ Object a8)
1006+ { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1007+ private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1008+ Object a4, Object a5, Object a6, Object a7,
1009+ Object a8, Object a9)
1010+ { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1011+ private static MethodHandle[] makeArrays() {
1012+ ArrayList<MethodHandle> mhs = new ArrayList<>();
1013+ for (;;) {
1014+ MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
1015+ if (mh == null) break;
1016+ mhs.add(mh);
1017+ }
1018+ assert(mhs.size() == 11); // current number of methods
1019+ return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
1020+ }
1021+ private static final MethodHandle[] ARRAYS = makeArrays();
1022+
1023+ // mh-fill versions of the above:
1024+ private static Object[] newArray(int len) { return new Object[len]; }
1025+ private static void fillWithArguments(Object[] a, int pos, Object... args) {
1026+ System.arraycopy(args, 0, a, pos, args.length);
1027+ }
1028+ // using Integer pos instead of int pos to avoid bootstrapping problems
1029+ private static Object[] fillArray(Object[] a, Integer pos, Object a0)
1030+ { fillWithArguments(a, pos, a0); return a; }
1031+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1)
1032+ { fillWithArguments(a, pos, a0, a1); return a; }
1033+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2)
1034+ { fillWithArguments(a, pos, a0, a1, a2); return a; }
1035+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3)
1036+ { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
1037+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3,
1038+ Object a4)
1039+ { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
1040+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3,
1041+ Object a4, Object a5)
1042+ { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
1043+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3,
1044+ Object a4, Object a5, Object a6)
1045+ { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
1046+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3,
1047+ Object a4, Object a5, Object a6, Object a7)
1048+ { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
1049+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3,
1050+ Object a4, Object a5, Object a6, Object a7,
1051+ Object a8)
1052+ { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
1053+ private static Object[] fillArray(Object[] a, Integer pos, Object a0, Object a1, Object a2, Object a3,
1054+ Object a4, Object a5, Object a6, Object a7,
1055+ Object a8, Object a9)
1056+ { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
1057+ private static MethodHandle[] makeFillArrays() {
1058+ ArrayList<MethodHandle> mhs = new ArrayList<>();
1059+ mhs.add(null); // there is no empty fill; at least a0 is required
1060+ for (;;) {
1061+ MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Object[].class, Integer.class);
1062+ if (mh == null) break;
1063+ mhs.add(mh);
1064+ }
1065+ assert(mhs.size() == 11); // current number of methods
1066+ return mhs.toArray(new MethodHandle[0]);
1067+ }
1068+ private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
1069+
1070+ private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
1071+ return Arrays.copyOf(a, a.length, arrayType);
1072+ }
1073+ private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
1074+ Object a = w.makeArray(boxes.length);
1075+ w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
1076+ return a;
1077+ }
1078+
1079+ /** Return a method handle that takes the indicated number of Object
1080+ * arguments and returns an Object array of them, as if for varargs.
1081+ */
1082+ public static MethodHandle varargsArray(int nargs) {
1083+ MethodHandle mh = ARRAYS[nargs];
1084+ if (mh != null) return mh;
1085+ mh = findCollector("array", nargs, Object[].class);
1086+ if (mh != null) return ARRAYS[nargs] = mh;
1087+ MethodHandle producer = filler(0); // identity function produces result
1088+ return ARRAYS[nargs] = buildVarargsArray(producer, nargs);
1089+ }
1090+
1091+ private static MethodHandle buildVarargsArray(MethodHandle producer, int nargs) {
1092+ // Build up the result mh as a sequence of fills like this:
1093+ // producer(fill(fill(fill(newArray(23),0,x1..x10),10,x11..x20),20,x21..x23))
1094+ // The various fill(_,10*I,___*[J]) are reusable.
1095+ MethodHandle filler = filler(nargs);
1096+ MethodHandle mh = producer;
1097+ mh = MethodHandles.dropArguments(mh, 1, filler.type().parameterList());
1098+ mh = MethodHandles.foldArguments(mh, filler);
1099+ mh = MethodHandles.foldArguments(mh, buildNewArray(nargs));
1100+ return mh;
1101+ }
1102+
1103+ private static MethodHandle buildNewArray(int nargs) {
1104+ return MethodHandles.insertArguments(NEW_ARRAY, 0, (int) nargs);
1105+ }
1106+
1107+ private static final MethodHandle[] FILLERS = new MethodHandle[MAX_ARITY+1];
1108+ // filler(N).invoke(a, arg0..arg[N-1]) fills a[0]..a[N-1]
1109+ private static MethodHandle filler(int nargs) {
1110+ MethodHandle filler = FILLERS[nargs];
1111+ if (filler != null) return filler;
1112+ return FILLERS[nargs] = buildFiller(nargs);
1113+ }
1114+ private static MethodHandle buildFiller(int nargs) {
1115+ if (nargs == 0)
1116+ return MethodHandles.identity(Object[].class);
1117+ final int CHUNK = (FILL_ARRAYS.length - 1);
1118+ int rightLen = nargs % CHUNK;
1119+ int leftLen = nargs - rightLen;
1120+ if (rightLen == 0) {
1121+ leftLen = nargs - (rightLen = CHUNK);
1122+ if (FILLERS[leftLen] == null) {
1123+ // build some precursors from left to right
1124+ for (int j = 0; j < leftLen; j += CHUNK) filler(j);
1125+ }
1126+ }
1127+ MethodHandle leftFill = filler(leftLen); // recursive fill
1128+ MethodHandle rightFill = FILL_ARRAYS[rightLen];
1129+ rightFill = MethodHandles.insertArguments(rightFill, 1, (int) leftLen); // [leftLen..nargs-1]
1130+
1131+ // Combine the two fills: right(left(newArray(nargs), x1..x20), x21..x23)
1132+ MethodHandle mh = filler(0); // identity function produces result
1133+ mh = MethodHandles.dropArguments(mh, 1, rightFill.type().parameterList());
1134+ mh = MethodHandles.foldArguments(mh, rightFill);
1135+ if (leftLen > 0) {
1136+ mh = MethodHandles.dropArguments(mh, 1, leftFill.type().parameterList());
1137+ mh = MethodHandles.foldArguments(mh, leftFill);
1138+ }
1139+ return mh;
1140+ }
1141+
1142+ // Type-polymorphic version of varargs maker.
1143+ private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
1144+ = new ClassValue<MethodHandle[]>() {
1145+ protected MethodHandle[] computeValue(Class<?> type) {
1146+ return new MethodHandle[256];
1147+ }
1148+ };
1149+
1150+ /** Return a method handle that takes the indicated number of
1151+ * typed arguments and returns an array of them.
1152+ * The type argument is the array type.
1153+ */
1154+ public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
1155+ Class<?> elemType = arrayType.getComponentType();
1156+ if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType);
1157+ // FIXME: Need more special casing and caching here.
1158+ if (elemType == Object.class)
1159+ return varargsArray(nargs);
1160+ // other cases: primitive arrays, subtypes of Object[]
1161+ MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
1162+ MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
1163+ if (mh != null) return mh;
1164+ MethodHandle producer = buildArrayProducer(arrayType);
1165+ mh = buildVarargsArray(producer, nargs);
1166+ mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
1167+ cache[nargs] = mh;
1168+ return mh;
1169+ }
1170+
1171+ private static MethodHandle buildArrayProducer(Class<?> arrayType) {
1172+ Class<?> elemType = arrayType.getComponentType();
1173+ if (elemType.isPrimitive())
1174+ return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
1175+ else
1176+ return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
1177+ }
1178+
1179+ // List version of varargs maker.
1180+
1181+ private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
1182+ private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
1183+ private static List<Object> list() { return NO_ARGS_LIST; }
1184+ private static List<Object> list(Object a0)
1185+ { return makeList(a0); }
1186+ private static List<Object> list(Object a0, Object a1)
1187+ { return makeList(a0, a1); }
1188+ private static List<Object> list(Object a0, Object a1, Object a2)
1189+ { return makeList(a0, a1, a2); }
1190+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
1191+ { return makeList(a0, a1, a2, a3); }
1192+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1193+ Object a4)
1194+ { return makeList(a0, a1, a2, a3, a4); }
1195+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1196+ Object a4, Object a5)
1197+ { return makeList(a0, a1, a2, a3, a4, a5); }
1198+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1199+ Object a4, Object a5, Object a6)
1200+ { return makeList(a0, a1, a2, a3, a4, a5, a6); }
1201+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1202+ Object a4, Object a5, Object a6, Object a7)
1203+ { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
1204+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1205+ Object a4, Object a5, Object a6, Object a7,
1206+ Object a8)
1207+ { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1208+ private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1209+ Object a4, Object a5, Object a6, Object a7,
1210+ Object a8, Object a9)
1211+ { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1212+ private static MethodHandle[] makeLists() {
1213+ ArrayList<MethodHandle> mhs = new ArrayList<>();
1214+ for (;;) {
1215+ MethodHandle mh = findCollector("list", mhs.size(), List.class);
1216+ if (mh == null) break;
1217+ mhs.add(mh);
1218+ }
1219+ assert(mhs.size() == 11); // current number of methods
1220+ return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
1221+ }
1222+ private static final MethodHandle[] LISTS = makeLists();
1223+
1224+ /** Return a method handle that takes the indicated number of Object
1225+ * arguments and returns a List.
1226+ */
1227+ public static MethodHandle varargsList(int nargs) {
1228+ MethodHandle mh = LISTS[nargs];
1229+ if (mh != null) return mh;
1230+ mh = findCollector("list", nargs, List.class);
1231+ if (mh != null) return LISTS[nargs] = mh;
1232+ return LISTS[nargs] = buildVarargsList(nargs);
1233+ }
1234+ private static MethodHandle buildVarargsList(int nargs) {
1235+ return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
1236+ }
1237+}