 Chromium Code Reviews
 Chromium Code Reviews Issue 13975005:
  Update V8GCController to use new V8 GC-related APIs.  (Closed) 
  Base URL: svn://svn.chromium.org/blink/trunk
    
  
    Issue 13975005:
  Update V8GCController to use new V8 GC-related APIs.  (Closed) 
  Base URL: svn://svn.chromium.org/blink/trunk| 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 |