ValueConversionsTest.java revision 4183:4732a76af216
1/* 2 * Copyright (c) 2009, 2011, 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 24package test.sun.invoke.util; 25 26import sun.invoke.util.ValueConversions; 27import sun.invoke.util.Wrapper; 28import java.lang.invoke.MethodType; 29import java.lang.invoke.MethodHandle; 30import java.lang.invoke.MethodHandles; 31import java.io.Serializable; 32import java.util.Arrays; 33import java.util.Collections; 34import org.junit.Ignore; 35import org.junit.Test; 36import static org.junit.Assert.*; 37 38/* @test 39 * @summary unit tests for value-type conversion utilities 40 * @ignore This test requires a special compilation environment to access sun.inovke.util. Run by hand. 41 * @run junit/othervm test.sun.invoke.util.ValueConversionsTest 42 * @run junit/othervm 43 * -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.START_ARITY=250 44 * test.sun.invoke.util.ValueConversionsTest 45 */ 46 47// This might take a while and burn lots of metadata: 48// @run junit/othervm -DValueConversionsTest.MAX_ARITY=255 -DValueConversionsTest.EXHAUSTIVE=true test.sun.invoke.util.ValueConversionsTest 49 50/** 51 * 52 * @author jrose 53 */ 54public class ValueConversionsTest { 55 private static final Class CLASS = ValueConversionsTest.class; 56 private static final int MAX_ARITY = Integer.getInteger(CLASS.getSimpleName()+".MAX_ARITY", 40); 57 private static final int START_ARITY = Integer.getInteger(CLASS.getSimpleName()+".START_ARITY", 0); 58 private static final boolean EXHAUSTIVE = Boolean.getBoolean(CLASS.getSimpleName()+".EXHAUSTIVE"); 59 60 @Test 61 public void testUnbox() throws Throwable { 62 testUnbox(false); 63 } 64 65 @Test 66 public void testUnboxCast() throws Throwable { 67 testUnbox(true); 68 } 69 70 private void testUnbox(boolean doCast) throws Throwable { 71 //System.out.println("unbox"); 72 for (Wrapper dst : Wrapper.values()) { 73 //System.out.println(dst); 74 for (Wrapper src : Wrapper.values()) { 75 testUnbox(doCast, dst, src); 76 } 77 } 78 } 79 80 private void testUnbox(boolean doCast, Wrapper dst, Wrapper src) throws Throwable { 81 boolean expectThrow = !doCast && !dst.isConvertibleFrom(src); 82 if (dst == Wrapper.OBJECT || src == Wrapper.OBJECT) return; // must have prims 83 if (dst == Wrapper.OBJECT) 84 expectThrow = false; // everything (even VOID==null here) converts to OBJECT 85 try { 86 for (int n = -5; n < 10; n++) { 87 Object box = src.wrap(n); 88 switch (src) { 89 case VOID: assertEquals(box, null); break; 90 case OBJECT: box = box.toString(); break; 91 case SHORT: assertEquals(box.getClass(), Short.class); break; 92 default: assertEquals(box.getClass(), src.wrapperType()); break; 93 } 94 MethodHandle unboxer; 95 if (doCast) 96 unboxer = ValueConversions.unboxCast(dst.primitiveType()); 97 else 98 unboxer = ValueConversions.unbox(dst.primitiveType()); 99 Object expResult = (box == null) ? dst.zero() : dst.wrap(box); 100 Object result = null; 101 switch (dst) { 102 case INT: result = (int) unboxer.invokeExact(box); break; 103 case LONG: result = (long) unboxer.invokeExact(box); break; 104 case FLOAT: result = (float) unboxer.invokeExact(box); break; 105 case DOUBLE: result = (double) unboxer.invokeExact(box); break; 106 case CHAR: result = (char) unboxer.invokeExact(box); break; 107 case BYTE: result = (byte) unboxer.invokeExact(box); break; 108 case SHORT: result = (short) unboxer.invokeExact(box); break; 109 case OBJECT: result = (Object) unboxer.invokeExact(box); break; 110 case BOOLEAN: result = (boolean) unboxer.invokeExact(box); break; 111 case VOID: result = null; unboxer.invokeExact(box); break; 112 } 113 if (expectThrow) { 114 expResult = "(need an exception)"; 115 } 116 assertEquals("(doCast,expectThrow,dst,src,n,box)="+Arrays.asList(doCast,expectThrow,dst,src,n,box), 117 expResult, result); 118 } 119 } catch (RuntimeException ex) { 120 if (expectThrow) return; 121 System.out.println("Unexpected throw for (doCast,expectThrow,dst,src)="+Arrays.asList(doCast,expectThrow,dst,src)); 122 throw ex; 123 } 124 } 125 126 @Test 127 public void testUnboxRaw() throws Throwable { 128 //System.out.println("unboxRaw"); 129 for (Wrapper w : Wrapper.values()) { 130 if (w == Wrapper.OBJECT) continue; // skip this; no raw form 131 //System.out.println(w); 132 for (int n = -5; n < 10; n++) { 133 Object box = w.wrap(n); 134 long expResult = w.unwrapRaw(box); 135 Object box2 = w.wrapRaw(expResult); 136 assertEquals(box, box2); 137 MethodHandle unboxer = ValueConversions.unboxRaw(w.primitiveType()); 138 long result = -1; 139 switch (w) { 140 case INT: result = (int) unboxer.invokeExact(box); break; 141 case LONG: result = (long) unboxer.invokeExact(box); break; 142 case FLOAT: result = (int) unboxer.invokeExact(box); break; 143 case DOUBLE: result = (long) unboxer.invokeExact(box); break; 144 case CHAR: result = (int) unboxer.invokeExact(box); break; 145 case BYTE: result = (int) unboxer.invokeExact(box); break; 146 case SHORT: result = (int) unboxer.invokeExact(box); break; 147 case BOOLEAN: result = (int) unboxer.invokeExact(box); break; 148 case VOID: result = (int) unboxer.invokeExact(box); break; 149 } 150 assertEquals("(w,n,box)="+Arrays.asList(w,n,box), 151 expResult, result); 152 } 153 } 154 } 155 156 @Test 157 public void testBox() throws Throwable { 158 //System.out.println("box"); 159 for (Wrapper w : Wrapper.values()) { 160 if (w == Wrapper.VOID) continue; // skip this; no unboxed form 161 //System.out.println(w); 162 for (int n = -5; n < 10; n++) { 163 Object box = w.wrap(n); 164 MethodHandle boxer = ValueConversions.box(w.primitiveType()); 165 Object expResult = box; 166 Object result = null; 167 switch (w) { 168 case INT: result = boxer.invokeExact((int)n); break; 169 case LONG: result = boxer.invokeExact((long)n); break; 170 case FLOAT: result = boxer.invokeExact((float)n); break; 171 case DOUBLE: result = boxer.invokeExact((double)n); break; 172 case CHAR: result = boxer.invokeExact((char)n); break; 173 case BYTE: result = boxer.invokeExact((byte)n); break; 174 case SHORT: result = boxer.invokeExact((short)n); break; 175 case OBJECT: result = boxer.invokeExact((Object)n); break; 176 case BOOLEAN: result = boxer.invokeExact((n & 1) != 0); break; 177 } 178 assertEquals("(dst,src,n,box)="+Arrays.asList(w,w,n,box), 179 expResult, result); 180 } 181 } 182 } 183 184 @Test 185 public void testBoxRaw() throws Throwable { 186 //System.out.println("boxRaw"); 187 for (Wrapper w : Wrapper.values()) { 188 if (w == Wrapper.VOID) continue; // skip this; no unboxed form 189 if (w == Wrapper.OBJECT) continue; // skip this; no raw form 190 //System.out.println(w); 191 for (int n = -5; n < 10; n++) { 192 Object box = w.wrap(n); 193 long raw = w.unwrapRaw(box); 194 Object expResult = box; 195 MethodHandle boxer = ValueConversions.boxRaw(w.primitiveType()); 196 Object result = null; 197 switch (w) { 198 case INT: result = boxer.invokeExact((int)raw); break; 199 case LONG: result = boxer.invokeExact(raw); break; 200 case FLOAT: result = boxer.invokeExact((int)raw); break; 201 case DOUBLE: result = boxer.invokeExact(raw); break; 202 case CHAR: result = boxer.invokeExact((int)raw); break; 203 case BYTE: result = boxer.invokeExact((int)raw); break; 204 case SHORT: result = boxer.invokeExact((int)raw); break; 205 case BOOLEAN: result = boxer.invokeExact((int)raw); break; 206 } 207 assertEquals("(dst,src,n,box)="+Arrays.asList(w,w,n,box), 208 expResult, result); 209 } 210 } 211 } 212 213 @Test 214 public void testReboxRaw() throws Throwable { 215 //System.out.println("reboxRaw"); 216 for (Wrapper w : Wrapper.values()) { 217 Wrapper pw = Wrapper.forPrimitiveType(w.rawPrimitiveType()); 218 if (w == Wrapper.VOID) continue; // skip this; no unboxed form 219 if (w == Wrapper.OBJECT) continue; // skip this; no raw form 220 //System.out.println(w); 221 for (int n = -5; n < 10; n++) { 222 Object box = w.wrap(n); 223 Object raw = pw.wrap(w.unwrapRaw(box)); 224 Object expResult = box; 225 MethodHandle boxer = ValueConversions.rebox(w.primitiveType()); 226 Object result = null; 227 switch (w) { 228 case INT: result = boxer.invokeExact(raw); break; 229 case LONG: result = boxer.invokeExact(raw); break; 230 case FLOAT: result = boxer.invokeExact(raw); break; 231 case DOUBLE: result = boxer.invokeExact(raw); break; 232 case CHAR: result = boxer.invokeExact(raw); break; 233 case BYTE: result = boxer.invokeExact(raw); break; 234 case SHORT: result = boxer.invokeExact(raw); break; 235 case BOOLEAN: result = boxer.invokeExact(raw); break; 236 } 237 assertEquals("(dst,src,n,box)="+Arrays.asList(w,w,n,box), 238 expResult, result); 239 } 240 } 241 } 242 243 @Test 244 public void testCast() throws Throwable { 245 //System.out.println("cast"); 246 Class<?>[] types = { Object.class, Serializable.class, String.class, Number.class, Integer.class }; 247 Object[] objects = { new Object(), Boolean.FALSE, "hello", (Long)12L, (Integer)6 }; 248 for (Class<?> dst : types) { 249 MethodHandle caster = ValueConversions.cast(dst); 250 assertEquals(caster.type(), ValueConversions.identity().type()); 251 for (Object obj : objects) { 252 Class<?> src = obj.getClass(); 253 boolean canCast; 254 if (dst.isInterface()) { 255 canCast = true; 256 } else { 257 canCast = dst.isAssignableFrom(src); 258 assertEquals(canCast, dst.isInstance(obj)); 259 } 260 //System.out.println("obj="+obj+" <: dst="+dst); 261 try { 262 Object result = caster.invokeExact(obj); 263 if (canCast) 264 assertEquals(obj, result); 265 else 266 assertEquals("cast should not have succeeded", dst, obj); 267 } catch (ClassCastException ex) { 268 if (canCast) 269 throw ex; 270 } 271 } 272 } 273 } 274 275 @Test 276 public void testIdentity() throws Throwable { 277 //System.out.println("identity"); 278 MethodHandle id = ValueConversions.identity(); 279 Object expResult = "foo"; 280 Object result = id.invokeExact(expResult); 281 // compiler bug: ValueConversions.identity().invokeExact("bar"); 282 assertEquals(expResult, result); 283 } 284 285 @Test 286 public void testVarargsArray() throws Throwable { 287 //System.out.println("varargsArray"); 288 final int MIN = START_ARITY; 289 final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added 290 for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) { 291 MethodHandle target = ValueConversions.varargsArray(nargs); 292 Object[] args = new Object[nargs]; 293 for (int i = 0; i < nargs; i++) 294 args[i] = "#"+i; 295 Object res = target.invokeWithArguments(args); 296 assertArrayEquals(args, (Object[])res); 297 } 298 } 299 300 @Test 301 public void testVarargsReferenceArray() throws Throwable { 302 //System.out.println("varargsReferenceArray"); 303 testTypedVarargsArray(Object[].class); 304 testTypedVarargsArray(String[].class); 305 testTypedVarargsArray(Number[].class); 306 } 307 308 @Test 309 public void testVarargsPrimitiveArray() throws Throwable { 310 //System.out.println("varargsPrimitiveArray"); 311 testTypedVarargsArray(int[].class); 312 testTypedVarargsArray(long[].class); 313 testTypedVarargsArray(byte[].class); 314 testTypedVarargsArray(boolean[].class); 315 testTypedVarargsArray(short[].class); 316 testTypedVarargsArray(char[].class); 317 testTypedVarargsArray(float[].class); 318 testTypedVarargsArray(double[].class); 319 } 320 321 private static int nextArgCount(int nargs, int density, int MAX) { 322 if (EXHAUSTIVE) return nargs + 1; 323 if (nargs >= MAX) return Integer.MAX_VALUE; 324 int BOT = 20, TOP = MAX-5; 325 if (density < 10) { BOT = 10; MAX = TOP-2; } 326 if (nargs <= BOT || nargs >= TOP) { 327 ++nargs; 328 } else { 329 int bump = Math.max(1, 100 / density); 330 nargs += bump; 331 if (nargs > TOP) nargs = TOP; 332 } 333 return nargs; 334 } 335 336 private void testTypedVarargsArray(Class<?> arrayType) throws Throwable { 337 System.out.println(arrayType.getSimpleName()); 338 Class<?> elemType = arrayType.getComponentType(); 339 int MIN = START_ARITY; 340 int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added 341 int density = 3; 342 if (elemType == int.class || elemType == long.class) density = 7; 343 if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; } 344 for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) { 345 Object[] args = makeTestArray(elemType, nargs); 346 MethodHandle varargsArray = ValueConversions.varargsArray(arrayType, nargs); 347 MethodType vaType = varargsArray.type(); 348 assertEquals(arrayType, vaType.returnType()); 349 if (nargs != 0) { 350 assertEquals(elemType, vaType.parameterType(0)); 351 assertEquals(elemType, vaType.parameterType(vaType.parameterCount()-1)); 352 } 353 assertEquals(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)), 354 vaType); 355 Object res = varargsArray.invokeWithArguments(args); 356 String resString = toArrayString(res); 357 assertEquals(Arrays.toString(args), resString); 358 359 MethodHandle spreader = varargsArray.asSpreader(arrayType, nargs); 360 MethodType stype = spreader.type(); 361 assert(stype == MethodType.methodType(arrayType, arrayType)); 362 if (nargs <= 5) { 363 // invoke target as a spreader also: 364 Object res2 = spreader.invokeWithArguments((Object)res); 365 String res2String = toArrayString(res2); 366 assertEquals(Arrays.toString(args), res2String); 367 // invoke the spreader on a generic Object[] array; check for error 368 try { 369 Object res3 = spreader.invokeWithArguments((Object)args); 370 String res3String = toArrayString(res3); 371 assertTrue(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); 372 assertEquals(Arrays.toString(args), res3String); 373 } catch (ClassCastException ex) { 374 assertFalse(arrayType.getName(), arrayType.isAssignableFrom(Object[].class)); 375 } 376 } 377 if (nargs == 0) { 378 // invoke spreader on null arglist 379 Object res3 = spreader.invokeWithArguments((Object)null); 380 String res3String = toArrayString(res3); 381 assertEquals(Arrays.toString(args), res3String); 382 } 383 } 384 } 385 386 private static Object[] makeTestArray(Class<?> elemType, int len) { 387 Wrapper elem = null; 388 if (elemType.isPrimitive()) 389 elem = Wrapper.forPrimitiveType(elemType); 390 else if (Wrapper.isWrapperType(elemType)) 391 elem = Wrapper.forWrapperType(elemType); 392 Object[] args = new Object[len]; 393 for (int i = 0; i < len; i++) { 394 Object arg = i * 100; 395 if (elem == null) { 396 if (elemType == String.class) 397 arg = "#"+arg; 398 arg = elemType.cast(arg); // just to make sure 399 } else { 400 switch (elem) { 401 case BOOLEAN: arg = (i % 3 == 0); break; 402 case CHAR: arg = 'a' + i; break; 403 case LONG: arg = (long)i * 1000_000_000; break; 404 case FLOAT: arg = (float)i / 100; break; 405 case DOUBLE: arg = (double)i / 1000_000; break; 406 } 407 arg = elem.cast(arg, elemType); 408 } 409 args[i] = arg; 410 } 411 //System.out.println(elemType.getName()+Arrays.toString(args)); 412 return args; 413 } 414 415 private static String toArrayString(Object a) { 416 if (a == null) return "null"; 417 Class<?> elemType = a.getClass().getComponentType(); 418 if (elemType == null) return a.toString(); 419 if (elemType.isPrimitive()) { 420 switch (Wrapper.forPrimitiveType(elemType)) { 421 case INT: return Arrays.toString((int[])a); 422 case BYTE: return Arrays.toString((byte[])a); 423 case BOOLEAN: return Arrays.toString((boolean[])a); 424 case SHORT: return Arrays.toString((short[])a); 425 case CHAR: return Arrays.toString((char[])a); 426 case FLOAT: return Arrays.toString((float[])a); 427 case LONG: return Arrays.toString((long[])a); 428 case DOUBLE: return Arrays.toString((double[])a); 429 } 430 } 431 return Arrays.toString((Object[])a); 432 } 433 434 @Test 435 public void testVarargsList() throws Throwable { 436 //System.out.println("varargsList"); 437 final int MIN = START_ARITY; 438 final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added 439 for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 7, MAX)) { 440 MethodHandle target = ValueConversions.varargsList(nargs); 441 Object[] args = new Object[nargs]; 442 for (int i = 0; i < nargs; i++) 443 args[i] = "#"+i; 444 Object res = target.invokeWithArguments(args); 445 assertEquals(Arrays.asList(args), res); 446 } 447 } 448} 449