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