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