Home | History | Annotate | Download | only in src
      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 "include/v8.h"
      9 #include "src/base/functional.h"
     10 #include "src/base/macros.h"
     11 #include "src/checks.h"
     12 #include "src/globals.h"
     13 #include "src/zone.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 // Forward declarations.
     19 class DeferredHandles;
     20 class HandleScopeImplementer;
     21 class Isolate;
     22 class Object;
     23 
     24 
     25 // ----------------------------------------------------------------------------
     26 // Base class for Handle instantiations.  Don't use directly.
     27 class HandleBase {
     28  public:
     29   V8_INLINE explicit HandleBase(Object** location) : location_(location) {}
     30   V8_INLINE explicit HandleBase(Object* object, Isolate* isolate);
     31 
     32   // Check if this handle refers to the exact same object as the other handle.
     33   V8_INLINE bool is_identical_to(const HandleBase that) const {
     34     // Dereferencing deferred handles to check object equality is safe.
     35     SLOW_DCHECK((this->location_ == nullptr ||
     36                  this->IsDereferenceAllowed(NO_DEFERRED_CHECK)) &&
     37                 (that.location_ == nullptr ||
     38                  that.IsDereferenceAllowed(NO_DEFERRED_CHECK)));
     39     if (this->location_ == that.location_) return true;
     40     if (this->location_ == NULL || that.location_ == NULL) return false;
     41     return *this->location_ == *that.location_;
     42   }
     43 
     44   V8_INLINE bool is_null() const { return location_ == nullptr; }
     45 
     46  protected:
     47   // Provides the C++ dereference operator.
     48   V8_INLINE Object* operator*() const {
     49     SLOW_DCHECK(IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
     50     return *location_;
     51   }
     52 
     53   // Returns the address to where the raw pointer is stored.
     54   V8_INLINE Object** location() const {
     55     SLOW_DCHECK(location_ == nullptr ||
     56                 IsDereferenceAllowed(INCLUDE_DEFERRED_CHECK));
     57     return location_;
     58   }
     59 
     60   enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK };
     61 #ifdef DEBUG
     62   bool IsDereferenceAllowed(DereferenceCheckMode mode) const;
     63 #else
     64   V8_INLINE
     65   bool IsDereferenceAllowed(DereferenceCheckMode mode) const { return true; }
     66 #endif  // DEBUG
     67 
     68   Object** location_;
     69 };
     70 
     71 
     72 // ----------------------------------------------------------------------------
     73 // A Handle provides a reference to an object that survives relocation by
     74 // the garbage collector.
     75 //
     76 // Handles are only valid within a HandleScope. When a handle is created
     77 // for an object a cell is allocated in the current HandleScope.
     78 //
     79 // Also note that Handles do not provide default equality comparison or hashing
     80 // operators on purpose. Such operators would be misleading, because intended
     81 // semantics is ambiguous between Handle location and object identity. Instead
     82 // use either {is_identical_to} or {location} explicitly.
     83 template <typename T>
     84 class Handle final : public HandleBase {
     85  public:
     86   V8_INLINE explicit Handle(T** location = nullptr)
     87       : HandleBase(reinterpret_cast<Object**>(location)) {
     88     Object* a = nullptr;
     89     T* b = nullptr;
     90     a = b;  // Fake assignment to enforce type checks.
     91     USE(a);
     92   }
     93   V8_INLINE explicit Handle(T* object) : Handle(object, object->GetIsolate()) {}
     94   V8_INLINE Handle(T* object, Isolate* isolate) : HandleBase(object, isolate) {}
     95 
     96   // Allocate a new handle for the object, do not canonicalize.
     97   V8_INLINE static Handle<T> New(T* object, Isolate* isolate);
     98 
     99   // Constructor for handling automatic up casting.
    100   // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
    101   template <typename S>
    102   V8_INLINE Handle(Handle<S> handle)
    103       : HandleBase(handle) {
    104     T* a = nullptr;
    105     S* b = nullptr;
    106     a = b;  // Fake assignment to enforce type checks.
    107     USE(a);
    108   }
    109 
    110   V8_INLINE T* operator->() const { return operator*(); }
    111 
    112   // Provides the C++ dereference operator.
    113   V8_INLINE T* operator*() const {
    114     return reinterpret_cast<T*>(HandleBase::operator*());
    115   }
    116 
    117   // Returns the address to where the raw pointer is stored.
    118   V8_INLINE T** location() const {
    119     return reinterpret_cast<T**>(HandleBase::location());
    120   }
    121 
    122   template <typename S>
    123   static const Handle<T> cast(Handle<S> that) {
    124     T::cast(*reinterpret_cast<T**>(that.location_));
    125     return Handle<T>(reinterpret_cast<T**>(that.location_));
    126   }
    127 
    128   // TODO(yangguo): Values that contain empty handles should be declared as
    129   // MaybeHandle to force validation before being used as handles.
    130   static const Handle<T> null() { return Handle<T>(); }
    131 
    132   // Provide function object for location equality comparison.
    133   struct equal_to : public std::binary_function<Handle<T>, Handle<T>, bool> {
    134     V8_INLINE bool operator()(Handle<T> lhs, Handle<T> rhs) const {
    135       return lhs.location() == rhs.location();
    136     }
    137   };
    138 
    139   // Provide function object for location hashing.
    140   struct hash : public std::unary_function<Handle<T>, size_t> {
    141     V8_INLINE size_t operator()(Handle<T> const& handle) const {
    142       return base::hash<void*>()(handle.location());
    143     }
    144   };
    145 
    146  private:
    147   // Handles of different classes are allowed to access each other's location_.
    148   template <typename>
    149   friend class Handle;
    150   // MaybeHandle is allowed to access location_.
    151   template <typename>
    152   friend class MaybeHandle;
    153 };
    154 
    155 template <typename T>
    156 inline std::ostream& operator<<(std::ostream& os, Handle<T> handle);
    157 
    158 template <typename T>
    159 V8_INLINE Handle<T> handle(T* object, Isolate* isolate) {
    160   return Handle<T>(object, isolate);
    161 }
    162 
    163 template <typename T>
    164 V8_INLINE Handle<T> handle(T* object) {
    165   return Handle<T>(object);
    166 }
    167 
    168 
    169 // ----------------------------------------------------------------------------
    170 // A Handle can be converted into a MaybeHandle. Converting a MaybeHandle
    171 // into a Handle requires checking that it does not point to NULL.  This
    172 // ensures NULL checks before use.
    173 //
    174 // Also note that Handles do not provide default equality comparison or hashing
    175 // operators on purpose. Such operators would be misleading, because intended
    176 // semantics is ambiguous between Handle location and object identity.
    177 template <typename T>
    178 class MaybeHandle final {
    179  public:
    180   V8_INLINE MaybeHandle() {}
    181   V8_INLINE ~MaybeHandle() {}
    182 
    183   // Constructor for handling automatic up casting from Handle.
    184   // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected.
    185   template <typename S>
    186   V8_INLINE MaybeHandle(Handle<S> handle)
    187       : location_(reinterpret_cast<T**>(handle.location_)) {
    188     T* a = nullptr;
    189     S* b = nullptr;
    190     a = b;  // Fake assignment to enforce type checks.
    191     USE(a);
    192   }
    193 
    194   // Constructor for handling automatic up casting.
    195   // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected.
    196   template <typename S>
    197   V8_INLINE MaybeHandle(MaybeHandle<S> maybe_handle)
    198       : location_(reinterpret_cast<T**>(maybe_handle.location_)) {
    199     T* a = nullptr;
    200     S* b = nullptr;
    201     a = b;  // Fake assignment to enforce type checks.
    202     USE(a);
    203   }
    204 
    205   V8_INLINE void Assert() const { DCHECK_NOT_NULL(location_); }
    206   V8_INLINE void Check() const { CHECK_NOT_NULL(location_); }
    207 
    208   V8_INLINE Handle<T> ToHandleChecked() const {
    209     Check();
    210     return Handle<T>(location_);
    211   }
    212 
    213   // Convert to a Handle with a type that can be upcasted to.
    214   template <typename S>
    215   V8_INLINE bool ToHandle(Handle<S>* out) const {
    216     if (location_ == nullptr) {
    217       *out = Handle<T>::null();
    218       return false;
    219     } else {
    220       *out = Handle<T>(location_);
    221       return true;
    222     }
    223   }
    224 
    225   bool is_null() const { return location_ == nullptr; }
    226 
    227  protected:
    228   T** location_ = nullptr;
    229 
    230   // MaybeHandles of different classes are allowed to access each
    231   // other's location_.
    232   template <typename>
    233   friend class MaybeHandle;
    234 };
    235 
    236 
    237 // ----------------------------------------------------------------------------
    238 // A stack-allocated class that governs a number of local handles.
    239 // After a handle scope has been created, all local handles will be
    240 // allocated within that handle scope until either the handle scope is
    241 // deleted or another handle scope is created.  If there is already a
    242 // handle scope and a new one is created, all allocations will take
    243 // place in the new handle scope until it is deleted.  After that,
    244 // new handles will again be allocated in the original handle scope.
    245 //
    246 // After the handle scope of a local handle has been deleted the
    247 // garbage collector will no longer track the object stored in the
    248 // handle and may deallocate it.  The behavior of accessing a handle
    249 // for which the handle scope has been deleted is undefined.
    250 class HandleScope {
    251  public:
    252   explicit inline HandleScope(Isolate* isolate);
    253 
    254   inline ~HandleScope();
    255 
    256   // Counts the number of allocated handles.
    257   static int NumberOfHandles(Isolate* isolate);
    258 
    259   // Create a new handle or lookup a canonical handle.
    260   V8_INLINE static Object** GetHandle(Isolate* isolate, Object* value);
    261 
    262   // Creates a new handle with the given value.
    263   V8_INLINE static Object** CreateHandle(Isolate* isolate, Object* value);
    264 
    265   // Deallocates any extensions used by the current scope.
    266   static void DeleteExtensions(Isolate* isolate);
    267 
    268   static Address current_next_address(Isolate* isolate);
    269   static Address current_limit_address(Isolate* isolate);
    270   static Address current_level_address(Isolate* isolate);
    271 
    272   // Closes the HandleScope (invalidating all handles
    273   // created in the scope of the HandleScope) and returns
    274   // a Handle backed by the parent scope holding the
    275   // value of the argument handle.
    276   template <typename T>
    277   Handle<T> CloseAndEscape(Handle<T> handle_value);
    278 
    279   Isolate* isolate() { return isolate_; }
    280 
    281   // Limit for number of handles with --check-handle-count. This is
    282   // large enough to compile natives and pass unit tests with some
    283   // slack for future changes to natives.
    284   static const int kCheckHandleThreshold = 30 * 1024;
    285 
    286  private:
    287   // Prevent heap allocation or illegal handle scopes.
    288   HandleScope(const HandleScope&);
    289   void operator=(const HandleScope&);
    290   void* operator new(size_t size);
    291   void operator delete(void* size_t);
    292 
    293   Isolate* isolate_;
    294   Object** prev_next_;
    295   Object** prev_limit_;
    296 
    297   // Close the handle scope resetting limits to a previous state.
    298   static inline void CloseScope(Isolate* isolate,
    299                                 Object** prev_next,
    300                                 Object** prev_limit);
    301 
    302   // Extend the handle scope making room for more handles.
    303   static Object** Extend(Isolate* isolate);
    304 
    305 #ifdef ENABLE_HANDLE_ZAPPING
    306   // Zaps the handles in the half-open interval [start, end).
    307   static void ZapRange(Object** start, Object** end);
    308 #endif
    309 
    310   friend class v8::HandleScope;
    311   friend class DeferredHandles;
    312   friend class DeferredHandleScope;
    313   friend class HandleScopeImplementer;
    314   friend class Isolate;
    315 };
    316 
    317 
    318 // Forward declarations for CanonicalHandleScope.
    319 template <typename V>
    320 class IdentityMap;
    321 class RootIndexMap;
    322 
    323 
    324 // A CanonicalHandleScope does not open a new HandleScope. It changes the
    325 // existing HandleScope so that Handles created within are canonicalized.
    326 // This does not apply to nested inner HandleScopes unless a nested
    327 // CanonicalHandleScope is introduced. Handles are only canonicalized within
    328 // the same CanonicalHandleScope, but not across nested ones.
    329 class CanonicalHandleScope final {
    330  public:
    331   explicit CanonicalHandleScope(Isolate* isolate);
    332   ~CanonicalHandleScope();
    333 
    334  private:
    335   Object** Lookup(Object* object);
    336 
    337   Isolate* isolate_;
    338   Zone zone_;
    339   RootIndexMap* root_index_map_;
    340   IdentityMap<Object**>* identity_map_;
    341   // Ordinary nested handle scopes within the current one are not canonical.
    342   int canonical_level_;
    343   // We may have nested canonical scopes. Handles are canonical within each one.
    344   CanonicalHandleScope* prev_canonical_scope_;
    345 
    346   friend class HandleScope;
    347 };
    348 
    349 
    350 class DeferredHandleScope final {
    351  public:
    352   explicit DeferredHandleScope(Isolate* isolate);
    353   // The DeferredHandles object returned stores the Handles created
    354   // since the creation of this DeferredHandleScope.  The Handles are
    355   // alive as long as the DeferredHandles object is alive.
    356   DeferredHandles* Detach();
    357   ~DeferredHandleScope();
    358 
    359  private:
    360   Object** prev_limit_;
    361   Object** prev_next_;
    362   HandleScopeImplementer* impl_;
    363 
    364 #ifdef DEBUG
    365   bool handles_detached_;
    366   int prev_level_;
    367 #endif
    368 
    369   friend class HandleScopeImplementer;
    370 };
    371 
    372 
    373 // Seal off the current HandleScope so that new handles can only be created
    374 // if a new HandleScope is entered.
    375 class SealHandleScope final {
    376  public:
    377 #ifndef DEBUG
    378   explicit SealHandleScope(Isolate* isolate) {}
    379   ~SealHandleScope() {}
    380 #else
    381   explicit inline SealHandleScope(Isolate* isolate);
    382   inline ~SealHandleScope();
    383  private:
    384   Isolate* isolate_;
    385   Object** prev_limit_;
    386   int prev_sealed_level_;
    387 #endif
    388 };
    389 
    390 
    391 struct HandleScopeData final {
    392   Object** next;
    393   Object** limit;
    394   int level;
    395   int sealed_level;
    396   CanonicalHandleScope* canonical_scope;
    397 
    398   void Initialize() {
    399     next = limit = NULL;
    400     sealed_level = level = 0;
    401     canonical_scope = NULL;
    402   }
    403 };
    404 
    405 }  // namespace internal
    406 }  // namespace v8
    407 
    408 #endif  // V8_HANDLES_H_
    409