• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/handles/persistent-handles.h"
6 
7 #include "src/api/api.h"
8 #include "src/heap/heap-inl.h"
9 #include "src/heap/safepoint.h"
10 #include "src/utils/allocation.h"
11 
12 namespace v8 {
13 namespace internal {
14 
PersistentHandles(Isolate * isolate)15 PersistentHandles::PersistentHandles(Isolate* isolate)
16     : isolate_(isolate),
17       block_next_(nullptr),
18       block_limit_(nullptr),
19       prev_(nullptr),
20       next_(nullptr) {
21   isolate->persistent_handles_list()->Add(this);
22 }
23 
~PersistentHandles()24 PersistentHandles::~PersistentHandles() {
25   isolate_->persistent_handles_list()->Remove(this);
26 
27   for (Address* block_start : blocks_) {
28 #if ENABLE_HANDLE_ZAPPING
29     HandleScope::ZapRange(block_start, block_start + kHandleBlockSize);
30 #endif
31     DeleteArray(block_start);
32   }
33 }
34 
35 #ifdef DEBUG
Attach(LocalHeap * local_heap)36 void PersistentHandles::Attach(LocalHeap* local_heap) {
37   DCHECK_NULL(owner_);
38   owner_ = local_heap;
39 }
40 
Detach()41 void PersistentHandles::Detach() {
42   DCHECK_NOT_NULL(owner_);
43   owner_ = nullptr;
44 }
45 
CheckOwnerIsNotParked()46 void PersistentHandles::CheckOwnerIsNotParked() {
47   if (owner_) DCHECK(!owner_->IsParked());
48 }
49 
Contains(Address * location)50 bool PersistentHandles::Contains(Address* location) {
51   auto it = ordered_blocks_.upper_bound(location);
52   if (it == ordered_blocks_.begin()) return false;
53   --it;
54   DCHECK_LE(*it, location);
55   if (*it == blocks_.back()) {
56     // The last block is a special case because it may have
57     // less than block_size_ handles.
58     return location < block_next_;
59   }
60   return location < *it + kHandleBlockSize;
61 }
62 #endif
63 
AddBlock()64 void PersistentHandles::AddBlock() {
65   DCHECK_EQ(block_next_, block_limit_);
66 
67   Address* block_start = NewArray<Address>(kHandleBlockSize);
68   blocks_.push_back(block_start);
69 
70   block_next_ = block_start;
71   block_limit_ = block_start + kHandleBlockSize;
72 
73 #ifdef DEBUG
74   ordered_blocks_.insert(block_start);
75 #endif
76 }
77 
GetHandle(Address value)78 Address* PersistentHandles::GetHandle(Address value) {
79   if (block_next_ == block_limit_) {
80     AddBlock();
81   }
82 
83   DCHECK_LT(block_next_, block_limit_);
84   *block_next_ = value;
85   return block_next_++;
86 }
87 
Iterate(RootVisitor * visitor)88 void PersistentHandles::Iterate(RootVisitor* visitor) {
89   for (int i = 0; i < static_cast<int>(blocks_.size()) - 1; i++) {
90     Address* block_start = blocks_[i];
91     Address* block_end = block_start + kHandleBlockSize;
92     visitor->VisitRootPointers(Root::kHandleScope, nullptr,
93                                FullObjectSlot(block_start),
94                                FullObjectSlot(block_end));
95   }
96 
97   if (!blocks_.empty()) {
98     Address* block_start = blocks_.back();
99     visitor->VisitRootPointers(Root::kHandleScope, nullptr,
100                                FullObjectSlot(block_start),
101                                FullObjectSlot(block_next_));
102   }
103 }
104 
Add(PersistentHandles * persistent_handles)105 void PersistentHandlesList::Add(PersistentHandles* persistent_handles) {
106   base::MutexGuard guard(&persistent_handles_mutex_);
107   if (persistent_handles_head_)
108     persistent_handles_head_->prev_ = persistent_handles;
109   persistent_handles->prev_ = nullptr;
110   persistent_handles->next_ = persistent_handles_head_;
111   persistent_handles_head_ = persistent_handles;
112 }
113 
Remove(PersistentHandles * persistent_handles)114 void PersistentHandlesList::Remove(PersistentHandles* persistent_handles) {
115   base::MutexGuard guard(&persistent_handles_mutex_);
116   if (persistent_handles->next_)
117     persistent_handles->next_->prev_ = persistent_handles->prev_;
118   if (persistent_handles->prev_)
119     persistent_handles->prev_->next_ = persistent_handles->next_;
120   else
121     persistent_handles_head_ = persistent_handles->next_;
122 }
123 
Iterate(RootVisitor * visitor,Isolate * isolate)124 void PersistentHandlesList::Iterate(RootVisitor* visitor, Isolate* isolate) {
125   isolate->heap()->safepoint()->AssertActive();
126   base::MutexGuard guard(&persistent_handles_mutex_);
127   for (PersistentHandles* current = persistent_handles_head_; current;
128        current = current->next_) {
129     current->Iterate(visitor);
130   }
131 }
132 
PersistentHandlesScope(Isolate * isolate)133 PersistentHandlesScope::PersistentHandlesScope(Isolate* isolate)
134     : impl_(isolate->handle_scope_implementer()) {
135   impl_->BeginDeferredScope();
136   HandleScopeData* data = impl_->isolate()->handle_scope_data();
137   Address* new_next = impl_->GetSpareOrNewBlock();
138   Address* new_limit = &new_next[kHandleBlockSize];
139   // Check that at least one HandleScope with at least one Handle in it exists,
140   // see the class description.
141   DCHECK(!impl_->blocks()->empty());
142   // Check that we are not in a SealHandleScope.
143   DCHECK(data->limit == &impl_->blocks()->back()[kHandleBlockSize]);
144   impl_->blocks()->push_back(new_next);
145 
146 #ifdef DEBUG
147   prev_level_ = data->level;
148 #endif
149   data->level++;
150   prev_limit_ = data->limit;
151   prev_next_ = data->next;
152   data->next = new_next;
153   data->limit = new_limit;
154 }
155 
~PersistentHandlesScope()156 PersistentHandlesScope::~PersistentHandlesScope() {
157   DCHECK(handles_detached_);
158   impl_->isolate()->handle_scope_data()->level--;
159   DCHECK_EQ(impl_->isolate()->handle_scope_data()->level, prev_level_);
160 }
161 
Detach()162 std::unique_ptr<PersistentHandles> PersistentHandlesScope::Detach() {
163   std::unique_ptr<PersistentHandles> ph = impl_->DetachPersistent(prev_limit_);
164   HandleScopeData* data = impl_->isolate()->handle_scope_data();
165   data->next = prev_next_;
166   data->limit = prev_limit_;
167 #ifdef DEBUG
168   handles_detached_ = true;
169 #endif
170   return ph;
171 }
172 
173 }  // namespace internal
174 }  // namespace v8
175