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