Skip to content

Commit cca69f3

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

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
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: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,9 @@
3838
import java.nio.file.Path;
3939
import java.nio.file.Paths;
4040
import java.util.ArrayList;
41+
import java.util.HashSet;
42+
import java.util.List;
43+
import java.util.Set;
4144
import java.util.stream.Stream;
4245

4346
public class ClassUnloadCommon {
@@ -67,6 +70,41 @@ public static void triggerUnloading() {
6770
wb.fullGC(); // will do class unloading
6871
}
6972

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

0 commit comments

Comments
 (0)