Mercurial > hg > shenandoah-preopenjdk-archive > openjdk8 > hotspot
view src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp @ 7460:a5cdb779dc9c
Refactor timing code to be more generic and easier to extend.
author | Roman Kennke <rkennke@redhat.com> |
---|---|
date | Wed, 11 Feb 2015 18:05:39 +0100 |
parents | ac5d21fb6715 |
children | 2868d01310a4 |
line wrap: on
line source
/* Copyright 2014 Red Hat, Inc. and/or its affiliates. */ /* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * 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 "gc_implementation/shared/gcTimer.hpp" #include "gc_implementation/shenandoah/shenandoahBarrierSet.hpp" #include "gc_implementation/shenandoah/shenandoahConcurrentMark.hpp" #include "gc_implementation/shenandoah/shenandoahHeap.hpp" #include "gc_implementation/shenandoah/brooksPointer.hpp" #include "memory/referenceProcessor.hpp" #include "classfile/symbolTable.hpp" // Mark the object and add it to the queue to be scanned class ShenandoahMarkObjsClosure : public ObjectClosure { uint _worker_id; ShenandoahHeap* _heap; size_t* _live_data; public: ShenandoahMarkObjsClosure(uint worker_id) : _worker_id(worker_id), _heap((ShenandoahHeap*)(Universe::heap())), _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() { // 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, mtGC); } void do_object(oop obj) { ShenandoahConcurrentMark* scm = _heap->concurrentMark(); if (obj != NULL) { assert(obj == oopDesc::bs()->resolve_oop(obj), "needs to be in to-space"); #ifdef ASSERT if (_heap->heap_region_containing(obj)->is_in_collection_set()) { tty->print_cr("trying to mark obj: %p (%d) in dirty region: ", (HeapWord*) obj, _heap->isMarkedCurrent(obj)); // _heap->heap_region_containing(obj)->print(); // _heap->print_heap_regions(); } #endif assert(! _heap->heap_region_containing(obj)->is_in_collection_set(), "we don't want to mark objects in from-space"); assert(_heap->is_in(obj), "referenced objects must be in the heap. No?"); if (_heap->mark_current(obj)) { #ifdef ASSERT if (ShenandoahTraceConcurrentMarking) { tty->print_cr("marked obj: %p", (HeapWord*) obj); } #endif // Calculate liveness of heap region containing object. uint region_idx = _heap->heap_region_index_containing(obj); _live_data[region_idx] += (obj->size() + BrooksPointer::BROOKS_POINTER_OBJ_SIZE) * HeapWordSize; scm->add_task(obj, _worker_id); } #ifdef ASSERT else { if (ShenandoahTraceConcurrentMarking) { tty->print_cr("failed to mark obj (already marked): %p", (HeapWord*) obj); } assert(_heap->isMarkedCurrent(obj), "make sure object is marked"); } #endif /* else { tty->print_cr("already marked object %p, %d", obj, getMark(obj)->age()); } */ } /* else { if (obj != NULL) { tty->print_cr("not marking root object because it's not in heap: %p", obj); } } */ } }; // Walks over all the objects in the generation updating any // references to from space. class ShenandoahMarkRefsClosure : public ExtendedOopClosure { uint _worker_id; ShenandoahHeap* _heap; ShenandoahMarkObjsClosure _mark_objs; public: ShenandoahMarkRefsClosure(uint worker_id) : ExtendedOopClosure(((ShenandoahHeap *) Universe::heap())->ref_processor_cm()), _worker_id(worker_id), _heap((ShenandoahHeap*) Universe::heap()), _mark_objs(ShenandoahMarkObjsClosure(worker_id)) { } void do_oop(narrowOop* p) { Unimplemented(); } void do_oop(oop* p) { do_oop_work(p); } private: void do_oop_work(oop* p) { // We piggy-back reference updating to the marking tasks. oop* old = p; oop obj = _heap->maybe_update_oop_ref(p); #ifdef ASSERT if (ShenandoahTraceUpdates) { if (p != old) tty->print("Update %p => %p to %p => %p\n", p, (HeapWord*) *p, old, (HeapWord*) *old); } #endif // NOTE: We used to assert the following here. This does not always work because // a concurrent Java thread could change the the field after we updated it. // oop obj = oopDesc::load_heap_oop(p); // assert(oopDesc::bs()->resolve_oop(obj) == *p, "we just updated the referrer"); // assert(obj == NULL || ! _heap->heap_region_containing(obj)->is_dirty(), "must not point to dirty region"); // ShenandoahExtendedMarkObjsClosure cl(_heap->ref_processor_cm(), _worker_id); // ShenandoahMarkObjsClosure mocl(cl, _worker_id); if (obj != NULL) { _mark_objs.do_object(obj); } } }; class ShenandoahMarkRefsNoUpdateClosure : public ExtendedOopClosure { uint _worker_id; ShenandoahHeap* _heap; ShenandoahMarkObjsClosure _mark_objs; public: ShenandoahMarkRefsNoUpdateClosure(uint worker_id) : ExtendedOopClosure(((ShenandoahHeap *) Universe::heap())->ref_processor_cm()), _worker_id(worker_id), _heap(ShenandoahHeap::heap()), _mark_objs(ShenandoahMarkObjsClosure(worker_id)) { } void do_oop(narrowOop* p) { Unimplemented(); } void do_oop(oop* p) { do_oop_work(p); } private: void do_oop_work(oop* p) { oop obj = *p; if (! oopDesc::is_null(obj)) { #ifdef ASSERT ResourceMark rm; #endif assert(obj == oopDesc::bs()->resolve_oop(obj), err_msg("only mark forwarded copy of objects, obj: "PTR_FORMAT", obj_prime: "PTR_FORMAT", obj-klass: %s", (HeapWord*) obj, (HeapWord*) oopDesc::bs()->resolve_oop(obj), obj->klass()->internal_name())); if (ShenandoahTraceConcurrentMarking) { tty->print("Calling ShenandoahMarkRefsNoUpdateClosure on %p\n", (HeapWord*)obj); ShenandoahHeap::heap()->print_heap_locations((HeapWord*) obj, (HeapWord*) obj + obj->size()); } _mark_objs.do_object(obj); } } }; class ShenandoahMarkRootsTask : public AbstractGangTask { private: bool _update_refs; public: ShenandoahMarkRootsTask(bool update_refs) : AbstractGangTask("Shenandoah update roots task"), _update_refs(update_refs) { } void work(uint worker_id) { // tty->print_cr("start mark roots worker: %d", worker_id); ExtendedOopClosure* cl; ShenandoahMarkRefsClosure rootsCl1(worker_id); ShenandoahMarkRefsNoUpdateClosure rootsCl2(worker_id); if (_update_refs) { cl = &rootsCl1; } else { cl = &rootsCl2; } CodeBlobToOopClosure blobsCl(cl, true); CLDToOopClosure cldCl(cl); ShenandoahHeap* heap = ShenandoahHeap::heap(); ResourceMark m; heap->process_all_roots(false, SharedHeap::SO_AllCodeCache, cl, &cldCl, &blobsCl); // tty->print_cr("finish mark roots worker: %d", 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) { ShenandoahMarkRefsClosure cl1(worker_id); ShenandoahMarkRefsNoUpdateClosure cl2(worker_id); ExtendedOopClosure* cl; if (_update_refs) { cl = &cl1; } else { cl = &cl2; } while (true) { if (!_cm->try_queue(worker_id,cl) && !_cm->try_overflow_queue(worker_id, cl) && !_cm->try_to_steal(worker_id, cl, &_seed) && !_cm->try_draining_an_satb_buffer(worker_id)) { if (_terminator->offer_termination()) break; } } } }; void ShenandoahConcurrentMark::prepare_unmarked_root_objs() { if (! ShenandoahUpdateRefsEarly) { COMPILER2_PRESENT(DerivedPointerTable::clear()); } prepare_unmarked_root_objs_no_derived_ptrs(! ShenandoahUpdateRefsEarly); if (! ShenandoahUpdateRefsEarly) { 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) { heap->workers()->set_active_workers(_max_worker_id); heap->set_par_threads(heap->workers()->active_workers()); // Prepare for parallel processing. ClassLoaderDataGraph::clear_claimed_marks(); SharedHeap::StrongRootsScope strong_roots_scope(heap, true); ShenandoahMarkRootsTask mark_roots(update_refs); heap->workers()->run_task(&mark_roots); heap->set_par_threads(0); // Prepare for serial processing in future calls to process_strong_roots. ReferenceProcessor* rp = heap->ref_processor_cm(); ShenandoahMarkRefsNoUpdateClosure rootsCl2(0); rp->weak_oops_do(&rootsCl2); } else { ExtendedOopClosure* cl; ShenandoahMarkRefsClosure rootsCl1(0); ShenandoahMarkRefsNoUpdateClosure rootsCl2(0); if (update_refs) { cl = &rootsCl1; } else { cl = &rootsCl2; } heap->roots_iterate(cl); } // tty->print_cr("all root marker threads done"); } bool ShenandoahConcurrentMark::try_queue(uint worker_id, ExtendedOopClosure* cl) { oop obj; if (task_queues()->queue(worker_id % _max_worker_id)->pop_local(obj)) { traverse_object(cl, obj); return true; } else return false;; } bool ShenandoahConcurrentMark::try_to_steal(uint worker_id, ExtendedOopClosure* cl, int *seed) { oop obj; if (task_queues()->steal(worker_id, seed, obj)) { traverse_object(cl, obj); return true; } else return false; } bool ShenandoahConcurrentMark::try_overflow_queue(uint worker_id, ExtendedOopClosure* cl) { oop obj = overflow_queue()->pop(); if (obj != NULL) { traverse_object(cl, obj); return true; } else return false; } bool ShenandoahConcurrentMark:: try_draining_an_satb_buffer(uint worker_id) { return drain_one_satb_buffer(worker_id); } void ShenandoahConcurrentMark::traverse_object(ExtendedOopClosure* cl, oop obj) { ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); assert(sh->is_in(obj), "Should only traverse objects in the heap"); if (obj != NULL) { assert(obj->is_oop(), "Oops, not an oop"); assert(! sh->heap_region_containing(obj)->is_in_collection_set(), "we don't want to mark objects in from-space"); obj->oop_iterate(cl); } } void ShenandoahConcurrentMark::initialize() { _max_worker_id = MAX2((uint) ParallelGCThreads, 1U); _max_conc_worker_id = MAX2((uint) ConcGCThreads, 1U); _task_queues = new SCMObjToScanQueueSet((int) _max_worker_id); _overflow_queue = new SharedOverflowMarkQueue(); for (uint i = 0; i < _max_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(bool update_refs, bool full_gc) { if (ShenandoahGCVerbose) { tty->print_cr("STOPPING THE WORLD: before marking"); tty->print_cr("Starting markFromRoots"); } ShenandoahHeap* sh = (ShenandoahHeap *) Universe::heap(); sh->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::conc_mark); uint max_workers = full_gc ? _max_worker_id : _max_conc_worker_id; ParallelTaskTerminator terminator(max_workers, _task_queues); ReferenceProcessor* rp = sh->ref_processor_cm(); // enable ("weak") refs discovery rp->enable_discovery(true /*verify_disabled*/, 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->workers()->set_active_workers(max_workers); sh->workers()->run_task(&markingTask); sh->workers()->set_active_workers(_max_worker_id); if (ShenandoahGCVerbose) { tty->print_cr("Finishing markFromRoots"); tty->print_cr("RESUMING THE WORLD: after marking"); TASKQUEUE_STATS_ONLY(print_taskqueue_stats()); TASKQUEUE_STATS_ONLY(reset_taskqueue_stats()); } 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); } }; void ShenandoahConcurrentMark::finish_mark_from_roots(bool full_gc) { if (ShenandoahGCVerbose) { tty->print_cr("Starting finishMarkFromRoots"); } ShenandoahHeap* sh = (ShenandoahHeap *) Universe::heap(); // Trace any (new) unmarked root references. if (! full_gc) { prepare_unmarked_root_objs(); } { ParallelTaskTerminator terminator(_max_worker_id, _task_queues); ShenandoahHeap::StrongRootsScope srs(sh); // drain_satb_buffers(0, true); FinishDrainSATBBuffersTask drain_satb_buffers(this, &terminator); sh->workers()->set_active_workers(_max_worker_id); sh->workers()->run_task(&drain_satb_buffers); } // Also drain our overflow queue. ShenandoahMarkRefsClosure cl1(0); ShenandoahMarkRefsNoUpdateClosure cl2(0); ExtendedOopClosure* cl; if (! ShenandoahUpdateRefsEarly) { cl = &cl1; } else { cl = &cl2; } oop obj = _overflow_queue->pop(); while (obj != NULL) { assert(obj->is_oop(), "Oops, not an oop"); obj->oop_iterate(cl); obj = _overflow_queue->pop(); } // Finally mark everything else we've got in our queues during the previous steps. { ParallelTaskTerminator terminator(_max_worker_id, _task_queues); SCMConcurrentMarkingTask markingTask = SCMConcurrentMarkingTask(this, &terminator, !ShenandoahUpdateRefsEarly); sh->workers()->set_active_workers(_max_worker_id); sh->workers()->run_task(&markingTask); } #ifdef ASSERT for (int i = 0; i < sh->max_workers(); i++) { assert(_task_queues->queue(i)->is_empty(), "Should be empty"); } #endif // When we're done marking everything, we process weak references. weak_refs_work(); #ifdef ASSERT for (int i = 0; i < sh->max_workers(); 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_worker_id; i++) { tty->print("Queue: %d:", i); _task_queues->queue(i)->stats.print(tty, 10); tty->print("\n"); // _task_queues->queue(i)->stats.verify(); } #endif } #ifdef ASSERT if (ShenandoahDumpHeapAfterConcurrentMark) { sh->ensure_parsability(false); sh->print_all_refs("post-mark"); } #endif } class ShenandoahSATBMarkObjsClosure : public ObjectClosure { uint _worker_id; ShenandoahMarkObjsClosure _wrapped; public: ShenandoahSATBMarkObjsClosure(uint worker_id) : _worker_id(worker_id), _wrapped(ShenandoahMarkObjsClosure(worker_id)) { } void do_object(oop obj) { obj = ShenandoahBarrierSet::resolve_oop_static(obj); _wrapped.do_object(obj); } }; void ShenandoahConcurrentMark::drain_satb_buffers(uint worker_id, bool remark) { // tty->print_cr("start draining SATB buffers"); ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); ShenandoahSATBMarkObjsClosure cl(worker_id); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.set_par_closure(worker_id, &cl); while (satb_mq_set.par_apply_closure_to_completed_buffer(worker_id)); if (remark) { satb_mq_set.par_iterate_closure_all_threads(worker_id); assert(satb_mq_set.completed_buffers_num() == 0, "invariant"); } satb_mq_set.set_par_closure(worker_id, NULL); // tty->print_cr("end draining SATB buffers"); } bool ShenandoahConcurrentMark::drain_one_satb_buffer(uint worker_id) { ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); ShenandoahSATBMarkObjsClosure cl(worker_id); SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); satb_mq_set.set_par_closure(worker_id, &cl); bool result = satb_mq_set.par_apply_closure_to_completed_buffer(worker_id); satb_mq_set.set_par_closure(worker_id, NULL); return result; } void ShenandoahConcurrentMark::add_task(oop obj, int q) { q = q % _max_worker_id; assert(obj->is_oop(), "Oops, not an oop"); assert(! ShenandoahHeap::heap()->heap_region_containing(obj)->is_in_collection_set(), "we don't want to mark objects in from-space"); assert(ShenandoahHeap::heap()->is_in((HeapWord*) obj), "Only push heap objects on the queue"); #ifdef ASSERT if (ShenandoahTraceConcurrentMarking){ tty->print_cr("Adding object %p to marking queue %d", (HeapWord*) obj, q); } #endif if (!_task_queues->queue(q)->push(obj)) { // tty->print_cr("WARNING: Shenandoah mark queues overflown overflow_queue: obj = %p", (HeapWord*) obj); _overflow_queue->push(obj); } } SharedOverflowMarkQueue* ShenandoahConcurrentMark::overflow_queue() { return _overflow_queue; } #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->workers() != NULL ? sh->workers()->total_workers() : 1; for (int i = 0; i < n; ++i) { st->print("%3d ", i); _task_queues->queue(i)->stats.print(st); st->cr(); totals += _task_queues->queue(i)->stats; } st->print_raw("tot "); totals.print(st); st->cr(); DEBUG_ONLY(totals.verify()); } void ShenandoahConcurrentMark::reset_taskqueue_stats() { ShenandoahHeap* sh = (ShenandoahHeap*) Universe::heap(); const int n = sh->workers() != NULL ? sh->workers()->total_workers() : 1; 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; public: ShenandoahCMDrainMarkingStackClosure(uint worker_id): _worker_id(worker_id) { _sh = (ShenandoahHeap*) Universe::heap(); _scm = _sh->concurrentMark(); } void do_void() { ShenandoahMarkRefsClosure cl1(_worker_id); ShenandoahMarkRefsNoUpdateClosure cl2(_worker_id); ExtendedOopClosure* cl; if (! ShenandoahUpdateRefsEarly) { cl = &cl1; } else { cl = &cl2; } while (true) { if (!_scm->try_queue(_worker_id, cl) && !_scm->try_overflow_queue(_worker_id, cl) && !_scm->try_draining_an_satb_buffer(_worker_id)) { break; } } } }; class ShenandoahCMKeepAliveAndDrainClosure: public OopClosure { uint _worker_id; ShenandoahHeap* _sh; ShenandoahConcurrentMark* _scm; size_t _ref_count; public: ShenandoahCMKeepAliveAndDrainClosure(uint worker_id) { _worker_id = worker_id; _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 (! ShenandoahUpdateRefsEarly) { obj = _sh->maybe_update_oop_ref(p); } else { obj = oopDesc::load_heap_oop(p); } assert(obj == oopDesc::bs()->resolve_oop(obj), "only get updated oops in weak ref processing"); if (obj != NULL) { if (Verbose && ShenandoahTraceWeakReferences) { gclog_or_tty->print_cr("\t[%u] we're looking at location " "*"PTR_FORMAT" = "PTR_FORMAT, _worker_id, p2i(p), p2i((void*) obj)); obj->print(); } _sh->mark_current(obj); _scm->add_task(obj, _worker_id); _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) { ShenandoahIsAliveClosure is_alive; ShenandoahCMKeepAliveAndDrainClosure keep_alive(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()->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_cm(); // 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(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); // no timing for now. ConcurrentGCTimer gc_timer; if (ShenandoahTraceWeakReferences) { gclog_or_tty->print_cr("start processing references"); } rp->process_discovered_references(&is_alive, &keep_alive, &complete_gc, &par_task_executor, &gc_timer, 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"); // Now clean up stale oops in StringTable StringTable::unlink(&is_alive); // Clean up unreferenced symbols in symbol table. SymbolTable::unlink(); }