1 /*
2 * Copyright (c) 2019, 2020, Red Hat, Inc. All rights reserved.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This code is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * version 2 for more details (a copy is included in the LICENSE file that
12 * accompanied this code).
13 *
14 * You should have received a copy of the GNU General Public License version
15 * 2 along with this work; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
19 * or visit www.oracle.com if you need additional information or have any
20 * questions.
21 *
22 */
23
24 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
25 #define SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
26
27 #include "classfile/classLoaderDataGraph.hpp"
28 #include "classfile/stringTable.hpp"
29 #include "classfile/systemDictionary.hpp"
30 #include "gc/shared/oopStorageParState.inline.hpp"
31 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
32 #include "gc/shenandoah/shenandoahConcurrentRoots.hpp"
33 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
34 #include "gc/shenandoah/shenandoahPhaseTimings.hpp"
35 #include "gc/shenandoah/shenandoahRootProcessor.hpp"
36 #include "gc/shenandoah/shenandoahUtils.hpp"
37 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
38 #include "memory/resourceArea.hpp"
39 #include "prims/resolvedMethodTable.hpp"
40 #include "runtime/safepoint.hpp"
41
42 template <bool CONCURRENT>
ShenandoahVMRoot(OopStorage * storage,ShenandoahPhaseTimings::Phase phase,ShenandoahPhaseTimings::ParPhase par_phase)43 inline ShenandoahVMRoot<CONCURRENT>::ShenandoahVMRoot(OopStorage* storage,
44 ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
45 _itr(storage), _phase(phase), _par_phase(par_phase) {
46 }
47
48 template <bool CONCURRENT>
49 template <typename Closure>
oops_do(Closure * cl,uint worker_id)50 inline void ShenandoahVMRoot<CONCURRENT>::oops_do(Closure* cl, uint worker_id) {
51 ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id);
52 _itr.oops_do(cl);
53 }
54
55 template <bool CONCURRENT>
ShenandoahWeakRoot(OopStorage * storage,ShenandoahPhaseTimings::Phase phase,ShenandoahPhaseTimings::ParPhase par_phase)56 inline ShenandoahWeakRoot<CONCURRENT>::ShenandoahWeakRoot(OopStorage* storage,
57 ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
58 ShenandoahVMRoot<CONCURRENT>(storage, phase, par_phase) {
59 }
60
ShenandoahWeakRoot(OopStorage * storage,ShenandoahPhaseTimings::Phase phase,ShenandoahPhaseTimings::ParPhase par_phase)61 inline ShenandoahWeakRoot<false>::ShenandoahWeakRoot(OopStorage* storage,
62 ShenandoahPhaseTimings::Phase phase, ShenandoahPhaseTimings::ParPhase par_phase) :
63 _itr(storage), _phase(phase), _par_phase(par_phase) {
64 }
65
66 template <typename IsAliveClosure, typename KeepAliveClosure>
weak_oops_do(IsAliveClosure * is_alive,KeepAliveClosure * keep_alive,uint worker_id)67 void ShenandoahWeakRoot<false /* concurrent */>::weak_oops_do(IsAliveClosure* is_alive, KeepAliveClosure* keep_alive, uint worker_id) {
68 ShenandoahWorkerTimingsTracker timer(_phase, _par_phase, worker_id);
69 _itr.weak_oops_do(is_alive, keep_alive);
70 }
71
72 template <bool CONCURRENT>
ShenandoahWeakRoots(ShenandoahPhaseTimings::Phase phase)73 ShenandoahWeakRoots<CONCURRENT>::ShenandoahWeakRoots(ShenandoahPhaseTimings::Phase phase) :
74 _jni_roots(OopStorageSet::jni_weak(), phase, ShenandoahPhaseTimings::JNIWeakRoots),
75 _string_table_roots(OopStorageSet::string_table_weak(), phase, ShenandoahPhaseTimings::StringTableRoots),
76 _resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), phase, ShenandoahPhaseTimings::ResolvedMethodTableRoots),
77 _vm_roots(OopStorageSet::vm_weak(), phase, ShenandoahPhaseTimings::VMWeakRoots) {
78 }
79
80 template <bool CONCURRENT>
81 template <typename Closure>
oops_do(Closure * cl,uint worker_id)82 void ShenandoahWeakRoots<CONCURRENT>::oops_do(Closure* cl, uint worker_id) {
83 _jni_roots.oops_do(cl, worker_id);
84 _string_table_roots.oops_do(cl, worker_id);
85 _resolved_method_table_roots.oops_do(cl, worker_id);
86 _vm_roots.oops_do(cl, worker_id);
87 }
88
ShenandoahWeakRoots(ShenandoahPhaseTimings::Phase phase)89 inline ShenandoahWeakRoots<false /* concurrent */>::ShenandoahWeakRoots(ShenandoahPhaseTimings::Phase phase) :
90 _jni_roots(OopStorageSet::jni_weak(), phase, ShenandoahPhaseTimings::JNIWeakRoots),
91 _string_table_roots(OopStorageSet::string_table_weak(), phase, ShenandoahPhaseTimings::StringTableRoots),
92 _resolved_method_table_roots(OopStorageSet::resolved_method_table_weak(), phase, ShenandoahPhaseTimings::ResolvedMethodTableRoots),
93 _vm_roots(OopStorageSet::vm_weak(), phase, ShenandoahPhaseTimings::VMWeakRoots) {
94 }
95
96 template <typename IsAliveClosure, typename KeepAliveClosure>
weak_oops_do(IsAliveClosure * is_alive,KeepAliveClosure * keep_alive,uint worker_id)97 void ShenandoahWeakRoots<false /* concurrent*/>::weak_oops_do(IsAliveClosure* is_alive, KeepAliveClosure* keep_alive, uint worker_id) {
98 _jni_roots.weak_oops_do(is_alive, keep_alive, worker_id);
99 _string_table_roots.weak_oops_do(is_alive, keep_alive, worker_id);
100 _resolved_method_table_roots.weak_oops_do(is_alive, keep_alive, worker_id);
101 _vm_roots.weak_oops_do(is_alive, keep_alive, worker_id);
102 }
103
104 template <typename Closure>
oops_do(Closure * cl,uint worker_id)105 void ShenandoahWeakRoots<false /* concurrent */>::oops_do(Closure* cl, uint worker_id) {
106 AlwaysTrueClosure always_true;
107 weak_oops_do<AlwaysTrueClosure, Closure>(&always_true, cl, worker_id);
108 }
109
110 template <bool CONCURRENT>
ShenandoahVMRoots(ShenandoahPhaseTimings::Phase phase)111 ShenandoahVMRoots<CONCURRENT>::ShenandoahVMRoots(ShenandoahPhaseTimings::Phase phase) :
112 _jni_handle_roots(OopStorageSet::jni_global(), phase, ShenandoahPhaseTimings::JNIRoots),
113 _vm_global_roots(OopStorageSet::vm_global(), phase, ShenandoahPhaseTimings::VMGlobalRoots) {
114 }
115
116 template <bool CONCURRENT>
117 template <typename T>
oops_do(T * cl,uint worker_id)118 void ShenandoahVMRoots<CONCURRENT>::oops_do(T* cl, uint worker_id) {
119 _jni_handle_roots.oops_do(cl, worker_id);
120 _vm_global_roots.oops_do(cl, worker_id);
121 }
122
123 template <bool CONCURRENT, bool SINGLE_THREADED>
ShenandoahClassLoaderDataRoots(ShenandoahPhaseTimings::Phase phase,uint n_workers)124 ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::ShenandoahClassLoaderDataRoots(ShenandoahPhaseTimings::Phase phase, uint n_workers) :
125 _semaphore(worker_count(n_workers)),
126 _phase(phase) {
127 if (!SINGLE_THREADED) {
128 ClassLoaderDataGraph::clear_claimed_marks();
129 }
130 if (CONCURRENT) {
131 ClassLoaderDataGraph_lock->lock();
132 }
133 }
134
135 template <bool CONCURRENT, bool SINGLE_THREADED>
~ShenandoahClassLoaderDataRoots()136 ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::~ShenandoahClassLoaderDataRoots() {
137 if (CONCURRENT) {
138 ClassLoaderDataGraph_lock->unlock();
139 }
140 }
141
142
143 template <bool CONCURRENT, bool SINGLE_THREADED>
always_strong_cld_do(CLDClosure * clds,uint worker_id)144 void ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::always_strong_cld_do(CLDClosure* clds, uint worker_id) {
145 if (SINGLE_THREADED) {
146 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
147 assert(Thread::current()->is_VM_thread(), "Single threaded CLDG iteration can only be done by VM thread");
148 ClassLoaderDataGraph::always_strong_cld_do(clds);
149 } else if (_semaphore.try_acquire()) {
150 ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id);
151 ClassLoaderDataGraph::always_strong_cld_do(clds);
152 _semaphore.claim_all();
153 }
154 }
155
156 template <bool CONCURRENT, bool SINGLE_THREADED>
cld_do(CLDClosure * clds,uint worker_id)157 void ShenandoahClassLoaderDataRoots<CONCURRENT, SINGLE_THREADED>::cld_do(CLDClosure* clds, uint worker_id) {
158 if (SINGLE_THREADED) {
159 assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
160 assert(Thread::current()->is_VM_thread(), "Single threaded CLDG iteration can only be done by VM thread");
161 ClassLoaderDataGraph::cld_do(clds);
162 } else if (_semaphore.try_acquire()) {
163 ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CLDGRoots, worker_id);
164 ClassLoaderDataGraph::cld_do(clds);
165 _semaphore.claim_all();
166 }
167 }
168
169 template <typename ITR>
ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase)170 ShenandoahCodeCacheRoots<ITR>::ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase) : _phase(phase) {
171 nmethod::oops_do_marking_prologue();
172 }
173
174 template <typename ITR>
code_blobs_do(CodeBlobClosure * blob_cl,uint worker_id)175 void ShenandoahCodeCacheRoots<ITR>::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) {
176 ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
177 _coderoots_iterator.possibly_parallel_blobs_do(blob_cl);
178 }
179
180 template <typename ITR>
~ShenandoahCodeCacheRoots()181 ShenandoahCodeCacheRoots<ITR>::~ShenandoahCodeCacheRoots() {
182 nmethod::oops_do_marking_epilogue();
183 }
184
185 class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
186 private:
187 OopClosure* _f;
188 CodeBlobClosure* _cf;
189 ThreadClosure* _thread_cl;
190 public:
ShenandoahParallelOopsDoThreadClosure(OopClosure * f,CodeBlobClosure * cf,ThreadClosure * thread_cl)191 ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) :
192 _f(f), _cf(cf), _thread_cl(thread_cl) {}
193
do_thread(Thread * t)194 void do_thread(Thread* t) {
195 if (_thread_cl != NULL) {
196 _thread_cl->do_thread(t);
197 }
198 t->oops_do(_f, _cf);
199 }
200 };
201
202 template <typename ITR>
ShenandoahRootScanner(uint n_workers,ShenandoahPhaseTimings::Phase phase)203 ShenandoahRootScanner<ITR>::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
204 ShenandoahRootProcessor(phase),
205 _serial_roots(phase),
206 _thread_roots(phase, n_workers > 1),
207 _code_roots(phase),
208 _vm_roots(phase),
209 _dedup_roots(phase),
210 _cld_roots(phase, n_workers) {
211 }
212
213 template <typename ITR>
roots_do(uint worker_id,OopClosure * oops)214 void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops) {
215 CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
216 MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
217 roots_do(worker_id, oops, &clds_cl, &blobs_cl);
218 }
219
220 template <typename ITR>
strong_roots_do(uint worker_id,OopClosure * oops)221 void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops) {
222 CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
223 MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
224 strong_roots_do(worker_id, oops, &clds_cl, &blobs_cl);
225 }
226
227 template <typename ITR>
roots_do(uint worker_id,OopClosure * oops,CLDClosure * clds,CodeBlobClosure * code,ThreadClosure * tc)228 void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) {
229 assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint() ||
230 !ShenandoahHeap::heap()->unload_classes(),
231 "Expect class unloading when Shenandoah cycle is running");
232 assert(clds != NULL, "Only possible with CLD closure");
233
234 AlwaysTrueClosure always_true;
235 ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
236
237 ResourceMark rm;
238
239 // Process serial-claiming roots first
240 _serial_roots.oops_do(oops, worker_id);
241
242 // Process light-weight/limited parallel roots then
243 _vm_roots.oops_do(oops, worker_id);
244 _dedup_roots.oops_do(&always_true, oops, worker_id);
245 _cld_roots.cld_do(clds, worker_id);
246
247 // Process heavy-weight/fully parallel roots the last
248 _thread_roots.threads_do(&tc_cl, worker_id);
249 }
250
251 template <typename ITR>
strong_roots_do(uint worker_id,OopClosure * oops,CLDClosure * clds,CodeBlobClosure * code,ThreadClosure * tc)252 void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
253 assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
254 ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
255 ResourceMark rm;
256
257 // Process serial-claiming roots first
258 _serial_roots.oops_do(oops, worker_id);
259
260 // Process light-weight/limited parallel roots then
261 _vm_roots.oops_do(oops, worker_id);
262 _cld_roots.always_strong_cld_do(clds, worker_id);
263
264 // Process heavy-weight/fully parallel roots the last
265 _thread_roots.threads_do(&tc_cl, worker_id);
266 }
267
268 template <typename IsAlive, typename KeepAlive>
roots_do(uint worker_id,IsAlive * is_alive,KeepAlive * keep_alive)269 void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) {
270 CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations);
271 ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(keep_alive);
272 CodeBlobToOopClosure* codes_cl = ShenandoahConcurrentRoots::can_do_concurrent_class_unloading() ?
273 static_cast<CodeBlobToOopClosure*>(&blobs_and_disarm_Cl) :
274 static_cast<CodeBlobToOopClosure*>(&update_blobs);
275
276 CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong);
277
278 // Process serial-claiming roots first
279 _serial_roots.oops_do(keep_alive, worker_id);
280 _serial_weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);
281
282 // Process light-weight/limited parallel roots then
283 _vm_roots.oops_do(keep_alive, worker_id);
284 _weak_roots.weak_oops_do(is_alive, keep_alive, worker_id);
285 _dedup_roots.oops_do(is_alive, keep_alive, worker_id);
286 _cld_roots.cld_do(&clds, worker_id);
287
288 // Process heavy-weight/fully parallel roots the last
289 _code_roots.code_blobs_do(codes_cl, worker_id);
290 _thread_roots.oops_do(keep_alive, NULL, worker_id);
291
292 }
293
294 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
295