| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2009 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 #include "bindings/v8/V8RecursionScope.h" | 40 #include "bindings/v8/V8RecursionScope.h" |
| 41 #include "bindings/v8/WrapperTypeInfo.h" | 41 #include "bindings/v8/WrapperTypeInfo.h" |
| 42 #include "core/dom/Attr.h" | 42 #include "core/dom/Attr.h" |
| 43 #include "core/html/HTMLImageElement.h" | 43 #include "core/html/HTMLImageElement.h" |
| 44 #include "core/platform/MemoryUsageSupport.h" | 44 #include "core/platform/MemoryUsageSupport.h" |
| 45 #include "core/platform/chromium/TraceEvent.h" | 45 #include "core/platform/chromium/TraceEvent.h" |
| 46 #include <algorithm> | 46 #include <algorithm> |
| 47 | 47 |
| 48 namespace WebCore { | 48 namespace WebCore { |
| 49 | 49 |
| 50 class ImplicitConnection { | |
| 51 public: | |
| 52 ImplicitConnection(void* root, v8::Persistent<v8::Object> wrapper) | |
| 53 : m_root(root) | |
| 54 , m_wrapper(wrapper) | |
| 55 , m_rootNode(0) | |
| 56 { | |
| 57 } | |
| 58 ImplicitConnection(Node* root, v8::Persistent<v8::Object> wrapper) | |
| 59 : m_root(root) | |
| 60 , m_wrapper(wrapper) | |
| 61 , m_rootNode(root) | |
| 62 { | |
| 63 } | |
| 64 | |
| 65 void* root() const { return m_root; } | |
| 66 v8::Persistent<v8::Object> wrapper() const { return m_wrapper; } | |
| 67 | |
| 68 PassOwnPtr<RetainedObjectInfo> retainedObjectInfo() | |
| 69 { | |
| 70 if (!m_rootNode) | |
| 71 return nullptr; | |
| 72 return adoptPtr(new RetainedDOMInfo(m_rootNode)); | |
| 73 } | |
| 74 | |
| 75 private: | |
| 76 void* m_root; | |
| 77 v8::Persistent<v8::Object> m_wrapper; | |
| 78 Node* m_rootNode; | |
| 79 }; | |
| 80 | |
| 81 bool operator<(const ImplicitConnection& left, const ImplicitConnection& right) | |
| 82 { | |
| 83 return left.root() < right.root(); | |
| 84 } | |
| 85 | |
| 86 struct ImplicitReference { | |
| 87 ImplicitReference(void* parent, v8::Persistent<v8::Object> child) | |
| 88 : parent(parent) | |
| 89 , child(child) | |
| 90 { | |
| 91 } | |
| 92 | |
| 93 void* parent; | |
| 94 v8::Persistent<v8::Object> child; | |
| 95 }; | |
| 96 | |
| 97 bool operator<(const ImplicitReference& left, const ImplicitReference& right) | |
| 98 { | |
| 99 return left.parent < right.parent; | |
| 100 } | |
| 101 | |
| 102 class WrapperGrouper { | |
| 103 public: | |
| 104 WrapperGrouper() | |
| 105 { | |
| 106 m_liveObjects.append(V8PerIsolateData::current()->ensureLiveRoot()); | |
| 107 } | |
| 108 | |
| 109 void addObjectWrapperToGroup(void* root, v8::Persistent<v8::Object> wrapper) | |
| 110 { | |
| 111 m_connections.append(ImplicitConnection(root, wrapper)); | |
| 112 } | |
| 113 | |
| 114 void addNodeWrapperToGroup(Node* root, v8::Persistent<v8::Object> wrapper) | |
| 115 { | |
| 116 m_connections.append(ImplicitConnection(root, wrapper)); | |
| 117 } | |
| 118 | |
| 119 void addImplicitReference(void* parent, v8::Persistent<v8::Object> child) | |
| 120 { | |
| 121 m_references.append(ImplicitReference(parent, child)); | |
| 122 m_rootGroupMap.add(parent, v8::Persistent<v8::Object>()); | |
| 123 } | |
| 124 | |
| 125 void keepAlive(v8::Persistent<v8::Value> wrapper) | |
| 126 { | |
| 127 m_liveObjects.append(wrapper); | |
| 128 } | |
| 129 | |
| 130 void apply() | |
| 131 { | |
| 132 if (m_liveObjects.size() > 1) | |
| 133 v8::V8::AddObjectGroup(m_liveObjects.data(), m_liveObjects.size()); | |
| 134 | |
| 135 std::sort(m_connections.begin(), m_connections.end()); | |
| 136 Vector<v8::Persistent<v8::Value> > group; | |
| 137 ImplicitConnection* connectionIterator = m_connections.begin(); | |
| 138 const ImplicitConnection* connectionIteratorEnd = m_connections.end(); | |
| 139 while (connectionIterator < connectionIteratorEnd) { | |
| 140 void* root = connectionIterator->root(); | |
| 141 v8::Persistent<v8::Object> groupRepresentativeWrapper = connectionIt
erator->wrapper(); | |
| 142 OwnPtr<RetainedObjectInfo> retainedObjectInfo = connectionIterator->
retainedObjectInfo(); | |
| 143 | |
| 144 do { | |
| 145 group.append(connectionIterator->wrapper()); | |
| 146 ++connectionIterator; | |
| 147 } while (connectionIterator < connectionIteratorEnd && root == conne
ctionIterator->root()); | |
| 148 | |
| 149 if (group.size() > 1) | |
| 150 v8::V8::AddObjectGroup(group.data(), group.size(), retainedObjec
tInfo.leakPtr()); | |
| 151 | |
| 152 HashMap<void*, v8::Persistent<v8::Object> >::iterator iter = m_rootG
roupMap.find(root); | |
| 153 if (iter != m_rootGroupMap.end()) | |
| 154 iter->value = groupRepresentativeWrapper; | |
| 155 | |
| 156 group.shrink(0); | |
| 157 } | |
| 158 | |
| 159 std::sort(m_references.begin(), m_references.end()); | |
| 160 const ImplicitReference* referenceIterator = m_references.begin(); | |
| 161 const ImplicitReference* referenceIteratorEnd = m_references.end(); | |
| 162 while (referenceIterator < referenceIteratorEnd) { | |
| 163 void* parent = referenceIterator->parent; | |
| 164 v8::Persistent<v8::Object> parentWrapper = m_rootGroupMap.get(parent
); | |
| 165 if (parentWrapper.IsEmpty()) { | |
| 166 ++referenceIterator; | |
| 167 continue; | |
| 168 } | |
| 169 | |
| 170 Vector<v8::Persistent<v8::Value> > children; | |
| 171 do { | |
| 172 children.append(referenceIterator->child); | |
| 173 ++referenceIterator; | |
| 174 } while (referenceIterator < referenceIteratorEnd && parent == refer
enceIterator->parent); | |
| 175 | |
| 176 v8::V8::AddImplicitReferences(parentWrapper, children.data(), childr
en.size()); | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 private: | |
| 181 Vector<v8::Persistent<v8::Value> > m_liveObjects; | |
| 182 Vector<ImplicitConnection> m_connections; | |
| 183 Vector<ImplicitReference> m_references; | |
| 184 HashMap<void*, v8::Persistent<v8::Object> > m_rootGroupMap; | |
| 185 }; | |
| 186 | |
| 187 // FIXME: This should use opaque GC roots. | 50 // FIXME: This should use opaque GC roots. |
| 188 static void addImplicitReferencesForNodeWithEventListeners(Node* node, v8::Persi
stent<v8::Object> wrapper) | 51 static void addReferencesForNodeWithEventListeners(v8::Isolate* isolate, Node* n
ode, const v8::Persistent<v8::Object>& wrapper) |
| 189 { | 52 { |
| 190 ASSERT(node->hasEventListeners()); | 53 ASSERT(node->hasEventListeners()); |
| 191 | 54 |
| 192 Vector<v8::Persistent<v8::Value> > listeners; | |
| 193 | |
| 194 EventListenerIterator iterator(node); | 55 EventListenerIterator iterator(node); |
| 195 while (EventListener* listener = iterator.nextListener()) { | 56 while (EventListener* listener = iterator.nextListener()) { |
| 196 if (listener->type() != EventListener::JSEventListenerType) | 57 if (listener->type() != EventListener::JSEventListenerType) |
| 197 continue; | 58 continue; |
| 198 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListene
r*>(listener); | 59 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListene
r*>(listener); |
| 199 if (!v8listener->hasExistingListenerObject()) | 60 if (!v8listener->hasExistingListenerObject()) |
| 200 continue; | 61 continue; |
| 201 listeners.append(v8listener->existingListenerObjectPersistentHandle()); | 62 |
| 63 isolate->SetReference(wrapper, v8listener->existingListenerObjectPersist
entHandle()); |
| 202 } | 64 } |
| 203 | |
| 204 if (listeners.isEmpty()) | |
| 205 return; | |
| 206 | |
| 207 v8::V8::AddImplicitReferences(wrapper, listeners.data(), listeners.size()); | |
| 208 } | 65 } |
| 209 | 66 |
| 210 Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) | 67 Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) |
| 211 { | 68 { |
| 212 // FIXME: Remove the special handling for image elements. | 69 // FIXME: Remove the special handling for image elements. |
| 213 // The same special handling is in V8GCController::gcTree(). | 70 // The same special handling is in V8GCController::gcTree(). |
| 214 // Maybe should image elements be active DOM nodes? | 71 // Maybe should image elements be active DOM nodes? |
| 215 // See https://code.google.com/p/chromium/issues/detail?id=164882 | 72 // See https://code.google.com/p/chromium/issues/detail?id=164882 |
| 216 if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && static_cas
t<HTMLImageElement*>(node)->hasPendingActivity())) | 73 if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && static_cas
t<HTMLImageElement*>(node)->hasPendingActivity())) |
| 217 return node->document(); | 74 return node->document(); |
| 218 | 75 |
| 219 if (node->isAttributeNode()) { | 76 if (node->isAttributeNode()) { |
| 220 Node* ownerElement = static_cast<Attr*>(node)->ownerElement(); | 77 Node* ownerElement = static_cast<Attr*>(node)->ownerElement(); |
| 221 if (!ownerElement) | 78 if (!ownerElement) |
| 222 return node; | 79 return node; |
| 223 node = ownerElement; | 80 node = ownerElement; |
| 224 } | 81 } |
| 225 | 82 |
| 226 while (Node* parent = node->parentOrShadowHostNode()) | 83 while (Node* parent = node->parentOrShadowHostNode()) |
| 227 node = parent; | 84 node = parent; |
| 228 | 85 |
| 229 return node; | 86 return node; |
| 230 } | 87 } |
| 231 | 88 |
| 232 static void gcTree(v8::Isolate* isolate, Node* startNode) | 89 static void gcTree(v8::Isolate* isolate, Node* startNode) |
| 233 { | 90 { |
| 234 Vector<v8::Persistent<v8::Value>, initialNodeVectorSize> newSpaceWrappers; | 91 Vector<Node*, initialNodeVectorSize> newSpaceNodes; |
| 235 | 92 |
| 236 // We traverse a DOM tree in the DFS order starting from startNode. | 93 // We traverse a DOM tree in the DFS order starting from startNode. |
| 237 // The traversal order does not matter for correctness but does matter for p
erformance. | 94 // The traversal order does not matter for correctness but does matter for p
erformance. |
| 238 Node* node = startNode; | 95 Node* node = startNode; |
| 239 // To make each minor GC time bounded, we might need to give up | 96 // To make each minor GC time bounded, we might need to give up |
| 240 // traversing at some point for a large DOM tree. That being said, | 97 // traversing at some point for a large DOM tree. That being said, |
| 241 // I could not observe the need even in pathological test cases. | 98 // I could not observe the need even in pathological test cases. |
| 242 do { | 99 do { |
| 243 ASSERT(node); | 100 ASSERT(node); |
| 244 if (!node->wrapper().IsEmpty()) { | 101 if (!node->wrapper().IsEmpty()) { |
| 245 // FIXME: Remove the special handling for image elements. | 102 // FIXME: Remove the special handling for image elements. |
| 246 // The same special handling is in V8GCController::opaqueRootForGC()
. | 103 // The same special handling is in V8GCController::opaqueRootForGC()
. |
| 247 // Maybe should image elements be active DOM nodes? | 104 // Maybe should image elements be active DOM nodes? |
| 248 // See https://code.google.com/p/chromium/issues/detail?id=164882 | 105 // See https://code.google.com/p/chromium/issues/detail?id=164882 |
| 249 if (!node->isV8CollectableDuringMinorGC() || (node->hasTagName(HTMLN
ames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity())) { | 106 if (!node->isV8CollectableDuringMinorGC() || (node->hasTagName(HTMLN
ames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity())) { |
| 250 // This node is not in the new space of V8. This indicates that | 107 // This node is not in the new space of V8. This indicates that |
| 251 // the minor GC cannot anyway judge reachability of this DOM tre
e. | 108 // the minor GC cannot anyway judge reachability of this DOM tre
e. |
| 252 // Thus we give up traversing the DOM tree. | 109 // Thus we give up traversing the DOM tree. |
| 253 return; | 110 return; |
| 254 } | 111 } |
| 255 node->setV8CollectableDuringMinorGC(false); | 112 node->setV8CollectableDuringMinorGC(false); |
| 256 newSpaceWrappers.append(node->wrapper()); | 113 newSpaceNodes.append(node); |
| 257 } | 114 } |
| 258 if (node->firstChild()) { | 115 if (node->firstChild()) { |
| 259 node = node->firstChild(); | 116 node = node->firstChild(); |
| 260 continue; | 117 continue; |
| 261 } | 118 } |
| 262 while (!node->nextSibling()) { | 119 while (!node->nextSibling()) { |
| 263 if (!node->parentNode()) | 120 if (!node->parentNode()) |
| 264 break; | 121 break; |
| 265 node = node->parentNode(); | 122 node = node->parentNode(); |
| 266 } | 123 } |
| 267 if (node->parentNode()) | 124 if (node->parentNode()) |
| 268 node = node->nextSibling(); | 125 node = node->nextSibling(); |
| 269 } while (node != startNode); | 126 } while (node != startNode); |
| 270 | 127 |
| 271 // We completed the DOM tree traversal. All wrappers in the DOM tree are | 128 // We completed the DOM tree traversal. All wrappers in the DOM tree are |
| 272 // stored in newSpaceWrappers and are expected to exist in the new space of
V8. | 129 // stored in newSpaceNodes and are expected to exist in the new space of V8. |
| 273 // We report those wrappers to V8 as an object group. | 130 // We report those wrappers to V8 as an object group. |
| 274 v8::Persistent<v8::Value>* wrapperIterator = newSpaceWrappers.begin(); | 131 Node** nodeIterator = newSpaceNodes.begin(); |
| 275 const v8::Persistent<v8::Value>* wrapperIteratorEnd = newSpaceWrappers.end()
; | 132 Node** const nodeIteratorEnd = newSpaceNodes.end(); |
| 276 for (; wrapperIterator != wrapperIteratorEnd; ++wrapperIterator) | 133 if (nodeIterator == nodeIteratorEnd) |
| 277 wrapperIterator->MarkPartiallyDependent(isolate); | 134 return; |
| 278 if (newSpaceWrappers.size() > 0) | 135 v8::UniqueId id(reinterpret_cast<intptr_t>(*(*nodeIterator)->wrapper())); |
| 279 v8::V8::AddObjectGroup(&newSpaceWrappers[0], newSpaceWrappers.size()); | 136 for (; nodeIterator != nodeIteratorEnd; ++nodeIterator) { |
| 137 v8::Persistent<v8::Object> wrapper((*nodeIterator)->wrapper()); |
| 138 wrapper.MarkPartiallyDependent(isolate); |
| 139 isolate->SetObjectGroupId(wrapper, id); |
| 140 } |
| 280 } | 141 } |
| 281 | 142 |
| 282 // Regarding a minor GC algorithm for DOM nodes, see this document: | 143 // Regarding a minor GC algorithm for DOM nodes, see this document: |
| 283 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g
49mWNMW2gaWvMN5NLk8/edit#slide=id.p | 144 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g
49mWNMW2gaWvMN5NLk8/edit#slide=id.p |
| 284 class MinorGCWrapperVisitor : public v8::PersistentHandleVisitor { | 145 class MinorGCWrapperVisitor : public v8::PersistentHandleVisitor { |
| 285 public: | 146 public: |
| 286 explicit MinorGCWrapperVisitor(v8::Isolate* isolate) | 147 explicit MinorGCWrapperVisitor(v8::Isolate* isolate) |
| 287 : m_isolate(isolate) | 148 : m_isolate(isolate) |
| 288 { | 149 { |
| 289 UNUSED_PARAM(m_isolate); | 150 UNUSED_PARAM(m_isolate); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 } | 197 } |
| 337 } | 198 } |
| 338 | 199 |
| 339 private: | 200 private: |
| 340 Vector<Node*> m_nodesInNewSpace; | 201 Vector<Node*> m_nodesInNewSpace; |
| 341 v8::Isolate* m_isolate; | 202 v8::Isolate* m_isolate; |
| 342 }; | 203 }; |
| 343 | 204 |
| 344 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { | 205 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { |
| 345 public: | 206 public: |
| 346 explicit MajorGCWrapperVisitor(v8::Isolate* isolate) | 207 explicit MajorGCWrapperVisitor(v8::Isolate* isolate, bool constructRetainedO
bjectInfos) |
| 347 : m_isolate(isolate) | 208 : m_isolate(isolate) |
| 209 , m_liveRootGroupIdSet(false) |
| 210 , m_constructRetainedObjectInfos(constructRetainedObjectInfos) |
| 348 { | 211 { |
| 349 } | 212 } |
| 350 | 213 |
| 351 virtual void VisitPersistentHandle(v8::Persistent<v8::Value> value, uint16_t
classId) OVERRIDE | 214 virtual void VisitPersistentHandle(v8::Persistent<v8::Value> value, uint16_t
classId) OVERRIDE |
| 352 { | 215 { |
| 353 ASSERT(value->IsObject()); | 216 ASSERT(value->IsObject()); |
| 354 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(va
lue); | 217 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(va
lue); |
| 355 | 218 |
| 356 if (classId != v8DOMNodeClassId && classId != v8DOMObjectClassId) | 219 if (classId != v8DOMNodeClassId && classId != v8DOMObjectClassId) |
| 357 return; | 220 return; |
| 358 | 221 |
| 359 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); | 222 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); |
| 360 | 223 |
| 361 if (value.IsIndependent(m_isolate)) | 224 if (value.IsIndependent(m_isolate)) |
| 362 return; | 225 return; |
| 363 | 226 |
| 364 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); | 227 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); |
| 365 void* object = toNative(wrapper); | 228 void* object = toNative(wrapper); |
| 366 | 229 |
| 367 if (V8MessagePort::info.equals(type)) { | 230 if (V8MessagePort::info.equals(type)) { |
| 368 // Mark each port as in-use if it's entangled. For simplicity's sake
, | 231 // Mark each port as in-use if it's entangled. For simplicity's sake
, |
| 369 // we assume all ports are remotely entangled, since the Chromium po
rt | 232 // we assume all ports are remotely entangled, since the Chromium po
rt |
| 370 // implementation can't tell the difference. | 233 // implementation can't tell the difference. |
| 371 MessagePort* port = static_cast<MessagePort*>(object); | 234 MessagePort* port = static_cast<MessagePort*>(object); |
| 372 if (port->isEntangled() || port->hasPendingActivity()) | 235 if (port->isEntangled() || port->hasPendingActivity()) |
| 373 m_grouper.keepAlive(wrapper); | 236 m_isolate->SetObjectGroupId(wrapper, liveRootId()); |
| 374 } else if (V8MutationObserver::info.equals(type)) { | 237 } else if (V8MutationObserver::info.equals(type)) { |
| 375 // FIXME: Allow opaqueRootForGC to operate on multiple roots and mov
e this logic into V8MutationObserverCustom. | 238 // FIXME: Allow opaqueRootForGC to operate on multiple roots and mov
e this logic into V8MutationObserverCustom. |
| 376 MutationObserver* observer = static_cast<MutationObserver*>(object); | 239 MutationObserver* observer = static_cast<MutationObserver*>(object); |
| 377 HashSet<Node*> observedNodes = observer->getObservedNodes(); | 240 HashSet<Node*> observedNodes = observer->getObservedNodes(); |
| 378 for (HashSet<Node*>::iterator it = observedNodes.begin(); it != obse
rvedNodes.end(); ++it) | 241 for (HashSet<Node*>::iterator it = observedNodes.begin(); it != obse
rvedNodes.end(); ++it) { |
| 379 m_grouper.addImplicitReference(V8GCController::opaqueRootForGC(*
it, m_isolate), wrapper); | 242 v8::UniqueId id(reinterpret_cast<intptr_t>(V8GCController::opaqu
eRootForGC(*it, m_isolate))); |
| 243 m_isolate->SetReferenceFromGroup(id, wrapper); |
| 244 } |
| 380 } else { | 245 } else { |
| 381 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); | 246 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); |
| 382 if (activeDOMObject && activeDOMObject->hasPendingActivity()) | 247 if (activeDOMObject && activeDOMObject->hasPendingActivity()) |
| 383 m_grouper.keepAlive(wrapper); | 248 m_isolate->SetObjectGroupId(wrapper, liveRootId()); |
| 384 } | 249 } |
| 385 | 250 |
| 386 if (classId == v8DOMNodeClassId) { | 251 if (classId == v8DOMNodeClassId) { |
| 387 UNUSED_PARAM(m_isolate); | 252 UNUSED_PARAM(m_isolate); |
| 388 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); | 253 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); |
| 389 ASSERT(!wrapper.IsIndependent(m_isolate)); | 254 ASSERT(!wrapper.IsIndependent(m_isolate)); |
| 390 | 255 |
| 391 Node* node = static_cast<Node*>(object); | 256 Node* node = static_cast<Node*>(object); |
| 392 | 257 |
| 393 if (node->hasEventListeners()) | 258 if (node->hasEventListeners()) |
| 394 addImplicitReferencesForNodeWithEventListeners(node, wrapper); | 259 addReferencesForNodeWithEventListeners(m_isolate, node, wrapper)
; |
| 395 | 260 Node* root = V8GCController::opaqueRootForGC(node, m_isolate); |
| 396 m_grouper.addNodeWrapperToGroup(V8GCController::opaqueRootForGC(node
, m_isolate), wrapper); | 261 m_isolate->SetObjectGroupId(wrapper, v8::UniqueId(reinterpret_cast<i
ntptr_t>(root))); |
| 262 if (m_constructRetainedObjectInfos) |
| 263 m_groupsWhichNeedRetainerInfo.append(root); |
| 397 } else if (classId == v8DOMObjectClassId) { | 264 } else if (classId == v8DOMObjectClassId) { |
| 398 m_grouper.addObjectWrapperToGroup(type->opaqueRootForGC(object, wrap
per, m_isolate), wrapper); | 265 void* root = type->opaqueRootForGC(object, wrapper, m_isolate); |
| 266 m_isolate->SetObjectGroupId(wrapper, v8::UniqueId(reinterpret_cast<i
ntptr_t>(root))); |
| 399 } else { | 267 } else { |
| 400 ASSERT_NOT_REACHED(); | 268 ASSERT_NOT_REACHED(); |
| 401 } | 269 } |
| 402 } | 270 } |
| 403 | 271 |
| 404 void notifyFinished() | 272 void notifyFinished() |
| 405 { | 273 { |
| 406 m_grouper.apply(); | 274 if (!m_constructRetainedObjectInfos) |
| 275 return; |
| 276 std::sort(m_groupsWhichNeedRetainerInfo.begin(), m_groupsWhichNeedRetain
erInfo.end()); |
| 277 Node* alreadyAdded = 0; |
| 278 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); |
| 279 for (size_t i = 0; i < m_groupsWhichNeedRetainerInfo.size(); ++i) { |
| 280 Node* root = m_groupsWhichNeedRetainerInfo[i]; |
| 281 if (root != alreadyAdded) { |
| 282 profiler->SetRetainedObjectInfo(v8::UniqueId(reinterpret_cast<in
tptr_t>(root)), new RetainedDOMInfo(root)); |
| 283 alreadyAdded = root; |
| 284 } |
| 285 } |
| 407 } | 286 } |
| 408 | 287 |
| 409 private: | 288 private: |
| 410 WrapperGrouper m_grouper; | 289 v8::UniqueId liveRootId() |
| 290 { |
| 291 const v8::Persistent<v8::Value>& liveRoot = V8PerIsolateData::from(m_iso
late)->ensureLiveRoot(); |
| 292 v8::UniqueId id(reinterpret_cast<intptr_t>(*liveRoot)); |
| 293 if (!m_liveRootGroupIdSet) { |
| 294 m_isolate->SetObjectGroupId(*liveRoot, id); |
| 295 m_liveRootGroupIdSet = true; |
| 296 } |
| 297 return id; |
| 298 } |
| 299 |
| 411 v8::Isolate* m_isolate; | 300 v8::Isolate* m_isolate; |
| 301 Vector<Node*> m_groupsWhichNeedRetainerInfo; |
| 302 bool m_liveRootGroupIdSet; |
| 303 bool m_constructRetainedObjectInfos; |
| 412 }; | 304 }; |
| 413 | 305 |
| 414 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) | 306 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) |
| 415 { | 307 { |
| 416 // It would be nice if the GC callbacks passed the Isolate directly.... | 308 // It would be nice if the GC callbacks passed the Isolate directly.... |
| 417 if (type == v8::kGCTypeScavenge) | 309 if (type == v8::kGCTypeScavenge) |
| 418 minorGCPrologue(v8::Isolate::GetCurrent()); | 310 minorGCPrologue(v8::Isolate::GetCurrent()); |
| 419 else if (type == v8::kGCTypeMarkSweepCompact) | 311 else if (type == v8::kGCTypeMarkSweepCompact) |
| 420 majorGCPrologue(); | 312 majorGCPrologue(flags & v8::kGCCallbackFlagConstructRetainedObjectInfos)
; |
| 421 } | 313 } |
| 422 | 314 |
| 423 void V8GCController::minorGCPrologue(v8::Isolate* isolate) | 315 void V8GCController::minorGCPrologue(v8::Isolate* isolate) |
| 424 { | 316 { |
| 425 TRACE_EVENT_BEGIN0("v8", "GC"); | 317 TRACE_EVENT_BEGIN0("v8", "GC"); |
| 426 | 318 |
| 427 if (isMainThread()) { | 319 if (isMainThread()) { |
| 428 v8::HandleScope scope; | 320 v8::HandleScope scope; |
| 429 | 321 |
| 430 MinorGCWrapperVisitor visitor(isolate); | 322 MinorGCWrapperVisitor visitor(isolate); |
| 431 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); | 323 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); |
| 432 visitor.notifyFinished(); | 324 visitor.notifyFinished(); |
| 433 } | 325 } |
| 434 } | 326 } |
| 435 | 327 |
| 436 // Create object groups for DOM tree nodes. | 328 // Create object groups for DOM tree nodes. |
| 437 void V8GCController::majorGCPrologue() | 329 void V8GCController::majorGCPrologue(bool constructRetainedObjectInfos) |
| 438 { | 330 { |
| 439 TRACE_EVENT_BEGIN0("v8", "GC"); | 331 TRACE_EVENT_BEGIN0("v8", "GC"); |
| 440 | 332 |
| 441 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 333 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 442 v8::HandleScope scope; | 334 v8::HandleScope scope; |
| 443 | 335 |
| 444 MajorGCWrapperVisitor visitor(isolate); | 336 MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos); |
| 445 v8::V8::VisitHandlesWithClassIds(&visitor); | 337 v8::V8::VisitHandlesWithClassIds(&visitor); |
| 446 visitor.notifyFinished(); | 338 visitor.notifyFinished(); |
| 447 | 339 |
| 448 V8PerIsolateData::from(isolate)->stringCache()->clearOnGC(); | 340 V8PerIsolateData::from(isolate)->stringCache()->clearOnGC(); |
| 449 } | 341 } |
| 450 | 342 |
| 451 static int workingSetEstimateMB = 0; | 343 static int workingSetEstimateMB = 0; |
| 452 | 344 |
| 453 static Mutex& workingSetEstimateMBMutex() | 345 static Mutex& workingSetEstimateMBMutex() |
| 454 { | 346 { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 538 if (!script.IsEmpty()) { | 430 if (!script.IsEmpty()) { |
| 539 V8RecursionScope::MicrotaskSuppression scope; | 431 V8RecursionScope::MicrotaskSuppression scope; |
| 540 script->Run(); | 432 script->Run(); |
| 541 } | 433 } |
| 542 } | 434 } |
| 543 | 435 |
| 544 context.clear(); | 436 context.clear(); |
| 545 } | 437 } |
| 546 | 438 |
| 547 } // namespace WebCore | 439 } // namespace WebCore |
| OLD | NEW |