// 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