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
99
100class 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.
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
228  List<ObjectGroup*>* object_groups() {
229    ComputeObjectGroupsAndImplicitReferences();
230    return &object_groups_;
231  }
232
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
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
306class 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
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.
325  inline Handle<Object> Get(int index) {
326    return Handle<Object>(GetLocation(index));
327  }
328
329  // Grab the handle for an existing SingletonHandle.
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.
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.
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
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