mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
439 lines
14 KiB
439 lines
14 KiB
// 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 the 0, 1 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_0_INTERNAL_FIELDS,
|
|
PHANTOM_WEAK_1_INTERNAL_FIELDS,
|
|
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 MakePhantom(Object** location, void* parameter,
|
|
int number_of_internal_fields,
|
|
PhantomCallbackData<void>::Callback weak_callback);
|
|
|
|
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 PhantomCallbackData<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_
|
|
|