}
}
-Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*)
+Node* V8GCController::opaqueRootForGC(v8::Isolate*, Node* node)
{
ASSERT(node);
// FIXME: Remove the special handling for image elements.
: m_isolate(isolate)
{ }
- virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) OVERRIDE
+ virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override
{
// A minor DOM GC can collect only Nodes.
if (classId != WrapperTypeInfo::NodeClassId)
// To make each minor GC time bounded, we might need to give up
// traversing at some point for a large DOM tree. That being said,
// I could not observe the need even in pathological test cases.
- for (Node* node = rootNode; node; node = NodeTraversal::next(*node)) {
- if (node->containsWrapper()) {
- if (!node->isV8CollectableDuringMinorGC()) {
+ for (Node& node : NodeTraversal::startsAt(rootNode)) {
+ if (node.containsWrapper()) {
+ if (!node.isV8CollectableDuringMinorGC()) {
// This node is not in the new space of V8. This indicates that
// the minor GC cannot anyway judge reachability of this DOM tree.
// Thus we give up traversing the DOM tree.
return false;
}
- node->clearV8CollectableDuringMinorGC();
- partiallyDependentNodes->append(node);
+ node.clearV8CollectableDuringMinorGC();
+ partiallyDependentNodes->append(&node);
}
- if (ShadowRoot* shadowRoot = node->youngestShadowRoot()) {
+ if (ShadowRoot* shadowRoot = node.youngestShadowRoot()) {
if (!traverseTree(shadowRoot, partiallyDependentNodes))
return false;
- } else if (node->isShadowRoot()) {
- if (ShadowRoot* shadowRoot = toShadowRoot(node)->olderShadowRoot()) {
+ } else if (node.isShadowRoot()) {
+ if (ShadowRoot* shadowRoot = toShadowRoot(node).olderShadowRoot()) {
if (!traverseTree(shadowRoot, partiallyDependentNodes))
return false;
}
}
// <template> has a |content| property holding a DOM fragment which we must traverse,
// just like we do for the shadow trees above.
- if (isHTMLTemplateElement(*node)) {
- if (!traverseTree(toHTMLTemplateElement(*node).content(), partiallyDependentNodes))
+ if (isHTMLTemplateElement(node)) {
+ if (!traverseTree(toHTMLTemplateElement(node).content(), partiallyDependentNodes))
return false;
}
// Document maintains the list of imported documents through HTMLImportsController.
- if (node->isDocumentNode()) {
- Document* document = toDocument(node);
- HTMLImportsController* controller = document->importsController();
+ if (node.isDocumentNode()) {
+ Document& document = toDocument(node);
+ HTMLImportsController* controller = document.importsController();
if (controller && document == controller->master()) {
for (unsigned i = 0; i < controller->loaderCount(); ++i) {
if (!traverseTree(controller->loaderDocumentAt(i), partiallyDependentNodes))
public:
explicit MajorGCWrapperVisitor(v8::Isolate* isolate, bool constructRetainedObjectInfos)
: m_isolate(isolate)
+ , m_domObjectsWithPendingActivity(0)
, m_liveRootGroupIdSet(false)
, m_constructRetainedObjectInfos(constructRetainedObjectInfos)
{
}
- virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) OVERRIDE
+ virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override
{
if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId)
return;
const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper);
ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper);
- if (activeDOMObject && activeDOMObject->hasPendingActivity())
+ if (activeDOMObject && activeDOMObject->hasPendingActivity()) {
m_isolate->SetObjectGroupId(*value, liveRootId());
+ ++m_domObjectsWithPendingActivity;
+ }
if (classId == WrapperTypeInfo::NodeClassId) {
ASSERT(V8Node::hasInstance(*wrapper, m_isolate));
Node* node = V8Node::toImpl(*wrapper);
if (node->hasEventListeners())
addReferencesForNodeWithEventListeners(m_isolate, node, v8::Persistent<v8::Object>::Cast(*value));
- Node* root = V8GCController::opaqueRootForGC(node, m_isolate);
+ Node* root = V8GCController::opaqueRootForGC(m_isolate, node);
m_isolate->SetObjectGroupId(*value, v8::UniqueId(reinterpret_cast<intptr_t>(root)));
if (m_constructRetainedObjectInfos)
m_groupsWhichNeedRetainerInfo.append(root);
} else if (classId == WrapperTypeInfo::ObjectClassId) {
- type->visitDOMWrapper(toScriptWrappableBase(*wrapper), v8::Persistent<v8::Object>::Cast(*value), m_isolate);
+ type->visitDOMWrapper(m_isolate, toScriptWrappableBase(*wrapper), v8::Persistent<v8::Object>::Cast(*value));
} else {
ASSERT_NOT_REACHED();
}
alreadyAdded = root;
}
}
+ if (m_liveRootGroupIdSet)
+ profiler->SetRetainedObjectInfo(liveRootId(), new ActiveDOMObjectsInfo(m_domObjectsWithPendingActivity));
}
private:
if (!m_liveRootGroupIdSet) {
m_isolate->SetObjectGroupId(liveRoot, id);
m_liveRootGroupIdSet = true;
+ ++m_domObjectsWithPendingActivity;
}
return id;
}
v8::Isolate* m_isolate;
WillBePersistentHeapVector<RawPtrWillBeMember<Node> > m_groupsWhichNeedRetainerInfo;
+ int m_domObjectsWithPendingActivity;
bool m_liveRootGroupIdSet;
bool m_constructRetainedObjectInfos;
};
if (type == v8::kGCTypeScavenge)
minorGCPrologue(isolate);
else if (type == v8::kGCTypeMarkSweepCompact)
- majorGCPrologue(flags & v8::kGCCallbackFlagConstructRetainedObjectInfos, isolate);
+ majorGCPrologue(isolate, flags & v8::kGCCallbackFlagConstructRetainedObjectInfos);
}
void V8GCController::minorGCPrologue(v8::Isolate* isolate)
}
// Create object groups for DOM tree nodes.
-void V8GCController::majorGCPrologue(bool constructRetainedObjectInfos, v8::Isolate* isolate)
+void V8GCController::majorGCPrologue(v8::Isolate* isolate, bool constructRetainedObjectInfos)
{
v8::HandleScope scope(isolate);
TRACE_EVENT_BEGIN0("v8", "majorGC");
{
TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "DOMMajorGC");
MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos);
- v8::V8::VisitHandlesWithClassIds(&visitor);
+ v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
visitor.notifyFinished();
}
V8PerIsolateData::from(isolate)->setPreviousSamplingState(TRACE_EVENT_GET_SAMPLING_STATE());
TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8MajorGC");
} else {
MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos);
- v8::V8::VisitHandlesWithClassIds(&visitor);
+ v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
visitor.notifyFinished();
}
}
lastUsageReportedToV8 = currentUsage;
}
+class DOMWrapperTracer : public v8::PersistentHandleVisitor {
+public:
+ explicit DOMWrapperTracer(Visitor* visitor)
+ : m_visitor(visitor)
+ {
+ }
+
+ virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_t classId) override
+ {
+ if (classId != WrapperTypeInfo::NodeClassId && classId != WrapperTypeInfo::ObjectClassId)
+ return;
+
+ // Casting to a Handle is safe here, since the Persistent doesn't get GCd
+ // during tracing.
+ ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject());
+ v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object>*>(value);
+ ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper));
+ if (m_visitor)
+ toWrapperTypeInfo(*wrapper)->trace(m_visitor, toScriptWrappableBase(*wrapper));
+ }
+
+private:
+ Visitor* m_visitor;
+};
+
+void V8GCController::traceDOMWrappers(v8::Isolate* isolate, Visitor* visitor)
+{
+ DOMWrapperTracer tracer(visitor);
+ v8::V8::VisitHandlesWithClassIds(isolate, &tracer);
+}
+
} // namespace blink