blob: df9a6d951c9b18dddb066ad2e0f53ed20382b171 [file] [log] [blame]
// Copyright 2020 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/handles/persistent-handles.h"
#include "src/api/api.h"
#include "src/heap/heap-inl.h"
#include "src/heap/safepoint.h"
#include "src/utils/allocation.h"
namespace v8 {
namespace internal {
PersistentHandles::PersistentHandles(Isolate* isolate)
: isolate_(isolate),
block_next_(nullptr),
block_limit_(nullptr),
prev_(nullptr),
next_(nullptr) {
isolate->persistent_handles_list()->Add(this);
}
PersistentHandles::~PersistentHandles() {
isolate_->persistent_handles_list()->Remove(this);
for (Address* block_start : blocks_) {
#if ENABLE_HANDLE_ZAPPING
HandleScope::ZapRange(block_start, block_start + kHandleBlockSize);
#endif
DeleteArray(block_start);
}
}
#ifdef DEBUG
void PersistentHandles::Attach(LocalHeap* local_heap) {
DCHECK_NULL(owner_);
owner_ = local_heap;
}
void PersistentHandles::Detach() {
DCHECK_NOT_NULL(owner_);
owner_ = nullptr;
}
void PersistentHandles::CheckOwnerIsNotParked() {
if (owner_) DCHECK(!owner_->IsParked());
}
bool PersistentHandles::Contains(Address* location) {
auto it = ordered_blocks_.upper_bound(location);
if (it == ordered_blocks_.begin()) return false;
--it;
DCHECK_LE(*it, location);
if (*it == blocks_.back()) {
// The last block is a special case because it may have
// less than block_size_ handles.
return location < block_next_;
}
return location < *it + kHandleBlockSize;
}
#endif
void PersistentHandles::AddBlock() {
DCHECK_EQ(block_next_, block_limit_);
Address* block_start = NewArray<Address>(kHandleBlockSize);
blocks_.push_back(block_start);
block_next_ = block_start;
block_limit_ = block_start + kHandleBlockSize;
#ifdef DEBUG
ordered_blocks_.insert(block_start);
#endif
}
Address* PersistentHandles::GetHandle(Address value) {
if (block_next_ == block_limit_) {
AddBlock();
}
DCHECK_LT(block_next_, block_limit_);
*block_next_ = value;
return block_next_++;
}
void PersistentHandles::Iterate(RootVisitor* visitor) {
for (int i = 0; i < static_cast<int>(blocks_.size()) - 1; i++) {
Address* block_start = blocks_[i];
Address* block_end = block_start + kHandleBlockSize;
visitor->VisitRootPointers(Root::kHandleScope, nullptr,
FullObjectSlot(block_start),
FullObjectSlot(block_end));
}
if (!blocks_.empty()) {
Address* block_start = blocks_.back();
visitor->VisitRootPointers(Root::kHandleScope, nullptr,
FullObjectSlot(block_start),
FullObjectSlot(block_next_));
}
}
void PersistentHandlesList::Add(PersistentHandles* persistent_handles) {
base::MutexGuard guard(&persistent_handles_mutex_);
if (persistent_handles_head_)
persistent_handles_head_->prev_ = persistent_handles;
persistent_handles->prev_ = nullptr;
persistent_handles->next_ = persistent_handles_head_;
persistent_handles_head_ = persistent_handles;
}
void PersistentHandlesList::Remove(PersistentHandles* persistent_handles) {
base::MutexGuard guard(&persistent_handles_mutex_);
if (persistent_handles->next_)
persistent_handles->next_->prev_ = persistent_handles->prev_;
if (persistent_handles->prev_)
persistent_handles->prev_->next_ = persistent_handles->next_;
else
persistent_handles_head_ = persistent_handles->next_;
}
void PersistentHandlesList::Iterate(RootVisitor* visitor, Isolate* isolate) {
DCHECK_IMPLIES(FLAG_local_heaps, isolate->heap()->safepoint()->IsActive());
base::MutexGuard guard(&persistent_handles_mutex_);
for (PersistentHandles* current = persistent_handles_head_; current;
current = current->next_) {
current->Iterate(visitor);
}
}
PersistentHandlesScope::PersistentHandlesScope(Isolate* isolate)
: impl_(isolate->handle_scope_implementer()) {
impl_->BeginDeferredScope();
HandleScopeData* data = impl_->isolate()->handle_scope_data();
Address* new_next = impl_->GetSpareOrNewBlock();
Address* new_limit = &new_next[kHandleBlockSize];
// Check that at least one HandleScope with at least one Handle in it exists,
// see the class description.
DCHECK(!impl_->blocks()->empty());
// Check that we are not in a SealHandleScope.
DCHECK(data->limit == &impl_->blocks()->back()[kHandleBlockSize]);
impl_->blocks()->push_back(new_next);
#ifdef DEBUG
prev_level_ = data->level;
#endif
data->level++;
prev_limit_ = data->limit;
prev_next_ = data->next;
data->next = new_next;
data->limit = new_limit;
}
PersistentHandlesScope::~PersistentHandlesScope() {
DCHECK(handles_detached_);
impl_->isolate()->handle_scope_data()->level--;
DCHECK_EQ(impl_->isolate()->handle_scope_data()->level, prev_level_);
}
std::unique_ptr<PersistentHandles> PersistentHandlesScope::Detach() {
std::unique_ptr<PersistentHandles> ph = impl_->DetachPersistent(prev_limit_);
HandleScopeData* data = impl_->isolate()->handle_scope_data();
data->next = prev_next_;
data->limit = prev_limit_;
#ifdef DEBUG
handles_detached_ = true;
#endif
return ph;
}
} // namespace internal
} // namespace v8