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   ~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 
    367 class 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 
    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 
    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