1 /*
  2  * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * Copyright (c) 2020, 2021, Red Hat, Inc. and/or its affiliates.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  *
 24  */
 25 
 26 #ifndef SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP
 27 #define SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP
 28 
 29 #include "gc/shared/referenceDiscoverer.hpp"
 30 #include "gc/shared/referencePolicy.hpp"
 31 #include "gc/shared/referenceProcessorStats.hpp"
 32 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
 33 #include "memory/allocation.hpp"
 34 
 35 class ShenandoahMarkRefsSuperClosure;
 36 class WorkerThreads;
 37 
 38 static const size_t reference_type_count = REF_PHANTOM + 1;
 39 typedef size_t Counters[reference_type_count];
 40 
 41 /*
 42  * Shenandoah concurrent reference processing
 43  *
 44  * Concurrent reference processing is made up of two main phases:
 45  * 1. Concurrent reference marking: Discover all j.l.r.Reference objects and determine reachability of all live objects.
 46  * 2. Concurrent reference processing: For all discoved j.l.r.References, determine whether to keep them alive or clean
 47  *    them. Also, clean and enqueue relevant references concurrently.
 48  *
 49  * Concurrent reference marking:
 50  * The goal here is to establish the kind of reachability for all objects on the heap. We distinguish two kinds of
 51  * reachability:
 52  * - An object is 'strongly reachable' if it can be found by searching transitively from GC roots.
 53  * - An object is 'finalizably reachable' if it is not strongly reachable, but can be found by searching
 54  *   from the referents of FinalReferences.
 55  *
 56  * These reachabilities are implemented in shenandoahMarkBitMap.*
 57  * Conceptually, marking starts with a strong wavefront at the GC roots. Whenever a Reference object is encountered,
 58  * it may be discovered by the ShenandoahReferenceProcessor. If it is discovered, it
 59  * gets added to the discovered list, and that wavefront stops there, except when it's a FinalReference, in which
 60  * case the wavefront switches to finalizable marking and marks through the referent. When a Reference is not
 61  * discovered, e.g. if it's a SoftReference that is not eligible for discovery, then marking continues as if the
 62  * Reference was a regular object. Whenever a strong wavefront encounters an object that is already marked
 63  * finalizable, then the object's reachability is upgraded to strong.
 64  *
 65  * Concurrent reference processing:
 66  * This happens after the concurrent marking phase and the final marking pause, when reachability for all objects
 67  * has been established.
 68  * The discovered list is scanned and for each reference is decided what to do:
 69  * - If the referent is reachable (finalizable for PhantomReference, strong for all others), then the Reference
 70  *   is dropped from the discovered list and otherwise ignored
 71  * - Otherwise its referent becomes cleared and the Reference added to the pending list, from which it will later
 72  *   be processed (e.g. enqueued in its ReferenceQueue) by the Java ReferenceHandler thread.
 73  *
 74  * In order to prevent resurrection by Java threads calling Reference.get() concurrently while we are clearing
 75  * referents, we employ a special barrier, the native LRB, which returns nullptr when the referent is unreachable.
 76  */
 77 
 78 class ShenandoahRefProcThreadLocal : public CHeapObj<mtGC> {
 79 private:
 80   void* _discovered_list;
 81   ShenandoahMarkRefsSuperClosure* _mark_closure;
 82   Counters _encountered_count;
 83   Counters _discovered_count;
 84   Counters _enqueued_count;
 85   NONCOPYABLE(ShenandoahRefProcThreadLocal);
 86 
 87 public:
 88   ShenandoahRefProcThreadLocal();
 89 
 90   void reset();
 91 
 92   ShenandoahMarkRefsSuperClosure* mark_closure() const {
 93     return _mark_closure;
 94   }
 95 
 96   void set_mark_closure(ShenandoahMarkRefsSuperClosure* mark_closure) {
 97     _mark_closure = mark_closure;
 98   }
 99 
100   template<typename T>
101   T* discovered_list_addr();
102   template<typename T>
103   oop discovered_list_head() const;
104   template<typename T>
105   void set_discovered_list_head(oop head);
106 
107   size_t encountered(ReferenceType type) const {
108     return _encountered_count[type];
109   }
110   size_t discovered(ReferenceType type) const {
111     return _discovered_count[type];
112   }
113   size_t enqueued(ReferenceType type) const {
114     return _enqueued_count[type];
115   }
116 
117   void inc_encountered(ReferenceType type) {
118     _encountered_count[type]++;
119   }
120   void inc_discovered(ReferenceType type) {
121     _discovered_count[type]++;
122   }
123   void inc_enqueued(ReferenceType type) {
124     _enqueued_count[type]++;
125   }
126 };
127 
128 class ShenandoahReferenceProcessor : public ReferenceDiscoverer {
129 private:
130   ReferencePolicy* _soft_reference_policy;
131 
132   ShenandoahRefProcThreadLocal* _ref_proc_thread_locals;
133 
134   oop _pending_list;
135   void* _pending_list_tail; // T*
136 
137   volatile uint _iterate_discovered_list_id;
138 
139   ReferenceProcessorStats _stats;
140 
141   template <typename T>
142   bool is_inactive(oop reference, oop referent, ReferenceType type) const;
143   bool is_strongly_live(oop referent) const;
144   bool is_softly_live(oop reference, ReferenceType type) const;
145 
146   template <typename T>
147   bool should_discover(oop reference, ReferenceType type) const;
148   template <typename T>
149   bool should_drop(oop reference, ReferenceType type) const;
150 
151   template <typename T>
152   void make_inactive(oop reference, ReferenceType type) const;
153 
154   template <typename T>
155   bool discover(oop reference, ReferenceType type, uint worker_id);
156 
157   template <typename T>
158   oop drop(oop reference, ReferenceType type);
159   template <typename T>
160   T* keep(oop reference, ReferenceType type, uint worker_id);
161 
162   template <typename T>
163   void process_references(ShenandoahRefProcThreadLocal& refproc_data, uint worker_id);
164   void enqueue_references_locked();
165   void enqueue_references(bool concurrent);
166 
167   void collect_statistics();
168 
169   template<typename T>
170   void clean_discovered_list(T* list);
171 
172 public:
173   ShenandoahReferenceProcessor(uint max_workers);
174 
175   void reset_thread_locals();
176   void set_mark_closure(uint worker_id, ShenandoahMarkRefsSuperClosure* mark_closure);
177 
178   void set_soft_reference_policy(bool clear);
179 
180   bool discover_reference(oop obj, ReferenceType type) override;
181 
182   void process_references(ShenandoahPhaseTimings::Phase phase, WorkerThreads* workers, bool concurrent);
183 
184   const ReferenceProcessorStats& reference_process_stats() { return _stats; }
185 
186   void work();
187 
188   void abandon_partial_discovery();
189 };
190 
191 #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHREFERENCEPROCESSOR_HPP