src/share/vm/gc_implementation/g1/heapRegion.cpp
Print this page
rev 4801 : imported patch code-movement
rev 4802 : imported patch optimize-nmethod-scanning
rev 4803 : imported patch thomas-comments-2
*** 21,30 ****
--- 21,31 ----
* questions.
*
*/
#include "precompiled.hpp"
+ #include "code/nmethod.hpp"
#include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp"
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1OopClosures.inline.hpp"
#include "gc_implementation/g1/heapRegion.inline.hpp"
#include "gc_implementation/g1/heapRegionRemSet.hpp"
*** 48,195 ****
FilterOutOfRegionClosure::FilterOutOfRegionClosure(HeapRegion* r,
OopClosure* oc) :
_r_bottom(r->bottom()), _r_end(r->end()), _oc(oc) { }
- class VerifyLiveClosure: public OopClosure {
- private:
- G1CollectedHeap* _g1h;
- CardTableModRefBS* _bs;
- oop _containing_obj;
- bool _failures;
- int _n_failures;
- VerifyOption _vo;
- public:
- // _vo == UsePrevMarking -> use "prev" marking information,
- // _vo == UseNextMarking -> use "next" marking information,
- // _vo == UseMarkWord -> use mark word from object header.
- VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) :
- _g1h(g1h), _bs(NULL), _containing_obj(NULL),
- _failures(false), _n_failures(0), _vo(vo)
- {
- BarrierSet* bs = _g1h->barrier_set();
- if (bs->is_a(BarrierSet::CardTableModRef))
- _bs = (CardTableModRefBS*)bs;
- }
-
- void set_containing_obj(oop obj) {
- _containing_obj = obj;
- }
-
- bool failures() { return _failures; }
- int n_failures() { return _n_failures; }
-
- virtual void do_oop(narrowOop* p) { do_oop_work(p); }
- virtual void do_oop( oop* p) { do_oop_work(p); }
-
- void print_object(outputStream* out, oop obj) {
- #ifdef PRODUCT
- Klass* k = obj->klass();
- const char* class_name = InstanceKlass::cast(k)->external_name();
- out->print_cr("class name %s", class_name);
- #else // PRODUCT
- obj->print_on(out);
- #endif // PRODUCT
- }
-
- template <class T>
- void do_oop_work(T* p) {
- assert(_containing_obj != NULL, "Precondition");
- assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo),
- "Precondition");
- T heap_oop = oopDesc::load_heap_oop(p);
- if (!oopDesc::is_null(heap_oop)) {
- oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
- bool failed = false;
- if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) {
- MutexLockerEx x(ParGCRareEvent_lock,
- Mutex::_no_safepoint_check_flag);
-
- if (!_failures) {
- gclog_or_tty->print_cr("");
- gclog_or_tty->print_cr("----------");
- }
- if (!_g1h->is_in_closed_subset(obj)) {
- HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
- gclog_or_tty->print_cr("Field "PTR_FORMAT
- " of live obj "PTR_FORMAT" in region "
- "["PTR_FORMAT", "PTR_FORMAT")",
- p, (void*) _containing_obj,
- from->bottom(), from->end());
- print_object(gclog_or_tty, _containing_obj);
- gclog_or_tty->print_cr("points to obj "PTR_FORMAT" not in the heap",
- (void*) obj);
- } else {
- HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
- HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
- gclog_or_tty->print_cr("Field "PTR_FORMAT
- " of live obj "PTR_FORMAT" in region "
- "["PTR_FORMAT", "PTR_FORMAT")",
- p, (void*) _containing_obj,
- from->bottom(), from->end());
- print_object(gclog_or_tty, _containing_obj);
- gclog_or_tty->print_cr("points to dead obj "PTR_FORMAT" in region "
- "["PTR_FORMAT", "PTR_FORMAT")",
- (void*) obj, to->bottom(), to->end());
- print_object(gclog_or_tty, obj);
- }
- gclog_or_tty->print_cr("----------");
- gclog_or_tty->flush();
- _failures = true;
- failed = true;
- _n_failures++;
- }
-
- if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) {
- HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
- HeapRegion* to = _g1h->heap_region_containing(obj);
- if (from != NULL && to != NULL &&
- from != to &&
- !to->isHumongous()) {
- jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
- jbyte cv_field = *_bs->byte_for_const(p);
- const jbyte dirty = CardTableModRefBS::dirty_card_val();
-
- bool is_bad = !(from->is_young()
- || to->rem_set()->contains_reference(p)
- || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed
- (_containing_obj->is_objArray() ?
- cv_field == dirty
- : cv_obj == dirty || cv_field == dirty));
- if (is_bad) {
- MutexLockerEx x(ParGCRareEvent_lock,
- Mutex::_no_safepoint_check_flag);
-
- if (!_failures) {
- gclog_or_tty->print_cr("");
- gclog_or_tty->print_cr("----------");
- }
- gclog_or_tty->print_cr("Missing rem set entry:");
- gclog_or_tty->print_cr("Field "PTR_FORMAT" "
- "of obj "PTR_FORMAT", "
- "in region "HR_FORMAT,
- p, (void*) _containing_obj,
- HR_FORMAT_PARAMS(from));
- _containing_obj->print_on(gclog_or_tty);
- gclog_or_tty->print_cr("points to obj "PTR_FORMAT" "
- "in region "HR_FORMAT,
- (void*) obj,
- HR_FORMAT_PARAMS(to));
- obj->print_on(gclog_or_tty);
- gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.",
- cv_obj, cv_field);
- gclog_or_tty->print_cr("----------");
- gclog_or_tty->flush();
- _failures = true;
- if (!failed) _n_failures++;
- }
- }
- }
- }
- }
- };
-
template<class ClosureType>
HeapWord* walk_mem_region_loop(ClosureType* cl, G1CollectedHeap* g1h,
HeapRegion* hr,
HeapWord* cur, HeapWord* top) {
oop cur_oop = oop(cur);
--- 49,58 ----
*** 361,371 ****
reset_pre_dummy_top();
if (!par) {
// If this is parallel, this will be done later.
HeapRegionRemSet* hrrs = rem_set();
! if (hrrs != NULL) hrrs->clear();
_claimed = InitialClaimValue;
}
zero_marked_bytes();
_offsets.resize(HeapRegion::GrainWords);
--- 224,234 ----
reset_pre_dummy_top();
if (!par) {
// If this is parallel, this will be done later.
HeapRegionRemSet* hrrs = rem_set();
! hrrs->clear();
_claimed = InitialClaimValue;
}
zero_marked_bytes();
_offsets.resize(HeapRegion::GrainWords);
*** 498,516 ****
#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*/);
set_top(bottom());
set_saved_mark();
- _rem_set = new HeapRegionRemSet(sharedOffsetArray, this);
-
assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant.");
}
CompactibleSpace* HeapRegion::next_compaction_space() const {
// We're not using an iterator given that it will wrap around when
--- 361,378 ----
#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)
{
+ _rem_set = new HeapRegionRemSet(sharedOffsetArray, this);
_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*/);
set_top(bottom());
set_saved_mark();
assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant.");
}
CompactibleSpace* HeapRegion::next_compaction_space() const {
// We're not using an iterator given that it will wrap around when
*** 726,735 ****
--- 588,751 ----
cur = next;
}
return NULL;
}
+ // Code roots support
+
+ void HeapRegion::add_strong_code_root(nmethod* nm) {
+ HeapRegionRemSet* hrrs = rem_set();
+ hrrs->add_strong_code_root(nm);
+ }
+
+ void HeapRegion::remove_strong_code_root(nmethod* nm) {
+ HeapRegionRemSet* hrrs = rem_set();
+ hrrs->remove_strong_code_root(nm);
+ }
+
+ void HeapRegion::migrate_strong_code_roots() {
+ assert(in_collection_set(), "only collection set regions");
+ assert(!isHumongous(), "not humongous regions");
+
+ HeapRegionRemSet* hrrs = rem_set();
+ hrrs->migrate_strong_code_roots();
+ }
+
+ void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const {
+ HeapRegionRemSet* hrrs = rem_set();
+ hrrs->strong_code_roots_do(blk);
+ }
+
+ 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;
+ }
+
+ HeapRegionRemSet* hrrs = rem_set();
+ int strong_code_roots_length = hrrs->strong_code_roots_list_length();
+
+ // if this region is empty then there should be no entries
+ // on its strong code root list
+ if (is_empty()) {
+ if (strong_code_roots_length > 0) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty "
+ "but has "INT32_FORMAT" code root entries",
+ bottom(), end(), strong_code_roots_length);
+ *failures = true;
+ }
+ return;
+ }
+
+ // An H-region should have an empty strong code root list
+ if (isHumongous()) {
+ if (strong_code_roots_length > 0) {
+ gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is humongous "
+ "but has "INT32_FORMAT" code root entries",
+ bottom(), end(), strong_code_roots_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");
*** 754,767 ****
st->print(" PTAMS "PTR_FORMAT" NTAMS "PTR_FORMAT,
prev_top_at_mark_start(), next_top_at_mark_start());
G1OffsetTableContigSpace::print_on(st);
}
! void HeapRegion::verify() const {
! bool dummy = false;
! verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy);
! }
// This really ought to be commoned up into OffsetTableContigSpace somehow.
// We would need a mechanism to make that code skip dead objects.
void HeapRegion::verify(VerifyOption vo,
--- 770,916 ----
st->print(" PTAMS "PTR_FORMAT" NTAMS "PTR_FORMAT,
prev_top_at_mark_start(), next_top_at_mark_start());
G1OffsetTableContigSpace::print_on(st);
}
! class VerifyLiveClosure: public OopClosure {
! private:
! G1CollectedHeap* _g1h;
! CardTableModRefBS* _bs;
! oop _containing_obj;
! bool _failures;
! int _n_failures;
! VerifyOption _vo;
! public:
! // _vo == UsePrevMarking -> use "prev" marking information,
! // _vo == UseNextMarking -> use "next" marking information,
! // _vo == UseMarkWord -> use mark word from object header.
! VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) :
! _g1h(g1h), _bs(NULL), _containing_obj(NULL),
! _failures(false), _n_failures(0), _vo(vo)
! {
! BarrierSet* bs = _g1h->barrier_set();
! if (bs->is_a(BarrierSet::CardTableModRef))
! _bs = (CardTableModRefBS*)bs;
! }
!
! void set_containing_obj(oop obj) {
! _containing_obj = obj;
! }
!
! bool failures() { return _failures; }
! int n_failures() { return _n_failures; }
!
! virtual void do_oop(narrowOop* p) { do_oop_work(p); }
! virtual void do_oop( oop* p) { do_oop_work(p); }
!
! void print_object(outputStream* out, oop obj) {
! #ifdef PRODUCT
! Klass* k = obj->klass();
! const char* class_name = InstanceKlass::cast(k)->external_name();
! out->print_cr("class name %s", class_name);
! #else // PRODUCT
! obj->print_on(out);
! #endif // PRODUCT
! }
!
! template <class T>
! void do_oop_work(T* p) {
! assert(_containing_obj != NULL, "Precondition");
! assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo),
! "Precondition");
! T heap_oop = oopDesc::load_heap_oop(p);
! if (!oopDesc::is_null(heap_oop)) {
! oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
! bool failed = false;
! if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) {
! MutexLockerEx x(ParGCRareEvent_lock,
! Mutex::_no_safepoint_check_flag);
!
! if (!_failures) {
! gclog_or_tty->print_cr("");
! gclog_or_tty->print_cr("----------");
! }
! if (!_g1h->is_in_closed_subset(obj)) {
! HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
! gclog_or_tty->print_cr("Field "PTR_FORMAT
! " of live obj "PTR_FORMAT" in region "
! "["PTR_FORMAT", "PTR_FORMAT")",
! p, (void*) _containing_obj,
! from->bottom(), from->end());
! print_object(gclog_or_tty, _containing_obj);
! gclog_or_tty->print_cr("points to obj "PTR_FORMAT" not in the heap",
! (void*) obj);
! } else {
! HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
! HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
! gclog_or_tty->print_cr("Field "PTR_FORMAT
! " of live obj "PTR_FORMAT" in region "
! "["PTR_FORMAT", "PTR_FORMAT")",
! p, (void*) _containing_obj,
! from->bottom(), from->end());
! print_object(gclog_or_tty, _containing_obj);
! gclog_or_tty->print_cr("points to dead obj "PTR_FORMAT" in region "
! "["PTR_FORMAT", "PTR_FORMAT")",
! (void*) obj, to->bottom(), to->end());
! print_object(gclog_or_tty, obj);
! }
! gclog_or_tty->print_cr("----------");
! gclog_or_tty->flush();
! _failures = true;
! failed = true;
! _n_failures++;
! }
!
! if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) {
! HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
! HeapRegion* to = _g1h->heap_region_containing(obj);
! if (from != NULL && to != NULL &&
! from != to &&
! !to->isHumongous()) {
! jbyte cv_obj = *_bs->byte_for_const(_containing_obj);
! jbyte cv_field = *_bs->byte_for_const(p);
! const jbyte dirty = CardTableModRefBS::dirty_card_val();
!
! bool is_bad = !(from->is_young()
! || to->rem_set()->contains_reference(p)
! || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed
! (_containing_obj->is_objArray() ?
! cv_field == dirty
! : cv_obj == dirty || cv_field == dirty));
! if (is_bad) {
! MutexLockerEx x(ParGCRareEvent_lock,
! Mutex::_no_safepoint_check_flag);
!
! if (!_failures) {
! gclog_or_tty->print_cr("");
! gclog_or_tty->print_cr("----------");
! }
! gclog_or_tty->print_cr("Missing rem set entry:");
! gclog_or_tty->print_cr("Field "PTR_FORMAT" "
! "of obj "PTR_FORMAT", "
! "in region "HR_FORMAT,
! p, (void*) _containing_obj,
! HR_FORMAT_PARAMS(from));
! _containing_obj->print_on(gclog_or_tty);
! gclog_or_tty->print_cr("points to obj "PTR_FORMAT" "
! "in region "HR_FORMAT,
! (void*) obj,
! HR_FORMAT_PARAMS(to));
! obj->print_on(gclog_or_tty);
! gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.",
! cv_obj, cv_field);
! gclog_or_tty->print_cr("----------");
! gclog_or_tty->flush();
! _failures = true;
! if (!failed) _n_failures++;
! }
! }
! }
! }
! }
! };
// This really ought to be commoned up into OffsetTableContigSpace somehow.
// We would need a mechanism to make that code skip dead objects.
void HeapRegion::verify(VerifyOption vo,
*** 897,906 ****
--- 1046,1062 ----
"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);
}
// G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go
// away eventually.