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