1 /*
  2  * Copyright (c) 2020, 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 /**
 25  * @test
 26  * @bug 8252506
 27  * @summary Verify that arraycopy intrinsics properly handle flat inline type arrays with oop fields.
 28  * @library /test/lib
 29  * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::test*
 30  *                   -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::create*
 31  *                   -Xbatch
 32  *                   compiler.valhalla.inlinetypes.TestArrayCopyWithOops
 33  * @run main/othervm -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::test*
 34  *                   -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.TestArrayCopyWithOops::create*
 35  *                   -Xbatch -XX:FlatArrayElementMaxSize=0
 36  *                   compiler.valhalla.inlinetypes.TestArrayCopyWithOops
 37  */
 38 
 39 package compiler.valhalla.inlinetypes;
 40 
 41 import java.util.Arrays;
 42 
 43 import jdk.test.lib.Asserts;
 44 
 45 public class TestArrayCopyWithOops {
 46     static final int LEN = 200;
 47 
 48     static class MyObject {
 49         long val = Integer.MAX_VALUE;
 50     }
 51 
 52     static primitive class ManyOops {
 53         MyObject o1 = new MyObject();
 54         MyObject o2 = new MyObject();
 55         MyObject o3 = new MyObject();
 56         MyObject o4 = new MyObject();
 57 
 58         long hash() {
 59             return o1.val + o2.val + o3.val + o4.val;
 60         }
 61     }
 62 
 63     static ManyOops[] createArrayInline() {
 64         ManyOops[] array = new ManyOops[LEN];
 65         for (int i = 0; i < LEN; ++i) {
 66             array[i] = new ManyOops();
 67         }
 68         return array;
 69     }
 70 
 71     static Object[] createArrayObject() {
 72         return createArrayInline();
 73     }
 74 
 75     static Object createObject() {
 76         return createArrayInline();
 77     }
 78 
 79     // System.arraycopy tests
 80 
 81     static void test1(ManyOops[] dst) {
 82         System.arraycopy(createArrayInline(), 0, dst, 0, LEN);
 83     }
 84 
 85     static void test2(Object[] dst) {
 86         System.arraycopy(createArrayObject(), 0, dst, 0, LEN);
 87     }
 88 
 89     static void test3(ManyOops[] dst) {
 90         System.arraycopy(createArrayObject(), 0, dst, 0, LEN);
 91     }
 92 
 93     static void test4(Object[] dst) {
 94         System.arraycopy(createArrayInline(), 0, dst, 0, LEN);
 95     }
 96 
 97     // System.arraycopy tests (tightly coupled with allocation of dst array)
 98 
 99     static Object[] test5() {
100         ManyOops[] dst = new ManyOops[LEN];
101         System.arraycopy(createArrayInline(), 0, dst, 0, LEN);
102         return dst;
103     }
104 
105     static Object[] test6() {
106         Object[] dst = new Object[LEN];
107         System.arraycopy(createArrayObject(), 0, dst, 0, LEN);
108         return dst;
109     }
110 
111     static Object[] test7() {
112         ManyOops[] dst = new ManyOops[LEN];
113         System.arraycopy(createArrayObject(), 0, dst, 0, LEN);
114         return dst;
115     }
116 
117     static Object[] test8() {
118         Object[] dst = new Object[LEN];
119         System.arraycopy(createArrayInline(), 0, dst, 0, LEN);
120         return dst;
121     }
122 
123     // Arrays.copyOf tests
124 
125     static Object[] test9() {
126         return Arrays.copyOf(createArrayInline(), LEN, ManyOops[].class);
127     }
128 
129     static Object[] test10() {
130         return Arrays.copyOf(createArrayObject(), LEN, Object[].class);
131     }
132 
133     static Object[] test11() {
134         return Arrays.copyOf(createArrayInline(), LEN, ManyOops[].class);
135     }
136 
137     static Object[] test12() {
138         return Arrays.copyOf(createArrayObject(), LEN, Object[].class);
139     }
140 
141     // System.arraycopy test using generic_copy stub
142 
143     static void test13(Object dst) {
144         System.arraycopy(createObject(), 0, dst, 0, LEN);
145     }
146 
147     static void produceGarbage() {
148         for (int i = 0; i < 100; ++i) {
149             Object[] arrays = new Object[1024];
150             for (int j = 0; j < arrays.length; j++) {
151                 arrays[i] = new int[1024];
152             }
153         }
154         System.gc();
155     }
156 
157     public static void main(String[] args) {
158         ManyOops[] dst1 = createArrayInline();
159         ManyOops[] dst2 = createArrayInline();
160         ManyOops[] dst3 = createArrayInline();
161         ManyOops[] dst4 = createArrayInline();
162         ManyOops[] dst13 = createArrayInline();
163 
164         // Warmup runs to trigger compilation
165         for (int i = 0; i < 50_000; ++i) {
166             test1(dst1);
167             test2(dst2);
168             test3(dst3);
169             test4(dst4);
170             test5();
171             test6();
172             test7();
173             test8();
174             test9();
175             test10();
176             test11();
177             test12();
178             test13(dst13);
179         }
180 
181         // Trigger GC to make sure dst arrays are moved to old gen
182         produceGarbage();
183 
184         // Move data from flat src to flat dest
185         test1(dst1);
186         test2(dst2);
187         test3(dst3);
188         test4(dst4);
189         Object[] dst5 = test5();
190         Object[] dst6 = test6();
191         Object[] dst7 = test7();
192         Object[] dst8 = test8();
193         Object[] dst9 = test9();
194         Object[] dst10 = test10();
195         Object[] dst11 = test11();
196         Object[] dst12 = test12();
197         test13(dst13);
198 
199         // Trigger GC again to make sure that the now dead src arrays are collected.
200         // MyObjects should be kept alive via oop references from the dst array.
201         produceGarbage();
202 
203         // Verify content
204         long expected = 4L*Integer.MAX_VALUE;
205         for (int i = 0; i < LEN; ++i) {
206             Asserts.assertEquals(dst1[i].hash(), expected);
207             Asserts.assertEquals(dst2[i].hash(), expected);
208             Asserts.assertEquals(dst3[i].hash(), expected);
209             Asserts.assertEquals(dst4[i].hash(), expected);
210             Asserts.assertEquals(((ManyOops)dst5[i]).hash(), expected);
211             Asserts.assertEquals(((ManyOops)dst7[i]).hash(), expected);
212             Asserts.assertEquals(((ManyOops)dst8[i]).hash(), expected);
213             Asserts.assertEquals(((ManyOops)dst8[i]).hash(), expected);
214             Asserts.assertEquals(((ManyOops)dst9[i]).hash(), expected);
215             Asserts.assertEquals(((ManyOops)dst10[i]).hash(), expected);
216             Asserts.assertEquals(((ManyOops)dst11[i]).hash(), expected);
217             Asserts.assertEquals(((ManyOops)dst12[i]).hash(), expected);
218             Asserts.assertEquals(dst13[i].hash(), expected);
219         }
220     }
221 }