1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/sun/invoke/util/ValueConversions.java Sat Aug 09 11:11:13 2014 +0200
1.3 @@ -0,0 +1,1188 @@
1.4 +/*
1.5 + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +package sun.invoke.util;
1.30 +
1.31 +import java.lang.invoke.MethodHandle;
1.32 +import java.lang.invoke.MethodHandles;
1.33 +import java.lang.invoke.MethodHandles.Lookup;
1.34 +import java.lang.invoke.MethodType;
1.35 +import java.security.AccessController;
1.36 +import java.security.PrivilegedAction;
1.37 +import java.util.ArrayList;
1.38 +import java.util.Arrays;
1.39 +import java.util.Collections;
1.40 +import java.util.EnumMap;
1.41 +import java.util.List;
1.42 +
1.43 +public class ValueConversions {
1.44 + private static final Class<?> THIS_CLASS = ValueConversions.class;
1.45 + // Do not adjust this except for special platforms:
1.46 + private static final int MAX_ARITY;
1.47 + static {
1.48 + final Object[] values = { 255 };
1.49 + AccessController.doPrivileged(new PrivilegedAction<Void>() {
1.50 + @Override
1.51 + public Void run() {
1.52 + values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
1.53 + return null;
1.54 + }
1.55 + });
1.56 + MAX_ARITY = (Integer) values[0];
1.57 + }
1.58 +
1.59 + private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
1.60 +
1.61 + private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
1.62 + @SuppressWarnings("unchecked") // generic array creation
1.63 + EnumMap<Wrapper, MethodHandle>[] caches
1.64 + = (EnumMap<Wrapper, MethodHandle>[]) new EnumMap<?,?>[n];
1.65 + for (int i = 0; i < n; i++)
1.66 + caches[i] = new EnumMap<>(Wrapper.class);
1.67 + return caches;
1.68 + }
1.69 +
1.70 + /// Converting references to values.
1.71 +
1.72 + // There are several levels of this unboxing conversions:
1.73 + // no conversions: exactly Integer.valueOf, etc.
1.74 + // implicit conversions sanctioned by JLS 5.1.2, etc.
1.75 + // explicit conversions as allowed by explicitCastArguments
1.76 +
1.77 + static int unboxInteger(Object x, boolean cast) {
1.78 + if (x instanceof Integer)
1.79 + return ((Integer) x).intValue();
1.80 + return primitiveConversion(Wrapper.INT, x, cast).intValue();
1.81 + }
1.82 +
1.83 + static byte unboxByte(Object x, boolean cast) {
1.84 + if (x instanceof Byte)
1.85 + return ((Byte) x).byteValue();
1.86 + return primitiveConversion(Wrapper.BYTE, x, cast).byteValue();
1.87 + }
1.88 +
1.89 + static short unboxShort(Object x, boolean cast) {
1.90 + if (x instanceof Short)
1.91 + return ((Short) x).shortValue();
1.92 + return primitiveConversion(Wrapper.SHORT, x, cast).shortValue();
1.93 + }
1.94 +
1.95 + static boolean unboxBoolean(Object x, boolean cast) {
1.96 + if (x instanceof Boolean)
1.97 + return ((Boolean) x).booleanValue();
1.98 + return (primitiveConversion(Wrapper.BOOLEAN, x, cast).intValue() & 1) != 0;
1.99 + }
1.100 +
1.101 + static char unboxCharacter(Object x, boolean cast) {
1.102 + if (x instanceof Character)
1.103 + return ((Character) x).charValue();
1.104 + return (char) primitiveConversion(Wrapper.CHAR, x, cast).intValue();
1.105 + }
1.106 +
1.107 + static long unboxLong(Object x, boolean cast) {
1.108 + if (x instanceof Long)
1.109 + return ((Long) x).longValue();
1.110 + return primitiveConversion(Wrapper.LONG, x, cast).longValue();
1.111 + }
1.112 +
1.113 + static float unboxFloat(Object x, boolean cast) {
1.114 + if (x instanceof Float)
1.115 + return ((Float) x).floatValue();
1.116 + return primitiveConversion(Wrapper.FLOAT, x, cast).floatValue();
1.117 + }
1.118 +
1.119 + static double unboxDouble(Object x, boolean cast) {
1.120 + if (x instanceof Double)
1.121 + return ((Double) x).doubleValue();
1.122 + return primitiveConversion(Wrapper.DOUBLE, x, cast).doubleValue();
1.123 + }
1.124 +
1.125 + private static MethodType unboxType(Wrapper wrap) {
1.126 + return MethodType.methodType(wrap.primitiveType(), Object.class, boolean.class);
1.127 + }
1.128 +
1.129 + private static final EnumMap<Wrapper, MethodHandle>[]
1.130 + UNBOX_CONVERSIONS = newWrapperCaches(2);
1.131 +
1.132 + private static MethodHandle unbox(Wrapper wrap, boolean cast) {
1.133 + EnumMap<Wrapper, MethodHandle> cache = UNBOX_CONVERSIONS[(cast?1:0)];
1.134 + MethodHandle mh = cache.get(wrap);
1.135 + if (mh != null) {
1.136 + return mh;
1.137 + }
1.138 + // slow path
1.139 + switch (wrap) {
1.140 + case OBJECT:
1.141 + mh = IDENTITY; break;
1.142 + case VOID:
1.143 + mh = IGNORE; break;
1.144 + }
1.145 + if (mh != null) {
1.146 + cache.put(wrap, mh);
1.147 + return mh;
1.148 + }
1.149 + // look up the method
1.150 + String name = "unbox" + wrap.wrapperSimpleName();
1.151 + MethodType type = unboxType(wrap);
1.152 + try {
1.153 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
1.154 + } catch (ReflectiveOperationException ex) {
1.155 + mh = null;
1.156 + }
1.157 + if (mh != null) {
1.158 + mh = MethodHandles.insertArguments(mh, 1, cast);
1.159 + cache.put(wrap, mh);
1.160 + return mh;
1.161 + }
1.162 + throw new IllegalArgumentException("cannot find unbox adapter for " + wrap
1.163 + + (cast ? " (cast)" : ""));
1.164 + }
1.165 +
1.166 + public static MethodHandle unboxCast(Wrapper type) {
1.167 + return unbox(type, true);
1.168 + }
1.169 +
1.170 + public static MethodHandle unbox(Class<?> type) {
1.171 + return unbox(Wrapper.forPrimitiveType(type), false);
1.172 + }
1.173 +
1.174 + public static MethodHandle unboxCast(Class<?> type) {
1.175 + return unbox(Wrapper.forPrimitiveType(type), true);
1.176 + }
1.177 +
1.178 + static private final Integer ZERO_INT = 0, ONE_INT = 1;
1.179 +
1.180 + /// Primitive conversions
1.181 + /**
1.182 + * Produce a Number which represents the given value {@code x}
1.183 + * according to the primitive type of the given wrapper {@code wrap}.
1.184 + * Caller must invoke intValue, byteValue, longValue (etc.) on the result
1.185 + * to retrieve the desired primitive value.
1.186 + */
1.187 + public static Number primitiveConversion(Wrapper wrap, Object x, boolean cast) {
1.188 + // Maybe merge this code with Wrapper.convert/cast.
1.189 + Number res;
1.190 + if (x == null) {
1.191 + if (!cast) return null;
1.192 + return ZERO_INT;
1.193 + }
1.194 + if (x instanceof Number) {
1.195 + res = (Number) x;
1.196 + } else if (x instanceof Boolean) {
1.197 + res = ((boolean)x ? ONE_INT : ZERO_INT);
1.198 + } else if (x instanceof Character) {
1.199 + res = (int)(char)x;
1.200 + } else {
1.201 + // this will fail with the required ClassCastException:
1.202 + res = (Number) x;
1.203 + }
1.204 + Wrapper xwrap = Wrapper.findWrapperType(x.getClass());
1.205 + if (xwrap == null || !cast && !wrap.isConvertibleFrom(xwrap))
1.206 + // this will fail with the required ClassCastException:
1.207 + return (Number) wrap.wrapperType().cast(x);
1.208 + return res;
1.209 + }
1.210 +
1.211 + /**
1.212 + * The JVM verifier allows boolean, byte, short, or char to widen to int.
1.213 + * Support exactly this conversion, from a boxed value type Boolean,
1.214 + * Byte, Short, Character, or Integer.
1.215 + */
1.216 + public static int widenSubword(Object x) {
1.217 + if (x instanceof Integer)
1.218 + return (int) x;
1.219 + else if (x instanceof Boolean)
1.220 + return fromBoolean((boolean) x);
1.221 + else if (x instanceof Character)
1.222 + return (char) x;
1.223 + else if (x instanceof Short)
1.224 + return (short) x;
1.225 + else if (x instanceof Byte)
1.226 + return (byte) x;
1.227 + else
1.228 + // Fail with a ClassCastException.
1.229 + return (int) x;
1.230 + }
1.231 +
1.232 + /// Converting primitives to references
1.233 +
1.234 + static Integer boxInteger(int x) {
1.235 + return x;
1.236 + }
1.237 +
1.238 + static Byte boxByte(byte x) {
1.239 + return x;
1.240 + }
1.241 +
1.242 + static Short boxShort(short x) {
1.243 + return x;
1.244 + }
1.245 +
1.246 + static Boolean boxBoolean(boolean x) {
1.247 + return x;
1.248 + }
1.249 +
1.250 + static Character boxCharacter(char x) {
1.251 + return x;
1.252 + }
1.253 +
1.254 + static Long boxLong(long x) {
1.255 + return x;
1.256 + }
1.257 +
1.258 + static Float boxFloat(float x) {
1.259 + return x;
1.260 + }
1.261 +
1.262 + static Double boxDouble(double x) {
1.263 + return x;
1.264 + }
1.265 +
1.266 + private static MethodType boxType(Wrapper wrap) {
1.267 + // be exact, since return casts are hard to compose
1.268 + Class<?> boxType = wrap.wrapperType();
1.269 + return MethodType.methodType(boxType, wrap.primitiveType());
1.270 + }
1.271 +
1.272 + private static final EnumMap<Wrapper, MethodHandle>[]
1.273 + BOX_CONVERSIONS = newWrapperCaches(2);
1.274 +
1.275 + private static MethodHandle box(Wrapper wrap, boolean exact) {
1.276 + EnumMap<Wrapper, MethodHandle> cache = BOX_CONVERSIONS[(exact?1:0)];
1.277 + MethodHandle mh = cache.get(wrap);
1.278 + if (mh != null) {
1.279 + return mh;
1.280 + }
1.281 + // slow path
1.282 + switch (wrap) {
1.283 + case OBJECT:
1.284 + mh = IDENTITY; break;
1.285 + case VOID:
1.286 + mh = ZERO_OBJECT;
1.287 + break;
1.288 + }
1.289 + if (mh != null) {
1.290 + cache.put(wrap, mh);
1.291 + return mh;
1.292 + }
1.293 + // look up the method
1.294 + String name = "box" + wrap.wrapperSimpleName();
1.295 + MethodType type = boxType(wrap);
1.296 + if (exact) {
1.297 + try {
1.298 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
1.299 + } catch (ReflectiveOperationException ex) {
1.300 + mh = null;
1.301 + }
1.302 + } else {
1.303 + mh = box(wrap, !exact).asType(type.erase());
1.304 + }
1.305 + if (mh != null) {
1.306 + cache.put(wrap, mh);
1.307 + return mh;
1.308 + }
1.309 + throw new IllegalArgumentException("cannot find box adapter for "
1.310 + + wrap + (exact ? " (exact)" : ""));
1.311 + }
1.312 +
1.313 + public static MethodHandle box(Class<?> type) {
1.314 + boolean exact = false;
1.315 + // e.g., boxShort(short)Short if exact,
1.316 + // e.g., boxShort(short)Object if !exact
1.317 + return box(Wrapper.forPrimitiveType(type), exact);
1.318 + }
1.319 +
1.320 + public static MethodHandle box(Wrapper type) {
1.321 + boolean exact = false;
1.322 + return box(type, exact);
1.323 + }
1.324 +
1.325 + /// Constant functions
1.326 +
1.327 + static void ignore(Object x) {
1.328 + // no value to return; this is an unbox of null
1.329 + }
1.330 +
1.331 + static void empty() {
1.332 + }
1.333 +
1.334 + static Object zeroObject() {
1.335 + return null;
1.336 + }
1.337 +
1.338 + static int zeroInteger() {
1.339 + return 0;
1.340 + }
1.341 +
1.342 + static long zeroLong() {
1.343 + return 0;
1.344 + }
1.345 +
1.346 + static float zeroFloat() {
1.347 + return 0;
1.348 + }
1.349 +
1.350 + static double zeroDouble() {
1.351 + return 0;
1.352 + }
1.353 +
1.354 + private static final EnumMap<Wrapper, MethodHandle>[]
1.355 + CONSTANT_FUNCTIONS = newWrapperCaches(2);
1.356 +
1.357 + public static MethodHandle zeroConstantFunction(Wrapper wrap) {
1.358 + EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[0];
1.359 + MethodHandle mh = cache.get(wrap);
1.360 + if (mh != null) {
1.361 + return mh;
1.362 + }
1.363 + // slow path
1.364 + MethodType type = MethodType.methodType(wrap.primitiveType());
1.365 + switch (wrap) {
1.366 + case VOID:
1.367 + mh = EMPTY;
1.368 + break;
1.369 + case OBJECT:
1.370 + case INT: case LONG: case FLOAT: case DOUBLE:
1.371 + try {
1.372 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "zero"+wrap.wrapperSimpleName(), type);
1.373 + } catch (ReflectiveOperationException ex) {
1.374 + mh = null;
1.375 + }
1.376 + break;
1.377 + }
1.378 + if (mh != null) {
1.379 + cache.put(wrap, mh);
1.380 + return mh;
1.381 + }
1.382 +
1.383 + // use zeroInt and cast the result
1.384 + if (wrap.isSubwordOrInt() && wrap != Wrapper.INT) {
1.385 + mh = MethodHandles.explicitCastArguments(zeroConstantFunction(Wrapper.INT), type);
1.386 + cache.put(wrap, mh);
1.387 + return mh;
1.388 + }
1.389 + throw new IllegalArgumentException("cannot find zero constant for " + wrap);
1.390 + }
1.391 +
1.392 + /// Converting references to references.
1.393 +
1.394 + /**
1.395 + * Identity function.
1.396 + * @param x an arbitrary reference value
1.397 + * @return the same value x
1.398 + */
1.399 + static <T> T identity(T x) {
1.400 + return x;
1.401 + }
1.402 +
1.403 + static <T> T[] identity(T[] x) {
1.404 + return x;
1.405 + }
1.406 +
1.407 + /**
1.408 + * Identity function on ints.
1.409 + * @param x an arbitrary int value
1.410 + * @return the same value x
1.411 + */
1.412 + static int identity(int x) {
1.413 + return x;
1.414 + }
1.415 +
1.416 + static byte identity(byte x) {
1.417 + return x;
1.418 + }
1.419 +
1.420 + static short identity(short x) {
1.421 + return x;
1.422 + }
1.423 +
1.424 + static boolean identity(boolean x) {
1.425 + return x;
1.426 + }
1.427 +
1.428 + static char identity(char x) {
1.429 + return x;
1.430 + }
1.431 +
1.432 + /**
1.433 + * Identity function on longs.
1.434 + * @param x an arbitrary long value
1.435 + * @return the same value x
1.436 + */
1.437 + static long identity(long x) {
1.438 + return x;
1.439 + }
1.440 +
1.441 + static float identity(float x) {
1.442 + return x;
1.443 + }
1.444 +
1.445 + static double identity(double x) {
1.446 + return x;
1.447 + }
1.448 +
1.449 + /**
1.450 + * Identity function, with reference cast.
1.451 + * @param t an arbitrary reference type
1.452 + * @param x an arbitrary reference value
1.453 + * @return the same value x
1.454 + */
1.455 + @SuppressWarnings("unchecked")
1.456 + static <T,U> T castReference(Class<? extends T> t, U x) {
1.457 + // inlined Class.cast because we can't ForceInline it
1.458 + if (x != null && !t.isInstance(x))
1.459 + throw newClassCastException(t, x);
1.460 + return (T) x;
1.461 + }
1.462 +
1.463 + private static ClassCastException newClassCastException(Class<?> t, Object obj) {
1.464 + return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
1.465 + }
1.466 +
1.467 + private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
1.468 + ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
1.469 + static {
1.470 + try {
1.471 + MethodType idType = MethodType.genericMethodType(1);
1.472 + MethodType castType = idType.insertParameterTypes(0, Class.class);
1.473 + MethodType ignoreType = idType.changeReturnType(void.class);
1.474 + MethodType zeroObjectType = MethodType.genericMethodType(0);
1.475 + IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", idType);
1.476 + //CAST_REFERENCE = IMPL_LOOKUP.findVirtual(Class.class, "cast", idType);
1.477 + CAST_REFERENCE = IMPL_LOOKUP.findStatic(THIS_CLASS, "castReference", castType);
1.478 + ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
1.479 + IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
1.480 + EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
1.481 + ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
1.482 + FILL_NEW_ARRAY = IMPL_LOOKUP
1.483 + .findStatic(THIS_CLASS, "fillNewArray",
1.484 + MethodType.methodType(Object[].class, Integer.class, Object[].class));
1.485 + FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
1.486 + .findStatic(THIS_CLASS, "fillNewTypedArray",
1.487 + MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
1.488 + } catch (NoSuchMethodException | IllegalAccessException ex) {
1.489 + throw newInternalError("uncaught exception", ex);
1.490 + }
1.491 + }
1.492 +
1.493 + // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
1.494 + static class LazyStatics {
1.495 + private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
1.496 + static {
1.497 + try {
1.498 + //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
1.499 + COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
1.500 + COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
1.501 + MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
1.502 + } catch (ReflectiveOperationException ex) {
1.503 + throw newInternalError("uncaught exception", ex);
1.504 + }
1.505 + }
1.506 + }
1.507 +
1.508 + private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
1.509 + = newWrapperCaches(1);
1.510 +
1.511 + /** Return a method that casts its sole argument (an Object) to the given type
1.512 + * and returns it as the given type.
1.513 + */
1.514 + public static MethodHandle cast(Class<?> type) {
1.515 + if (type.isPrimitive()) throw new IllegalArgumentException("cannot cast primitive type "+type);
1.516 + MethodHandle mh;
1.517 + Wrapper wrap = null;
1.518 + EnumMap<Wrapper, MethodHandle> cache = null;
1.519 + if (Wrapper.isWrapperType(type)) {
1.520 + wrap = Wrapper.forWrapperType(type);
1.521 + cache = WRAPPER_CASTS[0];
1.522 + mh = cache.get(wrap);
1.523 + if (mh != null) return mh;
1.524 + }
1.525 + mh = MethodHandles.insertArguments(CAST_REFERENCE, 0, type);
1.526 + if (cache != null)
1.527 + cache.put(wrap, mh);
1.528 + return mh;
1.529 + }
1.530 +
1.531 + public static MethodHandle identity() {
1.532 + return IDENTITY;
1.533 + }
1.534 +
1.535 + public static MethodHandle identity(Class<?> type) {
1.536 + if (!type.isPrimitive())
1.537 + // Reference identity has been moved into MethodHandles:
1.538 + return MethodHandles.identity(type);
1.539 + return identity(Wrapper.findPrimitiveType(type));
1.540 + }
1.541 +
1.542 + public static MethodHandle identity(Wrapper wrap) {
1.543 + EnumMap<Wrapper, MethodHandle> cache = CONSTANT_FUNCTIONS[1];
1.544 + MethodHandle mh = cache.get(wrap);
1.545 + if (mh != null) {
1.546 + return mh;
1.547 + }
1.548 + // slow path
1.549 + MethodType type = MethodType.methodType(wrap.primitiveType());
1.550 + if (wrap != Wrapper.VOID)
1.551 + type = type.appendParameterTypes(wrap.primitiveType());
1.552 + try {
1.553 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", type);
1.554 + } catch (ReflectiveOperationException ex) {
1.555 + mh = null;
1.556 + }
1.557 + if (mh == null && wrap == Wrapper.VOID) {
1.558 + mh = EMPTY; // #(){} : #()void
1.559 + }
1.560 + if (mh != null) {
1.561 + cache.put(wrap, mh);
1.562 + return mh;
1.563 + }
1.564 +
1.565 + if (mh != null) {
1.566 + cache.put(wrap, mh);
1.567 + return mh;
1.568 + }
1.569 + throw new IllegalArgumentException("cannot find identity for " + wrap);
1.570 + }
1.571 +
1.572 + /// Primitive conversions.
1.573 + // These are supported directly by the JVM, usually by a single instruction.
1.574 + // In the case of narrowing to a subword, there may be a pair of instructions.
1.575 + // In the case of booleans, there may be a helper routine to manage a 1-bit value.
1.576 + // This is the full 8x8 matrix (minus the diagonal).
1.577 +
1.578 + // narrow double to all other types:
1.579 + static float doubleToFloat(double x) { // bytecode: d2f
1.580 + return (float) x;
1.581 + }
1.582 + static long doubleToLong(double x) { // bytecode: d2l
1.583 + return (long) x;
1.584 + }
1.585 + static int doubleToInt(double x) { // bytecode: d2i
1.586 + return (int) x;
1.587 + }
1.588 + static short doubleToShort(double x) { // bytecodes: d2i, i2s
1.589 + return (short) x;
1.590 + }
1.591 + static char doubleToChar(double x) { // bytecodes: d2i, i2c
1.592 + return (char) x;
1.593 + }
1.594 + static byte doubleToByte(double x) { // bytecodes: d2i, i2b
1.595 + return (byte) x;
1.596 + }
1.597 + static boolean doubleToBoolean(double x) {
1.598 + return toBoolean((byte) x);
1.599 + }
1.600 +
1.601 + // widen float:
1.602 + static double floatToDouble(float x) { // bytecode: f2d
1.603 + return x;
1.604 + }
1.605 + // narrow float:
1.606 + static long floatToLong(float x) { // bytecode: f2l
1.607 + return (long) x;
1.608 + }
1.609 + static int floatToInt(float x) { // bytecode: f2i
1.610 + return (int) x;
1.611 + }
1.612 + static short floatToShort(float x) { // bytecodes: f2i, i2s
1.613 + return (short) x;
1.614 + }
1.615 + static char floatToChar(float x) { // bytecodes: f2i, i2c
1.616 + return (char) x;
1.617 + }
1.618 + static byte floatToByte(float x) { // bytecodes: f2i, i2b
1.619 + return (byte) x;
1.620 + }
1.621 + static boolean floatToBoolean(float x) {
1.622 + return toBoolean((byte) x);
1.623 + }
1.624 +
1.625 + // widen long:
1.626 + static double longToDouble(long x) { // bytecode: l2d
1.627 + return x;
1.628 + }
1.629 + static float longToFloat(long x) { // bytecode: l2f
1.630 + return x;
1.631 + }
1.632 + // narrow long:
1.633 + static int longToInt(long x) { // bytecode: l2i
1.634 + return (int) x;
1.635 + }
1.636 + static short longToShort(long x) { // bytecodes: f2i, i2s
1.637 + return (short) x;
1.638 + }
1.639 + static char longToChar(long x) { // bytecodes: f2i, i2c
1.640 + return (char) x;
1.641 + }
1.642 + static byte longToByte(long x) { // bytecodes: f2i, i2b
1.643 + return (byte) x;
1.644 + }
1.645 + static boolean longToBoolean(long x) {
1.646 + return toBoolean((byte) x);
1.647 + }
1.648 +
1.649 + // widen int:
1.650 + static double intToDouble(int x) { // bytecode: i2d
1.651 + return x;
1.652 + }
1.653 + static float intToFloat(int x) { // bytecode: i2f
1.654 + return x;
1.655 + }
1.656 + static long intToLong(int x) { // bytecode: i2l
1.657 + return x;
1.658 + }
1.659 + // narrow int:
1.660 + static short intToShort(int x) { // bytecode: i2s
1.661 + return (short) x;
1.662 + }
1.663 + static char intToChar(int x) { // bytecode: i2c
1.664 + return (char) x;
1.665 + }
1.666 + static byte intToByte(int x) { // bytecode: i2b
1.667 + return (byte) x;
1.668 + }
1.669 + static boolean intToBoolean(int x) {
1.670 + return toBoolean((byte) x);
1.671 + }
1.672 +
1.673 + // widen short:
1.674 + static double shortToDouble(short x) { // bytecode: i2d (implicit 's2i')
1.675 + return x;
1.676 + }
1.677 + static float shortToFloat(short x) { // bytecode: i2f (implicit 's2i')
1.678 + return x;
1.679 + }
1.680 + static long shortToLong(short x) { // bytecode: i2l (implicit 's2i')
1.681 + return x;
1.682 + }
1.683 + static int shortToInt(short x) { // (implicit 's2i')
1.684 + return x;
1.685 + }
1.686 + // narrow short:
1.687 + static char shortToChar(short x) { // bytecode: i2c (implicit 's2i')
1.688 + return (char)x;
1.689 + }
1.690 + static byte shortToByte(short x) { // bytecode: i2b (implicit 's2i')
1.691 + return (byte)x;
1.692 + }
1.693 + static boolean shortToBoolean(short x) {
1.694 + return toBoolean((byte) x);
1.695 + }
1.696 +
1.697 + // widen char:
1.698 + static double charToDouble(char x) { // bytecode: i2d (implicit 'c2i')
1.699 + return x;
1.700 + }
1.701 + static float charToFloat(char x) { // bytecode: i2f (implicit 'c2i')
1.702 + return x;
1.703 + }
1.704 + static long charToLong(char x) { // bytecode: i2l (implicit 'c2i')
1.705 + return x;
1.706 + }
1.707 + static int charToInt(char x) { // (implicit 'c2i')
1.708 + return x;
1.709 + }
1.710 + // narrow char:
1.711 + static short charToShort(char x) { // bytecode: i2s (implicit 'c2i')
1.712 + return (short)x;
1.713 + }
1.714 + static byte charToByte(char x) { // bytecode: i2b (implicit 'c2i')
1.715 + return (byte)x;
1.716 + }
1.717 + static boolean charToBoolean(char x) {
1.718 + return toBoolean((byte) x);
1.719 + }
1.720 +
1.721 + // widen byte:
1.722 + static double byteToDouble(byte x) { // bytecode: i2d (implicit 'b2i')
1.723 + return x;
1.724 + }
1.725 + static float byteToFloat(byte x) { // bytecode: i2f (implicit 'b2i')
1.726 + return x;
1.727 + }
1.728 + static long byteToLong(byte x) { // bytecode: i2l (implicit 'b2i')
1.729 + return x;
1.730 + }
1.731 + static int byteToInt(byte x) { // (implicit 'b2i')
1.732 + return x;
1.733 + }
1.734 + static short byteToShort(byte x) { // bytecode: i2s (implicit 'b2i')
1.735 + return (short)x;
1.736 + }
1.737 + static char byteToChar(byte x) { // bytecode: i2b (implicit 'b2i')
1.738 + return (char)x;
1.739 + }
1.740 + // narrow byte to boolean:
1.741 + static boolean byteToBoolean(byte x) {
1.742 + return toBoolean(x);
1.743 + }
1.744 +
1.745 + // widen boolean to all types:
1.746 + static double booleanToDouble(boolean x) {
1.747 + return fromBoolean(x);
1.748 + }
1.749 + static float booleanToFloat(boolean x) {
1.750 + return fromBoolean(x);
1.751 + }
1.752 + static long booleanToLong(boolean x) {
1.753 + return fromBoolean(x);
1.754 + }
1.755 + static int booleanToInt(boolean x) {
1.756 + return fromBoolean(x);
1.757 + }
1.758 + static short booleanToShort(boolean x) {
1.759 + return fromBoolean(x);
1.760 + }
1.761 + static char booleanToChar(boolean x) {
1.762 + return (char)fromBoolean(x);
1.763 + }
1.764 + static byte booleanToByte(boolean x) {
1.765 + return fromBoolean(x);
1.766 + }
1.767 +
1.768 + // helpers to force boolean into the conversion scheme:
1.769 + static boolean toBoolean(byte x) {
1.770 + // see javadoc for MethodHandles.explicitCastArguments
1.771 + return ((x & 1) != 0);
1.772 + }
1.773 + static byte fromBoolean(boolean x) {
1.774 + // see javadoc for MethodHandles.explicitCastArguments
1.775 + return (x ? (byte)1 : (byte)0);
1.776 + }
1.777 +
1.778 + private static final EnumMap<Wrapper, MethodHandle>[]
1.779 + CONVERT_PRIMITIVE_FUNCTIONS = newWrapperCaches(Wrapper.values().length);
1.780 +
1.781 + public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
1.782 + EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
1.783 + MethodHandle mh = cache.get(wdst);
1.784 + if (mh != null) {
1.785 + return mh;
1.786 + }
1.787 + // slow path
1.788 + Class<?> src = wsrc.primitiveType();
1.789 + Class<?> dst = wdst.primitiveType();
1.790 + MethodType type = src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
1.791 + if (wsrc == wdst) {
1.792 + mh = identity(src);
1.793 + } else if (wsrc == Wrapper.VOID) {
1.794 + mh = zeroConstantFunction(wdst);
1.795 + } else if (wdst == Wrapper.VOID) {
1.796 + mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles.
1.797 + } else if (wsrc == Wrapper.OBJECT) {
1.798 + mh = unboxCast(dst);
1.799 + } else if (wdst == Wrapper.OBJECT) {
1.800 + mh = box(src);
1.801 + } else {
1.802 + assert(src.isPrimitive() && dst.isPrimitive());
1.803 + try {
1.804 + mh = IMPL_LOOKUP.findStatic(THIS_CLASS, src.getSimpleName()+"To"+capitalize(dst.getSimpleName()), type);
1.805 + } catch (ReflectiveOperationException ex) {
1.806 + mh = null;
1.807 + }
1.808 + }
1.809 + if (mh != null) {
1.810 + assert(mh.type() == type) : mh;
1.811 + cache.put(wdst, mh);
1.812 + return mh;
1.813 + }
1.814 +
1.815 + throw new IllegalArgumentException("cannot find primitive conversion function for " +
1.816 + src.getSimpleName()+" -> "+dst.getSimpleName());
1.817 + }
1.818 +
1.819 + public static MethodHandle convertPrimitive(Class<?> src, Class<?> dst) {
1.820 + return convertPrimitive(Wrapper.forPrimitiveType(src), Wrapper.forPrimitiveType(dst));
1.821 + }
1.822 +
1.823 + private static String capitalize(String x) {
1.824 + return Character.toUpperCase(x.charAt(0))+x.substring(1);
1.825 + }
1.826 +
1.827 + /// Collection of multiple arguments.
1.828 +
1.829 + public static Object convertArrayElements(Class<?> arrayType, Object array) {
1.830 + Class<?> src = array.getClass().getComponentType();
1.831 + Class<?> dst = arrayType.getComponentType();
1.832 + if (src == null || dst == null) throw new IllegalArgumentException("not array type");
1.833 + Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
1.834 + Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
1.835 + int length;
1.836 + if (sw == null) {
1.837 + Object[] a = (Object[]) array;
1.838 + length = a.length;
1.839 + if (dw == null)
1.840 + return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
1.841 + Object res = dw.makeArray(length);
1.842 + dw.copyArrayUnboxing(a, 0, res, 0, length);
1.843 + return res;
1.844 + }
1.845 + length = java.lang.reflect.Array.getLength(array);
1.846 + Object[] res;
1.847 + if (dw == null) {
1.848 + res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
1.849 + } else {
1.850 + res = new Object[length];
1.851 + }
1.852 + sw.copyArrayBoxing(array, 0, res, 0, length);
1.853 + if (dw == null) return res;
1.854 + Object a = dw.makeArray(length);
1.855 + dw.copyArrayUnboxing(res, 0, a, 0, length);
1.856 + return a;
1.857 + }
1.858 +
1.859 + private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
1.860 + MethodType type = MethodType.genericMethodType(nargs)
1.861 + .changeReturnType(rtype)
1.862 + .insertParameterTypes(0, ptypes);
1.863 + try {
1.864 + return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
1.865 + } catch (ReflectiveOperationException ex) {
1.866 + return null;
1.867 + }
1.868 + }
1.869 +
1.870 + private static final Object[] NO_ARGS_ARRAY = {};
1.871 + private static Object[] makeArray(Object... args) { return args; }
1.872 + private static Object[] array() { return NO_ARGS_ARRAY; }
1.873 + private static Object[] array(Object a0)
1.874 + { return makeArray(a0); }
1.875 + private static Object[] array(Object a0, Object a1)
1.876 + { return makeArray(a0, a1); }
1.877 + private static Object[] array(Object a0, Object a1, Object a2)
1.878 + { return makeArray(a0, a1, a2); }
1.879 + private static Object[] array(Object a0, Object a1, Object a2, Object a3)
1.880 + { return makeArray(a0, a1, a2, a3); }
1.881 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1.882 + Object a4)
1.883 + { return makeArray(a0, a1, a2, a3, a4); }
1.884 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1.885 + Object a4, Object a5)
1.886 + { return makeArray(a0, a1, a2, a3, a4, a5); }
1.887 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1.888 + Object a4, Object a5, Object a6)
1.889 + { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
1.890 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1.891 + Object a4, Object a5, Object a6, Object a7)
1.892 + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
1.893 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1.894 + Object a4, Object a5, Object a6, Object a7,
1.895 + Object a8)
1.896 + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1.897 + private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1.898 + Object a4, Object a5, Object a6, Object a7,
1.899 + Object a8, Object a9)
1.900 + { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1.901 + private static MethodHandle[] makeArrays() {
1.902 + ArrayList<MethodHandle> mhs = new ArrayList<>();
1.903 + for (;;) {
1.904 + MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
1.905 + if (mh == null) break;
1.906 + mhs.add(mh);
1.907 + }
1.908 + assert(mhs.size() == 11); // current number of methods
1.909 + return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
1.910 + }
1.911 + private static final MethodHandle[] ARRAYS = makeArrays();
1.912 +
1.913 + // filling versions of the above:
1.914 + // using Integer len instead of int len and no varargs to avoid bootstrapping problems
1.915 + private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
1.916 + Object[] a = new Object[len];
1.917 + fillWithArguments(a, 0, args);
1.918 + return a;
1.919 + }
1.920 + private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
1.921 + Object[] a = Arrays.copyOf(example, len);
1.922 + fillWithArguments(a, 0, args);
1.923 + return a;
1.924 + }
1.925 + private static void fillWithArguments(Object[] a, int pos, Object... args) {
1.926 + System.arraycopy(args, 0, a, pos, args.length);
1.927 + }
1.928 + // using Integer pos instead of int pos to avoid bootstrapping problems
1.929 + private static Object[] fillArray(Integer pos, Object[] a, Object a0)
1.930 + { fillWithArguments(a, pos, a0); return a; }
1.931 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
1.932 + { fillWithArguments(a, pos, a0, a1); return a; }
1.933 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
1.934 + { fillWithArguments(a, pos, a0, a1, a2); return a; }
1.935 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
1.936 + { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
1.937 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1.938 + Object a4)
1.939 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
1.940 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1.941 + Object a4, Object a5)
1.942 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
1.943 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1.944 + Object a4, Object a5, Object a6)
1.945 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
1.946 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1.947 + Object a4, Object a5, Object a6, Object a7)
1.948 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
1.949 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1.950 + Object a4, Object a5, Object a6, Object a7,
1.951 + Object a8)
1.952 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
1.953 + private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1.954 + Object a4, Object a5, Object a6, Object a7,
1.955 + Object a8, Object a9)
1.956 + { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
1.957 + private static MethodHandle[] makeFillArrays() {
1.958 + ArrayList<MethodHandle> mhs = new ArrayList<>();
1.959 + mhs.add(null); // there is no empty fill; at least a0 is required
1.960 + for (;;) {
1.961 + MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
1.962 + if (mh == null) break;
1.963 + mhs.add(mh);
1.964 + }
1.965 + assert(mhs.size() == 11); // current number of methods
1.966 + return mhs.toArray(new MethodHandle[0]);
1.967 + }
1.968 + private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
1.969 +
1.970 + private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
1.971 + return Arrays.copyOf(a, a.length, arrayType);
1.972 + }
1.973 + private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
1.974 + Object a = w.makeArray(boxes.length);
1.975 + w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
1.976 + return a;
1.977 + }
1.978 +
1.979 + /** Return a method handle that takes the indicated number of Object
1.980 + * arguments and returns an Object array of them, as if for varargs.
1.981 + */
1.982 + public static MethodHandle varargsArray(int nargs) {
1.983 + MethodHandle mh = ARRAYS[nargs];
1.984 + if (mh != null) return mh;
1.985 + mh = findCollector("array", nargs, Object[].class);
1.986 + if (mh != null) return ARRAYS[nargs] = mh;
1.987 + mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
1.988 + assert(assertCorrectArity(mh, nargs));
1.989 + return ARRAYS[nargs] = mh;
1.990 + }
1.991 +
1.992 + private static boolean assertCorrectArity(MethodHandle mh, int arity) {
1.993 + assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
1.994 + return true;
1.995 + }
1.996 +
1.997 + private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
1.998 + // Build up the result mh as a sequence of fills like this:
1.999 + // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
1.1000 + // The various fill(_,10*I,___*[J]) are reusable.
1.1001 + int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately
1.1002 + int rightLen = nargs - leftLen;
1.1003 + MethodHandle leftCollector = newArray.bindTo(nargs);
1.1004 + leftCollector = leftCollector.asCollector(Object[].class, leftLen);
1.1005 + MethodHandle mh = finisher;
1.1006 + if (rightLen > 0) {
1.1007 + MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
1.1008 + if (mh == ARRAY_IDENTITY)
1.1009 + mh = rightFiller;
1.1010 + else
1.1011 + mh = MethodHandles.collectArguments(mh, 0, rightFiller);
1.1012 + }
1.1013 + if (mh == ARRAY_IDENTITY)
1.1014 + mh = leftCollector;
1.1015 + else
1.1016 + mh = MethodHandles.collectArguments(mh, 0, leftCollector);
1.1017 + return mh;
1.1018 + }
1.1019 +
1.1020 + private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
1.1021 + private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
1.1022 + /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
1.1023 + * fills a[L]..a[N-1] with corresponding arguments,
1.1024 + * and then returns a. The value L is a global constant (LEFT_ARGS).
1.1025 + */
1.1026 + private static MethodHandle fillToRight(int nargs) {
1.1027 + MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
1.1028 + if (filler != null) return filler;
1.1029 + filler = buildFiller(nargs);
1.1030 + assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
1.1031 + return FILL_ARRAY_TO_RIGHT[nargs] = filler;
1.1032 + }
1.1033 + private static MethodHandle buildFiller(int nargs) {
1.1034 + if (nargs <= LEFT_ARGS)
1.1035 + return ARRAY_IDENTITY; // no args to fill; return the array unchanged
1.1036 + // we need room for both mh and a in mh.invoke(a, arg*[nargs])
1.1037 + final int CHUNK = LEFT_ARGS;
1.1038 + int rightLen = nargs % CHUNK;
1.1039 + int midLen = nargs - rightLen;
1.1040 + if (rightLen == 0) {
1.1041 + midLen = nargs - (rightLen = CHUNK);
1.1042 + if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
1.1043 + // build some precursors from left to right
1.1044 + for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
1.1045 + if (j > LEFT_ARGS) fillToRight(j);
1.1046 + }
1.1047 + }
1.1048 + if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
1.1049 + assert(rightLen > 0);
1.1050 + MethodHandle midFill = fillToRight(midLen); // recursive fill
1.1051 + MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
1.1052 + assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
1.1053 + assert(rightFill.type().parameterCount() == 1 + rightLen);
1.1054 +
1.1055 + // Combine the two fills:
1.1056 + // right(mid(a, x10..x19), x20..x23)
1.1057 + // The final product will look like this:
1.1058 + // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
1.1059 + if (midLen == LEFT_ARGS)
1.1060 + return rightFill;
1.1061 + else
1.1062 + return MethodHandles.collectArguments(rightFill, 0, midFill);
1.1063 + }
1.1064 +
1.1065 + // Type-polymorphic version of varargs maker.
1.1066 + private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
1.1067 + = new ClassValue<MethodHandle[]>() {
1.1068 + @Override
1.1069 + protected MethodHandle[] computeValue(Class<?> type) {
1.1070 + return new MethodHandle[256];
1.1071 + }
1.1072 + };
1.1073 +
1.1074 + static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM
1.1075 +
1.1076 + /** Return a method handle that takes the indicated number of
1.1077 + * typed arguments and returns an array of them.
1.1078 + * The type argument is the array type.
1.1079 + */
1.1080 + public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
1.1081 + Class<?> elemType = arrayType.getComponentType();
1.1082 + if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType);
1.1083 + // FIXME: Need more special casing and caching here.
1.1084 + if (nargs >= MAX_JVM_ARITY/2 - 1) {
1.1085 + int slots = nargs;
1.1086 + final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
1.1087 + if (arrayType == double[].class || arrayType == long[].class)
1.1088 + slots *= 2;
1.1089 + if (slots > MAX_ARRAY_SLOTS)
1.1090 + throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
1.1091 + }
1.1092 + if (elemType == Object.class)
1.1093 + return varargsArray(nargs);
1.1094 + // other cases: primitive arrays, subtypes of Object[]
1.1095 + MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
1.1096 + MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
1.1097 + if (mh != null) return mh;
1.1098 + if (elemType.isPrimitive()) {
1.1099 + MethodHandle builder = FILL_NEW_ARRAY;
1.1100 + MethodHandle producer = buildArrayProducer(arrayType);
1.1101 + mh = buildVarargsArray(builder, producer, nargs);
1.1102 + } else {
1.1103 + @SuppressWarnings("unchecked")
1.1104 + Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
1.1105 + Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
1.1106 + MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
1.1107 + MethodHandle producer = ARRAY_IDENTITY;
1.1108 + mh = buildVarargsArray(builder, producer, nargs);
1.1109 + }
1.1110 + mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
1.1111 + assert(assertCorrectArity(mh, nargs));
1.1112 + if (nargs < cache.length)
1.1113 + cache[nargs] = mh;
1.1114 + return mh;
1.1115 + }
1.1116 +
1.1117 + private static MethodHandle buildArrayProducer(Class<?> arrayType) {
1.1118 + Class<?> elemType = arrayType.getComponentType();
1.1119 + if (elemType.isPrimitive())
1.1120 + return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
1.1121 + else
1.1122 + return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
1.1123 + }
1.1124 +
1.1125 + // List version of varargs maker.
1.1126 +
1.1127 + private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
1.1128 + private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
1.1129 + private static List<Object> list() { return NO_ARGS_LIST; }
1.1130 + private static List<Object> list(Object a0)
1.1131 + { return makeList(a0); }
1.1132 + private static List<Object> list(Object a0, Object a1)
1.1133 + { return makeList(a0, a1); }
1.1134 + private static List<Object> list(Object a0, Object a1, Object a2)
1.1135 + { return makeList(a0, a1, a2); }
1.1136 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
1.1137 + { return makeList(a0, a1, a2, a3); }
1.1138 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1.1139 + Object a4)
1.1140 + { return makeList(a0, a1, a2, a3, a4); }
1.1141 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1.1142 + Object a4, Object a5)
1.1143 + { return makeList(a0, a1, a2, a3, a4, a5); }
1.1144 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1.1145 + Object a4, Object a5, Object a6)
1.1146 + { return makeList(a0, a1, a2, a3, a4, a5, a6); }
1.1147 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1.1148 + Object a4, Object a5, Object a6, Object a7)
1.1149 + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
1.1150 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1.1151 + Object a4, Object a5, Object a6, Object a7,
1.1152 + Object a8)
1.1153 + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1.1154 + private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
1.1155 + Object a4, Object a5, Object a6, Object a7,
1.1156 + Object a8, Object a9)
1.1157 + { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1.1158 + private static MethodHandle[] makeLists() {
1.1159 + ArrayList<MethodHandle> mhs = new ArrayList<>();
1.1160 + for (;;) {
1.1161 + MethodHandle mh = findCollector("list", mhs.size(), List.class);
1.1162 + if (mh == null) break;
1.1163 + mhs.add(mh);
1.1164 + }
1.1165 + assert(mhs.size() == 11); // current number of methods
1.1166 + return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
1.1167 + }
1.1168 + private static final MethodHandle[] LISTS = makeLists();
1.1169 +
1.1170 + /** Return a method handle that takes the indicated number of Object
1.1171 + * arguments and returns a List.
1.1172 + */
1.1173 + public static MethodHandle varargsList(int nargs) {
1.1174 + MethodHandle mh = LISTS[nargs];
1.1175 + if (mh != null) return mh;
1.1176 + mh = findCollector("list", nargs, List.class);
1.1177 + if (mh != null) return LISTS[nargs] = mh;
1.1178 + return LISTS[nargs] = buildVarargsList(nargs);
1.1179 + }
1.1180 + private static MethodHandle buildVarargsList(int nargs) {
1.1181 + return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
1.1182 + }
1.1183 +
1.1184 + // handy shared exception makers (they simplify the common case code)
1.1185 + private static InternalError newInternalError(String message, Throwable cause) {
1.1186 + return new InternalError(message, cause);
1.1187 + }
1.1188 + private static InternalError newInternalError(Throwable cause) {
1.1189 + return new InternalError(cause);
1.1190 + }
1.1191 +}