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 100 class GlobalHandles { 101 public: 102 ~GlobalHandles(); 103 104 // Creates a new global handle that is alive until Destroy is called. 105 Handle<Object> Create(Object* value); 106 107 // Copy a global handle 108 static Handle<Object> CopyGlobal(Object** location); 109 110 // Destroy a global handle. 111 static void Destroy(Object** location); 112 113 typedef WeakCallbackData<v8::Value, void>::Callback WeakCallback; 114 115 // Make the global handle weak and set the callback parameter for the 116 // handle. When the garbage collector recognizes that only weak global 117 // handles point to an object the handles are cleared and the callback 118 // function is invoked (for each handle) with the handle and corresponding 119 // parameter as arguments. Note: cleared means set to Smi::FromInt(0). The 120 // reason is that Smi::FromInt(0) does not change during garage collection. 121 static void MakeWeak(Object** location, 122 void* parameter, 123 WeakCallback weak_callback); 124 125 void RecordStats(HeapStats* stats); 126 127 // Returns the current number of weak handles. 128 int NumberOfWeakHandles(); 129 130 // Returns the current number of weak handles to global objects. 131 // These handles are also included in NumberOfWeakHandles(). 132 int NumberOfGlobalObjectWeakHandles(); 133 134 // Returns the current number of handles to global objects. global_handles_count()135 int global_handles_count() const { 136 return number_of_global_handles_; 137 } 138 139 // Clear the weakness of a global handle. 140 static void* ClearWeakness(Object** location); 141 142 // Clear the weakness of a global handle. 143 static void MarkIndependent(Object** location); 144 145 // Mark the reference to this object externaly unreachable. 146 static void MarkPartiallyDependent(Object** location); 147 148 static bool IsIndependent(Object** location); 149 150 // Tells whether global handle is near death. 151 static bool IsNearDeath(Object** location); 152 153 // Tells whether global handle is weak. 154 static bool IsWeak(Object** location); 155 156 // Process pending weak handles. 157 // Returns the number of freed nodes. 158 int PostGarbageCollectionProcessing(GarbageCollector collector); 159 160 // Iterates over all strong handles. 161 void IterateStrongRoots(ObjectVisitor* v); 162 163 // Iterates over all handles. 164 void IterateAllRoots(ObjectVisitor* v); 165 166 // Iterates over all handles that have embedder-assigned class ID. 167 void IterateAllRootsWithClassIds(ObjectVisitor* v); 168 169 // Iterates over all handles in the new space that have embedder-assigned 170 // class ID. 171 void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v); 172 173 // Iterates over all weak roots in heap. 174 void IterateWeakRoots(ObjectVisitor* v); 175 176 // Find all weak handles satisfying the callback predicate, mark 177 // them as pending. 178 void IdentifyWeakHandles(WeakSlotCallback f); 179 180 // NOTE: Three ...NewSpace... functions below are used during 181 // scavenge collections and iterate over sets of handles that are 182 // guaranteed to contain all handles holding new space objects (but 183 // may also include old space objects). 184 185 // Iterates over strong and dependent handles. See the node above. 186 void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v); 187 188 // Finds weak independent or partially independent handles satisfying 189 // the callback predicate and marks them as pending. See the note above. 190 void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f); 191 192 // Iterates over weak independent or partially independent handles. 193 // See the note above. 194 void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v); 195 196 // Iterate over objects in object groups that have at least one object 197 // which requires visiting. The callback has to return true if objects 198 // can be skipped and false otherwise. 199 bool IterateObjectGroups(ObjectVisitor* v, WeakSlotCallbackWithHeap can_skip); 200 201 // Add an object group. 202 // Should be only used in GC callback function before a collection. 203 // All groups are destroyed after a garbage collection. 204 void AddObjectGroup(Object*** handles, 205 size_t length, 206 v8::RetainedObjectInfo* info); 207 208 // Associates handle with the object group represented by id. 209 // Should be only used in GC callback function before a collection. 210 // All groups are destroyed after a garbage collection. 211 void SetObjectGroupId(Object** handle, UniqueId id); 212 213 // Set RetainedObjectInfo for an object group. Should not be called more than 214 // once for a group. Should not be called for a group which contains no 215 // handles. 216 void SetRetainedObjectInfo(UniqueId id, RetainedObjectInfo* info); 217 218 // Adds an implicit reference from a group to an object. Should be only used 219 // in GC callback function before a collection. All implicit references are 220 // destroyed after a mark-compact collection. 221 void SetReferenceFromGroup(UniqueId id, Object** child); 222 223 // Adds an implicit reference from a parent object to a child object. Should 224 // be only used in GC callback function before a collection. All implicit 225 // references are destroyed after a mark-compact collection. 226 void SetReference(HeapObject** parent, Object** child); 227 object_groups()228 List<ObjectGroup*>* object_groups() { 229 ComputeObjectGroupsAndImplicitReferences(); 230 return &object_groups_; 231 } 232 implicit_ref_groups()233 List<ImplicitRefGroup*>* implicit_ref_groups() { 234 ComputeObjectGroupsAndImplicitReferences(); 235 return &implicit_ref_groups_; 236 } 237 238 // Remove bags, this should only happen after GC. 239 void RemoveObjectGroups(); 240 void RemoveImplicitRefGroups(); 241 242 // Tear down the global handle structure. 243 void TearDown(); 244 isolate()245 Isolate* isolate() { return isolate_; } 246 247 #ifdef DEBUG 248 void PrintStats(); 249 void Print(); 250 #endif 251 252 private: 253 explicit GlobalHandles(Isolate* isolate); 254 255 // Migrates data from the internal representation (object_group_connections_, 256 // retainer_infos_ and implicit_ref_connections_) to the public and more 257 // efficient representation (object_groups_ and implicit_ref_groups_). 258 void ComputeObjectGroupsAndImplicitReferences(); 259 260 // v8::internal::List is inefficient even for small number of elements, if we 261 // don't assign any initial capacity. 262 static const int kObjectGroupConnectionsCapacity = 20; 263 264 // Internal node structures. 265 class Node; 266 class NodeBlock; 267 class NodeIterator; 268 269 Isolate* isolate_; 270 271 // Field always containing the number of handles to global objects. 272 int number_of_global_handles_; 273 274 // List of all allocated node blocks. 275 NodeBlock* first_block_; 276 277 // List of node blocks with used nodes. 278 NodeBlock* first_used_block_; 279 280 // Free list of nodes. 281 Node* first_free_; 282 283 // Contains all nodes holding new space objects. Note: when the list 284 // is accessed, some of the objects may have been promoted already. 285 List<Node*> new_space_nodes_; 286 287 int post_gc_processing_count_; 288 289 // Object groups and implicit references, public and more efficient 290 // representation. 291 List<ObjectGroup*> object_groups_; 292 List<ImplicitRefGroup*> implicit_ref_groups_; 293 294 // Object groups and implicit references, temporary representation while 295 // constructing the groups. 296 List<ObjectGroupConnection> object_group_connections_; 297 List<ObjectGroupRetainerInfo> retainer_infos_; 298 List<ObjectGroupConnection> implicit_ref_connections_; 299 300 friend class Isolate; 301 302 DISALLOW_COPY_AND_ASSIGN(GlobalHandles); 303 }; 304 305 306 class EternalHandles { 307 public: 308 enum SingletonHandle { 309 I18N_TEMPLATE_ONE, 310 I18N_TEMPLATE_TWO, 311 DATE_CACHE_VERSION, 312 313 NUMBER_OF_SINGLETON_HANDLES 314 }; 315 316 EternalHandles(); 317 ~EternalHandles(); 318 NumberOfHandles()319 int NumberOfHandles() { return size_; } 320 321 // Create an EternalHandle, overwriting the index. 322 void Create(Isolate* isolate, Object* object, int* index); 323 324 // Grab the handle for an existing EternalHandle. Get(int index)325 inline Handle<Object> Get(int index) { 326 return Handle<Object>(GetLocation(index)); 327 } 328 329 // Grab the handle for an existing SingletonHandle. GetSingleton(SingletonHandle singleton)330 inline Handle<Object> GetSingleton(SingletonHandle singleton) { 331 DCHECK(Exists(singleton)); 332 return Get(singleton_handles_[singleton]); 333 } 334 335 // Checks whether a SingletonHandle has been assigned. Exists(SingletonHandle singleton)336 inline bool Exists(SingletonHandle singleton) { 337 return singleton_handles_[singleton] != kInvalidIndex; 338 } 339 340 // Assign a SingletonHandle to an empty slot and returns the handle. CreateSingleton(Isolate * isolate,Object * object,SingletonHandle singleton)341 Handle<Object> CreateSingleton(Isolate* isolate, 342 Object* object, 343 SingletonHandle singleton) { 344 Create(isolate, object, &singleton_handles_[singleton]); 345 return Get(singleton_handles_[singleton]); 346 } 347 348 // Iterates over all handles. 349 void IterateAllRoots(ObjectVisitor* visitor); 350 // Iterates over all handles which might be in new space. 351 void IterateNewSpaceRoots(ObjectVisitor* visitor); 352 // Rebuilds new space list. 353 void PostGarbageCollectionProcessing(Heap* heap); 354 355 private: 356 static const int kInvalidIndex = -1; 357 static const int kShift = 8; 358 static const int kSize = 1 << kShift; 359 static const int kMask = 0xff; 360 361 // Gets the slot for an index GetLocation(int index)362 inline Object** GetLocation(int index) { 363 DCHECK(index >= 0 && index < size_); 364 return &blocks_[index >> kShift][index & kMask]; 365 } 366 367 int size_; 368 List<Object**> blocks_; 369 List<int> new_space_indices_; 370 int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES]; 371 372 DISALLOW_COPY_AND_ASSIGN(EternalHandles); 373 }; 374 375 376 } } // namespace v8::internal 377 378 #endif // V8_GLOBAL_HANDLES_H_ 379