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