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);