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_HANDLES_H_ 6 #define V8_HANDLES_HANDLES_H_ 7 8 #include <type_traits> 9 10 #include "src/base/functional.h" 11 #include "src/base/macros.h" 12 #include "src/common/checks.h" 13 #include "src/common/globals.h" 14 #include "src/zone/zone.h" 15 16 namespace v8 { 17 18 class HandleScope; 19 20 namespace internal { 21 22 // Forward declarations. 23 class HandleScopeImplementer; 24 class Isolate; 25 class LocalHeap; 26 class LocalIsolate; 27 template <typename T> 28 class MaybeHandle; 29 class Object; 30 class OrderedHashMap; 31 class OrderedHashSet; 32 class OrderedNameDictionary; 33 class RootVisitor; 34 class SmallOrderedHashMap; 35 class SmallOrderedHashSet; 36 class SmallOrderedNameDictionary; 37 class SwissNameDictionary; 38 class WasmExportedFunctionData; 39 40 // ---------------------------------------------------------------------------- 41 // Base class for Handle instantiations. Don't use directly. 42 class HandleBase { 43 public: HandleBase(Address * location)44 V8_INLINE explicit HandleBase(Address* location) : location_(location) {} 45 V8_INLINE explicit HandleBase(Address object, Isolate* isolate); 46 V8_INLINE explicit HandleBase(Address object, LocalIsolate* isolate); 47 V8_INLINE explicit HandleBase(Address object, LocalHeap* local_heap); 48 49 // Check if this handle refers to the exact same object as the other handle. 50 V8_INLINE bool is_identical_to(const HandleBase that) const; is_null()51 V8_INLINE bool is_null() const { return location_ == nullptr; } 52 53 // Returns the raw address where this handle is stored. This should only be 54 // used for hashing handles; do not ever try to dereference it. address()55 V8_INLINE Address address() const { return bit_cast<Address>(location_); } 56 57 // Returns the address to where the raw pointer is stored. 58 // TODO(leszeks): This should probably be a const Address*, to encourage using 59 // PatchValue for modifying the handle's value. location()60 V8_INLINE Address* location() const { 61 SLOW_DCHECK(location_ == nullptr || IsDereferenceAllowed()); 62 return location_; 63 } 64 65 protected: 66 #ifdef DEBUG 67 bool V8_EXPORT_PRIVATE IsDereferenceAllowed() const; 68 #else 69 V8_INLINE 70 bool V8_EXPORT_PRIVATE IsDereferenceAllowed() const { return true; } 71 #endif // DEBUG 72 73 // This uses type Address* as opposed to a pointer type to a typed 74 // wrapper class, because it doesn't point to instances of such a 75 // wrapper class. Design overview: https://goo.gl/Ph4CGz 76 Address* location_; 77 }; 78 79 // ---------------------------------------------------------------------------- 80 // A Handle provides a reference to an object that survives relocation by 81 // the garbage collector. 82 // 83 // Handles are only valid within a HandleScope. When a handle is created 84 // for an object a cell is allocated in the current HandleScope. 85 // 86 // Also note that Handles do not provide default equality comparison or hashing 87 // operators on purpose. Such operators would be misleading, because intended 88 // semantics is ambiguous between Handle location and object identity. Instead 89 // use either {is_identical_to} or {location} explicitly. 90 template <typename T> 91 class Handle final : public HandleBase { 92 public: 93 // {ObjectRef} is returned by {Handle::operator->}. It should never be stored 94 // anywhere or used in any other code; no one should ever have to spell out 95 // {ObjectRef} in code. Its only purpose is to be dereferenced immediately by 96 // "operator-> chaining". Returning the address of the field is valid because 97 // this objects lifetime only ends at the end of the full statement. 98 class ObjectRef { 99 public: 100 T* operator->() { return &object_; } 101 102 private: 103 friend class Handle<T>; ObjectRef(T object)104 explicit ObjectRef(T object) : object_(object) {} 105 106 T object_; 107 }; 108 Handle()109 V8_INLINE explicit Handle() : HandleBase(nullptr) { 110 // Skip static type check in order to allow Handle<XXX>::null() as default 111 // parameter values in non-inl header files without requiring full 112 // definition of type XXX. 113 } 114 Handle(Address * location)115 V8_INLINE explicit Handle(Address* location) : HandleBase(location) { 116 // This static type check also fails for forward class declarations. 117 static_assert(std::is_convertible<T*, Object*>::value, 118 "static type violation"); 119 // TODO(jkummerow): Runtime type check here as a SLOW_DCHECK? 120 } 121 122 V8_INLINE Handle(T object, Isolate* isolate); 123 V8_INLINE Handle(T object, LocalIsolate* isolate); 124 V8_INLINE Handle(T object, LocalHeap* local_heap); 125 126 // Allocate a new handle for the object, do not canonicalize. 127 V8_INLINE static Handle<T> New(T object, Isolate* isolate); 128 129 // Constructor for handling automatic up casting. 130 // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected. 131 template <typename S, typename = typename std::enable_if< 132 std::is_convertible<S*, T*>::value>::type> Handle(Handle<S> handle)133 V8_INLINE Handle(Handle<S> handle) : HandleBase(handle) {} 134 135 V8_INLINE ObjectRef operator->() const { return ObjectRef{**this}; } 136 137 V8_INLINE T operator*() const { 138 // unchecked_cast because we rather trust Handle<T> to contain a T than 139 // include all the respective -inl.h headers for SLOW_DCHECKs. 140 SLOW_DCHECK(IsDereferenceAllowed()); 141 return T::unchecked_cast(Object(*location())); 142 } 143 144 template <typename S> 145 inline static const Handle<T> cast(Handle<S> that); 146 147 // Consider declaring values that contain empty handles as 148 // MaybeHandle to force validation before being used as handles. null()149 static const Handle<T> null() { return Handle<T>(); } 150 151 // Location equality. equals(Handle<T> other)152 bool equals(Handle<T> other) const { return address() == other.address(); } 153 154 // Patches this Handle's value, in-place, with a new value. All handles with 155 // the same location will see this update. PatchValue(T new_value)156 void PatchValue(T new_value) { 157 SLOW_DCHECK(location_ != nullptr && IsDereferenceAllowed()); 158 *location_ = new_value.ptr(); 159 } 160 161 // Provide function object for location equality comparison. 162 struct equal_to { operatorequal_to163 V8_INLINE bool operator()(Handle<T> lhs, Handle<T> rhs) const { 164 return lhs.equals(rhs); 165 } 166 }; 167 168 // Provide function object for location hashing. 169 struct hash { operatorhash170 V8_INLINE size_t operator()(Handle<T> const& handle) const { 171 return base::hash<Address>()(handle.address()); 172 } 173 }; 174 175 private: 176 // Handles of different classes are allowed to access each other's location_. 177 template <typename> 178 friend class Handle; 179 // MaybeHandle is allowed to access location_. 180 template <typename> 181 friend class MaybeHandle; 182 }; 183 184 template <typename T> 185 std::ostream& operator<<(std::ostream& os, Handle<T> handle); 186 187 // ---------------------------------------------------------------------------- 188 // A stack-allocated class that governs a number of local handles. 189 // After a handle scope has been created, all local handles will be 190 // allocated within that handle scope until either the handle scope is 191 // deleted or another handle scope is created. If there is already a 192 // handle scope and a new one is created, all allocations will take 193 // place in the new handle scope until it is deleted. After that, 194 // new handles will again be allocated in the original handle scope. 195 // 196 // After the handle scope of a local handle has been deleted the 197 // garbage collector will no longer track the object stored in the 198 // handle and may deallocate it. The behavior of accessing a handle 199 // for which the handle scope has been deleted is undefined. 200 class V8_NODISCARD HandleScope { 201 public: 202 explicit V8_INLINE HandleScope(Isolate* isolate); 203 inline HandleScope(HandleScope&& other) V8_NOEXCEPT; 204 HandleScope(const HandleScope&) = delete; 205 HandleScope& operator=(const HandleScope&) = delete; 206 207 // Allow placement new. new(size_t size,void * storage)208 void* operator new(size_t size, void* storage) { 209 return ::operator new(size, storage); 210 } 211 212 // Prevent heap allocation or illegal handle scopes. 213 void* operator new(size_t size) = delete; 214 void operator delete(void* size_t) = delete; 215 216 V8_INLINE ~HandleScope(); 217 218 inline HandleScope& operator=(HandleScope&& other) V8_NOEXCEPT; 219 220 // Counts the number of allocated handles. 221 V8_EXPORT_PRIVATE static int NumberOfHandles(Isolate* isolate); 222 223 // Create a new handle or lookup a canonical handle. 224 V8_INLINE static Address* GetHandle(Isolate* isolate, Address value); 225 226 // Creates a new handle with the given value. 227 V8_INLINE static Address* CreateHandle(Isolate* isolate, Address value); 228 229 // Deallocates any extensions used by the current scope. 230 V8_EXPORT_PRIVATE static void DeleteExtensions(Isolate* isolate); 231 232 static Address current_next_address(Isolate* isolate); 233 static Address current_limit_address(Isolate* isolate); 234 static Address current_level_address(Isolate* isolate); 235 236 // Closes the HandleScope (invalidating all handles 237 // created in the scope of the HandleScope) and returns 238 // a Handle backed by the parent scope holding the 239 // value of the argument handle. 240 template <typename T> 241 Handle<T> CloseAndEscape(Handle<T> handle_value); 242 isolate()243 Isolate* isolate() { return isolate_; } 244 245 // Limit for number of handles with --check-handle-count. This is 246 // large enough to compile natives and pass unit tests with some 247 // slack for future changes to natives. 248 static const int kCheckHandleThreshold = 30 * 1024; 249 250 private: 251 Isolate* isolate_; 252 Address* prev_next_; 253 Address* prev_limit_; 254 255 // Close the handle scope resetting limits to a previous state. 256 static V8_INLINE void CloseScope(Isolate* isolate, Address* prev_next, 257 Address* prev_limit); 258 259 // Extend the handle scope making room for more handles. 260 V8_EXPORT_PRIVATE static Address* Extend(Isolate* isolate); 261 262 #ifdef ENABLE_HANDLE_ZAPPING 263 // Zaps the handles in the half-open interval [start, end). 264 V8_EXPORT_PRIVATE static void ZapRange(Address* start, Address* end); 265 #endif 266 267 friend class v8::HandleScope; 268 friend class HandleScopeImplementer; 269 friend class Isolate; 270 friend class LocalHandles; 271 friend class LocalHandleScope; 272 friend class PersistentHandles; 273 }; 274 275 // Forward declarations for CanonicalHandleScope. 276 template <typename V, class AllocationPolicy> 277 class IdentityMap; 278 class RootIndexMap; 279 class OptimizedCompilationInfo; 280 281 namespace maglev { 282 class ExportedMaglevCompilationInfo; 283 } // namespace maglev 284 285 using CanonicalHandlesMap = IdentityMap<Address*, ZoneAllocationPolicy>; 286 287 // A CanonicalHandleScope does not open a new HandleScope. It changes the 288 // existing HandleScope so that Handles created within are canonicalized. 289 // This does not apply to nested inner HandleScopes unless a nested 290 // CanonicalHandleScope is introduced. Handles are only canonicalized within 291 // the same CanonicalHandleScope, but not across nested ones. 292 class V8_EXPORT_PRIVATE V8_NODISCARD CanonicalHandleScope { 293 public: 294 // If no Zone is passed to this constructor, we create (and own) a new zone. 295 // To properly dispose of said zone, we need to first free the identity_map_ 296 // which is done manually even though identity_map_ is a unique_ptr. 297 explicit CanonicalHandleScope(Isolate* isolate, Zone* zone = nullptr); 298 ~CanonicalHandleScope(); 299 300 protected: 301 std::unique_ptr<CanonicalHandlesMap> DetachCanonicalHandles(); 302 303 Zone* zone_; // *Not* const, may be mutated by subclasses. 304 305 private: 306 Address* Lookup(Address object); 307 308 Isolate* const isolate_; 309 RootIndexMap* root_index_map_; 310 std::unique_ptr<CanonicalHandlesMap> identity_map_; 311 // Ordinary nested handle scopes within the current one are not canonical. 312 int canonical_level_; 313 // We may have nested canonical scopes. Handles are canonical within each one. 314 CanonicalHandleScope* prev_canonical_scope_; 315 316 friend class HandleScope; 317 }; 318 319 template <class CompilationInfoT> 320 class V8_EXPORT_PRIVATE V8_NODISCARD CanonicalHandleScopeForOptimization final 321 : public CanonicalHandleScope { 322 public: 323 // We created the 324 // CanonicalHandlesMap on the compilation info's zone(). In the 325 // CanonicalHandleScope destructor we hand off the canonical handle map to the 326 // compilation info. The compilation info is responsible for the disposal. 327 explicit CanonicalHandleScopeForOptimization(Isolate* isolate, 328 CompilationInfoT* info); 329 ~CanonicalHandleScopeForOptimization(); 330 331 private: 332 CompilationInfoT* const info_; 333 }; 334 335 using CanonicalHandleScopeForTurbofan = 336 CanonicalHandleScopeForOptimization<OptimizedCompilationInfo>; 337 using CanonicalHandleScopeForMaglev = 338 CanonicalHandleScopeForOptimization<maglev::ExportedMaglevCompilationInfo>; 339 340 // Seal off the current HandleScope so that new handles can only be created 341 // if a new HandleScope is entered. 342 class V8_NODISCARD SealHandleScope final { 343 public: 344 #ifndef DEBUG SealHandleScope(Isolate * isolate)345 explicit SealHandleScope(Isolate* isolate) {} 346 ~SealHandleScope() = default; 347 #else 348 explicit inline SealHandleScope(Isolate* isolate); 349 inline ~SealHandleScope(); 350 351 private: 352 Isolate* isolate_; 353 Address* prev_limit_; 354 int prev_sealed_level_; 355 #endif 356 }; 357 358 struct HandleScopeData final { 359 Address* next; 360 Address* limit; 361 int level; 362 int sealed_level; 363 CanonicalHandleScope* canonical_scope; 364 Initializefinal365 void Initialize() { 366 next = limit = nullptr; 367 sealed_level = level = 0; 368 canonical_scope = nullptr; 369 } 370 }; 371 372 } // namespace internal 373 } // namespace v8 374 375 #endif // V8_HANDLES_HANDLES_H_ 376