handles.h 13.3 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_HANDLES_HANDLES_H_
#define V8_HANDLES_HANDLES_H_
7

8 9
#include <type_traits>

10
#include "include/v8.h"
11
#include "src/base/functional.h"
12
#include "src/base/macros.h"
13 14
#include "src/common/checks.h"
#include "src/common/globals.h"
15
#include "src/zone/zone.h"
16

17 18
namespace v8 {
namespace internal {
19

20 21 22
// Forward declarations.
class DeferredHandles;
class HandleScopeImplementer;
23
class Isolate;
24
class LocalHeap;
25
class OffThreadIsolate;
26 27
template <typename T>
class MaybeHandle;
28
class Object;
29 30 31
class OrderedHashMap;
class OrderedHashSet;
class OrderedNameDictionary;
32
class RootVisitor;
33 34 35
class SmallOrderedHashMap;
class SmallOrderedHashSet;
class SmallOrderedNameDictionary;
36
class WasmExportedFunctionData;
37

38 39 40 41
// ----------------------------------------------------------------------------
// Base class for Handle instantiations.  Don't use directly.
class HandleBase {
 public:
42 43
  V8_INLINE explicit HandleBase(Address* location) : location_(location) {}
  V8_INLINE explicit HandleBase(Address object, Isolate* isolate);
44
  V8_INLINE explicit HandleBase(Address object, OffThreadIsolate* isolate);
45
  V8_INLINE explicit HandleBase(Address object, LocalHeap* local_heap);
46

47 48
  // Check if this handle refers to the exact same object as the other handle.
  V8_INLINE bool is_identical_to(const HandleBase that) const {
49 50
    SLOW_DCHECK((this->location_ == nullptr || this->IsDereferenceAllowed()) &&
                (that.location_ == nullptr || that.IsDereferenceAllowed()));
51
    if (this->location_ == that.location_) return true;
52
    if (this->location_ == nullptr || that.location_ == nullptr) return false;
53
    return *this->location_ == *that.location_;
54 55
  }

56
  V8_INLINE bool is_null() const { return location_ == nullptr; }
57

58 59 60 61
  // Returns the raw address where this handle is stored. This should only be
  // used for hashing handles; do not ever try to dereference it.
  V8_INLINE Address address() const { return bit_cast<Address>(location_); }

62
  // Returns the address to where the raw pointer is stored.
63
  V8_INLINE Address* location() const {
64
    SLOW_DCHECK(location_ == nullptr || IsDereferenceAllowed());
65
    return location_;
66 67
  }

68
 protected:
69
#ifdef DEBUG
70
  bool V8_EXPORT_PRIVATE IsDereferenceAllowed() const;
71 72
#else
  V8_INLINE
73
  bool V8_EXPORT_PRIVATE IsDereferenceAllowed() const { return true; }
74
#endif  // DEBUG
75

76 77 78 79
  // This uses type Address* as opposed to a pointer type to a typed
  // wrapper class, because it doesn't point to instances of such a
  // wrapper class. Design overview: https://goo.gl/Ph4CGz
  Address* location_;
80 81
};

82 83 84
// ----------------------------------------------------------------------------
// A Handle provides a reference to an object that survives relocation by
// the garbage collector.
85 86 87 88 89 90 91 92
//
// Handles are only valid within a HandleScope. When a handle is created
// for an object a cell is allocated in the current HandleScope.
//
// Also note that Handles do not provide default equality comparison or hashing
// operators on purpose. Such operators would be misleading, because intended
// semantics is ambiguous between Handle location and object identity. Instead
// use either {is_identical_to} or {location} explicitly.
93 94
template <typename T>
class Handle final : public HandleBase {
95
 public:
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
  // {ObjectRef} is returned by {Handle::operator->}. It should never be stored
  // anywhere or used in any other code; no one should ever have to spell out
  // {ObjectRef} in code. Its only purpose is to be dereferenced immediately by
  // "operator-> chaining". Returning the address of the field is valid because
  // this objects lifetime only ends at the end of the full statement.
  class ObjectRef {
   public:
    T* operator->() { return &object_; }

   private:
    friend class Handle<T>;
    explicit ObjectRef(T object) : object_(object) {}

    T object_;
  };

112 113 114 115 116 117 118 119
  V8_INLINE explicit Handle() : HandleBase(nullptr) {
    // Skip static type check in order to allow Handle<XXX>::null() as default
    // parameter values in non-inl header files without requiring full
    // definition of type XXX.
  }

