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