Skip to content

Commit f553819

Browse files
author
Thomas Schatzl
committed
8317007: Add bulk removal of dead nmethods during class unloading
Reviewed-by: ayang, iwalulya
1 parent 34351b7 commit f553819

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
@@ -1788,7 +1788,7 @@ bool CompileBroker::init_compiler_runtime() {
17881788
void CompileBroker::free_buffer_blob_if_allocated(CompilerThread* thread) {
17891789
BufferBlob* blob = thread->get_buffer_blob();
17901790
if (blob != nullptr) {
1791-
blob->purge();
1791+
blob->purge(true /* free_code_cache_data */, true /* unregister_nmethod */);
17921792
MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
17931793
CodeCache::free(blob);
17941794
}

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

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

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

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

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
@@ -2517,6 +2517,7 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25172517
GCTraceTime(Debug, gc, phases) debug(description, timer);
25182518

25192519
ClassUnloadingContext ctx(workers()->active_workers(),
2520+
false /* unregister_nmethods_during_purge */,
25202521
false /* lock_codeblob_free_separately */);
25212522
{
25222523
CodeCache::UnlinkingScope scope(is_alive);
@@ -2528,6 +2529,10 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25282529
GCTraceTime(Debug, gc, phases) t("Purge Unlinked NMethods", timer);
25292530
ctx.purge_nmethods();
25302531
}
2532+
{
2533+
GCTraceTime(Debug, gc, phases) ur("Unregister NMethods", timer);
2534+
G1CollectedHeap::heap()->bulk_unregister_nmethods();
2535+
}
25312536
{
25322537
GCTraceTime(Debug, gc, phases) t("Free Code Blobs", timer);
25332538
ctx.free_code_blobs();
@@ -2539,6 +2544,33 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec
25392544
}
25402545
}
25412546

2547+
class G1BulkUnregisterNMethodTask : public WorkerTask {
2548+
HeapRegionClaimer _hrclaimer;
2549+
2550+
class UnregisterNMethodsHeapRegionClosure : public HeapRegionClosure {
2551+
public:
2552+
2553+
bool do_heap_region(HeapRegion* hr) {
2554+
hr->rem_set()->bulk_remove_code_roots();
2555+
return false;
2556+
}
2557+
} _cl;
2558+
2559+
public:
2560+
G1BulkUnregisterNMethodTask(uint num_workers)
2561+
: WorkerTask("G1 Remove Unlinked NMethods From Code Root Set Task"),
2562+
_hrclaimer(num_workers) { }
2563+
2564+
void work(uint worker_id) {
2565+
G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&_cl, &_hrclaimer, worker_id);
2566+
}
2567+
};
2568+
2569+
void G1CollectedHeap::bulk_unregister_nmethods() {
2570+
uint num_workers = workers()->active_workers();
2571+
G1BulkUnregisterNMethodTask t(num_workers);
2572+
workers()->run_task(&t);
2573+
}
25422574

25432575
bool G1STWSubjectToDiscoveryClosure::do_object_b(oop obj) {
25442576
assert(obj != nullptr, "must not be null");
@@ -2963,41 +2995,15 @@ class RegisterNMethodOopClosure: public OopClosure {
29632995
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
29642996
};
29652997

2966-
class UnregisterNMethodOopClosure: public OopClosure {
2967-
G1CollectedHeap* _g1h;
2968-
nmethod* _nm;
2969-
2970-
public:
2971-
UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
2972-
_g1h(g1h), _nm(nm) {}
2973-
2974-
void do_oop(oop* p) {
2975-
oop heap_oop = RawAccess<>::oop_load(p);
2976-
if (!CompressedOops::is_null(heap_oop)) {
2977-
oop obj = CompressedOops::decode_not_null(heap_oop);
2978-
HeapRegion* hr = _g1h->heap_region_containing(obj);
2979-
assert(!hr->is_continues_humongous(),
2980-
"trying to remove code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT
2981-
" starting at " HR_FORMAT,
2982-
p2i(_nm), HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region()));
2983-
2984-
hr->remove_code_root(_nm);
2985-
}
2986-
}
2987-
2988-
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
2989-
};
2990-
29912998
void G1CollectedHeap::register_nmethod(nmethod* nm) {
29922999
guarantee(nm != nullptr, "sanity");
29933000
RegisterNMethodOopClosure reg_cl(this, nm);
29943001
nm->oops_do(&reg_cl);
29953002
}
29963003

29973004
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
2998-
guarantee(nm != nullptr, "sanity");
2999-
UnregisterNMethodOopClosure reg_cl(this, nm);
3000-
nm->oops_do(&reg_cl, true);
3005+
// We always unregister nmethods in bulk during code unloading only.
3006+
ShouldNotReachHere();
30013007
}
30023008

30033009
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
@@ -1270,6 +1270,8 @@ class G1CollectedHeap : public CollectedHeap {
12701270

12711271
void unload_classes_and_code(const char* description, BoolObjectClosure* cl, GCTimer* timer);
12721272

1273+
void bulk_unregister_nmethods();
1274+
12731275
// Verification
12741276

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

0 commit comments

Comments
 (0)