1 /*
  2  * Copyright (c) 2018, 2025, 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.inlinetypes;
 25 
 26 import jdk.internal.value.ValueClass;
 27 import jdk.internal.vm.annotation.LooselyConsistentValue;
 28 import jdk.internal.vm.annotation.NullRestricted;
 29 import jdk.internal.vm.annotation.Strict;
 30 import java.lang.reflect.Array;
 31 import java.util.Arrays;
 32 import java.util.ArrayList;
 33 import java.util.List;
 34 
 35 import static jdk.test.lib.Asserts.*;
 36 
 37 /*
 38  * @test InlineTypeArray
 39  * @summary Plain array test for Inline Types
 40  * @modules java.base/jdk.internal.value
 41  *          java.base/jdk.internal.vm.annotation
 42  * @library /test/lib
 43  * @enablePreview
 44  * @compile --source 25 InlineTypeArray.java Point.java Long8Inline.java Person.java
 45  * @run main/othervm -XX:+UseArrayFlattening -XX:+UseFieldFlattening runtime.valhalla.inlinetypes.InlineTypeArray
 46  * @run main/othervm -XX:-UseArrayFlattening runtime.valhalla.inlinetypes.InlineTypeArray
 47  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* runtime.valhalla.inlinetypes.InlineTypeArray
 48  * @run main/othervm -XX:+UseArrayFlattening -XX:+UseFieldFlattening -XX:+UseNullableValueFlattening runtime.valhalla.inlinetypes.InlineTypeArray
 49  */
 50 public class InlineTypeArray {
 51     public static void main(String[] args) {
 52         InlineTypeArray inlineTypeArray = new InlineTypeArray();
 53         inlineTypeArray.run();
 54     }
 55 
 56     public void run() {
 57         testClassForName();
 58         testSimplePointArray();
 59         testLong8Array();
 60         testMixedPersonArray();
 61         testMultiDimPointArray();
 62         testComposition();
 63 
 64         testSanityCheckcasts();
 65         testObjectArrayOfInlines();
 66 
 67         testReflectArray();
 68         testUtilArraysOnNullRestrictedNonAtomicArrays();
 69         testUtilArraysOnNullRestrictedAtomicArrays();
 70         testUtilArraysOnNullableAtomicArrays();
 71 
 72         testInlineArrayOom();
 73     }
 74 
 75     void testClassForName() {
 76         String arrayClsName = "[Lruntime.valhalla.inlinetypes.Point;";
 77         try {
 78             Class<?> arrayCls = Class.forName(arrayClsName);
 79             assertTrue(arrayCls.isArray(), "Expected an array class");
 80 
 81             arrayClsName = "[" + arrayClsName;
 82             Class<?> mulArrayCls = Class.forName(arrayClsName);
 83             assertTrue(mulArrayCls.isArray());
 84             assertTrue(mulArrayCls.getComponentType() == arrayCls);
 85         }
 86         catch (ClassNotFoundException cnfe) {
 87             fail("Class.forName(" + arrayClsName + ") failed", cnfe);
 88         }
 89     }
 90 
 91     void testSimplePointArray() {
 92         Point[] defaultPoint = (Point[])ValueClass.newNullRestrictedNonAtomicArray(Point.class, 1, new Point(0, 0));
 93         Point p = defaultPoint[0];
 94         assertEquals(p.x, 0, "invalid default loaded from array");
 95         assertEquals(p.y, 0, "invalid default loaded from array");
 96         boolean gotNpe = false;
 97         try {
 98             defaultPoint[0] = (Point) getNull();
 99         } catch (NullPointerException npe) {
100             gotNpe = true;
101         }
102         assertTrue(gotNpe, "Expected NullPointerException");
103 
104         Point[] points = createSimplePointArray();
105         System.gc(); // check that VTs survive GC
106         checkSimplePointArray(points);
107         assertTrue(points instanceof Point[], "Instance of");
108 
109         testSimplePointArrayCopy();
110 
111         // Locked/unlocked flat array type checks
112         points = createSimplePointArray();
113         Point[] pointsCopy = (Point[])ValueClass.newNullRestrictedNonAtomicArray(Point.class, points.length, new Point(0, 0));
114         synchronized (points) {
115             assertTrue(points instanceof Point[], "Instance of");
116             checkSimplePointArray(points);
117             System.arraycopy(points, 0, pointsCopy, 0, points.length);
118             synchronized (pointsCopy) {
119                 assertTrue(pointsCopy instanceof Point[], "Instance of");
120                 checkSimplePointArray(pointsCopy);
121                 System.gc();
122             }
123             System.gc();
124         }
125         assertTrue(pointsCopy instanceof Point[], "Instance of");
126         checkSimplePointArray(pointsCopy);
127     }
128 
129     void testSimplePointArrayCopy() {
130         Point[] points = createSimplePointArray();
131         Point[] pointsCopy = (Point[])ValueClass.newNullRestrictedNonAtomicArray(Point.class, points.length, new Point(0, 0));
132         System.arraycopy(points, 0, pointsCopy, 0, points.length);
133         checkSimplePointArray(pointsCopy);
134 
135         // Conjoint, overlap...left
136         System.arraycopy(points, 0, points, 1, 2);
137         checkArrayElementsEqual(points, new Point[] { pointsCopy[0], pointsCopy[0], pointsCopy[1], pointsCopy[3] });
138 
139         // Conjoint, overlap...right
140         points = createSimplePointArray();
141         System.arraycopy(points, 2, points, 1, 2);
142         checkArrayElementsEqual(points, new Point[] { pointsCopy[0], pointsCopy[2], pointsCopy[3], pointsCopy[3] });
143     }
144 
145     static Point[] createSimplePointArray() {
146         Point[] ps = (Point[])ValueClass.newNullRestrictedNonAtomicArray(Point.class, 4, new Point(0, 0));
147         assertEquals(ps.length, 4, "Length");
148         ps.toString();
149         ps[0] = new Point(1, 2);
150         ps[1] = new Point(3, 4);
151         ps[2] = new Point(5, 6);
152         ps[3] = new Point(7, 8);
153         boolean sawOob = false;
154         try {
155             ps[ps.length] = new Point(0, 0);
156         } catch (ArrayIndexOutOfBoundsException aioobe) { sawOob = true; }
157         assertTrue(sawOob, "Didn't see AIOOBE");
158         return ps;
159     }
160 
161     static void checkSimplePointArray(Point[] points) {
162         assertEquals(points[0].x, 1, "invalid 0 point x value");
163         assertEquals(points[0].y, 2, "invalid 0 point y value");
164         assertEquals(points[1].x, 3, "invalid 1 point x value");
165         assertEquals(points[1].y, 4, "invalid 1 point y value");
166         assertEquals(points[2].x, 5, "invalid 2 point x value");
167         assertEquals(points[2].y, 6, "invalid 2 point y value");
168         assertEquals(points[3].x, 7, "invalid 3 point x value");
169         assertEquals(points[3].y, 8, "invalid 3 point y value");
170     }
171 
172     void testLong8Array() {
173         Long8Inline[] values = (Long8Inline[])ValueClass.newNullRestrictedNonAtomicArray(Long8Inline.class, 3, new Long8Inline());
174         assertEquals(values.length, 3, "length");
175         values.toString();
176         Long8Inline value = values[1];
177         long zl = 0;
178         Long8Inline.check(value, zl, zl, zl, zl, zl, zl, zl, zl);
179         values[1] = new Long8Inline(1, 2, 3, 4, 5, 6, 7, 8);
180         value = values[1];
181         Long8Inline.check(value, 1, 2, 3, 4, 5, 6, 7, 8);
182 
183         Long8Inline[] copy = (Long8Inline[])ValueClass.newNullRestrictedNonAtomicArray(Long8Inline.class, values.length, new Long8Inline());
184         System.arraycopy(values, 0, copy, 0, values.length);
185         value = copy[1];
186         Long8Inline.check(value, 1, 2, 3, 4, 5, 6, 7, 8);
187     }
188 
189     void testMixedPersonArray() {
190         Person[] people = (Person[])ValueClass.newNullRestrictedNonAtomicArray(Person.class, 3, new Person(0, null, null));
191 
192         people[0] = new Person(1, "First", "Last");
193         assertEquals(people[0].getId(), 1, "Invalid Id person");
194         assertEquals(people[0].getFirstName(), "First", "Invalid First Name");
195         assertEquals(people[0].getLastName(), "Last", "Invalid Last Name");
196 
197         people[1] = new Person(2, "Jane", "Wayne");
198         people[2] = new Person(3, "Bob", "Dobalina");
199 
200         Person[] peopleCopy = (Person[])ValueClass.newNullRestrictedNonAtomicArray(Person.class, people.length, new Person(0, null, null));
201         System.arraycopy(people, 0, peopleCopy, 0, people.length);
202         assertEquals(peopleCopy[2].getId(), 3, "Invalid Id");
203         assertEquals(peopleCopy[2].getFirstName(), "Bob", "Invalid First Name");
204         assertEquals(peopleCopy[2].getLastName(), "Dobalina", "Invalid Last Name");
205     }
206 
207     void testMultiDimPointArray() {
208         /*
209         Point[][][] multiPoints = new Point[2][3][4];
210         assertEquals(multiPoints.length, 2, "1st dim length");
211         assertEquals(multiPoints[0].length, 3, "2st dim length");
212         assertEquals(multiPoints[0][0].length, 4, "3rd dim length");
213 
214         Point defaultPoint = multiPoints[1][2][3];
215         assertEquals(defaultPoint.x, 0, "invalid point x value");
216         assertEquals(defaultPoint.y, 0, "invalid point x value");
217         */
218     }
219 
220     void testReflectArray() {
221         // Check the java.lang.reflect.Array.newInstance methods...
222         Class<?> cls = (Class<?>) Point[].class;
223         Point[][] array = (Point[][]) Array.newInstance(cls, 1);
224         assertEquals(array.length, 1, "Incorrect length");
225         assertTrue(array[0] == null, "Expected NULL");
226 
227         Point[][][] array3 = (Point[][][]) Array.newInstance(cls, 1, 2);
228         assertEquals(array3.length, 1, "Incorrect length");
229         assertEquals(array3[0].length, 2, "Incorrect length");
230         assertTrue(array3[0][0] == null, "Expected NULL");
231 
232         // Now create ObjArrays of InlineArray...
233         Point[][] barray = (Point[][]) Array.newInstance(Point.class, 1, 2);
234         assertEquals(barray.length, 1, "Incorrect length");
235         assertEquals(barray[0].length, 2, "Incorrect length");
236         barray[0][1] = new Point(1, 2);
237         Point pb = barray[0][1];
238         int x = pb.getX();
239         assertEquals(x, 1, "Bad Point Value");
240     }
241 
242     @LooselyConsistentValue
243     static value class MyInt implements Comparable<MyInt> {
244         int value;
245 
246         private MyInt() { this(0); }
247         private MyInt(int v) { value = v; }
248         public int getValue() { return value; }
249         public String toString() { return "MyInt: " + getValue(); }
250         public int compareTo(MyInt that) { return Integer.compare(this.getValue(), that.getValue()); }
251         public boolean equals(Object o) {
252             if (o instanceof MyInt) {
253                 return this.getValue() == ((MyInt) o).getValue();
254             }
255             return false;
256         }
257 
258         public static MyInt create(int v) {
259             return new MyInt(v);
260         }
261 
262         public static final MyInt MIN = MyInt.create(Integer.MIN_VALUE);
263         public static final MyInt ZERO = MyInt.create(0);
264         public static final MyInt MAX = MyInt.create(Integer.MAX_VALUE);
265     }
266 
267     static MyInt staticMyInt;
268     static MyInt[] staticMyIntArray;
269     static MyInt[][] staticMyIntArrayArray;
270 
271     static {
272         staticMyInt = MyInt.create(-1);
273         staticMyIntArray = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 1, new MyInt());
274         staticMyIntArray[0] = staticMyInt;
275         staticMyIntArrayArray = new MyInt[][] { staticMyIntArray, staticMyIntArray };
276     }
277 
278     static value class MyShorts implements Comparable<MyShorts> {
279         short s0, s1;
280 
281         private MyShorts() { this((short)0, (short)0); }
282         private MyShorts(short sa, short sb) { s0 = sa; s1 = sb; }
283         public short getS0() { return s0; }
284         public short getS1() { return s1; }
285         public String toString() { return "MyShorts: " + getS0() + " " + getS1(); }
286         public int compareTo(MyShorts that) {
287             int r = Short.compare(this.getS0(), that.getS0());
288             return r != 0 ? r : Short.compare(this.getS1(), that.getS1());
289         }
290         public boolean equals(Object o) {
291             if (o instanceof MyShorts) {
292                 return this.getS0() == ((MyShorts) o).getS0() && this.getS1() == ((MyShorts) o).getS1();
293             }
294             return false;
295         }
296 
297         public static MyShorts create(short s0, short s1) {
298             return new MyShorts(s0, s1);
299         }
300 
301         public static final MyShorts MIN = MyShorts.create(Short.MIN_VALUE, Short.MIN_VALUE);
302         public static final MyShorts ZERO = MyShorts.create((short)0, (short)0);
303         public static final MyShorts MAX = MyShorts.create(Short.MAX_VALUE, Short.MAX_VALUE);
304     }
305 
306     static interface SomeSecondaryType {
307         default String hi() { return "Hi"; }
308     }
309 
310     @LooselyConsistentValue
311     static value class MyOtherInt implements SomeSecondaryType {
312         final int value;
313         private MyOtherInt() { value = 0; }
314     }
315 
316     void testSanityCheckcasts() {
317         MyInt[] myInts = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 1, new MyInt());
318         assertTrue(myInts instanceof Object[]);
319         assertTrue(myInts instanceof Comparable[]);
320         assertTrue(myInts instanceof MyInt[]);
321 
322         Class<?> cls = MyInt.class;
323         assertTrue(cls.isValue());
324         Object arrObj = Array.newInstance(cls, 1);
325         assertTrue(arrObj instanceof Object[], "Not Object array");
326         assertTrue(arrObj instanceof Comparable[], "Not Comparable array");
327         assertTrue(arrObj instanceof MyInt[], "Not MyInt array");
328 
329         Object[] arr = (Object[]) arrObj;
330         assertTrue(arr instanceof Comparable[], "Not Comparable array");
331         assertTrue(arr instanceof MyInt[], "Not MyInt array");
332         Comparable[] comparables = (Comparable[])arr;
333         MyInt[] myIntArr = (MyInt[]) arr;
334 
335         // multi-dim, check secondary array types are setup...
336         MyOtherInt[][] matrix = new MyOtherInt[1][1];
337         assertTrue(matrix[0] instanceof MyOtherInt[]);
338         assertTrue(matrix[0] instanceof SomeSecondaryType[]);
339         assertTrue(matrix[0] instanceof MyOtherInt[]);
340 
341         // Box types vs Inline...
342         MyInt[] myValueRefs = new MyInt[1];
343         assertTrue(myValueRefs instanceof MyInt[]);
344         assertTrue(myValueRefs instanceof Object[]);
345         assertTrue(myValueRefs instanceof Comparable[]);
346 
347         MyInt[][] myMdValueRefs = new MyInt[1][1];
348         assertTrue(myMdValueRefs[0] instanceof MyInt[]);
349         assertTrue(myMdValueRefs[0] instanceof Object[]);
350         assertTrue(myMdValueRefs[0] instanceof Comparable[]);
351 
352         // Did we break checkcast...
353         MyInt[]     va1 = (MyInt[])null;
354         MyInt[]     va2 = null;
355         MyInt[][]   va3 = (MyInt[][])null;
356         MyInt[][][] va4 = (MyInt[][][])null;
357     }
358 
359 
360     void testUtilArraysOnNullRestrictedNonAtomicArrays() {
361         // Sanity check j.u.Arrays
362 
363         // Testing Arrays.copyOf()
364         MyInt[] myInts = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 3, new MyInt());
365         myInts[0] = MyInt.MAX;
366         myInts[1] = MyInt.MIN;
367         myInts[2] = MyInt.ZERO;
368 
369         // Copy of same length, must work
370         MyInt[] copyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length);
371         MyInt[] expected = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 3, new MyInt());
372         expected[0] = myInts[0];
373         expected[1] = myInts[1];
374         expected[2] = myInts[2];
375         checkArrayElementsEqual(copyMyInts, expected);
376 
377         // Copy of shorter length, must work
378         MyInt[] smallCopyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length - 1);
379         MyInt[] expected2 = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 2, new MyInt());
380         expected2[0] = myInts[0];
381         expected2[1] = myInts[1];
382         checkArrayElementsEqual(smallCopyMyInts, expected2);
383 
384         // Copy of bigger length, must fail for null-restricted arrays
385         IllegalArgumentException iae = null;
386         try {
387             MyInt[] bigCopyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length + 1);
388         } catch (IllegalArgumentException e) {
389             iae = e;
390         }
391         assertTrue(iae != null, "Exception not received");
392 
393         // Testing Arrays.copyOfRange()
394         MyInt[] fullRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 0, myInts.length);
395         checkArrayElementsEqual(copyMyInts, expected);
396 
397         MyInt[] beginningRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 0, 2);
398         checkArrayElementsEqual(beginningRangeCopy, expected2);
399 
400 
401         MyInt[] endingRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 1, myInts.length);
402         MyInt[] expected3 = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 2, new MyInt());
403         expected3[0] = myInts[1];
404         expected3[1] = myInts[2];
405         checkArrayElementsEqual(endingRangeCopy, expected3);
406 
407         // Range exceeding initial array's length, must fail for null-restricted arrays
408         iae = null;
409         try {
410             MyInt[] exceedingRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 1, myInts.length + 1);
411         } catch (IllegalArgumentException e) {
412             iae = e;
413         }
414         assertTrue(iae != null, "Exception not received");
415 
416         // Range starting after the end of the original array, must fail for null-restricted arrays
417         iae = null;
418         try {
419             MyInt[] farRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, myInts.length, myInts.length + 1);
420         } catch (IllegalArgumentException e) {
421             iae = e;
422         }
423         assertTrue(iae != null, "Exception not received");
424 
425         Arrays.sort(copyMyInts);
426         expected = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 3, new MyInt());
427         expected[0] = (MyInt) MyInt.MIN;
428         expected[1] = (MyInt) MyInt.ZERO;
429         expected[2] = (MyInt) MyInt.MAX;
430         checkArrayElementsEqual(copyMyInts, expected);
431 
432         List myIntList = Arrays.asList(copyMyInts);
433 
434         MyInt[] dest = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, copyMyInts.length, new MyInt());
435         checkArrayElementsEqual(copyMyInts, myIntList.toArray(dest));
436         // This next line needs testMixedLayoutArrays to work
437         checkArrayElementsEqual(copyMyInts, myIntList.toArray());
438 
439         // Sanity check j.u.ArrayList
440         ArrayList<MyInt> aList = new ArrayList<MyInt>(Arrays.asList(copyMyInts));
441         assertTrue(aList.indexOf(MyInt.MIN) == 0, "Bad Index");
442         assertTrue(aList.indexOf(MyInt.ZERO) == 1, "Bad Index");
443         assertTrue(aList.indexOf(MyInt.MAX) == 2, "Bad Index");
444 
445         aList.remove(2);
446         aList.add(MyInt.create(5));
447     }
448 
449     void testUtilArraysOnNullRestrictedAtomicArrays() {
450         // Sanity check j.u.Arrays
451 
452         // Testing Arrays.copyOf()
453         MyShorts[] myShorts = (MyShorts[])ValueClass.newNullRestrictedAtomicArray(MyShorts.class, 3, new MyShorts());
454         myShorts[0] = MyShorts.MAX;
455         myShorts[1] = MyShorts.MIN;
456         myShorts[2] = MyShorts.ZERO;
457 
458         // Copy of same length, must work
459         MyShorts[] copyMyInts = (MyShorts[]) Arrays.copyOf(myShorts, myShorts.length);
460         MyShorts[] expected = (MyShorts[])ValueClass.newNullRestrictedAtomicArray(MyShorts.class, 3, new MyShorts());
461         expected[0] = myShorts[0];
462         expected[1] = myShorts[1];
463         expected[2] = myShorts[2];
464         checkArrayElementsEqual(copyMyInts, expected);
465 
466         // Copy of shorter length, must work
467         MyShorts[] smallCopyMyInts = (MyShorts[]) Arrays.copyOf(myShorts, myShorts.length - 1);
468         MyShorts[] expected2 = (MyShorts[])ValueClass.newNullRestrictedAtomicArray(MyShorts.class, 2, new MyShorts());
469         expected2[0] = myShorts[0];
470         expected2[1] = myShorts[1];
471         checkArrayElementsEqual(smallCopyMyInts, expected2);
472 
473         // Copy of bigger length, must fail for null-restricted arrays
474         IllegalArgumentException iae = null;
475         try {
476             MyShorts[] bigCopyMyInts = (MyShorts[]) Arrays.copyOf(myShorts, myShorts.length + 1);
477         } catch (IllegalArgumentException e) {
478             iae = e;
479         }
480         assertTrue(iae != null, "Exception not received");
481 
482         // Testing Arrays.copyOfRange()
483         MyShorts[] fullRangeCopy = (MyShorts[]) Arrays.copyOfRange(myShorts, 0, myShorts.length);
484         checkArrayElementsEqual(copyMyInts, expected);
485 
486         MyShorts[] beginningRangeCopy = (MyShorts[]) Arrays.copyOfRange(myShorts, 0, 2);
487         checkArrayElementsEqual(beginningRangeCopy, expected2);
488 
489 
490         MyShorts[] endingRangeCopy = (MyShorts[]) Arrays.copyOfRange(myShorts, 1, myShorts.length);
491         MyShorts[] expected3 = (MyShorts[])ValueClass.newNullRestrictedAtomicArray(MyShorts.class, 2, new MyShorts());
492         expected3[0] = myShorts[1];
493         expected3[1] = myShorts[2];
494         checkArrayElementsEqual(endingRangeCopy, expected3);
495 
496         // Range exceeding initial array's length, must fail for null-restricted arrays
497         iae = null;
498         try {
499             MyShorts[] exceedingRangeCopy = (MyShorts[]) Arrays.copyOfRange(myShorts, 1, myShorts.length + 1);
500         } catch (IllegalArgumentException e) {
501             iae = e;
502         }
503         assertTrue(iae != null, "Exception not received");
504 
505         // Range starting after the end of the original array, must fail for null-restricted arrays
506         iae = null;
507         try {
508             MyShorts[] farRangeCopy = (MyShorts[]) Arrays.copyOfRange(myShorts, myShorts.length, myShorts.length + 1);
509         } catch (IllegalArgumentException e) {
510             iae = e;
511         }
512         assertTrue(iae != null, "Exception not received");
513 
514         Arrays.sort(copyMyInts);
515         expected = (MyShorts[])ValueClass.newNullRestrictedAtomicArray(MyShorts.class, 3, new MyShorts());
516         expected[0] = (MyShorts) MyShorts.MIN;
517         expected[1] = (MyShorts) MyShorts.ZERO;
518         expected[2] = (MyShorts) MyShorts.MAX;
519         checkArrayElementsEqual(copyMyInts, expected);
520 
521         List myIntList = Arrays.asList(copyMyInts);
522 
523         MyShorts[] dest = (MyShorts[])ValueClass.newNullRestrictedAtomicArray(MyShorts.class, copyMyInts.length, new MyShorts());
524         checkArrayElementsEqual(copyMyInts, myIntList.toArray(dest));
525         // This next line needs testMixedLayoutArrays to work
526         checkArrayElementsEqual(copyMyInts, myIntList.toArray());
527 
528         // Sanity check j.u.ArrayList
529         ArrayList<MyShorts> aList = new ArrayList<MyShorts>(Arrays.asList(copyMyInts));
530         assertTrue(aList.indexOf(MyShorts.MIN) == 0, "Bad Index");
531         assertTrue(aList.indexOf(MyShorts.ZERO) == 1, "Bad Index");
532         assertTrue(aList.indexOf(MyShorts.MAX) == 2, "Bad Index");
533 
534         aList.remove(2);
535         aList.add(MyShorts.create((short)5, (short)7));
536     }
537 
538     void testUtilArraysOnNullableAtomicArrays() {
539         // Sanity check j.u.Arrays
540 
541         // Testing Arrays.copyOf()
542         MyInt[] myInts = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 3);
543         myInts[0] = MyInt.MAX;
544         myInts[1] = MyInt.MIN;
545         myInts[2] = MyInt.ZERO;
546 
547         // Copy of same length, must work
548         MyInt[] copyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length);
549         MyInt[] expected = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 3);
550         expected[0] = myInts[0];
551         expected[1] = myInts[1];
552         expected[2] = myInts[2];
553         checkArrayElementsEqual(copyMyInts, expected);
554 
555         // Copy of shorter length, must work
556         MyInt[] smallCopyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length - 1);
557         MyInt[] expected2 = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 2);
558         expected2[0] = myInts[0];
559         expected2[1] = myInts[1];
560         checkArrayElementsEqual(smallCopyMyInts, expected2);
561 
562         // Copy of bigger length, must work for nullable arrays
563         MyInt[] bigCopyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length + 1);
564         MyInt[] expected2b = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 4);
565         expected2b[0] = myInts[0];
566         expected2b[1] = myInts[1];
567         expected2b[2] = myInts[2];
568         expected2b[3] = null;
569         checkArrayElementsEqual(bigCopyMyInts, expected2b);
570 
571         // Testing Arrays.copyOfRange()
572         MyInt[] fullRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 0, myInts.length);
573         checkArrayElementsEqual(copyMyInts, expected);
574 
575         MyInt[] beginningRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 0, 2);
576         checkArrayElementsEqual(beginningRangeCopy, expected2);
577 
578         MyInt[] endingRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 1, myInts.length);
579         MyInt[] expected3 = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 2);
580         expected3[0] = myInts[1];
581         expected3[1] = myInts[2];
582         checkArrayElementsEqual(endingRangeCopy, expected3);
583 
584         // Range exceeding initial array's length, must succeed for nullable arrays
585         MyInt[] exceedingRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, 1, myInts.length + 1);
586         MyInt[] expected3b = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 3);
587         expected3b[0] = myInts[1];
588         expected3b[1] = myInts[2];
589         expected3b[2] = null;
590         checkArrayElementsEqual(exceedingRangeCopy, expected3b);
591 
592         // Range starting after the end of the original array, must suceed for nullable arrays
593         MyInt[] farRangeCopy = (MyInt[]) Arrays.copyOfRange(myInts, myInts.length, myInts.length + 1);
594         MyInt[] expected3c = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 1);
595         expected3c[0] = null;
596         checkArrayElementsEqual(farRangeCopy, expected3c);
597 
598         Arrays.sort(copyMyInts);
599         expected = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, 3);
600         expected[0] = (MyInt) MyInt.MIN;
601         expected[1] = (MyInt) MyInt.ZERO;
602         expected[2] = (MyInt) MyInt.MAX;
603         checkArrayElementsEqual(copyMyInts, expected);
604 
605         List myIntList = Arrays.asList(copyMyInts);
606 
607         MyInt[] dest = (MyInt[])ValueClass.newNullableAtomicArray(MyInt.class, copyMyInts.length);
608         checkArrayElementsEqual(copyMyInts, myIntList.toArray(dest));
609         // This next line needs testMixedLayoutArrays to work
610         checkArrayElementsEqual(copyMyInts, myIntList.toArray());
611 
612         // Sanity check j.u.ArrayList
613         ArrayList<MyInt> aList = new ArrayList<MyInt>(Arrays.asList(copyMyInts));
614         assertTrue(aList.indexOf(MyInt.MIN) == 0, "Bad Index");
615         assertTrue(aList.indexOf(MyInt.ZERO) == 1, "Bad Index");
616         assertTrue(aList.indexOf(MyInt.MAX) == 2, "Bad Index");
617 
618         aList.remove(2);
619         aList.add(MyInt.create(5));
620     }
621 
622     void testObjectArrayOfInlines() {
623         testSanityObjectArrays();
624         testMixedLayoutArrays();
625     }
626 
627     void testSanityObjectArrays() {
628         Object[] objects = new Object[2];
629         assertTrue(objects[0] == null && objects[1] == null, "Not null ?");
630 
631         objects[0] = MyInt.create(1);
632         objects[1] = Integer.valueOf(2);
633         assertTrue(objects[0].equals(MyInt.create(1)), "Bad Value");
634         assertTrue(objects[1].equals(Integer.valueOf(2)), "Bad Object");
635 
636         Comparable[] copyComparables = new Comparable[objects.length];
637         System.arraycopy(objects, 0, copyComparables, 0, objects.length);
638         checkArrayElementsEqual(objects, copyComparables);
639 
640         objects[0] = null;
641         objects[1] = null;
642         assertTrue(objects[0] == null && objects[1] == null, "Not null ?");
643 
644         Comparable[] comparables = new Comparable[2];
645         assertTrue(comparables[0] == null && comparables[1] == null, "Not null ?");
646         comparables[0] = MyInt.create(3);
647         comparables[1] = Integer.valueOf(4);
648         assertTrue(comparables[0].equals(MyInt.create(3)), "Bad Value");
649         assertTrue(comparables[1].equals(Integer.valueOf(4)), "Bad Object");
650 
651         Object[] copyObjects = new Object[2];
652         System.arraycopy(comparables, 0, copyObjects, 0, comparables.length);
653         checkArrayElementsEqual(comparables, copyObjects);
654 
655         comparables[0] = null;
656         comparables[1] = null;
657         assertTrue(comparables[0] == null && comparables[1] == null, "Not null ?");
658 
659         MyInt[] myIntRefArray = new MyInt[1];
660         assertTrue(myIntRefArray[0] == null, "Got: " + myIntRefArray[0]);
661         myIntRefArray[0] = null;
662 
663         MyInt[] srcNulls = new MyInt[2];
664         MyInt[] dstNulls = new MyInt[2];
665         System.arraycopy(srcNulls, 0, dstNulls, 0, 2);
666         checkArrayElementsEqual(srcNulls, dstNulls);
667         srcNulls[1] = MyInt.create(1);
668         System.arraycopy(srcNulls, 0, dstNulls, 0, 2);
669         checkArrayElementsEqual(srcNulls, dstNulls);
670 
671 
672         // Locked/unlocked flat array type checks
673         synchronized (srcNulls) {
674             System.arraycopy(srcNulls, 0, dstNulls, 0, 2);
675             checkArrayElementsEqual(srcNulls, dstNulls);
676             System.gc();
677         }
678         System.gc();
679         checkArrayElementsEqual(srcNulls, dstNulls);
680     }
681 
682     void testMixedLayoutArrays() {
683         Object[] objArray = new Object[3];
684         Comparable[] compArray = new Comparable[3];
685         MyInt[] valArray = new MyInt[] { (MyInt) MyInt.MIN, (MyInt) MyInt.ZERO, (MyInt) MyInt.MAX };
686 
687         arrayCopy(valArray, 0, objArray, 0, 3);
688         checkArrayElementsEqual(valArray, objArray);
689         arrayCopy(valArray, 0, objArray, 0, 3);
690 
691         objArray = new Object[3];
692         System.arraycopy(valArray, 0, objArray, 0, 3);
693         checkArrayElementsEqual(valArray, objArray);
694 
695         System.arraycopy(valArray, 0, compArray, 0, 3);
696         checkArrayElementsEqual(valArray, compArray);
697 
698         valArray = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 3, new MyInt());
699         valArray[0] = (MyInt) MyInt.ZERO;
700         valArray[1] = (MyInt) MyInt.ZERO;
701         valArray[2] = (MyInt) MyInt.ZERO;
702         System.arraycopy(compArray, 0, valArray, 0, 3);
703         checkArrayElementsEqual(valArray, compArray);
704 
705         valArray = (MyInt[])ValueClass.newNullRestrictedNonAtomicArray(MyInt.class, 3, new MyInt());
706         valArray[0] = (MyInt) MyInt.ZERO;
707         valArray[1] = (MyInt) MyInt.ZERO;
708         valArray[2] = (MyInt) MyInt.ZERO;
709         System.arraycopy(objArray, 0, valArray, 0, 3);
710         checkArrayElementsEqual(valArray, objArray);
711 
712         // Sanity check dst == src
713         System.arraycopy(valArray, 0, valArray, 0, 3);
714         checkArrayElementsEqual(valArray, objArray);
715 
716         objArray[0] = "Not an inline object";
717         try {
718             System.arraycopy(objArray, 0, valArray, 0, 3);
719             throw new RuntimeException("Expected ArrayStoreException");
720         } catch (ArrayStoreException ase) {}
721 
722         MyInt[] myIntRefArray = new MyInt[3];
723         System.arraycopy(valArray, 0, myIntRefArray, 0, 3);
724         checkArrayElementsEqual(valArray, myIntRefArray);
725 
726         myIntRefArray[0] = null;
727         try {
728             System.arraycopy(myIntRefArray, 0, valArray, 0, 3);
729             throw new RuntimeException("Expected NullPointerException");
730         } catch (NullPointerException npe) {}
731     }
732 
733     @LooselyConsistentValue
734     static value class MyPoint {
735         @Strict
736         @NullRestricted
737         MyInt x;
738         @Strict
739         @NullRestricted
740         MyInt y;
741 
742         private MyPoint() { this(0, 0); }
743         private MyPoint(int x, int y) {
744             this.x = new MyInt(x);
745             this.y = new MyInt(y);
746         }
747         public boolean equals(Object that) {
748             if (that instanceof MyPoint) {
749                 MyPoint thatPoint = (MyPoint) that;
750                 return x.equals(thatPoint.x) && java.util.Objects.equals(y, thatPoint.y);
751             }
752             return false;
753         }
754         static MyPoint create(int x) {
755             return new MyPoint(x, x);
756         }
757         static MyPoint create(int x, int y) {
758             return new MyPoint(x, y);
759         }
760         @Strict
761         @NullRestricted
762         static final MyPoint ORIGIN = create(0);
763     }
764 
765     void testComposition() {
766         // Test array operations with compostion of inline types, check element payload is correct...
767         MyPoint a = MyPoint.create(1, 2);
768         MyPoint b = MyPoint.create(7, 21);
769         MyPoint c = MyPoint.create(Integer.MAX_VALUE, Integer.MIN_VALUE);
770 
771         MyPoint[] pts = (MyPoint[])ValueClass.newNullRestrictedNonAtomicArray(MyPoint.class, 3, new MyPoint());
772         if (!pts[0].equals(MyPoint.ORIGIN)) {
773             throw new RuntimeException("Equals failed: " + pts[0] + " vs " + MyPoint.ORIGIN);
774         }
775         pts = (MyPoint[])ValueClass.newNullRestrictedNonAtomicArray(MyPoint.class, 3, new MyPoint());
776         pts[0] = a;
777         pts[1] = b;
778         pts[2] = c;
779         checkArrayElementsEqual(pts, new Object[] { a, b, c});
780         Object[] oarr = new Object[3];
781 
782         arrayCopy(pts, 0, oarr, 0, 3);
783         checkArrayElementsEqual(pts, oarr);
784 
785         oarr = new Object[3];
786         System.arraycopy(pts, 0, oarr, 0, 3);
787         checkArrayElementsEqual(pts, oarr);
788 
789         System.arraycopy(oarr, 0, pts, 0, 3);
790         checkArrayElementsEqual(pts, oarr);
791 
792         oarr = new Object[3];
793         try {
794             System.arraycopy(oarr, 0, pts, 0, 3);
795             throw new RuntimeException("Expected NPE");
796         }
797         catch (NullPointerException npe) {}
798 
799         oarr = new Object[3];
800         oarr[0] = new Object();
801         try {
802             System.arraycopy(oarr, 0, pts, 0, 3);
803             throw new RuntimeException("Expected ASE");
804         }
805         catch (ArrayStoreException ase) {}
806     }
807 
808     void checkArrayElementsEqual(MyInt[] arr1, Object[] arr2) {
809         assertTrue(arr1.length == arr2.length, "Bad length");
810         for (int i = 0; i < arr1.length; i++) {
811             assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal");
812         }
813     }
814 
815     void checkArrayElementsEqual(MyPoint[] arr1, Object[] arr2) {
816         assertTrue(arr1.length == arr2.length, "Bad length");
817         for (int i = 0; i < arr1.length; i++) {
818             assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal");
819         }
820     }
821 
822     void checkArrayElementsEqual(Object[] arr1, Object[] arr2) {
823         assertTrue(arr1.length == arr2.length, "Bad length");
824         for (int i = 0; i < arr1.length; i++) {
825             assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal");
826         }
827     }
828 
829     void arrayCopy(MyInt[] src, int srcPos, Object[] dst, int dstPos, int length) {
830         for (int i = 0; i < length ; i++) {
831             dst[dstPos++] = src[srcPos++];
832         }
833     }
834     void arrayCopy(MyPoint[] src, int srcPos, Object[] dst, int dstPos, int length) {
835         for (int i = 0; i < length ; i++) {
836             dst[dstPos++] = src[srcPos++];
837         }
838     }
839 
840     Object getNull() { return null; }
841 
842 
843     void testInlineArrayOom() {
844         int size = Integer.MAX_VALUE;
845         try {
846             MyPoint[] pts = new MyPoint[size];
847             throw new RuntimeException("Excepted OOM");
848         } catch (OutOfMemoryError oom) {}
849     }
850 
851 }