%PDF- %PDF-
| Direktori : /home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/heap/ |
| Current File : //home2/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/heap/marking-worklist.cc |
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/heap/marking-worklist.h"
#include <algorithm>
#include <cstddef>
#include <map>
#include "src/heap/cppgc-js/cpp-heap.h"
#include "src/heap/cppgc-js/cpp-marking-state.h"
#include "src/heap/marking-worklist-inl.h"
#include "src/objects/heap-object-inl.h"
#include "src/objects/heap-object.h"
#include "src/objects/instance-type-inl.h"
#include "src/objects/instance-type.h"
#include "src/objects/map.h"
#include "src/objects/objects-definitions.h"
namespace v8 {
namespace internal {
void MarkingWorklists::Clear() {
shared_.Clear();
on_hold_.Clear();
other_.Clear();
for (auto& cw : context_worklists_) {
cw.worklist->Clear();
}
ReleaseContextWorklists();
}
void MarkingWorklists::Print() {
PrintWorklist("shared", &shared_);
PrintWorklist("on_hold", &on_hold_);
}
void MarkingWorklists::CreateContextWorklists(
const std::vector<Address>& contexts) {
DCHECK(context_worklists_.empty());
if (contexts.empty()) return;
context_worklists_.reserve(contexts.size());
for (Address context : contexts) {
context_worklists_.push_back(
{context, std::make_unique<MarkingWorklist>()});
}
}
void MarkingWorklists::ReleaseContextWorklists() { context_worklists_.clear(); }
void MarkingWorklists::PrintWorklist(const char* worklist_name,
MarkingWorklist* worklist) {
#ifdef DEBUG
std::map<InstanceType, int> count;
int total_count = 0;
worklist->Iterate([&count, &total_count](Tagged<HeapObject> obj) {
++total_count;
count[obj->map()->instance_type()]++;
});
std::vector<std::pair<int, InstanceType>> rank;
rank.reserve(count.size());
for (const auto& i : count) {
rank.emplace_back(i.second, i.first);
}
std::map<InstanceType, std::string> instance_type_name;
#define INSTANCE_TYPE_NAME(name) instance_type_name[name] = #name;
INSTANCE_TYPE_LIST(INSTANCE_TYPE_NAME)
#undef INSTANCE_TYPE_NAME
std::sort(rank.begin(), rank.end(),
std::greater<std::pair<int, InstanceType>>());
PrintF("Worklist %s: %d\n", worklist_name, total_count);
for (auto i : rank) {
PrintF(" [%s]: %d\n", instance_type_name[i.second].c_str(), i.first);
}
#endif
}
constexpr Address MarkingWorklists::Local::kSharedContext;
constexpr Address MarkingWorklists::Local::kOtherContext;
constexpr std::nullptr_t MarkingWorklists::Local::kNoCppMarkingState;
namespace {
inline std::unordered_map<Address, std::unique_ptr<MarkingWorklist::Local>>
GetLocalPerContextMarkingWorklists(bool is_per_context_mode,
MarkingWorklists* global) {
if (!is_per_context_mode) return {};
std::unordered_map<Address, std::unique_ptr<MarkingWorklist::Local>>
worklist_by_context;
worklist_by_context.reserve(global->context_worklists().size());
for (auto& cw : global->context_worklists()) {
worklist_by_context[cw.context] =
std::make_unique<MarkingWorklist::Local>(*cw.worklist.get());
}
return worklist_by_context;
}
} // namespace
MarkingWorklists::Local::Local(
MarkingWorklists* global,
std::unique_ptr<CppMarkingState> cpp_marking_state)
: active_(&shared_),
shared_(*global->shared()),
on_hold_(*global->on_hold()),
active_context_(kSharedContext),
is_per_context_mode_(!global->context_worklists().empty()),
worklist_by_context_(
GetLocalPerContextMarkingWorklists(is_per_context_mode_, global)),
other_(*global->other()),
cpp_marking_state_(std::move(cpp_marking_state)) {}
void MarkingWorklists::Local::Publish() {
shared_.Publish();
on_hold_.Publish();
other_.Publish();
if (is_per_context_mode_) {
for (auto& cw : worklist_by_context_) {
cw.second->Publish();
}
}
PublishWrapper();
}
bool MarkingWorklists::Local::IsEmpty() {
// This function checks the on_hold_ worklist, so it works only for the main
// thread.
if (!active_->IsLocalEmpty() || !on_hold_.IsLocalEmpty() ||
!active_->IsGlobalEmpty() || !on_hold_.IsGlobalEmpty()) {
return false;
}
if (!is_per_context_mode_) {
return true;
}
if (!shared_.IsLocalEmpty() || !other_.IsLocalEmpty() ||
!shared_.IsGlobalEmpty() || !other_.IsGlobalEmpty()) {
return false;
}
for (auto& cw : worklist_by_context_) {
if (cw.first != active_context_ &&
!(cw.second->IsLocalEmpty() && cw.second->IsGlobalEmpty())) {
SwitchToContextImpl(cw.first, cw.second.get());
return false;
}
}
return true;
}
bool MarkingWorklists::Local::IsWrapperEmpty() const {
return !cpp_marking_state_ || cpp_marking_state_->IsLocalEmpty();
}
void MarkingWorklists::Local::ShareWork() {
if (!active_->IsLocalEmpty() && active_->IsGlobalEmpty()) {
active_->Publish();
}
if (is_per_context_mode_ && active_context_ != kSharedContext) {
if (!shared_.IsLocalEmpty() && shared_.IsGlobalEmpty()) {
shared_.Publish();
}
}
}
void MarkingWorklists::Local::PublishWork() {
DCHECK(!is_per_context_mode_);
shared_.Publish();
}
void MarkingWorklists::Local::MergeOnHold() { shared_.Merge(on_hold_); }
bool MarkingWorklists::Local::PopContext(Tagged<HeapObject>* object) {
DCHECK(is_per_context_mode_);
// As an optimization we first check only the local segments to avoid locks.
for (auto& cw : worklist_by_context_) {
if (cw.first != active_context_ && !cw.second->IsLocalEmpty()) {
SwitchToContextImpl(cw.first, cw.second.get());
return active_->Pop(object);
}
}
// All local segments are empty. Check global segments.
for (auto& cw : worklist_by_context_) {
if (cw.first != active_context_ && cw.second->Pop(object)) {
SwitchToContextImpl(cw.first, cw.second.get());
return true;
}
}
// All worklists are empty. Switch to the default shared worklist.
SwitchToContext(kSharedContext);
return false;
}
Address MarkingWorklists::Local::SwitchToContextSlow(Address context) {
const auto& it = worklist_by_context_.find(context);
if (V8_UNLIKELY(it == worklist_by_context_.end())) {
// The context passed is not an actual context:
// - Shared context that should use the explicit worklist.
// - This context was created during marking and should use the other
// bucket.
if (context == kSharedContext) {
SwitchToContextImpl(kSharedContext, &shared_);
} else {
SwitchToContextImpl(kOtherContext, &other_);
}
} else {
SwitchToContextImpl(it->first, it->second.get());
}
return active_context_;
}
Address MarkingWorklists::Local::SwitchToSharedForTesting() {
return SwitchToContext(kSharedContext);
}
} // namespace internal
} // namespace v8