1/*
2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#ifndef SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
26#define SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
27
28#include "classfile/stringTable.hpp"
29#include "gc/shared/oopStorage.inline.hpp"
30#include "gc/shared/oopStorageParState.inline.hpp"
31#include "gc/shared/weakProcessor.hpp"
32#include "gc/shared/weakProcessorPhases.hpp"
33#include "gc/shared/weakProcessorPhaseTimes.hpp"
34#include "gc/shared/workgroup.hpp"
35#include "prims/resolvedMethodTable.hpp"
36#include "utilities/debug.hpp"
37
38class BoolObjectClosure;
39class OopClosure;
40
41template<typename IsAlive>
42class CountingIsAliveClosure : public BoolObjectClosure {
43 IsAlive* _inner;
44
45 size_t _num_dead;
46 size_t _num_total;
47
48public:
49 CountingIsAliveClosure(IsAlive* cl) : _inner(cl), _num_dead(0), _num_total(0) { }
50
51 virtual bool do_object_b(oop obj) {
52 bool result = _inner->do_object_b(obj);
53 _num_dead += !result;
54 _num_total++;
55 return result;
56 }
57
58 size_t num_dead() const { return _num_dead; }
59 size_t num_total() const { return _num_total; }
60};
61
62template <typename IsAlive, typename KeepAlive>
63class CountingSkippedIsAliveClosure : public Closure {
64 CountingIsAliveClosure<IsAlive> _counting_is_alive;
65 KeepAlive* _keep_alive;
66
67 size_t _num_skipped;
68
69public:
70 CountingSkippedIsAliveClosure(IsAlive* is_alive, KeepAlive* keep_alive) :
71 _counting_is_alive(is_alive), _keep_alive(keep_alive), _num_skipped(0) { }
72
73 void do_oop(oop* p) {
74 oop obj = *p;
75 if (obj == NULL) {
76 _num_skipped++;
77 } else if (_counting_is_alive.do_object_b(obj)) {
78 _keep_alive->do_oop(p);
79 } else {
80 *p = NULL;
81 }
82 }
83
84 size_t num_dead() const { return _counting_is_alive.num_dead(); }
85 size_t num_skipped() const { return _num_skipped; }
86 size_t num_total() const { return _counting_is_alive.num_total() + num_skipped(); }
87};
88
89template<typename IsAlive, typename KeepAlive>
90void WeakProcessor::Task::work(uint worker_id,
91 IsAlive* is_alive,
92 KeepAlive* keep_alive) {
93 assert(worker_id < _nworkers,
94 "worker_id (%u) exceeds task's configured workers (%u)",
95 worker_id, _nworkers);
96
97 FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
98 if (WeakProcessorPhases::is_serial(phase)) {
99 CountingIsAliveClosure<IsAlive> cl(is_alive);
100 uint serial_index = WeakProcessorPhases::serial_index(phase);
101 if (_serial_phases_done.try_claim_task(serial_index)) {
102 WeakProcessorPhaseTimeTracker pt(_phase_times, phase);
103 WeakProcessorPhases::processor(phase)(&cl, keep_alive);
104 if (_phase_times != NULL) {
105 _phase_times->record_phase_items(phase, cl.num_dead(), cl.num_total());
106 }
107 }
108 } else {
109 CountingSkippedIsAliveClosure<IsAlive, KeepAlive> cl(is_alive, keep_alive);
110 WeakProcessorPhaseTimeTracker pt(_phase_times, phase, worker_id);
111 uint storage_index = WeakProcessorPhases::oop_storage_index(phase);
112 _storage_states[storage_index].oops_do(&cl);
113 if (_phase_times != NULL) {
114 _phase_times->record_worker_items(worker_id, phase, cl.num_dead(), cl.num_total());
115 }
116 if (WeakProcessorPhases::is_stringtable(phase)) {
117 StringTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
118 }
119 if (WeakProcessorPhases::is_resolved_method_table(phase)) {
120 ResolvedMethodTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
121 }
122 }
123 }
124
125 _serial_phases_done.all_tasks_completed(_nworkers);
126}
127
128class WeakProcessor::GangTask : public AbstractGangTask {
129 Task _task;
130 BoolObjectClosure* _is_alive;
131 OopClosure* _keep_alive;
132 void (*_erased_do_work)(GangTask* task, uint worker_id);
133
134 template<typename IsAlive, typename KeepAlive>
135 static void erased_do_work(GangTask* task, uint worker_id) {
136 task->_task.work(worker_id,
137 static_cast<IsAlive*>(task->_is_alive),
138 static_cast<KeepAlive*>(task->_keep_alive));
139 }
140
141public:
142 template<typename IsAlive, typename KeepAlive>
143 GangTask(const char* name,
144 IsAlive* is_alive,
145 KeepAlive* keep_alive,
146 WeakProcessorPhaseTimes* phase_times,
147 uint nworkers) :
148 AbstractGangTask(name),
149 _task(phase_times, nworkers),
150 _is_alive(is_alive),
151 _keep_alive(keep_alive),
152 _erased_do_work(&erased_do_work<IsAlive, KeepAlive>)
153 {}
154
155 virtual void work(uint worker_id);
156};
157
158template<typename IsAlive, typename KeepAlive>
159void WeakProcessor::weak_oops_do(WorkGang* workers,
160 IsAlive* is_alive,
161 KeepAlive* keep_alive,
162 WeakProcessorPhaseTimes* phase_times) {
163 WeakProcessorTimeTracker tt(phase_times);
164
165 uint nworkers = ergo_workers(MIN2(workers->active_workers(),
166 phase_times->max_threads()));
167
168 GangTask task("Weak Processor", is_alive, keep_alive, phase_times, nworkers);
169 workers->run_task(&task, nworkers);
170}
171
172template<typename IsAlive, typename KeepAlive>
173void WeakProcessor::weak_oops_do(WorkGang* workers,
174 IsAlive* is_alive,
175 KeepAlive* keep_alive,
176 uint indent_log) {
177 uint nworkers = ergo_workers(workers->active_workers());
178 WeakProcessorPhaseTimes pt(nworkers);
179 weak_oops_do(workers, is_alive, keep_alive, &pt);
180 pt.log_print_phases(indent_log);
181}
182
183#endif // SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
184