| /* |
| * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2020, 2021, Red Hat, Inc. and/or its affiliates. |
| * 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. |
| * |
| */ |
| |
| #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP |
| #define SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP |
| |
| #include "gc/shared/referenceDiscoverer.hpp" |
| #include "gc/shared/referencePolicy.hpp" |
| #include "gc/shared/referenceProcessorStats.hpp" |
| #include "gc/shenandoah/shenandoahPhaseTimings.hpp" |
| #include "memory/allocation.hpp" |
| |
| class ShenandoahMarkRefsSuperClosure; |
| class WorkerThreads; |
| |
| static const size_t reference_type_count = REF_PHANTOM + 1; |
| typedef size_t Counters[reference_type_count]; |
| |
| /* |
| * Shenandoah concurrent reference processing |
| * |
| * Concurrent reference processing is made up of two main phases: |
| * 1. Concurrent reference marking: Discover all j.l.r.Reference objects and determine reachability of all live objects. |
| * 2. Concurrent reference processing: For all discoved j.l.r.References, determine whether to keep them alive or clean |
| * them. Also, clean and enqueue relevant references concurrently. |
| * |
| * Concurrent reference marking: |
| * The goal here is to establish the kind of reachability for all objects on the heap. We distinguish two kinds of |
| * reachability: |
| * - An object is 'strongly reachable' if it can be found by searching transitively from GC roots. |
| * - An object is 'finalizably reachable' if it is not strongly reachable, but can be found by searching |
| * from the referents of FinalReferences. |
| * |
| * These reachabilities are implemented in shenandoahMarkBitMap.* |
| * Conceptually, marking starts with a strong wavefront at the GC roots. Whenever a Reference object is encountered, |
| * it may be discovered by the ShenandoahReferenceProcessor. If it is discovered, it |
| * gets added to the discovered list, and that wavefront stops there, except when it's a FinalReference, in which |
| * case the wavefront switches to finalizable marking and marks through the referent. When a Reference is not |
| * discovered, e.g. if it's a SoftReference that is not eligible for discovery, then marking continues as if the |
| * Reference was a regular object. Whenever a strong wavefront encounters an object that is already marked |
| * finalizable, then the object's reachability is upgraded to strong. |
| * |
| * Concurrent reference processing: |
| * This happens after the concurrent marking phase and the final marking pause, when reachability for all objects |
| * has been established. |
| * The discovered list is scanned and for each reference is decided what to do: |
| * - If the referent is reachable (finalizable for PhantomReference, strong for all others), then the Reference |
| * is dropped from the discovered list and otherwise ignored |
| * - Otherwise its referent becomes cleared and the Reference added to the pending list, from which it will later |
| * be processed (e.g. enqueued in its ReferenceQueue) by the Java ReferenceHandler thread. |
| * |
| * In order to prevent resurrection by Java threads calling Reference.get() concurrently while we are clearing |
| * referents, we employ a special barrier, the native LRB, which returns nullptr when the referent is unreachable. |
| */ |
| |
| class ShenandoahRefProcThreadLocal : public CHeapObj<mtGC> { |
| private: |
| void* _discovered_list; |
| ShenandoahMarkRefsSuperClosure* _mark_closure; |
| Counters _encountered_count; |
| Counters _discovered_count; |
| Counters _enqueued_count; |
| NONCOPYABLE(ShenandoahRefProcThreadLocal); |
| |
| public: |
| ShenandoahRefProcThreadLocal(); |
| |
| void reset(); |
| |
| ShenandoahMarkRefsSuperClosure* mark_closure() const { |
| return _mark_closure; |
| } |
| |
| void set_mark_closure(ShenandoahMarkRefsSuperClosure* mark_closure) { |
| _mark_closure = mark_closure; |
| } |
| |
| template<typename T> |
| T* discovered_list_addr(); |
| template<typename T> |
| oop discovered_list_head() const; |
| template<typename T> |
| void set_discovered_list_head(oop head); |
| |
| size_t encountered(ReferenceType type) const { |
| return _encountered_count[type]; |
| } |
| size_t discovered(ReferenceType type) const { |
| return _discovered_count[type]; |
| } |
| size_t enqueued(ReferenceType type) const { |
| return _enqueued_count[type]; |
| } |
| |
| void inc_encountered(ReferenceType type) { |
| _encountered_count[type]++; |
| } |
| void inc_discovered(ReferenceType type) { |
| _discovered_count[type]++; |
| } |
| void inc_enqueued(ReferenceType type) { |
| _enqueued_count[type]++; |
| } |
| }; |
| |
| class ShenandoahReferenceProcessor : public ReferenceDiscoverer { |
| private: |
| ReferencePolicy* _soft_reference_policy; |
| |
| ShenandoahRefProcThreadLocal* _ref_proc_thread_locals; |
| |
| oop _pending_list; |
| void* _pending_list_tail; // T* |
| |
| volatile uint _iterate_discovered_list_id; |
| |
| ReferenceProcessorStats _stats; |
| |
| template <typename T> |
| bool is_inactive(oop reference, oop referent, ReferenceType type) const; |
| bool is_strongly_live(oop referent) const; |
| bool is_softly_live(oop reference, ReferenceType type) const; |
| |
| template <typename T> |
| bool should_discover(oop reference, ReferenceType type) const; |
| template <typename T> |
| bool should_drop(oop reference, ReferenceType type) const; |
| |
| template <typename T> |
| void make_inactive(oop reference, ReferenceType type) const; |
| |
| template <typename T> |
| bool discover(oop reference, ReferenceType type, uint worker_id); |
| |
| template <typename T> |
| oop drop(oop reference, ReferenceType type); |
| template <typename T> |
| T* keep(oop reference, ReferenceType type, uint worker_id); |
| |
| template <typename T> |
| void process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id); |
| void enqueue_references_locked(); |
| void enqueue_references(bool concurrent); |
| |
| void collect_statistics(); |
| |
| template<typename T> |
| void clean_discovered_list(T* list); |
| |
| public: |
| ShenandoahReferenceProcessor(uint max_workers); |
| |
| void reset_thread_locals(); |
| void set_mark_closure(uint worker_id, ShenandoahMarkRefsSuperClosure* mark_closure); |
| |
| void set_soft_reference_policy(bool clear); |
| |
| bool discover_reference(oop obj, ReferenceType type) override; |
| |
| void process_references(ShenandoahPhaseTimings::Phase phase, WorkerThreads* workers, bool concurrent); |
| |
| const ReferenceProcessorStats& reference_process_stats() { return _stats; } |
| |
| void work(); |
| |
| void abandon_partial_discovery(); |
| }; |
| |
| #endif // SHARE_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP |