33 |
33 |
34 PerfCounter* DependencyContext::_perf_total_buckets_allocated_count = NULL; |
34 PerfCounter* DependencyContext::_perf_total_buckets_allocated_count = NULL; |
35 PerfCounter* DependencyContext::_perf_total_buckets_deallocated_count = NULL; |
35 PerfCounter* DependencyContext::_perf_total_buckets_deallocated_count = NULL; |
36 PerfCounter* DependencyContext::_perf_total_buckets_stale_count = NULL; |
36 PerfCounter* DependencyContext::_perf_total_buckets_stale_count = NULL; |
37 PerfCounter* DependencyContext::_perf_total_buckets_stale_acc_count = NULL; |
37 PerfCounter* DependencyContext::_perf_total_buckets_stale_acc_count = NULL; |
38 nmethodBucket* volatile DependencyContext::_purge_list = NULL; |
38 nmethodBucket* volatile DependencyContext::_purge_list = NULL; |
39 volatile uint64_t DependencyContext::_cleaning_epoch = 0; |
39 volatile uint64_t DependencyContext::_cleaning_epoch = 0; |
|
40 uint64_t DependencyContext::_cleaning_epoch_monotonic = 0; |
40 |
41 |
41 void dependencyContext_init() { |
42 void dependencyContext_init() { |
42 DependencyContext::init(); |
43 DependencyContext::init(); |
43 } |
44 } |
44 |
45 |
260 |
261 |
261 int nmethodBucket::decrement() { |
262 int nmethodBucket::decrement() { |
262 return Atomic::sub(1, &_count); |
263 return Atomic::sub(1, &_count); |
263 } |
264 } |
264 |
265 |
265 // We use a safepoint counter to track the safepoint counter the last time a given |
266 // We use a monotonically increasing epoch counter to track the last epoch a given |
266 // dependency context was cleaned. GC threads claim cleanup tasks by performing |
267 // dependency context was cleaned. GC threads claim cleanup tasks by performing |
267 // a CAS on this value. |
268 // a CAS on this value. |
268 bool DependencyContext::claim_cleanup() { |
269 bool DependencyContext::claim_cleanup() { |
269 uint64_t cleaning_epoch = Atomic::load(&_cleaning_epoch); |
270 uint64_t cleaning_epoch = Atomic::load(&_cleaning_epoch); |
270 uint64_t last_cleanup = Atomic::load(_last_cleanup_addr); |
271 uint64_t last_cleanup = Atomic::load(_last_cleanup_addr); |
309 // After the gc_prologue, the dependency contexts may be claimed by the GC |
310 // After the gc_prologue, the dependency contexts may be claimed by the GC |
310 // and releasing of nmethodBucket entries will be deferred and placed on |
311 // and releasing of nmethodBucket entries will be deferred and placed on |
311 // a purge list to be deleted later. |
312 // a purge list to be deleted later. |
312 void DependencyContext::cleaning_start() { |
313 void DependencyContext::cleaning_start() { |
313 assert(SafepointSynchronize::is_at_safepoint(), "must be"); |
314 assert(SafepointSynchronize::is_at_safepoint(), "must be"); |
314 uint64_t epoch = SafepointSynchronize::safepoint_counter(); |
315 uint64_t epoch = ++_cleaning_epoch_monotonic; |
315 Atomic::store(epoch, &_cleaning_epoch); |
316 Atomic::store(epoch, &_cleaning_epoch); |
316 } |
317 } |
317 |
318 |
318 // The epilogue marks the end of dependency context cleanup by the GC, |
319 // The epilogue marks the end of dependency context cleanup by the GC, |
319 // and also makes subsequent releases of nmethodBuckets case immediate |
320 // and also makes subsequent releases of nmethodBuckets cause immediate |
320 // deletion. It is admitted to end the cleanup in a concurrent phase. |
321 // deletion. It is okay to delay calling of cleaning_end() to a concurrent |
|
322 // phase, subsequent to the safepoint operation in which cleaning_start() |
|
323 // was called. That allows dependency contexts to be cleaned concurrently. |
321 void DependencyContext::cleaning_end() { |
324 void DependencyContext::cleaning_end() { |
322 uint64_t epoch = 0; |
325 uint64_t epoch = 0; |
323 Atomic::store(epoch, &_cleaning_epoch); |
326 Atomic::store(epoch, &_cleaning_epoch); |
324 } |
327 } |
325 |
328 |