8049555: Move varargsArray from sun.invoke.util package to java.lang.invoke
Reviewed-by: psandoz, iignatyev
--- 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);
- }
- }
}