v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
handles.cc
Go to the documentation of this file.
1// Copyright 2012 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
6
7#include "src/api/api.h"
8#include "src/base/logging.h"
13#include "src/heap/base/stack.h"
16#include "src/roots/roots-inl.h"
19
20#ifdef V8_ENABLE_MAGLEV
22#endif // V8_ENABLE_MAGLEV
23
24#ifdef DEBUG
25// For GetIsolateFromWritableHeapObject.
27// For GetIsolateFromWritableObject.
29#endif
30
31#ifdef V8_ENABLE_DIRECT_HANDLE
32// For Isolate::Current() in indirect_handle.
34#endif
35
36namespace v8 {
37namespace internal {
38
39// Handles should be trivially copyable so that the contained value can be
40// efficiently passed by value in a register. This is important for two
41// reasons: better performance and a simpler ABI for generated code and fast
42// API calls.
46
47#ifdef V8_ENABLE_DIRECT_HANDLE
48
49#if !(defined(DEBUG) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI)
50// Direct handles should be trivially copyable, for the same reasons as above.
51// In debug builds, however, we want to define a non-default copy constructor
52// and destructor for debugging purposes. This makes them non-trivially
53// copyable. We only do it in builds where we can declare them as "trivial ABI",
54// which guarantees that they can be efficiently passed by value in a register.
57#endif
58
59// static
60Address* HandleBase::indirect_handle(Address object) {
62}
63
64// static
65Address* HandleBase::indirect_handle(Address object, Isolate* isolate) {
66 return HandleScope::CreateHandle(isolate, object);
67}
68
69// static
70Address* HandleBase::indirect_handle(Address object, LocalIsolate* isolate) {
71 return LocalHandleScope::GetHandle(isolate->heap(), object);
72}
73
74// static
75Address* HandleBase::indirect_handle(Address object, LocalHeap* local_heap) {
76 return LocalHandleScope::GetHandle(local_heap, object);
77}
78
79#endif // V8_ENABLE_DIRECT_HANDLE
80
81#ifdef DEBUG
82
86 if (IsSmi(object)) return true;
87 Tagged<HeapObject> heap_object = Cast<HeapObject>(object);
88 if (HeapLayout::InReadOnlySpace(heap_object)) return true;
89 Isolate* isolate = Isolate::Current();
90 RootIndex root_index;
91 if (isolate->roots_table().IsRootHandleLocation(location_, &root_index) &&
93 return true;
94 }
95 if (isolate->IsBuiltinTableHandleLocation(location_)) return true;
96 if (!AllowHandleDereference::IsAllowed()) return false;
97
98 // Allocations in the shared heap may be dereferenced by multiple threads.
99 if (HeapLayout::InWritableSharedSpace(heap_object)) return true;
100
101 // Deref is explicitly allowed from any thread. Used for running internal GC
102 // epilogue callbacks in the safepoint after a GC.
103 if (AllowHandleUsageOnAllThreads::IsAllowed()) return true;
104
105 LocalHeap* local_heap = isolate->CurrentLocalHeap();
106
107 // Local heap can't access handles when parked
108 if (!local_heap->IsHandleDereferenceAllowed()) {
109 StdoutStream{} << "Cannot dereference handle owned by "
110 << "non-running local heap\n";
111 return false;
112 }
113
114 // We are pretty strict with handle dereferences on background threads: A
115 // background local heap is only allowed to dereference its own local or
116 // persistent handles.
117 if (!local_heap->is_main_thread()) {
118 // The current thread owns the handle and thus can dereference it.
119 return local_heap->ContainsPersistentHandle(location_) ||
120 local_heap->ContainsLocalHandle(location_);
121 }
122 // If LocalHeap::Current() is null, we're on the main thread -- if we were to
123 // check main thread HandleScopes here, we should additionally check the
124 // main-thread LocalHeap.
125 DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
126
127 // TODO(leszeks): Check if the main thread owns this handle.
128 return true;
129}
130
131#ifdef V8_ENABLE_DIRECT_HANDLE
132bool DirectHandleBase::IsDereferenceAllowed() const {
134 Tagged<Object> object(obj_);
135 if (IsSmi(object)) return true;
136 Tagged<HeapObject> heap_object = Cast<HeapObject>(object);
137 if (HeapLayout::InReadOnlySpace(heap_object)) return true;
138 Isolate* isolate = Isolate::Current();
139 if (!AllowHandleDereference::IsAllowed()) return false;
140
141 // Allocations in the shared heap may be dereferenced by multiple threads.
142 if (HeapLayout::InWritableSharedSpace(heap_object)) return true;
143
144 // Deref is explicitly allowed from any thread. Used for running internal GC
145 // epilogue callbacks in the safepoint after a GC.
146 if (AllowHandleUsageOnAllThreads::IsAllowed()) return true;
147
148 LocalHeap* local_heap = isolate->CurrentLocalHeap();
149
150 // Local heap can't access handles when parked
151 if (!local_heap->IsHandleDereferenceAllowed()) {
152 StdoutStream{} << "Cannot dereference handle owned by "
153 << "non-running local heap\n";
154 return false;
155 }
156
157 // We are pretty strict with handle dereferences on background threads: A
158 // background local heap is only allowed to dereference its own local handles.
159 if (!local_heap->is_main_thread())
160 return ::heap::base::Stack::IsOnStack(this);
161
162 // If LocalHeap::Current() is null, we're on the main thread -- if we were to
163 // check main thread HandleScopes here, we should additionally check the
164 // main-thread LocalHeap.
165 DCHECK_EQ(ThreadId::Current(), isolate->thread_id());
166
167 return true;
168}
169#endif // V8_ENABLE_DIRECT_HANDLE
170
171#endif // DEBUG
172
174 HandleScopeImplementer* impl = isolate->handle_scope_implementer();
175 int n = static_cast<int>(impl->blocks()->size());
176 if (n == 0) return 0;
177 return ((n - 1) * kHandleBlockSize) +
178 static_cast<int>(
179 (isolate->handle_scope_data()->next - impl->blocks()->back()));
180}
181
183 HandleScopeData* current = isolate->handle_scope_data();
184
185 Address* result = current->next;
186
187 DCHECK(result == current->limit);
188 // Make sure there's at least one scope on the stack and that the
189 // top of the scope stack isn't a barrier.
190 if (!Utils::ApiCheck(current->level != current->sealed_level,
191 "v8::HandleScope::CreateHandle()",
192 "Cannot create a handle without a HandleScope")) {
193 return nullptr;
194 }
195 HandleScopeImplementer* impl = isolate->handle_scope_implementer();
196 // If there's more room in the last block, we use that. This is used
197 // for fast creation of scopes after scope barriers.
198 if (!impl->blocks()->empty()) {
199 Address* limit = &impl->blocks()->back()[kHandleBlockSize];
200 if (current->limit != limit) {
201 current->limit = limit;
202 DCHECK_LT(limit - current->next, kHandleBlockSize);
203 }
204 }
205
206 // If we still haven't found a slot for the handle, we extend the
207 // current handle scope by allocating a new handle block.
208 if (result == current->limit) {
209 // If there's a spare block, use it for growing the current scope.
210 result = impl->GetSpareOrNewBlock();
211 // Add the extension to the global list of blocks, but count the
212 // extension as part of the current scope.
213 impl->blocks()->push_back(result);
214 current->limit = &result[kHandleBlockSize];
215 }
216
217 return result;
218}
219
221 HandleScopeData* current = isolate->handle_scope_data();
222 isolate->handle_scope_implementer()->DeleteExtensions(current->limit);
223}
224
225#if defined(ENABLE_GLOBAL_HANDLE_ZAPPING) || \
226 defined(ENABLE_LOCAL_HANDLE_ZAPPING)
227void HandleScope::ZapRange(Address* start, Address* end, uintptr_t zap_value) {
229 for (Address* p = start; p != end; p++) {
230 *p = static_cast<Address>(zap_value);
231 }
232}
233#endif
234
236 return reinterpret_cast<Address>(&isolate->handle_scope_data()->level);
237}
238
240 return reinterpret_cast<Address>(&isolate->handle_scope_data()->next);
241}
242
244 return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit);
245}
246
247} // namespace internal
248} // namespace v8
DirectHandle< JSObject > obj_
static V8_INLINE bool ApiCheck(bool condition, const char *location, const char *message)
Definition api.h:214
V8_INLINE bool IsDereferenceAllowed() const
Definition handles.h:128
static V8_EXPORT_PRIVATE int NumberOfHandles(Isolate *isolate)
Definition handles.cc:173
static Address current_limit_address(Isolate *isolate)
Definition handles.cc:243
static V8_EXPORT_PRIVATE void DeleteExtensions(Isolate *isolate)
Definition handles.cc:220
static Address current_next_address(Isolate *isolate)
Definition handles.cc:239
V8_EXPORT_PRIVATE static V8_NOINLINE Address * Extend(Isolate *isolate)
Definition handles.cc:182
static V8_INLINE Address * CreateHandle(Isolate *isolate, Address value)
static Address current_level_address(Isolate *isolate)
Definition handles.cc:235
static V8_INLINE bool InWritableSharedSpace(Tagged< HeapObject > object)
static V8_INLINE bool InReadOnlySpace(Tagged< HeapObject > object)
static V8_INLINE Isolate * Current()
Definition isolate-inl.h:35
static V8_INLINE Address * GetHandle(LocalHeap *local_heap, Address value)
static constexpr bool IsImmortalImmovable(RootIndex root_index)
Definition roots.h:616
static ThreadId Current()
Definition thread-id.h:32
int start
int end
ZoneVector< RpoNumber > & result
constexpr Address kTaggedNullAddress
Definition handles.h:53
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
kInterpreterTrampolineOffset Tagged< HeapObject >
const int kHandleBlockSize
Definition api.h:444
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define ASSERT_TRIVIALLY_COPYABLE(T)
Definition macros.h:267