@@ -111,8 +111,7 @@ void DependencyContext::add_dependent_nmethod(nmethod* nm) {
111
111
}
112
112
113
113
void DependencyContext::release (nmethodBucket* b) {
114
- bool expunge = Atomic::load (&_cleaning_epoch) == 0 ;
115
- if (expunge) {
114
+ if (delete_on_release ()) {
116
115
assert_locked_or_safepoint (CodeCache_lock);
117
116
delete b;
118
117
if (UsePerfData) {
@@ -178,9 +177,41 @@ nmethodBucket* DependencyContext::release_and_get_next_not_unloading(nmethodBuck
178
177
//
179
178
// Invalidate all dependencies in the context
180
179
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
+
182
214
set_dependencies (nullptr );
183
- assert (b == nullptr , " All dependents should be unloading" );
184
215
}
185
216
186
217
void DependencyContext::remove_and_mark_for_deoptimization_all_dependents (DeoptimizationScope* deopt_scope) {
@@ -234,6 +265,10 @@ bool DependencyContext::claim_cleanup() {
234
265
return Atomic::cmpxchg (_last_cleanup_addr, last_cleanup, cleaning_epoch) == last_cleanup;
235
266
}
236
267
268
+ bool DependencyContext::delete_on_release () {
269
+ return Atomic::load (&_cleaning_epoch) == 0 ;
270
+ }
271
+
237
272
// Retrieve the first nmethodBucket that has a dependent that does not correspond to
238
273
// an is_unloading nmethod. Any nmethodBucket entries observed from the original head
239
274
// that is_unloading() will be unlinked and placed on the purge list.
0 commit comments