8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @library /test/lib
27 *
28 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=false -Xcheck:jni ClassInitBarrier
29 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -Xint -DTHROW=true -Xcheck:jni ClassInitBarrier
30 *
31 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -Xcheck:jni ClassInitBarrier
32 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -Xcheck:jni ClassInitBarrier
33 *
34 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -Xcheck:jni ClassInitBarrier
35 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -Xcheck:jni ClassInitBarrier
36 *
37 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
38 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
39 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
40 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
41 *
42 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
43 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
44 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
45 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
46 */
47
48 import jdk.test.lib.Asserts;
49
50 import java.util.*;
51 import java.util.concurrent.atomic.AtomicBoolean;
52 import java.util.concurrent.atomic.AtomicInteger;
53 import java.util.function.Consumer;
54
55 public class ClassInitBarrier {
56 static {
57 System.loadLibrary("ClassInitBarrier");
58
59 if (!init()) {
60 throw new Error("init failed");
61 }
62 }
63
64 static native boolean init();
65
66 static final boolean THROW = Boolean.getBoolean("THROW");
67
68 static class Test {
69 static class A {
70 static {
71 if (!init(B.class)) {
72 throw new Error("init failed");
73 }
74
75 changePhase(Phase.IN_PROGRESS);
76 runTests(); // interpreted mode
77 warmup(); // trigger compilation
78 runTests(); // compiled mode
79
80 ensureBlocked(); // ensure still blocked
81 maybeThrow(); // fail initialization if needed
82
83 changePhase(Phase.FINISHED);
84 }
85
86 static void staticM(Runnable action) { action.run(); }
87 static synchronized void staticS(Runnable action) { action.run(); }
88 static native void staticN(Runnable action);
89
90 static int staticF;
91
92 int f;
93 void m() {}
94
95 static native boolean init(Class<B> cls);
96 }
97
98 static class B extends A {}
99
100 static void testInvokeStatic(Runnable action) { A.staticM(action); }
101 static void testInvokeStaticSync(Runnable action) { A.staticS(action); }
102 static void testInvokeStaticNative(Runnable action) { A.staticN(action); }
103
104 static int testGetStatic(Runnable action) { int v = A.staticF; action.run(); return v; }
105 static void testPutStatic(Runnable action) { A.staticF = 1; action.run(); }
106 static A testNewInstanceA(Runnable action) { A obj = new A(); action.run(); return obj; }
107 static B testNewInstanceB(Runnable action) { B obj = new B(); action.run(); return obj; }
108
109 static int testGetField(A recv, Runnable action) { int v = recv.f; action.run(); return v; }
110 static void testPutField(A recv, Runnable action) { recv.f = 1; action.run(); }
111 static void testInvokeVirtual(A recv, Runnable action) { recv.m(); action.run(); }
112
113 static native void testInvokeStaticJNI(Runnable action);
114 static native void testInvokeStaticSyncJNI(Runnable action);
115 static native void testInvokeStaticNativeJNI(Runnable action);
116
117 static native int testGetStaticJNI(Runnable action);
118 static native void testPutStaticJNI(Runnable action);
119 static native A testNewInstanceAJNI(Runnable action);
120 static native B testNewInstanceBJNI(Runnable action);
121
122 static native int testGetFieldJNI(A recv, Runnable action);
123 static native void testPutFieldJNI(A recv, Runnable action);
124 static native void testInvokeVirtualJNI(A recv, Runnable action);
125
126 static void runTests() {
127 checkBlockingAction(Test::testInvokeStatic); // invokestatic
128 checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
129 checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
130 checkBlockingAction(Test::testGetStatic); // getstatic
131 checkBlockingAction(Test::testPutStatic); // putstatic
132 checkBlockingAction(Test::testNewInstanceA); // new
133
134 checkNonBlockingAction(Test::testInvokeStaticJNI); // invokestatic
135 checkNonBlockingAction(Test::testInvokeStaticSyncJNI); // invokestatic
136 checkNonBlockingAction(Test::testInvokeStaticNativeJNI); // invokestatic
137 checkNonBlockingAction(Test::testGetStaticJNI); // getstatic
138 checkNonBlockingAction(Test::testPutStaticJNI); // putstatic
139 checkBlockingAction(Test::testNewInstanceAJNI); // new
140
141 A recv = testNewInstanceB(NON_BLOCKING.get()); // trigger B initialization
142 checkNonBlockingAction(Test::testNewInstanceB); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
143
144 checkNonBlockingAction(recv, Test::testGetField); // getfield
145 checkNonBlockingAction(recv, Test::testPutField); // putfield
146 checkNonBlockingAction(recv, Test::testInvokeVirtual); // invokevirtual
147
148 checkNonBlockingAction(Test::testNewInstanceBJNI); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
149 checkNonBlockingAction(recv, Test::testGetFieldJNI); // getfield
150 checkNonBlockingAction(recv, Test::testPutFieldJNI); // putfield
151 checkNonBlockingAction(recv, Test::testInvokeVirtualJNI); // invokevirtual
152 }
153
154 static void warmup() {
155 for (int i = 0; i < 20_000; i++) {
156 testInvokeStatic( NON_BLOCKING_WARMUP);
157 testInvokeStaticNative(NON_BLOCKING_WARMUP);
158 testInvokeStaticSync( NON_BLOCKING_WARMUP);
159 testGetStatic( NON_BLOCKING_WARMUP);
160 testPutStatic( NON_BLOCKING_WARMUP);
161 testNewInstanceA( NON_BLOCKING_WARMUP);
162 testNewInstanceB( NON_BLOCKING_WARMUP);
163
164 testGetField(new B(), NON_BLOCKING_WARMUP);
165 testPutField(new B(), NON_BLOCKING_WARMUP);
166 testInvokeVirtual(new B(), NON_BLOCKING_WARMUP);
167 }
168 }
169
170 static void run() {
171 execute(ExceptionInInitializerError.class, () -> triggerInitialization(A.class));
172 ensureFinished();
173 runTests(); // after initialization is over
174 }
175 }
176
177 // ============================================================================================================== //
178
179 static void execute(Class<? extends Throwable> expectedExceptionClass, Runnable action) {
180 try {
181 action.run();
182 if (THROW) throw failure("no exception thrown");
183 } catch (Throwable e) {
184 if (THROW) {
185 if (e.getClass() == expectedExceptionClass) {
186 // expected
246 if (ex.getClass() != NoClassDefFoundError.class) {
247 throw new AssertionError(thr + ": wrong exception thrown", ex);
248 }
249 } else {
250 if (FAILED_THREADS.containsKey(thr)) {
251 Throwable ex = FAILED_THREADS.get(thr);
252 throw new AssertionError(thr + ": exception thrown", ex);
253 }
254 }
255 }
256 if (THROW) {
257 Asserts.assertEquals(BLOCKING_COUNTER.get(), 0);
258 } else {
259 Asserts.assertEquals(BLOCKING_COUNTER.get(), BLOCKING_ACTIONS.get());
260 }
261
262 dumpInfo();
263 }
264
265 interface TestCase0 {
266 void run(Runnable runnable);
267 }
268
269 interface TestCase1<T> {
270 void run(T arg, Runnable runnable);
271 }
272
273 enum Phase { BEFORE_INIT, IN_PROGRESS, FINISHED, INIT_FAILURE }
274
275 static volatile Phase phase = Phase.BEFORE_INIT;
276
277 static void changePhase(Phase newPhase) {
278 dumpInfo();
279
280 Phase oldPhase = phase;
281 switch (oldPhase) {
282 case BEFORE_INIT:
283 Asserts.assertEquals(NON_BLOCKING_ACTIONS.get(), 0);
284 Asserts.assertEquals(NON_BLOCKING_COUNTER.get(), 0);
285
286 Asserts.assertEquals(BLOCKING_ACTIONS.get(), 0);
287 Asserts.assertEquals(BLOCKING_COUNTER.get(), 0);
288 break;
289 case IN_PROGRESS:
290 Asserts.assertEquals(NON_BLOCKING_COUNTER.get(), NON_BLOCKING_ACTIONS.get());
320 if (phase != validPhase) {
321 throw new AssertionError("NON_BLOCKING: wrong phase: " + phase);
322 }
323 };
324 }
325
326 @FunctionalInterface
327 interface Factory<V> {
328 V get();
329 }
330
331 static final AtomicInteger NON_BLOCKING_COUNTER = new AtomicInteger(0);
332 static final AtomicInteger NON_BLOCKING_ACTIONS = new AtomicInteger(0);
333 static final Factory<Runnable> NON_BLOCKING = () -> disposableAction(phase, NON_BLOCKING_COUNTER, NON_BLOCKING_ACTIONS);
334
335 static final AtomicInteger BLOCKING_COUNTER = new AtomicInteger(0);
336 static final AtomicInteger BLOCKING_ACTIONS = new AtomicInteger(0);
337 static final Factory<Runnable> BLOCKING = () -> disposableAction(Phase.FINISHED, BLOCKING_COUNTER, BLOCKING_ACTIONS);
338
339 static void checkBlockingAction(TestCase0 r) {
340 switch (phase) {
341 case IN_PROGRESS: {
342 // Barrier during class initalization.
343 r.run(NON_BLOCKING.get()); // initializing thread
344 checkBlocked(ON_BLOCK, ON_FAILURE, r); // different thread
345 break;
346 }
347 case FINISHED: {
348 // No barrier after class initalization is over.
349 r.run(NON_BLOCKING.get()); // initializing thread
350 checkNotBlocked(r); // different thread
351 break;
352 }
353 case INIT_FAILURE: {
354 // Exception is thrown after class initialization failed.
355 TestCase0 test = action -> execute(NoClassDefFoundError.class, () -> r.run(action));
356
357 test.run(NON_BLOCKING.get()); // initializing thread
358 checkNotBlocked(test); // different thread
359 break;
360 }
361 default: throw new Error("wrong phase: " + phase);
362 }
363 }
364
365 static void checkNonBlockingAction(TestCase0 r) {
366 r.run(NON_BLOCKING.get()); // initializing thread
367 checkNotBlocked(r); // different thread
368 }
369
370 static <T> void checkNonBlockingAction(T recv, TestCase1<T> r) {
371 r.run(recv, NON_BLOCKING.get()); // initializing thread
372 checkNotBlocked((action) -> r.run(recv, action)); // different thread
373 }
374
375 static void checkFailingAction(TestCase0 r) {
376 r.run(NON_BLOCKING.get()); // initializing thread
377 checkNotBlocked(r); // different thread
378 }
379
380 static void triggerInitialization(Class<?> cls) {
381 try {
382 Class<?> loadedClass = Class.forName(cls.getName(), true, cls.getClassLoader());
383 if (loadedClass != cls) {
384 throw new Error("wrong class");
385 }
386 } catch (ClassNotFoundException e) {
387 throw new Error(e);
388 }
389 }
390
391 static void checkBlocked(Consumer<Thread> onBlockHandler, Thread.UncaughtExceptionHandler onException, TestCase0 r) {
392 Thread thr = new Thread(() -> {
393 try {
394 r.run(BLOCKING.get());
395 System.out.println("Thread " + Thread.currentThread() + ": Finished successfully");
396 } catch(Throwable e) {
397 System.out.println("Thread " + Thread.currentThread() + ": Exception thrown: " + e);
398 if (!THROW) {
399 e.printStackTrace();
400 }
401 throw e;
402 }
403 } );
404 thr.setUncaughtExceptionHandler(onException);
405
406 thr.start();
407 try {
408 thr.join(100);
409
410 dump(thr);
411 if (thr.isAlive()) {
412 onBlockHandler.accept(thr); // blocked
413 } else {
414 throw new AssertionError("not blocked");
415 }
416 } catch (InterruptedException e) {
417 throw new Error(e);
418 }
419 }
420
421 static void checkNotBlocked(TestCase0 r) {
422 final Thread thr = new Thread(() -> r.run(NON_BLOCKING.get()));
423 final Throwable[] ex = new Throwable[1];
424 thr.setUncaughtExceptionHandler((t, e) -> {
425 if (thr != t) {
426 ex[0] = new Error("wrong thread: " + thr + " vs " + t);
427 } else {
428 ex[0] = e;
429 }
430 });
431
432 thr.start();
433 try {
434 thr.join(15_000);
435 if (thr.isAlive()) {
436 dump(thr);
437 throw new AssertionError("blocked");
438 }
439 } catch (InterruptedException e) {
440 throw new Error(e);
441 }
442
|
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @library /test/lib
27 *
28 * @enablePreview
29 *
30 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -Xcheck:jni ClassInitBarrier
31 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -Xcheck:jni ClassInitBarrier
32 *
33 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
34 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
35 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
36 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=dontinline,*::static* -Xcheck:jni ClassInitBarrier
37 *
38 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
39 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:TieredStopAtLevel=1 -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
40 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=false -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
41 * @run main/othervm/native -Xbatch -XX:CompileCommand=dontinline,*::test* -XX:-TieredCompilation -DTHROW=true -XX:CompileCommand=exclude,*::static* -Xcheck:jni ClassInitBarrier
42 */
43
44 import jdk.test.lib.Asserts;
45
46 import java.util.*;
47 import java.util.concurrent.atomic.AtomicBoolean;
48 import java.util.concurrent.atomic.AtomicInteger;
49 import java.util.function.Consumer;
50
51 public class ClassInitBarrier {
52 static {
53 System.loadLibrary("ClassInitBarrier");
54
55 if (!init()) {
56 throw new Error("init failed");
57 }
58 }
59
60 static native boolean init();
61
62 static final boolean THROW = Boolean.getBoolean("THROW");
63
64 static value class MyValue {
65 int x = 42;
66
67 void verify() {
68 Asserts.assertEquals(x, 42);
69 }
70 }
71
72 static class Test {
73
74 static class A {
75 static {
76 if (!init(B.class)) {
77 throw new Error("init failed");
78 }
79
80 changePhase(Phase.IN_PROGRESS);
81 runTests(); // interpreted mode
82 warmup(); // trigger compilation
83 runTests(); // compiled mode
84
85 ensureBlocked(); // ensure still blocked
86 maybeThrow(); // fail initialization if needed
87
88 changePhase(Phase.FINISHED);
89 }
90
91 static void staticM(Runnable action, MyValue val) { action.run(); val.verify(); }
92 static synchronized void staticS(Runnable action, MyValue val) { action.run(); val.verify(); }
93 static native void staticN(Runnable action, MyValue val);
94
95 static int staticF;
96
97 int f;
98 void m() {}
99
100 static native boolean init(Class<B> cls);
101 }
102
103 static class B extends A {}
104
105 static void testInvokeStatic(Runnable action, MyValue val) { A.staticM(action, val); }
106 static void testInvokeStaticSync(Runnable action, MyValue val) { A.staticS(action, val); }
107 static void testInvokeStaticNative(Runnable action, MyValue val) { A.staticN(action, val); }
108
109 static int testGetStatic(Runnable action, MyValue val) { int v = A.staticF; action.run(); val.verify(); return v; }
110 static void testPutStatic(Runnable action, MyValue val) { A.staticF = 1; action.run(); val.verify(); }
111 static A testNewInstanceA(Runnable action, MyValue val) { A obj = new A(); action.run(); val.verify(); return obj; }
112 static B testNewInstanceB(Runnable action, MyValue val) { B obj = new B(); action.run(); val.verify(); return obj; }
113
114 static int testGetField(A recv, Runnable action, MyValue val) { int v = recv.f; action.run(); val.verify(); return v; }
115 static void testPutField(A recv, Runnable action, MyValue val) { recv.f = 1; action.run(); val.verify(); }
116 static void testInvokeVirtual(A recv, Runnable action, MyValue val) { recv.m(); action.run(); val.verify(); }
117
118 static native void testInvokeStaticJNI(Runnable action, MyValue val);
119 static native void testInvokeStaticSyncJNI(Runnable action, MyValue val);
120 static native void testInvokeStaticNativeJNI(Runnable action, MyValue val);
121
122 static native int testGetStaticJNI(Runnable action, MyValue val);
123 static native void testPutStaticJNI(Runnable action, MyValue val);
124 static native A testNewInstanceAJNI(Runnable action, MyValue val);
125 static native B testNewInstanceBJNI(Runnable action, MyValue val);
126
127 static native int testGetFieldJNI(A recv, Runnable action, MyValue val);
128 static native void testPutFieldJNI(A recv, Runnable action, MyValue val);
129 static native void testInvokeVirtualJNI(A recv, Runnable action, MyValue val);
130
131 static void runTests() {
132 checkBlockingAction(Test::testInvokeStatic); // invokestatic
133 checkBlockingAction(Test::testInvokeStaticSync); // invokestatic
134 checkBlockingAction(Test::testInvokeStaticNative); // invokestatic
135 checkBlockingAction(Test::testGetStatic); // getstatic
136 checkBlockingAction(Test::testPutStatic); // putstatic
137 checkBlockingAction(Test::testNewInstanceA); // new
138
139 checkNonBlockingAction(Test::testInvokeStaticJNI); // invokestatic
140 checkNonBlockingAction(Test::testInvokeStaticSyncJNI); // invokestatic
141 checkNonBlockingAction(Test::testInvokeStaticNativeJNI); // invokestatic
142 checkNonBlockingAction(Test::testGetStaticJNI); // getstatic
143 checkNonBlockingAction(Test::testPutStaticJNI); // putstatic
144 checkBlockingAction(Test::testNewInstanceAJNI); // new
145
146 A recv = testNewInstanceB(NON_BLOCKING.get(), new MyValue()); // trigger B initialization
147 checkNonBlockingAction(Test::testNewInstanceB); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
148
149 checkNonBlockingAction(recv, Test::testGetField); // getfield
150 checkNonBlockingAction(recv, Test::testPutField); // putfield
151 checkNonBlockingAction(recv, Test::testInvokeVirtual); // invokevirtual
152
153 checkNonBlockingAction(Test::testNewInstanceBJNI); // new: NO BLOCKING: same thread: A being initialized, B fully initialized
154 checkNonBlockingAction(recv, Test::testGetFieldJNI); // getfield
155 checkNonBlockingAction(recv, Test::testPutFieldJNI); // putfield
156 checkNonBlockingAction(recv, Test::testInvokeVirtualJNI); // invokevirtual
157 }
158
159 static void warmup() {
160 MyValue val = new MyValue();
161 for (int i = 0; i < 20_000; i++) {
162 testInvokeStatic( NON_BLOCKING_WARMUP, val);
163 testInvokeStaticNative(NON_BLOCKING_WARMUP, val);
164 testInvokeStaticSync( NON_BLOCKING_WARMUP, val);
165 testGetStatic( NON_BLOCKING_WARMUP, val);
166 testPutStatic( NON_BLOCKING_WARMUP, val);
167 testNewInstanceA( NON_BLOCKING_WARMUP, val);
168 testNewInstanceB( NON_BLOCKING_WARMUP, val);
169
170 testGetField(new B(), NON_BLOCKING_WARMUP, val);
171 testPutField(new B(), NON_BLOCKING_WARMUP, val);
172 testInvokeVirtual(new B(), NON_BLOCKING_WARMUP, val);
173 }
174 }
175
176 static void run() {
177 execute(ExceptionInInitializerError.class, () -> triggerInitialization(A.class));
178 ensureFinished();
179 runTests(); // after initialization is over
180 }
181 }
182
183 // ============================================================================================================== //
184
185 static void execute(Class<? extends Throwable> expectedExceptionClass, Runnable action) {
186 try {
187 action.run();
188 if (THROW) throw failure("no exception thrown");
189 } catch (Throwable e) {
190 if (THROW) {
191 if (e.getClass() == expectedExceptionClass) {
192 // expected
252 if (ex.getClass() != NoClassDefFoundError.class) {
253 throw new AssertionError(thr + ": wrong exception thrown", ex);
254 }
255 } else {
256 if (FAILED_THREADS.containsKey(thr)) {
257 Throwable ex = FAILED_THREADS.get(thr);
258 throw new AssertionError(thr + ": exception thrown", ex);
259 }
260 }
261 }
262 if (THROW) {
263 Asserts.assertEquals(BLOCKING_COUNTER.get(), 0);
264 } else {
265 Asserts.assertEquals(BLOCKING_COUNTER.get(), BLOCKING_ACTIONS.get());
266 }
267
268 dumpInfo();
269 }
270
271 interface TestCase0 {
272 void run(Runnable runnable, MyValue val);
273 }
274
275 interface TestCase1<T> {
276 void run(T arg, Runnable runnable, MyValue val);
277 }
278
279 enum Phase { BEFORE_INIT, IN_PROGRESS, FINISHED, INIT_FAILURE }
280
281 static volatile Phase phase = Phase.BEFORE_INIT;
282
283 static void changePhase(Phase newPhase) {
284 dumpInfo();
285
286 Phase oldPhase = phase;
287 switch (oldPhase) {
288 case BEFORE_INIT:
289 Asserts.assertEquals(NON_BLOCKING_ACTIONS.get(), 0);
290 Asserts.assertEquals(NON_BLOCKING_COUNTER.get(), 0);
291
292 Asserts.assertEquals(BLOCKING_ACTIONS.get(), 0);
293 Asserts.assertEquals(BLOCKING_COUNTER.get(), 0);
294 break;
295 case IN_PROGRESS:
296 Asserts.assertEquals(NON_BLOCKING_COUNTER.get(), NON_BLOCKING_ACTIONS.get());
326 if (phase != validPhase) {
327 throw new AssertionError("NON_BLOCKING: wrong phase: " + phase);
328 }
329 };
330 }
331
332 @FunctionalInterface
333 interface Factory<V> {
334 V get();
335 }
336
337 static final AtomicInteger NON_BLOCKING_COUNTER = new AtomicInteger(0);
338 static final AtomicInteger NON_BLOCKING_ACTIONS = new AtomicInteger(0);
339 static final Factory<Runnable> NON_BLOCKING = () -> disposableAction(phase, NON_BLOCKING_COUNTER, NON_BLOCKING_ACTIONS);
340
341 static final AtomicInteger BLOCKING_COUNTER = new AtomicInteger(0);
342 static final AtomicInteger BLOCKING_ACTIONS = new AtomicInteger(0);
343 static final Factory<Runnable> BLOCKING = () -> disposableAction(Phase.FINISHED, BLOCKING_COUNTER, BLOCKING_ACTIONS);
344
345 static void checkBlockingAction(TestCase0 r) {
346 MyValue val = new MyValue();
347 switch (phase) {
348 case IN_PROGRESS: {
349 // Barrier during class initalization.
350 r.run(NON_BLOCKING.get(), val); // initializing thread
351 checkBlocked(ON_BLOCK, ON_FAILURE, r); // different thread
352 break;
353 }
354 case FINISHED: {
355 // No barrier after class initalization is over.
356 r.run(NON_BLOCKING.get(), val); // initializing thread
357 checkNotBlocked(r); // different thread
358 break;
359 }
360 case INIT_FAILURE: {
361 // Exception is thrown after class initialization failed.
362 TestCase0 test = (action, valarg) -> execute(NoClassDefFoundError.class, () -> r.run(action, valarg));
363
364 test.run(NON_BLOCKING.get(), val); // initializing thread
365 checkNotBlocked(test); // different thread
366 break;
367 }
368 default: throw new Error("wrong phase: " + phase);
369 }
370 }
371
372 static void checkNonBlockingAction(TestCase0 r) {
373 r.run(NON_BLOCKING.get(), new MyValue()); // initializing thread
374 checkNotBlocked(r); // different thread
375 }
376
377 static <T> void checkNonBlockingAction(T recv, TestCase1<T> r) {
378 r.run(recv, NON_BLOCKING.get(), new MyValue()); // initializing thread
379 checkNotBlocked((action, val) -> r.run(recv, action, val)); // different thread
380 }
381
382 static void checkFailingAction(TestCase0 r) {
383 r.run(NON_BLOCKING.get(), new MyValue()); // initializing thread
384 checkNotBlocked(r); // different thread
385 }
386
387 static void triggerInitialization(Class<?> cls) {
388 try {
389 Class<?> loadedClass = Class.forName(cls.getName(), true, cls.getClassLoader());
390 if (loadedClass != cls) {
391 throw new Error("wrong class");
392 }
393 } catch (ClassNotFoundException e) {
394 throw new Error(e);
395 }
396 }
397
398 static void checkBlocked(Consumer<Thread> onBlockHandler, Thread.UncaughtExceptionHandler onException, TestCase0 r) {
399 Thread thr = new Thread(() -> {
400 try {
401 r.run(BLOCKING.get(), new MyValue());
402 System.out.println("Thread " + Thread.currentThread() + ": Finished successfully");
403 } catch(Throwable e) {
404 System.out.println("Thread " + Thread.currentThread() + ": Exception thrown: " + e);
405 if (!THROW) {
406 e.printStackTrace();
407 }
408 throw e;
409 }
410 } );
411 thr.setUncaughtExceptionHandler(onException);
412
413 thr.start();
414 try {
415 thr.join(100);
416
417 dump(thr);
418 if (thr.isAlive()) {
419 onBlockHandler.accept(thr); // blocked
420 } else {
421 throw new AssertionError("not blocked");
422 }
423 } catch (InterruptedException e) {
424 throw new Error(e);
425 }
426 }
427
428 static void checkNotBlocked(TestCase0 r) {
429 final Thread thr = new Thread(() -> r.run(NON_BLOCKING.get(), new MyValue()));
430 final Throwable[] ex = new Throwable[1];
431 thr.setUncaughtExceptionHandler((t, e) -> {
432 if (thr != t) {
433 ex[0] = new Error("wrong thread: " + thr + " vs " + t);
434 } else {
435 ex[0] = e;
436 }
437 });
438
439 thr.start();
440 try {
441 thr.join(15_000);
442 if (thr.isAlive()) {
443 dump(thr);
444 throw new AssertionError("blocked");
445 }
446 } catch (InterruptedException e) {
447 throw new Error(e);
448 }
449
|