• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 class Object;
25 
26 
27 // ----------------------------------------------------------------------------
28 // Base class for Handle instantiations.  Don't use directly.
29 class HandleBase {
30  public:
HandleBase(Object ** location)31   V8_INLINE explicit HandleBase(Object** location) : location_(location) {}
32   V8_INLINE explicit HandleBase(Object* object, Isolate* isolate);
33 
34   // Check if this handle refers to the exact same object as the other handle.
is_identical_to(const HandleBase that)35   V8_INLINE bool is_identical_to(const HandleBase that) const {
36     // Dereferencing deferred handles to check object equality is safe.
37     SLOW_DCHECK((this->location_ == nullptr ||
38                  this->IsDereferenceAllowed(NO_DEFERRED_CHECK)) &&
39                 (that.location_ == nullptr ||
40                  that.IsDereferenceAllowed(NO_DEFERRED_CHECK)));
41     if (this->location_ == that.location_) return true;
42     if (this->location_ == NULL || that.location_ == NULL) return false;
43     return *this->location_ == *that.location_;
44   }
45 
is_null()46   V8_INLINE bool is_null() const { return location_ == nullptr; }
47 
48   // Returns the raw address where this handle is stored. This should only be
49   // used for hashing handles; do not ever try to dereference it.
address()50   V8_INLINE Address address() const { return bit_cast<Address>(location_); }
51 
52  protected:
53   // Provides the C++ dereference operator.
54   V8_INLINE Object* operator*() const {
55     SLOW_DCHECK(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
56     return *location_;
57   }
58 
59   // Returns the address to where the raw pointer is stored.
location()60   V8_INLINE Object** location() const {
61     SLOW_DCHECK(location_ == nullptr ||
62                 IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
63     return location_;
64   }
65 
66   enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK };
67 #ifdef DEBUG
68   bool V8_EXPORT_PRIVATE IsDereferenceAllowed(DereferenceCheckMode mode) const;
69 #else
70   V8_INLINE
IsDereferenceAllowed(DereferenceCheckMode mode)71   bool V8_EXPORT_PRIVATE IsDereferenceAllowed(DereferenceCheckMode mode) const {
72     return true;
73   }
74 #endif  // DEBUG
75 
76   Object** location_;
77 };
78 
79 
80 // ----------------------------------------------------------------------------
81 // A Handle provides a reference to an object that survives relocation by
82 // the garbage collector.
83 //
84 // Handles are only valid within a HandleScope. When a handle is created
85 // for an object a cell is allocated in the current HandleScope.
86 //
87 // Also note that Handles do not provide default equality comparison or hashing
88 // operators on purpose. Such operators would be misleading, because intended
89 // semantics is ambiguous between Handle location and object identity. Instead
90 // use either {is_identical_to} or {location} explicitly.
91 template <typename T>
92 class Handle final : public HandleBase {
93  public:
94   V8_INLINE explicit Handle(T** location = nullptr)
HandleBase(reinterpret_cast<Object ** > (location))95       : HandleBase(reinterpret_cast<Object**>(location)) {
96     // Type check:
97     static_assert(std::is_base_of<Object, T>::value, "static type violation");
98   }
99 
Handle(T * object)100   V8_INLINE explicit Handle(T* object) : Handle(object, object->GetIsolate()) {}
Handle(T * object,Isolate * isolate)101   V8_INLINE Handle(T* object, Isolate* isolate) : HandleBase(object, isolate) {}
102 
103   // Allocate a new handle for the object, do not canonicalize.
104   V8_INLINE static Handle<T> New(T* object, Isolate* isolate);
105 
106   // Constructor for handling automatic up casting.
107   // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
108   template <typename S>
Handle(Handle<S> handle)109   V8_INLINE Handle(Handle<S> handle)
110       : HandleBase(handle) {
111     T* a = nullptr;
112     S* b = nullptr;
113     a = b;  // Fake assignment to enforce type checks.
114     USE(a);
115   }
116 
117   V8_INLINE T* operator->() const { return operator*(); }
118 
119   // Provides the C++ dereference operator.
120   V8_INLINE T* operator*() const {
121     return reinterpret_cast<T*>(HandleBase::operator*());
122   }
123 
124   // Returns the address to where the raw pointer is stored.
location()125   V8_INLINE T** location() const {
126     return reinterpret_cast<T**>(HandleBase::location());
127   }
128 
129   template <typename S>
cast(Handle<S> that)130   static const Handle<T> cast(Handle<S> that) {
131     T::cast(*reinterpret_cast<T**>(that.location_));
132     return Handle<T>(reinterpret_cast<T**>(that.location_));
133   }
134 
135   // TODO(yangguo): Values that contain empty handles should be declared as
136   // MaybeHandle to force validation before being used as handles.
null()137   static const Handle<T> null() { return Handle<T>(); }
138 
139   // Provide function object for location equality comparison.
140   struct equal_to : public std::binary_function<Handle<T>, Handle<T>, bool> {
operatorequal_to141     V8_INLINE bool operator()(Handle<T> lhs, Handle<T> rhs) const {
142       return lhs.address() == rhs.address();
143     }
144   };
145 
146   // Provide function object for location hashing.
147   struct hash : public std::unary_function<Handle<T>, size_t> {
operatorhash148     V8_INLINE size_t operator()(Handle<T> const& handle) const {
149       return base::hash<void*>()(handle.address());
150     }
151   };
152 
153  private:
154   // Handles of different classes are allowed to access each other's location_.
155   template <typename>
156   friend class Handle;
157   // MaybeHandle is allowed to access location_.
158   template <typename>
159   friend class MaybeHandle;
160 };
161 
162 template <typename T>
163 inline std::ostream& operator<<(std::ostream& os, Handle<T> handle);
164 
165 template <typename T>
handle(T * object,Isolate * isolate)166 V8_INLINE Handle<T> handle(T* object, Isolate* isolate) {
167   return Handle<T>(object, isolate);
168 }
169 
170 template <typename T>
handle(T * object)171 V8_INLINE Handle<T> handle(T* object) {
172   return Handle<T>(object);
173 }
174 
175 
176 // ----------------------------------------------------------------------------
177 // A Handle can be converted into a MaybeHandle. Converting a MaybeHandle
178 // into a Handle requires checking that it does not point to NULL.  This
179 // ensures NULL checks before use.
180 //
181 // Also note that Handles do not provide default equality comparison or hashing
182 // operators on purpose. Such operators would be misleading, because intended
183 // semantics is ambiguous between Handle location and object identity.
184 template <typename T>
185 class MaybeHandle final {
186  public:
MaybeHandle()187   V8_INLINE MaybeHandle() {}
~MaybeHandle()188   V8_INLINE ~MaybeHandle() {}
189 
190   // Constructor for handling automatic up casting from Handle.
191   // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected.
192   template <typename S>
MaybeHandle(Handle<S> handle)193   V8_INLINE MaybeHandle(Handle<S> handle)
194       : location_(reinterpret_cast<T**>(handle.location_)) {
195     T* a = nullptr;
196     S* b = nullptr;
197     a = b;  // Fake assignment to enforce type checks.
198     USE(a);
199   }
200 
201   // Constructor for handling automatic up casting.
202   // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected.
203   template <typename S>
MaybeHandle(MaybeHandle<S> maybe_handle)204   V8_INLINE MaybeHandle(MaybeHandle<S> maybe_handle)
205       : location_(reinterpret_cast<T**>(maybe_handle.location_)) {
206     T* a = nullptr;
207     S* b = nullptr;
208     a = b;  // Fake assignment to enforce type checks.
209     USE(a);
210   }
211 
212   template <typename S>
MaybeHandle(S * object,Isolate * isolate)213   V8_INLINE MaybeHandle(S* object, Isolate* isolate)
214       : MaybeHandle(handle(object, isolate)) {}
215 
Assert()216   V8_INLINE void Assert() const { DCHECK_NOT_NULL(location_); }
Check()217   V8_INLINE void Check() const { CHECK_NOT_NULL(location_); }
218 
ToHandleChecked()219   V8_INLINE Handle<T> ToHandleChecked() const {
220     Check();
221     return Handle<T>(location_);
222   }
223 
224   // Convert to a Handle with a type that can be upcasted to.
225   template <typename S>
ToHandle(Handle<S> * out)226   V8_INLINE bool ToHandle(Handle<S>* out) const {
227     if (location_ == nullptr) {
228       *out = Handle<T>::null();
229       return false;
230     } else {
231       *out = Handle<T>(location_);
232       return true;
233     }
234   }
235 
236   // Returns the raw address where this handle is stored. This should only be
237   // used for hashing handles; do not ever try to dereference it.
address()238   V8_INLINE Address address() const { return bit_cast<Address>(location_); }
239 
is_null()240   bool is_null() const { return location_ == nullptr; }
241 
242  protected:
243   T** location_ = nullptr;
244 
245   // MaybeHandles of different classes are allowed to access each
246   // other's location_.
247   template <typename>
248   friend class MaybeHandle;
249 };
250 
251 
252 // ----------------------------------------------------------------------------
253 // A stack-allocated class that governs a number of local handles.
254 // After a handle scope has been created, all local handles will be
255 // allocated within that handle scope until either the handle scope is
256 // deleted or another handle scope is created.  If there is already a
257 // handle scope and a new one is created, all allocations will take
258 // place in the new handle scope until it is deleted.  After that,
259 // new handles will again be allocated in the original handle scope.
260 //
261 // After the handle scope of a local handle has been deleted the
262 // garbage collector will no longer track the object stored in the
263 // handle and may deallocate it.  The behavior of accessing a handle
264 // for which the handle scope has been deleted is undefined.
265 class HandleScope {
266  public:
267   explicit inline HandleScope(Isolate* isolate);
268 
269   inline ~HandleScope();
270 
271   // Counts the number of allocated handles.
272   V8_EXPORT_PRIVATE static int NumberOfHandles(Isolate* isolate);
273 
274   // Create a new handle or lookup a canonical handle.
275   V8_INLINE static Object** GetHandle(Isolate* isolate, Object* value);
276 
277   // Creates a new handle with the given value.
278   V8_INLINE static Object** CreateHandle(Isolate* isolate, Object* value);
279 
280   // Deallocates any extensions used by the current scope.
281   V8_EXPORT_PRIVATE static void DeleteExtensions(Isolate* isolate);
282 
283   static Address current_next_address(Isolate* isolate);
284   static Address current_limit_address(Isolate* isolate);
285   static Address current_level_address(Isolate* isolate);
286 
287   // Closes the HandleScope (invalidating all handles
288   // created in the scope of the HandleScope) and returns
289   // a Handle backed by the parent scope holding the
290   // value of the argument handle.
291   template <typename T>
292   Handle<T> CloseAndEscape(Handle<T> handle_value);
293 
isolate()294   Isolate* isolate() { return isolate_; }
295 
296   // Limit for number of handles with --check-handle-count. This is
297   // large enough to compile natives and pass unit tests with some
298   // slack for future changes to natives.
299   static const int kCheckHandleThreshold = 30 * 1024;
300 
301  private:
302   // Prevent heap allocation or illegal handle scopes.
303   void* operator new(size_t size);
304   void operator delete(void* size_t);
305 
306   Isolate* isolate_;
307   Object** prev_next_;
308   Object** prev_limit_;
309 
310   // Close the handle scope resetting limits to a previous state.
311   static inline void CloseScope(Isolate* isolate,
312                                 Object** prev_next,
313                                 Object** prev_limit);
314 
315   // Extend the handle scope making room for more handles.
316   V8_EXPORT_PRIVATE static Object** Extend(Isolate* isolate);
317 
318 #ifdef ENABLE_HANDLE_ZAPPING
319   // Zaps the handles in the half-open interval [start, end).
320   V8_EXPORT_PRIVATE static void ZapRange(Object** start, Object** end);
321 #endif
322 
323   friend class v8::HandleScope;
324   friend class DeferredHandles;
325   friend class DeferredHandleScope;
326   friend class HandleScopeImplementer;
327   friend class Isolate;
328 
329   DISALLOW_COPY_AND_ASSIGN(HandleScope);
330 };
331 
332 
333 // Forward declarations for CanonicalHandleScope.
334 template <typename V, class AllocationPolicy>
335 class IdentityMap;
336 class RootIndexMap;
337 
338 
339 // A CanonicalHandleScope does not open a new HandleScope. It changes the
340 // existing HandleScope so that Handles created within are canonicalized.
341 // This does not apply to nested inner HandleScopes unless a nested
342 // CanonicalHandleScope is introduced. Handles are only canonicalized within
343 // the same CanonicalHandleScope, but not across nested ones.
344 class V8_EXPORT_PRIVATE CanonicalHandleScope final {
345  public:
346   explicit CanonicalHandleScope(Isolate* isolate);
347   ~CanonicalHandleScope();
348 
349  private:
350   Object** Lookup(Object* object);
351 
352   Isolate* isolate_;
353   Zone zone_;
354   RootIndexMap* root_index_map_;
355   IdentityMap<Object**, ZoneAllocationPolicy>* identity_map_;
356   // Ordinary nested handle scopes within the current one are not canonical.
357   int canonical_level_;
358   // We may have nested canonical scopes. Handles are canonical within each one.
359   CanonicalHandleScope* prev_canonical_scope_;
360 
361   friend class HandleScope;
362 };
363 
364 class V8_EXPORT_PRIVATE DeferredHandleScope final {
365  public:
366   explicit DeferredHandleScope(Isolate* isolate);
367   // The DeferredHandles object returned stores the Handles created
368   // since the creation of this DeferredHandleScope.  The Handles are
369   // alive as long as the DeferredHandles object is alive.
370   DeferredHandles* Detach();
371   ~DeferredHandleScope();
372 
373  private:
374   Object** prev_limit_;
375   Object** prev_next_;
376   HandleScopeImplementer* impl_;
377 
378 #ifdef DEBUG
379   bool handles_detached_;
380   int prev_level_;
381 #endif
382 
383   friend class HandleScopeImplementer;
384 };
385 
386 
387 // Seal off the current HandleScope so that new handles can only be created
388 // if a new HandleScope is entered.
389 class SealHandleScope final {
390  public:
391 #ifndef DEBUG
SealHandleScope(Isolate * isolate)392   explicit SealHandleScope(Isolate* isolate) {}
~SealHandleScope()393   ~SealHandleScope() {}
394 #else
395   explicit inline SealHandleScope(Isolate* isolate);
396   inline ~SealHandleScope();
397  private:
398   Isolate* isolate_;
399   Object** prev_limit_;
400   int prev_sealed_level_;
401 #endif
402 };
403 
404 
405 struct HandleScopeData final {
406   Object** next;
407   Object** limit;
408   int level;
409   int sealed_level;
410   CanonicalHandleScope* canonical_scope;
411 
Initializefinal412   void Initialize() {
413     next = limit = NULL;
414     sealed_level = level = 0;
415     canonical_scope = NULL;
416   }
417 };
418 
419 }  // namespace internal
420 }  // namespace v8
421 
422 #endif  // V8_HANDLES_H_
423