• 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 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   enum IterationMode {
117     HANDLE_PHANTOM_NODES_VISIT_OTHERS,
118     VISIT_OTHERS,
119     HANDLE_PHANTOM_NODES
120   };
121 
122   ~GlobalHandles();
123 
124   // Creates a new global handle that is alive until Destroy is called.
125   Handle<Object> Create(Object* value);
126 
127   // Copy a global handle
128   static Handle<Object> CopyGlobal(Object** location);
129 
130   // Destroy a global handle.
131   static void Destroy(Object** location);
132 
133   // Make the global handle weak and set the callback parameter for the
134   // handle.  When the garbage collector recognizes that only weak global
135   // handles point to an object the callback function is invoked (for each
136   // handle) with the handle and corresponding parameter as arguments.  By
137   // default the handle still contains a pointer to the object that is being
138   // collected.  For this reason the object is not collected until the next
139   // GC.  For a phantom weak handle the handle is cleared (set to a Smi)
140   // before the callback is invoked, but the handle can still be identified
141   // in the callback by using the location() of the handle.
142   static void MakeWeak(Object** location, void* parameter,
143                        WeakCallbackInfo<void>::Callback weak_callback,
144                        v8::WeakCallbackType type);
145 
146   static void MakeWeak(Object*** location_addr);
147 
148   void RecordStats(HeapStats* stats);
149 
150   // Returns the current number of weak handles.
151   int NumberOfWeakHandles();
152 
153   // Returns the current number of weak handles to global objects.
154   // These handles are also included in NumberOfWeakHandles().
155   int NumberOfGlobalObjectWeakHandles();
156 
157   // Returns the current number of handles to global objects.
global_handles_count()158   int global_handles_count() const {
159     return number_of_global_handles_;
160   }
161 
NumberOfPhantomHandleResets()162   size_t NumberOfPhantomHandleResets() {
163     return number_of_phantom_handle_resets_;
164   }
165 
ResetNumberOfPhantomHandleResets()166   void ResetNumberOfPhantomHandleResets() {
167     number_of_phantom_handle_resets_ = 0;
168   }
169 
170   // Clear the weakness of a global handle.
171   static void* ClearWeakness(Object** location);
172 
173   // Mark the reference to this object independent of any object group.
174   static void MarkIndependent(Object** location);
175 
176   static bool IsIndependent(Object** location);
177 
178   // Tells whether global handle is near death.
179   static bool IsNearDeath(Object** location);
180 
181   // Tells whether global handle is weak.
182   static bool IsWeak(Object** location);
183 
184   // Process pending weak handles.
185   // Returns the number of freed nodes.
186   int PostGarbageCollectionProcessing(
187       GarbageCollector collector, const v8::GCCallbackFlags gc_callback_flags);
188 
189   // Iterates over all strong handles.
190   void IterateStrongRoots(ObjectVisitor* v);
191 
192   // Iterates over all handles.
193   void IterateAllRoots(ObjectVisitor* v);
194 
195   // Iterates over all handles that have embedder-assigned class ID.
196   void IterateAllRootsWithClassIds(ObjectVisitor* v);
197 
198   // Iterates over all handles in the new space that have embedder-assigned
199   // class ID.
200   void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v);
201 
202   // Iterate over all handles in the new space that are weak, unmodified
203   // and have class IDs
204   void IterateWeakRootsInNewSpaceWithClassIds(ObjectVisitor* v);
205 
206   // Iterates over all weak roots in heap.
207   void IterateWeakRoots(ObjectVisitor* v);
208 
209   // Find all weak handles satisfying the callback predicate, mark
210   // them as pending.
211   void IdentifyWeakHandles(WeakSlotCallback f);
212 
213   // NOTE: Five ...NewSpace... functions below are used during
214   // scavenge collections and iterate over sets of handles that are
215   // guaranteed to contain all handles holding new space objects (but
216   // may also include old space objects).
217 
218   // Iterates over strong and dependent handles. See the node above.
219   void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v);
220 
221   // Finds weak independent or partially independent handles satisfying
222   // the callback predicate and marks them as pending. See the note above.
223   void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f);
224 
225   // Iterates over weak independent or partially independent handles.
226   // See the note above.
227   void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);
228 
229   // Finds weak independent or unmodified handles satisfying
230   // the callback predicate and marks them as pending. See the note above.
231   void MarkNewSpaceWeakUnmodifiedObjectsPending(
232       WeakSlotCallbackWithHeap is_unscavenged);
233 
234   // Iterates over weak independent or unmodified handles.
235   // See the note above.
236   template <IterationMode mode>
237   void IterateNewSpaceWeakUnmodifiedRoots(ObjectVisitor* v);
238 
239   // Identify unmodified objects that are in weak state and marks them
240   // unmodified
241   void IdentifyWeakUnmodifiedObjects(WeakSlotCallback is_unmodified);
242 
243   // Iterate over objects in object groups that have at least one object
244   // which requires visiting. The callback has to return true if objects
245   // can be skipped and false otherwise.
246   bool IterateObjectGroups(ObjectVisitor* v, WeakSlotCallbackWithHeap can_skip);
247 
248   // Print all objects in object groups
249   void PrintObjectGroups();
250 
251   // Add an object group.
252   // Should be only used in GC callback function before a collection.
253   // All groups are destroyed after a garbage collection.
254   void AddObjectGroup(Object*** handles,
255                       size_t length,
256                       v8::RetainedObjectInfo* info);
257 
258   // Associates handle with the object group represented by id.
259   // Should be only used in GC callback function before a collection.
260   // All groups are destroyed after a garbage collection.
261   void SetObjectGroupId(Object** handle, UniqueId id);
262 
263   // Set RetainedObjectInfo for an object group. Should not be called more than
264   // once for a group. Should not be called for a group which contains no
265   // handles.
266   void SetRetainedObjectInfo(UniqueId id, RetainedObjectInfo* info);
267 
268   // Adds an implicit reference from a group to an object. Should be only used
269   // in GC callback function before a collection. All implicit references are
270   // destroyed after a mark-compact collection.
271   void SetReferenceFromGroup(UniqueId id, Object** child);
272 
273   // Adds an implicit reference from a parent object to a child object. Should
274   // be only used in GC callback function before a collection. All implicit
275   // references are destroyed after a mark-compact collection.
276   void SetReference(HeapObject** parent, Object** child);
277 
object_groups()278   List<ObjectGroup*>* object_groups() {
279     ComputeObjectGroupsAndImplicitReferences();
280     return &object_groups_;
281   }
282 
implicit_ref_groups()283   List<ImplicitRefGroup*>* implicit_ref_groups() {
284     ComputeObjectGroupsAndImplicitReferences();
285     return &implicit_ref_groups_;
286   }
287 
288   // Remove bags, this should only happen after GC.
289   void RemoveObjectGroups();
290   void RemoveImplicitRefGroups();
291 
292   // Tear down the global handle structure.
293   void TearDown();
294 
isolate()295   Isolate* isolate() { return isolate_; }
296 
297 #ifdef DEBUG
298   void PrintStats();
299   void Print();
300 #endif  // DEBUG
301 
302  private:
303   explicit GlobalHandles(Isolate* isolate);
304 
305   // Migrates data from the internal representation (object_group_connections_,
306   // retainer_infos_ and implicit_ref_connections_) to the public and more
307   // efficient representation (object_groups_ and implicit_ref_groups_).
308   void ComputeObjectGroupsAndImplicitReferences();
309 
310   // v8::internal::List is inefficient even for small number of elements, if we
311   // don't assign any initial capacity.
312   static const int kObjectGroupConnectionsCapacity = 20;
313 
314   class PendingPhantomCallback;
315 
316   // Helpers for PostGarbageCollectionProcessing.
317   static void InvokeSecondPassPhantomCallbacks(
318       List<PendingPhantomCallback>* callbacks, Isolate* isolate);
319   int PostScavengeProcessing(int initial_post_gc_processing_count);
320   int PostMarkSweepProcessing(int initial_post_gc_processing_count);
321   int DispatchPendingPhantomCallbacks(bool synchronous_second_pass);
322   void UpdateListOfNewSpaceNodes();
323 
324   // Internal node structures.
325   class Node;
326   class NodeBlock;
327   class NodeIterator;
328   class PendingPhantomCallbacksSecondPassTask;
329 
330   Isolate* isolate_;
331 
332   // Field always containing the number of handles to global objects.
333   int number_of_global_handles_;
334 
335   // List of all allocated node blocks.
336   NodeBlock* first_block_;
337 
338   // List of node blocks with used nodes.
339   NodeBlock* first_used_block_;
340 
341   // Free list of nodes.
342   Node* first_free_;
343 
344   // Contains all nodes holding new space objects. Note: when the list
345   // is accessed, some of the objects may have been promoted already.
346   List<Node*> new_space_nodes_;
347 
348   int post_gc_processing_count_;
349 
350   size_t number_of_phantom_handle_resets_;
351 
352   // Object groups and implicit references, public and more efficient
353   // representation.
354   List<ObjectGroup*> object_groups_;
355   List<ImplicitRefGroup*> implicit_ref_groups_;
356 
357   // Object groups and implicit references, temporary representation while
358   // constructing the groups.
359   List<ObjectGroupConnection> object_group_connections_;
360   List<ObjectGroupRetainerInfo> retainer_infos_;
361   List<ObjectGroupConnection> implicit_ref_connections_;
362 
363   List<PendingPhantomCallback> pending_phantom_callbacks_;
364 
365   friend class Isolate;
366 
367   DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
368 };
369 
370 
371 class GlobalHandles::PendingPhantomCallback {
372  public:
373   typedef v8::WeakCallbackInfo<void> Data;
PendingPhantomCallback(Node * node,Data::Callback callback,void * parameter,void * internal_fields[v8::kInternalFieldsInWeakCallback])374   PendingPhantomCallback(
375       Node* node, Data::Callback callback, void* parameter,
376       void* internal_fields[v8::kInternalFieldsInWeakCallback])
377       : node_(node), callback_(callback), parameter_(parameter) {
378     for (int i = 0; i < v8::kInternalFieldsInWeakCallback; ++i) {
379       internal_fields_[i] = internal_fields[i];
380     }
381   }
382 
383   void Invoke(Isolate* isolate);
384 
node()385   Node* node() { return node_; }
callback()386   Data::Callback callback() { return callback_; }
387 
388  private:
389   Node* node_;
390   Data::Callback callback_;
391   void* parameter_;
392   void* internal_fields_[v8::kInternalFieldsInWeakCallback];
393 };
394 
395 
396 class EternalHandles {
397  public:
398   enum SingletonHandle {
399     DATE_CACHE_VERSION,
400 
401     NUMBER_OF_SINGLETON_HANDLES
402   };
403 
404   EternalHandles();
405   ~EternalHandles();
406 
NumberOfHandles()407   int NumberOfHandles() { return size_; }
408 
409   // Create an EternalHandle, overwriting the index.
410   void Create(Isolate* isolate, Object* object, int* index);
411 
412   // Grab the handle for an existing EternalHandle.
Get(int index)413   inline Handle<Object> Get(int index) {
414     return Handle<Object>(GetLocation(index));
415   }
416 
417   // Grab the handle for an existing SingletonHandle.
GetSingleton(SingletonHandle singleton)418   inline Handle<Object> GetSingleton(SingletonHandle singleton) {
419     DCHECK(Exists(singleton));
420     return Get(singleton_handles_[singleton]);
421   }
422 
423   // Checks whether a SingletonHandle has been assigned.
Exists(SingletonHandle singleton)424   inline bool Exists(SingletonHandle singleton) {
425     return singleton_handles_[singleton] != kInvalidIndex;
426   }
427 
428   // Assign a SingletonHandle to an empty slot and returns the handle.
CreateSingleton(Isolate * isolate,Object * object,SingletonHandle singleton)429   Handle<Object> CreateSingleton(Isolate* isolate,
430                                  Object* object,
431                                  SingletonHandle singleton) {
432     Create(isolate, object, &singleton_handles_[singleton]);
433     return Get(singleton_handles_[singleton]);
434   }
435 
436   // Iterates over all handles.
437   void IterateAllRoots(ObjectVisitor* visitor);
438   // Iterates over all handles which might be in new space.
439   void IterateNewSpaceRoots(ObjectVisitor* visitor);
440   // Rebuilds new space list.
441   void PostGarbageCollectionProcessing(Heap* heap);
442 
443  private:
444   static const int kInvalidIndex = -1;
445   static const int kShift = 8;
446   static const int kSize = 1 << kShift;
447   static const int kMask = 0xff;
448 
449   // Gets the slot for an index
GetLocation(int index)450   inline Object** GetLocation(int index) {
451     DCHECK(index >= 0 && index < size_);
452     return &blocks_[index >> kShift][index & kMask];
453   }
454 
455   int size_;
456   List<Object**> blocks_;
457   List<int> new_space_indices_;
458   int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES];
459 
460   DISALLOW_COPY_AND_ASSIGN(EternalHandles);
461 };
462 
463 
464 }  // namespace internal
465 }  // namespace v8
466 
467 #endif  // V8_GLOBAL_HANDLES_H_
468