Skip to content

Commit

Permalink
8319955: Improve dependencies removal during class unloading
Browse files Browse the repository at this point in the history
Reviewed-by: stuefe
Backport-of: fbe19378c38decaff221f6570d1b78bb801a5e5d
  • Loading branch information
GoeLin committed Apr 19, 2024
1 parent 2a3c4fc commit 7c63791
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
43 changes: 39 additions & 4 deletions src/hotspot/share/code/dependencyContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ void DependencyContext::add_dependent_nmethod(nmethod* nm) {
}

void DependencyContext::release(nmethodBucket* b) {
bool expunge = Atomic::load(&_cleaning_epoch) == 0;
if (expunge) {
if (delete_on_release()) {
assert_locked_or_safepoint(CodeCache_lock);
delete b;
if (UsePerfData) {
Expand Down Expand Up @@ -178,9 +177,41 @@ nmethodBucket* DependencyContext::release_and_get_next_not_unloading(nmethodBuck
//
// Invalidate all dependencies in the context
void DependencyContext::remove_all_dependents() {
nmethodBucket* b = dependencies_not_unloading();
// Assume that the dependency is not deleted immediately but moved into the
// purge list when calling this.
assert(!delete_on_release(), "should not delete on release");

nmethodBucket* first = Atomic::load_acquire(_dependency_context_addr);
if (first == nullptr) {
return;
}

nmethodBucket* cur = first;
nmethodBucket* last = cur;
jlong count = 0;
for (; cur != nullptr; cur = cur->next()) {
assert(cur->get_nmethod()->is_unloading(), "must be");
last = cur;
count++;
}

// Add the whole list to the purge list at once.
nmethodBucket* old_purge_list_head = Atomic::load(&_purge_list);
for (;;) {
last->set_purge_list_next(old_purge_list_head);
nmethodBucket* next_purge_list_head = Atomic::cmpxchg(&_purge_list, old_purge_list_head, first);
if (old_purge_list_head == next_purge_list_head) {
break;
}
old_purge_list_head = next_purge_list_head;
}

if (UsePerfData) {
_perf_total_buckets_stale_count->inc(count);
_perf_total_buckets_stale_acc_count->inc(count);
}

set_dependencies(nullptr);
assert(b == nullptr, "All dependents should be unloading");
}

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

bool DependencyContext::delete_on_release() {
return Atomic::load(&_cleaning_epoch) == 0;
}

// Retrieve the first nmethodBucket that has a dependent that does not correspond to
// an is_unloading nmethod. Any nmethodBucket entries observed from the original head
// that is_unloading() will be unlinked and placed on the purge list.
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/code/dependencyContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class DependencyContext : public StackObj {
volatile uint64_t* _last_cleanup_addr;

bool claim_cleanup();
static bool delete_on_release();
void set_dependencies(nmethodBucket* b);
nmethodBucket* dependencies();
nmethodBucket* dependencies_not_unloading();
Expand Down

1 comment on commit 7c63791

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.