• 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   ~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