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