1 /*
2  * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 // Android-added: package name.
25 package test.java.lang.invoke;
26 
27 import sun.invoke.util.Wrapper;
28 import test.java.lang.invoke.lib.CodeCacheOverflowProcessor;
29 
30 import java.lang.invoke.MethodHandle;
31 import java.lang.invoke.MethodHandles;
32 import java.lang.invoke.MethodType;
33 import java.util.Arrays;
34 import java.util.Collections;
35 
36 // Android-added: testng imports.
37 import static org.testng.AssertJUnit.*;
38 import org.testng.annotations.*;
39 
40 /* @test
41  * @summary unit tests for varargs array methods: MethodHandleInfo.varargsArray(int),
42  *          MethodHandleInfo.varargsArray(Class,int) & MethodHandleInfo.varargsList(int)
43  * @modules java.base/sun.invoke.util
44  * @library /lib/testlibrary /java/lang/invoke/common
45  * @compile/module=java.base java/lang/invoke/MethodHandleHelper.java
46  * @run main/bootclasspath VarargsArrayTest
47  * @run main/bootclasspath/othervm -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250
48  *                         VarargsArrayTest
49  */
50 
51 /* This might take a while and burn lots of metadata:
52  * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true VarargsArrayTest
53  */
54 public class VarargsArrayTest {
55     private static final Class<?> CLASS = VarargsArrayTest.class;
56     private static final int MAX_ARITY = Integer.getInteger(
57             CLASS.getSimpleName()+".MAX_ARITY", 40);
58     private static final int START_ARITY = Integer.getInteger(
59             CLASS.getSimpleName()+".START_ARITY", 0);
60     private static final boolean EXHAUSTIVE = Boolean.getBoolean(
61             CLASS.getSimpleName()+".EXHAUSTIVE");
62 
main(String[] args)63     public static void main(String[] args) throws Throwable {
64         // Android-removed: test converted to testng.
65         // CodeCacheOverflowProcessor.runMHTest(VarargsArrayTest::test);
66     }
67 
68     // Android-removed: Added @Test annotations.
69     /*
70     @Test
71     public static void test() throws Throwable {
72         testVarargsArray();
73         testVarargsReferenceArray();
74         testVarargsPrimitiveArray();
75     }
76     */
77 
78     // Android-added: @Test annotation.
79     @Test
testVarargsArray()80     public static void testVarargsArray() throws Throwable {
81         final int MIN = START_ARITY;
82         final int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
83         for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) {
84             // Android-changed: use VarargsArrayTest.varargsArray().
85             // MethodHandle target = MethodHandleHelper.varargsArray(nargs);
86             MethodHandle target = varargsArray(Object[].class, nargs);
87             Object[] args = new Object[nargs];
88             for (int i = 0; i < nargs; i++)
89                 args[i] = "#"+i;
90             Object res = target.invokeWithArguments(args);
91             assertArrayEquals(args, (Object[])res);
92         }
93     }
94 
95     // Android-added: @Test annotation.
96     @Test
testVarargsReferenceArray()97     public static void testVarargsReferenceArray() throws Throwable {
98         testTypedVarargsArray(Object[].class);
99         testTypedVarargsArray(String[].class);
100         testTypedVarargsArray(Number[].class);
101     }
102 
103     // Android-added: @Test annotation.
104     @Test
testVarargsPrimitiveArray()105     public static void testVarargsPrimitiveArray() throws Throwable {
106         testTypedVarargsArray(int[].class);
107         testTypedVarargsArray(long[].class);
108         testTypedVarargsArray(byte[].class);
109         testTypedVarargsArray(boolean[].class);
110         testTypedVarargsArray(short[].class);
111         testTypedVarargsArray(char[].class);
112         testTypedVarargsArray(float[].class);
113         testTypedVarargsArray(double[].class);
114     }
115 
nextArgCount(int nargs, int density, int MAX)116     private static int nextArgCount(int nargs, int density, int MAX) {
117         if (EXHAUSTIVE)  return nargs + 1;
118         if (nargs >= MAX)  return Integer.MAX_VALUE;
119         int BOT = 20, TOP = MAX-5;
120         if (density < 10) { BOT = 10; MAX = TOP-2; }
121         if (nargs <= BOT || nargs >= TOP) {
122             ++nargs;
123         } else {
124             int bump = Math.max(1, 100 / density);
125             nargs += bump;
126             if (nargs > TOP)  nargs = TOP;
127         }
128         return nargs;
129     }
130 
131     // Android-added: simplified alternative to MethodHandleHelper.varargsArray().
varargsArray(Class<?> arrayType, int nargs)132     private static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
133         return MethodHandles.identity(arrayType).asCollector(arrayType, nargs);
134     }
135 
testTypedVarargsArray(Class<?> arrayType)136     private static void testTypedVarargsArray(Class<?> arrayType) throws Throwable {
137         Class<?> elemType = arrayType.getComponentType();
138         int MIN = START_ARITY;
139         int MAX = MAX_ARITY-2;  // 253+1 would cause parameter overflow with 'this' added
140         int density = 3;
141         if (elemType == int.class || elemType == long.class)  density = 7;
142         if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; }
143         for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) {
144             Object[] args = makeTestArray(elemType, nargs);
145             // Android-changed: used varargsArrayHelper above.
146             // MethodHandle varargsArray = MethodHandleHelper.varargsArray(arrayType, nargs);
147             MethodHandle varargsArray = varargsArray(arrayType, nargs);
148             MethodType vaType = varargsArray.type();
149             assertEquals(arrayType, vaType.returnType());
150             if (nargs != 0) {
151                 assertEquals(elemType, vaType.parameterType(0));
152                 assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1));
153             }
154             assertEquals(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)),
155                          vaType);
156             Object res = varargsArray.invokeWithArguments(args);
157             assertEquals(res.getClass(), arrayType);
158             String resString = toArrayString(res);
159             assertEquals(Arrays.toString(args), resString);
160 
161             MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs);
162             MethodType stype = spreader.type();
163             assert(stype == MethodType.methodType(arrayType, arrayType));
164             if (nargs <= 5) {
165                 // invoke target as a spreader also:
166                 @SuppressWarnings("cast")
167                 Object res2 = spreader.invokeWithArguments((Object)res);
168                 String res2String = toArrayString(res2);
169                 assertEquals(Arrays.toString(args), res2String);
170                 // invoke the spreader on a generic Object[] array; check for error
171                 try {
172                     Object res3 = spreader.invokeWithArguments((Object)args);
173                     String res3String = toArrayString(res3);
174                     assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class));
175                     assertEquals(Arrays.toString(args), res3String);
176                 } catch (ClassCastException ex) {
177                     assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class));
178                 }
179             }
180             if (nargs == 0) {
181                 // invoke spreader on null arglist
182                 Object res3 = spreader.invokeWithArguments((Object)null);
183                 String res3String = toArrayString(res3);
184                 assertEquals(Arrays.toString(args), res3String);
185             }
186         }
187     }
188 
makeTestArray(Class<?> elemType, int len)189     private static Object[] makeTestArray(Class<?> elemType, int len) {
190         Wrapper elem = null;
191         if (elemType.isPrimitive())
192             elem = Wrapper.forPrimitiveType(elemType);
193         else if (Wrapper.isWrapperType(elemType))
194             elem = Wrapper.forWrapperType(elemType);
195         Object[] args = new Object[len];
196         for (int i = 0; i < len; i++) {
197             Object arg = i * 100;
198             if (elem == null) {
199                 if (elemType == String.class)
200                     arg = "#"+arg;
201                 arg = elemType.cast(arg);  // just to make sure
202             } else {
203                 switch (elem) {
204                     case BOOLEAN: arg = (i % 3 == 0);           break;
205                     case CHAR:    arg = 'a' + i;                break;
206                     case LONG:    arg = (long)i * 1000_000_000; break;
207                     case FLOAT:   arg = (float)i / 100;         break;
208                     case DOUBLE:  arg = (double)i / 1000_000;   break;
209                 }
210                 arg = elem.cast(arg, elemType);
211             }
212             args[i] = arg;
213         }
214         return args;
215     }
216 
toArrayString(Object a)217     private static String toArrayString(Object a) {
218         if (a == null)  return "null";
219         Class<?> elemType = a.getClass().getComponentType();
220         if (elemType == null)  return a.toString();
221         if (elemType.isPrimitive()) {
222             switch (Wrapper.forPrimitiveType(elemType)) {
223                 case INT:      return Arrays.toString((int[])a);
224                 case BYTE:     return Arrays.toString((byte[])a);
225                 case BOOLEAN:  return Arrays.toString((boolean[])a);
226                 case SHORT:    return Arrays.toString((short[])a);
227                 case CHAR:     return Arrays.toString((char[])a);
228                 case FLOAT:    return Arrays.toString((float[])a);
229                 case LONG:     return Arrays.toString((long[])a);
230                 case DOUBLE:   return Arrays.toString((double[])a);
231             }
232         }
233         return Arrays.toString((Object[])a);
234     }
235 
assertArrayEquals(Object[] arr1, Object[] arr2)236     public static void assertArrayEquals(Object[] arr1, Object[] arr2) {
237         if (arr1 == null && arr2 == null)  return;
238         if (arr1 != null && arr2 != null && arr1.length == arr2.length) {
239             for (int i = 0; i < arr1.length; i++) {
240                 assertEquals(arr1[i], arr2[i]);
241             }
242             return;
243         }
244         throw new AssertionError(Arrays.deepToString(arr1)
245                 + " != " + Arrays.deepToString(arr2));
246     }
247 
248     // Android-removed: use asserts from testng API for use in test harness.
249     /*
250     public static void assertEquals(Object o1, Object o2) {
251         if (o1 == null && o2 == null)    return;
252         if (o1 != null && o1.equals(o2)) return;
253         throw new AssertionError(o1 + " != " + o2);
254     }
255 
256     public static void assertTrue(String msg, boolean b) {
257         if (!b) {
258             throw new AssertionError(msg);
259         }
260     }
261 
262     public static void assertFalse(String msg, boolean b) {
263         assertTrue(msg, !b);
264     }
265     */
266 }
267