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:
 50   CountingIsAliveClosure(IsAlive* cl) : _inner(cl), _num_dead(0), _num_total(0) { }
 51 
 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 
 59   size_t num_dead() const { return _num_dead; }
 60   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:
 71   CountingSkippedIsAliveClosure(IsAlive* is_alive, KeepAlive* keep_alive) :
 72     _counting_is_alive(is_alive), _keep_alive(keep_alive), _num_skipped(0) { }
 73 
 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 
 85   size_t num_dead() const { return _counting_is_alive.num_dead(); }
 86   size_t num_skipped() const { return _num_skipped; }
 87   size_t num_total() const { return _counting_is_alive.num_total() + num_skipped(); }
 88 };
 89 
 90 template<typename IsAlive, typename KeepAlive>
 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->can_notify()) {
125       cur_state.increment_dead_counter(cl.num_dead());
126     }
127   }
128 
129   _serial_phases_done.all_tasks_completed(_nworkers);
130 }
131 
132 class WeakProcessor::GangTask : public AbstractGangTask {
133   Task _task;
134   BoolObjectClosure* _is_alive;
135   OopClosure* _keep_alive;
136   void (*_erased_do_work)(GangTask* task, uint worker_id);
137 
138   template<typename IsAlive, typename KeepAlive>
139   static void erased_do_work(GangTask* task, uint worker_id) {
140     task->_task.work(worker_id,
141                      static_cast<IsAlive*>(task->_is_alive),
142                      static_cast<KeepAlive*>(task->_keep_alive));
143   }
144 
145 public:
146   template<typename IsAlive, typename KeepAlive>
147   GangTask(const char* name,
148            IsAlive* is_alive,
149            KeepAlive* keep_alive,
150            WeakProcessorPhaseTimes* phase_times,
151            uint nworkers) :
152     AbstractGangTask(name),
153     _task(phase_times, nworkers),
154     _is_alive(is_alive),
155     _keep_alive(keep_alive),
156     _erased_do_work(&erased_do_work<IsAlive, KeepAlive>)
157   {}
158 
159   virtual void work(uint worker_id);
160 };
161 
162 template<typename IsAlive, typename KeepAlive>
163 void WeakProcessor::weak_oops_do(WorkGang* workers,
164                                  IsAlive* is_alive,
165                                  KeepAlive* keep_alive,
166                                  WeakProcessorPhaseTimes* phase_times) {
167   WeakProcessorTimeTracker tt(phase_times);
168 
169   uint nworkers = ergo_workers(MIN2(workers->active_workers(),
170                                     phase_times->max_threads()));
171 
172   GangTask task("Weak Processor", is_alive, keep_alive, phase_times, nworkers);
173   workers->run_task(&task, nworkers);
174 }
175 
176 template<typename IsAlive, typename KeepAlive>
177 void WeakProcessor::weak_oops_do(WorkGang* workers,
178                                  IsAlive* is_alive,
179                                  KeepAlive* keep_alive,
180                                  uint indent_log) {
181   uint nworkers = ergo_workers(workers->active_workers());
182   WeakProcessorPhaseTimes pt(nworkers);
183   weak_oops_do(workers, is_alive, keep_alive, &pt);
184   pt.log_print_phases(indent_log);
185 }
186 
187 #endif // SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP