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.stress.ihash;
25
26 /*
27 * @test id=Shenandoah
28 * @bug 8387285
29 * @summary An identity-hashed object whose size equals exactly one region must be
30 * allocated as humongous, so that the one-word hash expansion on a GC copy
31 * does not overflow a regular region.
32 * @requires vm.gc.Shenandoah
33 * @run main/othervm
34 * -XX:+UseCompactObjectHeaders -XX:+UseShenandoahGC
35 * -XX:+UnlockDiagnosticVMOptions -XX:+VerifyDuringGC -XX:+ShenandoahVerify
36 * -XX:-ExplicitGCInvokesConcurrent
37 * -Xms32m -Xmx32m
38 * -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=256K
39 * gc.stress.ihash.TestRegionSizedHash
40 */
41
42 /*
43 * @test id=Shenandoah-aggressive
44 * @bug 8387285
45 * @summary An identity-hashed object whose size equals exactly one region must be
46 * allocated as humongous, so that the one-word hash expansion on a GC copy
47 * does not overflow a regular region.
48 * @requires vm.gc.Shenandoah
49 * @run main/othervm
50 * -XX:+UseCompactObjectHeaders -XX:+UseShenandoahGC
51 * -XX:+UnlockDiagnosticVMOptions -XX:+VerifyDuringGC -XX:+ShenandoahVerify
52 * -XX:-ExplicitGCInvokesConcurrent
53 * -XX:ShenandoahGCHeuristics=aggressive
54 * -Xms32m -Xmx32m
55 * -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=256K
56 * gc.stress.ihash.TestRegionSizedHash
57 */
58
59 /**
60 * Regression test for the allocation-routing half of JDK-8387285.
61 *
62 * With compact object headers, an object whose size is exactly one region (its
63 * allocation fills the region) would, if allocated as a regular object, overflow
64 * that region when a GC copy injects an identity hash-code and grows it by one
65 * word. ShenandoahFreeSet::allocate therefore classifies a fresh mutator object by
66 * its potential expanded size: requires_humongous(size, may_expand_for_hash=true)
67 * is align_object_size(size + 1) > RegionSizeWords, which is true for a
68 * region-sized object, so it is placed in a humongous region up front.
69 *
70 * Without that routing flip, a region-sized object is allocated regular; once it is
71 * identity-hashed and relocated by a STW Full GC, the expanded copy no longer fits
72 * its destination region and Full GC fails:
73 * assert(_compact_point + obj_size <= _to_region->end()) failed: must fit
74 *
75 * The test allocates several region-sized, identity-hashed byte[] arrays at the
76 * minimum (256K) region size -- the only regime where the expanded size of a
77 * single-region object crosses the region boundary -- fragments them, and forces
78 * STW Full GC compaction (-XX:-ExplicitGCInvokesConcurrent + System.gc()).
79 */
80 public class TestRegionSizedHash {
81
82 static final int REGION_SIZE = 256 * 1024;
83
84 // byte[] allocation size (with compact headers) = align_up(8 + length, 8).
85 // length = REGION_SIZE - 8 yields an allocation of exactly one region.
86 static byte[] oneRegion() {
87 return new byte[REGION_SIZE - 8];
88 }
89
90 static final int COUNT = 8;
91
92 static Object[] keep;
93
94 public static void main(String[] args) {
95 keep = new Object[COUNT];
96 int[] hashes = new int[COUNT];
97 for (int i = 0; i < COUNT; i++) {
98 byte[] o = oneRegion();
99 hashes[i] = System.identityHashCode(o); // hash -> must expand on copy
100 keep[i] = o;
101 }
102
103 // Fragment so Full GC slides the surviving region-sized objects.
104 keep[1] = null;
105 keep[3] = null;
106 keep[5] = null;
107
108 // STW Full GC compaction. Without the routing flip the relocated, expanded
109 // region-sized objects overflow their destination region and Full GC fails.
110 System.gc();
111
112 // Validate survivors are intact across expansion/relocation.
113 for (int i = 0; i < COUNT; i++) {
114 byte[] o = (byte[]) keep[i];
115 if (o == null) {
116 continue;
117 }
118 if (System.identityHashCode(o) != hashes[i]) {
119 throw new RuntimeException("hash mismatch at " + i);
120 }
121 }
122 System.out.println("OK");
123 }
124 }