1 /*
  2  * Copyright (c) 2018, 2024, 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.ImplicitlyConstructible;
 28 import jdk.internal.vm.annotation.LooselyConsistentValue;
 29 import jdk.internal.vm.annotation.NullRestricted;
 30 
 31 import java.lang.reflect.Array;
 32 import java.util.Arrays;
 33 import java.util.ArrayList;
 34 import java.util.List;
 35 
 36 import static jdk.test.lib.Asserts.*;
 37 
 38 /*
 39  * @test InlineTypeArray
 40  * @summary Plain array test for Inline Types
 41  * @modules java.base/jdk.internal.value
 42  *          java.base/jdk.internal.vm.annotation
 43  * @library /test/lib
 44  * @enablePreview
 45  * @compile --source 22 InlineTypeArray.java Point.java Long8Inline.java Person.java
 46  * @run main/othervm -XX:FlatArrayElementMaxSize=-1 runtime.valhalla.inlinetypes.InlineTypeArray
 47  * @run main/othervm -XX:FlatArrayElementMaxSize=0 runtime.valhalla.inlinetypes.InlineTypeArray
 48  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:ForceNonTearable=* 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         testUtilArrays();
 69 
 70         testInlineArrayOom();
 71     }
 72 
 73     void testClassForName() {
 74         String arrayClsName = "[Lruntime.valhalla.inlinetypes.Point;";
 75         try {
 76             Class<?> arrayCls = Class.forName(arrayClsName);
 77             assertTrue(arrayCls.isArray(), "Expected an array class");
 78 
 79             arrayClsName = "[" + arrayClsName;
 80             Class<?> mulArrayCls = Class.forName(arrayClsName);
 81             assertTrue(mulArrayCls.isArray());
 82             assertTrue(mulArrayCls.getComponentType() == arrayCls);
 83         }
 84         catch (ClassNotFoundException cnfe) {
 85             fail("Class.forName(" + arrayClsName + ") failed", cnfe);
 86         }
 87     }
 88 
 89     void testSimplePointArray() {
 90         Point[] defaultPoint = (Point[])ValueClass.newNullRestrictedArray(Point.class, 1);
 91         Point p = defaultPoint[0];
 92         assertEquals(p.x, 0, "invalid default loaded from array");
 93         assertEquals(p.y, 0, "invalid default loaded from array");
 94         boolean gotNpe = false;
 95         try {
 96             defaultPoint[0] = (Point) getNull();
 97         } catch (NullPointerException npe) {
 98             gotNpe = true;
 99         }
100         assertTrue(gotNpe, "Expected NullPointerException");
101 
102         Point[] points = createSimplePointArray();
103         System.gc(); // check that VTs survive GC
104         checkSimplePointArray(points);
105         assertTrue(points instanceof Point[], "Instance of");
106 
107         testSimplePointArrayCopy();
108 
109         // Locked/unlocked flat array type checks
110         points = createSimplePointArray();
111         Point[] pointsCopy = (Point[])ValueClass.newNullRestrictedArray(Point.class, points.length);
112         synchronized (points) {
113             assertTrue(points instanceof Point[], "Instance of");
114             checkSimplePointArray(points);
115             System.arraycopy(points, 0, pointsCopy, 0, points.length);
116             synchronized (pointsCopy) {
117                 assertTrue(pointsCopy instanceof Point[], "Instance of");
118                 checkSimplePointArray(pointsCopy);
119                 System.gc();
120             }
121             System.gc();
122         }
123         assertTrue(pointsCopy instanceof Point[], "Instance of");
124         checkSimplePointArray(pointsCopy);
125     }
126 
127     void testSimplePointArrayCopy() {
128         Point[] points = createSimplePointArray();
129         Point[] pointsCopy = (Point[])ValueClass.newNullRestrictedArray(Point.class, points.length);
130         System.arraycopy(points, 0, pointsCopy, 0, points.length);
131         checkSimplePointArray(pointsCopy);
132 
133         // Conjoint, overlap...left
134         System.arraycopy(points, 0, points, 1, 2);
135         checkArrayElementsEqual(points, new Point[] { pointsCopy[0], pointsCopy[0], pointsCopy[1], pointsCopy[3] });
136 
137         // Conjoint, overlap...right
138         points = createSimplePointArray();
139         System.arraycopy(points, 2, points, 1, 2);
140         checkArrayElementsEqual(points, new Point[] { pointsCopy[0], pointsCopy[2], pointsCopy[3], pointsCopy[3] });
141     }
142 
143     static Point[] createSimplePointArray() {
144         Point[] ps = (Point[])ValueClass.newNullRestrictedArray(Point.class, 4);
145         assertEquals(ps.length, 4, "Length");
146         ps.toString();
147         ps[0] = new Point(1, 2);
148         ps[1] = new Point(3, 4);
149         ps[2] = new Point(5, 6);
150         ps[3] = new Point(7, 8);
151         boolean sawOob = false;
152         try {
153             ps[ps.length] = new Point(0, 0);
154         } catch (ArrayIndexOutOfBoundsException aioobe) { sawOob = true; }
155         assertTrue(sawOob, "Didn't see AIOOBE");
156         return ps;
157     }
158 
159     static void checkSimplePointArray(Point[] points) {
160         assertEquals(points[0].x, 1, "invalid 0 point x value");
161         assertEquals(points[0].y, 2, "invalid 0 point y value");
162         assertEquals(points[1].x, 3, "invalid 1 point x value");
163         assertEquals(points[1].y, 4, "invalid 1 point y value");
164         assertEquals(points[2].x, 5, "invalid 2 point x value");
165         assertEquals(points[2].y, 6, "invalid 2 point y value");
166         assertEquals(points[3].x, 7, "invalid 3 point x value");
167         assertEquals(points[3].y, 8, "invalid 3 point y value");
168     }
169 
170     void testLong8Array() {
171         Long8Inline[] values = (Long8Inline[])ValueClass.newNullRestrictedArray(Long8Inline.class, 3);
172         assertEquals(values.length, 3, "length");
173         values.toString();
174         Long8Inline value = values[1];
175         long zl = 0;
176         Long8Inline.check(value, zl, zl, zl, zl, zl, zl, zl, zl);
177         values[1] = new Long8Inline(1, 2, 3, 4, 5, 6, 7, 8);
178         value = values[1];
179         Long8Inline.check(value, 1, 2, 3, 4, 5, 6, 7, 8);
180 
181         Long8Inline[] copy = (Long8Inline[])ValueClass.newNullRestrictedArray(Long8Inline.class, values.length);
182         System.arraycopy(values, 0, copy, 0, values.length);
183         value = copy[1];
184         Long8Inline.check(value, 1, 2, 3, 4, 5, 6, 7, 8);
185     }
186 
187     void testMixedPersonArray() {
188         Person[] people = (Person[])ValueClass.newNullRestrictedArray(Person.class, 3);
189 
190         people[0] = new Person(1, "First", "Last");
191         assertEquals(people[0].getId(), 1, "Invalid Id person");
192         assertEquals(people[0].getFirstName(), "First", "Invalid First Name");
193         assertEquals(people[0].getLastName(), "Last", "Invalid Last Name");
194 
195         people[1] = new Person(2, "Jane", "Wayne");
196         people[2] = new Person(3, "Bob", "Dobalina");
197 
198         Person[] peopleCopy = (Person[])ValueClass.newNullRestrictedArray(Person.class, people.length);
199         System.arraycopy(people, 0, peopleCopy, 0, people.length);
200         assertEquals(peopleCopy[2].getId(), 3, "Invalid Id");
201         assertEquals(peopleCopy[2].getFirstName(), "Bob", "Invalid First Name");
202         assertEquals(peopleCopy[2].getLastName(), "Dobalina", "Invalid Last Name");
203     }
204 
205     void testMultiDimPointArray() {
206         /*
207         Point[][][] multiPoints = new Point[2][3][4];
208         assertEquals(multiPoints.length, 2, "1st dim length");
209         assertEquals(multiPoints[0].length, 3, "2st dim length");
210         assertEquals(multiPoints[0][0].length, 4, "3rd dim length");
211 
212         Point defaultPoint = multiPoints[1][2][3];
213         assertEquals(defaultPoint.x, 0, "invalid point x value");
214         assertEquals(defaultPoint.y, 0, "invalid point x value");
215         */
216     }
217 
218     void testReflectArray() {
219         // Check the java.lang.reflect.Array.newInstance methods...
220         Class<?> cls = (Class<?>) Point[].class;
221         Point[][] array = (Point[][]) Array.newInstance(cls, 1);
222         assertEquals(array.length, 1, "Incorrect length");
223         assertTrue(array[0] == null, "Expected NULL");
224 
225         Point[][][] array3 = (Point[][][]) Array.newInstance(cls, 1, 2);
226         assertEquals(array3.length, 1, "Incorrect length");
227         assertEquals(array3[0].length, 2, "Incorrect length");
228         assertTrue(array3[0][0] == null, "Expected NULL");
229 
230         // Now create ObjArrays of InlineArray...
231         Point[][] barray = (Point[][]) Array.newInstance(Point.class, 1, 2);
232         assertEquals(barray.length, 1, "Incorrect length");
233         assertEquals(barray[0].length, 2, "Incorrect length");
234         barray[0][1] = new Point(1, 2);
235         Point pb = barray[0][1];
236         int x = pb.getX();
237         assertEquals(x, 1, "Bad Point Value");
238     }
239 
240     @ImplicitlyConstructible
241     @LooselyConsistentValue
242     static value class MyInt implements Comparable<MyInt> {
243         int value;
244 
245         private MyInt() { this(0); }
246         private MyInt(int v) { value = v; }
247         public int getValue() { return value; }
248         public String toString() { return "MyInt: " + getValue(); }
249         public int compareTo(MyInt that) { return Integer.compare(this.getValue(), that.getValue()); }
250         public boolean equals(Object o) {
251             if (o instanceof MyInt) {
252                 return this.getValue() == ((MyInt) o).getValue();
253             }
254             return false;
255         }
256 
257         public static MyInt create(int v) {
258             return new MyInt(v);
259         }
260 
261         // Null-able fields here are a temp hack to avoid ClassCircularityError
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.newNullRestrictedArray(MyInt.class, 1);
274         staticMyIntArray[0] = staticMyInt;
275         staticMyIntArrayArray = new MyInt[][] { staticMyIntArray, staticMyIntArray };
276     }
277 
278     static interface SomeSecondaryType {
279         default String hi() { return "Hi"; }
280     }
281 
282     @ImplicitlyConstructible
283     @LooselyConsistentValue
284     static value class MyOtherInt implements SomeSecondaryType {
285         final int value;
286         private MyOtherInt() { value = 0; }
287     }
288 
289     void testSanityCheckcasts() {
290         MyInt[] myInts = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, 1);
291         assertTrue(myInts instanceof Object[]);
292         assertTrue(myInts instanceof Comparable[]);
293         assertTrue(myInts instanceof MyInt[]);
294 
295         Class<?> cls = MyInt.class;
296         assertTrue(cls.isValue());
297         Object arrObj = Array.newInstance(cls, 1);
298         assertTrue(arrObj instanceof Object[], "Not Object array");
299         assertTrue(arrObj instanceof Comparable[], "Not Comparable array");
300         assertTrue(arrObj instanceof MyInt[], "Not MyInt array");
301 
302         Object[] arr = (Object[]) arrObj;
303         assertTrue(arr instanceof Comparable[], "Not Comparable array");
304         assertTrue(arr instanceof MyInt[], "Not MyInt array");
305         Comparable[] comparables = (Comparable[])arr;
306         MyInt[] myIntArr = (MyInt[]) arr;
307 
308         // multi-dim, check secondary array types are setup...
309         MyOtherInt[][] matrix = new MyOtherInt[1][1];
310         assertTrue(matrix[0] instanceof MyOtherInt[]);
311         assertTrue(matrix[0] instanceof SomeSecondaryType[]);
312         assertTrue(matrix[0] instanceof MyOtherInt[]);
313 
314         // Box types vs Inline...
315         MyInt[] myValueRefs = new MyInt[1];
316         assertTrue(myValueRefs instanceof MyInt[]);
317         assertTrue(myValueRefs instanceof Object[]);
318         assertTrue(myValueRefs instanceof Comparable[]);
319 
320         MyInt[][] myMdValueRefs = new MyInt[1][1];
321         assertTrue(myMdValueRefs[0] instanceof MyInt[]);
322         assertTrue(myMdValueRefs[0] instanceof Object[]);
323         assertTrue(myMdValueRefs[0] instanceof Comparable[]);
324 
325         // Did we break checkcast...
326         MyInt[]     va1 = (MyInt[])null;
327         MyInt[]     va2 = null;
328         MyInt[][]   va3 = (MyInt[][])null;
329         MyInt[][][] va4 = (MyInt[][][])null;
330     }
331 
332 
333     void testUtilArrays() {
334         // Sanity check j.u.Arrays
335 
336         // cast to q-type temp effect of avoiding circularity error (decl static MyInt.ref)
337         MyInt[] myInts = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, 2);
338         myInts[0] = (MyInt) MyInt.MAX;
339         myInts[1] = (MyInt) MyInt.MIN;
340 
341         // Sanity sort another copy
342 
343         // Arrays.copyOf() API needs discussion, avoid just now...
344         boolean useArraysCopyOf = false;
345         MyInt[] copyMyInts;
346         if (useArraysCopyOf) {
347             copyMyInts = (MyInt[]) Arrays.copyOf(myInts, myInts.length + 1);
348         } else {
349             copyMyInts = (MyInt[]) (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, myInts.length + 1);
350             for (int i = 0; i < myInts.length; i++) {
351                 copyMyInts[i] = myInts[i];
352             }
353         }
354         MyInt[] expected = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, 3);
355         expected[0] = myInts[0];
356         expected[1] = myInts[1];
357         expected[2] = (MyInt) MyInt.ZERO;
358         checkArrayElementsEqual(copyMyInts, expected);
359 
360         Arrays.sort(copyMyInts);
361         expected = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, 3);
362         expected[0] = (MyInt) MyInt.MIN;
363         expected[1] = (MyInt) MyInt.ZERO;
364         expected[2] = (MyInt) MyInt.MAX;
365         checkArrayElementsEqual(copyMyInts, expected);
366 
367         List myIntList = Arrays.asList(copyMyInts);
368 
369         MyInt[] dest = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, copyMyInts.length);
370         checkArrayElementsEqual(copyMyInts, myIntList.toArray(dest));
371         // This next line needs testMixedLayoutArrays to work
372         checkArrayElementsEqual(copyMyInts, myIntList.toArray());
373 
374         // Sanity check j.u.ArrayList
375         ArrayList<MyInt> aList = new ArrayList<MyInt>(Arrays.asList(copyMyInts));
376         assertTrue(aList.indexOf(MyInt.MIN) == 0, "Bad Index");
377         assertTrue(aList.indexOf(MyInt.ZERO) == 1, "Bad Index");
378         assertTrue(aList.indexOf(MyInt.MAX) == 2, "Bad Index");
379 
380         aList.remove(2);
381         aList.add(MyInt.create(5));
382     }
383 
384 
385     void testObjectArrayOfInlines() {
386         testSanityObjectArrays();
387         testMixedLayoutArrays();
388     }
389 
390     void testSanityObjectArrays() {
391         Object[] objects = new Object[2];
392         assertTrue(objects[0] == null && objects[1] == null, "Not null ?");
393 
394         objects[0] = MyInt.create(1);
395         objects[1] = Integer.valueOf(2);
396         assertTrue(objects[0].equals(MyInt.create(1)), "Bad Value");
397         assertTrue(objects[1].equals(Integer.valueOf(2)), "Bad Object");
398 
399         Comparable[] copyComparables = new Comparable[objects.length];
400         System.arraycopy(objects, 0, copyComparables, 0, objects.length);
401         checkArrayElementsEqual(objects, copyComparables);
402 
403         objects[0] = null;
404         objects[1] = null;
405         assertTrue(objects[0] == null && objects[1] == null, "Not null ?");
406 
407         Comparable[] comparables = new Comparable[2];
408         assertTrue(comparables[0] == null && comparables[1] == null, "Not null ?");
409         comparables[0] = MyInt.create(3);
410         comparables[1] = Integer.valueOf(4);
411         assertTrue(comparables[0].equals(MyInt.create(3)), "Bad Value");
412         assertTrue(comparables[1].equals(Integer.valueOf(4)), "Bad Object");
413 
414         Object[] copyObjects = new Object[2];
415         System.arraycopy(comparables, 0, copyObjects, 0, comparables.length);
416         checkArrayElementsEqual(comparables, copyObjects);
417 
418         comparables[0] = null;
419         comparables[1] = null;
420         assertTrue(comparables[0] == null && comparables[1] == null, "Not null ?");
421 
422         MyInt[] myIntRefArray = new MyInt[1];
423         assertTrue(myIntRefArray[0] == null, "Got: " + myIntRefArray[0]);
424         myIntRefArray[0] = null;
425 
426         MyInt[] srcNulls = new MyInt[2];
427         MyInt[] dstNulls = new MyInt[2];
428         System.arraycopy(srcNulls, 0, dstNulls, 0, 2);
429         checkArrayElementsEqual(srcNulls, dstNulls);
430         srcNulls[1] = MyInt.create(1);
431         System.arraycopy(srcNulls, 0, dstNulls, 0, 2);
432         checkArrayElementsEqual(srcNulls, dstNulls);
433 
434 
435         // Locked/unlocked flat array type checks
436         synchronized (srcNulls) {
437             System.arraycopy(srcNulls, 0, dstNulls, 0, 2);
438             checkArrayElementsEqual(srcNulls, dstNulls);
439             System.gc();
440         }
441         System.gc();
442         checkArrayElementsEqual(srcNulls, dstNulls);
443     }
444 
445     void testMixedLayoutArrays() {
446         Object[] objArray = new Object[3];
447         Comparable[] compArray = new Comparable[3];
448         MyInt[] valArray = new MyInt[] { (MyInt) MyInt.MIN, (MyInt) MyInt.ZERO, (MyInt) MyInt.MAX };
449 
450         arrayCopy(valArray, 0, objArray, 0, 3);
451         checkArrayElementsEqual(valArray, objArray);
452         arrayCopy(valArray, 0, objArray, 0, 3);
453 
454         objArray = new Object[3];
455         System.arraycopy(valArray, 0, objArray, 0, 3);
456         checkArrayElementsEqual(valArray, objArray);
457 
458         System.arraycopy(valArray, 0, compArray, 0, 3);
459         checkArrayElementsEqual(valArray, compArray);
460 
461         valArray = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, 3);
462         valArray[0] = (MyInt) MyInt.ZERO;
463         valArray[1] = (MyInt) MyInt.ZERO;
464         valArray[2] = (MyInt) MyInt.ZERO;
465         System.arraycopy(compArray, 0, valArray, 0, 3);
466         checkArrayElementsEqual(valArray, compArray);
467 
468         valArray = (MyInt[])ValueClass.newNullRestrictedArray(MyInt.class, 3);
469         valArray[0] = (MyInt) MyInt.ZERO;
470         valArray[1] = (MyInt) MyInt.ZERO;
471         valArray[2] = (MyInt) MyInt.ZERO;
472         System.arraycopy(objArray, 0, valArray, 0, 3);
473         checkArrayElementsEqual(valArray, objArray);
474 
475         // Sanity check dst == src
476         System.arraycopy(valArray, 0, valArray, 0, 3);
477         checkArrayElementsEqual(valArray, objArray);
478 
479         objArray[0] = "Not an inline object";
480         try {
481             System.arraycopy(objArray, 0, valArray, 0, 3);
482             throw new RuntimeException("Expected ArrayStoreException");
483         } catch (ArrayStoreException ase) {}
484 
485         MyInt[] myIntRefArray = new MyInt[3];
486         System.arraycopy(valArray, 0, myIntRefArray, 0, 3);
487         checkArrayElementsEqual(valArray, myIntRefArray);
488 
489         myIntRefArray[0] = null;
490         try {
491             System.arraycopy(myIntRefArray, 0, valArray, 0, 3);
492             throw new RuntimeException("Expected NullPointerException");
493         } catch (NullPointerException npe) {}
494     }
495 
496     @ImplicitlyConstructible
497     @LooselyConsistentValue
498     static value class MyPoint {
499         @NullRestricted
500         MyInt x;
501         @NullRestricted
502         MyInt y;
503 
504         private MyPoint() { this(0, 0); }
505         private MyPoint(int x, int y) {
506             this.x = new MyInt(x);
507             this.y = new MyInt(y);
508         }
509         public boolean equals(Object that) {
510             if (that instanceof MyPoint) {
511                 MyPoint thatPoint = (MyPoint) that;
512                 return x.equals(thatPoint.x) && java.util.Objects.equals(y, thatPoint.y);
513             }
514             return false;
515         }
516         static MyPoint create(int x) {
517             return new MyPoint(x, x);
518         }
519         static MyPoint create(int x, int y) {
520             return new MyPoint(x, y);
521         }
522         @NullRestricted
523         static final MyPoint ORIGIN = create(0);
524     }
525 
526     void testComposition() {
527         // Test array operations with compostion of inline types, check element payload is correct...
528         MyPoint a = MyPoint.create(1, 2);
529         MyPoint b = MyPoint.create(7, 21);
530         MyPoint c = MyPoint.create(Integer.MAX_VALUE, Integer.MIN_VALUE);
531 
532         MyPoint[] pts = (MyPoint[])ValueClass.newNullRestrictedArray(MyPoint.class, 3);
533         if (!pts[0].equals(MyPoint.ORIGIN)) {
534             throw new RuntimeException("Equals failed: " + pts[0] + " vs " + MyPoint.ORIGIN);
535         }
536         pts = (MyPoint[])ValueClass.newNullRestrictedArray(MyPoint.class, 3);
537         pts[0] = a;
538         pts[1] = b;
539         pts[2] = c;
540         checkArrayElementsEqual(pts, new Object[] { a, b, c});
541         Object[] oarr = new Object[3];
542 
543         arrayCopy(pts, 0, oarr, 0, 3);
544         checkArrayElementsEqual(pts, oarr);
545 
546         oarr = new Object[3];
547         System.arraycopy(pts, 0, oarr, 0, 3);
548         checkArrayElementsEqual(pts, oarr);
549 
550         System.arraycopy(oarr, 0, pts, 0, 3);
551         checkArrayElementsEqual(pts, oarr);
552 
553         oarr = new Object[3];
554         try {
555             System.arraycopy(oarr, 0, pts, 0, 3);
556             throw new RuntimeException("Expected NPE");
557         }
558         catch (NullPointerException npe) {}
559 
560         oarr = new Object[3];
561         oarr[0] = new Object();
562         try {
563             System.arraycopy(oarr, 0, pts, 0, 3);
564             throw new RuntimeException("Expected ASE");
565         }
566         catch (ArrayStoreException ase) {}
567     }
568 
569     void checkArrayElementsEqual(MyInt[] arr1, Object[] arr2) {
570         assertTrue(arr1.length == arr2.length, "Bad length");
571         for (int i = 0; i < arr1.length; i++) {
572             assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal");
573         }
574     }
575 
576     void checkArrayElementsEqual(MyPoint[] arr1, Object[] arr2) {
577         assertTrue(arr1.length == arr2.length, "Bad length");
578         for (int i = 0; i < arr1.length; i++) {
579             assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal");
580         }
581     }
582 
583     void checkArrayElementsEqual(Object[] arr1, Object[] arr2) {
584         assertTrue(arr1.length == arr2.length, "Bad length");
585         for (int i = 0; i < arr1.length; i++) {
586             assertTrue(java.util.Objects.equals(arr1[i], arr2[i]), "Element " + i + " not equal");
587         }
588     }
589 
590     void arrayCopy(MyInt[] src, int srcPos, Object[] dst, int dstPos, int length) {
591         for (int i = 0; i < length ; i++) {
592             dst[dstPos++] = src[srcPos++];
593         }
594     }
595     void arrayCopy(MyPoint[] src, int srcPos, Object[] dst, int dstPos, int length) {
596         for (int i = 0; i < length ; i++) {
597             dst[dstPos++] = src[srcPos++];
598         }
599     }
600 
601     Object getNull() { return null; }
602 
603 
604     void testInlineArrayOom() {
605         int size = Integer.MAX_VALUE;
606         try {
607             MyPoint[] pts = new MyPoint[size];
608             throw new RuntimeException("Excepted OOM");
609         } catch (OutOfMemoryError oom) {}
610     }
611 
612 }