Index: Source/bindings/v8/V8GCController.cpp |
diff --git a/Source/bindings/v8/V8GCController.cpp b/Source/bindings/v8/V8GCController.cpp |
index c9b194482f254b522e848f2de08b787f367da6be..105b3e97f95a73752ef8537c6bee1f36ffe579b1 100644 |
--- a/Source/bindings/v8/V8GCController.cpp |
+++ b/Source/bindings/v8/V8GCController.cpp |
@@ -47,150 +47,11 @@ |
namespace WebCore { |
-class ImplicitConnection { |
-public: |
- ImplicitConnection(void* root, v8::Persistent<v8::Object> wrapper) |
- : m_root(root) |
- , m_wrapper(wrapper) |
- , m_rootNode(0) |
- { |
- } |
- ImplicitConnection(Node* root, v8::Persistent<v8::Object> wrapper) |
- : m_root(root) |
- , m_wrapper(wrapper) |
- , m_rootNode(root) |
- { |
- } |
- |
- void* root() const { return m_root; } |
- v8::Persistent<v8::Object> wrapper() const { return m_wrapper; } |
- |
- PassOwnPtr<RetainedObjectInfo> retainedObjectInfo() |
- { |
- if (!m_rootNode) |
- return nullptr; |
- return adoptPtr(new RetainedDOMInfo(m_rootNode)); |
- } |
- |
-private: |
- void* m_root; |
- v8::Persistent<v8::Object> m_wrapper; |
- Node* m_rootNode; |
-}; |
- |
-bool operator<(const ImplicitConnection& left, const ImplicitConnection& right) |
-{ |
- return left.root() < right.root(); |
-} |
- |
-struct ImplicitReference { |
- ImplicitReference(void* parent, v8::Persistent<v8::Object> child) |
- : parent(parent) |
- , child(child) |
- { |
- } |
- |
- void* parent; |
- v8::Persistent<v8::Object> child; |
-}; |
- |
-bool operator<(const ImplicitReference& left, const ImplicitReference& right) |
-{ |
- return left.parent < right.parent; |
-} |
- |
-class WrapperGrouper { |
-public: |
- WrapperGrouper() |
- { |
- m_liveObjects.append(V8PerIsolateData::current()->ensureLiveRoot()); |
- } |
- |
- void addObjectWrapperToGroup(void* root, v8::Persistent<v8::Object> wrapper) |
- { |
- m_connections.append(ImplicitConnection(root, wrapper)); |
- } |
- |
- void addNodeWrapperToGroup(Node* root, v8::Persistent<v8::Object> wrapper) |
- { |
- m_connections.append(ImplicitConnection(root, wrapper)); |
- } |
- |
- void addImplicitReference(void* parent, v8::Persistent<v8::Object> child) |
- { |
- m_references.append(ImplicitReference(parent, child)); |
- m_rootGroupMap.add(parent, v8::Persistent<v8::Object>()); |
- } |
- |
- void keepAlive(v8::Persistent<v8::Value> wrapper) |
- { |
- m_liveObjects.append(wrapper); |
- } |
- |
- void apply() |
- { |
- if (m_liveObjects.size() > 1) |
- v8::V8::AddObjectGroup(m_liveObjects.data(), m_liveObjects.size()); |
- |
- std::sort(m_connections.begin(), m_connections.end()); |
- Vector<v8::Persistent<v8::Value> > group; |
- ImplicitConnection* connectionIterator = m_connections.begin(); |
- const ImplicitConnection* connectionIteratorEnd = m_connections.end(); |
- while (connectionIterator < connectionIteratorEnd) { |
- void* root = connectionIterator->root(); |
- v8::Persistent<v8::Object> groupRepresentativeWrapper = connectionIterator->wrapper(); |
- OwnPtr<RetainedObjectInfo> retainedObjectInfo = connectionIterator->retainedObjectInfo(); |
- |
- do { |
- group.append(connectionIterator->wrapper()); |
- ++connectionIterator; |
- } while (connectionIterator < connectionIteratorEnd && root == connectionIterator->root()); |
- |
- if (group.size() > 1) |
- v8::V8::AddObjectGroup(group.data(), group.size(), retainedObjectInfo.leakPtr()); |
- |
- HashMap<void*, v8::Persistent<v8::Object> >::iterator iter = m_rootGroupMap.find(root); |
- if (iter != m_rootGroupMap.end()) |
- iter->value = groupRepresentativeWrapper; |
- |
- group.shrink(0); |
- } |
- |
- std::sort(m_references.begin(), m_references.end()); |
- const ImplicitReference* referenceIterator = m_references.begin(); |
- const ImplicitReference* referenceIteratorEnd = m_references.end(); |
- while (referenceIterator < referenceIteratorEnd) { |
- void* parent = referenceIterator->parent; |
- v8::Persistent<v8::Object> parentWrapper = m_rootGroupMap.get(parent); |
- if (parentWrapper.IsEmpty()) { |
- ++referenceIterator; |
- continue; |
- } |
- |
- Vector<v8::Persistent<v8::Value> > children; |
- do { |
- children.append(referenceIterator->child); |
- ++referenceIterator; |
- } while (referenceIterator < referenceIteratorEnd && parent == referenceIterator->parent); |
- |
- v8::V8::AddImplicitReferences(parentWrapper, children.data(), children.size()); |
- } |
- } |
- |
-private: |
- Vector<v8::Persistent<v8::Value> > m_liveObjects; |
- Vector<ImplicitConnection> m_connections; |
- Vector<ImplicitReference> m_references; |
- HashMap<void*, v8::Persistent<v8::Object> > m_rootGroupMap; |
-}; |
- |
// FIXME: This should use opaque GC roots. |
-static void addImplicitReferencesForNodeWithEventListeners(Node* node, v8::Persistent<v8::Object> wrapper) |
+static void addReferencesForNodeWithEventListeners(v8::Isolate* isolate, Node* node, const v8::Persistent<v8::Object>& wrapper) |
{ |
ASSERT(node->hasEventListeners()); |
- Vector<v8::Persistent<v8::Value> > listeners; |
- |
EventListenerIterator iterator(node); |
while (EventListener* listener = iterator.nextListener()) { |
if (listener->type() != EventListener::JSEventListenerType) |
@@ -198,13 +59,9 @@ static void addImplicitReferencesForNodeWithEventListeners(Node* node, v8::Persi |
V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener); |
if (!v8listener->hasExistingListenerObject()) |
continue; |
- listeners.append(v8listener->existingListenerObjectPersistentHandle()); |
- } |
- |
- if (listeners.isEmpty()) |
- return; |
- v8::V8::AddImplicitReferences(wrapper, listeners.data(), listeners.size()); |
+ isolate->SetReference(wrapper, v8listener->existingListenerObjectPersistentHandle()); |
+ } |
} |
Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) |
@@ -231,7 +88,7 @@ Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) |
static void gcTree(v8::Isolate* isolate, Node* startNode) |
{ |
- Vector<v8::Persistent<v8::Value>, initialNodeVectorSize> newSpaceWrappers; |
+ Vector<Node*, initialNodeVectorSize> newSpaceNodes; |
// We traverse a DOM tree in the DFS order starting from startNode. |
// The traversal order does not matter for correctness but does matter for performance. |
@@ -253,7 +110,7 @@ static void gcTree(v8::Isolate* isolate, Node* startNode) |
return; |
} |
node->setV8CollectableDuringMinorGC(false); |
- newSpaceWrappers.append(node->wrapper()); |
+ newSpaceNodes.append(node); |
} |
if (node->firstChild()) { |
node = node->firstChild(); |
@@ -269,14 +126,18 @@ static void gcTree(v8::Isolate* isolate, Node* startNode) |
} while (node != startNode); |
// We completed the DOM tree traversal. All wrappers in the DOM tree are |
- // stored in newSpaceWrappers and are expected to exist in the new space of V8. |
+ // stored in newSpaceNodes and are expected to exist in the new space of V8. |
// We report those wrappers to V8 as an object group. |
- v8::Persistent<v8::Value>* wrapperIterator = newSpaceWrappers.begin(); |
- const v8::Persistent<v8::Value>* wrapperIteratorEnd = newSpaceWrappers.end(); |
- for (; wrapperIterator != wrapperIteratorEnd; ++wrapperIterator) |
- wrapperIterator->MarkPartiallyDependent(isolate); |
- if (newSpaceWrappers.size() > 0) |
- v8::V8::AddObjectGroup(&newSpaceWrappers[0], newSpaceWrappers.size()); |
+ Node** nodeIterator = newSpaceNodes.begin(); |
+ Node** const nodeIteratorEnd = newSpaceNodes.end(); |
+ if (nodeIterator == nodeIteratorEnd) |
+ return; |
+ v8::UniqueId id(reinterpret_cast<intptr_t>(*(*nodeIterator)->wrapper())); |
+ for (; nodeIterator != nodeIteratorEnd; ++nodeIterator) { |
+ v8::Persistent<v8::Object> wrapper((*nodeIterator)->wrapper()); |
+ wrapper.MarkPartiallyDependent(isolate); |
+ isolate->SetObjectGroupId(wrapper, id); |
+ } |
} |
// Regarding a minor GC algorithm for DOM nodes, see this document: |
@@ -343,8 +204,10 @@ private: |
class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { |
public: |
- explicit MajorGCWrapperVisitor(v8::Isolate* isolate) |
+ explicit MajorGCWrapperVisitor(v8::Isolate* isolate, bool constructRetainedObjectInfos) |
: m_isolate(isolate) |
+ , m_liveRootGroupIdSet(false) |
+ , m_constructRetainedObjectInfos(constructRetainedObjectInfos) |
{ |
} |
@@ -370,17 +233,19 @@ public: |
// implementation can't tell the difference. |
MessagePort* port = static_cast<MessagePort*>(object); |
if (port->isEntangled() || port->hasPendingActivity()) |
- m_grouper.keepAlive(wrapper); |
+ m_isolate->SetObjectGroupId(wrapper, liveRootId()); |
} else if (V8MutationObserver::info.equals(type)) { |
// FIXME: Allow opaqueRootForGC to operate on multiple roots and move this logic into V8MutationObserverCustom. |
MutationObserver* observer = static_cast<MutationObserver*>(object); |
HashSet<Node*> observedNodes = observer->getObservedNodes(); |
- for (HashSet<Node*>::iterator it = observedNodes.begin(); it != observedNodes.end(); ++it) |
- m_grouper.addImplicitReference(V8GCController::opaqueRootForGC(*it, m_isolate), wrapper); |
+ for (HashSet<Node*>::iterator it = observedNodes.begin(); it != observedNodes.end(); ++it) { |
+ v8::UniqueId id(reinterpret_cast<intptr_t>(V8GCController::opaqueRootForGC(*it, m_isolate))); |
+ m_isolate->SetReferenceFromGroup(id, wrapper); |
+ } |
} else { |
ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); |
if (activeDOMObject && activeDOMObject->hasPendingActivity()) |
- m_grouper.keepAlive(wrapper); |
+ m_isolate->SetObjectGroupId(wrapper, liveRootId()); |
} |
if (classId == v8DOMNodeClassId) { |
@@ -391,11 +256,14 @@ public: |
Node* node = static_cast<Node*>(object); |
if (node->hasEventListeners()) |
- addImplicitReferencesForNodeWithEventListeners(node, wrapper); |
- |
- m_grouper.addNodeWrapperToGroup(V8GCController::opaqueRootForGC(node, m_isolate), wrapper); |
+ addReferencesForNodeWithEventListeners(m_isolate, node, wrapper); |
+ Node* root = V8GCController::opaqueRootForGC(node, m_isolate); |
+ m_isolate->SetObjectGroupId(wrapper, v8::UniqueId(reinterpret_cast<intptr_t>(root))); |
+ if (m_constructRetainedObjectInfos) |
+ m_groupsWhichNeedRetainerInfo.append(root); |
} else if (classId == v8DOMObjectClassId) { |
- m_grouper.addObjectWrapperToGroup(type->opaqueRootForGC(object, wrapper, m_isolate), wrapper); |
+ void* root = type->opaqueRootForGC(object, wrapper, m_isolate); |
+ m_isolate->SetObjectGroupId(wrapper, v8::UniqueId(reinterpret_cast<intptr_t>(root))); |
} else { |
ASSERT_NOT_REACHED(); |
} |
@@ -403,12 +271,36 @@ public: |
void notifyFinished() |
{ |
- m_grouper.apply(); |
+ if (!m_constructRetainedObjectInfos) |
+ return; |
+ std::sort(m_groupsWhichNeedRetainerInfo.begin(), m_groupsWhichNeedRetainerInfo.end()); |
+ Node* alreadyAdded = 0; |
+ v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); |
+ for (size_t i = 0; i < m_groupsWhichNeedRetainerInfo.size(); ++i) { |
+ Node* root = m_groupsWhichNeedRetainerInfo[i]; |
+ if (root != alreadyAdded) { |
+ profiler->SetRetainedObjectInfo(v8::UniqueId(reinterpret_cast<intptr_t>(root)), new RetainedDOMInfo(root)); |
+ alreadyAdded = root; |
+ } |
+ } |
} |
private: |
- WrapperGrouper m_grouper; |
+ v8::UniqueId liveRootId() |
+ { |
+ const v8::Persistent<v8::Value>& liveRoot = V8PerIsolateData::from(m_isolate)->ensureLiveRoot(); |
+ v8::UniqueId id(reinterpret_cast<intptr_t>(*liveRoot)); |
+ if (!m_liveRootGroupIdSet) { |
+ m_isolate->SetObjectGroupId(*liveRoot, id); |
+ m_liveRootGroupIdSet = true; |
+ } |
+ return id; |
+ } |
+ |
v8::Isolate* m_isolate; |
+ Vector<Node*> m_groupsWhichNeedRetainerInfo; |
+ bool m_liveRootGroupIdSet; |
+ bool m_constructRetainedObjectInfos; |
}; |
void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) |
@@ -417,7 +309,7 @@ void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) |
if (type == v8::kGCTypeScavenge) |
minorGCPrologue(v8::Isolate::GetCurrent()); |
else if (type == v8::kGCTypeMarkSweepCompact) |
- majorGCPrologue(); |
+ majorGCPrologue(flags & v8::kGCCallbackFlagConstructRetainedObjectInfos); |
} |
void V8GCController::minorGCPrologue(v8::Isolate* isolate) |
@@ -434,14 +326,14 @@ void V8GCController::minorGCPrologue(v8::Isolate* isolate) |
} |
// Create object groups for DOM tree nodes. |
-void V8GCController::majorGCPrologue() |
+void V8GCController::majorGCPrologue(bool constructRetainedObjectInfos) |
{ |
TRACE_EVENT_BEGIN0("v8", "GC"); |
v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
v8::HandleScope scope; |
- MajorGCWrapperVisitor visitor(isolate); |
+ MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos); |
v8::V8::VisitHandlesWithClassIds(&visitor); |
visitor.notifyFinished(); |