OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_HANDLES_H_ | 5 #ifndef V8_HANDLES_H_ |
6 #define V8_HANDLES_H_ | 6 #define V8_HANDLES_H_ |
7 | 7 |
8 #include "src/objects.h" | 8 #include "src/objects.h" |
9 | 9 |
10 namespace v8 { | 10 namespace v8 { |
11 namespace internal { | 11 namespace internal { |
12 | 12 |
| 13 // Forward declarations. |
| 14 class DeferredHandles; |
| 15 class HandleScopeImplementer; |
| 16 |
| 17 |
| 18 // ---------------------------------------------------------------------------- |
| 19 // Base class for Handle instantiations. Don't use directly. |
| 20 class HandleBase { |
| 21 public: |
| 22 V8_INLINE explicit HandleBase(Object** location) : location_(location) {} |
| 23 V8_INLINE explicit HandleBase(Object* object, Isolate* isolate); |
| 24 |
| 25 // Check if this handle refers to the exact same object as the other handle. |
| 26 V8_INLINE bool is_identical_to(const HandleBase that) const { |
| 27 // Dereferencing deferred handles to check object equality is safe. |
| 28 SLOW_DCHECK((this->location_ == NULL || |
| 29 this->IsDereferenceAllowed(NO_DEFERRED_CHECK)) && |
| 30 (that.location_ == NULL || |
| 31 that.IsDereferenceAllowed(NO_DEFERRED_CHECK))); |
| 32 if (this->location_ == that.location_) return true; |
| 33 if (this->location_ == NULL || that.location_ == NULL) return false; |
| 34 return *this->location_ == *that.location_; |
| 35 } |
| 36 |
| 37 V8_INLINE bool is_null() const { return location_ == nullptr; } |
| 38 |
| 39 protected: |
| 40 // Provides the C++ dereference operator. |
| 41 V8_INLINE Object* operator*() const { |
| 42 SLOW_DCHECK(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK)); |
| 43 return *location_; |
| 44 } |
| 45 |
| 46 // Returns the address to where the raw pointer is stored. |
| 47 V8_INLINE Object** location() const { |
| 48 SLOW_DCHECK(location_ == NULL || |
| 49 IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK)); |
| 50 return location_; |
| 51 } |
| 52 |
| 53 enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK }; |
| 54 #ifdef DEBUG |
| 55 bool IsDereferenceAllowed(DereferenceCheckMode mode) const; |
| 56 #else |
| 57 V8_INLINE |
| 58 bool IsDereferenceAllowed(DereferenceCheckMode mode) const { return true; } |
| 59 #endif // DEBUG |
| 60 |
| 61 Object** location_; |
| 62 }; |
| 63 |
| 64 |
| 65 // ---------------------------------------------------------------------------- |
| 66 // A Handle provides a reference to an object that survives relocation by |
| 67 // the garbage collector. |
| 68 // Handles are only valid within a HandleScope. |
| 69 // When a handle is created for an object a cell is allocated in the heap. |
| 70 template <typename T> |
| 71 class Handle final : public HandleBase { |
| 72 public: |
| 73 V8_INLINE explicit Handle(T** location = nullptr) |
| 74 : HandleBase(reinterpret_cast<Object**>(location)) { |
| 75 Object* a = nullptr; |
| 76 T* b = nullptr; |
| 77 a = b; // Fake assignment to enforce type checks. |
| 78 USE(a); |
| 79 } |
| 80 V8_INLINE explicit Handle(T* object) : Handle(object, object->GetIsolate()) {} |
| 81 V8_INLINE Handle(T* object, Isolate* isolate) : HandleBase(object, isolate) {} |
| 82 |
| 83 // Constructor for handling automatic up casting. |
| 84 // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected. |
| 85 template <typename S> |
| 86 V8_INLINE Handle(Handle<S> handle) |
| 87 : HandleBase(handle) { |
| 88 T* a = nullptr; |
| 89 S* b = nullptr; |
| 90 a = b; // Fake assignment to enforce type checks. |
| 91 USE(a); |
| 92 } |
| 93 |
| 94 V8_INLINE T* operator->() const { return operator*(); } |
| 95 |
| 96 // Provides the C++ dereference operator. |
| 97 V8_INLINE T* operator*() const { |
| 98 return reinterpret_cast<T*>(HandleBase::operator*()); |
| 99 } |
| 100 |
| 101 // Returns the address to where the raw pointer is stored. |
| 102 V8_INLINE T** location() const { |
| 103 return reinterpret_cast<T**>(HandleBase::location()); |
| 104 } |
| 105 |
| 106 template <typename S> |
| 107 static const Handle<T> cast(Handle<S> that) { |
| 108 T::cast(*reinterpret_cast<T**>(that.location_)); |
| 109 return Handle<T>(reinterpret_cast<T**>(that.location_)); |
| 110 } |
| 111 |
| 112 // TODO(yangguo): Values that contain empty handles should be declared as |
| 113 // MaybeHandle to force validation before being used as handles. |
| 114 static const Handle<T> null() { return Handle<T>(); } |
| 115 |
| 116 private: |
| 117 // Handles of different classes are allowed to access each other's location_. |
| 118 template <typename> |
| 119 friend class Handle; |
| 120 // MaybeHandle is allowed to access location_. |
| 121 template <typename> |
| 122 friend class MaybeHandle; |
| 123 }; |
| 124 |
| 125 template <typename T> |
| 126 V8_INLINE Handle<T> handle(T* object, Isolate* isolate) { |
| 127 return Handle<T>(object, isolate); |
| 128 } |
| 129 |
| 130 template <typename T> |
| 131 V8_INLINE Handle<T> handle(T* object) { |
| 132 return Handle<T>(object); |
| 133 } |
| 134 |
| 135 |
| 136 // ---------------------------------------------------------------------------- |
13 // A Handle can be converted into a MaybeHandle. Converting a MaybeHandle | 137 // A Handle can be converted into a MaybeHandle. Converting a MaybeHandle |
14 // into a Handle requires checking that it does not point to NULL. This | 138 // into a Handle requires checking that it does not point to NULL. This |
15 // ensures NULL checks before use. | 139 // ensures NULL checks before use. |
16 // Do not use MaybeHandle as argument type. | 140 // Do not use MaybeHandle as argument type. |
17 | 141 template <typename T> |
18 template<typename T> | 142 class MaybeHandle final { |
19 class MaybeHandle { | |
20 public: | 143 public: |
21 INLINE(MaybeHandle()) : location_(NULL) { } | 144 V8_INLINE MaybeHandle() {} |
| 145 V8_INLINE ~MaybeHandle() {} |
22 | 146 |
23 // Constructor for handling automatic up casting from Handle. | 147 // Constructor for handling automatic up casting from Handle. |
24 // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected. | 148 // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected. |
25 template <class S> MaybeHandle(Handle<S> handle) { | 149 template <typename S> |
26 #ifdef DEBUG | 150 V8_INLINE MaybeHandle(Handle<S> handle) |
27 T* a = NULL; | 151 : location_(reinterpret_cast<T**>(handle.location_)) { |
28 S* b = NULL; | 152 T* a = nullptr; |
29 a = b; // Fake assignment to enforce type checks. | 153 S* b = nullptr; |
30 USE(a); | 154 a = b; // Fake assignment to enforce type checks. |
31 #endif | 155 USE(a); |
32 this->location_ = reinterpret_cast<T**>(handle.location()); | |
33 } | 156 } |
34 | 157 |
35 // Constructor for handling automatic up casting. | 158 // Constructor for handling automatic up casting. |
36 // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected. | 159 // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected. |
37 template <class S> MaybeHandle(MaybeHandle<S> maybe_handle) { | 160 template <typename S> |
38 #ifdef DEBUG | 161 V8_INLINE MaybeHandle(MaybeHandle<S> maybe_handle) |
39 T* a = NULL; | 162 : location_(reinterpret_cast<T**>(maybe_handle.location_)) { |
40 S* b = NULL; | 163 T* a = nullptr; |
41 a = b; // Fake assignment to enforce type checks. | 164 S* b = nullptr; |
42 USE(a); | 165 a = b; // Fake assignment to enforce type checks. |
43 #endif | 166 USE(a); |
44 location_ = reinterpret_cast<T**>(maybe_handle.location_); | 167 } |
45 } | 168 |
46 | 169 V8_INLINE void Assert() const { DCHECK_NOT_NULL(location_); } |
47 INLINE(void Assert() const) { DCHECK(location_ != NULL); } | 170 V8_INLINE void Check() const { CHECK_NOT_NULL(location_); } |
48 INLINE(void Check() const) { CHECK(location_ != NULL); } | 171 |
49 | 172 V8_INLINE Handle<T> ToHandleChecked() const { |
50 INLINE(Handle<T> ToHandleChecked()) const { | |
51 Check(); | 173 Check(); |
52 return Handle<T>(location_); | 174 return Handle<T>(location_); |
53 } | 175 } |
54 | 176 |
55 // Convert to a Handle with a type that can be upcasted to. | 177 // Convert to a Handle with a type that can be upcasted to. |
56 template <class S> | 178 template <typename S> |
57 V8_INLINE bool ToHandle(Handle<S>* out) const { | 179 V8_INLINE bool ToHandle(Handle<S>* out) const { |
58 if (location_ == NULL) { | 180 if (location_ == nullptr) { |
59 *out = Handle<T>::null(); | 181 *out = Handle<T>::null(); |
60 return false; | 182 return false; |
61 } else { | 183 } else { |
62 *out = Handle<T>(location_); | 184 *out = Handle<T>(location_); |
63 return true; | 185 return true; |
64 } | 186 } |
65 } | 187 } |
66 | 188 |
67 bool is_null() const { return location_ == NULL; } | 189 bool is_null() const { return location_ == nullptr; } |
68 | 190 |
69 template <typename S> | 191 template <typename S> |
70 bool operator==(MaybeHandle<S> that) const { | 192 V8_INLINE bool operator==(MaybeHandle<S> that) const { |
71 return this->location_ == that.location_; | 193 return this->location_ == that.location_; |
72 } | 194 } |
73 template <typename S> | 195 template <typename S> |
74 bool operator!=(MaybeHandle<S> that) const { | 196 V8_INLINE bool operator!=(MaybeHandle<S> that) const { |
75 return !(*this == that); | 197 return this->location_ != that.location_; |
76 } | 198 } |
77 | |
78 | 199 |
79 protected: | 200 protected: |
80 T** location_; | 201 T** location_ = nullptr; |
81 | 202 |
82 // MaybeHandles of different classes are allowed to access each | 203 // MaybeHandles of different classes are allowed to access each |
83 // other's location_. | 204 // other's location_. |
84 template<class S> friend class MaybeHandle; | 205 template <typename> |
| 206 friend class MaybeHandle; |
| 207 // Utility functions are allowed to access location_. |
85 template <typename S> | 208 template <typename S> |
86 friend size_t hash_value(MaybeHandle<S>); | 209 friend size_t hash_value(MaybeHandle<S>); |
87 }; | 210 }; |
88 | 211 |
89 template <typename S> | 212 template <typename T> |
90 inline size_t hash_value(MaybeHandle<S> maybe_handle) { | 213 V8_INLINE size_t hash_value(MaybeHandle<T> maybe_handle) { |
91 return bit_cast<size_t>(maybe_handle.location_); | 214 uintptr_t v = bit_cast<uintptr_t>(maybe_handle.location_); |
| 215 DCHECK_EQ(0u, v & ((1u << kPointerSizeLog2) - 1)); |
| 216 return v >> kPointerSizeLog2; |
92 } | 217 } |
93 | 218 |
94 | 219 |
95 // ---------------------------------------------------------------------------- | |
96 // A Handle provides a reference to an object that survives relocation by | |
97 // the garbage collector. | |
98 // Handles are only valid within a HandleScope. | |
99 // When a handle is created for an object a cell is allocated in the heap. | |
100 | |
101 template<typename T> | |
102 class Handle { | |
103 public: | |
104 INLINE(explicit Handle(T** location)) { location_ = location; } | |
105 INLINE(explicit Handle(T* obj)); | |
106 INLINE(Handle(T* obj, Isolate* isolate)); | |
107 | |
108 // TODO(yangguo): Values that contain empty handles should be declared as | |
109 // MaybeHandle to force validation before being used as handles. | |
110 INLINE(Handle()) : location_(NULL) { } | |
111 | |
112 // Constructor for handling automatic up casting. | |
113 // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected. | |
114 template <class S> Handle(Handle<S> handle) { | |
115 #ifdef DEBUG | |
116 T* a = NULL; | |
117 S* b = NULL; | |
118 a = b; // Fake assignment to enforce type checks. | |
119 USE(a); | |
120 #endif | |
121 location_ = reinterpret_cast<T**>(handle.location_); | |
122 } | |
123 | |
124 INLINE(T* operator->() const) { return operator*(); } | |
125 | |
126 // Check if this handle refers to the exact same object as the other handle. | |
127 INLINE(bool is_identical_to(const Handle<T> other) const); | |
128 | |
129 // Provides the C++ dereference operator. | |
130 INLINE(T* operator*() const); | |
131 | |
132 // Returns the address to where the raw pointer is stored. | |
133 INLINE(T** location() const); | |
134 | |
135 template <class S> static Handle<T> cast(Handle<S> that) { | |
136 T::cast(*reinterpret_cast<T**>(that.location_)); | |
137 return Handle<T>(reinterpret_cast<T**>(that.location_)); | |
138 } | |
139 | |
140 // TODO(yangguo): Values that contain empty handles should be declared as | |
141 // MaybeHandle to force validation before being used as handles. | |
142 static Handle<T> null() { return Handle<T>(); } | |
143 bool is_null() const { return location_ == NULL; } | |
144 | |
145 // Closes the given scope, but lets this handle escape. See | |
146 // implementation in api.h. | |
147 inline Handle<T> EscapeFrom(v8::EscapableHandleScope* scope); | |
148 | |
149 #ifdef DEBUG | |
150 enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK }; | |
151 | |
152 bool IsDereferenceAllowed(DereferenceCheckMode mode) const; | |
153 #endif // DEBUG | |
154 | |
155 private: | |
156 T** location_; | |
157 | |
158 // Handles of different classes are allowed to access each other's location_. | |
159 template<class S> friend class Handle; | |
160 }; | |
161 | |
162 | |
163 // Convenience wrapper. | |
164 template<class T> | |
165 inline Handle<T> handle(T* t, Isolate* isolate) { | |
166 return Handle<T>(t, isolate); | |
167 } | |
168 | |
169 | |
170 // Convenience wrapper. | |
171 template<class T> | |
172 inline Handle<T> handle(T* t) { | |
173 return Handle<T>(t, t->GetIsolate()); | |
174 } | |
175 | |
176 | |
177 class DeferredHandles; | |
178 class HandleScopeImplementer; | |
179 | |
180 | |
181 // A stack-allocated class that governs a number of local handles. | 220 // A stack-allocated class that governs a number of local handles. |
182 // After a handle scope has been created, all local handles will be | 221 // After a handle scope has been created, all local handles will be |
183 // allocated within that handle scope until either the handle scope is | 222 // allocated within that handle scope until either the handle scope is |
184 // deleted or another handle scope is created. If there is already a | 223 // deleted or another handle scope is created. If there is already a |
185 // handle scope and a new one is created, all allocations will take | 224 // handle scope and a new one is created, all allocations will take |
186 // place in the new handle scope until it is deleted. After that, | 225 // place in the new handle scope until it is deleted. After that, |
187 // new handles will again be allocated in the original handle scope. | 226 // new handles will again be allocated in the original handle scope. |
188 // | 227 // |
189 // After the handle scope of a local handle has been deleted the | 228 // After the handle scope of a local handle has been deleted the |
190 // garbage collector will no longer track the object stored in the | 229 // garbage collector will no longer track the object stored in the |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 Isolate* isolate_; | 273 Isolate* isolate_; |
235 Object** prev_next_; | 274 Object** prev_next_; |
236 Object** prev_limit_; | 275 Object** prev_limit_; |
237 | 276 |
238 // Close the handle scope resetting limits to a previous state. | 277 // Close the handle scope resetting limits to a previous state. |
239 static inline void CloseScope(Isolate* isolate, | 278 static inline void CloseScope(Isolate* isolate, |
240 Object** prev_next, | 279 Object** prev_next, |
241 Object** prev_limit); | 280 Object** prev_limit); |
242 | 281 |
243 // Extend the handle scope making room for more handles. | 282 // Extend the handle scope making room for more handles. |
244 static internal::Object** Extend(Isolate* isolate); | 283 static Object** Extend(Isolate* isolate); |
245 | 284 |
246 #ifdef ENABLE_HANDLE_ZAPPING | 285 #ifdef ENABLE_HANDLE_ZAPPING |
247 // Zaps the handles in the half-open interval [start, end). | 286 // Zaps the handles in the half-open interval [start, end). |
248 static void ZapRange(Object** start, Object** end); | 287 static void ZapRange(Object** start, Object** end); |
249 #endif | 288 #endif |
250 | 289 |
251 friend class v8::HandleScope; | 290 friend class v8::HandleScope; |
252 friend class v8::internal::DeferredHandles; | 291 friend class DeferredHandles; |
253 friend class v8::internal::HandleScopeImplementer; | 292 friend class HandleScopeImplementer; |
254 friend class v8::internal::Isolate; | 293 friend class Isolate; |
255 }; | 294 }; |
256 | 295 |
257 | 296 |
258 class DeferredHandles; | 297 class DeferredHandleScope final { |
259 | |
260 | |
261 class DeferredHandleScope { | |
262 public: | 298 public: |
263 explicit DeferredHandleScope(Isolate* isolate); | 299 explicit DeferredHandleScope(Isolate* isolate); |
264 // The DeferredHandles object returned stores the Handles created | 300 // The DeferredHandles object returned stores the Handles created |
265 // since the creation of this DeferredHandleScope. The Handles are | 301 // since the creation of this DeferredHandleScope. The Handles are |
266 // alive as long as the DeferredHandles object is alive. | 302 // alive as long as the DeferredHandles object is alive. |
267 DeferredHandles* Detach(); | 303 DeferredHandles* Detach(); |
268 ~DeferredHandleScope(); | 304 ~DeferredHandleScope(); |
269 | 305 |
270 private: | 306 private: |
271 Object** prev_limit_; | 307 Object** prev_limit_; |
272 Object** prev_next_; | 308 Object** prev_next_; |
273 HandleScopeImplementer* impl_; | 309 HandleScopeImplementer* impl_; |
274 | 310 |
275 #ifdef DEBUG | 311 #ifdef DEBUG |
276 bool handles_detached_; | 312 bool handles_detached_; |
277 int prev_level_; | 313 int prev_level_; |
278 #endif | 314 #endif |
279 | 315 |
280 friend class HandleScopeImplementer; | 316 friend class HandleScopeImplementer; |
281 }; | 317 }; |
282 | 318 |
283 | 319 |
284 // Seal off the current HandleScope so that new handles can only be created | 320 // Seal off the current HandleScope so that new handles can only be created |
285 // if a new HandleScope is entered. | 321 // if a new HandleScope is entered. |
286 class SealHandleScope BASE_EMBEDDED { | 322 class SealHandleScope final { |
287 public: | 323 public: |
288 #ifndef DEBUG | 324 #ifndef DEBUG |
289 explicit SealHandleScope(Isolate* isolate) {} | 325 explicit SealHandleScope(Isolate* isolate) {} |
290 ~SealHandleScope() {} | 326 ~SealHandleScope() {} |
291 #else | 327 #else |
292 explicit inline SealHandleScope(Isolate* isolate); | 328 explicit inline SealHandleScope(Isolate* isolate); |
293 inline ~SealHandleScope(); | 329 inline ~SealHandleScope(); |
294 private: | 330 private: |
295 Isolate* isolate_; | 331 Isolate* isolate_; |
296 Object** limit_; | 332 Object** limit_; |
297 int level_; | 333 int level_; |
298 #endif | 334 #endif |
299 }; | 335 }; |
300 | 336 |
301 struct HandleScopeData { | 337 |
302 internal::Object** next; | 338 struct HandleScopeData final { |
303 internal::Object** limit; | 339 Object** next; |
| 340 Object** limit; |
304 int level; | 341 int level; |
305 | 342 |
306 void Initialize() { | 343 void Initialize() { |
307 next = limit = NULL; | 344 next = limit = NULL; |
308 level = 0; | 345 level = 0; |
309 } | 346 } |
310 }; | 347 }; |
311 | 348 |
312 } } // namespace v8::internal | 349 } // namespace internal |
| 350 } // namespace v8 |
313 | 351 |
314 #endif // V8_HANDLES_H_ | 352 #endif // V8_HANDLES_H_ |
OLD | NEW |