Chromium Code Reviews| 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 addImplicitReferencesForNodeWithEventListeners(v8::Isolate* isolate, Node* node, const v8::Persistent<v8::Object>& wrapper) |
|
haraken
2013/04/25 14:55:54
addImplicitReferencesForNodeWithEventListeners =>
marja
2013/04/26 08:14:47
As agreed offline: addReferencesFromNodeToEventLis
| |
| 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> newSpaceWrappers; |
|
haraken
2013/04/25 14:55:54
newSpaceWrappers => newSpaceNodes
marja
2013/04/26 08:14:47
Done.
| |
| 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 newSpaceWrappers.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 newSpaceWrappers 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 = newSpaceWrappers.begin(); |
| 275 const v8::Persistent<v8::Value>* wrapperIteratorEnd = newSpaceWrappers.end() ; | 132 Node** const nodeIteratorEnd = newSpaceWrappers.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 = v8::Persistent<v8::Object>((*nodeIt erator)->wrapper()); | |
|
haraken
2013/04/25 14:55:54
Nit: It looks redundant to access (*nodeIterator)-
marja
2013/04/26 08:14:47
Discussed offline -> not changing this. Streamlien
| |
| 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), m_liveRootGroupIdSet(false), m_constructRetainedOb jectInfos(constructRetainedObjectInfos) |
|
haraken
2013/04/25 14:55:54
Nit: We normally write one initialization per line
marja
2013/04/26 08:14:47
Done.
| |
| 348 { | 209 { |
| 349 } | 210 } |
| 350 | 211 |
| 351 virtual void VisitPersistentHandle(v8::Persistent<v8::Value> value, uint16_t classId) OVERRIDE | 212 virtual void VisitPersistentHandle(v8::Persistent<v8::Value> value, uint16_t classId) OVERRIDE |
| 352 { | 213 { |
| 353 ASSERT(value->IsObject()); | 214 ASSERT(value->IsObject()); |
| 354 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(va lue); | 215 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(va lue); |
| 355 | 216 |
| 356 if (classId != v8DOMNodeClassId && classId != v8DOMObjectClassId) | 217 if (classId != v8DOMNodeClassId && classId != v8DOMObjectClassId) |
| 357 return; | 218 return; |
| 358 | 219 |
| 359 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); | 220 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); |
| 360 | 221 |
| 361 if (value.IsIndependent(m_isolate)) | 222 if (value.IsIndependent(m_isolate)) |
| 362 return; | 223 return; |
| 363 | 224 |
| 364 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); | 225 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); |
| 365 void* object = toNative(wrapper); | 226 void* object = toNative(wrapper); |
| 366 | 227 |
| 367 if (V8MessagePort::info.equals(type)) { | 228 if (V8MessagePort::info.equals(type)) { |
| 368 // Mark each port as in-use if it's entangled. For simplicity's sake , | 229 // 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 | 230 // we assume all ports are remotely entangled, since the Chromium po rt |
| 370 // implementation can't tell the difference. | 231 // implementation can't tell the difference. |
| 371 MessagePort* port = static_cast<MessagePort*>(object); | 232 MessagePort* port = static_cast<MessagePort*>(object); |
| 372 if (port->isEntangled() || port->hasPendingActivity()) | 233 if (port->isEntangled() || port->hasPendingActivity()) |
| 373 m_grouper.keepAlive(wrapper); | 234 setObjectGroupId(wrapper, ensureLiveRoot()); |
| 374 } else if (V8MutationObserver::info.equals(type)) { | 235 } else if (V8MutationObserver::info.equals(type)) { |
| 375 // FIXME: Allow opaqueRootForGC to operate on multiple roots and mov e this logic into V8MutationObserverCustom. | 236 // FIXME: Allow opaqueRootForGC to operate on multiple roots and mov e this logic into V8MutationObserverCustom. |
| 376 MutationObserver* observer = static_cast<MutationObserver*>(object); | 237 MutationObserver* observer = static_cast<MutationObserver*>(object); |
| 377 HashSet<Node*> observedNodes = observer->getObservedNodes(); | 238 HashSet<Node*> observedNodes = observer->getObservedNodes(); |
| 378 for (HashSet<Node*>::iterator it = observedNodes.begin(); it != obse rvedNodes.end(); ++it) | 239 for (HashSet<Node*>::iterator it = observedNodes.begin(); it != obse rvedNodes.end(); ++it) |
| 379 m_grouper.addImplicitReference(V8GCController::opaqueRootForGC(* it, m_isolate), wrapper); | 240 m_isolate->SetReferenceFromGroup(v8::UniqueId(reinterpret_cast<i ntptr_t>(V8GCController::opaqueRootForGC(*it, m_isolate))), wrapper); |
|
haraken
2013/04/25 14:55:54
Nit: Shall we write this in two lines?
v8::Unique
marja
2013/04/26 08:14:47
Offline discussion -> not going to change the logi
| |
| 380 } else { | 241 } else { |
| 381 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); | 242 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); |
| 382 if (activeDOMObject && activeDOMObject->hasPendingActivity()) | 243 if (activeDOMObject && activeDOMObject->hasPendingActivity()) |
| 383 m_grouper.keepAlive(wrapper); | 244 setObjectGroupId(wrapper, ensureLiveRoot()); |
| 384 } | 245 } |
| 385 | 246 |
| 386 if (classId == v8DOMNodeClassId) { | 247 if (classId == v8DOMNodeClassId) { |
| 387 UNUSED_PARAM(m_isolate); | 248 UNUSED_PARAM(m_isolate); |
| 388 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); | 249 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); |
| 389 ASSERT(!wrapper.IsIndependent(m_isolate)); | 250 ASSERT(!wrapper.IsIndependent(m_isolate)); |
| 390 | 251 |
| 391 Node* node = static_cast<Node*>(object); | 252 Node* node = static_cast<Node*>(object); |
| 392 | 253 |
| 393 if (node->hasEventListeners()) | 254 if (node->hasEventListeners()) |
| 394 addImplicitReferencesForNodeWithEventListeners(node, wrapper); | 255 addImplicitReferencesForNodeWithEventListeners(m_isolate, node, wrapper); |
| 395 | 256 Node* root = V8GCController::opaqueRootForGC(node, m_isolate); |
| 396 m_grouper.addNodeWrapperToGroup(V8GCController::opaqueRootForGC(node , m_isolate), wrapper); | 257 setObjectGroupId(wrapper, root); |
| 258 if (m_constructRetainedObjectInfos) | |
| 259 m_groupsWhichNeedRetainerInfo.append(root); | |
| 397 } else if (classId == v8DOMObjectClassId) { | 260 } else if (classId == v8DOMObjectClassId) { |
| 398 m_grouper.addObjectWrapperToGroup(type->opaqueRootForGC(object, wrap per, m_isolate), wrapper); | 261 void* root = type->opaqueRootForGC(object, wrapper, m_isolate); |
| 262 setObjectGroupId(wrapper, root); | |
| 399 } else { | 263 } else { |
| 400 ASSERT_NOT_REACHED(); | 264 ASSERT_NOT_REACHED(); |
| 401 } | 265 } |
| 402 } | 266 } |
| 403 | 267 |
| 404 void notifyFinished() | 268 void notifyFinished() { |
| 405 { | 269 std::sort(m_groupsWhichNeedRetainerInfo.begin(), m_groupsWhichNeedRetain erInfo.end()); |
| 406 m_grouper.apply(); | 270 Node* already_added = 0; |
|
haraken
2013/04/25 14:55:54
Nit: already_added => alreadyAdded
marja
2013/04/26 08:14:47
Done.
| |
| 271 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); | |
| 272 for (size_t i = 0; i < m_groupsWhichNeedRetainerInfo.size(); ++i) { | |
| 273 Node* root = m_groupsWhichNeedRetainerInfo[i]; | |
| 274 if (root != already_added) { | |
| 275 profiler->SetRetainedObjectInfo(v8::UniqueId(reinterpret_cast<in tptr_t>(root)), new RetainedDOMInfo(root)); | |
| 276 already_added = root; | |
| 277 } | |
| 278 } | |
| 407 } | 279 } |
| 408 | 280 |
| 409 private: | 281 private: |
| 410 WrapperGrouper m_grouper; | 282 void setObjectGroupId(const v8::Persistent<v8::Object>& object, void* root) |
| 283 { | |
| 284 v8::UniqueId id(reinterpret_cast<intptr_t>(root)); | |
| 285 m_isolate->SetObjectGroupId(object, id); | |
| 286 } | |
| 287 | |
| 288 void* ensureLiveRoot() | |
| 289 { | |
| 290 v8::Persistent<v8::Value> liveRoot = V8PerIsolateData::current()->ensure LiveRoot(); | |
|
haraken
2013/04/25 14:55:54
V8PerIsolateData::current() is heavy. You should u
marja
2013/04/26 08:14:47
Ahh, thanks for pointing that out. The previous ve
| |
| 291 if (!m_liveRootGroupIdSet) { | |
| 292 v8::UniqueId id(reinterpret_cast<intptr_t>(*liveRoot)); | |
| 293 m_isolate->SetObjectGroupId(*liveRoot, id); | |
| 294 m_liveRootGroupIdSet = true; | |
| 295 } | |
| 296 return *liveRoot; | |
|
haraken
2013/04/25 14:55:54
How about returning id from this method?
Currentl
marja
2013/04/26 08:14:47
Done.
| |
| 297 } | |
| 298 | |
| 411 v8::Isolate* m_isolate; | 299 v8::Isolate* m_isolate; |
| 300 Vector<Node*> m_groupsWhichNeedRetainerInfo; | |
| 301 bool m_liveRootGroupIdSet; | |
| 302 bool m_constructRetainedObjectInfos; | |
| 412 }; | 303 }; |
| 413 | 304 |
| 414 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) | 305 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) |
| 415 { | 306 { |
| 416 // It would be nice if the GC callbacks passed the Isolate directly.... | 307 // It would be nice if the GC callbacks passed the Isolate directly.... |
| 417 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 308 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 418 if (type == v8::kGCTypeScavenge) | 309 if (type == v8::kGCTypeScavenge) |
| 419 minorGCPrologue(isolate); | 310 minorGCPrologue(isolate); |
| 420 else if (type == v8::kGCTypeMarkSweepCompact) | 311 else if (type == v8::kGCTypeMarkSweepCompact) |
| 421 majorGCPrologue(); | 312 majorGCPrologue(flags & v8::kGCCallbackFlagConstructRetainedObjectInfos) ; |
| 422 } | 313 } |
| 423 | 314 |
| 424 void V8GCController::minorGCPrologue(v8::Isolate* isolate) | 315 void V8GCController::minorGCPrologue(v8::Isolate* isolate) |
| 425 { | 316 { |
| 426 TRACE_EVENT_BEGIN0("v8", "GC"); | 317 TRACE_EVENT_BEGIN0("v8", "GC"); |
| 427 | 318 |
| 428 if (isMainThread()) { | 319 if (isMainThread()) { |
| 429 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 320 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 430 v8::HandleScope scope; | 321 v8::HandleScope scope; |
| 431 | 322 |
| 432 MinorGCWrapperVisitor visitor(isolate); | 323 MinorGCWrapperVisitor visitor(isolate); |
| 433 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); | 324 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); |
| 434 visitor.notifyFinished(); | 325 visitor.notifyFinished(); |
| 435 } | 326 } |
| 436 } | 327 } |
| 437 | 328 |
| 438 // Create object groups for DOM tree nodes. | 329 // Create object groups for DOM tree nodes. |
| 439 void V8GCController::majorGCPrologue() | 330 void V8GCController::majorGCPrologue(bool constructRetainedObjectInfos) |
| 440 { | 331 { |
| 441 TRACE_EVENT_BEGIN0("v8", "GC"); | 332 TRACE_EVENT_BEGIN0("v8", "GC"); |
| 442 | 333 |
| 443 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 334 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
| 444 v8::HandleScope scope; | 335 v8::HandleScope scope; |
| 445 | 336 |
| 446 MajorGCWrapperVisitor visitor(isolate); | 337 MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos); |
| 447 v8::V8::VisitHandlesWithClassIds(&visitor); | 338 v8::V8::VisitHandlesWithClassIds(&visitor); |
| 448 visitor.notifyFinished(); | 339 visitor.notifyFinished(); |
| 449 | 340 |
| 450 V8PerIsolateData::from(isolate)->stringCache()->clearOnGC(); | 341 V8PerIsolateData::from(isolate)->stringCache()->clearOnGC(); |
| 451 } | 342 } |
| 452 | 343 |
| 453 static int workingSetEstimateMB = 0; | 344 static int workingSetEstimateMB = 0; |
| 454 | 345 |
| 455 static Mutex& workingSetEstimateMBMutex() | 346 static Mutex& workingSetEstimateMBMutex() |
| 456 { | 347 { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 if (!script.IsEmpty()) { | 431 if (!script.IsEmpty()) { |
| 541 V8RecursionScope::MicrotaskSuppression scope; | 432 V8RecursionScope::MicrotaskSuppression scope; |
| 542 script->Run(); | 433 script->Run(); |
| 543 } | 434 } |
| 544 } | 435 } |
| 545 | 436 |
| 546 context.clear(); | 437 context.clear(); |
| 547 } | 438 } |
| 548 | 439 |
| 549 } // namespace WebCore | 440 } // namespace WebCore |
| OLD | NEW |