Line data Source code
1 : // Copyright 2011 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 : #ifndef V8_HANDLES_H_
6 : #define V8_HANDLES_H_
7 :
8 : #include <type_traits>
9 :
10 : #include "include/v8.h"
11 : #include "src/base/functional.h"
12 : #include "src/base/macros.h"
13 : #include "src/checks.h"
14 : #include "src/globals.h"
15 : #include "src/zone/zone.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : // Forward declarations.
21 : class DeferredHandles;
22 : class HandleScopeImplementer;
23 : class Isolate;
24 : template <typename T>
25 : class MaybeHandle;
26 : class Object;
27 : class OrderedHashMap;
28 : class OrderedHashSet;
29 : class OrderedNameDictionary;
30 : class SmallOrderedHashMap;
31 : class SmallOrderedHashSet;
32 : class SmallOrderedNameDictionary;
33 : class WasmExportedFunctionData;
34 :
35 : // ----------------------------------------------------------------------------
36 : // Base class for Handle instantiations. Don't use directly.
37 : class HandleBase {
38 : public:
39 944283885 : V8_INLINE explicit HandleBase(Address* location) : location_(location) {}
40 : V8_INLINE explicit HandleBase(Address object, Isolate* isolate);
41 :
42 : // Check if this handle refers to the exact same object as the other handle.
43 : V8_INLINE bool is_identical_to(const HandleBase that) const {
44 : // Dereferencing deferred handles to check object equality is safe.
45 : SLOW_DCHECK((this->location_ == nullptr ||
46 : this->IsDereferenceAllowed(NO_DEFERRED_CHECK)) &&
47 : (that.location_ == nullptr ||
48 : that.IsDereferenceAllowed(NO_DEFERRED_CHECK)));
49 35922902 : if (this->location_ == that.location_) return true;
50 23332953 : if (this->location_ == nullptr || that.location_ == nullptr) return false;
51 23292419 : return *this->location_ == *that.location_;
52 : }
53 :
54 490521868 : V8_INLINE bool is_null() const { return location_ == nullptr; }
55 :
56 : // Returns the raw address where this handle is stored. This should only be
57 : // used for hashing handles; do not ever try to dereference it.
58 : V8_INLINE Address address() const { return bit_cast<Address>(location_); }
59 :
60 : protected:
61 : // Provides the C++ dereference operator.
62 : V8_INLINE Address operator*() const {
63 : SLOW_DCHECK(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
64 23578972615 : return *location_;
65 : }
66 :
67 : // Returns the address to where the raw pointer is stored.
68 : V8_INLINE Address* location() const {
69 : SLOW_DCHECK(location_ == nullptr ||
70 : IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
71 49601623 : return location_;
72 : }
73 :
74 : enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK };
75 : #ifdef DEBUG
76 : bool V8_EXPORT_PRIVATE IsDereferenceAllowed(DereferenceCheckMode mode) const;
77 : #else
78 : V8_INLINE
79 : bool V8_EXPORT_PRIVATE IsDereferenceAllowed(DereferenceCheckMode mode) const {
80 : return true;
81 : }
82 : #endif // DEBUG
83 :
84 : // This uses type Address* as opposed to a pointer type to a typed
85 : // wrapper class, because it doesn't point to instances of such a
86 : // wrapper class. Design overview: https://goo.gl/Ph4CGz
87 : Address* location_;
88 : };
89 :
90 :
91 : // ----------------------------------------------------------------------------
92 : // A Handle provides a reference to an object that survives relocation by
93 : // the garbage collector.
94 : //
95 : // Handles are only valid within a HandleScope. When a handle is created
96 : // for an object a cell is allocated in the current HandleScope.
97 : //
98 : // Also note that Handles do not provide default equality comparison or hashing
99 : // operators on purpose. Such operators would be misleading, because intended
100 : // semantics is ambiguous between Handle location and object identity. Instead
101 : // use either {is_identical_to} or {location} explicitly.
102 : template <typename T>
103 : class Handle final : public HandleBase {
104 : public:
105 : V8_INLINE explicit Handle(Address* location = nullptr)
106 : : HandleBase(location) {
107 : // Type check:
108 : static_assert(std::is_convertible<T*, Object*>::value,
109 : "static type violation");
110 : // TODO(jkummerow): Runtime type check here as a SLOW_DCHECK?
111 : }
112 :
113 : V8_INLINE Handle(T object, Isolate* isolate);
114 :
115 : // Allocate a new handle for the object, do not canonicalize.
116 : V8_INLINE static Handle<T> New(T object, Isolate* isolate);
117 :
118 : // Constructor for handling automatic up casting.
119 : // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
120 : template <typename S, typename = typename std::enable_if<
121 : std::is_convertible<S*, T*>::value>::type>
122 645262530 : V8_INLINE Handle(Handle<S> handle) : HandleBase(handle) {}
123 :
124 : V8_INLINE T operator->() const {
125 : return operator*();
126 : }
127 :
128 : // Provides the C++ dereference operator.
129 : V8_INLINE T operator*() const {
130 : // unchecked_cast because we rather trust Handle<T> to contain a T than
131 : // include all the respective -inl.h headers for SLOW_DCHECKs.
132 2684571 : return T::unchecked_cast(Object(HandleBase::operator*()));
133 : }
134 :
135 : // Returns the address to where the raw pointer is stored.
136 : V8_INLINE Address* location() const { return HandleBase::location(); }
137 :
138 : template <typename S>
139 : inline static const Handle<T> cast(Handle<S> that);
140 :
141 : // TODO(yangguo): Values that contain empty handles should be declared as
142 : // MaybeHandle to force validation before being used as handles.
143 10792605 : static const Handle<T> null() { return Handle<T>(); }
144 :
145 : // Location equality.
146 3844327 : bool equals(Handle<T> other) const { return address() == other.address(); }
147 :
148 : // Provide function object for location equality comparison.
149 : struct equal_to {
150 : V8_INLINE bool operator()(Handle<T> lhs, Handle<T> rhs) const {
151 3844327 : return lhs.equals(rhs);
152 : }
153 : };
154 :
155 : // Provide function object for location hashing.
156 : struct hash {
157 : V8_INLINE size_t operator()(Handle<T> const& handle) const {
158 : return base::hash<Address>()(handle.address());
159 : }
160 : };
161 :
162 : private:
163 : // Handles of different classes are allowed to access each other's location_.
164 : template <typename>
165 : friend class Handle;
166 : // MaybeHandle is allowed to access location_.
167 : template <typename>
168 : friend class MaybeHandle;
169 : };
170 :
171 : template <typename T>
172 : inline std::ostream& operator<<(std::ostream& os, Handle<T> handle);
173 :
174 : // ----------------------------------------------------------------------------
175 : // A stack-allocated class that governs a number of local handles.
176 : // After a handle scope has been created, all local handles will be
177 : // allocated within that handle scope until either the handle scope is
178 : // deleted or another handle scope is created. If there is already a
179 : // handle scope and a new one is created, all allocations will take
180 : // place in the new handle scope until it is deleted. After that,
181 : // new handles will again be allocated in the original handle scope.
182 : //
183 : // After the handle scope of a local handle has been deleted the
184 : // garbage collector will no longer track the object stored in the
185 : // handle and may deallocate it. The behavior of accessing a handle
186 : // for which the handle scope has been deleted is undefined.
187 : class HandleScope {
188 : public:
189 : explicit inline HandleScope(Isolate* isolate);
190 :
191 : inline ~HandleScope();
192 :
193 : // Counts the number of allocated handles.
194 : V8_EXPORT_PRIVATE static int NumberOfHandles(Isolate* isolate);
195 :
196 : // Create a new handle or lookup a canonical handle.
197 : V8_INLINE static Address* GetHandle(Isolate* isolate, Address value);
198 :
199 : // Creates a new handle with the given value.
200 : V8_INLINE static Address* CreateHandle(Isolate* isolate, Address value);
201 :
202 : // Deallocates any extensions used by the current scope.
203 : V8_EXPORT_PRIVATE static void DeleteExtensions(Isolate* isolate);
204 :
205 : static Address current_next_address(Isolate* isolate);
206 : static Address current_limit_address(Isolate* isolate);
207 : static Address current_level_address(Isolate* isolate);
208 :
209 : // Closes the HandleScope (invalidating all handles
210 : // created in the scope of the HandleScope) and returns
211 : // a Handle backed by the parent scope holding the
212 : // value of the argument handle.
213 : template <typename T>
214 : Handle<T> CloseAndEscape(Handle<T> handle_value);
215 :
216 : Isolate* isolate() { return isolate_; }
217 :
218 : // Limit for number of handles with --check-handle-count. This is
219 : // large enough to compile natives and pass unit tests with some
220 : // slack for future changes to natives.
221 : static const int kCheckHandleThreshold = 30 * 1024;
222 :
223 : private:
224 : // Prevent heap allocation or illegal handle scopes.
225 : void* operator new(size_t size);
226 : void operator delete(void* size_t);
227 :
228 : Isolate* isolate_;
229 : Address* prev_next_;
230 : Address* prev_limit_;
231 :
232 : // Close the handle scope resetting limits to a previous state.
233 : static inline void CloseScope(Isolate* isolate, Address* prev_next,
234 : Address* prev_limit);
235 :
236 : // Extend the handle scope making room for more handles.
237 : V8_EXPORT_PRIVATE static Address* Extend(Isolate* isolate);
238 :
239 : #ifdef ENABLE_HANDLE_ZAPPING
240 : // Zaps the handles in the half-open interval [start, end).
241 : V8_EXPORT_PRIVATE static void ZapRange(Address* start, Address* end);
242 : #endif
243 :
244 : friend class v8::HandleScope;
245 : friend class DeferredHandles;
246 : friend class DeferredHandleScope;
247 : friend class HandleScopeImplementer;
248 : friend class Isolate;
249 :
250 : DISALLOW_COPY_AND_ASSIGN(HandleScope);
251 : };
252 :
253 :
254 : // Forward declarations for CanonicalHandleScope.
255 : template <typename V, class AllocationPolicy>
256 : class IdentityMap;
257 : class RootIndexMap;
258 :
259 :
260 : // A CanonicalHandleScope does not open a new HandleScope. It changes the
261 : // existing HandleScope so that Handles created within are canonicalized.
262 : // This does not apply to nested inner HandleScopes unless a nested
263 : // CanonicalHandleScope is introduced. Handles are only canonicalized within
264 : // the same CanonicalHandleScope, but not across nested ones.
265 : class V8_EXPORT_PRIVATE CanonicalHandleScope final {
266 : public:
267 : explicit CanonicalHandleScope(Isolate* isolate);
268 : ~CanonicalHandleScope();
269 :
270 : private:
271 : Address* Lookup(Address object);
272 :
273 : Isolate* isolate_;
274 : Zone zone_;
275 : RootIndexMap* root_index_map_;
276 : IdentityMap<Address*, ZoneAllocationPolicy>* identity_map_;
277 : // Ordinary nested handle scopes within the current one are not canonical.
278 : int canonical_level_;
279 : // We may have nested canonical scopes. Handles are canonical within each one.
280 : CanonicalHandleScope* prev_canonical_scope_;
281 :
282 : friend class HandleScope;
283 : };
284 :
285 : // A DeferredHandleScope is a HandleScope in which handles are not destroyed
286 : // when the DeferredHandleScope is left. Instead the DeferredHandleScope has to
287 : // be detached with {Detach}, and the result of {Detach} has to be destroyed
288 : // explicitly. A DeferredHandleScope should only be used with the following
289 : // design pattern:
290 : // 1) Open a HandleScope (not a DeferredHandleScope).
291 : // HandleScope scope(isolate_);
292 : // 2) Create handles.
293 : // Handle<Object> h1 = handle(object1, isolate);
294 : // Handle<Object> h2 = handle(object2, isolate);
295 : // 3) Open a DeferredHandleScope.
296 : // DeferredHandleScope deferred_scope(isolate);
297 : // 4) Reopen handles which should be in the DeferredHandleScope, e.g only h1.
298 : // h1 = handle(*h1, isolate);
299 : // 5) Detach the DeferredHandleScope.
300 : // DeferredHandles* deferred_handles = deferred_scope.Detach();
301 : // 6) Destroy the deferred handles.
302 : // delete deferred_handles;
303 : //
304 : // Note: A DeferredHandleScope must not be opened within a DeferredHandleScope.
305 : class V8_EXPORT_PRIVATE DeferredHandleScope final {
306 : public:
307 : explicit DeferredHandleScope(Isolate* isolate);
308 : // The DeferredHandles object returned stores the Handles created
309 : // since the creation of this DeferredHandleScope. The Handles are
310 : // alive as long as the DeferredHandles object is alive.
311 : DeferredHandles* Detach();
312 : ~DeferredHandleScope();
313 :
314 : private:
315 : Address* prev_limit_;
316 : Address* prev_next_;
317 : HandleScopeImplementer* impl_;
318 :
319 : #ifdef DEBUG
320 : bool handles_detached_ = false;
321 : int prev_level_;
322 : #endif
323 :
324 : friend class HandleScopeImplementer;
325 : };
326 :
327 :
328 : // Seal off the current HandleScope so that new handles can only be created
329 : // if a new HandleScope is entered.
330 : class SealHandleScope final {
331 : public:
332 : #ifndef DEBUG
333 : explicit SealHandleScope(Isolate* isolate) {}
334 : ~SealHandleScope() = default;
335 : #else
336 : explicit inline SealHandleScope(Isolate* isolate);
337 : inline ~SealHandleScope();
338 : private:
339 : Isolate* isolate_;
340 : Address* prev_limit_;
341 : int prev_sealed_level_;
342 : #endif
343 : };
344 :
345 :
346 : struct HandleScopeData final {
347 : Address* next;
348 : Address* limit;
349 : int level;
350 : int sealed_level;
351 : CanonicalHandleScope* canonical_scope;
352 :
353 : void Initialize() {
354 94878 : next = limit = nullptr;
355 94878 : sealed_level = level = 0;
356 94878 : canonical_scope = nullptr;
357 : }
358 : };
359 :
360 : } // namespace internal
361 : } // namespace v8
362 :
363 : #endif // V8_HANDLES_H_
|