src/share/vm/gc_implementation/g1/heapRegion.cpp
Print this page
rev 4801 : imported patch code-movement
rev 4802 : imported patch optimize-nmethod-scanning
*** 30,39 ****
--- 30,40 ----
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "memory/genOopClosures.inline.hpp"
#include "memory/iterator.hpp"
#include "oops/oop.inline.hpp"
+ #include "utilities/growableArray.hpp"
int HeapRegion::LogOfHRGrainBytes = 0;
int HeapRegion::LogOfHRGrainWords = 0;
size_t HeapRegion::GrainBytes = 0;
size_t HeapRegion::GrainWords = 0;
*** 230,239 ****
--- 231,247 ----
}
zero_marked_bytes();
_offsets.resize(HeapRegion::GrainWords);
init_top_at_mark_start();
+
+ if (_strong_code_root_list != NULL) {
+ delete _strong_code_root_list;
+ }
+ _strong_code_root_list = new (ResourceObj::C_HEAP, mtGC)
+ GrowableArray<nmethod*>(10, 0, NULL, true);
+
if (clear_space) clear(SpaceDecorator::Mangle);
}
void HeapRegion::par_clear() {
assert(used() == 0, "the region should have been already cleared");
*** 358,368 ****
#ifdef ASSERT
_containing_set(NULL),
#endif // ASSERT
_young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1),
_rem_set(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0),
! _predicted_bytes_to_copy(0)
{
_orig_end = mr.end();
// Note that initialize() will set the start of the unmarked area of the
// region.
hr_clear(false /*par*/, false /*clear_space*/);
--- 366,376 ----
#ifdef ASSERT
_containing_set(NULL),
#endif // ASSERT
_young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1),
_rem_set(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0),
! _predicted_bytes_to_copy(0), _strong_code_root_list(NULL)
{
_orig_end = mr.end();
// Note that initialize() will set the start of the unmarked area of the
// region.
hr_clear(false /*par*/, false /*clear_space*/);
*** 588,597 ****
--- 596,841 ----
cur = next;
}
return NULL;
}
+ // Code roots support
+
+ void HeapRegion::add_strong_code_root(nmethod* nm) {
+ assert(nm != NULL, "sanity");
+ // Search for the code blob from the RHS to avoid
+ // duplicate entries as much as possible
+ if (_strong_code_root_list->find_from_end(nm) < 0) {
+ // Code blob isn't already in the list
+ _strong_code_root_list->push(nm);
+ }
+ }
+
+ void HeapRegion::remove_strong_code_root(nmethod* nm) {
+ assert(nm != NULL, "sanity");
+ int idx = _strong_code_root_list->find(nm);
+ while (idx >= 0) {
+ _strong_code_root_list->remove_at(idx);
+ idx = _strong_code_root_list->find(nm);
+ }
+ }
+
+ class NMethodMigrationOopClosure : public OopClosure {
+ G1CollectedHeap* _g1h;
+ HeapRegion* _from;
+ nmethod* _nm;
+
+ uint _num_self_forwarded;
+
+ 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);
+ if (_from->is_in(obj)) {
+ // Reference still points into the source region.
+ // Since roots are immediately evacuated this means that
+ // we must have self forwarded the object
+ assert(obj->is_forwarded(),
+ err_msg("code roots should be immediately evacuated. "
+ "Ref: "PTR_FORMAT", "
+ "Obj: "PTR_FORMAT", "
+ "Region: "HR_FORMAT,
+ p, (void*) obj, HR_FORMAT_PARAMS(_from)));
+ assert(obj->forwardee() == obj,
+ err_msg("not self forwarded? obj = "PTR_FORMAT, (void*)obj));
+
+ // The object has been self forwarded.
+ // Note, if we're during an initial mark pause, there is
+ // no need to explicitly mark object. It will be marked
+ // during the regular evacuation failure handling code.
+ _num_self_forwarded++;
+ } else {
+ // The reference points into a promotion or to-space region
+ HeapRegion* to = _g1h->heap_region_containing(obj);
+ to->add_strong_code_root(_nm);
+ }
+ }
+ }
+
+ public:
+ NMethodMigrationOopClosure(G1CollectedHeap* g1h, HeapRegion* from, nmethod* nm):
+ _g1h(g1h), _from(from), _nm(nm), _num_self_forwarded(0) {}
+
+ void do_oop(narrowOop* p) { do_oop_work(p); }
+ void do_oop(oop* p) { do_oop_work(p); }
+
+ uint retain() { return _num_self_forwarded > 0; }
+ };
+
+ void HeapRegion::migrate_strong_code_roots() {
+ assert(in_collection_set(), "only collection set regions");
+ assert(!isHumongous(), "not humongous regions");
+
+ ResourceMark rm;
+
+ // List of code blobs to retain for this region
+ GrowableArray<nmethod*> to_be_retained(10);
+ G1CollectedHeap* g1h = G1CollectedHeap::heap();
+
+ while (strong_code_root_list()->is_nonempty()) {
+ nmethod *nm = strong_code_root_list()->pop();
+ if (nm != NULL) {
+ NMethodMigrationOopClosure oop_cl(g1h, this, nm);
+ nm->oops_do(&oop_cl);
+ if (oop_cl.retain()) {
+ to_be_retained.push(nm);
+ }
+ }
+ }
+
+ // Now push any code roots we need to retain
+ // FIXME: assert that region got an evacuation failure if non-empty
+ while (to_be_retained.is_nonempty()) {
+ nmethod* nm = to_be_retained.pop();
+ assert(nm != NULL, "sanity");
+ add_strong_code_root(nm);
+ }
+ }
+
+ void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const {
+ for (int i = 0; i < _strong_code_root_list->length(); i += 1) {
+ nmethod* nm = _strong_code_root_list->at(i);
+ blk->do_code_blob(nm);
+ }
+ }
+
+ size_t HeapRegion::strong_code_root_mem_size() {
+ return sizeof(GrowableArray<nmethod*>) +
+ _strong_code_root_list->max_length() * sizeof(nmethod*);
+ }
+
+ class VerifyStrongCodeRootOopClosure: public OopClosure {
+ const HeapRegion* _hr;
+ nmethod* _nm;
+ bool _failures;
+ bool _has_oops_in_region;
+
+ 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);
+
+ // Note: not all the oops embedded in the nmethod are in the
+ // current region. We only look at those which are.
+ if (_hr->is_in(obj)) {
+ // Object is in the region. Check that its less than top
+ if (_hr->top() <= (HeapWord*)obj) {
+ // Object is above top
+ gclog_or_tty->print_cr("Object "PTR_FORMAT" in region "
+ "["PTR_FORMAT", "PTR_FORMAT") is above "
+ "top "PTR_FORMAT,
+ obj, _hr->bottom(), _hr->end(), _hr->top());
+ _failures = true;
+ return;
+ }
+ // Nmethod has at least one oop in the current region
+ _has_oops_in_region = true;
+ }
+ }
+ }
+
+ public:
+ VerifyStrongCodeRootOopClosure(const HeapRegion* hr, nmethod* nm):
+ _hr(hr), _failures(false), _has_oops_in_region(false) {}
+
+ void do_oop(narrowOop* p) { do_oop_work(p); }
+ void do_oop(oop* p) { do_oop_work(p); }
+
+ bool failures() { return _failures; }
+ bool has_oops_in_region() { return _has_oops_in_region; }
+ };
+
+ class VerifyStrongCodeRootCodeBlobClosure: public CodeBlobClosure {
+ const HeapRegion* _hr;
+ bool _failures;
+ public:
+ VerifyStrongCodeRootCodeBlobClosure(const HeapRegion* hr) :
+ _hr(hr), _failures(false) {}
+
+ void do_code_blob(CodeBlob* cb) {
+ nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null();
+ if (nm != NULL) {
+ // Verify that the nemthod is live
+ if (!nm->is_alive()) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has dead nmethod "
+ PTR_FORMAT" in its strong code roots",
+ _hr->bottom(), _hr->end(), nm);
+ _failures = true;
+ } else {
+ VerifyStrongCodeRootOopClosure oop_cl(_hr, nm);
+ nm->oops_do(&oop_cl);
+ if (!oop_cl.has_oops_in_region()) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has nmethod "
+ PTR_FORMAT" in its strong code roots "
+ "with no pointers into region",
+ _hr->bottom(), _hr->end(), nm);
+ _failures = true;
+ } else if (oop_cl.failures()) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has other "
+ "failures for nmethod "PTR_FORMAT,
+ _hr->bottom(), _hr->end(), nm);
+ _failures = true;
+ }
+ }
+ }
+ }
+
+ bool failures() { return _failures; }
+ };
+
+ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const {
+ if (!G1VerifyHeapRegionCodeRoots) {
+ // We're not verifying code roots.
+ return;
+ }
+ if (vo == VerifyOption_G1UseMarkWord) {
+ // Marking verification during a full GC is performed after class
+ // unloading, code cache unloading, etc so the strong code roots
+ // attached to each heap region are in an inconsistent state. They won't
+ // be consistent until the strong code roots are rebuilt after the
+ // actual GC. Skip verifying the strong code roots in this particular
+ // time.
+ assert(VerifyDuringGC, "only way to get here");
+ return;
+ }
+
+ // if this region is empty then there should be no entries
+ // on its strong code root list
+ if (is_empty()) {
+ if (!_strong_code_root_list->is_empty()) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty "
+ "but has "INT32_FORMAT" code root entries",
+ bottom(), end(), _strong_code_root_list->length());
+ *failures = true;
+ }
+ return;
+ }
+
+ // An H-region should have an empty strong code root list
+ if (isHumongous()) {
+ if (!_strong_code_root_list->is_empty()) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is humongous "
+ "but has "INT32_FORMAT" code root entries",
+ bottom(), end(), _strong_code_root_list->length());
+ *failures = true;
+ }
+ return;
+ }
+
+ VerifyStrongCodeRootCodeBlobClosure cb_cl(this);
+ strong_code_roots_do(&cb_cl);
+
+ if (cb_cl.failures()) {
+ *failures = true;
+ }
+ }
+
void HeapRegion::print() const { print_on(gclog_or_tty); }
void HeapRegion::print_on(outputStream* st) const {
if (isHumongous()) {
if (startsHumongous())
st->print(" HS");
*** 892,901 ****
--- 1136,1147 ----
"but has "SIZE_FORMAT", objects",
bottom(), end(), object_num);
*failures = true;
return;
}
+
+ verify_strong_code_roots(vo, failures);
}
void HeapRegion::verify() const {
bool dummy = false;
verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy);