8049555: Move varargsArray from sun.invoke.util package to java.lang.invoke
authorvlivanov
Wed, 10 Sep 2014 19:19:47 +0400
changeset 26466 3bbb6a284bd4
parent 26465 5ff735dd0d52
child 26467 d69abed3a07d
8049555: Move varargsArray from sun.invoke.util package to java.lang.invoke Reviewed-by: psandoz, iignatyev
jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java
jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java
jdk/test/java/lang/invoke/VarargsArrayTest.java
jdk/test/sun/invoke/util/ValueConversionsTest.java
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Wed Sep 10 19:19:47 2014 +0400
@@ -36,7 +36,6 @@
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandleNatives.Constants.*;
 import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
-import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyAccess;
 import sun.invoke.util.VerifyType;
 import sun.invoke.util.Wrapper;
@@ -904,7 +903,7 @@
         if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
             return false;
         // Assume varargsArray caches pointers.
-        if (fn != ValueConversions.varargsArray(rtype, size))
+        if (fn != MethodHandleImpl.varargsArray(rtype, size))
             return false;
         return true;
     }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandle.java	Wed Sep 10 19:19:47 2014 +0400
@@ -28,7 +28,6 @@
 
 import java.util.*;
 import java.lang.invoke.LambdaForm.BasicType;
-import sun.invoke.util.*;
 import sun.misc.Unsafe;
 
 import static java.lang.invoke.MethodHandleStatics.*;
@@ -988,7 +987,7 @@
         MethodHandle target = this;
         if (arrayType != type().parameterType(collectArgPos))
             target = convertArguments(type().changeParameterType(collectArgPos, arrayType));
-        MethodHandle collector = ValueConversions.varargsArray(arrayType, arrayLength);
+        MethodHandle collector = MethodHandleImpl.varargsArray(arrayType, arrayLength);
         return MethodHandles.collectArguments(target, collectArgPos, collector);
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Sep 10 19:19:47 2014 +0400
@@ -27,8 +27,11 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
+import java.util.Collections;
+import java.util.List;
+
 import sun.invoke.empty.Empty;
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.VerifyType;
@@ -44,6 +47,20 @@
  * @author jrose
  */
 /*non-public*/ abstract class MethodHandleImpl {
+    // Do not adjust this except for special platforms:
+    private static final int MAX_ARITY;
+    static {
+        final Object[] values = { 255 };
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                values[0] = Integer.getInteger(MethodHandleImpl.class.getName()+".MAX_ARITY", 255);
+                return null;
+            }
+        });
+        MAX_ARITY = (Integer) values[0];
+    }
+
     /// Factory methods to create method handles:
 
     static void initStatics() {
@@ -516,6 +533,11 @@
         static final NamedFunction NF_throwException;
 
         static final MethodHandle MH_castReference;
+        static final MethodHandle MH_copyAsPrimitiveArray;
+        static final MethodHandle MH_copyAsReferenceArray;
+        static final MethodHandle MH_fillNewTypedArray;
+        static final MethodHandle MH_fillNewArray;
+        static final MethodHandle MH_arrayIdentity;
 
         static {
             try {
@@ -531,8 +553,18 @@
                 NF_selectAlternative.resolve();
                 NF_throwException.resolve();
 
-                MethodType mt = MethodType.methodType(Object.class, Class.class, Object.class);
-                MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", mt);
+                MH_castReference        = IMPL_LOOKUP.findStatic(MHI, "castReference",
+                                            MethodType.methodType(Object.class, Class.class, Object.class));
+                MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
+                                            MethodType.methodType(Object.class, Wrapper.class, Object[].class));
+                MH_copyAsReferenceArray = IMPL_LOOKUP.findStatic(MHI, "copyAsReferenceArray",
+                                            MethodType.methodType(Object[].class, Class.class, Object[].class));
+                MH_arrayIdentity        = IMPL_LOOKUP.findStatic(MHI, "identity",
+                                            MethodType.methodType(Object[].class, Object[].class));
+                MH_fillNewArray         = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
+                                            MethodType.methodType(Object[].class, Integer.class, Object[].class));
+                MH_fillNewTypedArray    = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
+                                            MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
             } catch (ReflectiveOperationException ex) {
                 throw newInternalError(ex);
             }
@@ -713,8 +745,7 @@
         // Prepare auxiliary method handles used during LambdaForm interpretation.
         // Box arguments and wrap them into Object[]: ValueConversions.array().
         MethodType varargsType = type.changeReturnType(Object[].class);
-        MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount())
-                                                   .asType(varargsType);
+        MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType);
         // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore().
         MethodHandle unboxResult;
         if (type.returnType().isPrimitive()) {
@@ -999,4 +1030,276 @@
         return new WrappedMember(target, target.type(), member, null);
     }
 
