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 */ getObjectLastAddress(Object[] o)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 */ getCardIndex32bit(long address)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 main(String[] args)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 runTest()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 */ findArray(Object[][] arrays)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 WB.getObjectAddress(target); // startAddress not used 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 145