Skip to content

Commit fbe1937

Browse files
author
Thomas Schatzl
committed
8319955: Improve dependencies removal during class unloading
Reviewed-by: dholmes, eosterlund
1 parent 4c1540b commit fbe1937

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

src/hotspot/share/code/dependencyContext.cpp

+39-4
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ void DependencyContext::add_dependent_nmethod(nmethod* nm) {
111111
}
112112

113113
void DependencyContext::release(nmethodBucket* b) {
114-
bool expunge = Atomic::load(&_cleaning_epoch) == 0;
115-
if (expunge) {
114+
if (delete_on_release()) {
116115
assert_locked_or_safepoint(CodeCache_lock);
117116
delete b;
118117
if (UsePerfData) {
@@ -178,9 +177,41 @@ nmethodBucket* DependencyContext::release_and_get_next_not_unloading(nmethodBuck
178177
//
179178
// Invalidate all dependencies in the context
180179
void DependencyContext::remove_all_dependents() {
181-
nmethodBucket* b = dependencies_not_unloading();
180+
// Assume that the dependency is not deleted immediately but moved into the
181+
// purge list when calling this.
182+
assert(!delete_on_release(), "should not delete on release");
183+
184+
nmethodBucket* first = Atomic::load_acquire(_dependency_context_addr);
185+
if (first == nullptr) {
186+
return;
187+
}
188+
189+
nmethodBucket* cur = first;
190+
nmethodBucket* last = cur;
191+
jlong count = 0;
192+
for (; cur != nullptr; cur = cur->next()) {
193+
assert(cur->get_nmethod()->is_unloading(), "must be");
194+
last = cur;
195+
count++;
196+
}
197+
198+
// Add the whole list to the purge list at once.
199+
nmethodBucket* old_purge_list_head = Atomic::load(&_purge_list);
200+
for (;;) {
201+
last->set_purge_list_next(old_purge_list_head);
202+
nmethodBucket* next_purge_list_head = Atomic::cmpxchg(&_purge_list, old_purge_list_head, first);
203+
if (old_purge_list_head == next_purge_list_head) {
204+
break;
205+
}
206+
old_purge_list_head = next_purge_list_head;
207+
}
208+
209+
if (UsePerfData) {
210+
_perf_total_buckets_stale_count->inc(count);
211+
_perf_total_buckets_stale_acc_count->inc(count);
212+
}
213+
182214
set_dependencies(nullptr);
183-
assert(b == nullptr, "All dependents should be unloading");
184215
}
185216

186217
void DependencyContext::remove_and_mark_for_deoptimization_all_dependents(DeoptimizationScope* deopt_scope) {
@@ -234,6 +265,10 @@ bool DependencyContext::claim_cleanup() {
234265
return Atomic::cmpxchg(_last_cleanup_addr, last_cleanup, cleaning_epoch) == last_cleanup;
235266
}
236267

268+
bool DependencyContext::delete_on_release() {
269+
return Atomic::load(&_cleaning_epoch) == 0;
270+
}
271+
237272
// Retrieve the first nmethodBucket that has a dependent that does not correspond to
238273
// an is_unloading nmethod. Any nmethodBucket entries observed from the original head
239274
// that is_unloading() will be unlinked and placed on the purge list.

src/hotspot/share/code/dependencyContext.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class DependencyContext : public StackObj {
7575
volatile uint64_t* _last_cleanup_addr;
7676

7777
bool claim_cleanup();
78+
static bool delete_on_release();
7879
void set_dependencies(nmethodBucket* b);
7980
nmethodBucket* dependencies();
8081
nmethodBucket* dependencies_not_unloading();

0 commit comments

Comments
 (0)