+    /// Collection of multiple arguments.
+
+    private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
+        MethodType type = MethodType.genericMethodType(nargs)
+                .changeReturnType(rtype)
+                .insertParameterTypes(0, ptypes);
+        try {
+            return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, name, type);
+        } catch (ReflectiveOperationException ex) {
+            return null;
+        }
+    }
+
+    private static final Object[] NO_ARGS_ARRAY = {};
+    private static Object[] makeArray(Object... args) { return args; }
+    private static Object[] array() { return NO_ARGS_ARRAY; }
+    private static Object[] array(Object a0)
+                { return makeArray(a0); }
+    private static Object[] array(Object a0, Object a1)
+                { return makeArray(a0, a1); }
+    private static Object[] array(Object a0, Object a1, Object a2)
+                { return makeArray(a0, a1, a2); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3)
+                { return makeArray(a0, a1, a2, a3); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4)
+                { return makeArray(a0, a1, a2, a3, a4); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5)
+                { return makeArray(a0, a1, a2, a3, a4, a5); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
+    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8, Object a9)
+                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
+    private static MethodHandle[] makeArrays() {
+        ArrayList<MethodHandle> mhs = new ArrayList<>();
+        for (;;) {
+            MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
+            if (mh == null)  break;
+            mhs.add(mh);
+        }
+        assert(mhs.size() == 11);  // current number of methods
+        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
+    }
+    private static final MethodHandle[] ARRAYS = makeArrays();
+
+    // filling versions of the above:
+    // using Integer len instead of int len and no varargs to avoid bootstrapping problems
+    private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
+        Object[] a = new Object[len];
+        fillWithArguments(a, 0, args);
+        return a;
+    }
+    private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
+        Object[] a = Arrays.copyOf(example, len);
+        fillWithArguments(a, 0, args);
+        return a;
+    }
+    private static void fillWithArguments(Object[] a, int pos, Object... args) {
+        System.arraycopy(args, 0, a, pos, args.length);
+    }
+    // using Integer pos instead of int pos to avoid bootstrapping problems
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0)
+                { fillWithArguments(a, pos, a0); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
+                { fillWithArguments(a, pos, a0, a1); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
+                { fillWithArguments(a, pos, a0, a1, a2); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
+                { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
+    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
+                                  Object a4, Object a5, Object a6, Object a7,
+                                  Object a8, Object a9)
+                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
+    private static MethodHandle[] makeFillArrays() {
+        ArrayList<MethodHandle> mhs = new ArrayList<>();
+        mhs.add(null);  // there is no empty fill; at least a0 is required
+        for (;;) {
+            MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
+            if (mh == null)  break;
+            mhs.add(mh);
+        }
+        assert(mhs.size() == 11);  // current number of methods
+        return mhs.toArray(new MethodHandle[0]);
+    }
+    private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
+
+    private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
+        return Arrays.copyOf(a, a.length, arrayType);
+    }
+    private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
+        Object a = w.makeArray(boxes.length);
+        w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
+        return a;
+    }
+
+    /** Return a method handle that takes the indicated number of Object
+     *  arguments and returns an Object array of them, as if for varargs.
+     */
+    static MethodHandle varargsArray(int nargs) {
+        MethodHandle mh = ARRAYS[nargs];
+        if (mh != null)  return mh;
+        mh = findCollector("array", nargs, Object[].class);
+        if (mh != null)  return ARRAYS[nargs] = mh;
+        mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
+        assert(assertCorrectArity(mh, nargs));
+        return ARRAYS[nargs] = mh;
+    }
+
+    private static boolean assertCorrectArity(MethodHandle mh, int arity) {
+        assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
+        return true;
+    }
+
+    // Array identity function (used as Lazy.MH_arrayIdentity).
+    static <T> T[] identity(T[] x) {
+        return x;
+    }
+
+    private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
+        // Build up the result mh as a sequence of fills like this:
+        //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
+        // The various fill(_,10*I,___*[J]) are reusable.
+        int leftLen = Math.min(nargs, LEFT_ARGS);  // absorb some arguments immediately
+        int rightLen = nargs - leftLen;
+        MethodHandle leftCollector = newArray.bindTo(nargs);
+        leftCollector = leftCollector.asCollector(Object[].class, leftLen);
+        MethodHandle mh = finisher;
+        if (rightLen > 0) {
+            MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
+            if (mh == Lazy.MH_arrayIdentity)
+                mh = rightFiller;
+            else
+                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
+        }
+        if (mh == Lazy.MH_arrayIdentity)
+            mh = leftCollector;
+        else
+            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
+        return mh;
+    }
+
+    private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
+    private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
+    /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
+     *  fills a[L]..a[N-1] with corresponding arguments,
+     *  and then returns a.  The value L is a global constant (LEFT_ARGS).
+     */
+    private static MethodHandle fillToRight(int nargs) {
+        MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
+        if (filler != null)  return filler;
+        filler = buildFiller(nargs);
+        assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
+        return FILL_ARRAY_TO_RIGHT[nargs] = filler;
+    }
+    private static MethodHandle buildFiller(int nargs) {
+        if (nargs <= LEFT_ARGS)
+            return Lazy.MH_arrayIdentity;  // no args to fill; return the array unchanged
+        // we need room for both mh and a in mh.invoke(a, arg*[nargs])
+        final int CHUNK = LEFT_ARGS;
+        int rightLen = nargs % CHUNK;
+        int midLen = nargs - rightLen;
+        if (rightLen == 0) {
+            midLen = nargs - (rightLen = CHUNK);
+            if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
+                // build some precursors from left to right
+                for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
+                    if (j > LEFT_ARGS)  fillToRight(j);
+            }
+        }
+        if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
+        assert(rightLen > 0);
+        MethodHandle midFill = fillToRight(midLen);  // recursive fill
+        MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
+        assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
+        assert(rightFill.type().parameterCount() == 1 + rightLen);
+
+        // Combine the two fills:
+        //   right(mid(a, x10..x19), x20..x23)
+        // The final product will look like this:
+        //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
+        if (midLen == LEFT_ARGS)
+            return rightFill;
+        else
+            return MethodHandles.collectArguments(rightFill, 0, midFill);
+    }
+
+    // Type-polymorphic version of varargs maker.
+    private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
+        = new ClassValue<MethodHandle[]>() {
+            @Override
+            protected MethodHandle[] computeValue(Class<?> type) {
+                return new MethodHandle[256];
+            }
+    };
+
+    static final int MAX_JVM_ARITY = 255;  // limit imposed by the JVM
+
+    /** Return a method handle that takes the indicated number of
+     *  typed arguments and returns an array of them.
+     *  The type argument is the array type.
+     */
+    static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
+        Class<?> elemType = arrayType.getComponentType();
+        if (elemType == null)  throw new IllegalArgumentException("not an array: "+arrayType);
+        // FIXME: Need more special casing and caching here.
+        if (nargs >= MAX_JVM_ARITY/2 - 1) {
+            int slots = nargs;
+            final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1;  // 1 for receiver MH
+            if (arrayType == double[].class || arrayType == long[].class)
+                slots *= 2;
+            if (slots > MAX_ARRAY_SLOTS)
+                throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
+        }
+        if (elemType == Object.class)
+            return varargsArray(nargs);
+        // other cases:  primitive arrays, subtypes of Object[]
+        MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
+        MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
+        if (mh != null)  return mh;
+        if (elemType.isPrimitive()) {
+            MethodHandle builder = Lazy.MH_fillNewArray;
+            MethodHandle producer = buildArrayProducer(arrayType);
+            mh = buildVarargsArray(builder, producer, nargs);
+        } else {
+            @SuppressWarnings("unchecked")
+            Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
+            Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
+            MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
+            MethodHandle producer = Lazy.MH_arrayIdentity;
+            mh = buildVarargsArray(builder, producer, nargs);
+        }
+        mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
+        assert(assertCorrectArity(mh, nargs));
+        if (nargs < cache.length)
+            cache[nargs] = mh;
+        return mh;
+    }
+
+    private static MethodHandle buildArrayProducer(Class<?> arrayType) {
+        Class<?> elemType = arrayType.getComponentType();
+        if (elemType.isPrimitive())
+            return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
+        else
+            return Lazy.MH_copyAsReferenceArray.bindTo(arrayType);
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/src/java.base/share/classes/sun/invoke/util/ValueConversions.java	Wed Sep 10 19:19:47 2014 +0400
@@ -29,30 +29,10 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.EnumMap;
-import java.util.List;
 
 public class ValueConversions {
     private static final Class<?> THIS_CLASS = ValueConversions.class;
-    // Do not adjust this except for special platforms:
-    private static final int MAX_ARITY;
-    static {
-        final Object[] values = { 255 };
-        AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                @Override
-                public Void run() {
-                    values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
-                    return null;
-                }
-            });
-        MAX_ARITY = (Integer) values[0];
-    }
-
     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
 
     private static EnumMap<Wrapper, MethodHandle>[] newWrapperCaches(int n) {
@@ -443,12 +423,7 @@
         return x;
     }
 
