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_GLOBAL_HANDLES_H_ 6 #define V8_HANDLES_GLOBAL_HANDLES_H_ 7 8 #include <memory> 9 #include <type_traits> 10 #include <utility> 11 #include <vector> 12 13 #include "include/v8-callbacks.h" 14 #include "include/v8-persistent-handle.h" 15 #include "include/v8-profiler.h" 16 #include "include/v8-traced-handle.h" 17 #include "src/handles/handles.h" 18 #include "src/heap/heap.h" 19 #include "src/objects/heap-object.h" 20 #include "src/objects/objects.h" 21 #include "src/utils/utils.h" 22 23 namespace v8 { 24 namespace internal { 25 26 class HeapStats; 27 class RootVisitor; 28 29 enum WeaknessType { 30 // Embedder gets a handle to the dying object. 31 FINALIZER_WEAK, 32 // In the following cases, the embedder gets the parameter they passed in 33 // earlier, and 0 or 2 first embedder fields. Note that the internal 34 // fields must contain aligned non-V8 pointers. Getting pointers to V8 35 // objects through this interface would be GC unsafe so in that case the 36 // embedder gets a null pointer instead. 37 PHANTOM_WEAK, 38 PHANTOM_WEAK_2_EMBEDDER_FIELDS, 39 // The handle is automatically reset by the garbage collector when 40 // the object is no longer reachable. 41 PHANTOM_WEAK_RESET_HANDLE 42 }; 43 44 // Global handles hold handles that are independent of stack-state and can have 45 // callbacks and finalizers attached to them. 46 class V8_EXPORT_PRIVATE GlobalHandles final { 47 public: 48 static void EnableMarkingBarrier(Isolate*); 49 static void DisableMarkingBarrier(Isolate*); 50 51 GlobalHandles(const GlobalHandles&) = delete; 52 GlobalHandles& operator=(const GlobalHandles&) = delete; 53 54 template <class NodeType> 55 class NodeBlock; 56 57 // 58 // API for regular handles. 59 // 60 61 static void MoveGlobal(Address** from, Address** to); 62 63 static Handle<Object> CopyGlobal(Address* location); 64 65 static void Destroy(Address* location); 66 67 // Make the global handle weak and set the callback parameter for the 68 // handle. When the garbage collector recognizes that only weak global 69 // handles point to an object the callback function is invoked (for each 70 // handle) with the handle and corresponding parameter as arguments. By 71 // default the handle still contains a pointer to the object that is being 72 // collected. For this reason the object is not collected until the next 73 // GC. For a phantom weak handle the handle is cleared (set to a Smi) 74 // before the callback is invoked, but the handle can still be identified 75 // in the callback by using the location() of the handle. 76 static void MakeWeak(Address* location, void* parameter, 77 WeakCallbackInfo<void>::Callback weak_callback, 78 v8::WeakCallbackType type); 79 static void MakeWeak(Address** location_addr); 80 81 static void AnnotateStrongRetainer(Address* location, const char* label); 82 83 // Clear the weakness of a global handle. 84 static void* ClearWeakness(Address* location); 85 86 // Tells whether global handle is weak. 87 static bool IsWeak(Address* location); 88 89 // 90 // API for traced handles. 91 // 92 93 static void MoveTracedReference(Address** from, Address** to); 94 static void CopyTracedReference(const Address* const* from, Address** to); 95 static void DestroyTracedReference(Address* location); 96 static void MarkTraced(Address* location); 97 98 explicit GlobalHandles(Isolate* isolate); 99 ~GlobalHandles(); 100 101 // Creates a new global handle that is alive until Destroy is called. 102 Handle<Object> Create(Object value); 103 Handle<Object> Create(Address value); 104 105 template <typename T> 106 inline Handle<T> Create(T value); 107 108 Handle<Object> CreateTraced(Object value, Address* slot, 109 GlobalHandleStoreMode store_mode, 110 bool is_on_stack); 111 Handle<Object> CreateTraced(Object value, Address* slot, 112 GlobalHandleStoreMode store_mode); 113 Handle<Object> CreateTraced(Address value, Address* slot, 114 GlobalHandleStoreMode store_mode); 115 116 void RecordStats(HeapStats* stats); 117 118 size_t InvokeFirstPassWeakCallbacks(); 119 void InvokeSecondPassPhantomCallbacks(); 120 121 // Process pending weak handles. 122 // Returns the number of freed nodes. 123 size_t PostGarbageCollectionProcessing( 124 GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags); 125 126 void IterateStrongRoots(RootVisitor* v); 127 void IterateStrongStackRoots(RootVisitor* v); 128 void IterateWeakRoots(RootVisitor* v); 129 void IterateAllRoots(RootVisitor* v); 130 void IterateAllYoungRoots(RootVisitor* v); 131 132 // Iterates over all handles that have embedder-assigned class ID. 133 void IterateAllRootsWithClassIds(v8::PersistentHandleVisitor* v); 134 135 // Iterates over all handles in the new space that have embedder-assigned 136 // class ID. 137 void IterateAllYoungRootsWithClassIds(v8::PersistentHandleVisitor* v); 138 139 // Iterate over all handles in the new space that are weak, unmodified 140 // and have class IDs 141 void IterateYoungWeakRootsWithClassIds(v8::PersistentHandleVisitor* v); 142 143 // Iterates over all traces handles represented by TracedGlobal. 144 void IterateTracedNodes( 145 v8::EmbedderHeapTracer::TracedGlobalHandleVisitor* visitor); 146 147 // Marks handles with finalizers on the predicate |should_reset_handle| as 148 // pending. 149 void IterateWeakRootsIdentifyFinalizers( 150 WeakSlotCallbackWithHeap should_reset_handle); 151 // Uses the provided visitor |v| to mark handles with finalizers that are 152 // pending. 153 void IterateWeakRootsForFinalizers(RootVisitor* v); 154 // Marks handles that are phantom or have callbacks based on the predicate 155 // |should_reset_handle| as pending. 156 void IterateWeakRootsForPhantomHandles( 157 WeakSlotCallbackWithHeap should_reset_handle); 158 159 // Note: The following *Young* methods are used for the Scavenger to 160 // identify and process handles in the young generation. The set of young 161 // handles is complete but the methods may encounter handles that are 162 // already in old space. 163 164 // Iterates over strong and dependent handles. See the note above. 165 void IterateYoungStrongAndDependentRoots(RootVisitor* v); 166 167 // Marks weak unmodified handles satisfying |is_dead| as pending. 168 void MarkYoungWeakDeadObjectsPending(WeakSlotCallbackWithHeap is_dead); 169 170 // Iterates over weak independent or unmodified handles. 171 // See the note above. 172 void IterateYoungWeakDeadObjectsForFinalizers(RootVisitor* v); 173 void IterateYoungWeakObjectsForPhantomHandles( 174 RootVisitor* v, WeakSlotCallbackWithHeap should_reset_handle); 175 176 // Identify unmodified objects that are in weak state and marks them 177 // unmodified 178 void IdentifyWeakUnmodifiedObjects(WeakSlotCallback is_unmodified); 179 isolate()180 Isolate* isolate() const { return isolate_; } 181 182 size_t TotalSize() const; 183 size_t UsedSize() const; 184 185 // Number of global handles. 186 size_t handles_count() const; 187 GetAndResetGlobalHandleResetCount()188 size_t GetAndResetGlobalHandleResetCount() { 189 size_t old = number_of_phantom_handle_resets_; 190 number_of_phantom_handle_resets_ = 0; 191 return old; 192 } 193 194 void SetStackStart(void* stack_start); 195 void NotifyEmptyEmbedderStack(); 196 void CleanupOnStackReferencesBelowCurrentStackPosition(); 197 size_t NumberOfOnStackHandlesForTesting(); 198 199 #ifdef DEBUG 200 void PrintStats(); 201 void Print(); 202 #endif // DEBUG 203 204 private: 205 // Internal node structures. 206 class Node; 207 template <class BlockType> 208 class NodeIterator; 209 template <class NodeType> 210 class NodeSpace; 211 class PendingPhantomCallback; 212 class TracedNode; 213 class OnStackTracedNodeSpace; 214 215 static GlobalHandles* From(const TracedNode*); 216 217 bool InRecursiveGC(unsigned gc_processing_counter); 218 219 void InvokeSecondPassPhantomCallbacksFromTask(); 220 void InvokeOrScheduleSecondPassPhantomCallbacks(bool synchronous_second_pass); 221 size_t PostScavengeProcessing(unsigned post_processing_count); 222 size_t PostMarkSweepProcessing(unsigned post_processing_count); 223 224 template <typename T> 225 size_t InvokeFirstPassWeakCallbacks( 226 std::vector<std::pair<T*, PendingPhantomCallback>>* pending); 227 228 template <typename T> 229 void UpdateAndCompactListOfYoungNode(std::vector<T*>* node_list); 230 void UpdateListOfYoungNodes(); 231 232 void ApplyPersistentHandleVisitor(v8::PersistentHandleVisitor* visitor, 233 Node* node); 234 235 Isolate* const isolate_; 236 bool is_marking_ = false; 237 238 std::unique_ptr<NodeSpace<Node>> regular_nodes_; 239 // Contains all nodes holding young objects. Note: when the list 240 // is accessed, some of the objects may have been promoted already. 241 std::vector<Node*> young_nodes_; 242 243 std::unique_ptr<NodeSpace<TracedNode>> traced_nodes_; 244 std::vector<TracedNode*> traced_young_nodes_; 245 std::unique_ptr<OnStackTracedNodeSpace> on_stack_nodes_; 246 247 size_t number_of_phantom_handle_resets_ = 0; 248 249 std::vector<std::pair<Node*, PendingPhantomCallback>> 250 regular_pending_phantom_callbacks_; 251 std::vector<std::pair<TracedNode*, PendingPhantomCallback>> 252 traced_pending_phantom_callbacks_; 253 std::vector<PendingPhantomCallback> second_pass_callbacks_; 254 bool second_pass_callbacks_task_posted_ = false; 255 bool running_second_pass_callbacks_ = false; 256 257 // Counter for recursive garbage collections during callback processing. 258 unsigned post_gc_processing_count_ = 0; 259 }; 260 261 class GlobalHandles::PendingPhantomCallback final { 262 public: 263 using Data = v8::WeakCallbackInfo<void>; 264 265 enum InvocationType { kFirstPass, kSecondPass }; 266 PendingPhantomCallback(Data::Callback callback,void * parameter,void * embedder_fields[v8::kEmbedderFieldsInWeakCallback])267 PendingPhantomCallback( 268 Data::Callback callback, void* parameter, 269 void* embedder_fields[v8::kEmbedderFieldsInWeakCallback]) 270 : callback_(callback), parameter_(parameter) { 271 for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) { 272 embedder_fields_[i] = embedder_fields[i]; 273 } 274 } 275 276 void Invoke(Isolate* isolate, InvocationType type); 277 callback()278 Data::Callback callback() const { return callback_; } 279 280 private: 281 Data::Callback callback_; 282 void* parameter_; 283 void* embedder_fields_[v8::kEmbedderFieldsInWeakCallback]; 284 }; 285 286 class EternalHandles final { 287 public: 288 EternalHandles() = default; 289 ~EternalHandles(); 290 EternalHandles(const EternalHandles&) = delete; 291 EternalHandles& operator=(const EternalHandles&) = delete; 292 293 // Create an EternalHandle, overwriting the index. 294 V8_EXPORT_PRIVATE void Create(Isolate* isolate, Object object, int* index); 295 296 // Grab the handle for an existing EternalHandle. Get(int index)297 inline Handle<Object> Get(int index) { 298 return Handle<Object>(GetLocation(index)); 299 } 300 301 // Iterates over all handles. 302 void IterateAllRoots(RootVisitor* visitor); 303 // Iterates over all handles which might be in the young generation. 304 void IterateYoungRoots(RootVisitor* visitor); 305 // Rebuilds new space list. 306 void PostGarbageCollectionProcessing(); 307 handles_count()308 size_t handles_count() const { return size_; } 309 310 private: 311 static const int kInvalidIndex = -1; 312 static const int kShift = 8; 313 static const int kSize = 1 << kShift; 314 static const int kMask = 0xff; 315 316 // Gets the slot for an index. This returns an Address* rather than an 317 // ObjectSlot in order to avoid #including slots.h in this header file. GetLocation(int index)318 inline Address* GetLocation(int index) { 319 DCHECK(index >= 0 && index < size_); 320 return &blocks_[index >> kShift][index & kMask]; 321 } 322 323 int size_ = 0; 324 std::vector<Address*> blocks_; 325 std::vector<int> young_node_indices_; 326 }; 327 328 // A vector of global Handles which automatically manages the backing of those 329 // Handles as a vector of strong-rooted addresses. Handles returned by the 330 // vector are valid as long as they are present in the vector. 331 template <typename T> 332 class GlobalHandleVector { 333 public: 334 class Iterator { 335 public: Iterator(std::vector<Address,StrongRootBlockAllocator>::iterator it)336 explicit Iterator( 337 std::vector<Address, StrongRootBlockAllocator>::iterator it) 338 : it_(it) {} 339 Iterator& operator++() { 340 ++it_; 341 return *this; 342 } 343 Handle<T> operator*() { return Handle<T>(&*it_); } 344 bool operator!=(Iterator& that) { return it_ != that.it_; } 345 346 private: 347 std::vector<Address, StrongRootBlockAllocator>::iterator it_; 348 }; 349 GlobalHandleVector(Heap * heap)350 explicit GlobalHandleVector(Heap* heap) 351 : locations_(StrongRootBlockAllocator(heap)) {} 352 353 Handle<T> operator[](size_t i) { return Handle<T>(&locations_[i]); } 354 size()355 size_t size() const { return locations_.size(); } empty()356 bool empty() const { return locations_.empty(); } 357 Push(T val)358 void Push(T val) { locations_.push_back(val.ptr()); } 359 // Handles into the GlobalHandleVector become invalid when they are removed, 360 // so "pop" returns a raw object rather than a handle. 361 inline T Pop(); 362 begin()363 Iterator begin() { return Iterator(locations_.begin()); } end()364 Iterator end() { return Iterator(locations_.end()); } 365 366 private: 367 std::vector<Address, StrongRootBlockAllocator> locations_; 368 }; 369 370 } // namespace internal 371 } // namespace v8 372 373 #endif // V8_HANDLES_GLOBAL_HANDLES_H_ 374