/* * @test TestFromCardCacheIndex.java * @bug 8196485 * @summary Ensure that G1 does not miss a remembered set entry due to from card cache default value indices. * @key gc * @requires vm.gc.G1 * @requires vm.debug * @requires vm.bits != "32" * @library /test/lib * @modules java.base/jdk.internal.misc * java.management * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Xms20M -Xmx20M -XX:+UseCompressedOops -XX:G1HeapRegionSize=1M -XX:HeapBaseMinAddress=2199011721216 -XX:+UseG1GC -verbose:gc TestFromCardCacheIndex */ import sun.hotspot.WhiteBox; /** * Repeatedly tries to generate references from objects that contained a card with the same index * of the from card cache default value. */ public class TestFromCardCacheIndex { private static WhiteBox WB; // Shift value to calculate card indices from addresses. private static final int CardSizeShift = 9; /** * Returns the last address on the heap within the object. * * @param The Object array to get the last address from. */ private static long getObjectLastAddress(Object[] o) { return WB.getObjectAddress(o) + WB.getObjectSize(o) - 1; } /** * Returns the (truncated) 32 bit card index for the given address. * * @param The address to get the 32 bit card index from. */ private static int getCardIndex32bit(long address) { return (int)(address >> CardSizeShift); } // The source arrays that are placed on the heap in old gen. private static int numArrays = 7000; private static int arraySize = 508; // Size of a humongous byte array, a bit less than a 1M region. This makes sure // that we always create a cross-region reference when referencing it. private static int byteArraySize = 1024*1023; public static void main(String[] args) { WB = sun.hotspot.WhiteBox.getWhiteBox(); for (int i = 0; i < 5; i++) { runTest(); WB.fullGC(); } } public static void runTest() { System.out.println("Starting test"); // Spray the heap with random object arrays in the hope that we get one // at the proper place. Object[][] arrays = new Object[numArrays][]; for (int i = 0; i < numArrays; i++) { arrays[i] = new Object[arraySize]; } // Make sure that everything is in old gen. WB.fullGC(); // Find if we got an allocation at the right spot. Object[] arrayWithCardMinus1 = findArray(arrays); if (arrayWithCardMinus1 == null) { System.out.println("Array with card -1 not found. Trying again."); return; } else { System.out.println("Array with card -1 found."); } System.out.println("Modifying the last card in the array with a new object in a different region..."); // Create a target object that is guaranteed to be in a different region. byte[] target = new byte[byteArraySize]; // Modify the last entry of the object we found. arrayWithCardMinus1[arraySize - 1] = target; target = null; // Make sure that the dirty cards are flushed by doing a GC. System.out.println("Doing a GC."); WB.youngGC(); System.out.println("The crash didn't reproduce. Trying again."); } /** * Finds an returns an array that contains a (32 bit truncated) card with value -1. */ private static Object[] findArray(Object[][] arrays) { for (int i = 0; i < arrays.length; i++) { Object[] target = arrays[i]; if (target == null) { continue; } final long startAddress = WB.getObjectAddress(target); final long lastAddress = getObjectLastAddress(target); final int card = getCardIndex32bit(lastAddress); if (card == -1) { Object[] foundArray = target; return foundArray; } } return null; } }