Skip to content

Commit 43f358f

Browse files
committed
8319932: [JVMCI] class unloading related tests can fail on libgraal
Backport-of: 7d53559d2f8f3c27f4d764f081fb031f7660c50b
1 parent 72bcd82 commit 43f358f

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

test/hotspot/jtreg/runtime/ClassInitErrors/InitExceptionUnloadTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737

3838
import java.io.ByteArrayOutputStream;
3939
import java.io.PrintStream;
40+
import java.util.Set;
41+
import java.util.List;
4042

4143
import jdk.test.whitebox.WhiteBox;
4244
import jdk.test.lib.classloader.ClassUnloadCommon;
@@ -122,10 +124,9 @@ static void test() throws Throwable {
122124
}
123125
}
124126
cl = null;
125-
ClassUnloadCommon.triggerUnloading(); // should unload these classes
126-
for (String className : classNames) {
127-
ClassUnloadCommon.failIf(wb.isClassAlive(className), "should be unloaded");
128-
}
127+
128+
Set<String> aliveClasses = ClassUnloadCommon.triggerUnloading(List.of(classNames));
129+
ClassUnloadCommon.failIf(!aliveClasses.isEmpty(), "should be unloaded: " + aliveClasses);
129130
}
130131
public static void main(java.lang.String[] unused) throws Throwable {
131132
test();

test/lib/jdk/test/lib/classloader/ClassUnloadCommon.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
import java.nio.file.Path;
4040
import java.nio.file.Paths;
4141
import java.util.ArrayList;
42+
import java.util.HashSet;
43+
import java.util.List;
44+
import java.util.Set;
4245
import java.util.stream.Stream;
4346

4447
public class ClassUnloadCommon {
@@ -71,6 +74,41 @@ public static void triggerUnloading() {
7174
wb.fullGC(); // will do class unloading
7275
}
7376

77+
/**
78+
* Calls triggerUnloading() in a retry loop for 2 seconds or until WhiteBox.isClassAlive
79+
* determines that no classes named in classNames are alive.
80+
*
81+
* This variant of triggerUnloading() accommodates the inherent raciness
82+
* of class unloading. For example, it's possible for a JIT compilation to hold
83+
* strong roots to types (e.g. in virtual call or instanceof profiles) that
84+
* are not released or converted to weak roots until the compilation completes.
85+
*
86+
* @param classNames the set of classes that are expected to be unloaded
87+
* @return the set of classes that have not been unloaded after exiting the retry loop
88+
*/
89+
public static Set<String> triggerUnloading(List<String> classNames) {
90+
WhiteBox wb = WhiteBox.getWhiteBox();
91+
Set<String> aliveClasses = new HashSet<>(classNames);
92+
int attempt = 0;
93+
while (!aliveClasses.isEmpty() && attempt < 20) {
94+
ClassUnloadCommon.triggerUnloading();
95+
for (String className : classNames) {
96+
if (aliveClasses.contains(className)) {
97+
if (wb.isClassAlive(className)) {
98+
try {
99+
Thread.sleep(100);
100+
} catch (InterruptedException ex) {
101+
}
102+
} else {
103+
aliveClasses.remove(className);
104+
}
105+
}
106+
}
107+
attempt++;
108+
}
109+
return aliveClasses;
110+
}
111+
74112
/**
75113
* Creates a class loader that loads classes from {@code ${test.class.path}}
76114
* before delegating to the system class loader.

0 commit comments

Comments
 (0)