7145569: G1: optimize nmethods scanning

Add a list of nmethods to the RSet for a region that contain references into the region. Skip scanning the code cache during root scanning and scan the nmethod lists during RSet scanning instead.

Reviewed-by: tschatzl, brutisso, mgerdin, twisti, kvn
This commit is contained in:
John Cuthbertson 2013-08-15 10:52:18 +02:00
parent c144b8c30f
commit f63547bf71
22 changed files with 1256 additions and 476 deletions

View file

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "gc_implementation/g1/bufferingOopClosure.hpp"
#include "gc_implementation/g1/concurrentG1Refine.hpp"
@ -1176,20 +1177,27 @@ class PostMCRemSetClearClosure: public HeapRegionClosure {
ModRefBarrierSet* _mr_bs;
public:
PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) :
_g1h(g1h), _mr_bs(mr_bs) { }
_g1h(g1h), _mr_bs(mr_bs) {}
bool doHeapRegion(HeapRegion* r) {
HeapRegionRemSet* hrrs = r->rem_set();
if (r->continuesHumongous()) {
// We'll assert that the strong code root list and RSet is empty
assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
assert(hrrs->occupied() == 0, "RSet should be empty");
return false;
}
_g1h->reset_gc_time_stamps(r);
HeapRegionRemSet* hrrs = r->rem_set();
if (hrrs != NULL) hrrs->clear();
hrrs->clear();
// You might think here that we could clear just the cards
// corresponding to the used region. But no: if we leave a dirty card
// in a region we might allocate into, then it would prevent that card
// from being enqueued, and cause it to be missed.
// Re: the performance cost: we shouldn't be doing full GC anyway!
_mr_bs->clear(MemRegion(r->bottom(), r->end()));
return false;
}
};
@ -1269,30 +1277,6 @@ void G1CollectedHeap::print_hrs_post_compaction() {
heap_region_iterate(&cl);
}
double G1CollectedHeap::verify(bool guard, const char* msg) {
double verify_time_ms = 0.0;
if (guard && total_collections() >= VerifyGCStartAt) {
double verify_start = os::elapsedTime();
HandleMark hm; // Discard invalid handles created during verification
prepare_for_verify();
Universe::verify(VerifyOption_G1UsePrevMarking, msg);
verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
}
return verify_time_ms;
}
void G1CollectedHeap::verify_before_gc() {
double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:");
g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
}
void G1CollectedHeap::verify_after_gc() {
double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:");
g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
}
bool G1CollectedHeap::do_collection(bool explicit_gc,
bool clear_all_soft_refs,
size_t word_size) {
@ -1433,7 +1417,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
ClassLoaderDataGraph::purge();
MetaspaceAux::verify_metrics();
MetaspaceAux::verify_metrics();
// Note: since we've just done a full GC, concurrent
// marking is no longer active. Therefore we need not
@ -1504,6 +1488,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
heap_region_iterate(&rebuild_rs);
}
// Rebuild the strong code root lists for each region
rebuild_strong_code_roots();
if (true) { // FIXME
MetaspaceGC::compute_new_size();
}
@ -3109,6 +3096,145 @@ const char* G1CollectedHeap::top_at_mark_start_str(VerifyOption vo) {
return NULL; // keep some compilers happy
}
// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can
// pass it as the perm_blk to SharedHeap::process_strong_roots.
// When process_strong_roots stop calling perm_blk->younger_refs_iterate
// we can change this closure to extend the simpler OopClosure.
class VerifyRootsClosure: public OopsInGenClosure {
private:
G1CollectedHeap* _g1h;
VerifyOption _vo;
bool _failures;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
// _vo == UseMarkWord -> use mark word from object header.
VerifyRootsClosure(VerifyOption vo) :
_g1h(G1CollectedHeap::heap()),
_vo(vo),
_failures(false) { }
bool failures() { return _failures; }
template <class T> void do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _vo)) {
gclog_or_tty->print_cr("Root location "PTR_FORMAT" "
"points to dead obj "PTR_FORMAT, p, (void*) obj);
if (_vo == VerifyOption_G1UseMarkWord) {
gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark()));
}
obj->print_on(gclog_or_tty);
_failures = true;
}
}
}
void do_oop(oop* p) { do_oop_nv(p); }
void do_oop(narrowOop* p) { do_oop_nv(p); }
};
class G1VerifyCodeRootOopClosure: public OopsInGenClosure {
G1CollectedHeap* _g1h;
OopClosure* _root_cl;
nmethod* _nm;
VerifyOption _vo;
bool _failures;
template <class T> void do_oop_work(T* p) {
// First verify that this root is live
_root_cl->do_oop(p);
if (!G1VerifyHeapRegionCodeRoots) {
// We're not verifying the code roots attached to heap region.
return;
}
// Don't check the code roots during marking verification in a full GC
if (_vo == VerifyOption_G1UseMarkWord) {
return;
}
// Now verify that the current nmethod (which contains p) is
// in the code root list of the heap region containing the
// object referenced by p.
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
// Now fetch the region containing the object
HeapRegion* hr = _g1h->heap_region_containing(obj);
HeapRegionRemSet* hrrs = hr->rem_set();
// Verify that the strong code root list for this region
// contains the nmethod
if (!hrrs->strong_code_roots_list_contains(_nm)) {
gclog_or_tty->print_cr("Code root location "PTR_FORMAT" "
"from nmethod "PTR_FORMAT" not in strong "
"code roots for region ["PTR_FORMAT","PTR_FORMAT")",
p, _nm, hr->bottom(), hr->end());
_failures = true;
}
}
}
public:
G1VerifyCodeRootOopClosure(G1CollectedHeap* g1h, OopClosure* root_cl, VerifyOption vo):
_g1h(g1h), _root_cl(root_cl), _vo(vo), _nm(NULL), _failures(false) {}
void do_oop(oop* p) { do_oop_work(p); }
void do_oop(narrowOop* p) { do_oop_work(p); }
void set_nmethod(nmethod* nm) { _nm = nm; }
bool failures() { return _failures; }
};
class G1VerifyCodeRootBlobClosure: public CodeBlobClosure {
G1VerifyCodeRootOopClosure* _oop_cl;
public:
G1VerifyCodeRootBlobClosure(G1VerifyCodeRootOopClosure* oop_cl):
_oop_cl(oop_cl) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = cb->as_nmethod_or_null();
if (nm != NULL) {
_oop_cl->set_nmethod(nm);
nm->oops_do(_oop_cl);
}
}
};
class YoungRefCounterClosure : public OopClosure {
G1CollectedHeap* _g1h;
int _count;
public:
YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {}
void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
int count() { return _count; }
void reset_count() { _count = 0; };
};
class VerifyKlassClosure: public KlassClosure {
YoungRefCounterClosure _young_ref_counter_closure;
OopClosure *_oop_closure;
public:
VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
void do_klass(Klass* k) {
k->oops_do(_oop_closure);
_young_ref_counter_closure.reset_count();
k->oops_do(&_young_ref_counter_closure);
if (_young_ref_counter_closure.count() > 0) {
guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k));
}
}
};
class VerifyLivenessOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
VerifyOption _vo;
@ -3242,75 +3368,7 @@ public:
}
};
class YoungRefCounterClosure : public OopClosure {
G1CollectedHeap* _g1h;
int _count;
public:
YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {}
void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
int count() { return _count; }
void reset_count() { _count = 0; };
};
class VerifyKlassClosure: public KlassClosure {
YoungRefCounterClosure _young_ref_counter_closure;
OopClosure *_oop_closure;
public:
VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
void do_klass(Klass* k) {
k->oops_do(_oop_closure);
_young_ref_counter_closure.reset_count();
k->oops_do(&_young_ref_counter_closure);
if (_young_ref_counter_closure.count() > 0) {
guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k));
}
}
};
// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can
// pass it as the perm_blk to SharedHeap::process_strong_roots.
// When process_strong_roots stop calling perm_blk->younger_refs_iterate
// we can change this closure to extend the simpler OopClosure.
class VerifyRootsClosure: public OopsInGenClosure {
private:
G1CollectedHeap* _g1h;
VerifyOption _vo;
bool _failures;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
// _vo == UseMarkWord -> use mark word from object header.
VerifyRootsClosure(VerifyOption vo) :
_g1h(G1CollectedHeap::heap()),
_vo(vo),
_failures(false) { }
bool failures() { return _failures; }
template <class T> void do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1h->is_obj_dead_cond(obj, _vo)) {
gclog_or_tty->print_cr("Root location "PTR_FORMAT" "
"points to dead obj "PTR_FORMAT, p, (void*) obj);
if (_vo == VerifyOption_G1UseMarkWord) {
gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark()));
}
obj->print_on(gclog_or_tty);
_failures = true;
}
}
}
void do_oop(oop* p) { do_oop_nv(p); }
void do_oop(narrowOop* p) { do_oop_nv(p); }
};
// This is the task used for parallel heap verification.
// This is the task used for parallel verification of the heap regions
class G1ParVerifyTask: public AbstractGangTask {
private:
@ -3344,20 +3402,15 @@ public:
}
};
void G1CollectedHeap::verify(bool silent) {
verify(silent, VerifyOption_G1UsePrevMarking);
}
void G1CollectedHeap::verify(bool silent,
VerifyOption vo) {
void G1CollectedHeap::verify(bool silent, VerifyOption vo) {
if (SafepointSynchronize::is_at_safepoint()) {
if (!silent) { gclog_or_tty->print("Roots "); }
VerifyRootsClosure rootsCl(vo);
assert(Thread::current()->is_VM_thread(),
"Expected to be executed serially by the VM thread at this point");
CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false);
if (!silent) { gclog_or_tty->print("Roots "); }
VerifyRootsClosure rootsCl(vo);
G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo);
G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl);
VerifyKlassClosure klassCl(this, &rootsCl);
// We apply the relevant closures to all the oops in the
@ -3376,7 +3429,7 @@ void G1CollectedHeap::verify(bool silent,
&klassCl
);
bool failures = rootsCl.failures();
bool failures = rootsCl.failures() || codeRootsCl.failures();
if (vo != VerifyOption_G1UseMarkWord) {
// If we're verifying during a full GC then the region sets
@ -3445,6 +3498,34 @@ void G1CollectedHeap::verify(bool silent,
}
}
void G1CollectedHeap::verify(bool silent) {
verify(silent, VerifyOption_G1UsePrevMarking);
}
double G1CollectedHeap::verify(bool guard, const char* msg) {
double verify_time_ms = 0.0;
if (guard && total_collections() >= VerifyGCStartAt) {
double verify_start = os::elapsedTime();
HandleMark hm; // Discard invalid handles created during verification
prepare_for_verify();
Universe::verify(VerifyOption_G1UsePrevMarking, msg);
verify_time_ms = (os::elapsedTime() - verify_start) * 1000;
}
return verify_time_ms;
}
void G1CollectedHeap::verify_before_gc() {
double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:");
g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms);
}
void G1CollectedHeap::verify_after_gc() {
double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:");
g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms);
}
class PrintRegionClosure: public HeapRegionClosure {
outputStream* _st;
public:
@ -3866,8 +3947,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
append_secondary_free_list_if_not_empty_with_lock();
}
assert(check_young_list_well_formed(),
"young list should be well formed");
assert(check_young_list_well_formed(), "young list should be well formed");
assert(check_heap_region_claim_values(HeapRegion::InitialClaimValue),
"sanity check");
// Don't dynamically change the number of GC threads this early. A value of
// 0 is used to indicate serial work. When parallel work is done,
@ -4987,7 +5069,11 @@ public:
G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss);
int so = SharedHeap::SO_AllClasses | SharedHeap::SO_Strings | SharedHeap::SO_CodeCache;
// Don't scan the scavengable methods in the code cache as part
// of strong root scanning. The code roots that point into a
// region in the collection set are scanned when we scan the
// region's RSet.
int so = SharedHeap::SO_AllClasses | SharedHeap::SO_Strings;
pss.start_strong_roots();
_g1h->g1_process_strong_roots(/* is scavenging */ true,
@ -5029,67 +5115,6 @@ public:
// *** Common G1 Evacuation Stuff
// Closures that support the filtering of CodeBlobs scanned during
// external root scanning.
// Closure applied to reference fields in code blobs (specifically nmethods)
// to determine whether an nmethod contains references that point into
// the collection set. Used as a predicate when walking code roots so
// that only nmethods that point into the collection set are added to the
// 'marked' list.
class G1FilteredCodeBlobToOopClosure : public CodeBlobToOopClosure {
class G1PointsIntoCSOopClosure : public OopClosure {
G1CollectedHeap* _g1;
bool _points_into_cs;
public:
G1PointsIntoCSOopClosure(G1CollectedHeap* g1) :
_g1(g1), _points_into_cs(false) { }
bool points_into_cs() const { return _points_into_cs; }
template <class T>
void do_oop_nv(T* p) {
if (!_points_into_cs) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop) &&
_g1->in_cset_fast_test(oopDesc::decode_heap_oop_not_null(heap_oop))) {
_points_into_cs = true;
}
}
}
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
G1CollectedHeap* _g1;
public:
G1FilteredCodeBlobToOopClosure(G1CollectedHeap* g1, OopClosure* cl) :
CodeBlobToOopClosure(cl, true), _g1(g1) { }
virtual void do_code_blob(CodeBlob* cb) {
nmethod* nm = cb->as_nmethod_or_null();
if (nm != NULL && !(nm->test_oops_do_mark())) {
G1PointsIntoCSOopClosure predicate_cl(_g1);
nm->oops_do(&predicate_cl);
if (predicate_cl.points_into_cs()) {
// At least one of the reference fields or the oop relocations
// in the nmethod points into the collection set. We have to
// 'mark' this nmethod.
// Note: Revisit the following if CodeBlobToOopClosure::do_code_blob()
// or MarkingCodeBlobClosure::do_code_blob() change.
if (!nm->test_set_oops_do_mark()) {
do_newly_marked_nmethod(nm);
}
}
}
}
};
// This method is run in a GC worker.
void
@ -5107,9 +5132,10 @@ g1_process_strong_roots(bool is_scavenging,
BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots);
// Walk the code cache w/o buffering, because StarTask cannot handle
// unaligned oop locations.
G1FilteredCodeBlobToOopClosure eager_scan_code_roots(this, scan_non_heap_roots);
assert(so & SO_CodeCache || scan_rs != NULL, "must scan code roots somehow");
// Walk the code cache/strong code roots w/o buffering, because StarTask
// cannot handle unaligned oop locations.
CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, true /* do_marking */);
process_strong_roots(false, // no scoping; this is parallel code
is_scavenging, so,
@ -5154,9 +5180,22 @@ g1_process_strong_roots(bool is_scavenging,
}
g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms);
// If this is an initial mark pause, and we're not scanning
// the entire code cache, we need to mark the oops in the
// strong code root lists for the regions that are not in
// the collection set.
// Note all threads participate in this set of root tasks.
double mark_strong_code_roots_ms = 0.0;
if (g1_policy()->during_initial_mark_pause() && !(so & SO_CodeCache)) {
double mark_strong_roots_start = os::elapsedTime();
mark_strong_code_roots(worker_i);
mark_strong_code_roots_ms = (os::elapsedTime() - mark_strong_roots_start) * 1000.0;
}
g1_policy()->phase_times()->record_strong_code_root_mark_time(worker_i, mark_strong_code_roots_ms);
// Now scan the complement of the collection set.
if (scan_rs != NULL) {
g1_rem_set()->oops_into_collection_set_do(scan_rs, worker_i);
g1_rem_set()->oops_into_collection_set_do(scan_rs, &eager_scan_code_roots, worker_i);
}
_process_strong_tasks->all_tasks_completed();
}
@ -5774,9 +5813,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
process_discovered_references(n_workers);
// Weak root processing.
// Note: when JSR 292 is enabled and code blobs can contain
// non-perm oops then we will need to process the code blobs
// here too.
{
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
@ -5792,6 +5828,17 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
hot_card_cache->reset_hot_cache();
hot_card_cache->set_use_cache(true);
// Migrate the strong code roots attached to each region in
// the collection set. Ideally we would like to do this
// after we have finished the scanning/evacuation of the
// strong code roots for a particular heap region.
migrate_strong_code_roots();
if (g1_policy()->during_initial_mark_pause()) {
// Reset the claim values set during marking the strong code roots
reset_heap_region_claim_values();
}
finalize_for_evac_failure();
if (evacuation_failed()) {
@ -6588,3 +6635,204 @@ void G1CollectedHeap::verify_region_sets() {
_humongous_set.verify_end();
_free_list.verify_end();
}
// Optimized nmethod scanning
class RegisterNMethodOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
nmethod* _nm;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
HeapRegion* hr = _g1h->heap_region_containing(obj);
assert(!hr->isHumongous(), "code root in humongous region?");
// HeapRegion::add_strong_code_root() avoids adding duplicate
// entries but having duplicates is OK since we "mark" nmethods
// as visited when we scan the strong code root lists during the GC.
hr->add_strong_code_root(_nm);
assert(hr->rem_set()->strong_code_roots_list_contains(_nm), "add failed?");
}
}
public:
RegisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
_g1h(g1h), _nm(nm) {}
void do_oop(oop* p) { do_oop_work(p); }
void do_oop(narrowOop* p) { do_oop_work(p); }
};
class UnregisterNMethodOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
nmethod* _nm;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
HeapRegion* hr = _g1h->heap_region_containing(obj);
assert(!hr->isHumongous(), "code root in humongous region?");
hr->remove_strong_code_root(_nm);
assert(!hr->rem_set()->strong_code_roots_list_contains(_nm), "remove failed?");
}
}
public:
UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) :
_g1h(g1h), _nm(nm) {}
void do_oop(oop* p) { do_oop_work(p); }
void do_oop(narrowOop* p) { do_oop_work(p); }
};
void G1CollectedHeap::register_nmethod(nmethod* nm) {
CollectedHeap::register_nmethod(nm);
guarantee(nm != NULL, "sanity");
RegisterNMethodOopClosure reg_cl(this, nm);
nm->oops_do(&reg_cl);
}
void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
CollectedHeap::unregister_nmethod(nm);
guarantee(nm != NULL, "sanity");
UnregisterNMethodOopClosure reg_cl(this, nm);
nm->oops_do(&reg_cl, true);
}
class MigrateCodeRootsHeapRegionClosure: public HeapRegionClosure {
public:
bool doHeapRegion(HeapRegion *hr) {
assert(!hr->isHumongous(), "humongous region in collection set?");
hr->migrate_strong_code_roots();
return false;
}
};
void G1CollectedHeap::migrate_strong_code_roots() {
MigrateCodeRootsHeapRegionClosure cl;
double migrate_start = os::elapsedTime();
collection_set_iterate(&cl);
double migration_time_ms = (os::elapsedTime() - migrate_start) * 1000.0;
g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms);
}
// Mark all the code roots that point into regions *not* in the
// collection set.
//
// Note we do not want to use a "marking" CodeBlobToOopClosure while
// walking the the code roots lists of regions not in the collection
// set. Suppose we have an nmethod (M) that points to objects in two
// separate regions - one in the collection set (R1) and one not (R2).
// Using a "marking" CodeBlobToOopClosure here would result in "marking"
// nmethod M when walking the code roots for R1. When we come to scan
// the code roots for R2, we would see that M is already marked and it
// would be skipped and the objects in R2 that are referenced from M
// would not be evacuated.
class MarkStrongCodeRootCodeBlobClosure: public CodeBlobClosure {
class MarkStrongCodeRootOopClosure: public OopClosure {
ConcurrentMark* _cm;
HeapRegion* _hr;
uint _worker_id;
template <class T> void do_oop_work(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
// Only mark objects in the region (which is assumed
// to be not in the collection set).
if (_hr->is_in(obj)) {
_cm->grayRoot(obj, (size_t) obj->size(), _worker_id);
}
}
}
public:
MarkStrongCodeRootOopClosure(ConcurrentMark* cm, HeapRegion* hr, uint worker_id) :
_cm(cm), _hr(hr), _worker_id(worker_id) {
assert(!_hr->in_collection_set(), "sanity");
}
void do_oop(narrowOop* p) { do_oop_work(p); }
void do_oop(oop* p) { do_oop_work(p); }
};
MarkStrongCodeRootOopClosure _oop_cl;
public:
MarkStrongCodeRootCodeBlobClosure(ConcurrentMark* cm, HeapRegion* hr, uint worker_id):
_oop_cl(cm, hr, worker_id) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null();
if (nm != NULL) {
nm->oops_do(&_oop_cl);
}
}
};
class MarkStrongCodeRootsHRClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
uint _worker_id;
public:
MarkStrongCodeRootsHRClosure(G1CollectedHeap* g1h, uint worker_id) :
_g1h(g1h), _worker_id(worker_id) {}
bool doHeapRegion(HeapRegion *hr) {
HeapRegionRemSet* hrrs = hr->rem_set();
if (hr->isHumongous()) {
// Code roots should never be attached to a humongous region
assert(hrrs->strong_code_roots_list_length() == 0, "sanity");
return false;
}
if (hr->in_collection_set()) {
// Don't mark code roots into regions in the collection set here.
// They will be marked when we scan them.
return false;
}
MarkStrongCodeRootCodeBlobClosure cb_cl(_g1h->concurrent_mark(), hr, _worker_id);
hr->strong_code_roots_do(&cb_cl);
return false;
}
};
void G1CollectedHeap::mark_strong_code_roots(uint worker_id) {
MarkStrongCodeRootsHRClosure cl(this, worker_id);
heap_region_par_iterate_chunked(&cl,
worker_id,
workers()->active_workers(),
HeapRegion::ParMarkRootClaimValue);
}
class RebuildStrongCodeRootClosure: public CodeBlobClosure {
G1CollectedHeap* _g1h;
public:
RebuildStrongCodeRootClosure(G1CollectedHeap* g1h) :
_g1h(g1h) {}
void do_code_blob(CodeBlob* cb) {
nmethod* nm = (cb != NULL) ? cb->as_nmethod_or_null() : NULL;
if (nm == NULL) {
return;
}
if (ScavengeRootsInCode && nm->detect_scavenge_root_oops()) {
_g1h->register_nmethod(nm);
}
}
};
void G1CollectedHeap::rebuild_strong_code_roots() {
RebuildStrongCodeRootClosure blob_cl(this);
CodeCache::blobs_do(&blob_cl);
}