--- /dev/null 2015-10-06 23:29:51.451421828 +0200 +++ new/src/share/vm/gc/shenandoah/shenandoahConcurrentMark.cpp 2015-10-14 13:54:48.090070438 +0200 @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2013, 2015, Red Hat, Inc. and/or its affiliates. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "classfile/stringTable.hpp" +#include "gc/shared/gcTimer.hpp" +#include "gc/shared/isGCActiveMark.hpp" +#include "gc/shared/strongRootsScope.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahRootProcessor.hpp" +#include "gc/shenandoah/brooksPointer.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "code/codeCache.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/systemDictionary.hpp" +#include "memory/iterator.inline.hpp" +#include "oops/oop.inline.hpp" +#include "gc/shared/taskqueue.inline.hpp" + +// Mark the object and add it to the queue to be scanned +ShenandoahMarkObjsClosure::ShenandoahMarkObjsClosure(SCMObjToScanQueue* q, bool update_refs) : + _heap((ShenandoahHeap*)(Universe::heap())), + _mark_refs(ShenandoahMarkRefsClosure(q, update_refs)), + _live_data(NEW_C_HEAP_ARRAY(size_t, _heap->max_regions(), mtGC)) +{ + Copy::zero_to_bytes(_live_data, _heap->max_regions() * sizeof(size_t)); +} + +ShenandoahMarkObjsClosure::~ShenandoahMarkObjsClosure() { + // Merge liveness data back into actual regions. + + // We need to lock the heap here, to avoid race with growing of heap. + MutexLockerEx ml(ShenandoahHeap_lock, true); + ShenandoahHeapRegion** regions = _heap->heap_regions(); + for (uint i = 0; i < _heap->num_regions(); i++) { + regions[i]->increase_live_data(_live_data[i]); + } + FREE_C_HEAP_ARRAY(size_t, _live_data); +} + +ShenandoahMarkRefsClosure::ShenandoahMarkRefsClosure(SCMObjToScanQueue* q, bool update_refs) : + MetadataAwareOopClosure(((ShenandoahHeap *) Universe::heap())->ref_processor()), + _queue(q), + _heap((ShenandoahHeap*) Universe::heap()), + _scm(_heap->concurrentMark()), + _update_refs(update_refs) +{ +} + +void ShenandoahMarkRefsClosure::do_oop(narrowOop* p) { + Unimplemented(); +} + + +// Walks over all the objects in the generation updating any +// references to from space. + +class CLDMarkAliveClosure : public CLDClosure { +private: + CLDClosure* _cl; +public: + CLDMarkAliveClosure(CLDClosure* cl) : _cl(cl) { + } + void do_cld(ClassLoaderData* cld) { + ShenandoahIsAliveClosure is_alive; + if (cld->is_alive(&is_alive)) { + _cl->do_cld(cld); + } + } +}; + +class ShenandoahMarkRootsTask : public AbstractGangTask { +private: + ShenandoahRootProcessor* _rp; + bool _update_refs; +public: + ShenandoahMarkRootsTask(ShenandoahRootProcessor* rp, bool update_refs) : + AbstractGangTask("Shenandoah update roots task"), _update_refs(update_refs), + _rp(rp) { + } + + void work(uint worker_id) { + // tty->print_cr("start mark roots worker: "INT32_FORMAT, worker_id); + ShenandoahHeap* heap = ShenandoahHeap::heap(); + SCMObjToScanQueue* q = heap->concurrentMark()->get_queue(worker_id); + ShenandoahMarkRefsClosure cl(q, _update_refs); + + CodeBlobToOopClosure blobsCl(&cl, true); + CLDToOopClosure cldCl(&cl); + + ResourceMark m; + if (ShenandoahProcessReferences && ClassUnloadingWithConcurrentMark) { + _rp->process_strong_roots(&cl, &cldCl, &blobsCl); + } else { + _rp->process_all_roots(&cl, &cldCl, &blobsCl); + } + // tty->print_cr("finish mark roots worker: "INT32_FORMAT, worker_id); + } +}; + +class SCMConcurrentMarkingTask : public AbstractGangTask { +private: + ShenandoahConcurrentMark* _cm; + ParallelTaskTerminator* _terminator; + int _seed; + bool _update_refs; + +public: + SCMConcurrentMarkingTask(ShenandoahConcurrentMark* cm, ParallelTaskTerminator* terminator, bool update_refs) : + AbstractGangTask("Root Region Scan"), _cm(cm), _terminator(terminator), _update_refs(update_refs), _seed(17) { + } + + + void work(uint worker_id) { + + SCMObjToScanQueue* q = _cm->get_queue(worker_id); + ShenandoahMarkObjsClosure cl(q, _update_refs); + ShenandoahHeap* heap = ShenandoahHeap::heap(); + while (true) { + if (heap->cancelled_concgc() || + (!_cm->try_queue(q, &cl) && + !_cm->try_draining_an_satb_buffer(worker_id) && + !_cm->try_to_steal(worker_id, &cl, &_seed)) + ) { + if (_terminator->offer_termination()) break; + } + } + if (ShenandoahTracePhases && heap->cancelled_concgc()) { + tty->print_cr("Cancelled concurrent marking"); + } + } +}; + +void ShenandoahConcurrentMark::prepare_unmarked_root_objs() { + + ShenandoahHeap* heap = ShenandoahHeap::heap(); + bool update_refs = heap->need_update_refs(); + + if (update_refs) { + COMPILER2_PRESENT(DerivedPointerTable::clear()); + } + + prepare_unmarked_root_objs_no_derived_ptrs(update_refs); + + if (update_refs) { + COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); + } + +} + +void ShenandoahConcurrentMark::prepare_unmarked_root_objs_no_derived_ptrs(bool update_refs) { + assert(Thread::current()->is_VM_thread(), "can only do this in VMThread"); + + ShenandoahHeap* heap = ShenandoahHeap::heap(); + if (ShenandoahParallelRootScan) { + + ClassLoaderDataGraph::clear_claimed_marks(); + heap->conc_workers()->set_active_workers(_max_conc_worker_id); + ShenandoahRootProcessor root_proc(heap, _max_conc_worker_id); + TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); + ShenandoahMarkRootsTask mark_roots(&root_proc, update_refs); + heap->conc_workers()->run_task(&mark_roots); + + // Mark through any class loaders that have been found alive. + ShenandoahMarkRefsClosure cl(get_queue(0), update_refs); + CLDToOopClosure cldCl(&cl); + CLDMarkAliveClosure cld_keep_alive(&cldCl); + ClassLoaderDataGraph::roots_cld_do(NULL, &cld_keep_alive); + + } else { + ShenandoahMarkRefsClosure cl(get_queue(0), update_refs); + heap->roots_iterate(&cl); + } + + if (!(ShenandoahProcessReferences && ClassUnloadingWithConcurrentMark)) { + ShenandoahMarkRefsClosure cl(get_queue(0), update_refs); + heap->weak_roots_iterate(&cl); + } + + // tty->print_cr("all root marker threads done"); +} + + +void ShenandoahConcurrentMark::initialize() { + _max_conc_worker_id = MAX2((uint) ConcGCThreads, 1U); + _task_queues = new SCMObjToScanQueueSet((int) _max_conc_worker_id); + + for (uint i = 0; i < _max_conc_worker_id; ++i) { + SCMObjToScanQueue* task_queue = new SCMObjToScanQueue(); + task_queue->initialize(); + _task_queues->register_queue(i, task_queue); + } + JavaThread::satb_mark_queue_set().set_buffer_size(1014 /* G1SATBBufferSize */); +} + +void ShenandoahConcurrentMark::mark_from_roots() { + if (ShenandoahGCVerbose) { + tty->print_cr("STOPPING THE WORLD: before marking"); + tty->print_cr("Starting markFromRoots"); + } + + ShenandoahHeap* sh = (ShenandoahHeap *) Universe::heap(); + + bool update_refs = sh->need_update_refs(); + + sh->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::conc_mark); + ParallelTaskTerminator terminator(_max_conc_worker_id, _task_queues); + + if (ShenandoahProcessReferences) { + ReferenceProcessor* rp = sh->ref_processor(); + // enable ("weak") refs discovery + rp->enable_discovery(true /*verify_no_refs*/); + rp->setup_policy(false); // snapshot the soft ref policy to be used in this cycle + } + + SCMConcurrentMarkingTask markingTask = SCMConcurrentMarkingTask(this, &terminator, update_refs); + sh->conc_workers()->set_active_workers(_max_conc_worker_id); + sh->conc_workers()->run_task(&markingTask); + + if (ShenandoahGCVerbose) { + tty->print("total workers = %u active workers = %u\n", + sh->conc_workers()->total_workers(), + sh->conc_workers()->active_workers()); + TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); + } + + if (ShenandoahGCVerbose) { + tty->print_cr("Finishing markFromRoots"); + tty->print_cr("RESUMING THE WORLD: after marking"); + } + + sh->shenandoahPolicy()->record_phase_end(ShenandoahCollectorPolicy::conc_mark); +} + +class FinishDrainSATBBuffersTask : public AbstractGangTask { +private: + ShenandoahConcurrentMark* _cm; + ParallelTaskTerminator* _terminator; +public: + FinishDrainSATBBuffersTask(ShenandoahConcurrentMark* cm, ParallelTaskTerminator* terminator) : + AbstractGangTask("Finish draining SATB buffers"), _cm(cm), _terminator(terminator) { + } + + void work(uint worker_id) { + _cm->drain_satb_buffers(worker_id, true); + } +}; + +class ShenandoahUpdateAliveRefs : public OopClosure { +private: + ShenandoahHeap* _heap; +public: + ShenandoahUpdateAliveRefs() : _heap(ShenandoahHeap::heap()) { + } + virtual void do_oop(oop* p) { + _heap->maybe_update_oop_ref(p); + } + + virtual void do_oop(narrowOop* p) { + Unimplemented(); + } +}; + +void ShenandoahConcurrentMark::finish_mark_from_roots() { + if (ShenandoahGCVerbose) { + tty->print_cr("Starting finishMarkFromRoots"); + } + + IsGCActiveMark is_active; + + ShenandoahHeap* sh = (ShenandoahHeap *) Universe::heap(); + + // Trace any (new) unmarked root references. + sh->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::rescan_roots); + prepare_unmarked_root_objs(); + sh->shenandoahPolicy()->record_phase_end(ShenandoahCollectorPolicy::rescan_roots); + sh->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::drain_satb); + { + StrongRootsScope scope(_max_conc_worker_id); + ParallelTaskTerminator terminator(_max_conc_worker_id, _task_queues); + // drain_satb_buffers(0, true); + FinishDrainSATBBuffersTask drain_satb_buffers(this, &terminator); + sh->conc_workers()->set_active_workers(_max_conc_worker_id); + sh->conc_workers()->run_task(&drain_satb_buffers); + sh->shenandoahPolicy()->record_phase_end(ShenandoahCollectorPolicy::drain_satb); + } + + // Finally mark everything else we've got in our queues during the previous steps. + { + sh->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::drain_queues); + ParallelTaskTerminator terminator(_max_conc_worker_id, _task_queues); + SCMConcurrentMarkingTask markingTask = SCMConcurrentMarkingTask(this, &terminator, sh->need_update_refs()); + sh->conc_workers()->set_active_workers(_max_conc_worker_id); + sh->conc_workers()->run_task(&markingTask); + sh->shenandoahPolicy()->record_phase_end(ShenandoahCollectorPolicy::drain_queues); + } + +#ifdef ASSERT + for (int i = 0; i < (int) _max_conc_worker_id; i++) { + assert(_task_queues->queue(i)->is_empty(), "Should be empty"); + } +#endif + + // When we're done marking everything, we process weak references. + if (ShenandoahProcessReferences) { + sh->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::weakrefs); + weak_refs_work(); + sh->shenandoahPolicy()->record_phase_end(ShenandoahCollectorPolicy::weakrefs); + } + +#ifdef ASSERT + for (int i = 0; i < (int) _max_conc_worker_id; i++) { + assert(_task_queues->queue(i)->is_empty(), "Should be empty"); + } +#endif + + if (ShenandoahGCVerbose) { + tty->print_cr("Finishing finishMarkFromRoots"); +#ifdef SLOWDEBUG + for (int i = 0; i <(int)_max_conc_worker_id; i++) { + tty->print("Queue: "INT32_FORMAT":", i); + _task_queues->queue(i)->stats.print(tty, 10); + tty->cr(); + _task_queues->queue(i)->stats.verify(); + } +#endif + } + + // We still need to update (without marking) alive refs in JNI handles. + if (ShenandoahProcessReferences && ClassUnloadingWithConcurrentMark) { + ShenandoahUpdateAliveRefs cl; + ShenandoahIsAliveClosure is_alive; + JNIHandles::weak_oops_do(&is_alive, &cl); + } + +#ifdef ASSERT + verify_roots(); + + if (ShenandoahDumpHeapAfterConcurrentMark) { + sh->ensure_parsability(false); + sh->print_all_refs("post-mark"); + } +#endif +} + +#ifdef ASSERT +void ShenandoahVerifyRootsClosure1::do_oop(oop* p) { + oop obj = oopDesc::load_heap_oop(p); + if (! oopDesc::is_null(obj)) { + guarantee(ShenandoahHeap::heap()->is_marked_current(obj), "oop must be marked"); + guarantee(obj == ShenandoahBarrierSet::resolve_oop_static_not_null(obj), "oop must not be forwarded"); + } +} + +void ShenandoahConcurrentMark::verify_roots() { + ShenandoahVerifyRootsClosure1 cl; + CodeBlobToOopClosure blobsCl(&cl, true); + CLDToOopClosure cldCl(&cl); + ClassLoaderDataGraph::clear_claimed_marks(); + ShenandoahRootProcessor rp(ShenandoahHeap::heap(), 1); + rp.process_roots(&cl, &cl, &cldCl, &cldCl, &cldCl, &blobsCl); +} +#endif + +class ShenandoahSATBBufferClosure : public SATBBufferClosure { +private: + SCMObjToScanQueue* _queue; + ShenandoahHeap* _heap; +public: + ShenandoahSATBBufferClosure(SCMObjToScanQueue* q) : + _queue(q), _heap(ShenandoahHeap::heap()) + { + } + + void do_buffer(void** buffer, size_t size) { + // tty->print_cr("draining one satb buffer"); + for (size_t i = 0; i < size; ++i) { + void* entry = buffer[i]; + oop obj = oop(entry); + // tty->print_cr("satb buffer entry: "PTR_FORMAT, p2i((HeapWord*) obj)); + if (!oopDesc::is_null(obj)) { + obj = ShenandoahBarrierSet::resolve_oop_static_not_null(obj); + if (_heap->mark_current(obj)) { + bool pushed = _queue->push(obj); + assert(pushed, "overflow queue should always succeed pushing"); + } + } + } + } +}; + +class ShenandoahSATBThreadsClosure : public ThreadClosure { + ShenandoahSATBBufferClosure* _satb_cl; + int _thread_parity; + + public: + ShenandoahSATBThreadsClosure(ShenandoahSATBBufferClosure* satb_cl) : + _satb_cl(satb_cl), + _thread_parity(Threads::thread_claim_parity()) {} + + void do_thread(Thread* thread) { + if (thread->is_Java_thread()) { + if (thread->claim_oops_do(true, _thread_parity)) { + JavaThread* jt = (JavaThread*)thread; + jt->satb_mark_queue().apply_closure_and_empty(_satb_cl); + } + } else if (thread->is_VM_thread()) { + if (thread->claim_oops_do(true, _thread_parity)) { + JavaThread::satb_mark_queue_set().shared_satb_queue()->apply_closure_and_empty(_satb_cl); + } + } + } +}; + +void ShenandoahConcurrentMark::drain_satb_buffers(uint worker_id, bool remark) { + + // tty->print_cr("start draining SATB buffers"); + + ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); + SCMObjToScanQueue* q = get_queue(worker_id); + ShenandoahSATBBufferClosure cl(q); + + SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); + while (satb_mq_set.apply_closure_to_completed_buffer(&cl)); + + if (remark) { + ShenandoahSATBThreadsClosure tc(&cl); + Threads::threads_do(&tc); + } + + // tty->print_cr("end draining SATB buffers"); + +} + +bool ShenandoahConcurrentMark::drain_one_satb_buffer(uint worker_id) { + + ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); + SCMObjToScanQueue* q = get_queue(worker_id); + ShenandoahSATBBufferClosure cl(q); + + SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); + bool result = satb_mq_set.apply_closure_to_completed_buffer(&cl); + return result; +} + +#if TASKQUEUE_STATS +void ShenandoahConcurrentMark::print_taskqueue_stats_hdr(outputStream* const st) { + st->print_raw_cr("GC Task Stats"); + st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); + st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); +} + +void ShenandoahConcurrentMark::print_taskqueue_stats(outputStream* const st) const { + print_taskqueue_stats_hdr(st); + ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); + TaskQueueStats totals; + const int n = sh->max_conc_workers(); + for (int i = 0; i < n; ++i) { + st->print(INT32_FORMAT_W(3), i); + _task_queues->queue(i)->stats.print(st); + st->print("\n"); + totals += _task_queues->queue(i)->stats; + } + st->print_raw("tot "); totals.print(st); st->cr(); + DEBUG_ONLY(totals.verify()); + +} + +void ShenandoahConcurrentMark::print_push_only_taskqueue_stats(outputStream* const st) const { + print_taskqueue_stats_hdr(st); + ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); + TaskQueueStats totals; + const int n = sh->max_conc_workers(); + for (int i = 0; i < n; ++i) { + st->print(INT32_FORMAT_W(3), i); + _task_queues->queue(i)->stats.print(st); + st->print("\n"); + totals += _task_queues->queue(i)->stats; + } + st->print_raw("tot "); totals.print(st); st->cr(); +} + +void ShenandoahConcurrentMark::reset_taskqueue_stats() { + ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); + const int n = sh->max_conc_workers(); + for (int i = 0; i < n; ++i) { + _task_queues->queue(i)->stats.reset(); + } +} +#endif // TASKQUEUE_STATS + +// Weak Reference Closures +class ShenandoahCMDrainMarkingStackClosure: public VoidClosure { + ShenandoahHeap* _sh; + ShenandoahConcurrentMark* _scm; + uint _worker_id; + int _seed; + +public: + ShenandoahCMDrainMarkingStackClosure(uint worker_id): _worker_id(worker_id), _seed(17) { + _sh = (ShenandoahHeap*) Universe::heap(); + _scm = _sh->concurrentMark(); + } + + + void do_void() { + + SCMObjToScanQueue* q = _scm->get_queue(_worker_id); + ShenandoahMarkObjsClosure cl(q, _sh->need_update_refs()); + while (true) { + if (!_scm->try_queue(q, &cl) && + !_scm->try_draining_an_satb_buffer(_worker_id) && + !_scm->try_to_steal(_worker_id, &cl, &_seed)) { + break; + } + } + } +}; + + +class ShenandoahCMKeepAliveAndDrainClosure: public OopClosure { + SCMObjToScanQueue* _queue; + ShenandoahHeap* _sh; + ShenandoahConcurrentMark* _scm; + + size_t _ref_count; + +public: + ShenandoahCMKeepAliveAndDrainClosure(SCMObjToScanQueue* q) : + _queue(q) { + _sh = (ShenandoahHeap*) Universe::heap(); + _scm = _sh->concurrentMark(); + _ref_count = 0; + } + + virtual void do_oop(oop* p){ do_oop_work(p);} + virtual void do_oop(narrowOop* p) { + assert(false, "narrowOops Aren't implemented"); + } + + + void do_oop_work(oop* p) { + + oop obj; + if (_sh->need_update_refs()) { + obj = _sh->maybe_update_oop_ref(p); + } else { + obj = oopDesc::load_heap_oop(p); + } + + assert(obj == oopDesc::bs()->read_barrier(obj), "only get updated oops in weak ref processing"); + + if (obj != NULL) { + if (Verbose && ShenandoahTraceWeakReferences) { + gclog_or_tty->print_cr("\twe're looking at location " + "*"PTR_FORMAT" = "PTR_FORMAT, + p2i(p), p2i((void*) obj)); + obj->print(); + } + if (_sh->mark_current(obj)) { + bool pushed = _queue->push(obj); + assert(pushed, "overflow queue should always succeed pushing"); + } + + _ref_count++; + } + } + + size_t ref_count() { return _ref_count; } + +}; + +class ShenandoahRefProcTaskProxy : public AbstractGangTask { + +private: + AbstractRefProcTaskExecutor::ProcessTask& _proc_task; + +public: + + ShenandoahRefProcTaskProxy(AbstractRefProcTaskExecutor::ProcessTask& proc_task) : + AbstractGangTask("Process reference objects in parallel"), + _proc_task(proc_task) { + } + + void work(uint worker_id) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + ShenandoahIsAliveClosure is_alive; + ShenandoahCMKeepAliveAndDrainClosure keep_alive(heap->concurrentMark()->get_queue(worker_id)); + ShenandoahCMDrainMarkingStackClosure complete_gc(worker_id); + _proc_task.work(worker_id, is_alive, keep_alive, complete_gc); + } +}; + +class ShenandoahRefEnqueueTaskProxy : public AbstractGangTask { + +private: + AbstractRefProcTaskExecutor::EnqueueTask& _enqueue_task; + +public: + + ShenandoahRefEnqueueTaskProxy(AbstractRefProcTaskExecutor::EnqueueTask& enqueue_task) : + AbstractGangTask("Enqueue reference objects in parallel"), + _enqueue_task(enqueue_task) { + } + + void work(uint worker_id) { + _enqueue_task.work(worker_id); + } +}; + +class ShenandoahRefProcTaskExecutor : public AbstractRefProcTaskExecutor { + +private: + WorkGang* _workers; + +public: + + ShenandoahRefProcTaskExecutor() : _workers(ShenandoahHeap::heap()->conc_workers()) { + } + + // Executes a task using worker threads. + void execute(ProcessTask& task) { + ShenandoahRefProcTaskProxy proc_task_proxy(task); + _workers->run_task(&proc_task_proxy); + } + + void execute(EnqueueTask& task) { + ShenandoahRefEnqueueTaskProxy enqueue_task_proxy(task); + _workers->run_task(&enqueue_task_proxy); + } +}; + + +void ShenandoahConcurrentMark::weak_refs_work() { + ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); + ReferenceProcessor* rp = sh->ref_processor(); + + // Setup collector policy for softref cleaning. + bool clear_soft_refs = sh->collector_policy()->use_should_clear_all_soft_refs(true /* bogus arg*/); + if (ShenandoahTraceWeakReferences) { + tty->print_cr("clearing soft refs: %s", BOOL_TO_STR(clear_soft_refs)); + } + rp->setup_policy(clear_soft_refs); + + uint serial_worker_id = 0; + ShenandoahIsAliveClosure is_alive; + ShenandoahCMKeepAliveAndDrainClosure keep_alive(get_queue(serial_worker_id)); + ShenandoahCMDrainMarkingStackClosure complete_gc(serial_worker_id); + ShenandoahRefProcTaskExecutor par_task_executor; + bool processing_is_mt = true; + AbstractRefProcTaskExecutor* executor = (processing_is_mt ? &par_task_executor : NULL); + + if (ShenandoahTraceWeakReferences) { + gclog_or_tty->print_cr("start processing references"); + } + + rp->process_discovered_references(&is_alive, &keep_alive, + &complete_gc, &par_task_executor, + NULL, + ShenandoahHeap::heap()->tracer()->gc_id()); + + if (ShenandoahTraceWeakReferences) { + gclog_or_tty->print_cr("finished processing references, processed "SIZE_FORMAT" refs", keep_alive.ref_count()); + gclog_or_tty->print_cr("start enqueuing references"); + } + + rp->enqueue_discovered_references(executor); + + if (ShenandoahTraceWeakReferences) { + gclog_or_tty->print_cr("finished enqueueing references"); + } + + rp->verify_no_references_recorded(); + assert(!rp->discovery_enabled(), "Post condition"); + + if (ClassUnloadingWithConcurrentMark) { + // Unload classes and purge SystemDictionary. + bool purged_class = SystemDictionary::do_unloading(&is_alive); + // Unload nmethods. + CodeCache::do_unloading(&is_alive, purged_class); + // Prune dead klasses from subklass/sibling/implementor lists. + Klass::clean_weak_klass_links(&is_alive); + // Delete entries from dead interned strings. + StringTable::unlink(&is_alive); + // Clean up unreferenced symbols in symbol table. + SymbolTable::unlink(); + + ClassLoaderDataGraph::purge(); + } +} + +void ShenandoahConcurrentMark::cancel() { + ShenandoahHeap* sh = ShenandoahHeap::heap(); + + // Cancel weak-ref discovery. + if (ShenandoahProcessReferences) { + ReferenceProcessor* rp = sh->ref_processor(); + rp->abandon_partial_discovery(); + rp->disable_discovery(); + } + + // Clean up marking stacks. + SCMObjToScanQueueSet* queues = task_queues(); + for (uint i = 0; i < _max_conc_worker_id; ++i) { + SCMObjToScanQueue* task_queue = queues->queue(i); + task_queue->set_empty(); + task_queue->overflow_stack()->clear(); + } + + // Cancel SATB buffers. + JavaThread::satb_mark_queue_set().abandon_partial_marking(); +} +SCMObjToScanQueue* ShenandoahConcurrentMark::get_queue(uint worker_id) { + worker_id = worker_id % _max_conc_worker_id; + return _task_queues->queue(worker_id); +}