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