8178813: Add test for G1 pre-barrier on dereference of weak JNI handles
Add regression test. Reviewed-by: mgerdin, tschatzl, pliden
This commit is contained in:
parent
4b288cf612
commit
afad47099c
@ -43,6 +43,7 @@ $(eval $(call IncludeCustomExtension, hotspot, test/JtregNative.gmk))
|
||||
|
||||
# Add more directories here when needed.
|
||||
BUILD_HOTSPOT_JTREG_NATIVE_SRC += \
|
||||
$(HOTSPOT_TOPDIR)/test/gc/g1/TestJNIWeakG1 \
|
||||
$(HOTSPOT_TOPDIR)/test/gc/stress/gclocker \
|
||||
$(HOTSPOT_TOPDIR)/test/native_sanity \
|
||||
$(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \
|
||||
|
265
hotspot/test/gc/g1/TestJNIWeakG1/TestJNIWeakG1.java
Normal file
265
hotspot/test/gc/g1/TestJNIWeakG1/TestJNIWeakG1.java
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8166188 8178813
|
||||
* @summary Test return of JNI weak global refs during concurrent
|
||||
* marking, verifying the use of the G1 load barrier to keep the
|
||||
* referent alive.
|
||||
* @key gc
|
||||
* @requires vm.gc.G1
|
||||
* @modules java.base
|
||||
* @library /test/lib
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm/native
|
||||
* -Xbootclasspath/a:.
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* -XX:+UseG1GC -XX:MaxTenuringThreshold=2
|
||||
* -Xint
|
||||
* TestJNIWeakG1
|
||||
* @run main/othervm/native
|
||||
* -Xbootclasspath/a:.
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* -XX:+UseG1GC -XX:MaxTenuringThreshold=2
|
||||
* -Xcomp
|
||||
* TestJNIWeakG1
|
||||
*/
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
|
||||
public final class TestJNIWeakG1 {
|
||||
|
||||
static {
|
||||
System.loadLibrary("TestJNIWeakG1");
|
||||
}
|
||||
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
private static final class TestObject {
|
||||
public final int value;
|
||||
|
||||
public TestObject(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private volatile TestObject testObject = null;
|
||||
|
||||
private static native void registerObject(Object o);
|
||||
private static native void unregisterObject();
|
||||
private static native Object getReturnedWeak();
|
||||
private static native Object getResolvedWeak();
|
||||
|
||||
// resolve controls whether getObject returns an explicitly
|
||||
// resolved jweak value (when resolve is true), or returns the
|
||||
// jweak directly and invokes the implicit resolution in the
|
||||
// native call return value handling path (when resolve is false).
|
||||
private boolean resolve = true;
|
||||
|
||||
TestJNIWeakG1(boolean resolve) {
|
||||
this.resolve = resolve;
|
||||
}
|
||||
|
||||
private Object getObject() {
|
||||
if (resolve) {
|
||||
return getResolvedWeak();
|
||||
} else {
|
||||
return getReturnedWeak();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the test object and record it both strongly and weakly.
|
||||
private void remember(int value) {
|
||||
TestObject o = new TestObject(value);
|
||||
registerObject(o);
|
||||
testObject = o;
|
||||
}
|
||||
|
||||
// Remove both strong and weak references to the current test object.
|
||||
private void forget() {
|
||||
unregisterObject();
|
||||
testObject = null;
|
||||
}
|
||||
|
||||
// Repeatedly perform young-only GC until o is in the old generation.
|
||||
private void gcUntilOld(Object o) {
|
||||
while (!WB.isObjectInOldGen(o)) {
|
||||
WB.youngGC();
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the weakly recorded object
|
||||
private void checkValue(int value) throws Exception {
|
||||
Object o = getObject();
|
||||
if (o == null) {
|
||||
throw new RuntimeException("Weak reference unexpectedly null");
|
||||
}
|
||||
TestObject t = (TestObject)o;
|
||||
if (t.value != value) {
|
||||
throw new RuntimeException("Incorrect value");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we can create a weak reference and get it back.
|
||||
private void checkSanity() throws Exception {
|
||||
System.out.println("running checkSanity");
|
||||
try {
|
||||
// Inhibit concurrent GC during this check.
|
||||
WB.requestConcurrentGCPhase("IDLE");
|
||||
|
||||
int value = 5;
|
||||
try {
|
||||
remember(value);
|
||||
checkValue(value);
|
||||
} finally {
|
||||
forget();
|
||||
}
|
||||
|
||||
} finally {
|
||||
// Remove request.
|
||||
WB.requestConcurrentGCPhase("ANY");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify weak ref value survives across collection if strong ref exists.
|
||||
private void checkSurvival() throws Exception {
|
||||
System.out.println("running checkSurvival");
|
||||
try {
|
||||
int value = 10;
|
||||
try {
|
||||
remember(value);
|
||||
checkValue(value);
|
||||
gcUntilOld(testObject);
|
||||
// Run a concurrent collection after object is old.
|
||||
WB.requestConcurrentGCPhase("CONCURRENT_CYCLE");
|
||||
WB.requestConcurrentGCPhase("IDLE");
|
||||
// Verify weak ref still has expected value.
|
||||
checkValue(value);
|
||||
} finally {
|
||||
forget();
|
||||
}
|
||||
} finally {
|
||||
// Remove request.
|
||||
WB.requestConcurrentGCPhase("ANY");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify weak ref cleared if no strong ref exists.
|
||||
private void checkClear() throws Exception {
|
||||
System.out.println("running checkClear");
|
||||
try {
|
||||
int value = 15;
|
||||
try {
|
||||
remember(value);
|
||||
checkValue(value);
|
||||
gcUntilOld(testObject);
|
||||
// Run a concurrent collection after object is old.
|
||||
WB.requestConcurrentGCPhase("CONCURRENT_CYCLE");
|
||||
WB.requestConcurrentGCPhase("IDLE");
|
||||
checkValue(value);
|
||||
testObject = null;
|
||||
// Run a concurrent collection after strong ref removed.
|
||||
WB.requestConcurrentGCPhase("CONCURRENT_CYCLE");
|
||||
WB.requestConcurrentGCPhase("IDLE");
|
||||
// Verify weak ref cleared as expected.
|
||||
Object recorded = getObject();
|
||||
if (recorded != null) {
|
||||
throw new RuntimeException("expected clear");
|
||||
}
|
||||
} finally {
|
||||
forget();
|
||||
}
|
||||
} finally {
|
||||
// Remove request.
|
||||
WB.requestConcurrentGCPhase("ANY");
|
||||
}
|
||||
}
|
||||
|
||||
// Verify weak ref not cleared if no strong ref at start of
|
||||
// collection but weak ref read during marking.
|
||||
private void checkShouldNotClear() throws Exception {
|
||||
System.out.println("running checkShouldNotClear");
|
||||
try {
|
||||
int value = 20;
|
||||
try {
|
||||
remember(value);
|
||||
checkValue(value);
|
||||
gcUntilOld(testObject);
|
||||
// Block concurrent cycle until we're ready.
|
||||
WB.requestConcurrentGCPhase("IDLE");
|
||||
checkValue(value);
|
||||
testObject = null; // Discard strong ref
|
||||
// Run through mark_from_roots.
|
||||
WB.requestConcurrentGCPhase("BEFORE_REMARK");
|
||||
// Fetch weak ref'ed object. Should be kept alive now.
|
||||
Object recovered = getObject();
|
||||
if (recovered == null) {
|
||||
throw new RuntimeException("unexpected clear during mark");
|
||||
}
|
||||
// Finish collection, including reference processing.
|
||||
// Block any further cycles while we finish check.
|
||||
WB.requestConcurrentGCPhase("IDLE");
|
||||
// Fetch weak ref'ed object. Referent is manifestly
|
||||
// live in recovered; the earlier fetch should have
|
||||
// kept it alive through collection, so weak ref
|
||||
// should not have been cleared.
|
||||
if (getObject() == null) {
|
||||
// 8166188 problem results in not doing the
|
||||
// keep-alive of earlier getObject result, so
|
||||
// recovered is now reachable but not marked.
|
||||
// We may eventually crash.
|
||||
throw new RuntimeException("cleared jweak for live object");
|
||||
}
|
||||
Reference.reachabilityFence(recovered);
|
||||
} finally {
|
||||
forget();
|
||||
}
|
||||
} finally {
|
||||
// Remove request.
|
||||
WB.requestConcurrentGCPhase("ANY");
|
||||
}
|
||||
}
|
||||
|
||||
private void check() throws Exception {
|
||||
checkSanity();
|
||||
checkSurvival();
|
||||
checkClear();
|
||||
checkShouldNotClear();
|
||||
System.out.println("Check passed");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Perform check with direct jweak resolution.
|
||||
System.out.println("Check with jweak resolved");
|
||||
new TestJNIWeakG1(true).check();
|
||||
|
||||
// Perform check with implicit jweak resolution by native
|
||||
// call's return value handling.
|
||||
System.out.println("Check with jweak returned");
|
||||
new TestJNIWeakG1(false).check();
|
||||
}
|
||||
}
|
58
hotspot/test/gc/g1/TestJNIWeakG1/libTestJNIWeakG1.c
Normal file
58
hotspot/test/gc/g1/TestJNIWeakG1/libTestJNIWeakG1.c
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Native support for TestJNIWeakG1 test.
|
||||
*/
|
||||
|
||||
#include "jni.h"
|
||||
|
||||
static jweak registered = NULL;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_TestJNIWeakG1_registerObject(JNIEnv* env, jclass jclazz, jobject value) {
|
||||
// assert registered == NULL
|
||||
registered = (*env)->NewWeakGlobalRef(env, value);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_TestJNIWeakG1_unregisterObject(JNIEnv* env, jclass jclazz) {
|
||||
if (registered != NULL) {
|
||||
(*env)->DeleteWeakGlobalRef(env, registered);
|
||||
registered = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Directly return jweak, to be resolved by native call's return value handling.
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_TestJNIWeakG1_getReturnedWeak(JNIEnv* env, jclass jclazz) {
|
||||
// assert registered != NULL
|
||||
return registered;
|
||||
}
|
||||
|
||||
// Directly resolve jweak and return the result.
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_TestJNIWeakG1_getResolvedWeak(JNIEnv* env, jclass jclazz) {
|
||||
// assert registered != NULL
|
||||
return (*env)->NewLocalRef(env, registered);
|
||||
}
|
Loading…
Reference in New Issue
Block a user