-    private static ClassCastException newClassCastException(Class<?> t, Object obj) {
-        return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName());
-    }
-
-    private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY,
-            ARRAY_IDENTITY, FILL_NEW_TYPED_ARRAY, FILL_NEW_ARRAY;
+    private static final MethodHandle IDENTITY, CAST_REFERENCE, ZERO_OBJECT, IGNORE, EMPTY;
     static {
         try {
             MethodType idType = MethodType.genericMethodType(1);
@@ -459,33 +434,11 @@
             ZERO_OBJECT = IMPL_LOOKUP.findStatic(THIS_CLASS, "zeroObject", zeroObjectType);
             IGNORE = IMPL_LOOKUP.findStatic(THIS_CLASS, "ignore", ignoreType);
             EMPTY = IMPL_LOOKUP.findStatic(THIS_CLASS, "empty", ignoreType.dropParameterTypes(0, 1));
-            ARRAY_IDENTITY = IMPL_LOOKUP.findStatic(THIS_CLASS, "identity", MethodType.methodType(Object[].class, Object[].class));
-            FILL_NEW_ARRAY = IMPL_LOOKUP
-                    .findStatic(THIS_CLASS, "fillNewArray",
-                          MethodType.methodType(Object[].class, Integer.class, Object[].class));
-            FILL_NEW_TYPED_ARRAY = IMPL_LOOKUP
-                    .findStatic(THIS_CLASS, "fillNewTypedArray",
-                          MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
         } catch (NoSuchMethodException | IllegalAccessException ex) {
             throw newInternalError("uncaught exception", ex);
         }
     }
 
-    // Varargs methods need to be in a separately initialized class, to avoid bootstrapping problems.
-    static class LazyStatics {
-        private static final MethodHandle COPY_AS_REFERENCE_ARRAY, COPY_AS_PRIMITIVE_ARRAY, MAKE_LIST;
-        static {
-            try {
-                //MAKE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeArray", MethodType.methodType(Object[].class, Object[].class));
-                COPY_AS_REFERENCE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsReferenceArray", MethodType.methodType(Object[].class, Class.class, Object[].class));
-                COPY_AS_PRIMITIVE_ARRAY = IMPL_LOOKUP.findStatic(THIS_CLASS, "copyAsPrimitiveArray", MethodType.methodType(Object.class, Wrapper.class, Object[].class));
-                MAKE_LIST = IMPL_LOOKUP.findStatic(THIS_CLASS, "makeList", MethodType.methodType(List.class, Object[].class));
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError("uncaught exception", ex);
-            }
-        }
-    }
-
     private static final EnumMap<Wrapper, MethodHandle>[] WRAPPER_CASTS
             = newWrapperCaches(1);
 
@@ -808,363 +761,6 @@
         return Character.toUpperCase(x.charAt(0))+x.substring(1);
     }
 
