blob: f2332306daee6c7a4a44d281876870d67469d672 [file] [log] [blame]
/*
* @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;
}
}