--- old/src/share/vm/gc_implementation/g1/concurrentMark.cpp 2013-01-08 10:43:09.883424283 -0800 +++ new/src/share/vm/gc_implementation/g1/concurrentMark.cpp 2013-01-08 10:43:09.669067585 -0800 @@ -2167,7 +2167,8 @@ assert(tmp_free_list.is_empty(), "post-condition"); } -// Support closures for reference procssing in G1 +// Supporting Object and Oop closures for reference discovery +// and processing in during marking bool G1CMIsAliveClosure::do_object_b(oop obj) { HeapWord* addr = (HeapWord*)obj; @@ -2175,75 +2176,29 @@ (!_g1->is_in_g1_reserved(addr) || !_g1->is_obj_ill(obj)); } -class G1CMKeepAliveClosure: public ExtendedOopClosure { - G1CollectedHeap* _g1; - ConcurrentMark* _cm; - public: - G1CMKeepAliveClosure(G1CollectedHeap* g1, ConcurrentMark* cm) : - _g1(g1), _cm(cm) { - assert(Thread::current()->is_VM_thread(), "otherwise fix worker id"); - } - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - - template void do_oop_work(T* p) { - oop obj = oopDesc::load_decode_heap_oop(p); - HeapWord* addr = (HeapWord*)obj; - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("\t[0] we're looking at location " - "*"PTR_FORMAT" = "PTR_FORMAT, - p, (void*) obj); - } - - if (_g1->is_in_g1_reserved(addr) && _g1->is_obj_ill(obj)) { - _cm->mark_and_count(obj); - _cm->mark_stack_push(obj); - } - } -}; - -class G1CMDrainMarkingStackClosure: public VoidClosure { - ConcurrentMark* _cm; - CMMarkStack* _markStack; - G1CMKeepAliveClosure* _oopClosure; - public: - G1CMDrainMarkingStackClosure(ConcurrentMark* cm, CMMarkStack* markStack, - G1CMKeepAliveClosure* oopClosure) : - _cm(cm), - _markStack(markStack), - _oopClosure(oopClosure) { } +// 'Keep Alive' oop closure used by both serial parallel reference processing. +// Uses the CMTask associated with a worker thread (for serial reference +// processing the CMTask for worker 0 is used) to preserve (mark) and +// trace referent objects. +// +// Using the CMTask and embedded local queues avoids having the worker +// threads operating on the global mark stack in parallel - potentially +// interfering with each other. - void do_void() { - _markStack->drain(_oopClosure, _cm->nextMarkBitMap(), false); - } -}; - -// 'Keep Alive' closure used by parallel reference processing. -// An instance of this closure is used in the parallel reference processing -// code rather than an instance of G1CMKeepAliveClosure. We could have used -// the G1CMKeepAliveClosure as it is MT-safe. Also reference objects are -// placed on to discovered ref lists once so we can mark and push with no -// need to check whether the object has already been marked. Using the -// G1CMKeepAliveClosure would mean, however, having all the worker threads -// operating on the global mark stack. This means that an individual -// worker would be doing lock-free pushes while it processes its own -// discovered ref list followed by drain call. If the discovered ref lists -// are unbalanced then this could cause interference with the other -// workers. Using a CMTask (and its embedded local data structures) -// avoids that potential interference. class G1CMParKeepAliveAndDrainClosure: public OopClosure { ConcurrentMark* _cm; CMTask* _task; int _ref_counter_limit; int _ref_counter; + bool _is_par; + public: - G1CMParKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task), + G1CMParKeepAliveAndDrainClosure(ConcurrentMark* cm, CMTask* task, bool is_par) : + _cm(cm), _task(task), _is_par(is_par), _ref_counter_limit(G1RefProcDrainInterval) { assert(_ref_counter_limit > 0, "sanity"); _ref_counter = _ref_counter_limit; + assert(_task->worker_id() == 0 || _is_par, "sanity"); } virtual void do_oop(narrowOop* p) { do_oop_work(p); } @@ -2290,14 +2245,32 @@ } }; +// 'Drain' oop closure used by both serial and parallel reference processing. +// Uses the CMTask associated with a given worker thread (for serial +// reference processing the CMtask for worker 0 is used). Calls the +// do_marking_step routine, with an unbelievably large timeout value, +// to drain the marking data structures of the remaining entries +// added by the 'keep alive' oop closure above. + class G1CMParDrainMarkingStackClosure: public VoidClosure { ConcurrentMark* _cm; - CMTask* _task; + CMTask* _task; + bool _is_par; public: - G1CMParDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task) : - _cm(cm), _task(task) { } + G1CMParDrainMarkingStackClosure(ConcurrentMark* cm, CMTask* task, bool is_par) : + _cm(cm), _task(task), _is_par(is_par) { + assert(_task->worker_id() == 0 || _is_par, "sanity"); + } void do_void() { + if (!_is_par) { + // We need to set the phase so that the termination protocol in + // do_marking_step only waits for a single thread. The parallel + // version of this closure has the phase set for it by the + // RefProcTask executor instance. + _cm->set_phase(1, false /* concurrent */); + } + do { if (_cm->verbose_high()) { gclog_or_tty->print_cr("\t[%u] Drain: Calling do marking_step", @@ -2363,8 +2336,8 @@ virtual void work(uint worker_id) { CMTask* marking_task = _cm->task(worker_id); G1CMIsAliveClosure g1_is_alive(_g1h); - G1CMParKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); - G1CMParDrainMarkingStackClosure g1_par_drain(_cm, marking_task); + G1CMParKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task, true /* is_par */); + G1CMParDrainMarkingStackClosure g1_par_drain(_cm, marking_task, true /* is_par */); _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain); } @@ -2429,13 +2402,13 @@ // See the comment in G1CollectedHeap::ref_processing_init() // about how reference processing currently works in G1. - // Process weak references. + // Set the soft reference policy rp->setup_policy(clear_all_soft_refs); assert(_markStack.isEmpty(), "mark stack should be empty"); - G1CMKeepAliveClosure g1_keep_alive(g1h, this); - G1CMDrainMarkingStackClosure - g1_drain_mark_stack(this, &_markStack, &g1_keep_alive); + // Non-MT 'Keep Alive' and 'Complete GC' oop closures. + G1CMParKeepAliveAndDrainClosure g1_keep_alive(this, task(0), false /* is_par */); + G1CMParDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), false /* is_par */); // We use the work gang from the G1CollectedHeap and we utilize all // the worker threads. @@ -2444,7 +2417,8 @@ G1CMRefProcTaskExecutor par_task_executor(g1h, this, g1h->workers(), active_workers); - + + // Process the weak references. if (rp->processing_is_mt()) { // Set the degree of MT here. If the discovery is done MT, there // may have been a different number of threads doing the discovery @@ -2452,36 +2426,30 @@ // That is OK as long as the Reference lists are balanced (see // balance_all_queues() and balance_queues()). rp->set_active_mt_degree(active_workers); + } - rp->process_discovered_references(&g1_is_alive, + rp->process_discovered_references(&g1_is_alive, &g1_keep_alive, &g1_drain_mark_stack, - &par_task_executor); + (rp->processing_is_mt() ? &par_task_executor + : NULL)); - // The work routines of the parallel keep_alive and drain_marking_stack - // will set the has_overflown flag if we overflow the global marking - // stack. - } else { - rp->process_discovered_references(&g1_is_alive, - &g1_keep_alive, - &g1_drain_mark_stack, - NULL); - } + // The do_oop work routines of the keep_alive and drain_marking_stack + // oop closures will set the has_overflown flag if we overflow the + // global marking stack. assert(_markStack.overflow() || _markStack.isEmpty(), "mark stack should be empty (unless it overflowed)"); if (_markStack.overflow()) { - // Should have been done already when we tried to push an + // This should have been done already when we tried to push an // entry on to the global mark stack. But let's do it again. set_has_overflown(); } - if (rp->processing_is_mt()) { - assert(rp->num_q() == active_workers, "why not"); - rp->enqueue_discovered_references(&par_task_executor); - } else { - rp->enqueue_discovered_references(); - } + assert(!rp->processing_is_mt() || rp->num_q() == active_workers, "why not"); + + rp->enqueue_discovered_references((rp->processing_is_mt() ? &par_task_executor + : NULL)); rp->verify_no_references_recorded(); assert(!rp->discovery_enabled(), "Post condition");