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
15namespace v8 {
16namespace internal {
17
18class HeapStats;
19class 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
37struct ObjectGroup {
38  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
51struct ImplicitRefGroup {
52  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.
66struct ObjectGroupConnection {
67  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
83struct ObjectGroupRetainerInfo {
84  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
99enum 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
114class 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.
152  int global_handles_count() const {
153    return number_of_global_handles_;
154  }
155
156  size_t NumberOfPhantomHandleResets() {
157    return number_of_phantom_handle_resets_;
158  }
159
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
274  List<ObjectGroup*>* object_groups() {
275    ComputeObjectGroupsAndImplicitReferences();
276    return &object_groups_;
277  }
278
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
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
367class GlobalHandles::PendingPhantomCallback {
368 public:
369  typedef v8::WeakCallbackInfo<void> Data;
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
381  Node* node() { return node_; }
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
392class 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
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.
411  inline Handle<Object> Get(int index) {
412    return Handle<Object>(GetLocation(index));
413  }
414
415  // Grab the handle for an existing SingletonHandle.
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.
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.
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
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