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 "V8Binding.h" | 40 #include "V8Binding.h" |
41 #include "V8MessagePort.h" | 41 #include "V8MessagePort.h" |
42 #include "V8MutationObserver.h" | 42 #include "V8MutationObserver.h" |
43 #include "V8Node.h" | 43 #include "V8Node.h" |
44 #include "V8RecursionScope.h" | 44 #include "V8RecursionScope.h" |
45 #include "WrapperTypeInfo.h" | 45 #include "WrapperTypeInfo.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 size_t i = 0; | |
138 while (i < m_connections.size()) { | |
139 void* root = m_connections[i].root(); | |
140 v8::Persistent<v8::Object> groupRepresentativeWrapper = m_connection s[i].wrapper(); | |
141 OwnPtr<RetainedObjectInfo> retainedObjectInfo = m_connections[i].ret ainedObjectInfo(); | |
142 | |
143 do { | |
144 group.append(m_connections[i++].wrapper()); | |
145 } while (i < m_connections.size() && root == m_connections[i].root() ); | |
146 | |
147 if (group.size() > 1) | |
148 v8::V8::AddObjectGroup(group.data(), group.size(), retainedObjec tInfo.leakPtr()); | |
149 | |
150 HashMap<void*, v8::Persistent<v8::Object> >::iterator iter = m_rootG roupMap.find(root); | |
151 if (iter != m_rootGroupMap.end()) | |
152 iter->value = groupRepresentativeWrapper; | |
153 | |
154 group.shrink(0); | |
155 } | |
156 | |
157 std::sort(m_references.begin(), m_references.end()); | |
158 i = 0; | |
159 while (i < m_references.size()) { | |
160 void* parent = m_references[i].parent; | |
161 v8::Persistent<v8::Object> parentWrapper = m_rootGroupMap.get(parent ); | |
162 if (parentWrapper.IsEmpty()) { | |
163 ++i; | |
164 continue; | |
165 } | |
166 | |
167 Vector<v8::Persistent<v8::Value> > children; | |
168 do { | |
169 children.append(m_references[i++].child); | |
170 } while (i < m_references.size() && parent == m_references[i].parent ); | |
171 | |
172 v8::V8::AddImplicitReferences(parentWrapper, children.data(), childr en.size()); | |
173 } | |
174 } | |
175 | |
176 private: | |
177 Vector<v8::Persistent<v8::Value> > m_liveObjects; | |
178 Vector<ImplicitConnection> m_connections; | |
179 Vector<ImplicitReference> m_references; | |
180 HashMap<void*, v8::Persistent<v8::Object> > m_rootGroupMap; | |
181 }; | |
182 | |
183 // FIXME: This should use opaque GC roots. | 50 // FIXME: This should use opaque GC roots. |
184 static void addImplicitReferencesForNodeWithEventListeners(Node* node, v8::Persi stent<v8::Object> wrapper) | 51 static void addImplicitReferencesForNodeWithEventListeners(v8::Isolate* isolate, Node* node, v8::Persistent<v8::Object> wrapper) |
185 { | 52 { |
186 ASSERT(node->hasEventListeners()); | 53 ASSERT(node->hasEventListeners()); |
187 | 54 |
188 Vector<v8::Persistent<v8::Value> > listeners; | 55 // Add a new object group just for the wrapper. |
56 v8::UniqueId id(reinterpret_cast<intptr_t>(*wrapper)); | |
57 v8::V8::SetObjectGroupId(isolate, wrapper, id); | |
189 | 58 |
190 EventListenerIterator iterator(node); | 59 EventListenerIterator iterator(node); |
191 while (EventListener* listener = iterator.nextListener()) { | 60 while (EventListener* listener = iterator.nextListener()) { |
192 if (listener->type() != EventListener::JSEventListenerType) | 61 if (listener->type() != EventListener::JSEventListenerType) |
193 continue; | 62 continue; |
194 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListene r*>(listener); | 63 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListene r*>(listener); |
195 if (!v8listener->hasExistingListenerObject()) | 64 if (!v8listener->hasExistingListenerObject()) |
196 continue; | 65 continue; |
197 listeners.append(v8listener->existingListenerObjectPersistentHandle()); | 66 |
67 v8::V8::AddImplicitReference(isolate, id, v8listener->existingListenerOb jectPersistentHandle()); | |
198 } | 68 } |
199 | |
200 if (listeners.isEmpty()) | |
201 return; | |
202 | |
203 v8::V8::AddImplicitReferences(wrapper, listeners.data(), listeners.size()); | |
204 } | 69 } |
205 | 70 |
206 Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) | 71 Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) |
207 { | 72 { |
208 // FIXME: Remove the special handling for image elements. | 73 // FIXME: Remove the special handling for image elements. |
209 // The same special handling is in V8GCController::gcTree(). | 74 // The same special handling is in V8GCController::gcTree(). |
210 // Maybe should image elements be active DOM nodes? | 75 // Maybe should image elements be active DOM nodes? |
211 // See https://code.google.com/p/chromium/issues/detail?id=164882 | 76 // See https://code.google.com/p/chromium/issues/detail?id=164882 |
212 if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && static_cas t<HTMLImageElement*>(node)->hasPendingActivity())) | 77 if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && static_cas t<HTMLImageElement*>(node)->hasPendingActivity())) |
213 return node->document(); | 78 return node->document(); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
354 | 219 |
355 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); | 220 WrapperTypeInfo* type = toWrapperTypeInfo(wrapper); |
356 void* object = toNative(wrapper); | 221 void* object = toNative(wrapper); |
357 | 222 |
358 if (V8MessagePort::info.equals(type)) { | 223 if (V8MessagePort::info.equals(type)) { |
359 // Mark each port as in-use if it's entangled. For simplicity's sake , | 224 // Mark each port as in-use if it's entangled. For simplicity's sake , |
360 // we assume all ports are remotely entangled, since the Chromium po rt | 225 // we assume all ports are remotely entangled, since the Chromium po rt |
361 // implementation can't tell the difference. | 226 // implementation can't tell the difference. |
362 MessagePort* port = static_cast<MessagePort*>(object); | 227 MessagePort* port = static_cast<MessagePort*>(object); |
363 if (port->isEntangled() || port->hasPendingActivity()) | 228 if (port->isEntangled() || port->hasPendingActivity()) |
364 m_grouper.keepAlive(wrapper); | 229 SetObjectGroupId(wrapper, *V8PerIsolateData::current()->ensureLi veRoot()); |
365 } else if (V8MutationObserver::info.equals(type)) { | 230 } else if (V8MutationObserver::info.equals(type)) { |
366 // FIXME: Allow opaqueRootForGC to operate on multiple roots and mov e this logic into V8MutationObserverCustom. | 231 // FIXME: Allow opaqueRootForGC to operate on multiple roots and mov e this logic into V8MutationObserverCustom. |
367 MutationObserver* observer = static_cast<MutationObserver*>(object); | 232 MutationObserver* observer = static_cast<MutationObserver*>(object); |
368 HashSet<Node*> observedNodes = observer->getObservedNodes(); | 233 HashSet<Node*> observedNodes = observer->getObservedNodes(); |
369 for (HashSet<Node*>::iterator it = observedNodes.begin(); it != obse rvedNodes.end(); ++it) | 234 for (HashSet<Node*>::iterator it = observedNodes.begin(); it != obse rvedNodes.end(); ++it) |
370 m_grouper.addImplicitReference(V8GCController::opaqueRootForGC(* it, m_isolate), wrapper); | 235 v8::V8::AddImplicitReference(m_isolate, v8::UniqueId(reinterpret _cast<intptr_t>(V8GCController::opaqueRootForGC(*it, m_isolate))), wrapper); |
371 } else { | 236 } else { |
372 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); | 237 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper); |
373 if (activeDOMObject && activeDOMObject->hasPendingActivity()) | 238 if (activeDOMObject && activeDOMObject->hasPendingActivity()) |
374 m_grouper.keepAlive(wrapper); | 239 SetObjectGroupId(wrapper, *V8PerIsolateData::current()->ensureLi veRoot()); |
375 } | 240 } |
376 | 241 |
377 if (classId == v8DOMNodeClassId) { | 242 if (classId == v8DOMNodeClassId) { |
378 UNUSED_PARAM(m_isolate); | 243 UNUSED_PARAM(m_isolate); |
379 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); | 244 ASSERT(V8Node::HasInstanceInAnyWorld(wrapper, m_isolate)); |
380 ASSERT(!wrapper.IsIndependent(m_isolate)); | 245 ASSERT(!wrapper.IsIndependent(m_isolate)); |
381 | 246 |
382 Node* node = static_cast<Node*>(object); | 247 Node* node = static_cast<Node*>(object); |
383 | 248 |
384 if (node->hasEventListeners()) | 249 if (node->hasEventListeners()) |
385 addImplicitReferencesForNodeWithEventListeners(node, wrapper); | 250 addImplicitReferencesForNodeWithEventListeners(m_isolate, node, wrapper); |
386 | 251 Node* root = V8GCController::opaqueRootForGC(node, m_isolate); |
387 m_grouper.addNodeWrapperToGroup(V8GCController::opaqueRootForGC(node , m_isolate), wrapper); | 252 SetObjectGroupId(wrapper, root); |
253 MaybeAddRetainedObjectInfo(root); | |
388 } else if (classId == v8DOMObjectClassId) { | 254 } else if (classId == v8DOMObjectClassId) { |
389 m_grouper.addObjectWrapperToGroup(type->opaqueRootForGC(object, wrap per, m_isolate), wrapper); | 255 void* root = type->opaqueRootForGC(object, wrapper, m_isolate); |
256 SetObjectGroupId(wrapper, root); | |
390 } else { | 257 } else { |
391 ASSERT_NOT_REACHED(); | 258 ASSERT_NOT_REACHED(); |
392 } | 259 } |
393 } | 260 } |
394 | 261 |
395 void notifyFinished() | 262 void MaybeAddRetainedObjectInfo(Node* root) |
abarth-chromium
2013/04/12 17:23:44
MaybeAddRetainedObjectInfo -> maybeAddRetainedObje
| |
396 { | 263 { |
397 m_grouper.apply(); | 264 if (root && !groups_with_retained_info_.contains(root)) { |
265 v8::V8::SetRetainedObjectInfo(m_isolate, v8::UniqueId(reinterpret_ca st<intptr_t>(root)), new RetainedDOMInfo(root)); | |
266 groups_with_retained_info_.add(root); | |
267 } | |
268 } | |
269 | |
270 void SetObjectGroupId(const v8::Persistent<v8::Object>& object, void* root) | |
abarth-chromium
2013/04/12 17:23:44
SetObjectGroupId -> setObjectGroupId
| |
271 { | |
272 v8::UniqueId id(reinterpret_cast<intptr_t>(root)); | |
273 v8::V8::SetObjectGroupId(m_isolate, object, id); | |
274 if (!groups_with_representative_objects_.contains(root)) { | |
275 v8::V8::SetObjectGroupRepresentativeObject(m_isolate, id, object); | |
276 groups_with_representative_objects_.add(root); | |
277 } | |
398 } | 278 } |
399 | 279 |
400 private: | 280 private: |
401 WrapperGrouper m_grouper; | |
402 v8::Isolate* m_isolate; | 281 v8::Isolate* m_isolate; |
282 HashSet<Node*> groups_with_retained_info_; | |
abarth-chromium
2013/04/12 17:23:44
m_groupsWithRetainedInfo
| |
283 HashSet<void*> groups_with_representative_objects_; | |
abarth-chromium
2013/04/12 17:23:44
m_groupsWithRepresentiveObjects
| |
403 }; | 284 }; |
404 | 285 |
405 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) | 286 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) |
406 { | 287 { |
407 // It would be nice if the GC callbacks passed the Isolate directly.... | 288 // It would be nice if the GC callbacks passed the Isolate directly.... |
408 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 289 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
409 if (type == v8::kGCTypeScavenge) | 290 if (type == v8::kGCTypeScavenge) |
410 minorGCPrologue(isolate); | 291 minorGCPrologue(isolate); |
411 else if (type == v8::kGCTypeMarkSweepCompact) | 292 else if (type == v8::kGCTypeMarkSweepCompact) |
412 majorGCPrologue(); | 293 majorGCPrologue(); |
(...skipping 16 matching lines...) Expand all Loading... | |
429 // Create object groups for DOM tree nodes. | 310 // Create object groups for DOM tree nodes. |
430 void V8GCController::majorGCPrologue() | 311 void V8GCController::majorGCPrologue() |
431 { | 312 { |
432 TRACE_EVENT_BEGIN0("v8", "GC"); | 313 TRACE_EVENT_BEGIN0("v8", "GC"); |
433 | 314 |
434 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 315 v8::Isolate* isolate = v8::Isolate::GetCurrent(); |
435 v8::HandleScope scope; | 316 v8::HandleScope scope; |
436 | 317 |
437 MajorGCWrapperVisitor visitor(isolate); | 318 MajorGCWrapperVisitor visitor(isolate); |
438 v8::V8::VisitHandlesWithClassIds(&visitor); | 319 v8::V8::VisitHandlesWithClassIds(&visitor); |
439 visitor.notifyFinished(); | |
440 | 320 |
441 V8PerIsolateData::from(isolate)->stringCache()->clearOnGC(); | 321 V8PerIsolateData::from(isolate)->stringCache()->clearOnGC(); |
442 } | 322 } |
443 | 323 |
444 static int workingSetEstimateMB = 0; | 324 static int workingSetEstimateMB = 0; |
445 | 325 |
446 static Mutex& workingSetEstimateMBMutex() | 326 static Mutex& workingSetEstimateMBMutex() |
447 { | 327 { |
448 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); | 328 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex); |
449 return mutex; | 329 return mutex; |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 if (!script.IsEmpty()) { | 411 if (!script.IsEmpty()) { |
532 V8RecursionScope::MicrotaskSuppression scope; | 412 V8RecursionScope::MicrotaskSuppression scope; |
533 script->Run(); | 413 script->Run(); |
534 } | 414 } |
535 } | 415 } |
536 | 416 |
537 context.clear(); | 417 context.clear(); |
538 } | 418 } |
539 | 419 |
540 } // namespace WebCore | 420 } // namespace WebCore |
OLD | NEW |