Skip to content

Commit 92b43c5

Browse files
committed
8317007: Add bulk removal of dead nmethods during class unloading
Backport-of: f55381950266088cc0284754b16663675867ac87
1 parent ed2f5a8 commit 92b43c5

27 files changed

+151
-65
lines changed

src/hotspot/share/code/codeBlob.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ RuntimeBlob::RuntimeBlob(
164164
void RuntimeBlob::free(RuntimeBlob* blob) {
165165
assert(blob != nullptr, "caller must check for nullptr");
166166
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
167-
blob->purge();
167+
blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
168168
{
169169
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
170170
CodeCache::free(blob);
@@ -173,7 +173,7 @@ void RuntimeBlob::free(RuntimeBlob* blob) {
173173
MemoryService::track_code_cache_memory_usage();
174174
}
175175

176-
void CodeBlob::purge(bool free_code_cache_data) {
176+
void CodeBlob::purge(bool free_code_cache_data, bool unregister_nmethod) {
177177
if (_oop_maps != nullptr) {
178178
delete _oop_maps;
179179
_oop_maps = nullptr;

src/hotspot/share/code/codeBlob.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ class CodeBlob {
143143
static unsigned int align_code_offset(int offset);
144144

145145
// Deletion
146-
virtual void purge(bool free_code_cache_data = true);
146+
virtual void purge(bool free_code_cache_data, bool unregister_nmethod);
147147

148148
// Typing
149149
virtual bool is_buffer_blob() const { return false; }

src/hotspot/share/code/compiledMethod.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ class CompiledMethod : public CodeBlob {
174174

175175
void* _gc_data;
176176

177-
virtual void purge(bool free_code_cache_data = true) = 0;
177+
virtual void purge(bool free_code_cache_data, bool unregister_nmethod) = 0;
178178

179179
private:
180180
DeoptimizationStatus deoptimization_status() const {

src/hotspot/share/code/nmethod.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,7 +1444,9 @@ void nmethod::unlink() {
14441444
ClassUnloadingContext::context()->register_unlinked_nmethod(this);
14451445
}
14461446

1447-
void nmethod::purge(bool free_code_cache_data) {
1447+
void nmethod::purge(bool free_code_cache_data, bool unregister_nmethod) {
1448+
assert(!free_code_cache_data, "must only call not freeing code cache data");
1449+
14481450
MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag);
14491451

14501452
// completely deallocate this method
@@ -1464,13 +1466,13 @@ void nmethod::purge(bool free_code_cache_data) {
14641466
ec = next;
14651467
}
14661468

1467-
Universe::heap()->unregister_nmethod(this);
1469+
if (unregister_nmethod) {
1470+
Universe::heap()->unregister_nmethod(this);
1471+
}
1472+
14681473
CodeCache::unregister_old_nmethod(this);
14691474

1470-
CodeBlob::purge();
1471-
if (free_code_cache_data) {
1472-
CodeCache::free(this);
1473-
}
1475+
CodeBlob::purge(free_code_cache_data, unregister_nmethod);
14741476
}
14751477

14761478
oop nmethod::oop_at(int index) const {

src/hotspot/share/code/nmethod.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ class nmethod : public CompiledMethod {
522522
void unlink();
523523

524524
// Deallocate this nmethod - called by the GC
525-
void purge(bool free_code_cache_data = true);
525+
void purge(bool free_code_cache_data, bool unregister_nmethod);
526526

527527
// See comment at definition of _last_seen_on_stack
528528
void mark_as_maybe_on_stack();

src/hotspot/share/compiler/compileBroker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1775,7 +1775,7 @@ bool CompileBroker::init_compiler_runtime() {
17751775
void CompileBroker::free_buffer_blob_if_allocated(CompilerThread* thread) {
17761776
BufferBlob* blob = thread->get_buffer_blob();
17771777
if (blob != nullptr) {
1778-
blob->purge();
1778+
blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
17791779
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
17801780
CodeCache::free(blob);
17811781
}

src/hotspot/share/gc/g1/g1CodeRootSet.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,15 @@ class G1CodeRootSetHashTable : public CHeapObj<mtGC> {
189189
}
190190
}
191191

192+
// Removes dead/unlinked entries.
193+
void bulk_remove() {
194+
auto delete_check = [&] (nmethod** value) {
195+
return (*value)->is_unlinked();
196+
};
197+
198+
clean(delete_check);
199+
}
200+
192201
// Calculate the log2 of the table size we want to shrink to.
193202
size_t log2_target_shrink_size(size_t current_size) const {
194203
// A table with the new size should be at most filled by this factor. Otherwise
@@ -257,6 +266,11 @@ bool G1CodeRootSet::remove(nmethod* method) {
257266
return _table->remove(method);
258267
}
259268

269+
void G1CodeRootSet::bulk_remove() {
270+
assert(!_is_iterating, "should not mutate while iterating the table");
271+
_table->bulk_remove();
272+
}
273+
260274
bool G1CodeRootSet::contains(nmethod* method) {
261275
return _table->contains(method);
262276
}

src/hotspot/share/gc/g1/g1CodeRootSet.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class G1CodeRootSet {
4444

4545
void add(nmethod* method);
4646
bool remove(nmethod* method);
47+
void bulk_remove();
4748
bool contains(nmethod* method);
4849
void clear();
4950

src/hotspot/share/gc/g1/g1CollectedHeap.cpp

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,7 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25972597
GCTraceTime(Debug, gc, phases) debug(description, timer);
25982598

25992599
ClassUnloadingContext ctx(workers()->active_workers(),
2600+
false /* unregister_nmethods_during_purge */,
26002601
false /* lock_codeblob_free_separately */);
26012602
{
26022603
CodeCache::UnlinkingScope scope(is_alive);
@@ -2608,6 +2609,10 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
26082609
GCTraceTime(Debug, gc, phases) t("Purge Unlinked NMethods", timer);
26092610
ctx.purge_nmethods();
26102611
}
2612+
{
2613+
GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", timer);
2614+
G1CollectedHeap::heap()->bulk_unregister_nmethods();
2615+
}
26112616
{
26122617
GCTraceTime(Debug, gc, phases) t("Free Code Blobs", timer);
26132618
ctx.free_code_blobs();
@@ -2619,6 +2624,33 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
26192624
}
26202625
}
26212626

2627+
class G1BulkUnregisterNMethodTask : public WorkerTask {
2628+
HeapRegionClaimer _hrclaimer;
2629+
2630+
class UnregisterNMethodsHeapRegionClosure : public HeapRegionClosure {
2631+
public:
2632+
2633+
bool do_heap_region(HeapRegion* hr) {
2634+
hr->rem_set()->bulk_remove_code_roots();
2635+
return false;
2636+
}
2637+
} _cl;
2638+
2639+
public:
2640+
G1BulkUnregisterNMethodTask(uint num_workers)
2641+
: WorkerTask("G1 Remove Unlinked NMethods From Code Root Set Task"),
2642+
_hrclaimer(num_workers) { }
2643+
2644+
void work(uint worker_id) {
2645+
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&_cl, &_hrclaimer, worker_id);
2646+
}
2647+
};
2648+
2649+
void G1CollectedHeap::bulk_unregister_nmethods() {
2650+
uint num_workers = workers()->active_workers();
2651+
G1BulkUnregisterNMethodTask t(num_workers);
2652+
workers()->run_task(&t);
2653+
}
26222654

26232655
bool G1STWSubjectToDiscoveryClosure::do_object_b(oop obj) {
26242656
assert(obj != nullptr, "must not be null");
@@ -3039,41 +3071,15 @@ class RegisterNMethodOopClosure: public OopClosure {
30393071
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
30403072
};
30413073

3042-
class UnregisterNMethodOopClosure: public OopClosure {
3043-
G1CollectedHeap* _g1h;
3044-
nmethod* _nm;
3045-
3046-
public:
3047-
UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
3048-
_g1h(g1h), _nm(nm) {}
3049-
3050-
void do_oop(oop* p) {
3051-
oop heap_oop = RawAccess<>::oop_load(p);
3052-
if (!CompressedOops::is_null(heap_oop)) {
3053-
oop obj = CompressedOops::decode_not_null(heap_oop);
3054-
HeapRegion* hr = _g1h->heap_region_containing(obj);
3055-
assert(!hr->is_continues_humongous(),
3056-
"trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT
3057-
" starting at " HR_FORMAT,
3058-
p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()));
3059-
3060-
hr->remove_code_root(_nm);
3061-
}
3062-
}
3063-
3064-
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
3065-
};
3066-
30673074
void G1CollectedHeap::register_nmethod(nmethod* nm) {
30683075
guarantee(nm != nullptr, "sanity");
30693076
RegisterNMethodOopClosure reg_cl(this, nm);
30703077
nm->oops_do(&reg_cl);
30713078
}
30723079

30733080
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
3074-
guarantee(nm != nullptr, "sanity");
3075-
UnregisterNMethodOopClosure reg_cl(this, nm);
3076-
nm->oops_do(&reg_cl, true);
3081+
// We always unregister nmethods in bulk during code unloading only.
3082+
ShouldNotReachHere();
30773083
}
30783084

30793085
void G1CollectedHeap::update_used_after_gc(bool evacuation_failed) {

src/hotspot/share/gc/g1/g1CollectedHeap.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,8 @@ class G1CollectedHeap : public CollectedHeap {
12671267

12681268
void unload_classes_and_code(const char* description, BoolObjectClosure* cl, GCTimer* timer);
12691269

1270+
void bulk_unregister_nmethods();
1271+
12701272
// Verification
12711273

12721274
// Perform any cleanup actions necessary before allowing a verification.

0 commit comments

Comments
 (0)