# HG changeset patch # Parent 63a5ca6b66a84bd5cd46e6b075573f0093c923cf Concurrent stringtable processing diff --git a/src/hotspot/share/gc/shared/parallelCleaning.cpp b/src/hotspot/share/gc/shared/parallelCleaning.cpp --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp @@ -247,12 +247,14 @@ } ParallelCleaningTask::ParallelCleaningTask(BoolObjectClosure* is_alive, - StringDedupUnlinkOrOopsDoClosure* dedup_closure, uint num_workers, bool unloading_occurred) : + StringDedupUnlinkOrOopsDoClosure* dedup_closure, uint num_workers, bool unloading_occurred, + bool clean_stringtable) : AbstractGangTask("Parallel Cleaning"), _unloading_occurred(unloading_occurred), _string_task(is_alive, StringDedup::is_enabled() ? dedup_closure : NULL, true), _code_cache_task(num_workers, is_alive, unloading_occurred), - _klass_cleaning_task() { + _klass_cleaning_task(), + _clean_stringtable(clean_stringtable) { } // The parallel work done by all worker threads. @@ -264,7 +266,9 @@ _code_cache_task.barrier_mark(worker_id); // Clean the Strings and Symbols. - _string_task.work(worker_id); + if (_clean_stringtable) { + _string_task.work(worker_id); + } // Wait for all workers to finish the first code cache cleaning pass. _code_cache_task.barrier_wait(worker_id); diff --git a/src/hotspot/share/gc/shared/parallelCleaning.hpp b/src/hotspot/share/gc/shared/parallelCleaning.hpp --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp @@ -126,11 +126,11 @@ StringCleaningTask _string_task; CodeCacheUnloadingTask _code_cache_task; KlassCleaningTask _klass_cleaning_task; - + bool _clean_stringtable; public: // The constructor is run in the VMThread. ParallelCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure, - uint num_workers, bool unloading_occurred); + uint num_workers, bool unloading_occurred, bool clean_stringtable = true); void work(uint worker_id); }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -265,11 +265,10 @@ // Needed for loads on non-heap weak references template - static oop oop_load_not_in_heap(T* addr) { - oop value = Raw::oop_load_not_in_heap(addr); - keep_alive_if_weak(decorators, value); - return value; - } + static oop oop_load_not_in_heap(T* addr); + + template + static void oop_store_not_in_heap(T* addr, oop value); static oop resolve(oop obj) { return ShenandoahBarrierSet::barrier_set()->write_barrier(obj); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -28,6 +28,7 @@ #include "gc/shenandoah/brooksPointer.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" bool ShenandoahBarrierSet::need_update_refs_barrier() { return _heap->is_update_refs_in_progress() || @@ -276,4 +277,29 @@ return bs->arraycopy_loop_1(src_raw, dst_raw, length, bound, checkcast, satb, storeval_mode); } +template +template +oop ShenandoahBarrierSet::AccessBarrier::oop_load_not_in_heap(T* addr) { + oop value = Raw::oop_load_not_in_heap(addr); + // In order to support concurrent reference cleaning (and similar + // constructs like concurrent string table cleaning) return + // logical NULL here if phantom ref and real oop is unreachable. + ShenandoahHeap* heap = ShenandoahHeap::heap(); + if (heap->is_refcleaning_in_progress() && + (decorators & ON_PHANTOM_OOP_REF) != 0 && + value != NULL && + !heap->complete_marking_context()->is_marked(value)) { + return NULL; + } + keep_alive_if_weak(decorators, value); + return value; +} + +template +template +void ShenandoahBarrierSet::AccessBarrier::oop_store_not_in_heap(T* addr, oop value) { + value = ShenandoahBarrierSet::barrier_set()->storeval_barrier(value); + Raw::oop_store_not_in_heap(addr, value); +} + #endif //SHARE_VM_GC_SHENANDOAH_SHENANDOAHBARRIERSET_INLINE_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -30,6 +30,7 @@ #include "gc/shared/weakProcessor.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shared/gcTimer.hpp" +#include "gc/shared/parallelCleaning.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp new file mode 100644 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, 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/oopStorageParState.inline.hpp" +#include "gc/shared/workgroup.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahMarkingContext.hpp" +#include "memory/iterator.hpp" +#include "oops/access.hpp" +#include "oops/compressedOops.inline.hpp" + +class Thread; + +template +class ShenandoahUnlinkAndUpdateStringTableClosure : public OopClosure { +private: + ShenandoahHeap* const _heap; + ShenandoahMarkingContext* const _ctx; + Thread* const _thread; + + template + inline void do_oop_work(T* p) { + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (_ctx->is_marked(obj)) { + if (_heap->in_collection_set(obj)) { + oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); + if (EVAC && oopDesc::equals_raw(resolved, obj)) { + resolved = _heap->evacuate_object(obj, _thread); + } + RawAccess::oop_store(p, resolved); + } + } else { + RawAccess<>::oop_store(p, (oop) NULL); + } + } + } +public: + ShenandoahUnlinkAndUpdateStringTableClosure() : + _heap(ShenandoahHeap::heap()), + _ctx(ShenandoahHeap::heap()->complete_marking_context()), + _thread(Thread::current()) {} + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } +}; + +template +class ShenandoahUnlinkAndUpdateStringTableTask : public AbstractGangTask { +private: + OopStorage::ParState _string_table; + +public: + ShenandoahUnlinkAndUpdateStringTableTask() : + AbstractGangTask("Shenandoah Unlink/Update StringTable Task"), + _string_table(StringTable::weak_storage()) {} + + void work(uint worker_id) { + if (EVAC) { + ShenandoahEvacOOMScope oom_evac; + ShenandoahUnlinkAndUpdateStringTableClosure stcl; + _string_table.oops_do(&stcl); + } else { + } + } +}; + + +void ShenandoahConcurrentRoots::unlink_and_update(bool evac) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + if (evac) { + ShenandoahUnlinkAndUpdateStringTableTask task; + heap->workers()->run_task(&task); + } else { + ShenandoahUnlinkAndUpdateStringTableTask task; + heap->workers()->run_task(&task); + } +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp new file mode 100644 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentRoots.hpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, 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. + * + */ + +#ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTROOTS_HPP +#define SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTROOTS_HPP + +#include "memory/allocation.hpp" + +class ShenandoahConcurrentRoots : public AllStatic { +public: + static void unlink_and_update(bool evac); +}; + +#endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHCONCURRENTROOTS_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -24,9 +24,13 @@ #include "precompiled.hpp" #include "memory/allocation.hpp" +#include "classfile/stringTable.hpp" + #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/memAllocator.hpp" +#include "gc/shared/oopStorage.hpp" +#include "gc/shared/oopStorageParState.inline.hpp" #include "gc/shared/parallelCleaning.hpp" #include "gc/shared/plab.hpp" @@ -37,6 +41,7 @@ #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahControlThread.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" @@ -882,6 +887,7 @@ private: ShenandoahHeap* const _sh; ShenandoahCollectionSet* const _cs; + OopStorage::ParState _string_table; bool _concurrent; public: ShenandoahEvacuationTask(ShenandoahHeap* sh, @@ -890,6 +896,7 @@ AbstractGangTask("Parallel Evacuation Task"), _sh(sh), _cs(cs), + _string_table(StringTable::weak_storage()), _concurrent(concurrent) {} @@ -1443,6 +1450,7 @@ verifier()->verify_before_evacuation(); } + set_refcleaning_in_progress(true); set_evacuation_in_progress(true); // From here on, we need to update references. set_has_forwarded_objects(true); @@ -1453,6 +1461,7 @@ pacer()->setup_for_evac(); } } else { + ShenandoahConcurrentRoots::unlink_and_update(false); if (ShenandoahVerify) { verifier()->verify_after_concmark(); } @@ -1480,6 +1489,7 @@ assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should be at safepoint"); set_evacuation_in_progress(false); + set_refcleaning_in_progress(false); retire_and_reset_gclabs(); @@ -1493,11 +1503,13 @@ } void ShenandoahHeap::op_conc_evac() { + ShenandoahConcurrentRoots::unlink_and_update(true); ShenandoahEvacuationTask task(this, _collection_set, true); workers()->run_task(&task); } void ShenandoahHeap::op_stw_evac() { + ShenandoahConcurrentRoots::unlink_and_update(true); ShenandoahEvacuationTask task(this, _collection_set, false); workers()->run_task(&task); } @@ -1874,7 +1886,7 @@ ShenandoahPhaseTimings::purge_par); uint active = _workers->active_workers(); StringDedupUnlinkOrOopsDoClosure dedup_cl(is_alive, NULL); - ParallelCleaningTask unlink_task(is_alive, &dedup_cl, active, purged_class); + ParallelCleaningTask unlink_task(is_alive, &dedup_cl, active, purged_class, false); _workers->run_task(&unlink_task); } @@ -1897,6 +1909,10 @@ set_gc_state_mask(HAS_FORWARDED, cond); } +void ShenandoahHeap::set_refcleaning_in_progress(bool in_progress) { + set_gc_state_mask(REFCLEANING, in_progress); +} + void ShenandoahHeap::set_process_references(bool pr) { _process_references.set_cond(pr); } @@ -2064,6 +2080,7 @@ assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at safepoint"); set_evacuation_in_progress(false); + set_refcleaning_in_progress(false); retire_and_reset_gclabs(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -273,16 +273,19 @@ HAS_FORWARDED_BITPOS = 0, // Heap is under marking: needs SATB barriers. - MARKING_BITPOS = 1, + MARKING_BITPOS = 1, // Heap is under evacuation: needs WB barriers. (Set together with UNSTABLE) - EVACUATION_BITPOS = 2, + EVACUATION_BITPOS = 2, // Heap is under updating: needs SVRB/SVWB barriers. - UPDATEREFS_BITPOS = 3, + UPDATEREFS_BITPOS = 3, // Heap is under traversal collection - TRAVERSAL_BITPOS = 4, + TRAVERSAL_BITPOS = 4, + + // We're cleaning weakrefs and similar constructs. + REFCLEANING_BITPOS = 5, }; enum GCState { @@ -292,6 +295,7 @@ EVACUATION = 1 << EVACUATION_BITPOS, UPDATEREFS = 1 << UPDATEREFS_BITPOS, TRAVERSAL = 1 << TRAVERSAL_BITPOS, + REFCLEANING = 1 << REFCLEANING_BITPOS, }; private: @@ -316,6 +320,7 @@ void set_full_gc_move_in_progress(bool in_progress); void set_concurrent_traversal_in_progress(bool in_progress); void set_has_forwarded_objects(bool cond); + void set_refcleaning_in_progress(bool in_progress); inline bool is_stable() const; inline bool is_idle() const; @@ -326,6 +331,7 @@ inline bool is_full_gc_in_progress() const; inline bool is_full_gc_move_in_progress() const; inline bool is_concurrent_traversal_in_progress() const; + inline bool is_refcleaning_in_progress() const; inline bool has_forwarded_objects() const; inline bool is_gc_in_progress_mask(uint mask) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -71,6 +71,10 @@ return _gc_state.is_set(HAS_FORWARDED); } +inline bool ShenandoahHeap::is_refcleaning_in_progress() const { + return _gc_state.is_set(REFCLEANING); +} + inline WorkGang* ShenandoahHeap::workers() const { return _workers; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp @@ -27,6 +27,7 @@ #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shenandoah/brooksPointer.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" @@ -225,7 +226,7 @@ cm->update_roots(ShenandoahPhaseTimings::full_gc_roots); cm->mark_roots(ShenandoahPhaseTimings::full_gc_roots); cm->finish_mark_from_roots(/* full_gc = */ true); - + ShenandoahConcurrentRoots::unlink_and_update(false); heap->mark_complete_marking_context(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -45,7 +45,6 @@ ShenandoahPhaseTimings::Phase phase) : _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)), _srs(n_workers), - _par_state_string(StringTable::weak_storage()), _phase(phase), _coderoots_all_iterator(ShenandoahCodeRoots::iterator()) { @@ -65,7 +64,7 @@ ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase); } -void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) { +void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops, bool do_stringtable) { CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong); CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); @@ -78,8 +77,9 @@ WeakProcessor::oops_do(oops); ObjectSynchronizer::oops_do(oops); SystemDictionary::oops_do(oops); - StringTable::oops_do(oops); - + if (do_stringtable) { + StringTable::oops_do(oops); + } if (ShenandoahStringDedup::is_enabled()) { ShenandoahStringDedup::oops_do_slow(oops); } @@ -209,13 +209,6 @@ ObjectSynchronizer::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(&_par_state_string, weak_roots); - } } uint ShenandoahRootProcessor::n_workers() const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -55,7 +55,6 @@ class ShenandoahRootProcessor : public StackObj { SubTasksDone* _process_strong_tasks; StrongRootsScope _srs; - OopStorage::ParState _par_state_string; ShenandoahPhaseTimings::Phase _phase; ParallelCLDRootIterator _cld_iterator; ShenandoahAllCodeRootsIterator _coderoots_all_iterator; @@ -94,7 +93,7 @@ uint worker_id); // For slow debug/verification code - void process_all_roots_slow(OopClosure* oops); + void process_all_roots_slow(OopClosure* oops, bool do_stringtable); // Number of worker threads used by the root processor. uint n_workers() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp @@ -25,6 +25,7 @@ #include "classfile/classLoaderData.hpp" #include "classfile/classLoaderDataGraph.hpp" +#include "classfile/stringTable.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/workgroup.hpp" @@ -34,6 +35,7 @@ #include "gc/shenandoah/shenandoahCodeRoots.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" +#include "gc/shenandoah/shenandoahConcurrentRoots.hpp" #include "gc/shenandoah/shenandoahFreeSet.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" @@ -612,6 +614,7 @@ _heap->unload_classes_and_cleanup_tables(false); fixup_roots(); } + ShenandoahConcurrentRoots::unlink_and_update(false); if (!_heap->cancelled_gc()) { assert(_task_queues->is_empty(), "queues must be empty after traversal GC"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -461,7 +461,8 @@ ShenandoahVerifyOopClosure cl(&stack, _bitmap, _ld, ShenandoahMessageBuffer("%s, Roots", _label), _options); - _rp->process_all_roots_slow(&cl); + bool stringtable = _options._verify_stringtable == ShenandoahVerifier::_verify_stringtable_enable; + _rp->process_all_roots_slow(&cl, stringtable); } size_t processed = 0; @@ -611,7 +612,7 @@ VerifyForwarded forwarded, VerifyMarked marked, VerifyCollectionSet cset, VerifyLiveness liveness, VerifyRegions regions, - VerifyGCState gcstate) { + VerifyGCState gcstate, VerifyStringTable stringtable) { guarantee(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "only when nothing else happens"); guarantee(ShenandoahVerify, "only when enabled, and bitmap is initialized in ShenandoahHeap::initialize"); @@ -687,7 +688,7 @@ ShenandoahLivenessData* ld = NEW_C_HEAP_ARRAY(ShenandoahLivenessData, _heap->num_regions(), mtGC); Copy::fill_to_bytes((void*)ld, _heap->num_regions()*sizeof(ShenandoahLivenessData), 0); - const VerifyOptions& options = ShenandoahVerifier::VerifyOptions(forwarded, marked, cset, liveness, regions, gcstate); + const VerifyOptions& options = ShenandoahVerifier::VerifyOptions(forwarded, marked, cset, liveness, regions, gcstate, stringtable); // Steps 1-2. Scan root set to get initial reachable set. Finish walking the reachable heap. // This verifies what application can see, since it only cares about reachable objects. @@ -762,7 +763,8 @@ _verify_cset_disable, // cset may be inconsistent _verify_liveness_disable, // no reliable liveness data _verify_regions_disable, // no reliable region data - _verify_gcstate_disable // no data about gcstate + _verify_gcstate_disable, // no data about gcstate + _verify_stringtable_disable // don't know if stringtable valid ); } @@ -775,7 +777,8 @@ _verify_cset_forwarded, // allow forwarded references to cset _verify_liveness_disable, // no reliable liveness data _verify_regions_notrash, // no trash regions - _verify_gcstate_forwarded // there are forwarded objects + _verify_gcstate_forwarded, // there are forwarded objects + _verify_stringtable_enable // check stringtable ); } else { verify_at_safepoint( @@ -785,7 +788,8 @@ _verify_cset_none, // UR should have fixed this _verify_liveness_disable, // no reliable liveness data _verify_regions_notrash, // no trash regions - _verify_gcstate_stable // there are no forwarded objects + _verify_gcstate_stable, // there are no forwarded objects + _verify_stringtable_enable // check stringtable ); } } @@ -798,7 +802,8 @@ _verify_cset_none, // no references to cset anymore _verify_liveness_complete, // liveness data must be complete here _verify_regions_disable, // trash regions not yet recycled - _verify_gcstate_stable // mark should have stabilized the heap + _verify_gcstate_stable, // mark should have stabilized the heap + _verify_stringtable_disable // stringtable not valid ); } @@ -810,7 +815,8 @@ _verify_cset_disable, // non-forwarded references to cset expected _verify_liveness_complete, // liveness data must be complete here _verify_regions_disable, // trash regions not yet recycled - _verify_gcstate_stable // mark should have stabilized the heap + _verify_gcstate_stable, // mark should have stabilized the heap + _verify_stringtable_disable // stringtable not valid ); } @@ -822,7 +828,8 @@ _verify_cset_forwarded, // all cset refs are fully forwarded _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash, // trash regions have been recycled already - _verify_gcstate_forwarded // evacuation produced some forwarded objects + _verify_gcstate_forwarded, // evacuation produced some forwarded objects + _verify_stringtable_enable // check stringtable ); } @@ -834,7 +841,8 @@ _verify_cset_forwarded, // all cset refs are fully forwarded _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash, // trash regions have been recycled already - _verify_gcstate_forwarded // evacuation should have produced some forwarded objects + _verify_gcstate_forwarded, // evacuation should have produced some forwarded objects + _verify_stringtable_enable // check stringtable ); } @@ -846,7 +854,8 @@ _verify_cset_none, // no cset references, all updated _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_nocset, // no cset regions, trash regions have appeared - _verify_gcstate_stable // update refs had cleaned up forwarded objects + _verify_gcstate_stable, // update refs had cleaned up forwarded objects + _verify_stringtable_enable // check stringtable ); } @@ -858,7 +867,8 @@ _verify_cset_none, // no cset references _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash_nocset, // no trash, no cset - _verify_gcstate_stable // degenerated refs had cleaned up forwarded objects + _verify_gcstate_stable, // degenerated refs had cleaned up forwarded objects + _verify_stringtable_disable // don't know if stringtable valid ); } @@ -870,7 +880,8 @@ _verify_cset_none, // no cset references before traversal _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash_nocset, // no trash and no cset regions - _verify_gcstate_stable // nothing forwarded before traversal + _verify_gcstate_stable, // nothing forwarded before traversal + _verify_stringtable_enable // check stringtable ); } @@ -882,7 +893,8 @@ _verify_cset_none, // no cset references left after traversal _verify_liveness_disable, // liveness data is not collected for new allocations _verify_regions_nocset, // no cset regions, trash regions allowed - _verify_gcstate_stable // nothing forwarded after traversal + _verify_gcstate_stable, // nothing forwarded after traversal + _verify_stringtable_enable // check stringtable ); } @@ -894,7 +906,8 @@ _verify_cset_disable, // cset might be foobared _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_disable, // no reliable region data here - _verify_gcstate_disable // no reliable gcstate data + _verify_gcstate_disable, // no reliable gcstate data + _verify_stringtable_enable // check stringtable ); } @@ -906,6 +919,7 @@ _verify_cset_none, // no cset references _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash_nocset, // no trash, no cset - _verify_gcstate_stable // full gc cleaned up everything + _verify_gcstate_stable, // full gc cleaned up everything + _verify_stringtable_enable // check stringtable ); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -137,6 +137,14 @@ _verify_gcstate_forwarded, } VerifyGCState; + typedef enum { + // Disable stringtable scanning + _verify_stringtable_disable, + + // Enable stringtable scanning + _verify_stringtable_enable, + } VerifyStringTable; + struct VerifyOptions { VerifyForwarded _verify_forwarded; VerifyMarked _verify_marked; @@ -144,17 +152,19 @@ VerifyLiveness _verify_liveness; VerifyRegions _verify_regions; VerifyGCState _verify_gcstate; + VerifyStringTable _verify_stringtable; VerifyOptions(VerifyForwarded verify_forwarded, VerifyMarked verify_marked, VerifyCollectionSet verify_collection_set, VerifyLiveness verify_liveness, VerifyRegions verify_regions, - VerifyGCState verify_gcstate) : + VerifyGCState verify_gcstate, + VerifyStringTable verify_stringtable) : _verify_forwarded(verify_forwarded), _verify_marked(verify_marked), _verify_cset(verify_collection_set), _verify_liveness(verify_liveness), _verify_regions(verify_regions), - _verify_gcstate(verify_gcstate) {} + _verify_gcstate(verify_gcstate), _verify_stringtable(verify_stringtable) {} }; private: @@ -164,7 +174,8 @@ VerifyCollectionSet cset, VerifyLiveness liveness, VerifyRegions regions, - VerifyGCState gcstate); + VerifyGCState gcstate, + VerifyStringTable stringtable); public: ShenandoahVerifier(ShenandoahHeap* heap, MarkBitMap* verification_bitmap) :