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