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