23 |
23 |
24 package test.sun.invoke.util; |
24 package test.sun.invoke.util; |
25 |
25 |
26 import sun.invoke.util.ValueConversions; |
26 import sun.invoke.util.ValueConversions; |
27 import sun.invoke.util.Wrapper; |
27 import sun.invoke.util.Wrapper; |
|
28 |
28 import java.lang.invoke.MethodType; |
29 import java.lang.invoke.MethodType; |
29 import java.lang.invoke.MethodHandle; |
30 import java.lang.invoke.MethodHandle; |
30 import java.io.Serializable; |
31 import java.io.Serializable; |
31 import java.util.Arrays; |
32 import java.util.Arrays; |
32 import java.util.Collections; |
|
33 import org.junit.Test; |
33 import org.junit.Test; |
34 import static org.junit.Assert.*; |
34 import static org.junit.Assert.*; |
35 |
35 |
36 /* @test |
36 /* @test |
37 * @summary unit tests for value-type conversion utilities |
37 * @summary unit tests for value-type conversion utilities |
38 * @compile -XDignore.symbol.file ValueConversionsTest.java |
38 * @compile -XDignore.symbol.file ValueConversionsTest.java |
39 * @run junit/othervm test.sun.invoke.util.ValueConversionsTest |
39 * @run junit/othervm test.sun.invoke.util.ValueConversionsTest |
40 * @run junit/othervm |
|
41 * -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.START_ARITY=250 |
|
42 * test.sun.invoke.util.ValueConversionsTest |
|
43 */ |
40 */ |
44 |
|
45 // This might take a while and burn lots of metadata: |
|
46 // @run junit/othervm -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.EXHAUSTIVE=true test.sun.invoke.util.ValueConversionsTest |
|
47 |
41 |
48 /** |
42 /** |
49 * |
43 * |
50 * @author jrose |
44 * @author jrose |
51 */ |
45 */ |
52 public class ValueConversionsTest { |
46 public class ValueConversionsTest { |
53 private static final Class<?> CLASS = ValueConversionsTest.class; |
|
54 private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); |
|
55 private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0); |
|
56 private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE"); |
|
57 |
|
58 @Test |
47 @Test |
59 public void testUnbox() throws Throwable { |
48 public void testUnbox() throws Throwable { |
60 testUnbox(false); |
49 testUnbox(false); |
61 } |
50 } |
62 |
51 |
149 } |
134 } |
150 } |
135 } |
151 |
136 |
152 @Test |
137 @Test |
153 public void testCast() throws Throwable { |
138 public void testCast() throws Throwable { |
154 //System.out.println("cast"); |
|
155 Class<?>[] types = { Object.class, Serializable.class, String.class, Number.class, Integer.class }; |
139 Class<?>[] types = { Object.class, Serializable.class, String.class, Number.class, Integer.class }; |
156 Object[] objects = { new Object(), Boolean.FALSE, "hello", (Long)12L, (Integer)6 }; |
140 Object[] objects = { new Object(), Boolean.FALSE, "hello", (Long)12L, (Integer)6 }; |
157 for (Class<?> dst : types) { |
141 for (Class<?> dst : types) { |
158 MethodHandle caster = ValueConversions.cast(dst); |
142 MethodHandle caster = ValueConversions.cast(dst); |
159 assertEquals(caster.type(), ValueConversions.identity().type()); |
143 assertEquals(caster.type(), ValueConversions.identity().type()); |
160 for (Object obj : objects) { |
144 for (Object obj : objects) { |
161 Class<?> src = obj.getClass(); |
145 Class<?> src = obj.getClass(); |
162 boolean canCast = dst.isAssignableFrom(src); |
146 boolean canCast = dst.isAssignableFrom(src); |
163 //System.out.println("obj="+obj+" <: dst="+dst+(canCast ? " (OK)" : " (will fail)")); |
|
164 try { |
147 try { |
165 Object result = caster.invokeExact(obj); |
148 Object result = caster.invokeExact(obj); |
166 if (canCast) |
149 if (canCast) |
167 assertEquals(obj, result); |
150 assertEquals(obj, result); |
168 else |
151 else |
175 } |
158 } |
176 } |
159 } |
177 |
160 |
178 @Test |
161 @Test |
179 public void testIdentity() throws Throwable { |
162 public void testIdentity() throws Throwable { |
180 //System.out.println("identity"); |
|
181 MethodHandle id = ValueConversions.identity(); |
163 MethodHandle id = ValueConversions.identity(); |
182 Object expResult = "foo"; |
164 Object expResult = "foo"; |
183 Object result = id.invokeExact(expResult); |
165 Object result = id.invokeExact(expResult); |
184 // compiler bug: ValueConversions.identity().invokeExact("bar"); |
|
185 assertEquals(expResult, result); |
166 assertEquals(expResult, result); |
186 } |
167 } |
187 |
168 |
188 @Test |
169 @Test |
189 public void testConvert() throws Throwable { |
170 public void testConvert() throws Throwable { |
190 //System.out.println("convert"); |
|
191 for (long tval = 0, ctr = 0;;) { |
171 for (long tval = 0, ctr = 0;;) { |
192 if (++ctr > 99999) throw new AssertionError("too many test values"); |
172 if (++ctr > 99999) throw new AssertionError("too many test values"); |
193 // next test value: |
173 // prints 3776 test patterns (3776 = 8*59*8) |
194 //System.out.println(Long.toHexString(tval)); // prints 3776 test patterns |
|
195 tval = nextTestValue(tval); |
174 tval = nextTestValue(tval); |
196 if (tval == 0) { |
175 if (tval == 0) { |
197 //System.out.println("test value count = "+ctr); // 3776 = 8*59*8 |
|
198 break; // repeat |
176 break; // repeat |
199 } |
177 } |
200 } |
178 } |
201 for (Wrapper src : Wrapper.values()) { |
179 for (Wrapper src : Wrapper.values()) { |
202 for (Wrapper dst : Wrapper.values()) { |
180 for (Wrapper dst : Wrapper.values()) { |
203 testConvert(src, dst, 0); |
181 testConvert(src, dst, 0); |
204 } |
182 } |
205 } |
183 } |
206 } |
184 } |
207 static void testConvert(Wrapper src, Wrapper dst, long tval) throws Throwable { |
185 static void testConvert(Wrapper src, Wrapper dst, long tval) throws Throwable { |
208 //System.out.println(src+" => "+dst); |
|
209 boolean testSingleCase = (tval != 0); |
186 boolean testSingleCase = (tval != 0); |
210 final long tvalInit = tval; |
187 final long tvalInit = tval; |
211 MethodHandle conv = ValueConversions.convertPrimitive(src, dst); |
188 MethodHandle conv = ValueConversions.convertPrimitive(src, dst); |
212 MethodType convType; |
189 MethodType convType; |
213 if (src == Wrapper.VOID) |
190 if (src == Wrapper.VOID) |
267 midBit = (1L<<LOW_BITS); // introduce a low bit |
244 midBit = (1L<<LOW_BITS); // introduce a low bit |
268 ux += midBit; |
245 ux += midBit; |
269 } |
246 } |
270 return tweakSign(ux); |
247 return tweakSign(ux); |
271 } |
248 } |
272 |
|
273 @Test |
|
274 public void testVarargsArray() throws Throwable { |
|
275 //System.out.println("varargsArray"); |
|
276 final int MIN = START_ARITY; |
|
277 final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added |
|
278 for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) { |
|
279 MethodHandle target = ValueConversions.varargsArray(nargs); |
|
280 Object[] args = new Object[nargs]; |
|
281 for (int i = 0; i < nargs; i++) |
|
282 args[i] = "#"+i; |
|
283 Object res = target.invokeWithArguments(args); |
|
284 assertArrayEquals(args, (Object[])res); |
|
285 } |
|
286 } |
|
287 |
|
288 @Test |
|
289 public void testVarargsReferenceArray() throws Throwable { |
|
290 //System.out.println("varargsReferenceArray"); |
|
291 testTypedVarargsArray(Object[].class); |
|
292 testTypedVarargsArray(String[].class); |
|
293 testTypedVarargsArray(Number[].class); |
|
294 } |
|
295 |
|
296 @Test |
|
297 public void testVarargsPrimitiveArray() throws Throwable { |
|
298 //System.out.println("varargsPrimitiveArray"); |
|
299 testTypedVarargsArray(int[].class); |
|
300 testTypedVarargsArray(long[].class); |
|
301 testTypedVarargsArray(byte[].class); |
|
302 testTypedVarargsArray(boolean[].class); |
|
303 testTypedVarargsArray(short[].class); |
|
304 testTypedVarargsArray(char[].class); |
|
305 testTypedVarargsArray(float[].class); |
|
306 testTypedVarargsArray(double[].class); |
|
307 } |
|
308 |
|
309 private static int nextArgCount(int nargs, int density, int MAX) { |
|
310 if (EXHAUSTIVE) return nargs + 1; |
|
311 if (nargs >= MAX) return Integer.MAX_VALUE; |
|
312 int BOT = 20, TOP = MAX-5; |
|
313 if (density < 10) { BOT = 10; MAX = TOP-2; } |
|
314 if (nargs <= BOT || nargs >= TOP) { |
|
315 ++nargs; |
|
316 } else { |
|
317 int bump = Math.max(1, 100 / density); |
|
318 nargs += bump; |
|
319 if (nargs > TOP) nargs = TOP; |
|
320 } |
|
321 return nargs; |
|
322 } |
|
323 |
|
324 private void testTypedVarargsArray(Class<?> arrayType) throws Throwable { |
|
325 //System.out.println(arrayType.getSimpleName()); |
|
326 Class<?> elemType = arrayType.getComponentType(); |
|
327 int MIN = START_ARITY; |
|
328 int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added |
|
329 int density = 3; |
|
330 if (elemType == int.class || elemType == long.class) density = 7; |
|
331 if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; } |
|
332 for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) { |
|
333 Object[] args = makeTestArray(elemType, nargs); |
|
334 MethodHandle varargsArray = ValueConversions.varargsArray(arrayType, nargs); |
|
335 MethodType vaType = varargsArray.type(); |
|
336 assertEquals(arrayType, vaType.returnType()); |
|
337 if (nargs != 0) { |
|
338 assertEquals(elemType, vaType.parameterType(0)); |
|
339 assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1)); |
|
340 } |
|
341 assertEquals(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)), |
|
342 vaType); |
|
343 Object res = varargsArray.invokeWithArguments(args); |
|
344 String resString = toArrayString(res); |
|
345 assertEquals(Arrays.toString(args), resString); |
|
346 |
|
347 MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs); |
|
348 MethodType stype = spreader.type(); |
|
349 assert(stype == MethodType.methodType(arrayType, arrayType)); |
|
350 if (nargs <= 5) { |
|
351 // invoke target as a spreader also: |
|
352 @SuppressWarnings("cast") |
|
353 Object res2 = spreader.invokeWithArguments((Object)res); |
|
354 String res2String = toArrayString(res2); |
|
355 assertEquals(Arrays.toString(args), res2String); |
|
356 // invoke the spreader on a generic Object[] array; check for error |
|
357 try { |
|
358 Object res3 = spreader.invokeWithArguments((Object)args); |
|
359 String res3String = toArrayString(res3); |
|
360 assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); |
|
361 assertEquals(Arrays.toString(args), res3String); |
|
362 } catch (ClassCastException ex) { |
|
363 assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); |
|
364 } |
|
365 } |
|
366 if (nargs == 0) { |
|
367 // invoke spreader on null arglist |
|
368 Object res3 = spreader.invokeWithArguments((Object)null); |
|
369 String res3String = toArrayString(res3); |
|
370 assertEquals(Arrays.toString(args), res3String); |
|
371 } |
|
372 } |
|
373 } |
|
374 |
|
375 private static Object[] makeTestArray(Class<?> elemType, int len) { |
|
376 Wrapper elem = null; |
|
377 if (elemType.isPrimitive()) |
|
378 elem = Wrapper.forPrimitiveType(elemType); |
|
379 else if (Wrapper.isWrapperType(elemType)) |
|
380 elem = Wrapper.forWrapperType(elemType); |
|
381 Object[] args = new Object[len]; |
|
382 for (int i = 0; i < len; i++) { |
|
383 Object arg = i * 100; |
|
384 if (elem == null) { |
|
385 if (elemType == String.class) |
|
386 arg = "#"+arg; |
|
387 arg = elemType.cast(arg); // just to make sure |
|
388 } else { |
|
389 switch (elem) { |
|
390 case BOOLEAN: arg = (i % 3 == 0); break; |
|
391 case CHAR: arg = 'a' + i; break; |
|
392 case LONG: arg = (long)i * 1000_000_000; break; |
|
393 case FLOAT: arg = (float)i / 100; break; |
|
394 case DOUBLE: arg = (double)i / 1000_000; break; |
|
395 } |
|
396 arg = elem.cast(arg, elemType); |
|
397 } |
|
398 args[i] = arg; |
|
399 } |
|
400 //System.out.println(elemType.getName()+Arrays.toString(args)); |
|
401 return args; |
|
402 } |
|
403 |
|
404 private static String toArrayString(Object a) { |
|
405 if (a == null) return "null"; |
|
406 Class<?> elemType = a.getClass().getComponentType(); |
|
407 if (elemType == null) return a.toString(); |
|
408 if (elemType.isPrimitive()) { |
|
409 switch (Wrapper.forPrimitiveType(elemType)) { |
|
410 case INT: return Arrays.toString((int[])a); |
|
411 case BYTE: return Arrays.toString((byte[])a); |
|
412 case BOOLEAN: return Arrays.toString((boolean[])a); |
|
413 case SHORT: return Arrays.toString((short[])a); |
|
414 case CHAR: return Arrays.toString((char[])a); |
|
415 case FLOAT: return Arrays.toString((float[])a); |
|
416 case LONG: return Arrays.toString((long[])a); |
|
417 case DOUBLE: return Arrays.toString((double[])a); |
|
418 } |
|
419 } |
|
420 return Arrays.toString((Object[])a); |
|
421 } |
|
422 |
|
423 @Test |
|
424 public void testVarargsList() throws Throwable { |
|
425 //System.out.println("varargsList"); |
|
426 final int MIN = START_ARITY; |
|
427 final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added |
|
428 for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 7, MAX)) { |
|
429 MethodHandle target = ValueConversions.varargsList(nargs); |
|
430 Object[] args = new Object[nargs]; |
|
431 for (int i = 0; i < nargs; i++) |
|
432 args[i] = "#"+i; |
|
433 Object res = target.invokeWithArguments(args); |
|
434 assertEquals(Arrays.asList(args), res); |
|
435 } |
|
436 } |
|
437 } |
249 } |