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/oopStorageSet.hpp"
32 #include "gc/shared/weakProcessor.hpp"
33 #include "gc/shared/weakProcessorPhases.hpp"
34 #include "gc/shared/weakProcessorPhaseTimes.hpp"
35 #include "gc/shared/workgroup.hpp"
36 #include "prims/resolvedMethodTable.hpp"
37 #include "utilities/debug.hpp"
38
39 class BoolObjectClosure;
40 class OopClosure;
41
42 template<typename IsAlive>
43 class CountingIsAliveClosure : public BoolObjectClosure {
44 IsAlive* _inner;
45
46 size_t _num_dead;
47 size_t _num_total;
48
49 public:
CountingIsAliveClosure(IsAlive * cl)50 CountingIsAliveClosure(IsAlive* cl) : _inner(cl), _num_dead(0), _num_total(0) { }
51
do_object_b(oop obj)52 virtual bool do_object_b(oop obj) {
53 bool result = _inner->do_object_b(obj);
54 _num_dead += !result;
55 _num_total++;
56 return result;
57 }
58
num_dead() const59 size_t num_dead() const { return _num_dead; }
num_total() const60 size_t num_total() const { return _num_total; }
61 };
62
63 template <typename IsAlive, typename KeepAlive>
64 class CountingSkippedIsAliveClosure : public Closure {
65 CountingIsAliveClosure<IsAlive> _counting_is_alive;
66 KeepAlive* _keep_alive;
67
68 size_t _num_skipped;
69
70 public:
CountingSkippedIsAliveClosure(IsAlive * is_alive,KeepAlive * keep_alive)71 CountingSkippedIsAliveClosure(IsAlive* is_alive, KeepAlive* keep_alive) :
72 _counting_is_alive(is_alive), _keep_alive(keep_alive), _num_skipped(0) { }
73
do_oop(oop * p)74 void do_oop(oop* p) {
75 oop obj = *p;
76 if (obj == NULL) {
77 _num_skipped++;
78 } else if (_counting_is_alive.do_object_b(obj)) {
79 _keep_alive->do_oop(p);
80 } else {
81 *p = NULL;
82 }
83 }
84
num_dead() const85 size_t num_dead() const { return _counting_is_alive.num_dead(); }
num_skipped() const86 size_t num_skipped() const { return _num_skipped; }
num_total() const87 size_t num_total() const { return _counting_is_alive.num_total() + num_skipped(); }
88 };
89
90 template<typename IsAlive, typename KeepAlive>
work(uint worker_id,IsAlive * is_alive,KeepAlive * keep_alive)91 void WeakProcessor::Task::work(uint worker_id,
92 IsAlive* is_alive,
93 KeepAlive* keep_alive) {
94 assert(worker_id < _nworkers,
95 "worker_id (%u) exceeds task's configured workers (%u)",
96 worker_id, _nworkers);
97
98 typedef WeakProcessorPhases::Iterator Iterator;
99
100 for (Iterator it = WeakProcessorPhases::serial_iterator(); !it.is_end(); ++it) {
101 WeakProcessorPhase phase = *it;
102 CountingIsAliveClosure<IsAlive> cl(is_alive);
103 uint serial_index = WeakProcessorPhases::serial_index(phase);
104 if (_serial_phases_done.try_claim_task(serial_index)) {
105 WeakProcessorPhaseTimeTracker pt(_phase_times, phase);
106 WeakProcessorPhases::processor(phase)(&cl, keep_alive);
107 if (_phase_times != NULL) {
108 _phase_times->record_phase_items(phase, cl.num_dead(), cl.num_total());
109 }
110 }
111 }
112
113 for (Iterator it = WeakProcessorPhases::oopstorage_iterator(); !it.is_end(); ++it) {
114 WeakProcessorPhase phase = *it;
115 CountingSkippedIsAliveClosure<IsAlive, KeepAlive> cl(is_alive, keep_alive);
116 WeakProcessorPhaseTimeTracker pt(_phase_times, phase, worker_id);
117 uint oopstorage_index = WeakProcessorPhases::oopstorage_index(phase);
118 StorageState& cur_state = _storage_states[oopstorage_index];
119 cur_state.oops_do(&cl);
120 if (_phase_times != NULL) {
121 _phase_times->record_worker_items(worker_id, phase, cl.num_dead(), cl.num_total());
122 }
123 const OopStorage* cur_storage = cur_state.storage();
124 if (cur_storage == OopStorageSet::string_table_weak()) {
125 StringTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
126 } else if (cur_storage == OopStorageSet::resolved_method_table_weak()) {
127 ResolvedMethodTable::inc_dead_counter(cl.num_dead() + cl.num_skipped());
128 }
129 }
130
131 _serial_phases_done.all_tasks_completed(_nworkers);
132 }
133
134 class WeakProcessor::GangTask : public AbstractGangTask {
135 Task _task;
136 BoolObjectClosure* _is_alive;
137 OopClosure* _keep_alive;
138 void (*_erased_do_work)(GangTask* task, uint worker_id);
139
140 template<typename IsAlive, typename KeepAlive>
erased_do_work(GangTask * task,uint worker_id)141 static void erased_do_work(GangTask* task, uint worker_id) {
142 task->_task.work(worker_id,
143 static_cast<IsAlive*>(task->_is_alive),
144 static_cast<KeepAlive*>(task->_keep_alive));
145 }
146
147 public:
148 template<typename IsAlive, typename KeepAlive>
GangTask(const char * name,IsAlive * is_alive,KeepAlive * keep_alive,WeakProcessorPhaseTimes * phase_times,uint nworkers)149 GangTask(const char* name,
150 IsAlive* is_alive,
151 KeepAlive* keep_alive,
152 WeakProcessorPhaseTimes* phase_times,
153 uint nworkers) :
154 AbstractGangTask(name),
155 _task(phase_times, nworkers),
156 _is_alive(is_alive),
157 _keep_alive(keep_alive),
158 _erased_do_work(&erased_do_work<IsAlive, KeepAlive>)
159 {}
160
161 virtual void work(uint worker_id);
162 };
163
164 template<typename IsAlive, typename KeepAlive>
weak_oops_do(WorkGang * workers,IsAlive * is_alive,KeepAlive * keep_alive,WeakProcessorPhaseTimes * phase_times)165 void WeakProcessor::weak_oops_do(WorkGang* workers,
166 IsAlive* is_alive,
167 KeepAlive* keep_alive,
168 WeakProcessorPhaseTimes* phase_times) {
169 WeakProcessorTimeTracker tt(phase_times);
170
171 uint nworkers = ergo_workers(MIN2(workers->active_workers(),
172 phase_times->max_threads()));
173
174 GangTask task("Weak Processor", is_alive, keep_alive, phase_times, nworkers);
175 workers->run_task(&task, nworkers);
176 }
177
178 template<typename IsAlive, typename KeepAlive>
weak_oops_do(WorkGang * workers,IsAlive * is_alive,KeepAlive * keep_alive,uint indent_log)179 void WeakProcessor::weak_oops_do(WorkGang* workers,
180 IsAlive* is_alive,
181 KeepAlive* keep_alive,
182 uint indent_log) {
183 uint nworkers = ergo_workers(workers->active_workers());
184 WeakProcessorPhaseTimes pt(nworkers);
185 weak_oops_do(workers, is_alive, keep_alive, &pt);
186 pt.log_print_phases(indent_log);
187 }
188
189 #endif // SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
190