1 /*
2 * Copyright (c) 2016, 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 /*
25 * @test
26 * @bug 8155643 8268125 8270461 8270098 8332959
27 * @summary Test Object.clone() intrinsic.
28 * @modules java.base/java.lang:+open
29 *
30 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-ReduceInitialCardMarks
31 * -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
32 * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke
33 * compiler.arraycopy.TestObjectArrayClone
34 * @run main/othervm -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
35 * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke
36 * compiler.arraycopy.TestObjectArrayClone
37 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedClassPointers -Xmx128m
38 * -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
39 * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke
40 * compiler.arraycopy.TestObjectArrayClone
41 * @run main/othervm -Xbatch -XX:-UseTypeProfile
42 * -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
43 * -XX:CompileCommand=compileonly,jdk.internal.reflect.GeneratedMethodAccessor*::invoke
44 * -XX:CompileCommand=compileonly,*::invokeVirtual
45 * compiler.arraycopy.TestObjectArrayClone
46 */
47
48 package compiler.arraycopy;
49
50 import java.lang.invoke.*;
51 import java.lang.reflect.InvocationTargetException;
52 import java.lang.reflect.Method;
53
54 class Payload implements Cloneable {
55 boolean b;
56 int i;
57 char c;
58 String str;
59 short s;
60 int i2;
61
62 public Payload(boolean b, int i, char c, String str, short s, int i2) {
63 super();
64 this.b = b;
65 this.i = i;
66 this.c = c;
67 this.str = str;
68 this.s = s;
69 this.i2 = i2;
70 }
71
72 public Payload clonep() {
73 try {
74 return (Payload) super.clone();
75 } catch (CloneNotSupportedException e) {
76 return null;
77 }
78 }
79 }
80
81 class Payload2 implements Cloneable {
82 boolean b;
83 int i;
84 char c;
85 String str;
86 short s;
87 int i2;
88 boolean b2;
89 int i3;
90 char c2;
91 String str2;
92 short s2;
93 int i4;
94
95 public Payload2(boolean b, int i, char c, String str, short s, int i2, boolean b2, int i3, char c2, String str2,
96 short s2, int i4) {
97 super();
98 this.b = b;
99 this.i = i;
100 this.c = c;
101 this.str = str;
102 this.s = s;
103 this.i2 = i2;
104 this.b2 = b2;
105 this.i3 = i3;
106 this.c2 = c2;
107 this.str2 = str2;
108 this.s2 = s2;
109 this.i4 = i4;
110 }
111
112 public Payload2 clonep() {
113 try {
114 return (Payload2) super.clone();
115 } catch(CloneNotSupportedException e) {
116 return null;
117 }
118 }
119 }
120
121 public class TestObjectArrayClone {
122
123 public static String[] escape_arr;
124
125 public static String str1 = new String("1");
126 public static String str2 = new String("2");
127 public static String str3 = new String("3");
128 public static String str4 = new String("4");
129 public static String str5 = new String("5");
130
131 public static String[] testCloneObjectArray(String[] arr) {
132 return arr.clone();
133 }
134
135 public static String[] testCloneObjectArrayCopy(String[] arr) {
136 String[] arr2 = new String[arr.length];
137 System.arraycopy(arr, 0, arr2, 0, arr.length);
138 return arr2;
139 }
140
141 public static String[] testCloneShortObjectArray() {
142 String[] arr = new String[5];
143 arr[0] = str1;
144 arr[1] = str2;
145 arr[2] = str3;
146 arr[3] = str4;
147 arr[4] = str5;
148 escape_arr = arr;
149 return arr.clone();
150 }
151
152 public static String[] testCloneShortObjectArray2(Method clone) throws Exception {
153 String[] arr = new String[5];
154 arr[0] = str1;
155 arr[1] = str2;
156 arr[2] = str3;
157 arr[3] = str4;
158 arr[4] = str5;
159 escape_arr = arr;
160 return (String[]) testCloneObject(clone, arr);
161 }
162
163 public static String[] testCloneShortObjectArrayCopy() {
164 String[] arr = new String[5];
165 arr[0] = str1;
166 arr[1] = str2;
167 arr[2] = str3;
168 arr[3] = str4;
169 arr[4] = str5;
170 escape_arr = arr;
171 String[] arr2 = new String[arr.length];
172 System.arraycopy(arr, 0, arr2, 0, arr.length);
173 return arr2;
174 }
175
176 public static int[] testClonePrimitiveArray(int[] arr) {
177 return arr.clone();
178 }
179
180 public static Object testCloneOop(Payload p) {
181 return p.clonep();
182 }
183
184 public static Object testCloneOop2(Payload2 p) {
185 return p.clonep();
186 }
187
188 public static Object testCloneObject(Method clone, Object obj) throws Exception {
189 return clone.invoke(obj);
190 }
191
192 public static Object testCloneObjectWithMethodHandle(MethodHandle clone, Object obj) throws Throwable {
193 return clone.invokeExact(obj);
194 }
195
196 public static void main(String[] args) throws Throwable {
197 Method clone = Object.class.getDeclaredMethod("clone");
198 clone.setAccessible(true);
199
200 MethodHandles.Lookup privateLookup = MethodHandles.privateLookupIn(Object.class, MethodHandles.lookup());
201 MethodType mt = MethodType.methodType(Object.class);
202 MethodHandle mh = privateLookup.findVirtual(Object.class, "clone", mt);
203
204 String[] arr1 = new String[42];
205 for (int j = 0; j < arr1.length; j++) {
206 arr1[j] = new String(Integer.toString(j));
207 }
208
209 for (int i = 0; i < 50_000; i++) {
210 String[] arr2 = testCloneObjectArray(arr1);
211 verifyStr(arr1, arr2);
212 String[] arr3 = testCloneObjectArray(arr1);
213 verifyStr(arr1, arr3);
214 String[] arr4 = testCloneObjectArray(arr1);
215 verifyStr(arr1, arr4);
216 verifyStr(arr1, arr3);
217 verifyStr(arr1, arr2);
218 }
219
220 for (int i = 0; i < 50_000; i++) {
221 for (int j = 0; j < arr1.length; j++) {
222 arr1[j] = new String(Integer.toString(j));
223 }
224 String[] arr2 = (String[]) testCloneObject(clone, arr1);
225 verifyStr(arr1, arr2);
226 String[] arr3 = (String[]) testCloneObject(clone, arr1);
227 verifyStr(arr1, arr3);
228 String[] arr4 = (String[]) testCloneObject(clone, arr1);
229 verifyStr(arr1, arr4);
230 verifyStr(arr1, arr3);
231 verifyStr(arr1, arr2);
232 }
233
234 for (int i = 0; i < 50_000; i++) {
235 String[] value = testCloneShortObjectArray();
236 verifyStr(value, escape_arr);
237 String[] value2 = testCloneShortObjectArray();
238 verifyStr(value2, escape_arr);
239 String[] value3 = testCloneShortObjectArray();
240 verifyStr(value3, escape_arr);
241 String[] value4 = testCloneShortObjectArray2(clone);
242 verifyStr(value4, escape_arr);
243 verifyStr(value, value4);
244 verifyStr(value, value3);
245 verifyStr(value, value2);
246 }
247
248 for (int i = 0; i < 50_000; i++) {
249 String[] arr2 = testCloneObjectArrayCopy(arr1);
250 verifyStr(arr1, arr2);
251 String[] arr3 = testCloneObjectArrayCopy(arr1);
252 verifyStr(arr1, arr3);
253 String[] arr4 = testCloneObjectArrayCopy(arr1);
254 verifyStr(arr1, arr4);
255 verifyStr(arr1, arr3);
256 verifyStr(arr1, arr2);
257 }
258
259 for (int i = 0; i < 50_000; i++) {
260 String[] value = testCloneShortObjectArrayCopy();
261 verifyStr(value, escape_arr);
262 String[] value2 = testCloneShortObjectArrayCopy();
263 verifyStr(value2, escape_arr);
264 String[] value3 = testCloneShortObjectArrayCopy();
265 verifyStr(value3, escape_arr);
266 verifyStr(value, value3);
267 verifyStr(value, value2);
268 }
269
270 for (int i = 0; i < 50_000; i++) {
271 String[] arr2 = (String[]) testCloneObjectWithMethodHandle(mh, (Object)arr1);
272 verifyStr(arr1, arr2);
273 String[] arr3 = (String[]) testCloneObjectWithMethodHandle(mh, (Object)arr1);
274 verifyStr(arr1, arr3);
275 String[] arr4 = (String[]) testCloneObjectWithMethodHandle(mh, (Object)arr1);
276 verifyStr(arr1, arr4);
277 verifyStr(arr1, arr3);
278 verifyStr(arr1, arr2);
279 }
280
281 int[] arr2 = new int[42];
282 for (int i = 0; i < arr2.length; i++) {
283 arr2[i] = i;
284 }
285 for (int i = 0; i < 50_000; i++) {
286 int[] res1 = testClonePrimitiveArray(arr2);
287 int[] res2 = (int[])testCloneObject(clone, arr2);
288 for (int j = 0; j < arr2.length; j++) {
289 if (res1[j] != j) {
290 throw new RuntimeException("Unexpected result: " + res1[j] + " != " + j);
291 }
292 if (res2[j] != j) {
293 throw new RuntimeException("Unexpected result: " + res2[j] + " != " + j);
294 }
295 }
296 }
297
298 Payload ref = new Payload(false, -1, 'c', str1, (short) 5, -1);
299 for (int i = 0; i < 50_000; i++) {
300 Payload p1 = (Payload) testCloneOop(ref);
301 verifyPayload(ref, p1);
302 Payload p2 = (Payload) testCloneOop(ref);
303 verifyPayload(ref, p2);
304 Payload p3 = (Payload) testCloneOop(ref);
305 verifyPayload(ref, p3);
306 verifyPayload(p2, p3);
307 verifyPayload(p1, p3);
308 }
309
310 for (int i = 0; i < 50_000; i++) {
311 Payload p1 = (Payload) testCloneObject(clone, ref);
312 verifyPayload(ref, p1);
313 Payload p2 = (Payload) testCloneObject(clone, ref);
314 verifyPayload(ref, p2);
315 Payload p3 = (Payload) testCloneObject(clone, ref);
316 verifyPayload(ref, p3);
317 verifyPayload(p2, p3);
318 verifyPayload(p1, p3);
319 }
320
321 Payload2 ref2 = new Payload2(false, -1, 'c', str1, (short) 5, -1, false, 0, 'k', str2, (short)-1, 0);
322 for (int i = 0; i < 50_000; i++) {
323 Payload2 p1 = (Payload2) testCloneOop2(ref2);
324 verifyPayload2(ref2, p1);
325 Payload2 p2 = (Payload2) testCloneOop2(ref2);
326 verifyPayload2(ref2, p2);
327 Payload2 p3 = (Payload2) testCloneOop2(ref2);
328 verifyPayload2(ref2, p3);
329 verifyPayload2(p2, p3);
330 verifyPayload2(p1, p3);
331 }
332
333 for (int i = 0; i < 50_000; i++) {
334 Payload2 p1 = (Payload2) testCloneObject(clone, ref2);
335 verifyPayload2(ref2, p1);
336 Payload2 p2 = (Payload2) testCloneObject(clone, ref2);
337 verifyPayload2(ref2, p2);
338 Payload2 p3 = (Payload2) testCloneObject(clone, ref2);
339 verifyPayload2(ref2, p3);
340 verifyPayload2(p2, p3);
341 verifyPayload2(p1, p3);
342 }
343
344 for (int i = 0; i < 50_000; i++) {
345 Payload2 p1 = (Payload2) testCloneObjectWithMethodHandle(mh, ref2);
346 verifyPayload2(ref2, p1);
347 Payload2 p2 = (Payload2) testCloneObjectWithMethodHandle(mh, ref2);
348 verifyPayload2(ref2, p2);
349 Payload2 p3 = (Payload2) testCloneObjectWithMethodHandle(mh, ref2);
350 verifyPayload2(ref2, p3);
351 verifyPayload2(p2, p3);
352 verifyPayload2(p1, p3);
353 }
354 }
355
356 public static void verifyPayload(Payload p1, Payload p2) {
357 if (p1.b != p2.b) {
358 throw new RuntimeException("b is wrong");
359 }
360 if (p1.c != p2.c) {
361 throw new RuntimeException("c is wrong");
362 }
363 if (p1.i != p2.i) {
364 throw new RuntimeException("i is wrong");
365 }
366 if (p1.s != p2.s) {
367 throw new RuntimeException("s is wrong");
368 }
369 if (p1.i2 != p2.i2) {
370 throw new RuntimeException("i2 is wrong");
371 }
372 if (p1.str != p2.str) {
373 throw new RuntimeException("str is wrong");
374 }
375 if (!p1.str.equals(p2.str)) {
376 throw new RuntimeException("str content is wrong");
377 }
378 }
379
380 public static void verifyPayload2(Payload2 p1, Payload2 p2) {
381 if (p1.b != p2.b) {
382 throw new RuntimeException("b is wrong");
383 }
384 if (p1.c != p2.c) {
385 throw new RuntimeException("c is wrong");
386 }
387 if (p1.i != p2.i) {
388 throw new RuntimeException("i is wrong");
389 }
390 if (p1.s != p2.s) {
391 throw new RuntimeException("s is wrong");
392 }
393 if (p1.i2 != p2.i2) {
394 throw new RuntimeException("i2 is wrong");
395 }
396 if (p1.str != p2.str) {
397 throw new RuntimeException("str is wrong");
398 }
399 if (!p1.str.equals(p2.str)) {
400 throw new RuntimeException("str content is wrong");
401 }
402 if (p1.b2 != p2.b2) {
403 throw new RuntimeException("b is wrong");
404 }
405 if (p1.c2 != p2.c2) {
406 throw new RuntimeException("c is wrong");
407 }
408 if (p1.i3 != p2.i3) {
409 throw new RuntimeException("i is wrong");
410 }
411 if (p1.s2 != p2.s2) {
412 throw new RuntimeException("s is wrong");
413 }
414 if (p1.i4 != p2.i4) {
415 throw new RuntimeException("i2 is wrong");
416 }
417 if (p1.str2 != p2.str2) {
418 throw new RuntimeException("str is wrong");
419 }
420 if (!p1.str2.equals(p2.str2)) {
421 throw new RuntimeException("str content is wrong");
422 }
423 }
424
425 public static void verifyStr(String[] arr1, String[] arr2) {
426 if (arr1 == arr2) {
427 throw new RuntimeException("Must not be the same");
428 }
429 if (arr1.length != arr2.length) {
430 throw new RuntimeException("Must have the same length");
431 }
432 for (int i = 0; i < arr1.length; i++) {
433 if (arr1[i] != arr2[i]) {
434 throw new RuntimeException("Fail cloned element not the same: " + i);
435 }
436 if (!arr1[i].equals(arr2[i])) {
437 throw new RuntimeException("Fail cloned element content not the same");
438 }
439 }
440 }
441 }
442