Path: blob/master/test/hotspot/jtreg/gc/TestJNIWeak/TestJNIWeak.java
40942 views
/*1* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package gc.TestJNIWeak;2425/* @test26* @bug 8166188 817881327* @summary Test return of JNI weak global refs during concurrent28* marking, verifying the use of the load barrier to keep the29* referent alive.30* @library /test/lib31* @build sun.hotspot.WhiteBox32* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox33* @run main/othervm/native34* -Xbootclasspath/a:.35* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI36* -Xint37* gc.TestJNIWeak.TestJNIWeak38* @run main/othervm/native39* -Xbootclasspath/a:.40* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI41* -Xcomp42* gc.TestJNIWeak.TestJNIWeak43*/4445import sun.hotspot.gc.GC;46import sun.hotspot.WhiteBox;47import jtreg.SkippedException;48import java.lang.ref.Reference;4950public final class TestJNIWeak {5152static {53System.loadLibrary("TestJNIWeak");54}5556private static final WhiteBox WB = WhiteBox.getWhiteBox();5758private static final class TestObject {59public final int value;6061public TestObject(int value) {62this.value = value;63}64}6566private volatile TestObject testObject = null;6768private static native void registerObject(Object o);69private static native void unregisterObject();70private static native Object getReturnedWeak();71private static native Object getResolvedWeak();7273// resolve controls whether getObject returns an explicitly74// resolved jweak value (when resolve is true), or returns the75// jweak directly and invokes the implicit resolution in the76// native call return value handling path (when resolve is false).77private boolean resolve = true;7879TestJNIWeak(boolean resolve) {80this.resolve = resolve;81}8283private Object getObject() {84if (resolve) {85return getResolvedWeak();86} else {87return getReturnedWeak();88}89}9091// Create the test object and record it both strongly and weakly.92private void remember(int value) {93TestObject o = new TestObject(value);94registerObject(o);95testObject = o;96}9798// Remove both strong and weak references to the current test object.99private void forget() {100unregisterObject();101testObject = null;102}103104// Repeatedly perform full GC until o is in the old generation.105private void gcUntilOld(Object o) {106while (!WB.isObjectInOldGen(o)) {107WB.fullGC();108}109}110111// Verify the weakly recorded object112private void checkValue(int value) throws Exception {113Object o = getObject();114if (o == null) {115throw new RuntimeException("Weak reference unexpectedly null");116}117TestObject t = (TestObject)o;118if (t.value != value) {119throw new RuntimeException("Incorrect value");120}121}122123// Verify we can create a weak reference and get it back.124private void checkSanity() throws Exception {125System.out.println("running checkSanity");126try {127// Inhibit concurrent GC during this check.128WB.concurrentGCAcquireControl();129130int value = 5;131try {132remember(value);133checkValue(value);134} finally {135forget();136}137138} finally {139WB.concurrentGCReleaseControl();140}141}142143// Verify weak ref value survives across collection if strong ref exists.144private void checkSurvival() throws Exception {145System.out.println("running checkSurvival");146try {147int value = 10;148try {149remember(value);150checkValue(value);151gcUntilOld(testObject);152// Run a concurrent collection after object is old.153WB.concurrentGCAcquireControl();154WB.concurrentGCRunTo(WB.AFTER_MARKING_STARTED);155WB.concurrentGCRunToIdle();156// Verify weak ref still has expected value.157checkValue(value);158} finally {159forget();160}161} finally {162WB.concurrentGCReleaseControl();163}164}165166// Verify weak ref cleared if no strong ref exists.167private void checkClear() throws Exception {168System.out.println("running checkClear");169try {170int value = 15;171try {172remember(value);173checkValue(value);174gcUntilOld(testObject);175// Run a concurrent collection after object is old.176WB.concurrentGCAcquireControl();177WB.concurrentGCRunTo(WB.AFTER_MARKING_STARTED);178WB.concurrentGCRunToIdle();179checkValue(value);180testObject = null;181// Run a concurrent collection after strong ref removed.182WB.concurrentGCRunTo(WB.AFTER_MARKING_STARTED);183WB.concurrentGCRunToIdle();184// Verify weak ref cleared as expected.185Object recorded = getObject();186if (recorded != null) {187throw new RuntimeException("expected clear");188}189} finally {190forget();191}192} finally {193WB.concurrentGCReleaseControl();194}195}196197// Verify weak ref not cleared if no strong ref at start of198// collection but weak ref read during marking.199private void checkShouldNotClear() throws Exception {200System.out.println("running checkShouldNotClear");201try {202int value = 20;203try {204remember(value);205checkValue(value);206gcUntilOld(testObject);207// Block concurrent cycle until we're ready.208WB.concurrentGCAcquireControl();209checkValue(value);210testObject = null; // Discard strong ref211// Run through most of marking212WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED);213// Fetch weak ref'ed object. Should be kept alive now.214Object recovered = getObject();215if (recovered == null) {216throw new RuntimeException("unexpected clear during mark");217}218// Finish collection, including reference processing.219// Block any further cycles while we finish check.220WB.concurrentGCRunToIdle();221// Fetch weak ref'ed object. Referent is manifestly222// live in recovered; the earlier fetch should have223// kept it alive through collection, so weak ref224// should not have been cleared.225if (getObject() == null) {226// 8166188 problem results in not doing the227// keep-alive of earlier getObject result, so228// recovered is now reachable but not marked.229// We may eventually crash.230throw new RuntimeException("cleared jweak for live object");231}232Reference.reachabilityFence(recovered);233} finally {234forget();235}236} finally {237WB.concurrentGCReleaseControl();238}239}240241private void check() throws Exception {242checkSanity();243checkSurvival();244checkClear();245checkShouldNotClear();246System.out.println("Check passed");247}248249public static void main(String[] args) throws Exception {250if (!WB.supportsConcurrentGCBreakpoints()) {251throw new SkippedException(252GC.selected().name() + " doesn't support concurrent GC breakpoints");253}254255// Perform check with direct jweak resolution.256System.out.println("Check with jweak resolved");257new TestJNIWeak(true).check();258259// Perform check with implicit jweak resolution by native260// call's return value handling.261System.out.println("Check with jweak returned");262new TestJNIWeak(false).check();263}264}265266267