-    /// Collection of multiple arguments.
-
-    public static Object convertArrayElements(Class<?> arrayType, Object array) {
-        Class<?> src = array.getClass().getComponentType();
-        Class<?> dst = arrayType.getComponentType();
-        if (src == null || dst == null)  throw new IllegalArgumentException("not array type");
-        Wrapper sw = (src.isPrimitive() ? Wrapper.forPrimitiveType(src) : null);
-        Wrapper dw = (dst.isPrimitive() ? Wrapper.forPrimitiveType(dst) : null);
-        int length;
-        if (sw == null) {
-            Object[] a = (Object[]) array;
-            length = a.length;
-            if (dw == null)
-                return Arrays.copyOf(a, length, arrayType.asSubclass(Object[].class));
-            Object res = dw.makeArray(length);
-            dw.copyArrayUnboxing(a, 0, res, 0, length);
-            return res;
-        }
-        length = java.lang.reflect.Array.getLength(array);
-        Object[] res;
-        if (dw == null) {
-            res = Arrays.copyOf(NO_ARGS_ARRAY, length, arrayType.asSubclass(Object[].class));
-        } else {
-            res = new Object[length];
-        }
-        sw.copyArrayBoxing(array, 0, res, 0, length);
-        if (dw == null)  return res;
-        Object a = dw.makeArray(length);
-        dw.copyArrayUnboxing(res, 0, a, 0, length);
-        return a;
-    }
-
-    private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) {
-        MethodType type = MethodType.genericMethodType(nargs)
-                .changeReturnType(rtype)
-                .insertParameterTypes(0, ptypes);
-        try {
-            return IMPL_LOOKUP.findStatic(THIS_CLASS, name, type);
-        } catch (ReflectiveOperationException ex) {
-            return null;
-        }
-    }
-
-    private static final Object[] NO_ARGS_ARRAY = {};
-    private static Object[] makeArray(Object... args) { return args; }
-    private static Object[] array() { return NO_ARGS_ARRAY; }
-    private static Object[] array(Object a0)
-                { return makeArray(a0); }
-    private static Object[] array(Object a0, Object a1)
-                { return makeArray(a0, a1); }
-    private static Object[] array(Object a0, Object a1, Object a2)
-                { return makeArray(a0, a1, a2); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3)
-                { return makeArray(a0, a1, a2, a3); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4)
-                { return makeArray(a0, a1, a2, a3, a4); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5)
-                { return makeArray(a0, a1, a2, a3, a4, a5); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
-    private static Object[] array(Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8, Object a9)
-                { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
-    private static MethodHandle[] makeArrays() {
-        ArrayList<MethodHandle> mhs = new ArrayList<>();
-        for (;;) {
-            MethodHandle mh = findCollector("array", mhs.size(), Object[].class);
-            if (mh == null)  break;
-            mhs.add(mh);
-        }
-        assert(mhs.size() == 11);  // current number of methods
-        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
-    }
-    private static final MethodHandle[] ARRAYS = makeArrays();
-
-    // filling versions of the above:
-    // using Integer len instead of int len and no varargs to avoid bootstrapping problems
-    private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
-        Object[] a = new Object[len];
-        fillWithArguments(a, 0, args);
-        return a;
-    }
-    private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
-        Object[] a = Arrays.copyOf(example, len);
-        fillWithArguments(a, 0, args);
-        return a;
-    }
-    private static void fillWithArguments(Object[] a, int pos, Object... args) {
-        System.arraycopy(args, 0, a, pos, args.length);
-    }
-    // using Integer pos instead of int pos to avoid bootstrapping problems
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0)
-                { fillWithArguments(a, pos, a0); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1)
-                { fillWithArguments(a, pos, a0, a1); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2)
-                { fillWithArguments(a, pos, a0, a1, a2); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3)
-                { fillWithArguments(a, pos, a0, a1, a2, a3); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
-    private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
-                                  Object a4, Object a5, Object a6, Object a7,
-                                  Object a8, Object a9)
-                { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
-    private static MethodHandle[] makeFillArrays() {
-        ArrayList<MethodHandle> mhs = new ArrayList<>();
-        mhs.add(null);  // there is no empty fill; at least a0 is required
-        for (;;) {
-            MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class);
-            if (mh == null)  break;
-            mhs.add(mh);
-        }
-        assert(mhs.size() == 11);  // current number of methods
-        return mhs.toArray(new MethodHandle[0]);
-    }
-    private static final MethodHandle[] FILL_ARRAYS = makeFillArrays();
-
-    private static Object[] copyAsReferenceArray(Class<? extends Object[]> arrayType, Object... a) {
-        return Arrays.copyOf(a, a.length, arrayType);
-    }
-    private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
-        Object a = w.makeArray(boxes.length);
-        w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
-        return a;
-    }
-
-    /** Return a method handle that takes the indicated number of Object
-     *  arguments and returns an Object array of them, as if for varargs.
-     */
-    public static MethodHandle varargsArray(int nargs) {
-        MethodHandle mh = ARRAYS[nargs];
-        if (mh != null)  return mh;
-        mh = findCollector("array", nargs, Object[].class);
-        if (mh != null)  return ARRAYS[nargs] = mh;
-        mh = buildVarargsArray(FILL_NEW_ARRAY, ARRAY_IDENTITY, nargs);
-        assert(assertCorrectArity(mh, nargs));
-        return ARRAYS[nargs] = mh;
-    }
-
-    private static boolean assertCorrectArity(MethodHandle mh, int arity) {
-        assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
-        return true;
-    }
-
-    private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
-        // Build up the result mh as a sequence of fills like this:
-        //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
-        // The various fill(_,10*I,___*[J]) are reusable.
-        int leftLen = Math.min(nargs, LEFT_ARGS);  // absorb some arguments immediately
-        int rightLen = nargs - leftLen;
-        MethodHandle leftCollector = newArray.bindTo(nargs);
-        leftCollector = leftCollector.asCollector(Object[].class, leftLen);
-        MethodHandle mh = finisher;
-        if (rightLen > 0) {
-            MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
-            if (mh == ARRAY_IDENTITY)
-                mh = rightFiller;
-            else
-                mh = MethodHandles.collectArguments(mh, 0, rightFiller);
-        }
-        if (mh == ARRAY_IDENTITY)
-            mh = leftCollector;
-        else
-            mh = MethodHandles.collectArguments(mh, 0, leftCollector);
-        return mh;
-    }
-
-    private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1);
-    private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
-    /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
-     *  fills a[L]..a[N-1] with corresponding arguments,
-     *  and then returns a.  The value L is a global constant (LEFT_ARGS).
-     */
-    private static MethodHandle fillToRight(int nargs) {
-        MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
-        if (filler != null)  return filler;
-        filler = buildFiller(nargs);
-        assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
-        return FILL_ARRAY_TO_RIGHT[nargs] = filler;
-    }
-    private static MethodHandle buildFiller(int nargs) {
-        if (nargs <= LEFT_ARGS)
-            return ARRAY_IDENTITY;  // no args to fill; return the array unchanged
-        // we need room for both mh and a in mh.invoke(a, arg*[nargs])
-        final int CHUNK = LEFT_ARGS;
-        int rightLen = nargs % CHUNK;
-        int midLen = nargs - rightLen;
-        if (rightLen == 0) {
-            midLen = nargs - (rightLen = CHUNK);
-            if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
-                // build some precursors from left to right
-                for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
-                    if (j > LEFT_ARGS)  fillToRight(j);
-            }
-        }
-        if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
-        assert(rightLen > 0);
-        MethodHandle midFill = fillToRight(midLen);  // recursive fill
-        MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
-        assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
-        assert(rightFill.type().parameterCount() == 1 + rightLen);
-
-        // Combine the two fills:
-        //   right(mid(a, x10..x19), x20..x23)
-        // The final product will look like this:
-        //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
-        if (midLen == LEFT_ARGS)
-            return rightFill;
-        else
-            return MethodHandles.collectArguments(rightFill, 0, midFill);
-    }
-
-    // Type-polymorphic version of varargs maker.
-    private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
-        = new ClassValue<MethodHandle[]>() {
-            @Override
-            protected MethodHandle[] computeValue(Class<?> type) {
-                return new MethodHandle[256];
-            }
-    };
-
-    static final int MAX_JVM_ARITY = 255;  // limit imposed by the JVM
-
-    /** Return a method handle that takes the indicated number of
-     *  typed arguments and returns an array of them.
-     *  The type argument is the array type.
-     */
-    public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
-        Class<?> elemType = arrayType.getComponentType();
-        if (elemType == null)  throw new IllegalArgumentException("not an array: "+arrayType);
-        // FIXME: Need more special casing and caching here.
-        if (nargs >= MAX_JVM_ARITY/2 - 1) {
-            int slots = nargs;
-            final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1;  // 1 for receiver MH
-            if (arrayType == double[].class || arrayType == long[].class)
-                slots *= 2;
-            if (slots > MAX_ARRAY_SLOTS)
-                throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
-        }
-        if (elemType == Object.class)
-            return varargsArray(nargs);
-        // other cases:  primitive arrays, subtypes of Object[]
-        MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
-        MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
-        if (mh != null)  return mh;
-        if (elemType.isPrimitive()) {
-            MethodHandle builder = FILL_NEW_ARRAY;
-            MethodHandle producer = buildArrayProducer(arrayType);
-            mh = buildVarargsArray(builder, producer, nargs);
-        } else {
-            @SuppressWarnings("unchecked")
-            Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
-            Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
-            MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
-            MethodHandle producer = ARRAY_IDENTITY;
-            mh = buildVarargsArray(builder, producer, nargs);
-        }
-        mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
-        assert(assertCorrectArity(mh, nargs));
-        if (nargs < cache.length)
-            cache[nargs] = mh;
-        return mh;
-    }
-
-    private static MethodHandle buildArrayProducer(Class<?> arrayType) {
-        Class<?> elemType = arrayType.getComponentType();
-        if (elemType.isPrimitive())
-            return LazyStatics.COPY_AS_PRIMITIVE_ARRAY.bindTo(Wrapper.forPrimitiveType(elemType));
-        else
-            return LazyStatics.COPY_AS_REFERENCE_ARRAY.bindTo(arrayType);
-    }
-
-    // List version of varargs maker.
-
-    private static final List<Object> NO_ARGS_LIST = Arrays.asList(NO_ARGS_ARRAY);
-    private static List<Object> makeList(Object... args) { return Arrays.asList(args); }
-    private static List<Object> list() { return NO_ARGS_LIST; }
-    private static List<Object> list(Object a0)
-                { return makeList(a0); }
-    private static List<Object> list(Object a0, Object a1)
-                { return makeList(a0, a1); }
-    private static List<Object> list(Object a0, Object a1, Object a2)
-                { return makeList(a0, a1, a2); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3)
-                { return makeList(a0, a1, a2, a3); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4)
-                { return makeList(a0, a1, a2, a3, a4); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5)
-                { return makeList(a0, a1, a2, a3, a4, a5); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6, Object a7)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6, Object a7,
-                                     Object a8)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
-    private static List<Object> list(Object a0, Object a1, Object a2, Object a3,
-                                     Object a4, Object a5, Object a6, Object a7,
-                                     Object a8, Object a9)
-                { return makeList(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
-    private static MethodHandle[] makeLists() {
-        ArrayList<MethodHandle> mhs = new ArrayList<>();
-        for (;;) {
-            MethodHandle mh = findCollector("list", mhs.size(), List.class);
-            if (mh == null)  break;
-            mhs.add(mh);
-        }
-        assert(mhs.size() == 11);  // current number of methods
-        return mhs.toArray(new MethodHandle[MAX_ARITY+1]);
-    }
-    private static final MethodHandle[] LISTS = makeLists();
-
-    /** Return a method handle that takes the indicated number of Object
-     *  arguments and returns a List.
-     */
-    public static MethodHandle varargsList(int nargs) {
-        MethodHandle mh = LISTS[nargs];
-        if (mh != null)  return mh;
-        mh = findCollector("list", nargs, List.class);
-        if (mh != null)  return LISTS[nargs] = mh;
-        return LISTS[nargs] = buildVarargsList(nargs);
-    }
-    private static MethodHandle buildVarargsList(int nargs) {
-        return MethodHandles.filterReturnValue(varargsArray(nargs), LazyStatics.MAKE_LIST);
-    }
-
     // handy shared exception makers (they simplify the common case code)
     private static InternalError newInternalError(String message, Throwable cause) {
         return new InternalError(message, cause);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/VarargsArrayTest.java	Wed Sep 10 19:19:47 2014 +0400
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import sun.invoke.util.Wrapper;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/* @test
+ * @summary unit tests for varargs array methods: MethodHandleInfo.varargsArray(int),
+ *          MethodHandleInfo.varargsArray(Class,int) & MethodHandleInfo.varargsList(int)
+ *
+ * @run main/bootclasspath java.lang.invoke.VarargsArrayTest
+ * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250
+ *                         java.lang.invoke.VarargsArrayTest
+ */
+
+/* This might take a while and burn lots of metadata:
+ * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true java.lang.invoke.VarargsArrayTest
+ */
+public class VarargsArrayTest {
+    private static final Class<?> CLASS = VarargsArrayTest.class;
+    private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40);
+    private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0);
+    private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE");
+
+    public static void main(String[] args) throws Throwable {
+        testVarargsArray();
+        testVarargsReferenceArray();
+        testVarargsPrimitiveArray();
+    }
+
+    public static void testVarargsArray() throws Throwable {
+        final int MIN = START_ARITY;
+        final int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
+        for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) {
+            MethodHandle target = MethodHandleImpl.varargsArray(nargs);
+            Object[] args = new Object[nargs];
+            for (int i = 0; i < nargs; i++)
+                args[i] = "#"+i;
+            Object res = target.invokeWithArguments(args);
+            assertArrayEquals(args, (Object[])res);
+        }
+    }
+
+    public static void testVarargsReferenceArray() throws Throwable {
+        testTypedVarargsArray(Object[].class);
+        testTypedVarargsArray(String[].class);
+        testTypedVarargsArray(Number[].class);
+    }
+
+    public static void testVarargsPrimitiveArray() throws Throwable {
+        testTypedVarargsArray(int[].class);
+        testTypedVarargsArray(long[].class);
+        testTypedVarargsArray(byte[].class);
+        testTypedVarargsArray(boolean[].class);
+        testTypedVarargsArray(short[].class);
+        testTypedVarargsArray(char[].class);
+        testTypedVarargsArray(float[].class);
+        testTypedVarargsArray(double[].class);
+    }
+
+    private static int nextArgCount(int nargs, int density, int MAX) {
+        if (EXHAUSTIVE)  return nargs + 1;
+        if (nargs >= MAX)  return Integer.MAX_VALUE;
+        int BOT = 20, TOP = MAX-5;
+        if (density < 10) { BOT = 10; MAX = TOP-2; }
+        if (nargs <= BOT || nargs >= TOP) {
+            ++nargs;
+        } else {
+            int bump = Math.max(1, 100 / density);
+            nargs += bump;
+            if (nargs > TOP)  nargs = TOP;
+        }
+        return nargs;
+    }
+
+    private static void testTypedVarargsArray(Class<?> arrayType) throws Throwable {
+        Class<?> elemType = arrayType.getComponentType();
+        int MIN = START_ARITY;
+        int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
+        int density = 3;
+        if (elemType == int.class || elemType == long.class)  density = 7;
+        if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; }
+        for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) {
+            Object[] args = makeTestArray(elemType, nargs);
+            MethodHandle varargsArray = MethodHandleImpl.varargsArray(arrayType, nargs);
+            MethodType vaType = varargsArray.type();
+            assertEquals(arrayType, vaType.returnType());
+            if (nargs != 0) {
+                assertEquals(elemType, vaType.parameterType(0));
+                assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1));
+            }
+            assertEquals(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)),
+                         vaType);
+            Object res = varargsArray.invokeWithArguments(args);
+            assertEquals(res.getClass(), arrayType);
+            String resString = toArrayString(res);
+            assertEquals(Arrays.toString(args), resString);
+
+            MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs);
+            MethodType stype = spreader.type();
+            assert(stype == MethodType.methodType(arrayType, arrayType));
+            if (nargs <= 5) {
+                // invoke target as a spreader also:
+                @SuppressWarnings("cast")
+                Object res2 = spreader.invokeWithArguments((Object)res);
+                String res2String = toArrayString(res2);
+                assertEquals(Arrays.toString(args), res2String);
+                // invoke the spreader on a generic Object[] array; check for error
+                try {
+                    Object res3 = spreader.invokeWithArguments((Object)args);
+                    String res3String = toArrayString(res3);
+                    assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class));
+                    assertEquals(Arrays.toString(args), res3String);
+                } catch (ClassCastException ex) {
+                    assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class));
+                }
+            }
+            if (nargs == 0) {
+                // invoke spreader on null arglist
+                Object res3 = spreader.invokeWithArguments((Object)null);
+                String res3String = toArrayString(res3);
+                assertEquals(Arrays.toString(args), res3String);
+            }
+        }
+    }
+
+    private static Object[] makeTestArray(Class<?> elemType, int len) {
+        Wrapper elem = null;
+        if (elemType.isPrimitive())
+            elem = Wrapper.forPrimitiveType(elemType);
+        else if (Wrapper.isWrapperType(elemType))
+            elem = Wrapper.forWrapperType(elemType);
+        Object[] args = new Object[len];
+        for (int i = 0; i < len; i++) {
+            Object arg = i * 100;
+            if (elem == null) {
+                if (elemType == String.class)
+                    arg = "#"+arg;
+                arg = elemType.cast(arg);  // just to make sure
+            } else {
+                switch (elem) {
+                    case BOOLEAN: arg = (i % 3 == 0);           break;
+                    case CHAR:    arg = 'a' + i;                break;
+                    case LONG:    arg = (long)i * 1000_000_000; break;
+                    case FLOAT:   arg = (float)i / 100;         break;
+                    case DOUBLE:  arg = (double)i / 1000_000;   break;
+                }
+                arg = elem.cast(arg, elemType);
+            }
+            args[i] = arg;
+        }
+        return args;
+    }
+
+    private static String toArrayString(Object a) {
+        if (a == null)  return "null";
+        Class<?> elemType = a.getClass().getComponentType();
+        if (elemType == null)  return a.toString();
+        if (elemType.isPrimitive()) {
+            switch (Wrapper.forPrimitiveType(elemType)) {
+                case INT:      return Arrays.toString((int[])a);
+                case BYTE:     return Arrays.toString((byte[])a);
+                case BOOLEAN:  return Arrays.toString((boolean[])a);
+                case SHORT:    return Arrays.toString((short[])a);
+                case CHAR:     return Arrays.toString((char[])a);
+                case FLOAT:    return Arrays.toString((float[])a);
+                case LONG:     return Arrays.toString((long[])a);
+                case DOUBLE:   return Arrays.toString((double[])a);
+            }
+        }
+        return Arrays.toString((Object[])a);
+    }
+
+    public static void assertArrayEquals(Object[] arr1, Object[] arr2) {
+        if (arr1 == null && arr2 == null)  return;
+        if (arr1 != null && arr2 != null && arr1.length == arr2.length) {
+            for (int i = 0; i < arr1.length; i++) {
+                assertEquals(arr1[i], arr2[i]);
+            }
+            return;
+        }
+        throw new AssertionError(Arrays.deepToString(arr1) + " != " + Arrays.deepToString(arr2));
+    }
+
+    public static void assertEquals(Object o1, Object o2) {
+        if (o1 == null && o2 == null)    return;
+        if (o1 != null && o1.equals(o2)) return;
+        throw new AssertionError(o1 + " != " + o2);
+    }
+
+    public static void assertTrue(String msg, boolean b) {
+        if (!b) {
+            throw new AssertionError(msg);
+        }
+    }
+
+    public static void assertFalse(String msg, boolean b) {
+        assertTrue(msg, !b);
+    }
+}
--- a/jdk/test/sun/invoke/util/ValueConversionsTest.java	Wed Sep 10 19:19:47 2014 +0400
+++ b/jdk/test/sun/invoke/util/ValueConversionsTest.java	Wed Sep 10 19:19:47 2014 +0400
@@ -25,11 +25,11 @@
 
 import sun.invoke.util.ValueConversions;
 import sun.invoke.util.Wrapper;
