File: TestJNIWeak.java

package info (click to toggle)
openjdk-21 21.0.9%2B10-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 821,844 kB
  • sloc: java: 5,620,360; xml: 1,643,607; cpp: 1,297,809; ansic: 421,231; asm: 404,850; objc: 21,018; sh: 15,299; javascript: 11,217; python: 6,895; makefile: 2,367; perl: 357; awk: 351; sed: 172; jsp: 24; csh: 3
file content (265 lines) | stat: -rw-r--r-- 9,276 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
 * Copyright (c) 2017, 2022, 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.
 */

package gc.TestJNIWeak;

/* @test
 * @bug 8166188 8178813
 * @summary Test return of JNI weak global refs during concurrent
 * marking, verifying the use of the load barrier to keep the
 * referent alive.
 * @library /test/lib
 * @build jdk.test.whitebox.WhiteBox
 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 * @run main/othervm/native
 *    -Xbootclasspath/a:.
 *    -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
 *    -Xint
 *    gc.TestJNIWeak.TestJNIWeak
 * @run main/othervm/native
 *    -Xbootclasspath/a:.
 *    -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
 *    -Xcomp
 *    gc.TestJNIWeak.TestJNIWeak
 */

import jdk.test.whitebox.gc.GC;
import jdk.test.whitebox.WhiteBox;
import jtreg.SkippedException;
import java.lang.ref.Reference;

public final class TestJNIWeak {

    static {
        System.loadLibrary("TestJNIWeak");
    }

    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;

    TestJNIWeak(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 full GC until o is in the old generation.
    private void gcUntilOld(Object o) {
        while (!WB.isObjectInOldGen(o)) {
            WB.fullGC();
        }
    }

    // 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.concurrentGCAcquireControl();

            int value = 5;
            try {
                remember(value);
                checkValue(value);
            } finally {
                forget();
            }

        } finally {
            WB.concurrentGCReleaseControl();
        }
    }

    // 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.concurrentGCAcquireControl();
                WB.concurrentGCRunTo(WB.AFTER_MARKING_STARTED);
                WB.concurrentGCRunToIdle();
                // Verify weak ref still has expected value.
                checkValue(value);
            } finally {
                forget();
            }
        } finally {
            WB.concurrentGCReleaseControl();
        }
    }

    // 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.concurrentGCAcquireControl();
                WB.concurrentGCRunTo(WB.AFTER_MARKING_STARTED);
                WB.concurrentGCRunToIdle();
                checkValue(value);
                testObject = null;
                // Run a concurrent collection after strong ref removed.
                WB.concurrentGCRunTo(WB.AFTER_MARKING_STARTED);
                WB.concurrentGCRunToIdle();
                // Verify weak ref cleared as expected.
                Object recorded = getObject();
                if (recorded != null) {
                    throw new RuntimeException("expected clear");
                }
            } finally {
                forget();
            }
        } finally {
            WB.concurrentGCReleaseControl();
        }
    }

    // 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.concurrentGCAcquireControl();
                checkValue(value);
                testObject = null; // Discard strong ref
                // Run through most of marking
                WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED);
                // 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.concurrentGCRunToIdle();
                // 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 {
            WB.concurrentGCReleaseControl();
        }
    }

    private void check() throws Exception {
        checkSanity();
        checkSurvival();
        checkClear();
        checkShouldNotClear();
        System.out.println("Check passed");
    }

    public static void main(String[] args) throws Exception {
        if (!WB.supportsConcurrentGCBreakpoints()) {
            throw new SkippedException(
                GC.selected().name() + " doesn't support concurrent GC breakpoints");
        }

        // Perform check with direct jweak resolution.
        System.out.println("Check with jweak resolved");
        new TestJNIWeak(true).check();

        // Perform check with implicit jweak resolution by native
        // call's return value handling.
        System.out.println("Check with jweak returned");
        new TestJNIWeak(false).check();
    }
}