1 /* 2 * Copyright (c) 2018, 2019, 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 package runtime.valhalla.valuetypes; 25 26 import java.lang.reflect.Array; 27 import java.util.Arrays; 28 import java.util.ArrayList; 29 import java.util.List; 30 31 import static jdk.test.lib.Asserts.*; 32 33 /* 34 * @test ValueTypeArray 35 * @summary Plain array test for Inline Types 36 * @library /test/lib 37 * @compile -XDemitQtypes -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers -XDallowGenericsOverValues ValueTypeArray.java Point.java Long8Value.java Person.java 38 * @run main/othervm -Xint -XX:ValueArrayElemMaxFlatSize=-1 -XX:+EnableValhalla runtime.valhalla.valuetypes.ValueTypeArray 39 * @run main/othervm -Xint -XX:ValueArrayElemMaxFlatSize=0 -XX:+EnableValhalla runtime.valhalla.valuetypes.ValueTypeArray 40 * @run main/othervm -Xcomp -XX:ValueArrayElemMaxFlatSize=-1 -XX:+EnableValhalla runtime.valhalla.valuetypes.ValueTypeArray 41 * @run main/othervm -Xcomp -XX:ValueArrayElemMaxFlatSize=0 -XX:+EnableValhalla runtime.valhalla.valuetypes.ValueTypeArray 42 */ 43 public class ValueTypeArray { 44 public static void main(String[] args) { 45 ValueTypeArray valueTypeArray = new ValueTypeArray(); 46 valueTypeArray.run(); 47 } 48 49 public void run() { 50 testClassForName(); 51 testSimplePointArray(); 52 testLong8Array(); 53 testMixedPersonArray(); 54 testMultiDimPointArray(); 55 testComposition(); 56 57 testSanityCheckcasts(); 58 testObjectArrayOfValues(); 59 60 testReflectArray(); 61 testUtilArrays(); 62 } 63 64 void testClassForName() { 65 String arrayClsName = "[Lruntime.valhalla.valuetypes.Point;"; 66 String qarrayClsName = "[Qruntime.valhalla.valuetypes.Point;"; 67 try { 68 // L-type.. 69 Class<?> arrayCls = Class.forName(arrayClsName); 70 assertTrue(arrayCls.isArray(), "Expected an array class"); 71 72 assertTrue(arrayCls.getComponentType() == Point.class.asNullableType(), 73 "Expected component type of Point.class got: " + arrayCls.getComponentType()); 74 75 arrayClsName = "[" + arrayClsName; 76 Class<?> mulArrayCls = Class.forName(arrayClsName); 77 assertTrue(mulArrayCls.isArray()); 78 assertTrue(mulArrayCls.getComponentType() == arrayCls); 79 80 // Q-type... 81 arrayCls = Class.forName(qarrayClsName); 82 assertTrue(arrayCls.isArray(), "Expected an array class"); 83 84 assertTrue(arrayCls.getComponentType() == Point.class.asPrimaryType(), 85 arrayCls + 86 " Expected component type of Point.class got: " + arrayCls.getComponentType()); 87 88 qarrayClsName = "[" + qarrayClsName; 89 mulArrayCls = Class.forName(qarrayClsName); 90 assertTrue(mulArrayCls.isArray()); 91 assertTrue(mulArrayCls.getComponentType() == arrayCls); 92 } 93 catch (ClassNotFoundException cnfe) { 94 fail("Class.forName(" + arrayClsName + ") failed", cnfe); 95 } 96 } 97 98 void testSimplePointArray() { 99 Point[] defaultPoint = new Point[1]; 100 Point p = defaultPoint[0]; 101 assertEquals(p.x, 0, "invalid default loaded from array"); 102 assertEquals(p.y, 0, "invalid default loaded from array"); 103 boolean gotNpe = false; 104 try { 105 defaultPoint[0] = (Point) getNull(); 106 } catch (NullPointerException npe) { 107 gotNpe = true; 108 } 109 assertTrue(gotNpe, "Expected NullPointerException"); 110 111 Point[] points = createSimplePointArray(); 112 checkSimplePointArray(points); 113 System.gc(); // check that VTs survive GC 114 115 assertTrue(points instanceof Point[], "Instance of"); 116 117 Point[] pointsCopy = new Point[points.length]; 118 System.arraycopy(points, 0, pointsCopy, 0, points.length); 119 checkSimplePointArray(pointsCopy); 120 } 121 122 static Point[] createSimplePointArray() { 123 Point[] ps = new Point[2]; 124 assertEquals(ps.length, 2, "Length"); 125 ps.toString(); 126 ps[0] = Point.createPoint(1, 2); 127 ps[1] = Point.createPoint(3, 4); 128 boolean sawOob = false; 129 try { 130 ps[2] = Point.createPoint(0, 0); 131 } catch (ArrayIndexOutOfBoundsException aioobe) { sawOob = true; } 132 assertTrue(sawOob, "Didn't see AIOOBE"); 133 System.gc(); // check that VTs survive GC 134 return ps; 135 } 136 137 static void checkSimplePointArray(Point[] points) { 138 assertEquals(points[0].x, 1, "invalid 0 point x value"); 139 assertEquals(points[0].y, 2, "invalid 0 point y value"); 140 assertEquals(points[1].x, 3, "invalid 1 point x value"); 141 assertEquals(points[1].y, 4, "invalid 1 point y value"); 142 } 143 144 void testLong8Array() { 145 Long8Value[] values = new Long8Value[3]; 146 assertEquals(values.length, 3, "length"); 147 values.toString(); 148 Long8Value value = values[1]; 149 long zl = 0; 150 Long8Value.check(value, zl, zl, zl, zl, zl, zl, zl, zl); 151 values[1] = Long8Value.create(1, 2, 3, 4, 5, 6, 7, 8); 152 value = values[1]; 153 Long8Value.check(value, 1, 2, 3, 4, 5, 6, 7, 8); 154 155 Long8Value[] copy = new Long8Value[values.length]; 156 System.arraycopy(values, 0, copy, 0, values.length); 157 value = copy[1]; 158 Long8Value.check(value, 1, 2, 3, 4, 5, 6, 7, 8); 159 } 160 161 void testMixedPersonArray() { 162 Person[] people = new Person[3]; 163 164 people[0] = Person.create(1, "First", "Last"); 165 assertEquals(people[0].getId(), 1, "Invalid Id person"); 166 assertEquals(people[0].getFirstName(), "First", "Invalid First Name"); 167 assertEquals(people[0].getLastName(), "Last", "Invalid Last Name"); 168 169 people[1] = Person.create(2, "Jane", "Wayne"); 170 people[2] = Person.create(3, "Bob", "Dobalina"); 171 172 Person[] peopleCopy = new Person[people.length]; 173 System.arraycopy(people, 0, peopleCopy, 0, people.length); 174 assertEquals(peopleCopy[2].getId(), 3, "Invalid Id"); 175 assertEquals(peopleCopy[2].getFirstName(), "Bob", "Invalid First Name"); 176 assertEquals(peopleCopy[2].getLastName(), "Dobalina", "Invalid Last Name"); 177 } 178 179 void testMultiDimPointArray() { 180 Point[][][] multiPoints = new Point[2][3][4]; 181 assertEquals(multiPoints.length, 2, "1st dim length"); 182 assertEquals(multiPoints[0].length, 3, "2st dim length"); 183 assertEquals(multiPoints[0][0].length, 4, "3rd dim length"); 184 185 Point defaultPoint = multiPoints[1][2][3]; 186 assertEquals(defaultPoint.x, 0, "invalid point x value"); 187 assertEquals(defaultPoint.y, 0, "invalid point x value"); 188 } 189 190 void testReflectArray() { 191 // Check the java.lang.reflect.Array.newInstance methods... 192 Class<?> cls = (Class<?>) Point[].class; 193 Point[][] array = (Point[][]) Array.newInstance(cls, 1); 194 assertEquals(array.length, 1, "Incorrect length"); 195 assertTrue(array[0] == null, "Expected NULL"); 196 197 Point[][][] array3 = (Point[][][]) Array.newInstance(cls, 1, 2); 198 assertEquals(array3.length, 1, "Incorrect length"); 199 assertEquals(array3[0].length, 2, "Incorrect length"); 200 assertTrue(array3[0][0] == null, "Expected NULL"); 201 202 // Now create ObjArrays of ValueArray... 203 cls = (Class<?>) Point.class.asNullableType(); 204 Point?[][] barray = (Point?[][]) Array.newInstance(cls, 1, 2); 205 assertEquals(barray.length, 1, "Incorrect length"); 206 assertEquals(barray[0].length, 2, "Incorrect length"); 207 barray[0][1] = Point.createPoint(1, 2); 208 Point? pb = barray[0][1]; 209 int x = pb.getX(); 210 assertEquals(x, 1, "Bad Point Value"); 211 } 212 213 static final inline class MyInt implements Comparable<MyInt?> { 214 final int value; 215 216 private MyInt() { value = 0; } 217 public int getValue() { return value; } 218 public String toString() { return "MyInt: " + getValue(); } 219 public int compareTo(MyInt? that) { return Integer.compare(this.getValue(), that.getValue()); } 220 public boolean equals(Object o) { 221 if (o instanceof MyInt) { 222 return this.getValue() == ((MyInt) o).getValue(); 223 } 224 return false; 225 } 226 227 public static MyInt create(int v) { 228 MyInt mi = MyInt.default; 229 mi = __WithField(mi.value, v); 230 return mi; 231 } 232 233 // Null-able fields here are a temp hack to avoid ClassCircularityError 234 public static final MyInt? MIN = MyInt.create(Integer.MIN_VALUE); 235 public static final MyInt? ZERO = MyInt.create(0); 236 public static final MyInt? MAX = MyInt.create(Integer.MAX_VALUE); 237 } 238 239 static MyInt staticMyInt = MyInt.create(-1); 240 static MyInt[] staticMyIntArray = new MyInt[] { staticMyInt }; 241 static MyInt[][] staticMyIntArrayArray = new MyInt[][] { staticMyIntArray, staticMyIntArray }; 242 243 static interface SomeSecondaryType { 244 default String hi() { return "Hi"; } 245 } 246 247 static final inline class MyOtherInt implements SomeSecondaryType { 248 final int value; 249 private MyOtherInt() { value = 0; } 250 } 251 252 void testSanityCheckcasts() { 253 MyInt[] myInts = new MyInt[1]; 254 assertTrue(myInts instanceof Object[]); 255 assertTrue(myInts instanceof Comparable[]); 256 assertTrue(myInts instanceof MyInt?[]); 257 258 Class<?> cls = MyInt.class.asPrimaryType(); 259 assertTrue(cls.isInlineClass()); 260 Object arrObj = Array.newInstance(cls, 1); 261 assertTrue(arrObj instanceof Object[], "Not Object array"); 262 assertTrue(arrObj instanceof Comparable[], "Not Comparable array"); 263 assertTrue(arrObj instanceof MyInt[], "Not MyInt array"); 264 265 Object[] arr = (Object[]) arrObj; 266 assertTrue(arr instanceof Comparable[], "Not Comparable array"); 267 assertTrue(arr instanceof MyInt[], "Not MyInt array"); 268 Comparable[] comparables = (Comparable[])arr; 269 MyInt[] myIntArr = (MyInt[]) arr; 270 271 // multi-dim, check secondary array types are setup... 272 MyOtherInt[][] matrix = new MyOtherInt[1][1]; 273 assertTrue(matrix[0] instanceof MyOtherInt[]); 274 assertTrue(matrix[0] instanceof SomeSecondaryType[]); 275 assertTrue(matrix[0] instanceof MyOtherInt?[]); 276 277 // Box types vs Inline... 278 MyInt?[] myValueRefs = new MyInt?[1]; 279 assertTrue(myValueRefs instanceof MyInt?[]); 280 assertTrue(myValueRefs instanceof Object[]); 281 assertTrue(myValueRefs instanceof Comparable[]); 282 assertFalse(myValueRefs instanceof MyInt[]); 283 284 MyInt?[][] myMdValueRefs = new MyInt?[1][1]; 285 assertTrue(myMdValueRefs[0] instanceof MyInt?[]); 286 assertTrue(myMdValueRefs[0] instanceof Object[]); 287 assertTrue(myMdValueRefs[0] instanceof Comparable[]); 288 assertFalse(myMdValueRefs[0] instanceof MyInt[]); 289 290 // Did we break checkcast... 291 MyInt?[] va1 = (MyInt?[])null; 292 MyInt?[] va2 = null; 293 MyInt?[][] va3 = (MyInt?[][])null; 294 MyInt?[][][] va4 = (MyInt?[][][])null; 295 MyInt[] va5 = null; 296 MyInt[] va6 = (MyInt[])null; 297 MyInt[][] va7 = (MyInt[][])null; 298 MyInt[][][] va8 = (MyInt[][][])null; 299 } 300 301 302 void testUtilArrays() { 303 // Sanity check j.u.Arrays 304 305 // cast to q-type temp effect of avoiding circularity error (decl static MyInt?) 306 MyInt[] myInts = new MyInt[] { (MyInt) MyInt.MAX, (MyInt) MyInt.MIN }; 307 // Sanity sort another copy 308 MyInt[] copyMyInts = Arrays.copyOf(myInts, myInts.length + 1); 309 checkArrayElementsEqual(copyMyInts, new MyInt[] { myInts[0], myInts[1], (MyInt) MyInt.ZERO}); 310 311 Arrays.sort(copyMyInts); 312 checkArrayElementsEqual(copyMyInts, new MyInt[] { (MyInt) MyInt.MIN, (MyInt) MyInt.ZERO, (MyInt) MyInt.MAX }); 313 314 List myIntList = Arrays.asList(copyMyInts); 315 checkArrayElementsEqual(copyMyInts, myIntList.toArray(new MyInt[copyMyInts.length])); 316 // This next line needs testMixedLayoutArrays to work 317 checkArrayElementsEqual(copyMyInts, myIntList.toArray()); 318 319 // Sanity check j.u.ArrayList 320 ArrayList<MyInt> aList = new ArrayList<MyInt>(Arrays.asList(copyMyInts)); 321 assertTrue(aList.indexOf(MyInt.MIN) == 0, "Bad Index"); 322 assertTrue(aList.indexOf(MyInt.ZERO) == 1, "Bad Index"); 323 assertTrue(aList.indexOf(MyInt.MAX) == 2, "Bad Index"); 324 325 aList.remove(2); 326 aList.add(MyInt.create(5)); 327 } 328 329 330 void testObjectArrayOfValues() { 331 testSanityObjectArrays(); 332 testMixedLayoutArrays(); 333 } 334 335 void testSanityObjectArrays() { 336 Object[] objects = new Object[2]; 337 assertTrue(objects[0] == null && objects[1] == null, "Not null ?"); 338 339 objects[0] = MyInt.create(1); 340 objects[1] = Integer.valueOf(2); 341 assertTrue(objects[0].equals(MyInt.create(1)), "Bad Value"); 342 assertTrue(objects[1].equals(Integer.valueOf(2)), "Bad Object"); 343 344 Comparable[] copyComparables = new Comparable[objects.length]; 345 System.arraycopy(objects, 0, copyComparables, 0, objects.length); 346 checkArrayElementsEqual(objects, copyComparables); 347 348 objects[0] = null; 349 objects[1] = null; 350 assertTrue(objects[0] == null && objects[1] == null, "Not null ?"); 351 352 Comparable[] comparables = new Comparable[2]; 353 assertTrue(comparables[0] == null && comparables[1] == null, "Not null ?"); 354 comparables[0] = MyInt.create(3); 355 comparables[1] = Integer.valueOf(4); 356 assertTrue(comparables[0].equals(MyInt.create(3)), "Bad Value"); 357 assertTrue(comparables[1].equals(Integer.valueOf(4)), "Bad Object"); 358 359 Object[] copyObjects = new Object[2]; 360 System.arraycopy(comparables, 0, copyObjects, 0, comparables.length); 361 checkArrayElementsEqual(comparables, copyObjects); 362 363 comparables[0] = null; 364 comparables[1] = null; 365 assertTrue(comparables[0] == null && comparables[1] == null, "Not null ?"); 366 367 MyInt?[] myIntRefArray = new MyInt?[1]; 368 assertTrue(myIntRefArray[0] == null, "Got: " + myIntRefArray[0]); 369 myIntRefArray[0] = null; 370 371 MyInt?[] srcNulls = new MyInt?[2]; 372 MyInt?[] dstNulls = new MyInt?[2]; 373 System.arraycopy(srcNulls, 0, dstNulls, 0, 2); 374 checkArrayElementsEqual(srcNulls, dstNulls); 375 srcNulls[1] = MyInt.create(1); 376 System.arraycopy(srcNulls, 0, dstNulls, 0, 2); 377 checkArrayElementsEqual(srcNulls, dstNulls); 378 } 379 380 void testMixedLayoutArrays() { 381 Object[] objArray = new Object[3]; 382 Comparable[] compArray = new Comparable[3]; 383 MyInt[] valArray = new MyInt[] { (MyInt) MyInt.MIN, (MyInt) MyInt.ZERO, (MyInt) MyInt.MAX }; 384 385 arrayCopy(valArray, 0, objArray, 0, 3); 386 checkArrayElementsEqual(valArray, objArray); 387 arrayCopy(valArray, 0, objArray, 0, 3); 388 389 objArray = new Object[3]; 390 System.arraycopy(valArray, 0, objArray, 0, 3); 391 checkArrayElementsEqual(valArray, objArray); 392 393 System.arraycopy(valArray, 0, compArray, 0, 3); 394 checkArrayElementsEqual(valArray, compArray); 395 396 valArray = new MyInt[] { (MyInt) MyInt.ZERO, (MyInt) MyInt.ZERO, (MyInt) MyInt.ZERO }; 397 System.arraycopy(compArray, 0, valArray, 0, 3); 398 checkArrayElementsEqual(valArray, compArray); 399 400 valArray = new MyInt[] { (MyInt) MyInt.ZERO, (MyInt) MyInt.ZERO, (MyInt) MyInt.ZERO }; 401 System.arraycopy(objArray, 0, valArray, 0, 3); 402 checkArrayElementsEqual(valArray, objArray); 403 404 // Sanity check dst == src 405 System.arraycopy(valArray, 0, valArray, 0, 3); 406 checkArrayElementsEqual(valArray, objArray); 407 408 objArray[0] = "Not an inline object"; 409 try { 410 System.arraycopy(objArray, 0, valArray, 0, 3); 411 throw new RuntimeException("Expected ArrayStoreException"); 412 } catch (ArrayStoreException ase) {} 413 414 MyInt?[] myIntRefArray = new MyInt?[3]; 415 System.arraycopy(valArray, 0, myIntRefArray, 0, 3); 416 checkArrayElementsEqual(valArray, myIntRefArray); 417 418 myIntRefArray[0] = null; 419 try { 420 System.arraycopy(myIntRefArray, 0, valArray, 0, 3); 421 throw new RuntimeException("Expected NullPointerException"); 422 } catch (NullPointerException npe) {} 423 } 424 425 static final inline class MyPoint { 426 final MyInt x; 427 final MyInt y; 428 429 private MyPoint() { 430 x = (MyInt) MyInt.ZERO; 431 y = x; 432 } 433 public boolean equals(Object that) { 434 if (that instanceof MyPoint) { 435 MyPoint thatPoint = (MyPoint) that; 436 return x.equals(thatPoint.x) && java.util.Objects.equals(y, thatPoint.y); 437 } 438 return false; 439 } 440 static MyPoint create(int x) { 441 MyPoint mp = MyPoint.default; 442 mp = __WithField(mp.x, MyInt.create(x)); 443 return mp; 444 } 445 static MyPoint create(int x, int y) { 446 MyPoint mp = MyPoint.default; 447 mp = __WithField(mp.x, MyInt.create(x)); 448 mp = __WithField(mp.y, MyInt.create(y)); 449 return mp; 450 } 451 static final MyPoint? ORIGIN = create(0); 452 } 453 454 void testComposition() { 455 // Test array operations with compostion of inline types, check element payload is correct... 456 MyPoint a = MyPoint.create(1, 2); 457 MyPoint b = MyPoint.create(7, 21); 458 MyPoint c = MyPoint.create(Integer.MAX_VALUE, Integer.MIN_VALUE); 459 460 MyPoint[] pts = new MyPoint[3]; 461 if (!pts[0].equals(MyPoint.ORIGIN)) { 462 throw new RuntimeException("Equals failed: " + pts[0] + " vs " + MyPoint.ORIGIN); 463 } 464 pts = new MyPoint[] { a, b, c }; 465 checkArrayElementsEqual(pts, new Object[] { a, b, c}); 466 Object[] oarr = new Object[3]; 467 468 arrayCopy(pts, 0, oarr, 0, 3); 469 checkArrayElementsEqual(pts, oarr); 470 471 oarr = new Object[3]; 472 System.arraycopy(pts, 0, oarr, 0, 3); 473 checkArrayElementsEqual(pts, oarr); 474 475 System.arraycopy(oarr, 0, pts, 0, 3); 476 checkArrayElementsEqual(pts, oarr); 477 478 oarr = new Object[3]; 479 try { 480 System.arraycopy(oarr, 0, pts, 0, 3); 481 throw new RuntimeException("Expected NPE"); 482 } 483 catch (NullPointerException npe) {} 484 485 oarr = new Object[3]; 486 oarr[0] = new Object(); 487 try { 488 System.arraycopy(oarr, 0, pts, 0, 3); 489 throw new RuntimeException("Expected ASE"); 490 } 491 catch (ArrayStoreException ase) {} 492 } 493 494 void checkArrayElementsEqual(MyInt[] arr1, Object[] arr2) { 495 assertTrue(arr1.length == arr2.length, "Bad length"); 496 for (int i = 0; i < arr1.length; i++) { 497 assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal"); 498 } 499 } 500 501 void checkArrayElementsEqual(MyPoint[] arr1, Object[] arr2) { 502 assertTrue(arr1.length == arr2.length, "Bad length"); 503 for (int i = 0; i < arr1.length; i++) { 504 assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal"); 505 } 506 } 507 508 void checkArrayElementsEqual(Object[] arr1, Object[] arr2) { 509 assertTrue(arr1.length == arr2.length, "Bad length"); 510 for (int i = 0; i < arr1.length; i++) { 511 assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal"); 512 } 513 } 514 515 void arrayCopy(MyInt[] src, int srcPos, Object[] dst, int dstPos, int length) { 516 for (int i = 0; i < length ; i++) { 517 dst[dstPos++] = src[srcPos++]; 518 } 519 } 520 void arrayCopy(MyPoint[] src, int srcPos, Object[] dst, int dstPos, int length) { 521 for (int i = 0; i < length ; i++) { 522 dst[dstPos++] = src[srcPos++]; 523 } 524 } 525 526 Object getNull() { return null; } 527 528 }