+
 import java.lang.invoke.MethodType;
 import java.lang.invoke.MethodHandle;
 import java.io.Serializable;
 import java.util.Arrays;
-import java.util.Collections;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -37,24 +37,13 @@
  * @summary unit tests for value-type conversion utilities
  * @compile -XDignore.symbol.file ValueConversionsTest.java
  * @run junit/othervm test.sun.invoke.util.ValueConversionsTest
- * @run junit/othervm
- *          -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.START_ARITY=250
- *              test.sun.invoke.util.ValueConversionsTest
  */
 
-// This might take a while and burn lots of metadata:
-// @run junit/othervm -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.EXHAUSTIVE=true test.sun.invoke.util.ValueConversionsTest
-
 /**
  *
  * @author jrose
  */
 public class ValueConversionsTest {
-    private static final Class<?> CLASS = ValueConversionsTest.class;
-    private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40);
-    private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0);
-    private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE");
-
     @Test
     public void testUnbox() throws Throwable {
         testUnbox(false);
@@ -66,9 +55,7 @@
     }
 
     private void testUnbox(boolean doCast) throws Throwable {
-        //System.out.println("unbox");
         for (Wrapper dst : Wrapper.values()) {
-            //System.out.println(dst);
             for (Wrapper src : Wrapper.values()) {
                 testUnbox(doCast, dst, src);
             }
@@ -123,10 +110,8 @@
 
     @Test
     public void testBox() throws Throwable {
-        //System.out.println("box");
         for (Wrapper w : Wrapper.values()) {
             if (w == Wrapper.VOID)  continue;  // skip this; no unboxed form
-            //System.out.println(w);
             for (int n = -5; n < 10; n++) {
                 Object box = w.wrap(n);
                 MethodHandle boxer = ValueConversions.box(w.primitiveType());
@@ -151,7 +136,6 @@
 
     @Test
     public void testCast() throws Throwable {
-        //System.out.println("cast");
         Class<?>[] types = { Object.class, Serializable.class, String.class, Number.class, Integer.class };
         Object[] objects = { new Object(), Boolean.FALSE,      "hello",      (Long)12L,    (Integer)6    };
         for (Class<?> dst : types) {
@@ -160,7 +144,6 @@
             for (Object obj : objects) {
                 Class<?> src = obj.getClass();
                 boolean canCast = dst.isAssignableFrom(src);
-                //System.out.println("obj="+obj+" <: dst="+dst+(canCast ? " (OK)" : " (will fail)"));
                 try {
                     Object result = caster.invokeExact(obj);
                     if (canCast)
@@ -177,24 +160,19 @@
 
     @Test
     public void testIdentity() throws Throwable {
-        //System.out.println("identity");
         MethodHandle id = ValueConversions.identity();
         Object expResult = "foo";
         Object result = id.invokeExact(expResult);
-        // compiler bug:  ValueConversions.identity().invokeExact("bar");
         assertEquals(expResult, result);
     }
 
     @Test
     public void testConvert() throws Throwable {
-        //System.out.println("convert");
         for (long tval = 0, ctr = 0;;) {
             if (++ctr > 99999)  throw new AssertionError("too many test values");
-            // next test value:
-            //System.out.println(Long.toHexString(tval)); // prints 3776 test patterns
+            // prints 3776 test patterns (3776 = 8*59*8)
             tval = nextTestValue(tval);
             if (tval == 0) {
-                //System.out.println("test value count = "+ctr);  // 3776 = 8*59*8
                 break;  // repeat
             }
         }
@@ -205,7 +183,6 @@
         }
     }
     static void testConvert(Wrapper src, Wrapper dst, long tval) throws Throwable {
-        //System.out.println(src+" => "+dst);
         boolean testSingleCase = (tval != 0);
         final long tvalInit = tval;
         MethodHandle conv = ValueConversions.convertPrimitive(src, dst);
@@ -269,169 +246,4 @@
         }
         return tweakSign(ux);
     }
-
-    @Test
-    public void testVarargsArray() throws Throwable {
-        //System.out.println("varargsArray");
-        final int MIN = START_ARITY;
-        final int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
-        for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) {
-            MethodHandle target = ValueConversions.varargsArray(nargs);
-            Object[] args = new Object[nargs];
-            for (int i = 0; i < nargs; i++)
-                args[i] = "#"+i;
-            Object res = target.invokeWithArguments(args);
-            assertArrayEquals(args, (Object[])res);
-        }
-    }
-
-    @Test
-    public void testVarargsReferenceArray() throws Throwable {
-        //System.out.println("varargsReferenceArray");
-        testTypedVarargsArray(Object[].class);
-        testTypedVarargsArray(String[].class);
-        testTypedVarargsArray(Number[].class);
-    }
-
-    @Test
-    public void testVarargsPrimitiveArray() throws Throwable {
-        //System.out.println("varargsPrimitiveArray");
-        testTypedVarargsArray(int[].class);
-        testTypedVarargsArray(long[].class);
-        testTypedVarargsArray(byte[].class);
-        testTypedVarargsArray(boolean[].class);
-        testTypedVarargsArray(short[].class);
-        testTypedVarargsArray(char[].class);
-        testTypedVarargsArray(float[].class);
-        testTypedVarargsArray(double[].class);
-    }
-
-    private static int nextArgCount(int nargs, int density, int MAX) {
-        if (EXHAUSTIVE)  return nargs + 1;
-        if (nargs >= MAX)  return Integer.MAX_VALUE;
-        int BOT = 20, TOP = MAX-5;
-        if (density < 10) { BOT = 10; MAX = TOP-2; }
-        if (nargs <= BOT || nargs >= TOP) {
-            ++nargs;
-        } else {
-            int bump = Math.max(1, 100 / density);
-            nargs += bump;
-            if (nargs > TOP)  nargs = TOP;
-        }
-        return nargs;
-    }
-
-    private void testTypedVarargsArray(Class<?> arrayType) throws Throwable {
-        //System.out.println(arrayType.getSimpleName());
-        Class<?> elemType = arrayType.getComponentType();
-        int MIN = START_ARITY;
-        int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
-        int density = 3;
-        if (elemType == int.class || elemType == long.class)  density = 7;
-        if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; }
-        for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) {
-            Object[] args = makeTestArray(elemType, nargs);
-            MethodHandle varargsArray = ValueConversions.varargsArray(arrayType, nargs);
-            MethodType vaType = varargsArray.type();
-            assertEquals(arrayType, vaType.returnType());
-            if (nargs != 0) {
-                assertEquals(elemType, vaType.parameterType(0));
-                assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1));
-            }
-            assertEquals(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)),
-                         vaType);
-            Object res = varargsArray.invokeWithArguments(args);
-            String resString = toArrayString(res);
-            assertEquals(Arrays.toString(args), resString);
-
-            MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs);
-            MethodType stype = spreader.type();
-            assert(stype == MethodType.methodType(arrayType, arrayType));
-            if (nargs <= 5) {
-                // invoke target as a spreader also:
-                @SuppressWarnings("cast")
-                Object res2 = spreader.invokeWithArguments((Object)res);
-                String res2String = toArrayString(res2);
-                assertEquals(Arrays.toString(args), res2String);
-                // invoke the spreader on a generic Object[] array; check for error
-                try {
-                    Object res3 = spreader.invokeWithArguments((Object)args);
-                    String res3String = toArrayString(res3);
-                    assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class));
-                    assertEquals(Arrays.toString(args), res3String);
-                } catch (ClassCastException ex) {
-                    assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class));
-                }
-            }
-            if (nargs == 0) {
-                // invoke spreader on null arglist
-                Object res3 = spreader.invokeWithArguments((Object)null);
-                String res3String = toArrayString(res3);
-                assertEquals(Arrays.toString(args), res3String);
-            }
-        }
-    }
-
-    private static Object[] makeTestArray(Class<?> elemType, int len) {
-        Wrapper elem = null;
-        if (elemType.isPrimitive())
-            elem = Wrapper.forPrimitiveType(elemType);
-        else if (Wrapper.isWrapperType(elemType))
-            elem = Wrapper.forWrapperType(elemType);
-        Object[] args = new Object[len];
-        for (int i = 0; i < len; i++) {
-            Object arg = i * 100;
-            if (elem == null) {
-                if (elemType == String.class)
-                    arg = "#"+arg;
-                arg = elemType.cast(arg);  // just to make sure
-            } else {
-                switch (elem) {
-                    case BOOLEAN: arg = (i % 3 == 0);           break;
-                    case CHAR:    arg = 'a' + i;                break;
-                    case LONG:    arg = (long)i * 1000_000_000; break;
-                    case FLOAT:   arg = (float)i / 100;         break;
-                    case DOUBLE:  arg = (double)i / 1000_000;   break;
-                }
-                arg = elem.cast(arg, elemType);
-            }
-            args[i] = arg;
-        }
-        //System.out.println(elemType.getName()+Arrays.toString(args));
-        return args;
-    }
-
-    private static String toArrayString(Object a) {
-        if (a == null)  return "null";
-        Class<?> elemType = a.getClass().getComponentType();
-        if (elemType == null)  return a.toString();
-        if (elemType.isPrimitive()) {
-            switch (Wrapper.forPrimitiveType(elemType)) {
-                case INT:      return Arrays.toString((int[])a);
-                case BYTE:     return Arrays.toString((byte[])a);
-                case BOOLEAN:  return Arrays.toString((boolean[])a);
-                case SHORT:    return Arrays.toString((short[])a);
-                case CHAR:     return Arrays.toString((char[])a);
-                case FLOAT:    return Arrays.toString((float[])a);
-                case LONG:     return Arrays.toString((long[])a);
-                case DOUBLE:   return Arrays.toString((double[])a);
-            }
-        }
-        return Arrays.toString((Object[])a);
-    }
-
-    @Test
-    public void testVarargsList() throws Throwable {
-        //System.out.println("varargsList");
-        final int MIN = START_ARITY;
-        final int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
-        for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 7, MAX)) {
-            MethodHandle target = ValueConversions.varargsList(nargs);
-            Object[] args = new Object[nargs];
-            for (int i = 0; i < nargs; i++)
-                args[i] = "#"+i;
-            Object res = target.invokeWithArguments(args);
-            assertEquals(Arrays.asList(args), res);
-        }
-    }
 }