Skip to content

Commit 9c92ecb

Browse files
committed
8231125: Improve testing of parallel loading of shared classes by the boot class loader
Reviewed-by: ccheung, coleenp, dholmes
1 parent 83f41d2 commit 9c92ecb

File tree

4 files changed

+75
-31
lines changed

4 files changed

+75
-31
lines changed

src/hotspot/share/classfile/systemDictionary.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,7 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
12701270
TRAPS) {
12711271

12721272
if (ik != NULL) {
1273+
assert(!ik->is_unshareable_info_restored(), "shared class can be loaded only once");
12731274
Symbol* class_name = ik->name();
12741275

12751276
bool visible = is_shared_class_visible(

src/hotspot/share/oops/klass.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,18 @@ class Klass : public Metadata {
524524
virtual void remove_java_mirror();
525525
virtual void restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS);
526526

527+
bool is_unshareable_info_restored() const {
528+
assert(is_shared(), "use this for shared classes only");
529+
if (has_raw_archived_mirror()) {
530+
// _java_mirror is not a valid OopHandle but rather an encoded reference in the shared heap
531+
return false;
532+
} else if (_java_mirror.ptr_raw() == NULL) {
533+
return false;
534+
} else {
535+
return true;
536+
}
537+
}
538+
527539
public:
528540
// subclass accessor (here for convenience; undefined for non-klass objects)
529541
virtual bool is_leaf_class() const { fatal("not a class"); return false; }

test/hotspot/jtreg/runtime/cds/appcds/ParallelLoadTest.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,42 @@
3636
public class ParallelLoadTest {
3737
public static final int MAX_CLASSES = 40;
3838

39+
/* For easy stress testing, do this:
40+
41+
i=0; while jtreg -DParallelLoadTest.app.loops=100 -DParallelLoadTest.boot.loops=100 \
42+
ParallelLoadTest.java; do i=$(expr $i + 1); echo =====$i; done
43+
44+
*/
45+
46+
private static final int APP_LOOPS = Integer.parseInt(System.getProperty("ParallelLoadTest.app.loops", "1"));
47+
private static final int BOOT_LOOPS = Integer.parseInt(System.getProperty("ParallelLoadTest.boot.loops", "1"));
48+
3949
public static void main(String[] args) throws Exception {
4050
JarBuilder.build("parallel_load", getClassList(true));
41-
String appJar = TestCommon.getTestJar("parallel_load.jar");
42-
TestCommon.test(appJar, getClassList(false), "ParallelLoad");
51+
String testJar = TestCommon.getTestJar("parallel_load.jar");
52+
53+
// (1) Load the classes from app class loader
54+
TestCommon.testDump(testJar, getClassList(false));
55+
for (int i = 0; i < APP_LOOPS; i++) {
56+
TestCommon.run("-cp", testJar, "ParallelLoad").assertNormalExit();
57+
}
58+
59+
// (2) Load the classes from boot class loader
60+
String bootcp = "-Xbootclasspath/a:" + testJar;
61+
TestCommon.testDump(null, getClassList(false), bootcp);
62+
for (int i = 0; i < BOOT_LOOPS; i++) {
63+
TestCommon.run(bootcp,
64+
// "-Xlog:class+load=debug",
65+
"ParallelLoad").assertNormalExit();
66+
}
4367
}
4468

4569
private static String[] getClassList(boolean includeWatchdog) {
4670
int extra = includeWatchdog ? 3 : 2;
4771
String[] classList = new String[MAX_CLASSES + extra];
4872

4973
int i;
50-
for (i=0; i<MAX_CLASSES; i++) {
74+
for (i = 0; i < MAX_CLASSES; i++) {
5175
classList[i] = "ParallelClass" + i;
5276
}
5377

test/hotspot/jtreg/runtime/cds/appcds/test-classes/ParallelLoad.java

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.io.*;
2626
import java.net.*;
2727
import java.lang.reflect.Field;
28+
import java.util.concurrent.atomic.AtomicInteger;
2829

2930

3031
// This test helper is parameterized by:
@@ -78,7 +79,7 @@ public static void run(String args[], ClassLoader loaders[]) throws Throwable {
7879
if ("FINGERPRINT_MODE".equals(args[1])) {
7980
mode = FINGERPRINT_MODE;
8081
classLoaders = new ClassLoader[NUM_THREADS];
81-
for (int i=0; i<NUM_THREADS; i++) {
82+
for (int i = 0; i < NUM_THREADS; i++) {
8283
URL url = new File(customJar).toURI().toURL();
8384
URL[] urls = new URL[] {url};
8485
classLoaders[i] = new URLClassLoader(urls);
@@ -93,7 +94,7 @@ public static void run(String args[], ClassLoader loaders[]) throws Throwable {
9394
System.out.println("Start Parallel Load ...");
9495

9596
Thread thread[] = new Thread[NUM_THREADS];
96-
for (int i=0; i<NUM_THREADS; i++) {
97+
for (int i = 0; i < NUM_THREADS; i++) {
9798
Thread t = new ParallelLoadThread(i);
9899
t.start();
99100
thread[i] = t;
@@ -103,7 +104,7 @@ public static void run(String args[], ClassLoader loaders[]) throws Throwable {
103104
watchdog.setDaemon(true);
104105
watchdog.start();
105106

106-
for (int i=0; i<NUM_THREADS; i++) {
107+
for (int i = 0; i < NUM_THREADS; i++) {
107108
thread[i].join();
108109
}
109110
System.out.println("Parallel Load ... done");
@@ -128,8 +129,13 @@ public void run() {
128129

129130

130131
class ParallelLoadThread extends Thread {
131-
static int num_ready[] = new int[ParallelLoad.MAX_CLASSES];
132-
static Object lock = new Object();
132+
static AtomicInteger num_ready[];
133+
static {
134+
num_ready = new AtomicInteger[ParallelLoad.MAX_CLASSES];
135+
for (int i = 0; i < ParallelLoad.MAX_CLASSES; i++) {
136+
num_ready[i] = new AtomicInteger();
137+
}
138+
}
133139
static String transformMode =
134140
System.getProperty("appcds.parallel.transform.mode", "none");
135141

@@ -153,35 +159,36 @@ private static void log(String msg, Object... args) {
153159
}
154160

155161
private void run0() throws Throwable {
156-
for (int i=0; i<ParallelLoad.MAX_CLASSES; i++) {
157-
synchronized(lock) {
158-
num_ready[i] ++;
159-
while (num_ready[i] < ParallelLoad.NUM_THREADS) {
160-
lock.wait();
161-
}
162-
lock.notifyAll();
163-
}
164-
log("this = %s %d", this, i);
162+
for (int i = 0; i < ParallelLoad.MAX_CLASSES; i++) {
165163
String className = "ParallelClass" + i;
166-
if (transformMode.equals("cflh"))
164+
if (transformMode.equals("cflh")) {
167165
className = "ParallelClassTr" + i;
168-
166+
}
169167
Class clazz = null;
170168

171-
switch (ParallelLoad.loaderType) {
172-
case ParallelLoad.SYSTEM_LOADER:
173-
clazz = Class.forName(className);
174-
break;
175-
case ParallelLoad.SINGLE_CUSTOM_LOADER:
176-
clazz = ParallelLoad.classLoaders[0].loadClass(className);
177-
break;
178-
case ParallelLoad.MULTI_CUSTOM_LOADER:
179-
clazz = ParallelLoad.classLoaders[thread_id].loadClass(className);
180-
break;
169+
// Spin until every thread is ready to proceed
170+
num_ready[i].incrementAndGet();
171+
while (num_ready[i].intValue() < ParallelLoad.NUM_THREADS) {
172+
;
173+
}
174+
175+
{ // Avoid logging in this block so the threads can proceed without
176+
// waiting for the stdout lock, etc.
177+
switch (ParallelLoad.loaderType) {
178+
case ParallelLoad.SYSTEM_LOADER:
179+
clazz = Class.forName(className);
180+
break;
181+
case ParallelLoad.SINGLE_CUSTOM_LOADER:
182+
clazz = ParallelLoad.classLoaders[0].loadClass(className);
183+
break;
184+
case ParallelLoad.MULTI_CUSTOM_LOADER:
185+
clazz = ParallelLoad.classLoaders[thread_id].loadClass(className);
186+
break;
187+
}
188+
testTransformation(clazz);
181189
}
182190

183-
log("clazz = %s", clazz);
184-
testTransformation(clazz);
191+
log("thread[%d] t = %s, c = %s, l = %s", thread_id, this, clazz, clazz.getClassLoader());
185192
}
186193
}
187194

0 commit comments

Comments
 (0)