< prev index next >
hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp
Print this page
rev 7368 : 8075215: SATB buffer processing found reclaimed humongous object
Summary: Don't assume SATB buffer entries are valid objects
Reviewed-by: brutisso, ecaspole
*** 2638,2673 ****
CMBitMapRO* temp = _prevMarkBitMap;
_prevMarkBitMap = (CMBitMapRO*)_nextMarkBitMap;
_nextMarkBitMap = (CMBitMap*) temp;
}
! class CMObjectClosure;
!
! // Closure for iterating over objects, currently only used for
! // processing SATB buffers.
! class CMObjectClosure : public ObjectClosure {
private:
CMTask* _task;
! public:
! void do_object(oop obj) {
! _task->deal_with_reference(obj);
}
! CMObjectClosure(CMTask* task) : _task(task) { }
};
class G1RemarkThreadsClosure : public ThreadClosure {
! CMObjectClosure _cm_obj;
G1CMOopClosure _cm_cl;
MarkingCodeBlobClosure _code_cl;
int _thread_parity;
bool _is_par;
public:
G1RemarkThreadsClosure(G1CollectedHeap* g1h, CMTask* task, bool is_par) :
! _cm_obj(task), _cm_cl(g1h, g1h->concurrent_mark(), task), _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations),
_thread_parity(SharedHeap::heap()->strong_roots_parity()), _is_par(is_par) {}
void do_thread(Thread* thread) {
if (thread->is_Java_thread()) {
if (thread->claim_oops_do(_is_par, _thread_parity)) {
--- 2638,2692 ----
CMBitMapRO* temp = _prevMarkBitMap;
_prevMarkBitMap = (CMBitMapRO*)_nextMarkBitMap;
_nextMarkBitMap = (CMBitMap*) temp;
}
! // Closure for marking entries in SATB buffers.
! class CMSATBBufferClosure : public SATBBufferClosure {
private:
CMTask* _task;
+ G1CollectedHeap* _g1h;
! // This is very similar to CMTask::deal_with_reference, but with
! // more relaxed requirements for the argument, so this must be more
! // circumspect about treating the argument as an object.
! void do_entry(void* entry) const {
! _task->increment_refs_reached();
! HeapRegion* hr = _g1h->heap_region_containing_raw(entry);
! if (entry < hr->next_top_at_mark_start()) {
! // Until we get here, we don't know whether entry refers to a valid
! // object; it could instead have been a stale reference.
! oop obj = static_cast<oop>(entry);
! assert(obj->is_oop(true /* ignore mark word */),
! err_msg("Invalid oop in SATB buffer: " PTR_FORMAT, p2i(obj)));
! _task->make_reference_grey(obj, hr);
! }
}
! public:
! CMSATBBufferClosure(CMTask* task, G1CollectedHeap* g1h)
! : _task(task), _g1h(g1h) { }
!
! virtual void do_buffer(void** buffer, size_t size) {
! for (size_t i = 0; i < size; ++i) {
! do_entry(buffer[i]);
! }
! }
};
class G1RemarkThreadsClosure : public ThreadClosure {
! CMSATBBufferClosure _cm_satb_cl;
G1CMOopClosure _cm_cl;
MarkingCodeBlobClosure _code_cl;
int _thread_parity;
bool _is_par;
public:
G1RemarkThreadsClosure(G1CollectedHeap* g1h, CMTask* task, bool is_par) :
! _cm_satb_cl(task, g1h),
! _cm_cl(g1h, g1h->concurrent_mark(), task),
! _code_cl(&_cm_cl, !CodeBlobToOopClosure::FixRelocations),
_thread_parity(SharedHeap::heap()->strong_roots_parity()), _is_par(is_par) {}
void do_thread(Thread* thread) {
if (thread->is_Java_thread()) {
if (thread->claim_oops_do(_is_par, _thread_parity)) {
*** 2679,2693 ****
// * Weakly reachable otherwise
// Some objects reachable from nmethods, such as the class loader (or klass_holder) of the receiver should be
// live by the SATB invariant but other oops recorded in nmethods may behave differently.
jt->nmethods_do(&_code_cl);
! jt->satb_mark_queue().apply_closure_and_empty(&_cm_obj);
}
} else if (thread->is_VM_thread()) {
if (thread->claim_oops_do(_is_par, _thread_parity)) {
! JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_obj);
}
}
}
};
--- 2698,2712 ----
// * Weakly reachable otherwise
// Some objects reachable from nmethods, such as the class loader (or klass_holder) of the receiver should be
// live by the SATB invariant but other oops recorded in nmethods may behave differently.
jt->nmethods_do(&_code_cl);
! jt->satb_mark_queue().apply_closure_and_empty(&_cm_satb_cl);
}
} else if (thread->is_VM_thread()) {
if (thread->claim_oops_do(_is_par, _thread_parity)) {
! JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(&_cm_satb_cl);
}
}
}
};
*** 3057,3069 ****
}
#ifndef PRODUCT
enum VerifyNoCSetOopsPhase {
VerifyNoCSetOopsStack,
! VerifyNoCSetOopsQueues,
! VerifyNoCSetOopsSATBCompleted,
! VerifyNoCSetOopsSATBThread
};
class VerifyNoCSetOopsClosure : public OopClosure, public ObjectClosure {
private:
G1CollectedHeap* _g1h;
--- 3076,3086 ----
}
#ifndef PRODUCT
enum VerifyNoCSetOopsPhase {
VerifyNoCSetOopsStack,
! VerifyNoCSetOopsQueues
};
class VerifyNoCSetOopsClosure : public OopClosure, public ObjectClosure {
private:
G1CollectedHeap* _g1h;
*** 3072,3083 ****
const char* phase_str() {
switch (_phase) {
case VerifyNoCSetOopsStack: return "Stack";
case VerifyNoCSetOopsQueues: return "Queue";
- case VerifyNoCSetOopsSATBCompleted: return "Completed SATB Buffers";
- case VerifyNoCSetOopsSATBThread: return "Thread SATB Buffers";
default: ShouldNotReachHere();
}
return NULL;
}
--- 3089,3098 ----
*** 3100,3157 ****
do_object_work(obj);
}
virtual void do_oop(narrowOop* p) {
// We should not come across narrow oops while scanning marking
! // stacks and SATB buffers.
ShouldNotReachHere();
}
virtual void do_object(oop obj) {
do_object_work(obj);
}
};
! void ConcurrentMark::verify_no_cset_oops(bool verify_stacks,
! bool verify_enqueued_buffers,
! bool verify_thread_buffers,
! bool verify_fingers) {
assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
if (!G1CollectedHeap::heap()->mark_in_progress()) {
return;
}
VerifyNoCSetOopsClosure cl;
- if (verify_stacks) {
// Verify entries on the global mark stack
cl.set_phase(VerifyNoCSetOopsStack);
_markStack.oops_do(&cl);
// Verify entries on the task queues
for (uint i = 0; i < _max_worker_id; i += 1) {
cl.set_phase(VerifyNoCSetOopsQueues, i);
CMTaskQueue* queue = _task_queues->queue(i);
queue->oops_do(&cl);
}
- }
- SATBMarkQueueSet& satb_qs = JavaThread::satb_mark_queue_set();
-
- // Verify entries on the enqueued SATB buffers
- if (verify_enqueued_buffers) {
- cl.set_phase(VerifyNoCSetOopsSATBCompleted);
- satb_qs.iterate_completed_buffers_read_only(&cl);
- }
-
- // Verify entries on the per-thread SATB buffers
- if (verify_thread_buffers) {
- cl.set_phase(VerifyNoCSetOopsSATBThread);
- satb_qs.iterate_thread_buffers_read_only(&cl);
- }
-
- if (verify_fingers) {
// Verify the global finger
HeapWord* global_finger = finger();
if (global_finger != NULL && global_finger < _heap_end) {
// The global finger always points to a heap region boundary. We
// use heap_region_containing_raw() to get the containing region
--- 3115,3152 ----
do_object_work(obj);
}
virtual void do_oop(narrowOop* p) {
// We should not come across narrow oops while scanning marking
! // stacks
ShouldNotReachHere();
}
virtual void do_object(oop obj) {
do_object_work(obj);
}
};
! void ConcurrentMark::verify_no_cset_oops() {
assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
if (!G1CollectedHeap::heap()->mark_in_progress()) {
return;
}
VerifyNoCSetOopsClosure cl;
// Verify entries on the global mark stack
cl.set_phase(VerifyNoCSetOopsStack);
_markStack.oops_do(&cl);
// Verify entries on the task queues
for (uint i = 0; i < _max_worker_id; i += 1) {
cl.set_phase(VerifyNoCSetOopsQueues, i);
CMTaskQueue* queue = _task_queues->queue(i);
queue->oops_do(&cl);
}
// Verify the global finger
HeapWord* global_finger = finger();
if (global_finger != NULL && global_finger < _heap_end) {
// The global finger always points to a heap region boundary. We
// use heap_region_containing_raw() to get the containing region
*** 3180,3190 ****
!task_hr->in_collection_set(),
err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT,
p2i(task_finger), HR_FORMAT_PARAMS(task_hr)));
}
}
- }
}
#endif // PRODUCT
// Aggregate the counting data that was constructed concurrently
// with marking.
--- 3175,3184 ----
*** 3508,3533 ****
}
gclog_or_tty->cr();
}
#endif
! void CMTask::scan_object(oop obj) {
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
if (_cm->verbose_high()) {
! gclog_or_tty->print_cr("[%u] we're scanning object "PTR_FORMAT,
_worker_id, p2i((void*) obj));
}
size_t obj_size = obj->size();
_words_scanned += obj_size;
obj->oop_iterate(_cm_oop_closure);
statsOnly( ++_objs_scanned );
check_limits();
}
// Closure for iteration over bitmaps
class CMBitMapClosure : public BitMapClosure {
private:
// the bitmap that is being iterated over
CMBitMap* _nextMarkBitMap;
--- 3502,3534 ----
}
gclog_or_tty->cr();
}
#endif
! template<bool scan>
! inline void CMTask::process_grey_object(oop obj) {
! assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray");
assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant");
if (_cm->verbose_high()) {
! gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT,
_worker_id, p2i((void*) obj));
}
size_t obj_size = obj->size();
_words_scanned += obj_size;
+ if (scan) {
obj->oop_iterate(_cm_oop_closure);
+ }
statsOnly( ++_objs_scanned );
check_limits();
}
+ template void CMTask::process_grey_object<true>(oop);
+ template void CMTask::process_grey_object<false>(oop);
+
// Closure for iteration over bitmaps
class CMBitMapClosure : public BitMapClosure {
private:
// the bitmap that is being iterated over
CMBitMap* _nextMarkBitMap;
*** 3992,4043 ****
// middle of draining buffers and doesn't set the abort flag when it
// notices that SATB buffers are available for draining. It'd be
// very counter productive if it did that. :-)
_draining_satb_buffers = true;
! CMObjectClosure oc(this);
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
- if (G1CollectedHeap::use_parallel_gc_threads()) {
- satb_mq_set.set_par_closure(_worker_id, &oc);
- } else {
- satb_mq_set.set_closure(&oc);
- }
// This keeps claiming and applying the closure to completed buffers
// until we run out of buffers or we need to abort.
- if (G1CollectedHeap::use_parallel_gc_threads()) {
while (!has_aborted() &&
! satb_mq_set.par_apply_closure_to_completed_buffer(_worker_id)) {
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
}
statsOnly( ++_satb_buffers_processed );
regular_clock_call();
}
- } else {
- while (!has_aborted() &&
- satb_mq_set.apply_closure_to_completed_buffer()) {
- if (_cm->verbose_medium()) {
- gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
- }
- statsOnly( ++_satb_buffers_processed );
- regular_clock_call();
- }
- }
_draining_satb_buffers = false;
assert(has_aborted() ||
concurrent() ||
satb_mq_set.completed_buffers_num() == 0, "invariant");
- if (G1CollectedHeap::use_parallel_gc_threads()) {
- satb_mq_set.set_par_closure(_worker_id, NULL);
- } else {
- satb_mq_set.set_closure(NULL);
- }
-
// again, this was a potentially expensive operation, decrease the
// limits to get the regular clock call early
decrease_limits();
}
--- 3993,4022 ----
// middle of draining buffers and doesn't set the abort flag when it
// notices that SATB buffers are available for draining. It'd be
// very counter productive if it did that. :-)
_draining_satb_buffers = true;
! CMSATBBufferClosure satb_cl(this, _g1h);
SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
// This keeps claiming and applying the closure to completed buffers
// until we run out of buffers or we need to abort.
while (!has_aborted() &&
! satb_mq_set.apply_closure_to_completed_buffer(&satb_cl)) {
if (_cm->verbose_medium()) {
gclog_or_tty->print_cr("[%u] processed an SATB buffer", _worker_id);
}
statsOnly( ++_satb_buffers_processed );
regular_clock_call();
}
_draining_satb_buffers = false;
assert(has_aborted() ||
concurrent() ||
satb_mq_set.completed_buffers_num() == 0, "invariant");
// again, this was a potentially expensive operation, decrease the
// limits to get the regular clock call early
decrease_limits();
}
< prev index next >