Chromium Code Reviews| Index: src/handles.h |
| diff --git a/src/handles.h b/src/handles.h |
| index eb57f0e26089383c9d7fe9f57a8cba5f41a111e2..b97badaea9cbcadeb13114fb43da099a1d8a9dab 100644 |
| --- a/src/handles.h |
| +++ b/src/handles.h |
| @@ -10,22 +10,26 @@ |
| namespace v8 { |
| namespace internal { |
| +// Forward declarations. |
| +class DeferredHandles; |
| +class HandleScopeImplementer; |
| + |
| + |
| // A Handle can be converted into a MaybeHandle. Converting a MaybeHandle |
| // into a Handle requires checking that it does not point to NULL. This |
| // ensures NULL checks before use. |
| // Do not use MaybeHandle as argument type. |
| - |
| template<typename T> |
| class MaybeHandle { |
| public: |
| - INLINE(MaybeHandle()) : location_(NULL) { } |
| + V8_INLINE MaybeHandle() : location_(nullptr) {} |
| // Constructor for handling automatic up casting from Handle. |
| // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected. |
| template <class S> MaybeHandle(Handle<S> handle) { |
| #ifdef DEBUG |
| - T* a = NULL; |
| - S* b = NULL; |
| + T* a = nullptr; |
| + S* b = nullptr; |
| a = b; // Fake assignment to enforce type checks. |
| USE(a); |
| #endif |
| @@ -44,10 +48,10 @@ class MaybeHandle { |
| location_ = reinterpret_cast<T**>(maybe_handle.location_); |
| } |
| - INLINE(void Assert() const) { DCHECK(location_ != NULL); } |
| - INLINE(void Check() const) { CHECK(location_ != NULL); } |
| + V8_INLINE void Assert() const { DCHECK_NOT_NULL(location_); } |
| + V8_INLINE void Check() const { CHECK_NOT_NULL(location_); } |
| - INLINE(Handle<T> ToHandleChecked()) const { |
| + V8_INLINE Handle<T> ToHandleChecked() const { |
| Check(); |
| return Handle<T>(location_); |
| } |
| @@ -74,69 +78,116 @@ class MaybeHandle { |
| template<class S> friend class MaybeHandle; |
| }; |
| + |
| +// Base class for Handles. Don't use this directly. |
| +class HandleBase { |
| + public: |
| + V8_INLINE explicit HandleBase(Object** location = nullptr) |
| + : location_(location) {} |
| + V8_INLINE explicit HandleBase(HandleBase const& other) |
| + : location_(other.location_) {} |
| + explicit HandleBase(HeapObject* object); |
| + explicit HandleBase(Object* object, Isolate* isolate); |
| + V8_INLINE ~HandleBase() {} |
| + |
| + // Check if this handle refers to the exact same object as the other handle. |
| + V8_INLINE bool is_identical_to(HandleBase const& other) const { |
| + // Dereferencing deferred handles to check object equality is safe. |
| + SLOW_DCHECK(location_ == nullptr || |
| + IsDereferenceAllowed(NO_DEFERRED_CHECK)); |
| + SLOW_DCHECK(other.location_ == nullptr || |
| + other.IsDereferenceAllowed(NO_DEFERRED_CHECK)); |
| + if (location_ == other.location_) return true; |
| + if (location_ == nullptr || other.location_ == nullptr) return false; |
| + return *location_ == *other.location_; |
| + } |
| + |
| + // Check if this handle is a NULL handle. |
| + V8_INLINE bool is_null() const { return location_ == nullptr; } |
| + |
| + protected: |
| + // Provides the C++ deference operator. |
| + V8_INLINE Object* operator*() const { |
| + SLOW_DCHECK(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK)); |
| + return *location_; |
| + } |
| + |
| + // Returns the address to where the raw pointer is stored. |
| + V8_INLINE Object** location() const { |
| + SLOW_DCHECK(location_ == nullptr || |
| + IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK)); |
| + return location_; |
| + } |
| + |
| + private: |
| + enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK }; |
| +#ifdef DEBUG |
| + bool IsDereferenceAllowed(DereferenceCheckMode mode) const; |
| +#else |
| + V8_INLINE bool IsDereferenceAllowed(DereferenceCheckMode) const { |
| + return true; |
| + } |
| +#endif // DEBUG |
| + |
| + Object** location_; |
| +}; |
| + |
| + |
| // ---------------------------------------------------------------------------- |
| // A Handle provides a reference to an object that survives relocation by |
| // the garbage collector. |
| // Handles are only valid within a HandleScope. |
| // When a handle is created for an object a cell is allocated in the heap. |
| - |
| -template<typename T> |
| -class Handle { |
| +template <typename T> |
| +class Handle final : public HandleBase { |
| public: |
| - INLINE(explicit Handle(T** location)) { location_ = location; } |
| - INLINE(explicit Handle(T* obj)); |
| - INLINE(Handle(T* obj, Isolate* isolate)); |
| + V8_INLINE explicit Handle(T** location) |
| + : HandleBase(reinterpret_cast<Object**>(location)) {} |
| + V8_INLINE explicit Handle(T* object) : HandleBase(object) {} |
| + V8_INLINE Handle(T* object, Isolate* isolate) : HandleBase(object, isolate) {} |
| // TODO(yangguo): Values that contain empty handles should be declared as |
| // MaybeHandle to force validation before being used as handles. |
| - INLINE(Handle()) : location_(NULL) { } |
| + V8_INLINE Handle() {} |
| // Constructor for handling automatic up casting. |
| // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected. |
| - template <class S> Handle(Handle<S> handle) { |
| -#ifdef DEBUG |
| - T* a = NULL; |
| - S* b = NULL; |
| + template <class S> |
| + V8_INLINE Handle(Handle<S> const& other) |
| + : HandleBase(other) { |
| + T* a = nullptr; |
| + S* b = nullptr; |
| a = b; // Fake assignment to enforce type checks. |
| USE(a); |
| -#endif |
| - location_ = reinterpret_cast<T**>(handle.location_); |
| } |
| - INLINE(T* operator->() const) { return operator*(); } |
| - |
| - // Check if this handle refers to the exact same object as the other handle. |
| - INLINE(bool is_identical_to(const Handle<T> other) const); |
| + V8_INLINE T* operator->() const { return operator*(); } |
| // Provides the C++ dereference operator. |
| - INLINE(T* operator*() const); |
| + V8_INLINE T* operator*() const { |
| + return reinterpret_cast<T*>(HandleBase::operator*()); |
| + } |
| // Returns the address to where the raw pointer is stored. |
| - INLINE(T** location() const); |
| + V8_INLINE T** location() const { |
| + return reinterpret_cast<T**>(HandleBase::location()); |
| + } |
| - template <class S> static Handle<T> cast(Handle<S> that) { |
| - T::cast(*reinterpret_cast<T**>(that.location_)); |
| - return Handle<T>(reinterpret_cast<T**>(that.location_)); |
| + template <class S> |
| + V8_INLINE static Handle<T> cast(Handle<S> const& other) { |
| + T::cast(*reinterpret_cast<T**>(other.location())); |
| + return Handle<T>(reinterpret_cast<T**>(other.location())); |
| } |
| // TODO(yangguo): Values that contain empty handles should be declared as |
| // MaybeHandle to force validation before being used as handles. |
| static Handle<T> null() { return Handle<T>(); } |
| - bool is_null() const { return location_ == NULL; } |
| // Closes the given scope, but lets this handle escape. See |
| // implementation in api.h. |
| inline Handle<T> EscapeFrom(v8::EscapableHandleScope* scope); |
| -#ifdef DEBUG |
| - enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK }; |
| - |
| - bool IsDereferenceAllowed(DereferenceCheckMode mode) const; |
| -#endif // DEBUG |
| - |
| private: |
| - T** location_; |
| - |
| // Handles of different classes are allowed to access each other's location_. |
| template<class S> friend class Handle; |
| }; |
| @@ -163,10 +214,6 @@ inline bool operator<(const Handle<Map>& lhs, const Handle<Map>& rhs) { |
| } |
| -class DeferredHandles; |
| -class HandleScopeImplementer; |
| - |
| - |
| // A stack-allocated class that governs a number of local handles. |
| // After a handle scope has been created, all local handles will be |
| // allocated within that handle scope until either the handle scope is |
| @@ -179,18 +226,21 @@ class HandleScopeImplementer; |
| // garbage collector will no longer track the object stored in the |
| // handle and may deallocate it. The behavior of accessing a handle |
| // for which the handle scope has been deleted is undefined. |
| -class HandleScope { |
| +class HandleScope final { |
| public: |
| - explicit inline HandleScope(Isolate* isolate); |
| - |
| - inline ~HandleScope(); |
| + explicit HandleScope(Isolate* isolate); |
| + ~HandleScope(); |
| // Counts the number of allocated handles. |
| static int NumberOfHandles(Isolate* isolate); |
| // Creates a new handle with the given value. |
| + static Object** CreateHandle(Isolate* isolate, Object* value); |
| template <typename T> |
| - static inline T** CreateHandle(Isolate* isolate, T* value); |
| + static T** CreateHandle(Isolate* isolate, T* value) { |
| + return reinterpret_cast<T**>( |
| + CreateHandle(isolate, static_cast<Object*>(value))); |
| + } |
| // Deallocates any extensions used by the current scope. |
| static void DeleteExtensions(Isolate* isolate); |
| @@ -203,43 +253,42 @@ class HandleScope { |
| // created in the scope of the HandleScope) and returns |
| // a Handle backed by the parent scope holding the |
| // value of the argument handle. |
| + Handle<Object> CloseAndEscape(Handle<Object> handle); |
| template <typename T> |
| - Handle<T> CloseAndEscape(Handle<T> handle_value); |
| + Handle<T> CloseAndEscape(Handle<T> handle) { |
| + return Handle<T>::cast(CloseAndEscape(Handle<Object>::cast(handle))); |
| + } |
| - Isolate* isolate() { return isolate_; } |
| + Isolate* isolate() const { return isolate_; } |
| private: |
| - // Prevent heap allocation or illegal handle scopes. |
| - HandleScope(const HandleScope&); |
| - void operator=(const HandleScope&); |
| - void* operator new(size_t size); |
| - void operator delete(void* size_t); |
| + friend class v8::HandleScope; |
| + friend class v8::internal::DeferredHandles; |
| + friend class v8::internal::HandleScopeImplementer; |
| + friend class v8::internal::Isolate; |
| - Isolate* isolate_; |
| - Object** prev_next_; |
| - Object** prev_limit_; |
| + // Prevent heap allocation or illegal handle scopes. |
| + void* operator new(size_t size) = delete; |
| + void operator delete(void* size_t) = delete; |
| // Close the handle scope resetting limits to a previous state. |
| - static inline void CloseScope(Isolate* isolate, |
| - Object** prev_next, |
| - Object** prev_limit); |
| + static void CloseScope(Isolate* isolate, Object** prev_next, |
| + Object** prev_limit); |
| // Extend the handle scope making room for more handles. |
| - static internal::Object** Extend(Isolate* isolate); |
| + static Object** Extend(Isolate* isolate); |
| #ifdef ENABLE_HANDLE_ZAPPING |
| // Zaps the handles in the half-open interval [start, end). |
| static void ZapRange(Object** start, Object** end); |
| #endif |
| - friend class v8::HandleScope; |
| - friend class v8::internal::DeferredHandles; |
| - friend class v8::internal::HandleScopeImplementer; |
| - friend class v8::internal::Isolate; |
| -}; |
| - |
| + Isolate* const isolate_; |
| + Object** prev_next_; |
| + Object** prev_limit_; |
| -class DeferredHandles; |
| + DISALLOW_COPY_AND_ASSIGN(HandleScope); |
| +}; |
| class DeferredHandleScope { |
| @@ -267,32 +316,38 @@ class DeferredHandleScope { |
| // Seal off the current HandleScope so that new handles can only be created |
| // if a new HandleScope is entered. |
| -class SealHandleScope BASE_EMBEDDED { |
|
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
|
| +class SealHandleScope final { |
| public: |
| #ifndef DEBUG |
| explicit SealHandleScope(Isolate* isolate) {} |
| ~SealHandleScope() {} |
| #else |
| - explicit inline SealHandleScope(Isolate* isolate); |
| - inline ~SealHandleScope(); |
| + explicit SealHandleScope(Isolate* isolate); |
| + ~SealHandleScope(); |
| + |
| private: |
| - Isolate* isolate_; |
| + Isolate* const isolate_; |
| Object** limit_; |
| int level_; |
| -#endif |
| +#endif // DEBUG |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(SealHandleScope); |
| }; |
| + |
| struct HandleScopeData { |
| internal::Object** next; |
| internal::Object** limit; |
| int level; |
| void Initialize() { |
| - next = limit = NULL; |
| + next = limit = nullptr; |
| level = 0; |
| } |
| }; |
| -} } // namespace v8::internal |
| +} // namespace internal |
| +} // namespace v8 |
| #endif // V8_HANDLES_H_ |