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