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