  V8_INLINE explicit Handle(Address* location) : HandleBase(location) {
    // This static type check also fails for forward class declarations.
120
    static_assert(std::is_convertible<T*, Object*>::value,
121
                  "static type violation");
122
    // TODO(jkummerow): Runtime type check here as a SLOW_DCHECK?
123
  }
124

125
  V8_INLINE Handle(T object, Isolate* isolate);
126
  V8_INLINE Handle(T object, OffThreadIsolate* isolate);
127
  V8_INLINE Handle(T object, LocalHeap* local_heap);
128

129
  // Allocate a new handle for the object, do not canonicalize.
130
  V8_INLINE static Handle<T> New(T object, Isolate* isolate);
131

132 133
  // Constructor for handling automatic up casting.
  // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
134 135
  template <typename S, typename = typename std::enable_if<
                            std::is_convertible<S*, T*>::value>::type>
136
  // NOLINTNEXTLINE
137
  V8_INLINE Handle(Handle<S> handle) : HandleBase(handle) {}
138

139
  V8_INLINE ObjectRef operator->() const { return ObjectRef{**this}; }
140

141
  V8_INLINE T operator*() const {
142 143
    // unchecked_cast because we rather trust Handle<T> to contain a T than
    // include all the respective -inl.h headers for SLOW_DCHECKs.
144
    SLOW_DCHECK(IsDereferenceAllowed());
145
    return T::unchecked_cast(Object(*location()));
146
  }
147

148
  template <typename S>
149
  inline static const Handle<T> cast(Handle<S> that);
150

151
  // Consider declaring values that contain empty handles as
152
  // MaybeHandle to force validation before being used as handles.
153
  static const Handle<T> null() { return Handle<T>(); }
154

155 156 157
  // Location equality.
  bool equals(Handle<T> other) const { return address() == other.address(); }

158
  // Provide function object for location equality comparison.
159
  struct equal_to {
160
    V8_INLINE bool operator()(Handle<T> lhs, Handle<T> rhs) const {
161
      return lhs.equals(rhs);
162 163 164 165
    }
  };

  // Provide function object for location hashing.
166
  struct hash {
167
    V8_INLINE size_t operator()(Handle<T> const& handle) const {
168
      return base::hash<Address>()(handle.address());
169 170 171
    }
  };

172 173
 private:
  // Handles of different classes are allowed to access each other's location_.
174 175 176 177 178
  template <typename>
  friend class Handle;
  // MaybeHandle is allowed to access location_.
  template <typename>
  friend class MaybeHandle;
179 180
};

181 182 183
template <typename T>
inline std::ostream& operator<<(std::ostream& os, Handle<T> handle);

184
// ----------------------------------------------------------------------------
185 186 187 188 189 190 191 192 193 194 195 196
// 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.
197
class HandleScope {
198
 public:
199
  explicit inline HandleScope(Isolate* isolate);
200
  inline HandleScope(HandleScope&& other) V8_NOEXCEPT;
201

202 203 204 205 206
  // Allow placement new.
  void* operator new(size_t size, void* storage) {
    return ::operator new(size, storage);
  }

207 208 209 210
  // Prevent heap allocation or illegal handle scopes.
  void* operator new(size_t size) = delete;
  void operator delete(void* size_t) = delete;

211
  inline ~HandleScope();
212

213 214
  inline HandleScope& operator=(HandleScope&& other) V8_NOEXCEPT;

215
  // Counts the number of allocated handles.
216
  V8_EXPORT_PRIVATE static int NumberOfHandles(Isolate* isolate);
217

218
  // Create a new handle or lookup a canonical handle.
219
  V8_INLINE static Address* GetHandle(Isolate* isolate, Address value);
220

221
  // Creates a new handle with the given value.
222
  V8_INLINE static Address* CreateHandle(Isolate* isolate, Address value);
223

224
  // Deallocates any extensions used by the current scope.
225
  V8_EXPORT_PRIVATE static void DeleteExtensions(Isolate* isolate);
226

227 228 229
  static Address current_next_address(Isolate* isolate);
  static Address current_limit_address(Isolate* isolate);
  static Address current_level_address(Isolate* isolate);
230

231 232 233 234 235
  // 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 <typename T>
236
  Handle<T> CloseAndEscape(Handle<T> handle_value);
237

238
  Isolate* isolate() { return isolate_; }
239

240
  // Limit for number of handles with --check-handle-count. This is
241 242 243 244
  // large enough to compile natives and pass unit tests with some
  // slack for future changes to natives.
  static const int kCheckHandleThreshold = 30 * 1024;

245
 private:
246
  Isolate* isolate_;
247 248
  Address* prev_next_;
  Address* prev_limit_;
249

250
  // Close the handle scope resetting limits to a previous state.
251 252
  static inline void CloseScope(Isolate* isolate, Address* prev_next,
                                Address* prev_limit);
253

254
  // Extend the handle scope making room for more handles.
255
  V8_EXPORT_PRIVATE static Address* Extend(Isolate* isolate);
256

257
#ifdef ENABLE_HANDLE_ZAPPING
258
  // Zaps the handles in the half-open interval [start, end).
259
  V8_EXPORT_PRIVATE static void ZapRange(Address* start, Address* end);
260
#endif
261

262
  friend class v8::HandleScope;
263
  friend class DeferredHandles;
264
  friend class DeferredHandleScope;
265 266
  friend class HandleScopeImplementer;
  friend class Isolate;
267 268

