1 /*
  2  * Copyright (c) 2018, 2019, 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 TestFromCardCacheIndex.java
 26  * @bug 8196485
 27  * @summary Ensure that G1 does not miss a remembered set entry due to from card cache default value indices.
 28  * @key gc
 29  * @requires vm.gc.G1
 30  * @requires vm.debug
 31  * @requires vm.bits != "32"
 32  * @library /test/lib
 33  * @modules java.base/jdk.internal.misc
 34  *          java.management
 35  * @build sun.hotspot.WhiteBox
 36  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
 37  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xms20M -Xmx20M -XX:+UseCompressedOops -XX:G1HeapRegionSize=1M -XX:HeapBaseMinAddress=2199011721216 -XX:+UseG1GC -verbose:gc gc.g1.TestFromCardCacheIndex
 38  */
 39 package gc.g1;
 40 
 41 import sun.hotspot.WhiteBox;
 42 
 43 /**
 44  * Repeatedly tries to generate references from objects that contained a card with the same index
 45  * of the from card cache default value.
 46  */
 47 public class TestFromCardCacheIndex {
 48     private static WhiteBox WB;
 49 
 50     // Shift value to calculate card indices from addresses.
 51     private static final int CardSizeShift = 9;
 52 
 53     /**
 54      * Returns the last address on the heap within the object.
 55      *
 56      * @param The Object array to get the last address from.
 57      */
 58     private static long getObjectLastAddress(Object[] o) {
 59         return WB.getObjectAddress(o) + WB.getObjectSize(o) - 1;
 60     }
 61 
 62     /**
 63      * Returns the (truncated) 32 bit card index for the given address.
 64      *
 65      * @param The address to get the 32 bit card index from.
 66      */
 67     private static int getCardIndex32bit(long address) {
 68         return (int)(address >> CardSizeShift);
 69     }
 70 
 71     // The source arrays that are placed on the heap in old gen.
 72     private static int numArrays = 7000;
 73     private static int arraySize = 508;
 74     // Size of a humongous byte array, a bit less than a 1M region. This makes sure
 75     // that we always create a cross-region reference when referencing it.
 76     private static int byteArraySize = 1024*1023;
 77 
 78     public static void main(String[] args) {
 79         WB = sun.hotspot.WhiteBox.getWhiteBox();
 80         for (int i = 0; i < 5; i++) {
 81           runTest();
 82           WB.fullGC();
 83         }
 84     }
 85 
 86     public static void runTest() {
 87         System.out.println("Starting test");
 88 
 89         // Spray the heap with random object arrays in the hope that we get one
 90         // at the proper place.
 91         Object[][] arrays = new Object[numArrays][];
 92         for (int i = 0; i < numArrays; i++) {
 93             arrays[i] = new Object[arraySize];
 94         }
 95 
 96         // Make sure that everything is in old gen.
 97         WB.fullGC();
 98 
 99         // Find if we got an allocation at the right spot.
100         Object[] arrayWithCardMinus1 = findArray(arrays);
101 
102         if (arrayWithCardMinus1 == null) {
103             System.out.println("Array with card -1 not found. Trying again.");
104             return;
105         } else {
106             System.out.println("Array with card -1 found.");
107         }
108 
109         System.out.println("Modifying the last card in the array with a new object in a different region...");
110         // Create a target object that is guaranteed to be in a different region.
111         byte[] target = new byte[byteArraySize];
112 
113         // Modify the last entry of the object we found.
114         arrayWithCardMinus1[arraySize - 1] = target;
115 
116         target = null;
117         // Make sure that the dirty cards are flushed by doing a GC.
118         System.out.println("Doing a GC.");
119         WB.youngGC();
120 
121         System.out.println("The crash didn't reproduce. Trying again.");
122     }
123 
124     /**
125      * Finds an returns an array that contains a (32 bit truncated) card with value -1.
126      */
127     private static Object[] findArray(Object[][] arrays) {
128         for (int i = 0; i < arrays.length; i++) {
129             Object[] target = arrays[i];
130             if (target == null) {
131                 continue;
132             }
133             final long startAddress = WB.getObjectAddress(target);
134             final long lastAddress = getObjectLastAddress(target);
135             final int card = getCardIndex32bit(lastAddress);
136             if (card == -1) {
137                 Object[] foundArray = target;
138                 return foundArray;
139             }
140         }
141         return null;
142     }
143 }
144