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