Home | History | Annotate | Download | only in src
      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 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.
    158   int global_handles_count() const {
    159     return number_of_global_handles_;
    160   }
    161 
    162   size_t NumberOfPhantomHandleResets() {
    163     return number_of_phantom_handle_resets_;
    164   }
    165 
    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 
    278   List<ObjectGroup*>* object_groups() {
    279     ComputeObjectGroupsAndImplicitReferences();
    280     return &object_groups_;
    281   }
    282 
    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 
    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;
    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 
    385   Node* node() { return node_; }
    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 
    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.
    413   inline Handle<Object> Get(int index) {
    414     return Handle<Object>(GetLocation(index));
    415   }
    416 
    417   // Grab the handle for an existing SingletonHandle.
    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.
    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.
    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
    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