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