1/*
2 * Copyright (c) 2019, 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 "gc/shenandoah/shenandoahHeuristics.hpp"
28#include "gc/shenandoah/shenandoahRootProcessor.hpp"
29#include "gc/shenandoah/shenandoahTimingTracker.hpp"
30#include "gc/shenandoah/shenandoahUtils.hpp"
31#include "memory/resourceArea.hpp"
32
33template <typename IsAlive, typename KeepAlive>
34void ShenandoahWeakRoots::oops_do(IsAlive* is_alive, KeepAlive* keep_alive, uint worker_id) {
35 _task.work<IsAlive, KeepAlive>(worker_id, is_alive, keep_alive);
36}
37
38template <typename ITR>
39ShenandoahCodeCacheRoots<ITR>::ShenandoahCodeCacheRoots() {
40 nmethod::oops_do_marking_prologue();
41}
42
43template <typename ITR>
44void ShenandoahCodeCacheRoots<ITR>::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) {
45 ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
46 ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
47 _coderoots_iterator.possibly_parallel_blobs_do(blob_cl);
48}
49
50template <typename ITR>
51ShenandoahCodeCacheRoots<ITR>::~ShenandoahCodeCacheRoots() {
52 nmethod::oops_do_marking_epilogue();
53}
54
55class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
56private:
57 OopClosure* _f;
58 CodeBlobClosure* _cf;
59 ThreadClosure* _thread_cl;
60public:
61 ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) :
62 _f(f), _cf(cf), _thread_cl(thread_cl) {}
63
64 void do_thread(Thread* t) {
65 if (_thread_cl != NULL) {
66 _thread_cl->do_thread(t);
67 }
68 t->oops_do(_f, _cf);
69 }
70};
71
72template <typename ITR>
73ShenandoahRootScanner<ITR>::ShenandoahRootScanner(uint n_workers, ShenandoahPhaseTimings::Phase phase) :
74 ShenandoahRootProcessor(phase),
75 _thread_roots(n_workers > 1) {
76}
77
78template <typename ITR>
79void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops) {
80 CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
81 MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
82 roots_do(worker_id, oops, &clds_cl, &blobs_cl);
83}
84
85template <typename ITR>
86void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops) {
87 CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
88 MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations);
89 strong_roots_do(worker_id, oops, &clds_cl, &blobs_cl);
90}
91
92template <typename ITR>
93void ShenandoahRootScanner<ITR>::roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure *tc) {
94 assert(!ShenandoahSafepoint::is_at_shenandoah_safepoint() ||
95 !ShenandoahHeap::heap()->unload_classes() ||
96 ShenandoahHeap::heap()->heuristics()->can_do_traversal_gc(),
97 "Expect class unloading or traversal when Shenandoah cycle is running");
98 ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
99 ResourceMark rm;
100
101 _serial_roots.oops_do(oops, worker_id);
102 _jni_roots.oops_do(oops, worker_id);
103 _cld_roots.clds_do(clds, clds, worker_id);
104 _thread_roots.threads_do(&tc_cl, worker_id);
105
106 // With ShenandoahConcurrentScanCodeRoots, we avoid scanning the entire code cache here,
107 // and instead do that in concurrent phase under the relevant lock. This saves init mark
108 // pause time.
109 if (code != NULL && !ShenandoahConcurrentScanCodeRoots) {
110 _code_roots.code_blobs_do(code, worker_id);
111 }
112}
113
114template <typename ITR>
115void ShenandoahRootScanner<ITR>::roots_do_unchecked(OopClosure* oops) {
116 CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong);
117 MarkingCodeBlobClosure code(oops, !CodeBlobToOopClosure::FixRelocations);
118 ShenandoahParallelOopsDoThreadClosure tc_cl(oops, &code, NULL);
119 ResourceMark rm;
120
121 _serial_roots.oops_do(oops, 0);
122 _jni_roots.oops_do(oops, 0);
123 _cld_roots.clds_do(&clds, &clds, 0);
124 _thread_roots.threads_do(&tc_cl, 0);
125 _code_roots.code_blobs_do(&code, 0);
126}
127
128template <typename ITR>
129void ShenandoahRootScanner<ITR>::strong_roots_do(uint worker_id, OopClosure* oops, CLDClosure* clds, CodeBlobClosure* code, ThreadClosure* tc) {
130 assert(ShenandoahHeap::heap()->unload_classes(), "Should be used during class unloading");
131 ShenandoahParallelOopsDoThreadClosure tc_cl(oops, code, tc);
132 ResourceMark rm;
133
134 _serial_roots.oops_do(oops, worker_id);
135 _jni_roots.oops_do(oops, worker_id);
136 _cld_roots.clds_do(clds, NULL, worker_id);
137 _thread_roots.threads_do(&tc_cl, worker_id);
138}
139
140template <typename IsAlive, typename KeepAlive>
141void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) {
142 CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations);
143 CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong);
144 CLDToOopClosure* weak_clds = ShenandoahHeap::heap()->unload_classes() ? NULL : &clds;
145
146 _serial_roots.oops_do(keep_alive, worker_id);
147 _jni_roots.oops_do(keep_alive, worker_id);
148
149 _thread_roots.oops_do(keep_alive, NULL, worker_id);
150 _cld_roots.clds_do(&clds, weak_clds, worker_id);
151
152 if(_update_code_cache) {
153 _code_roots.code_blobs_do(&update_blobs, worker_id);
154 }
155
156 _weak_roots.oops_do<IsAlive, KeepAlive>(is_alive, keep_alive, worker_id);
157 _dedup_roots.oops_do(is_alive, keep_alive, worker_id);
158}
159
160#endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
161