| /* |
| * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP |
| #define SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP |
| |
| #include "gc/shared/weakProcessor.hpp" |
| |
| #include "classfile/stringTable.hpp" |
| #include "gc/shared/oopStorage.inline.hpp" |
| #include "gc/shared/oopStorageParState.inline.hpp" |
| #include "gc/shared/oopStorageSet.hpp" |
| #include "gc/shared/weakProcessorTimes.hpp" |
| #include "gc/shared/workerThread.hpp" |
| #include "prims/resolvedMethodTable.hpp" |
| #include "utilities/debug.hpp" |
| #include "utilities/enumIterator.hpp" |
| |
| class BoolObjectClosure; |
| class OopClosure; |
| |
| template <typename IsAlive, typename KeepAlive> |
| class WeakProcessor::CountingClosure : public Closure { |
| IsAlive* _is_alive; |
| KeepAlive* _keep_alive; |
| size_t _old_dead; |
| size_t _new_dead; |
| size_t _live; |
| |
| public: |
| CountingClosure(IsAlive* is_alive, KeepAlive* keep_alive) : |
| _is_alive(is_alive), |
| _keep_alive(keep_alive), |
| _old_dead(0), |
| _new_dead(0), |
| _live(0) |
| {} |
| |
| void do_oop(oop* p) { |
| oop obj = *p; |
| if (obj == nullptr) { |
| ++_old_dead; |
| } else if (_is_alive->do_object_b(obj)) { |
| _keep_alive->do_oop(p); |
| ++_live; |
| } else { |
| *p = nullptr; |
| ++_new_dead; |
| } |
| } |
| |
| size_t dead() const { return _old_dead + _new_dead; } |
| size_t new_dead() const { return _new_dead; } |
| size_t total() const { return dead() + _live; } |
| }; |
| |
| template<typename IsAlive, typename KeepAlive> |
| void WeakProcessor::Task::work(uint worker_id, |
| IsAlive* is_alive, |
| KeepAlive* keep_alive) { |
| assert(worker_id < _nworkers, |
| "worker_id (%u) exceeds task's configured workers (%u)", |
| worker_id, _nworkers); |
| |
| for (auto id : EnumRange<OopStorageSet::WeakId>()) { |
| CountingClosure<IsAlive, KeepAlive> cl(is_alive, keep_alive); |
| WeakProcessorParTimeTracker pt(_times, id, worker_id); |
| StorageState* cur_state = _storage_states.par_state(id); |
| assert(cur_state->storage() == OopStorageSet::storage(id), "invariant"); |
| cur_state->oops_do(&cl); |
| cur_state->increment_num_dead(cl.dead()); |
| if (_times != nullptr) { |
| _times->record_worker_items(worker_id, id, cl.new_dead(), cl.total()); |
| } |
| } |
| } |
| |
| class WeakProcessor::WeakOopsDoTask : public WorkerTask { |
| Task _task; |
| BoolObjectClosure* _is_alive; |
| OopClosure* _keep_alive; |
| void (*_erased_do_work)(WeakOopsDoTask* task, uint worker_id); |
| |
| template<typename IsAlive, typename KeepAlive> |
| static void erased_do_work(WeakOopsDoTask* task, uint worker_id) { |
| task->_task.work(worker_id, |
| static_cast<IsAlive*>(task->_is_alive), |
| static_cast<KeepAlive*>(task->_keep_alive)); |
| } |
| |
| public: |
| template<typename IsAlive, typename KeepAlive> |
| WeakOopsDoTask(const char* name, |
| IsAlive* is_alive, |
| KeepAlive* keep_alive, |
| WeakProcessorTimes* times, |
| uint nworkers) : |
| WorkerTask(name), |
| _task(times, nworkers), |
| _is_alive(is_alive), |
| _keep_alive(keep_alive), |
| _erased_do_work(&erased_do_work<IsAlive, KeepAlive>) |
| {} |
| |
| virtual void work(uint worker_id); |
| void report_num_dead() { _task.report_num_dead(); } |
| }; |
| |
| template<typename IsAlive, typename KeepAlive> |
| void WeakProcessor::weak_oops_do(WorkerThreads* workers, |
| IsAlive* is_alive, |
| KeepAlive* keep_alive, |
| WeakProcessorTimes* times) { |
| WeakProcessorTimeTracker tt(times); |
| |
| uint nworkers = ergo_workers(MIN2(workers->max_workers(), |
| times->max_threads())); |
| |
| WeakOopsDoTask task("Weak Processor", is_alive, keep_alive, times, nworkers); |
| workers->run_task(&task, nworkers); |
| task.report_num_dead(); |
| } |
| |
| template<typename IsAlive, typename KeepAlive> |
| void WeakProcessor::weak_oops_do(WorkerThreads* workers, |
| IsAlive* is_alive, |
| KeepAlive* keep_alive, |
| uint indent_log) { |
| uint nworkers = ergo_workers(workers->max_workers()); |
| WeakProcessorTimes times(nworkers); |
| weak_oops_do(workers, is_alive, keep_alive, ×); |
| times.log_subtotals(indent_log); // Caller logs total if desired. |
| } |
| |
| #endif // SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP |