Changeset 141548 in webkit
- Timestamp:
- Feb 1, 2013 12:27:10 AM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r141547 r141548 1 2013-02-01 Kentaro Hara <haraken@chromium.org> 2 3 [V8] Remove V8GCController::m_edenNodes 4 https://bugs.webkit.org/show_bug.cgi?id=108579 5 6 Reviewed by Adam Barth. 7 8 Currently V8GCController::m_edenNodes stores a list of nodes whose 9 wrappers have been created since the latest GC. The reason why we 10 needed m_edenNodes is that there was no way to know a list of wrappers 11 in the new space of V8. By using m_edenNodes, we had been approximating 12 'wrappers in the new space' by 'wrappers that have been created since 13 the latest GC'. 14 15 Now V8 provides VisitHandlesForPartialDependence(), with which WebKit 16 can know a list of wrappers in the new space. By using the API, we can 17 remove V8GCController::m_edenNodes. The benefit is that (1) we no longer 18 need to keep m_edenNodes and that (2) it enables more precise minor 19 DOM GC (Remember that m_edenNodes was just an approximation). 20 21 Performance benchmark: https://bugs.webkit.org/attachment.cgi?id=185940 22 The benchmark runs 300 iterations, each of which creates 100000 elements. 23 The benchmark measures average, min, median, max and stdev of execution times 24 of the 300 iterations. This will tell us the worst-case overhead of this change. 25 26 Before: 27 mean=59.91ms, min=39ms, median=42ms, max=258ms, stdev=47.48ms 28 29 After: 30 mean=58.75ms, min=35ms, median=41ms, max=250ms, stdev=47.32ms 31 32 As shown above, I couldn't observe any performance regression. 33 34 No tests. No change in behavior. 35 36 * bindings/v8/DOMDataStore.h: 37 (WebCore::DOMDataStore::setWrapperInObject): 38 * bindings/v8/V8GCController.cpp: 39 (WebCore::gcTree): 40 (WebCore): 41 (MinorGCWrapperVisitor): 42 (WebCore::MinorGCWrapperVisitor::notifyFinished): 43 (WebCore::V8GCController::gcPrologue): 44 (WebCore::V8GCController::minorGCPrologue): 45 (WebCore::V8GCController::majorGCPrologue): 46 * bindings/v8/V8GCController.h: 47 (V8GCController): 48 1 49 2013-02-01 Vsevolod Vlasov <vsevik@chromium.org> 2 50 -
trunk/Source/WebCore/bindings/v8/DOMDataStore.h
r139458 r141548 165 165 wrapper.MakeWeak(object, weakCallback); 166 166 } 167 static void setWrapperInObject(Node* object, v8::Persistent<v8::Object> wrapper)168 {169 ASSERT(object->wrapper().IsEmpty());170 object->setWrapper(wrapper);171 V8GCController::didCreateWrapperForNode(object);172 wrapper.MakeWeak(static_cast<ScriptWrappable*>(object), weakCallback);173 }174 167 175 168 static void weakCallback(v8::Persistent<v8::Value>, void* context); -
trunk/Source/WebCore/bindings/v8/V8GCController.cpp
r141524 r141548 179 179 } 180 180 181 class WrapperVisitor : public v8::PersistentHandleVisitor { 181 static void gcTree(Node* startNode) 182 { 183 Vector<v8::Persistent<v8::Value>, initialNodeVectorSize> newSpaceWrappers; 184 185 // We traverse a DOM tree in the DFS order starting from startNode. 186 // The traversal order does not matter for correctness but does matter for performance. 187 Node* node = startNode; 188 // To make each minor GC time bounded, we might need to give up 189 // traversing at some point for a large DOM tree. That being said, 190 // I could not observe the need even in pathological test cases. 191 do { 192 ASSERT(node); 193 if (!node->wrapper().IsEmpty()) { 194 // FIXME: Remove the special handling for image elements. 195 // The same special handling is in V8GCController::opaqueRootForGC(). 196 // Maybe should image elements be active DOM nodes? 197 // See https://code.google.com/p/chromium/issues/detail?id=164882 198 if (!node->isV8CollectableDuringMinorGC() || (node->hasTagName(HTMLNames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity())) { 199 // This node is not in the new space of V8. This indicates that 200 // the minor GC cannot anyway judge reachability of this DOM tree. 201 // Thus we give up traversing the DOM tree. 202 return; 203 } 204 node->setV8CollectableDuringMinorGC(false); 205 newSpaceWrappers.append(node->wrapper()); 206 } 207 if (node->firstChild()) { 208 node = node->firstChild(); 209 continue; 210 } 211 while (!node->nextSibling()) { 212 if (!node->parentNode()) 213 break; 214 node = node->parentNode(); 215 } 216 if (node->parentNode()) 217 node = node->nextSibling(); 218 } while (node != startNode); 219 220 // We completed the DOM tree traversal. All wrappers in the DOM tree are 221 // stored in newSpaceWrappers and are expected to exist in the new space of V8. 222 // We report those wrappers to V8 as an object group. 223 for (size_t i = 0; i < newSpaceWrappers.size(); i++) 224 newSpaceWrappers[i].MarkPartiallyDependent(); 225 if (newSpaceWrappers.size() > 0) 226 v8::V8::AddObjectGroup(&newSpaceWrappers[0], newSpaceWrappers.size()); 227 } 228 229 // Regarding a minor GC algorithm for DOM nodes, see this document: 230 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g49mWNMW2gaWvMN5NLk8/edit#slide=id.p 231 class MinorGCWrapperVisitor : public v8::PersistentHandleVisitor { 232 public: 233 virtual void VisitPersistentHandle(v8::Persistent<v8::Value> value, uint16_t classId) OVERRIDE 234 { 235 // A minor DOM GC can collect only Nodes. 236 if (classId != v8DOMNodeClassId) 237 return; 238 239 // To make minor GC cycle time bounded, we limit the number of wrappers handled 240 // by each minor GC cycle to 10000. This value was selected so that the minor 241 // GC cycle time is bounded to 20 ms in a case where the new space size 242 // is 16 MB and it is full of wrappers (which is almost the worst case). 243 // Practically speaking, as far as I crawled real web applications, 244 // the number of wrappers handled by each minor GC cycle is at most 3000. 245 // So this limit is mainly for pathological micro benchmarks. 246 const unsigned wrappersHandledByEachMinorGC = 10000; 247 if (m_nodesInNewSpace.size() >= wrappersHandledByEachMinorGC) 248 return; 249 250 ASSERT(value->IsObject()); 251 v8::Persistent<v8::Object> wrapper = v8::Persistent<v8::Object>::Cast(value); 252 ASSERT(V8DOMWrapper::maybeDOMWrapper(value)); 253 ASSERT(V8Node::HasInstance(wrapper)); 254 Node* node = V8Node::toNative(wrapper); 255 m_nodesInNewSpace.append(node); 256 node->setV8CollectableDuringMinorGC(true); 257 } 258 259 void notifyFinished() 260 { 261 for (size_t i = 0; i < m_nodesInNewSpace.size(); i++) { 262 ASSERT(!m_nodesInNewSpace[i]->wrapper().IsEmpty()); 263 if (m_nodesInNewSpace[i]->isV8CollectableDuringMinorGC()) // This branch is just for performance. 264 gcTree(m_nodesInNewSpace[i]); 265 } 266 } 267 268 private: 269 Vector<Node*> m_nodesInNewSpace; 270 }; 271 272 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { 182 273 public: 183 274 virtual void VisitPersistentHandle(v8::Persistent<v8::Value> value, uint16_t classId) OVERRIDE … … 242 333 }; 243 334 244 // Regarding a minor GC algorithm for DOM nodes, see this document:245 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g49mWNMW2gaWvMN5NLk8/edit#slide=id.p246 //247 // m_edenNodes stores nodes that have wrappers that have been created since the last minor/major GC.248 Vector<Node*>* V8GCController::m_edenNodes = 0;249 250 static void gcTree(Node* startNode)251 {252 Vector<v8::Persistent<v8::Value>, initialNodeVectorSize> newSpaceWrappers;253 254 // We traverse a DOM tree in the DFS order starting from startNode.255 // The traversal order does not matter for correctness but does matter for performance.256 Node* node = startNode;257 // To make each minor GC time bounded, we might need to give up258 // traversing at some point for a large DOM tree. That being said,259 // I could not observe the need even in pathological test cases.260 do {261 ASSERT(node);262 if (!node->wrapper().IsEmpty()) {263 // FIXME: Remove the special handling for image elements.264 // The same special handling is in V8GCController::opaqueRootForGC().265 // Maybe should image elements be active DOM nodes?266 // See https://code.google.com/p/chromium/issues/detail?id=164882267 if (!node->isV8CollectableDuringMinorGC() || (node->hasTagName(HTMLNames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity())) {268 // The fact that we encounter a node that is not in the Eden space269 // implies that its wrapper might be in the old space of V8.270 // This indicates that the minor GC cannot anyway judge reachability271 // of this DOM tree. Thus we give up traversing the DOM tree.272 return;273 }274 // A once traversed node is removed from the Eden space.275 node->setV8CollectableDuringMinorGC(false);276 newSpaceWrappers.append(node->wrapper());277 }278 if (node->firstChild()) {279 node = node->firstChild();280 continue;281 }282 while (!node->nextSibling()) {283 if (!node->parentNode())284 break;285 node = node->parentNode();286 }287 if (node->parentNode())288 node = node->nextSibling();289 } while (node != startNode);290 291 // We completed the DOM tree traversal. All wrappers in the DOM tree are292 // stored in newSpaceWrappers and are expected to exist in the new space of V8.293 // We report those wrappers to V8 as an object group.294 for (size_t i = 0; i < newSpaceWrappers.size(); i++)295 newSpaceWrappers[i].MarkPartiallyDependent();296 if (newSpaceWrappers.size() > 0)297 v8::V8::AddObjectGroup(&newSpaceWrappers[0], newSpaceWrappers.size());298 }299 300 void V8GCController::didCreateWrapperForNode(Node* node)301 {302 // To make minor GC cycle time bounded, we limit the number of wrappers handled303 // by each minor GC cycle to 10000. This value was selected so that the minor304 // GC cycle time is bounded to 20 ms in a case where the new space size305 // is 16 MB and it is full of wrappers (which is almost the worst case).306 // Practically speaking, as far as I crawled real web applications,307 // the number of wrappers handled by each minor GC cycle is at most 3000.308 // So this limit is mainly for pathological micro benchmarks.309 const unsigned wrappersHandledByEachMinorGC = 10000;310 ASSERT(!node->wrapper().IsEmpty());311 if (!m_edenNodes)312 m_edenNodes = adoptPtr(new Vector<Node*>).leakPtr();313 if (m_edenNodes->size() <= wrappersHandledByEachMinorGC) {314 // A node of a newly created wrapper is put into the Eden space.315 m_edenNodes->append(node);316 node->setV8CollectableDuringMinorGC(true);317 }318 }319 320 335 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) 321 336 { … … 324 339 else if (type == v8::kGCTypeMarkSweepCompact) 325 340 majorGCPrologue(); 326 327 if (isMainThreadOrGCThread() && m_edenNodes) {328 // The Eden space is cleared at every minor/major GC.329 m_edenNodes->clear();330 }331 341 } 332 342 … … 335 345 TRACE_EVENT_BEGIN0("v8", "GC"); 336 346 337 if (isMainThreadOrGCThread() && m_edenNodes) { 338 for (size_t i = 0; i < m_edenNodes->size(); i++) { 339 ASSERT(!m_edenNodes->at(i)->wrapper().IsEmpty()); 340 if (m_edenNodes->at(i)->isV8CollectableDuringMinorGC()) // This branch is just for performance. 341 gcTree(m_edenNodes->at(i)); 342 } 343 } 347 v8::HandleScope scope; 348 349 MinorGCWrapperVisitor visitor; 350 v8::V8::VisitHandlesForPartialDependence(v8::Isolate::GetCurrent(), &visitor); 351 visitor.notifyFinished(); 344 352 } 345 353 … … 351 359 v8::HandleScope scope; 352 360 353 WrapperVisitor visitor;361 MajorGCWrapperVisitor visitor; 354 362 v8::V8::VisitHandlesWithClassIds(&visitor); 355 363 visitor.notifyFinished(); -
trunk/Source/WebCore/bindings/v8/V8GCController.h
r140949 r141548 53 53 54 54 static Node* opaqueRootForGC(Node*); 55 static void didCreateWrapperForNode(Node*);56 55 57 56 private:
Note: See TracChangeset
for help on using the changeset viewer.