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