  DISALLOW_COPY_AND_ASSIGN(HandleScope);
269
};
270

271
// Forward declarations for CanonicalHandleScope.
272
template <typename V, class AllocationPolicy>
273 274 275 276 277 278 279 280
class IdentityMap;
class RootIndexMap;

// A CanonicalHandleScope does not open a new HandleScope. It changes the
// existing HandleScope so that Handles created within are canonicalized.
// This does not apply to nested inner HandleScopes unless a nested
// CanonicalHandleScope is introduced. Handles are only canonicalized within
// the same CanonicalHandleScope, but not across nested ones.
281
class V8_EXPORT_PRIVATE CanonicalHandleScope final {
282 283 284 285 286
 public:
  explicit CanonicalHandleScope(Isolate* isolate);
  ~CanonicalHandleScope();

 private:
287
  Address* Lookup(Address object);
288 289 290 291

  Isolate* isolate_;
  Zone zone_;
  RootIndexMap* root_index_map_;
292
  IdentityMap<Address*, ZoneAllocationPolicy>* identity_map_;
293 294 295 296 297 298 299 300
  // Ordinary nested handle scopes within the current one are not canonical.
  int canonical_level_;
  // We may have nested canonical scopes. Handles are canonical within each one.
  CanonicalHandleScope* prev_canonical_scope_;

  friend class HandleScope;
};

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
// A DeferredHandleScope is a HandleScope in which handles are not destroyed
// when the DeferredHandleScope is left. Instead the DeferredHandleScope has to
// be detached with {Detach}, and the result of {Detach} has to be destroyed
// explicitly. A DeferredHandleScope should only be used with the following
// design pattern:
// 1) Open a HandleScope (not a DeferredHandleScope).
//    HandleScope scope(isolate_);
// 2) Create handles.
//    Handle<Object> h1 = handle(object1, isolate);
//    Handle<Object> h2 = handle(object2, isolate);
// 3) Open a DeferredHandleScope.
//    DeferredHandleScope deferred_scope(isolate);
// 4) Reopen handles which should be in the DeferredHandleScope, e.g only h1.
//    h1 = handle(*h1, isolate);
// 5) Detach the DeferredHandleScope.
//    DeferredHandles* deferred_handles = deferred_scope.Detach();
// 6) Destroy the deferred handles.
//    delete deferred_handles;
//
// Note: A DeferredHandleScope must not be opened within a DeferredHandleScope.
321
class V8_EXPORT_PRIVATE DeferredHandleScope final {
322 323 324 325 326
 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.
327
  std::unique_ptr<DeferredHandles> Detach();
328 329 330
  ~DeferredHandleScope();

 private:
331 332
  Address* prev_limit_;
  Address* prev_next_;
333 334 335
  HandleScopeImplementer* impl_;

#ifdef DEBUG
336
  bool handles_detached_ = false;
337 338 339 340 341 342
  int prev_level_;
#endif

  friend class HandleScopeImplementer;
};

343 344
// Seal off the current HandleScope so that new handles can only be created
// if a new HandleScope is entered.
345
class SealHandleScope final {
346 347
 public:
#ifndef DEBUG
348
  explicit SealHandleScope(Isolate* isolate) {}
349
  ~SealHandleScope() = default;
350
#else
351 352
  explicit inline SealHandleScope(Isolate* isolate);
  inline ~SealHandleScope();
353

354
 private:
355
  Isolate* isolate_;
356
  Address* prev_limit_;
357
  int prev_sealed_level_;
358
#endif
359 360
};

361
struct HandleScopeData final {
362 363
  Address* next;
  Address* limit;
364
  int level;
365 366
  int sealed_level;
  CanonicalHandleScope* canonical_scope;
367 368

  void Initialize() {
369
    next = limit = nullptr;
370
    sealed_level = level = 0;
371
    canonical_scope = nullptr;
372 373 374
  }
};

375 376
class OffThreadHandleScope {
 public:
377 378
  // Off-thread Handles are allocated in the parse/compile zone, and not
  // cleared out, so the scope doesn't have to do anything
379
  explicit OffThreadHandleScope(OffThreadIsolate* isolate) {}
380 381 382

  template <typename T>
  inline Handle<T> CloseAndEscape(Handle<T> handle_value);
383 384
};

385 386
}  // namespace internal
}  // namespace v8
387

388
#endif  // V8_HANDLES_HANDLES_H_