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