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
26package sun.invoke.util;
27
28import java.lang.invoke.MethodHandle;
29import java.lang.invoke.MethodHandles;
30import java.lang.invoke.MethodHandles.Lookup;
31import java.lang.invoke.MethodType;
32import java.security.AccessController;
33import java.security.PrivilegedAction;
34import java.util.ArrayList;
35import java.util.Arrays;
36import java.util.Collections;
37import java.util.EnumMap;
38import java.util.List;
39
40public 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}