// Copyright 2011 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_HANDLES_H_ #define V8_HANDLES_H_ #include "src/objects.h" namespace v8 { namespace internal { // 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 class MaybeHandle { public: INLINE(MaybeHandle()) : location_(NULL) { } // Constructor for handling automatic up casting from Handle. // Ex. Handle can be passed when MaybeHandle is expected. template MaybeHandle(Handle handle) { #ifdef DEBUG T* a = NULL; S* b = NULL; a = b; // Fake assignment to enforce type checks. USE(a); #endif this->location_ = reinterpret_cast(handle.location()); } // Constructor for handling automatic up casting. // Ex. MaybeHandle can be passed when Handle is expected. template MaybeHandle(MaybeHandle maybe_handle) { #ifdef DEBUG T* a = NULL; S* b = NULL; a = b; // Fake assignment to enforce type checks. USE(a); #endif location_ = reinterpret_cast(maybe_handle.location_); } INLINE(void Assert() const) { DCHECK(location_ != NULL); } INLINE(void Check() const) { CHECK(location_ != NULL); } INLINE(Handle ToHandleChecked()) const { Check(); return Handle(location_); } // Convert to a Handle with a type that can be upcasted to. template INLINE(bool ToHandle(Handle* out)) { if (location_ == NULL) { *out = Handle::null(); return false; } else { *out = Handle(location_); return true; } } bool is_null() const { return location_ == NULL; } protected: T** location_; // MaybeHandles of different classes are allowed to access each // other's location_. template friend class MaybeHandle; }; // ---------------------------------------------------------------------------- // 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 class Handle { public: INLINE(explicit Handle(T** location)) { location_ = location; } INLINE(explicit Handle(T* obj)); INLINE(Handle(T* obj, Isolate* 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) { } // Constructor for handling automatic up casting. // Ex. Handle can be passed when Handle is expected. template Handle(Handle handle) { #ifdef DEBUG T* a = NULL; S* b = NULL; a = b; // Fake assignment to enforce type checks. USE(a); #endif location_ = reinterpret_cast(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 other) const); // Provides the C++ dereference operator. INLINE(T* operator*() const); // Returns the address to where the raw pointer is stored. INLINE(T** location() const); template static Handle cast(Handle that) { T::cast(*reinterpret_cast(that.location_)); return Handle(reinterpret_cast(that.location_)); } // TODO(yangguo): Values that contain empty handles should be declared as // MaybeHandle to force validation before being used as handles. static Handle null() { return Handle(); } bool is_null() const { return location_ == NULL; } // Closes the given scope, but lets this handle escape. See // implementation in api.h. inline Handle 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 friend class Handle; }; // Convenience wrapper. template inline Handle handle(T* t, Isolate* isolate) { return Handle(t, isolate); } // Convenience wrapper. template inline Handle handle(T* t) { return Handle(t, t->GetIsolate()); } // Key comparison function for Map handles. inline bool operator<(const Handle& lhs, const Handle& rhs) { // This is safe because maps don't move. return *lhs < *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 // deleted or another handle scope is created. If there is already a // handle scope and a new one is created, all allocations will take // place in the new handle scope until it is deleted. After that, // new handles will again be allocated in the original handle scope. // // After the handle scope of a local handle has been deleted the // 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 { public: explicit inline HandleScope(Isolate* isolate); inline ~HandleScope(); // Counts the number of allocated handles. static int NumberOfHandles(Isolate* isolate); // Creates a new handle with the given value. template static inline T** CreateHandle(Isolate* isolate, T* value); // Deallocates any extensions used by the current scope. static void DeleteExtensions(Isolate* isolate); static Address current_next_address(Isolate* isolate); static Address current_limit_address(Isolate* isolate); static Address current_level_address(Isolate* isolate); // Closes the HandleScope (invalidating all handles // created in the scope of the HandleScope) and returns // a Handle backed by the parent scope holding the // value of the argument handle. template Handle CloseAndEscape(Handle handle_value); Isolate* isolate() { 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); Isolate* isolate_; Object** prev_next_; Object** prev_limit_; // Close the handle scope resetting limits to a previous state. static inline 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); #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; }; class DeferredHandles; class DeferredHandleScope { public: explicit DeferredHandleScope(Isolate* isolate); // The DeferredHandles object returned stores the Handles created // since the creation of this DeferredHandleScope. The Handles are // alive as long as the DeferredHandles object is alive. DeferredHandles* Detach(); ~DeferredHandleScope(); private: Object** prev_limit_; Object** prev_next_; HandleScopeImplementer* impl_; #ifdef DEBUG bool handles_detached_; int prev_level_; #endif friend class HandleScopeImplementer; }; // Seal off the current HandleScope so that new handles can only be created // if a new HandleScope is entered. class SealHandleScope BASE_EMBEDDED { public: #ifndef DEBUG explicit SealHandleScope(Isolate* isolate) {} ~SealHandleScope() {} #else explicit inline SealHandleScope(Isolate* isolate); inline ~SealHandleScope(); private: Isolate* isolate_; Object** limit_; int level_; #endif }; struct HandleScopeData { internal::Object** next; internal::Object** limit; int level; void Initialize() { next = limit = NULL; level = 0; } }; } } // namespace v8::internal #endif // V8_HANDLES_H_