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 }