1 /*
 2  * Copyright Amazon.com Inc. 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 gc.parallel;
25 
26 import java.util.Random;
27 
28 /*
29  * @test TestHashedObjectCopy
30  * @bug 8379910
31  * @summary Parallel GC scavenge could read past the end of a hashed object
32  *          when copying it to survivor/old space with compact object headers.
33  *          If a hashed-but-not-expanded object sits at the very end of eden,
34  *          the extra word read by copy_unmarked_to_survivor_space crosses into
35  *          unmapped memory, causing a crash.
36  * @requires vm.gc.Parallel
37  * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+UseCompactObjectHeaders
38  *      -XX:+UseParallelGC -Xmx128m -Xms128m -Xmn1m
39  *      gc.parallel.TestHashedObjectCopy
40  */
41 public class TestHashedObjectCopy {
42 
43     // Stress a variety of layouts.
44     static class S1 { byte a; }
45     static class S2 { byte a, b; }
46     static class S3 { byte a, b, c; }
47     static class S4 { byte a, b, c, d; }
48     static class S5 { byte a, b, c, d, e; }
49     static class S6 { byte a, b, c, d, e, f; }
50     static class S7 { byte a, b, c, d, e, f, g; }
51     static class S8 { byte a, b, c, d, e, f, g, h; }
52 
53     static volatile int sink;
54 
55     public static void main(String[] args) {
56         // Churn through different-sized objects. Keep some alive,
57         // because we're testing copy-to-survivor behaviour.
58         Random rng = new Random(42);
59         Object[] retained = new Object[10_000];
60         for (int cycle = 0; cycle < 1_000; cycle++) {
61             for (int i = 0; i < retained.length; i++) {
62                 Object obj = switch (rng.nextInt(8)) {
63                     case 0 -> new S1();
64                     case 1 -> new S2();
65                     case 2 -> new S3();
66                     case 3 -> new S4();
67                     case 4 -> new S5();
68                     case 5 -> new S6();
69                     case 6 -> new S7();
70                     default -> new S8();
71                 };
72                 // Trigger expansion on copy.
73                 sink = System.identityHashCode(obj);
74                 retained[i] = obj;
75             }
76         }
77     }
78 }