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_GLOBAL_HANDLES_H_ 6 #define V8_GLOBAL_HANDLES_H_ 7 8 #include "include/v8.h" 9 #include "include/v8-profiler.h" 10 11 #include "src/handles.h" 12 #include "src/list.h" 13 #include "src/utils.h" 14 15 namespace v8 { 16 namespace internal { 17 18 class HeapStats; 19 class ObjectVisitor; 20 21 // Structure for tracking global handles. 22 // A single list keeps all the allocated global handles. 23 // Destroyed handles stay in the list but is added to the free list. 24 // At GC the destroyed global handles are removed from the free list 25 // and deallocated. 26 27 // Data structures for tracking object groups and implicit references. 28 29 // An object group is treated like a single JS object: if one of object in 30 // the group is alive, all objects in the same group are considered alive. 31 // An object group is used to simulate object relationship in a DOM tree. 32 33 // An implicit references group consists of two parts: a parent object and a 34 // list of children objects. If the parent is alive, all the children are alive 35 // too. 36 37 struct ObjectGroup { ObjectGroupObjectGroup38 explicit ObjectGroup(size_t length) 39 : info(NULL), length(length) { 40 DCHECK(length > 0); 41 objects = new Object**[length]; 42 } 43 ~ObjectGroup(); 44 45 v8::RetainedObjectInfo* info; 46 Object*** objects; 47 size_t length; 48 }; 49 50 51 struct ImplicitRefGroup { ImplicitRefGroupImplicitRefGroup52 ImplicitRefGroup(HeapObject** parent, size_t length) 53 : parent(parent), length(length) { 54 DCHECK(length > 0); 55 children = new Object**[length]; 56 } 57 ~ImplicitRefGroup(); 58 59 HeapObject** parent; 60 Object*** children; 61 size_t length; 62 }; 63 64 65 // For internal bookkeeping. 66 struct ObjectGroupConnection { ObjectGroupConnectionObjectGroupConnection67 ObjectGroupConnection(UniqueId id, Object** object) 68 : id(id), object(object) {} 69 70 bool operator==(const ObjectGroupConnection& other) const { 71 return id == other.id; 72 } 73 74 bool operator<(const ObjectGroupConnection& other) const { 75 return id < other.id; 76 } 77 78 UniqueId id; 79 Object** object; 80 }; 81 82 83 struct ObjectGroupRetainerInfo { ObjectGroupRetainerInfoObjectGroupRetainerInfo84 ObjectGroupRetainerInfo(UniqueId id, RetainedObjectInfo* info) 85 : id(id), info(info) {} 86 87 bool operator==(const ObjectGroupRetainerInfo& other) const { 88 return id == other.id; 89 } 90 91 bool operator<(const ObjectGroupRetainerInfo& other) const { 92 return id < other.id; 93 } 94 95 UniqueId id; 96 RetainedObjectInfo* info; 97 }; 98 99 enum WeaknessType { 100 // Embedder gets a handle to the dying object. 101 FINALIZER_WEAK, 102 // In the following cases, the embedder gets the parameter they passed in 103 // earlier, and 0 or 2 first internal fields. Note that the internal 104 // fields must contain aligned non-V8 pointers. Getting pointers to V8 105 // objects through this interface would be GC unsafe so in that case the 106 // embedder gets a null pointer instead. 107 PHANTOM_WEAK, 108 PHANTOM_WEAK_2_INTERNAL_FIELDS, 109 // The handle is automatically reset by the garbage collector when 110 // the object is no longer reachable. 111 PHANTOM_WEAK_RESET_HANDLE 112 }; 113 114 class GlobalHandles { 115 public: 116 ~GlobalHandles(); 117 118 // Creates a new global handle that is alive until Destroy is called. 119 Handle<Object> Create(Object* value); 120 121 // Copy a global handle 122 static Handle<Object> CopyGlobal(Object** location); 123 124 // Destroy a global handle. 125 static void Destroy(Object** location); 126 127 // Make the global handle weak and set the callback parameter for the 128 // handle. When the garbage collector recognizes that only weak global 129 // handles point to an object the callback function is invoked (for each 130 // handle) with the handle and corresponding parameter as arguments. By 131 // default the handle still contains a pointer to the object that is being 132 // collected. For this reason the object is not collected until the next 133 // GC. For a phantom weak handle the handle is cleared (set to a Smi) 134 // before the callback is invoked, but the handle can still be identified 135 // in the callback by using the location() of the handle. 136 static void MakeWeak(Object** location, void* parameter, 137 WeakCallbackInfo<void>::Callback weak_callback, 138 v8::WeakCallbackType type); 139 140 static void MakeWeak(Object*** location_addr); 141 142 void RecordStats(HeapStats* stats); 143 144 // Returns the current number of weak handles. 145 int NumberOfWeakHandles(); 146 147 // Returns the current number of weak handles to global objects. 148 // These handles are also included in NumberOfWeakHandles(). 149 int NumberOfGlobalObjectWeakHandles(); 150 151 // Returns the current number of handles to global objects. global_handles_count()152 int global_handles_count() const { 153 return number_of_global_handles_; 154 } 155 NumberOfPhantomHandleResets()156 size_t NumberOfPhantomHandleResets() { 157 return number_of_phantom_handle_resets_; 158 } 159 ResetNumberOfPhantomHandleResets()160 void ResetNumberOfPhantomHandleResets() { 161 number_of_phantom_handle_resets_ = 0; 162 } 163 164 // Clear the weakness of a global handle. 165 static void* ClearWeakness(Object** location); 166 167 // Mark the reference to this object independent of any object group. 168 static void MarkIndependent(Object** location); 169 170 // Mark the reference to this object externaly unreachable. 171 static void MarkPartiallyDependent(Object** location); 172 173 static bool IsIndependent(Object** location); 174 175 // Tells whether global handle is near death. 176 static bool IsNearDeath(Object** location); 177 178 // Tells whether global handle is weak. 179 static bool IsWeak(Object** location); 180 181 // Process pending weak handles. 182 // Returns the number of freed nodes. 183 int PostGarbageCollectionProcessing( 184 GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags); 185 186 // Iterates over all strong handles. 187 void IterateStrongRoots(ObjectVisitor* v); 188 189 // Iterates over all handles. 190 void IterateAllRoots(ObjectVisitor* v); 191 192 // Iterates over all handles that have embedder-assigned class ID. 193 void IterateAllRootsWithClassIds(ObjectVisitor* v); 194 195 // Iterates over all handles in the new space that have embedder-assigned 196 // class ID. 197 void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v); 198 199 // Iterate over all handles in the new space that are weak, unmodified 200 // and have class IDs 201 void IterateWeakRootsInNewSpaceWithClassIds(ObjectVisitor* v); 202 203 // Iterates over all weak roots in heap. 204 void IterateWeakRoots(ObjectVisitor* v); 205 206 // Find all weak handles satisfying the callback predicate, mark 207 // them as pending. 208 void IdentifyWeakHandles(WeakSlotCallback f); 209 210 // NOTE: Five ...NewSpace... functions below are used during 211 // scavenge collections and iterate over sets of handles that are 212 // guaranteed to contain all handles holding new space objects (but 213 // may also include old space objects). 214 215 // Iterates over strong and dependent handles. See the node above. 216 void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v); 217 218 // Finds weak independent or partially independent handles satisfying 219 // the callback predicate and marks them as pending. See the note above. 220 void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f); 221 222 // Iterates over weak independent or partially independent handles. 223 // See the note above. 224 void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v); 225 226 // Finds weak independent or unmodified handles satisfying 227 // the callback predicate and marks them as pending. See the note above. 228 void MarkNewSpaceWeakUnmodifiedObjectsPending( 229 WeakSlotCallbackWithHeap is_unscavenged); 230 231 // Iterates over weak independent or unmodified handles. 232 // See the note above. 233 void IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v); 234 235 // Identify unmodified objects that are in weak state and marks them 236 // unmodified 237 void IdentifyWeakUnmodifiedObjects(WeakSlotCallback is_unmodified); 238 239 // Iterate over objects in object groups that have at least one object 240 // which requires visiting. The callback has to return true if objects 241 // can be skipped and false otherwise. 242 bool IterateObjectGroups(ObjectVisitor* v, WeakSlotCallbackWithHeap can_skip); 243 244 // Print all objects in object groups 245 void PrintObjectGroups(); 246 247 // Add an object group. 248 // Should be only used in GC callback function before a collection. 249 // All groups are destroyed after a garbage collection. 250 void AddObjectGroup(Object*** handles, 251 size_t length, 252 v8::RetainedObjectInfo* info); 253 254 // Associates handle with the object group represented by id. 255 // Should be only used in GC callback function before a collection. 256 // All groups are destroyed after a garbage collection. 257 void SetObjectGroupId(Object** handle, UniqueId id); 258 259 // Set RetainedObjectInfo for an object group. Should not be called more than 260 // once for a group. Should not be called for a group which contains no 261 // handles. 262 void SetRetainedObjectInfo(UniqueId id, RetainedObjectInfo* info); 263 264 // Adds an implicit reference from a group to an object. Should be only used 265 // in GC callback function before a collection. All implicit references are 266 // destroyed after a mark-compact collection. 267 void SetReferenceFromGroup(UniqueId id, Object** child); 268 269 // Adds an implicit reference from a parent object to a child object. Should 270 // be only used in GC callback function before a collection. All implicit 271 // references are destroyed after a mark-compact collection. 272 void SetReference(HeapObject** parent, Object** child); 273 object_groups()274 List<ObjectGroup*>* object_groups() { 275 ComputeObjectGroupsAndImplicitReferences(); 276 return &object_groups_; 277 } 278 implicit_ref_groups()279 List<ImplicitRefGroup*>* implicit_ref_groups() { 280 ComputeObjectGroupsAndImplicitReferences(); 281 return &implicit_ref_groups_; 282 } 283 284 // Remove bags, this should only happen after GC. 285 void RemoveObjectGroups(); 286 void RemoveImplicitRefGroups(); 287 288 // Tear down the global handle structure. 289 void TearDown(); 290 isolate()291 Isolate* isolate() { return isolate_; } 292 293 #ifdef DEBUG 294 void PrintStats(); 295 void Print(); 296 #endif 297 298 private: 299 explicit GlobalHandles(Isolate* isolate); 300 301 // Migrates data from the internal representation (object_group_connections_, 302 // retainer_infos_ and implicit_ref_connections_) to the public and more 303 // efficient representation (object_groups_ and implicit_ref_groups_). 304 void ComputeObjectGroupsAndImplicitReferences(); 305 306 // v8::internal::List is inefficient even for small number of elements, if we 307 // don't assign any initial capacity. 308 static const int kObjectGroupConnectionsCapacity = 20; 309 310 class PendingPhantomCallback; 311 312 // Helpers for PostGarbageCollectionProcessing. 313 static void InvokeSecondPassPhantomCallbacks( 314 List<PendingPhantomCallback>* callbacks, Isolate* isolate); 315 int PostScavengeProcessing(int initial_post_gc_processing_count); 316 int PostMarkSweepProcessing(int initial_post_gc_processing_count); 317 int DispatchPendingPhantomCallbacks(bool synchronous_second_pass); 318 void UpdateListOfNewSpaceNodes(); 319 320 // Internal node structures. 321 class Node; 322 class NodeBlock; 323 class NodeIterator; 324 class PendingPhantomCallbacksSecondPassTask; 325 326 Isolate* isolate_; 327 328 // Field always containing the number of handles to global objects. 329 int number_of_global_handles_; 330 331 // List of all allocated node blocks. 332 NodeBlock* first_block_; 333 334 // List of node blocks with used nodes. 335 NodeBlock* first_used_block_; 336 337 // Free list of nodes. 338 Node* first_free_; 339 340 // Contains all nodes holding new space objects. Note: when the list 341 // is accessed, some of the objects may have been promoted already. 342 List<Node*> new_space_nodes_; 343 344 int post_gc_processing_count_; 345 346 size_t number_of_phantom_handle_resets_; 347 348 // Object groups and implicit references, public and more efficient 349 // representation. 350 List<ObjectGroup*> object_groups_; 351 List<ImplicitRefGroup*> implicit_ref_groups_; 352 353 // Object groups and implicit references, temporary representation while 354 // constructing the groups. 355 List<ObjectGroupConnection> object_group_connections_; 356 List<ObjectGroupRetainerInfo> retainer_infos_; 357 List<ObjectGroupConnection> implicit_ref_connections_; 358 359 List<PendingPhantomCallback> pending_phantom_callbacks_; 360 361 friend class Isolate; 362 363 DISALLOW_COPY_AND_ASSIGN(GlobalHandles); 364 }; 365 366 367 class GlobalHandles::PendingPhantomCallback { 368 public: 369 typedef v8::WeakCallbackInfo<void> Data; PendingPhantomCallback(Node * node,Data::Callback callback,void * parameter,void * internal_fields[v8::kInternalFieldsInWeakCallback])370 PendingPhantomCallback( 371 Node* node, Data::Callback callback, void* parameter, 372 void* internal_fields[v8::kInternalFieldsInWeakCallback]) 373 : node_(node), callback_(callback), parameter_(parameter) { 374 for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) { 375 internal_fields_[i] = internal_fields[i]; 376 } 377 } 378 379 void Invoke(Isolate* isolate); 380 node()381 Node* node() { return node_; } callback()382 Data::Callback callback() { return callback_; } 383 384 private: 385 Node* node_; 386 Data::Callback callback_; 387 void* parameter_; 388 void* internal_fields_[v8::kInternalFieldsInWeakCallback]; 389 }; 390 391 392 class EternalHandles { 393 public: 394 enum SingletonHandle { 395 I18N_TEMPLATE_ONE, 396 I18N_TEMPLATE_TWO, 397 DATE_CACHE_VERSION, 398 399 NUMBER_OF_SINGLETON_HANDLES 400 }; 401 402 EternalHandles(); 403 ~EternalHandles(); 404 NumberOfHandles()405 int NumberOfHandles() { return size_; } 406 407 // Create an EternalHandle, overwriting the index. 408 void Create(Isolate* isolate, Object* object, int* index); 409 410 // Grab the handle for an existing EternalHandle. Get(int index)411 inline Handle<Object> Get(int index) { 412 return Handle<Object>(GetLocation(index)); 413 } 414 415 // Grab the handle for an existing SingletonHandle. GetSingleton(SingletonHandle singleton)416 inline Handle<Object> GetSingleton(SingletonHandle singleton) { 417 DCHECK(Exists(singleton)); 418 return Get(singleton_handles_[singleton]); 419 } 420 421 // Checks whether a SingletonHandle has been assigned. Exists(SingletonHandle singleton)422 inline bool Exists(SingletonHandle singleton) { 423 return singleton_handles_[singleton] != kInvalidIndex; 424 } 425 426 // Assign a SingletonHandle to an empty slot and returns the handle. CreateSingleton(Isolate * isolate,Object * object,SingletonHandle singleton)427 Handle<Object> CreateSingleton(Isolate* isolate, 428 Object* object, 429 SingletonHandle singleton) { 430 Create(isolate, object, &singleton_handles_[singleton]); 431 return Get(singleton_handles_[singleton]); 432 } 433 434 // Iterates over all handles. 435 void IterateAllRoots(ObjectVisitor* visitor); 436 // Iterates over all handles which might be in new space. 437 void IterateNewSpaceRoots(ObjectVisitor* visitor); 438 // Rebuilds new space list. 439 void PostGarbageCollectionProcessing(Heap* heap); 440 441 private: 442 static const int kInvalidIndex = -1; 443 static const int kShift = 8; 444 static const int kSize = 1 << kShift; 445 static const int kMask = 0xff; 446 447 // Gets the slot for an index GetLocation(int index)448 inline Object** GetLocation(int index) { 449 DCHECK(index >= 0 && index < size_); 450 return &blocks_[index >> kShift][index & kMask]; 451 } 452 453 int size_; 454 List<Object**> blocks_; 455 List<int> new_space_indices_; 456 int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES]; 457 458 DISALLOW_COPY_AND_ASSIGN(EternalHandles); 459 }; 460 461 462 } // namespace internal 463 } // namespace v8 464 465 #endif // V8_GLOBAL_HANDLES_H_ 466