LCOV - code coverage report
Current view: top level - src - handles.h (source / functions) Hit Total Coverage
Test: app.info Lines: 27 27 100.0 %
Date: 2017-10-20 Functions: 60 68 88.2 %

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

Generated by: LCOV version 1.10