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