text: // Copyright 2011 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef V8_GLOBAL_HANDLES_H_
  #define V8_GLOBAL_HANDLES_H_
  
  #include "include/v8.h"
  #include "include/v8-profiler.h"
  
  #include "src/handles.h"
  #include "src/list.h"
  #include "src/utils.h"
  
  namespace v8 {
  namespace internal {
  
  class HeapStats;
  class ObjectVisitor;
  
  // Structure for tracking global handles.
  // A single list keeps all the allocated global handles.
  // Destroyed handles stay in the list but is added to the free list.
  // At GC the destroyed global handles are removed from the free list
  // and deallocated.
  
  // Data structures for tracking object groups and implicit references.
  
  // An object group is treated like a single JS object: if one of object in
  // the group is alive, all objects in the same group are considered alive.
  // An object group is used to simulate object relationship in a DOM tree.
  
  // An implicit references group consists of two parts: a parent object and a
  // list of children objects.  If the parent is alive, all the children are alive
  // too.
  
  struct ObjectGroup {
    explicit ObjectGroup(size_t length)
        : info(NULL), length(length) {
      DCHECK(length > 0);
      objects = new Object**[length];
    }
    ~ObjectGroup();
  
    v8::RetainedObjectInfo* info;
    Object*** objects;
    size_t length;
  };
  
  
  struct ImplicitRefGroup {
    ImplicitRefGroup(HeapObject** parent, size_t length)
        : parent(parent), length(length) {
      DCHECK(length > 0);
      children = new Object**[length];
    }
    ~ImplicitRefGroup();
  
    HeapObject** parent;
    Object*** children;
    size_t length;
  };
  
  
  // For internal bookkeeping.
  struct ObjectGroupConnection {
    ObjectGroupConnection(UniqueId id, Object** object)
        : id(id), object(object) {}
  
    bool operator==(const ObjectGroupConnection& other) const {
      return id == other.id;
    }
  
    bool operator<(const ObjectGroupConnection& other) const {
      return id < other.id;
    }
  
    UniqueId id;
    Object** object;
  };
  
  
  struct ObjectGroupRetainerInfo {
    ObjectGroupRetainerInfo(UniqueId id, RetainedObjectInfo* info)
        : id(id), info(info) {}
  
    bool operator==(const ObjectGroupRetainerInfo& other) const {
      return id == other.id;
    }
  
    bool operator<(const ObjectGroupRetainerInfo& other) const {
      return id < other.id;
    }
  
    UniqueId id;
    RetainedObjectInfo* info;
  };
  
  
  enum WeaknessType {
    NORMAL_WEAK,  // Embedder gets a handle to the dying object.
    // In the following cases, the embedder gets the parameter they passed in
    // earlier, and 0 or 2 first internal fields. Note that the internal
    // fields must contain aligned non-V8 pointers.  Getting pointers to V8
    // objects through this interface would be GC unsafe so in that case the
    // embedder gets a null pointer instead.
    PHANTOM_WEAK,
    PHANTOM_WEAK_2_INTERNAL_FIELDS
  };
  
  
  class GlobalHandles {
   public:
    ~GlobalHandles();
  
    // Creates a new global handle that is alive until Destroy is called.
    Handle<Object> Create(Object* value);
  
    // Copy a global handle
    static Handle<Object> CopyGlobal(Object** location);
  
    // Destroy a global handle.
    static void Destroy(Object** location);
  
    typedef WeakCallbackData<v8::Value, void>::Callback WeakCallback;
  
    // For a phantom weak reference, the callback does not have access to the
    // dying object.  Phantom weak references are preferred because they allow
    // memory to be reclaimed in one GC cycle rather than two.  However, for
    // historical reasons the default is non-phantom.
    enum PhantomState { Nonphantom, Phantom };
  
    // Make the global handle weak and set the callback parameter for the
    // handle.  When the garbage collector recognizes that only weak global
    // handles point to an object the callback function is invoked (for each
    // handle) with the handle and corresponding parameter as arguments.  By
    // default the handle still contains a pointer to the object that is being
    // collected.  For this reason the object is not collected until the next
    // GC.  For a phantom weak handle the handle is cleared (set to a Smi)
    // before the callback is invoked, but the handle can still be identified
    // in the callback by using the location() of the handle.
    static void MakeWeak(Object** location, void* parameter,
                         WeakCallback weak_callback);
  
    // It would be nice to template this one, but it's really hard to get
    // the template instantiator to work right if you do.
    static void MakeWeak(Object** location, void* parameter,
                         WeakCallbackInfo<void>::Callback weak_callback,
                         v8::WeakCallbackType type);
  
    void RecordStats(HeapStats* stats);
  
    // Returns the current number of weak handles.
    int NumberOfWeakHandles();
  
    // Returns the current number of weak handles to global objects.
    // These handles are also included in NumberOfWeakHandles().
    int NumberOfGlobalObjectWeakHandles();
  
    // Returns the current number of handles to global objects.
    int global_handles_count() const {
      return number_of_global_handles_;
    }
  
    // Collect up data for the weak handle callbacks after GC has completed, but
    // before memory is reclaimed.
    void CollectAllPhantomCallbackData();
  
    // Collect up data for the weak handle callbacks referenced by young
    // generation after GC has completed, but before memory is reclaimed.
    void CollectYoungPhantomCallbackData();
  
    // Clear the weakness of a global handle.
    static void* ClearWeakness(Object** location);
  
    // Clear the weakness of a global handle.
    static void MarkIndependent(Object** location);
  
    // Mark the reference to this object externaly unreachable.
    static void MarkPartiallyDependent(Object** location);
  
    static bool IsIndependent(Object** location);
  
    // Tells whether global handle is near death.
    static bool IsNearDeath(Object** location);
  
    // Tells whether global handle is weak.
    static bool IsWeak(Object** location);
  
    // Process pending weak handles.
    // Returns the number of freed nodes.
    int PostGarbageCollectionProcessing(GarbageCollector collector);
  
    // Iterates over all strong handles.
    void IterateStrongRoots(ObjectVisitor* v);
  
    // Iterates over all handles.
    void IterateAllRoots(ObjectVisitor* v);
  
    // Iterates over all handles that have embedder-assigned class ID.
    void IterateAllRootsWithClassIds(ObjectVisitor* v);
  
    // Iterates over all handles in the new space that have embedder-assigned
    // class ID.
    void IterateAllRootsInNewSpaceWithClassIds(ObjectVisitor* v);
  
    // Iterates over all weak roots in heap.
    void IterateWeakRoots(ObjectVisitor* v);
  
    // Find all weak handles satisfying the callback predicate, mark
    // them as pending.
    void IdentifyWeakHandles(WeakSlotCallback f);
  
    // NOTE: Three ...NewSpace... functions below are used during
    // scavenge collections and iterate over sets of handles that are
    // guaranteed to contain all handles holding new space objects (but
    // may also include old space objects).
  
    // Iterates over strong and dependent handles. See the node above.
    void IterateNewSpaceStrongAndDependentRoots(ObjectVisitor* v);
  
    // Finds weak independent or partially independent handles satisfying
    // the callback predicate and marks them as pending. See the note above.
    void IdentifyNewSpaceWeakIndependentHandles(WeakSlotCallbackWithHeap f);
  
    // Iterates over weak independent or partially independent handles.
    // See the note above.
    void IterateNewSpaceWeakIndependentRoots(ObjectVisitor* v);
  
    // Iterate over objects in object groups that have at least one object
    // which requires visiting. The callback has to return true if objects
    // can be skipped and false otherwise.
    bool IterateObjectGroups(ObjectVisitor* v, WeakSlotCallbackWithHeap can_skip);
  
    // Add an object group.
    // Should be only used in GC callback function before a collection.
    // All groups are destroyed after a garbage collection.
    void AddObjectGroup(Object*** handles,
                        size_t length,
                        v8::RetainedObjectInfo* info);
  
    // Associates handle with the object group represented by id.
    // Should be only used in GC callback function before a collection.
    // All groups are destroyed after a garbage collection.
    void SetObjectGroupId(Object** handle, UniqueId id);
  
    // Set RetainedObjectInfo for an object group. Should not be called more than
    // once for a group. Should not be called for a group which contains no
    // handles.
    void SetRetainedObjectInfo(UniqueId id, RetainedObjectInfo* info);
  
    // Adds an implicit reference from a group to an object. Should be only used
    // in GC callback function before a collection. All implicit references are
    // destroyed after a mark-compact collection.
    void SetReferenceFromGroup(UniqueId id, Object** child);
  
    // Adds an implicit reference from a parent object to a child object. Should
    // be only used in GC callback function before a collection. All implicit
    // references are destroyed after a mark-compact collection.
    void SetReference(HeapObject** parent, Object** child);
  
    List<ObjectGroup*>* object_groups() {
      ComputeObjectGroupsAndImplicitReferences();
      return &object_groups_;
    }
  
    List<ImplicitRefGroup*>* implicit_ref_groups() {
      ComputeObjectGroupsAndImplicitReferences();
      return &implicit_ref_groups_;
    }
  
    // Remove bags, this should only happen after GC.
    void RemoveObjectGroups();
    void RemoveImplicitRefGroups();
  
    // Tear down the global handle structure.
    void TearDown();
  
    Isolate* isolate() { return isolate_; }
  
  #ifdef DEBUG
    void PrintStats();
    void Print();
  #endif
  
   private:
    explicit GlobalHandles(Isolate* isolate);
  
    // Migrates data from the internal representation (object_group_connections_,
    // retainer_infos_ and implicit_ref_connections_) to the public and more
    // efficient representation (object_groups_ and implicit_ref_groups_).
    void ComputeObjectGroupsAndImplicitReferences();
  
    // v8::internal::List is inefficient even for small number of elements, if we
    // don't assign any initial capacity.
    static const int kObjectGroupConnectionsCapacity = 20;
  
    // Helpers for PostGarbageCollectionProcessing.
    int PostScavengeProcessing(int initial_post_gc_processing_count);
    int PostMarkSweepProcessing(int initial_post_gc_processing_count);
    int DispatchPendingPhantomCallbacks();
    void UpdateListOfNewSpaceNodes();
  
    // Internal node structures.
    class Node;
    class NodeBlock;
    class NodeIterator;
    class PendingPhantomCallback;
  
    Isolate* isolate_;
  
    // Field always containing the number of handles to global objects.
    int number_of_global_handles_;
  
    // List of all allocated node blocks.
    NodeBlock* first_block_;
  
    // List of node blocks with used nodes.
    NodeBlock* first_used_block_;
  
    // Free list of nodes.
    Node* first_free_;
  
    // Contains all nodes holding new space objects. Note: when the list
    // is accessed, some of the objects may have been promoted already.
    List<Node*> new_space_nodes_;
  
    int post_gc_processing_count_;
  
    // Object groups and implicit references, public and more efficient
    // representation.
    List<ObjectGroup*> object_groups_;
    List<ImplicitRefGroup*> implicit_ref_groups_;
  
    // Object groups and implicit references, temporary representation while
    // constructing the groups.
    List<ObjectGroupConnection> object_group_connections_;
    List<ObjectGroupRetainerInfo> retainer_infos_;
    List<ObjectGroupConnection> implicit_ref_connections_;
  
    List<PendingPhantomCallback> pending_phantom_callbacks_;
  
    friend class Isolate;
  
    DISALLOW_COPY_AND_ASSIGN(GlobalHandles);
  };
  
  
  class GlobalHandles::PendingPhantomCallback {
   public:
    typedef v8::WeakCallbackInfo<void> Data;
    PendingPhantomCallback(Node* node, Data data, Data::Callback callback)
        : node_(node), data_(data), callback_(callback) {}
  
    void invoke();
  
    Node* node() { return node_; }
  
   private:
    Node* node_;
    Data data_;
    Data::Callback callback_;
  };
  
  
  class EternalHandles {
   public:
    enum SingletonHandle {
      I18N_TEMPLATE_ONE,
      I18N_TEMPLATE_TWO,
      DATE_CACHE_VERSION,
  
      NUMBER_OF_SINGLETON_HANDLES
    };
  
    EternalHandles();
    ~EternalHandles();
  
    int NumberOfHandles() { return size_; }
  
    // Create an EternalHandle, overwriting the index.
    void Create(Isolate* isolate, Object* object, int* index);
  
    // Grab the handle for an existing EternalHandle.
    inline Handle<Object> Get(int index) {
      return Handle<Object>(GetLocation(index));
    }
  
    // Grab the handle for an existing SingletonHandle.
    inline Handle<Object> GetSingleton(SingletonHandle singleton) {
      DCHECK(Exists(singleton));
      return Get(singleton_handles_[singleton]);
    }
  
    // Checks whether a SingletonHandle has been assigned.
    inline bool Exists(SingletonHandle singleton) {
      return singleton_handles_[singleton] != kInvalidIndex;
    }
  
    // Assign a SingletonHandle to an empty slot and returns the handle.
    Handle<Object> CreateSingleton(Isolate* isolate,
                                   Object* object,
                                   SingletonHandle singleton) {
      Create(isolate, object, &singleton_handles_[singleton]);
      return Get(singleton_handles_[singleton]);
    }
  
    // Iterates over all handles.
    void IterateAllRoots(ObjectVisitor* visitor);
    // Iterates over all handles which might be in new space.
    void IterateNewSpaceRoots(ObjectVisitor* visitor);
    // Rebuilds new space list.
    void PostGarbageCollectionProcessing(Heap* heap);
  
   private:
    static const int kInvalidIndex = -1;
    static const int kShift = 8;
    static const int kSize = 1 << kShift;
    static const int kMask = 0xff;
  
    // Gets the slot for an index
    inline Object** GetLocation(int index) {
      DCHECK(index >= 0 && index < size_);
      return &blocks_[index >> kShift][index & kMask];
    }
  
    int size_;
    List<Object**> blocks_;
    List<int> new_space_indices_;
    int singleton_handles_[NUMBER_OF_SINGLETON_HANDLES];
  
    DISALLOW_COPY_AND_ASSIGN(EternalHandles);
  };
  
  
  } }  // namespace v8::internal
  
  #endif  // V8_GLOBAL_HANDLES_H_
  