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 |