# HG changeset patch # User zgu # Date 1553616769 14400 # Tue Mar 26 12:12:49 2019 -0400 # Node ID ac40561279dc3aef9d1a88ae2448f7299e441307 # Parent e98f7c348290fdb9f92325f0e16ea2e1cefbf512 [backport] 8221435: Shenandoah should not mark through weak roots Reviewed-by: rkennke, shade diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.cpp Tue Mar 26 12:12:49 2019 -0400 @@ -37,6 +37,7 @@ #include "gc_implementation/shenandoah/shenandoahRootProcessor.hpp" #include "gc_implementation/shenandoah/shenandoahTaskqueue.inline.hpp" #include "gc_implementation/shenandoah/shenandoahTimingTracker.hpp" +#include "gc_implementation/shenandoah/shenandoahWeakProcessor.hpp" #include "gc_implementation/shenandoah/shenandoahWorkGroup.hpp" #include "gc_implementation/shenandoah/shenandoahUtils.hpp" #include "gc_implementation/shenandoah/shenandoah_specialized_oop_closures.hpp" @@ -129,11 +130,10 @@ CLDToOopClosure clds_cl(oops); MarkingCodeBlobClosure blobs_cl(oops, ! CodeBlobToOopClosure::FixRelocations); - OopClosure* weak_oops = _process_refs ? NULL : oops; ResourceMark m; if (heap->unload_classes()) { - _rp->process_strong_roots(oops, weak_oops, &clds_cl, NULL, &blobs_cl, NULL, worker_id); + _rp->process_strong_roots(oops, &clds_cl, NULL, &blobs_cl, NULL, worker_id); } else { if (ShenandoahConcurrentScanCodeRoots) { CodeBlobClosure* code_blobs = NULL; @@ -146,9 +146,9 @@ code_blobs = &assert_to_space; } #endif - _rp->process_all_roots(oops, weak_oops, &clds_cl, code_blobs, NULL, worker_id); + _rp->process_all_roots(oops, &clds_cl, code_blobs, NULL, worker_id); } else { - _rp->process_all_roots(oops, weak_oops, &clds_cl, &blobs_cl, NULL, worker_id); + _rp->process_all_roots(oops, &clds_cl, &blobs_cl, NULL, worker_id); } } } @@ -186,7 +186,7 @@ DEBUG_ONLY(&assert_to_space) NOT_DEBUG(NULL); } - _rp->process_all_roots(&cl, &cl, &cldCl, code_blobs, NULL, worker_id); + _rp->update_all_roots(&cl, &cldCl, code_blobs, NULL, worker_id); } }; @@ -467,11 +467,18 @@ weak_refs_work(full_gc); } + weak_roots_work(); + // And finally finish class unloading if (_heap->unload_classes()) { _heap->unload_classes_and_cleanup_tables(full_gc); } - + if (ShenandoahStringDedup::is_enabled()) { + ShenandoahGCPhase phase(full_gc ? + ShenandoahPhaseTimings::full_gc_purge_string_dedup : + ShenandoahPhaseTimings::purge_string_dedup); + ShenandoahStringDedup::parallel_cleanup(); + } assert(task_queues()->is_empty(), "Should be empty"); TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats()); TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); @@ -555,6 +562,43 @@ void do_oop(oop* p) { do_oop_nv(p); } }; +class ShenandoahWeakUpdateClosure : public OopClosure { +private: + ShenandoahHeap* const _heap; + + template + inline void do_oop_work(T* p) { + oop o = _heap->maybe_update_with_forwarded(p); + shenandoah_assert_marked_except(p, o, o == NULL); + } + +public: + ShenandoahWeakUpdateClosure() : _heap(ShenandoahHeap::heap()) {} + + void do_oop(narrowOop* p) { do_oop_work(p); } + void do_oop(oop* p) { do_oop_work(p); } +}; + +class ShenandoahWeakAssertNotForwardedClosure : public OopClosure { +private: + template + inline void do_oop_work(T* p) { +#ifdef ASSERT + T o = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(o)) { + oop obj = oopDesc::decode_heap_oop_not_null(o); + shenandoah_assert_not_forwarded(p, obj); + } +#endif + } + +public: + ShenandoahWeakAssertNotForwardedClosure() {} + + void do_oop(narrowOop* p) { do_oop_work(p); } + void do_oop(oop* p) { do_oop_work(p); } +}; + class ShenandoahRefProcTaskProxy : public AbstractGangTask { private: AbstractRefProcTaskExecutor::ProcessTask& _proc_task; @@ -653,6 +697,22 @@ } +// Process leftover weak oops: update them, if needed or assert they do not +// need updating otherwise. +// Weak processor API requires us to visit the oops, even if we are not doing +// anything to them. +void ShenandoahConcurrentMark::weak_roots_work() { + ShenandoahIsAliveSelector is_alive; + + if (_heap->has_forwarded_objects()) { + ShenandoahWeakUpdateClosure cl; + ShenandoahWeakProcessor::weak_oops_do(is_alive.is_alive_closure(), &cl); + } else { + ShenandoahWeakAssertNotForwardedClosure cl; + ShenandoahWeakProcessor::weak_oops_do(is_alive.is_alive_closure(), &cl); + } +} + void ShenandoahConcurrentMark::weak_refs_work_doit(bool full_gc) { ReferenceProcessor* rp = _heap->ref_processor(); diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.hpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.hpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahConcurrentMark.hpp Tue Mar 26 12:12:49 2019 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved. * * 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 @@ -85,6 +85,8 @@ void weak_refs_work(bool full_gc); void weak_refs_work_doit(bool full_gc); + void weak_roots_work(); + public: void preclean_weak_refs(); diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.cpp Tue Mar 26 12:12:49 2019 -0400 @@ -999,16 +999,6 @@ COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } -void ShenandoahHeap::roots_iterate(OopClosure* cl) { - assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Only iterate roots while world is stopped"); - - CodeBlobToOopClosure blobsCl(cl, false); - CLDToOopClosure cldCl(cl); - - ShenandoahRootProcessor rp(this, 1, ShenandoahPhaseTimings::_num_phases); - rp.process_all_roots(cl, NULL, &cldCl, &blobsCl, NULL, 0); -} - size_t ShenandoahHeap::unsafe_max_tlab_alloc(Thread *thread) const { // Returns size in bytes return MIN2(_free_set->unsafe_peek_free(), ShenandoahHeapRegion::max_tlab_size_bytes()); @@ -1226,7 +1216,7 @@ ObjectIterateScanRootClosure oops(&_aux_bit_map, &oop_stack); CLDToOopClosure clds(&oops, false); CodeBlobToOopClosure blobs(&oops, false); - rp.process_all_roots(&oops, &oops, &clds, &blobs, NULL, 0); + rp.process_all_roots(&oops, &clds, &blobs, NULL, 0); // Work through the oop stack to traverse heap. while (! oop_stack.is_empty()) { @@ -1858,13 +1848,6 @@ _workers->run_task(&unlink_task); } - if (ShenandoahStringDedup::is_enabled()) { - ShenandoahGCPhase phase(full_gc ? - ShenandoahPhaseTimings::full_gc_purge_string_dedup : - ShenandoahPhaseTimings::purge_string_dedup); - ShenandoahStringDedup::parallel_cleanup(); - } - { ShenandoahGCPhase phase(full_gc ? ShenandoahPhaseTimings::full_gc_purge_cldg : diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahHeap.hpp Tue Mar 26 12:12:49 2019 -0400 @@ -658,8 +658,6 @@ void stop_concurrent_marking(); - void roots_iterate(OopClosure* cl); - private: void trash_cset_regions(); void update_heap_references(bool concurrent); diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahMarkCompact.cpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahMarkCompact.cpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahMarkCompact.cpp Tue Mar 26 12:12:49 2019 -0400 @@ -574,9 +574,9 @@ MarkingCodeBlobClosure adjust_code_closure(&cl, CodeBlobToOopClosure::FixRelocations); - _rp->process_all_roots(&cl, &cl, - &adjust_cld_closure, - &adjust_code_closure, NULL, worker_id); + _rp->update_all_roots(&cl, + &adjust_cld_closure, + &adjust_code_closure, NULL, worker_id); } }; diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.cpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.cpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.cpp Tue Mar 26 12:12:49 2019 -0400 @@ -35,6 +35,7 @@ #include "gc_implementation/shenandoah/shenandoahPhaseTimings.hpp" #include "gc_implementation/shenandoah/shenandoahStringDedup.hpp" #include "gc_implementation/shenandoah/shenandoahTimingTracker.hpp" +#include "gc_implementation/shenandoah/shenandoahWeakProcessor.hpp" #include "memory/allocation.inline.hpp" #include "runtime/fprofiler.hpp" #include "memory/resourceArea.hpp" @@ -76,15 +77,10 @@ Management::oops_do(oops); JvmtiExport::oops_do(oops); JNIHandles::oops_do(oops); - JNIHandles::weak_oops_do(&always_true, oops); ObjectSynchronizer::oops_do(oops); SystemDictionary::roots_oops_do(oops, oops); StringTable::oops_do(oops); - if (ShenandoahStringDedup::is_enabled()) { - ShenandoahStringDedup::oops_do_slow(oops); - } - // Do thread roots the last. This allows verification code to find // any broken objects from those special roots first, not the accidental // dangling reference from the thread root. @@ -92,21 +88,25 @@ } void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops, - OopClosure* weak_oops, CLDClosure* clds, CLDClosure* weak_clds, CodeBlobClosure* blobs, ThreadClosure* thread_cl, uint worker_id) { assert(thread_cl == NULL, "not implemented yet"); + ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); process_java_roots(oops, clds, clds, weak_clds, blobs, worker_id); - process_vm_roots(oops, NULL, weak_oops, worker_id); + process_vm_roots(oops, worker_id); + + if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id); + SystemDictionary::roots_oops_do(oops, NULL); + } _process_strong_tasks->all_tasks_completed(); } void ShenandoahRootProcessor::process_all_roots(OopClosure* oops, - OopClosure* weak_oops, CLDClosure* clds, CodeBlobClosure* blobs, ThreadClosure* thread_cl, @@ -115,14 +115,47 @@ assert(thread_cl == NULL, "not implemented yet"); ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); process_java_roots(oops, NULL, clds, clds, NULL, worker_id); - process_vm_roots(oops, oops, weak_oops, worker_id); + process_vm_roots(oops, worker_id); if (blobs != NULL) { ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); _coderoots_all_iterator.possibly_parallel_blobs_do(blobs); } + // All threads execute the following. A specific chunk of buckets + // from the StringTable are the individual tasks. + { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::StringTableRoots, worker_id); + StringTable::possibly_parallel_oops_do(oops); + } + + if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id); + SystemDictionary::roots_oops_do(oops, oops); + } + _process_strong_tasks->all_tasks_completed(); + +} + +void ShenandoahRootProcessor::update_all_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs, + ThreadClosure* thread_cl, + uint worker_id) { + ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times(); + ShenandoahAlwaysTrueClosure always_true; + + if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_JNIHandles_weak_oops_do)) { + ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIWeakRoots, worker_id); + ShenandoahWeakProcessor::weak_oops_do(&always_true, oops); + } + + process_all_roots(oops, clds, blobs, thread_cl, worker_id); + + if (ShenandoahStringDedup::is_enabled()) { + ShenandoahStringDedup::parallel_oops_do(oops); + } } void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots, @@ -149,10 +182,7 @@ } void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots, - OopClosure* weak_roots, - OopClosure* jni_weak_roots, - uint worker_id) -{ + uint worker_id) { ShenandoahHeap* heap = ShenandoahHeap::heap(); ShenandoahWorkerTimings* worker_times = heap->phase_timings()->worker_times(); @@ -178,33 +208,19 @@ ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JVMTIRoots, worker_id); JvmtiExport::oops_do(strong_roots); } - if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_SystemDictionary_oops_do)) { - ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id); - SystemDictionary::roots_oops_do(strong_roots, weak_roots); - } // Note: Workaround bugs with JNI weak reference handling during concurrent cycles, - // by pessimistically assuming all JNI weak refs are alive. Achieve this by passing - // stronger closure, where weaker one would suffice otherwise. This effectively makes + // by pessimistically assuming all JNI weak refs are alive. This effectively makes // JNI weak refs non-reclaimable by concurrent GC, but they would be reclaimed by // STW GCs, that are not affected by the bug, nevertheless. if (!heap->is_full_gc_in_progress() && !heap->is_degenerated_gc_in_progress()) { - jni_weak_roots = strong_roots; - } - - if (jni_weak_roots != NULL) { if (!_process_strong_tasks->is_task_claimed(SHENANDOAH_RP_PS_JNIHandles_weak_oops_do)) { ShenandoahAlwaysTrueClosure always_true; ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::JNIWeakRoots, worker_id); - JNIHandles::weak_oops_do(&always_true, jni_weak_roots); + JNIHandles::weak_oops_do(&always_true, strong_roots); } } - if (ShenandoahStringDedup::is_enabled() && weak_roots != NULL) { - ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::StringDedupRoots, worker_id); - ShenandoahStringDedup::parallel_oops_do(weak_roots); - } - { ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id); if (ShenandoahFastSyncRoots && MonitorInUseLists) { @@ -213,12 +229,6 @@ while(_om_iterator.parallel_oops_do(strong_roots)); } } - // All threads execute the following. A specific chunk of buckets - // from the StringTable are the individual tasks. - if (weak_roots != NULL) { - ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::StringTableRoots, worker_id); - StringTable::possibly_parallel_oops_do(weak_roots); - } } ShenandoahRootEvacuator::ShenandoahRootEvacuator(ShenandoahHeap* heap, uint n_workers, ShenandoahPhaseTimings::Phase phase) : diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.hpp --- a/src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.hpp Fri May 10 01:41:45 2019 +0800 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahRootProcessor.hpp Tue Mar 26 12:12:49 2019 -0400 @@ -66,8 +66,6 @@ uint worker_i); void process_vm_roots(OopClosure* scan_non_heap_roots, - OopClosure* scan_non_heap_weak_roots, - OopClosure* weak_jni_roots, uint worker_i); public: @@ -75,21 +73,40 @@ ShenandoahPhaseTimings::Phase phase); ~ShenandoahRootProcessor(); - // Apply oops, clds and blobs to all strongly reachable roots in the system - void process_strong_roots(OopClosure* oops, OopClosure* weak_oops, + // Apply oops, clds and blobs to all strongly reachable roots in the system. + // Optionally, apply class loader closure to weak clds, depending on class unloading + // for the particular GC cycles. + void process_strong_roots(OopClosure* oops, CLDClosure* clds, CLDClosure* weak_clds, CodeBlobClosure* blobs, ThreadClosure* thread_cl, uint worker_id); - // Apply oops, clds and blobs to strongly and weakly reachable roots in the system - void process_all_roots(OopClosure* oops, OopClosure* weak_oops, + // Apply oops, clds and blobs to strongly reachable roots in the system + void process_all_roots(OopClosure* oops, CLDClosure* clds, CodeBlobClosure* blobs, ThreadClosure* thread_cl, uint worker_id); + // Apply oops, clds and blobs to strongly and weakly reachable roots in the system + void update_all_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs, + ThreadClosure* thread_cl, + uint worker_id); + + + // Apply oops, clds and blobs to strongly and weakly reachable roots in the system + // during traversal GC. + // It cleans up and updates weak roots in one iteration. + void traversal_update_all_roots(OopClosure* oops, + CLDClosure* clds, + CodeBlobClosure* blobs, + ThreadClosure* thread_cl, + uint worker_id); + // For slow debug/verification code void process_all_roots_slow(OopClosure* oops); diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahWeakProcessor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahWeakProcessor.cpp Tue Mar 26 12:12:49 2019 -0400 @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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 "precompiled.hpp" +#include "gc_implementation/shenandoah/shenandoahHeap.hpp" +#include "gc_implementation/shenandoah/shenandoahWeakProcessor.hpp" +#include "prims/jvmtiExport.hpp" +#include "runtime/jniHandles.hpp" +#include "utilities/macros.hpp" + +void ShenandoahWeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) { + JNIHandles::weak_oops_do(is_alive, keep_alive); + JvmtiExport::weak_oops_do(is_alive, keep_alive); +} + +void ShenandoahWeakProcessor::oops_do(OopClosure* closure) { + ShenandoahAlwaysTrueClosure always_true; + weak_oops_do(&always_true, closure); +} diff -r e98f7c348290 -r ac40561279dc src/share/vm/gc_implementation/shenandoah/shenandoahWeakProcessor.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/shenandoah/shenandoahWeakProcessor.hpp Tue Mar 26 12:12:49 2019 -0400 @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019, Red Hat, Inc. All rights reserved. + * + * 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. + * + */ + +#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHWEAKPROCESSOR_HPP +#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHWEAKPROCESSOR_HPP + +#include "memory/allocation.hpp" +#include "memory/iterator.hpp" + +// Helper class to aid in root scanning and cleaning of weak oops in the VM. +// This is a compatibility layer/drop-in-replacement of JDK11's WeakProcessor +// API. +class ShenandoahWeakProcessor : AllStatic { +public: + // Visit all oop*s and apply the keep_alive closure if the referenced + // object is considered alive by the is_alive closure, otherwise do some + // container specific cleanup of element holding the oop. + static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive); + + // Visit all oop*s and apply the given closure. + static void oops_do(OopClosure* closure); +}; + +#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHWEAKPROCESSOR_HPP