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