| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2009 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 #include "bindings/v8/V8GCController.h" | |
| 33 | |
| 34 #include "bindings/core/v8/V8MutationObserver.h" | |
| 35 #include "bindings/core/v8/V8Node.h" | |
| 36 #include "bindings/v8/RetainedDOMInfo.h" | |
| 37 #include "bindings/v8/V8AbstractEventListener.h" | |
| 38 #include "bindings/v8/V8Binding.h" | |
| 39 #include "bindings/v8/V8ScriptRunner.h" | |
| 40 #include "bindings/v8/WrapperTypeInfo.h" | |
| 41 #include "core/dom/Attr.h" | |
| 42 #include "core/dom/Document.h" | |
| 43 #include "core/dom/NodeTraversal.h" | |
| 44 #include "core/dom/TemplateContentDocumentFragment.h" | |
| 45 #include "core/dom/shadow/ElementShadow.h" | |
| 46 #include "core/dom/shadow/ShadowRoot.h" | |
| 47 #include "core/html/HTMLImageElement.h" | |
| 48 #include "core/html/HTMLTemplateElement.h" | |
| 49 #include "core/html/imports/HTMLImportsController.h" | |
| 50 #include "core/inspector/InspectorTraceEvents.h" | |
| 51 #include "core/svg/SVGElement.h" | |
| 52 #include "platform/Partitions.h" | |
| 53 #include "platform/TraceEvent.h" | |
| 54 #include <algorithm> | |
| 55 | |
| 56 namespace WebCore { | |
| 57 | |
| 58 // FIXME: This should use opaque GC roots. | |
| 59 static void addReferencesForNodeWithEventListeners(v8::Isolate* isolate, Node* n
ode, const v8::Persistent<v8::Object>& wrapper) | |
| 60 { | |
| 61 ASSERT(node->hasEventListeners()); | |
| 62 | |
| 63 EventListenerIterator iterator(node); | |
| 64 while (EventListener* listener = iterator.nextListener()) { | |
| 65 if (listener->type() != EventListener::JSEventListenerType) | |
| 66 continue; | |
| 67 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListene
r*>(listener); | |
| 68 if (!v8listener->hasExistingListenerObject()) | |
| 69 continue; | |
| 70 | |
| 71 isolate->SetReference(wrapper, v8::Persistent<v8::Value>::Cast(v8listene
r->existingListenerObjectPersistentHandle())); | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 Node* V8GCController::opaqueRootForGC(Node* node, v8::Isolate*) | |
| 76 { | |
| 77 ASSERT(node); | |
| 78 // FIXME: Remove the special handling for image elements. | |
| 79 // The same special handling is in V8GCController::gcTree(). | |
| 80 // Maybe should image elements be active DOM nodes? | |
| 81 // See https://code.google.com/p/chromium/issues/detail?id=164882 | |
| 82 if (node->inDocument() || (isHTMLImageElement(*node) && toHTMLImageElement(*
node).hasPendingActivity())) { | |
| 83 Document& document = node->document(); | |
| 84 if (HTMLImportsController* controller = document.importsController()) | |
| 85 return controller->master(); | |
| 86 return &document; | |
| 87 } | |
| 88 | |
| 89 if (node->isAttributeNode()) { | |
| 90 Node* ownerElement = toAttr(node)->ownerElement(); | |
| 91 if (!ownerElement) | |
| 92 return node; | |
| 93 node = ownerElement; | |
| 94 } | |
| 95 | |
| 96 while (Node* parent = node->parentOrShadowHostOrTemplateHostNode()) | |
| 97 node = parent; | |
| 98 | |
| 99 return node; | |
| 100 } | |
| 101 | |
| 102 // Regarding a minor GC algorithm for DOM nodes, see this document: | |
| 103 // https://docs.google.com/a/google.com/presentation/d/1uifwVYGNYTZDoGLyCb7sXa7g
49mWNMW2gaWvMN5NLk8/edit#slide=id.p | |
| 104 class MinorGCWrapperVisitor : public v8::PersistentHandleVisitor { | |
| 105 public: | |
| 106 explicit MinorGCWrapperVisitor(v8::Isolate* isolate) | |
| 107 : m_isolate(isolate) | |
| 108 { } | |
| 109 | |
| 110 virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_
t classId) OVERRIDE | |
| 111 { | |
| 112 // A minor DOM GC can collect only Nodes. | |
| 113 if (classId != v8DOMNodeClassId) | |
| 114 return; | |
| 115 | |
| 116 // To make minor GC cycle time bounded, we limit the number of wrappers
handled | |
| 117 // by each minor GC cycle to 10000. This value was selected so that the
minor | |
| 118 // GC cycle time is bounded to 20 ms in a case where the new space size | |
| 119 // is 16 MB and it is full of wrappers (which is almost the worst case). | |
| 120 // Practically speaking, as far as I crawled real web applications, | |
| 121 // the number of wrappers handled by each minor GC cycle is at most 3000
. | |
| 122 // So this limit is mainly for pathological micro benchmarks. | |
| 123 const unsigned wrappersHandledByEachMinorGC = 10000; | |
| 124 if (m_nodesInNewSpace.size() >= wrappersHandledByEachMinorGC) | |
| 125 return; | |
| 126 | |
| 127 // Casting to a Handle is safe here, since the Persistent doesn't get GC
d | |
| 128 // during the GC prologue. | |
| 129 ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject()); | |
| 130 v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object
>*>(value); | |
| 131 ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper)); | |
| 132 ASSERT(V8Node::hasInstance(*wrapper, m_isolate)); | |
| 133 Node* node = V8Node::toNative(*wrapper); | |
| 134 // A minor DOM GC can handle only node wrappers in the main world. | |
| 135 // Note that node->wrapper().IsEmpty() returns true for nodes that | |
| 136 // do not have wrappers in the main world. | |
| 137 if (node->containsWrapper()) { | |
| 138 const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper); | |
| 139 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper)
; | |
| 140 if (activeDOMObject && activeDOMObject->hasPendingActivity()) | |
| 141 return; | |
| 142 // FIXME: Remove the special handling for image elements. | |
| 143 // The same special handling is in V8GCController::opaqueRootForGC()
. | |
| 144 // Maybe should image elements be active DOM nodes? | |
| 145 // See https://code.google.com/p/chromium/issues/detail?id=164882 | |
| 146 if (isHTMLImageElement(*node) && toHTMLImageElement(*node).hasPendin
gActivity()) | |
| 147 return; | |
| 148 // FIXME: Remove the special handling for SVG context elements. | |
| 149 if (node->isSVGElement() && toSVGElement(node)->isContextElement()) | |
| 150 return; | |
| 151 | |
| 152 m_nodesInNewSpace.append(node); | |
| 153 node->markV8CollectableDuringMinorGC(); | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 void notifyFinished() | |
| 158 { | |
| 159 Node** nodeIterator = m_nodesInNewSpace.begin(); | |
| 160 Node** nodeIteratorEnd = m_nodesInNewSpace.end(); | |
| 161 for (; nodeIterator < nodeIteratorEnd; ++nodeIterator) { | |
| 162 Node* node = *nodeIterator; | |
| 163 ASSERT(node->containsWrapper()); | |
| 164 if (node->isV8CollectableDuringMinorGC()) { // This branch is just f
or performance. | |
| 165 gcTree(m_isolate, node); | |
| 166 node->clearV8CollectableDuringMinorGC(); | |
| 167 } | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 private: | |
| 172 bool traverseTree(Node* rootNode, Vector<Node*, initialNodeVectorSize>* part
iallyDependentNodes) | |
| 173 { | |
| 174 // To make each minor GC time bounded, we might need to give up | |
| 175 // traversing at some point for a large DOM tree. That being said, | |
| 176 // I could not observe the need even in pathological test cases. | |
| 177 for (Node* node = rootNode; node; node = NodeTraversal::next(*node)) { | |
| 178 if (node->containsWrapper()) { | |
| 179 if (!node->isV8CollectableDuringMinorGC()) { | |
| 180 // This node is not in the new space of V8. This indicates t
hat | |
| 181 // the minor GC cannot anyway judge reachability of this DOM
tree. | |
| 182 // Thus we give up traversing the DOM tree. | |
| 183 return false; | |
| 184 } | |
| 185 node->clearV8CollectableDuringMinorGC(); | |
| 186 partiallyDependentNodes->append(node); | |
| 187 } | |
| 188 if (ShadowRoot* shadowRoot = node->youngestShadowRoot()) { | |
| 189 if (!traverseTree(shadowRoot, partiallyDependentNodes)) | |
| 190 return false; | |
| 191 } else if (node->isShadowRoot()) { | |
| 192 if (ShadowRoot* shadowRoot = toShadowRoot(node)->olderShadowRoot
()) { | |
| 193 if (!traverseTree(shadowRoot, partiallyDependentNodes)) | |
| 194 return false; | |
| 195 } | |
| 196 } | |
| 197 // <template> has a |content| property holding a DOM fragment which
we must traverse, | |
| 198 // just like we do for the shadow trees above. | |
| 199 if (isHTMLTemplateElement(*node)) { | |
| 200 if (!traverseTree(toHTMLTemplateElement(*node).content(), partia
llyDependentNodes)) | |
| 201 return false; | |
| 202 } | |
| 203 | |
| 204 // Document maintains the list of imported documents through HTMLImp
ortsController. | |
| 205 if (node->isDocumentNode()) { | |
| 206 Document* document = toDocument(node); | |
| 207 HTMLImportsController* controller = document->importsController(
); | |
| 208 if (controller && document == controller->master()) { | |
| 209 for (unsigned i = 0; i < controller->loaderCount(); ++i) { | |
| 210 if (!traverseTree(controller->loaderDocumentAt(i), parti
allyDependentNodes)) | |
| 211 return false; | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 } | |
| 216 return true; | |
| 217 } | |
| 218 | |
| 219 void gcTree(v8::Isolate* isolate, Node* startNode) | |
| 220 { | |
| 221 Vector<Node*, initialNodeVectorSize> partiallyDependentNodes; | |
| 222 | |
| 223 Node* node = startNode; | |
| 224 while (Node* parent = node->parentOrShadowHostOrTemplateHostNode()) | |
| 225 node = parent; | |
| 226 | |
| 227 if (!traverseTree(node, &partiallyDependentNodes)) | |
| 228 return; | |
| 229 | |
| 230 // We completed the DOM tree traversal. All wrappers in the DOM tree are | |
| 231 // stored in partiallyDependentNodes and are expected to exist in the ne
w space of V8. | |
| 232 // We report those wrappers to V8 as an object group. | |
| 233 Node** nodeIterator = partiallyDependentNodes.begin(); | |
| 234 Node** const nodeIteratorEnd = partiallyDependentNodes.end(); | |
| 235 if (nodeIterator == nodeIteratorEnd) | |
| 236 return; | |
| 237 | |
| 238 Node* groupRoot = *nodeIterator; | |
| 239 for (; nodeIterator != nodeIteratorEnd; ++nodeIterator) { | |
| 240 (*nodeIterator)->markAsDependentGroup(groupRoot, isolate); | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 Vector<Node*> m_nodesInNewSpace; | |
| 245 v8::Isolate* m_isolate; | |
| 246 }; | |
| 247 | |
| 248 class MajorGCWrapperVisitor : public v8::PersistentHandleVisitor { | |
| 249 public: | |
| 250 explicit MajorGCWrapperVisitor(v8::Isolate* isolate, bool constructRetainedO
bjectInfos) | |
| 251 : m_isolate(isolate) | |
| 252 , m_liveRootGroupIdSet(false) | |
| 253 , m_constructRetainedObjectInfos(constructRetainedObjectInfos) | |
| 254 { | |
| 255 } | |
| 256 | |
| 257 virtual void VisitPersistentHandle(v8::Persistent<v8::Value>* value, uint16_
t classId) OVERRIDE | |
| 258 { | |
| 259 if (classId != v8DOMNodeClassId && classId != v8DOMObjectClassId) | |
| 260 return; | |
| 261 | |
| 262 // Casting to a Handle is safe here, since the Persistent doesn't get GC
d | |
| 263 // during the GC prologue. | |
| 264 ASSERT((*reinterpret_cast<v8::Handle<v8::Value>*>(value))->IsObject()); | |
| 265 v8::Handle<v8::Object>* wrapper = reinterpret_cast<v8::Handle<v8::Object
>*>(value); | |
| 266 ASSERT(V8DOMWrapper::isDOMWrapper(*wrapper)); | |
| 267 | |
| 268 if (value->IsIndependent()) | |
| 269 return; | |
| 270 | |
| 271 const WrapperTypeInfo* type = toWrapperTypeInfo(*wrapper); | |
| 272 void* object = toNative(*wrapper); | |
| 273 | |
| 274 ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(*wrapper); | |
| 275 if (activeDOMObject && activeDOMObject->hasPendingActivity()) | |
| 276 m_isolate->SetObjectGroupId(*value, liveRootId()); | |
| 277 | |
| 278 if (classId == v8DOMNodeClassId) { | |
| 279 ASSERT(V8Node::hasInstance(*wrapper, m_isolate)); | |
| 280 Node* node = static_cast<Node*>(object); | |
| 281 if (node->hasEventListeners()) | |
| 282 addReferencesForNodeWithEventListeners(m_isolate, node, v8::Pers
istent<v8::Object>::Cast(*value)); | |
| 283 Node* root = V8GCController::opaqueRootForGC(node, m_isolate); | |
| 284 m_isolate->SetObjectGroupId(*value, v8::UniqueId(reinterpret_cast<in
tptr_t>(root))); | |
| 285 if (m_constructRetainedObjectInfos) | |
| 286 m_groupsWhichNeedRetainerInfo.append(root); | |
| 287 } else if (classId == v8DOMObjectClassId) { | |
| 288 type->visitDOMWrapper(object, v8::Persistent<v8::Object>::Cast(*valu
e), m_isolate); | |
| 289 } else { | |
| 290 ASSERT_NOT_REACHED(); | |
| 291 } | |
| 292 } | |
| 293 | |
| 294 void notifyFinished() | |
| 295 { | |
| 296 if (!m_constructRetainedObjectInfos) | |
| 297 return; | |
| 298 std::sort(m_groupsWhichNeedRetainerInfo.begin(), m_groupsWhichNeedRetain
erInfo.end()); | |
| 299 Node* alreadyAdded = 0; | |
| 300 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); | |
| 301 for (size_t i = 0; i < m_groupsWhichNeedRetainerInfo.size(); ++i) { | |
| 302 Node* root = m_groupsWhichNeedRetainerInfo[i]; | |
| 303 if (root != alreadyAdded) { | |
| 304 profiler->SetRetainedObjectInfo(v8::UniqueId(reinterpret_cast<in
tptr_t>(root)), new RetainedDOMInfo(root)); | |
| 305 alreadyAdded = root; | |
| 306 } | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 private: | |
| 311 v8::UniqueId liveRootId() | |
| 312 { | |
| 313 const v8::Persistent<v8::Value>& liveRoot = V8PerIsolateData::from(m_iso
late)->ensureLiveRoot(); | |
| 314 const intptr_t* idPointer = reinterpret_cast<const intptr_t*>(&liveRoot)
; | |
| 315 v8::UniqueId id(*idPointer); | |
| 316 if (!m_liveRootGroupIdSet) { | |
| 317 m_isolate->SetObjectGroupId(liveRoot, id); | |
| 318 m_liveRootGroupIdSet = true; | |
| 319 } | |
| 320 return id; | |
| 321 } | |
| 322 | |
| 323 v8::Isolate* m_isolate; | |
| 324 Vector<Node*> m_groupsWhichNeedRetainerInfo; | |
| 325 bool m_liveRootGroupIdSet; | |
| 326 bool m_constructRetainedObjectInfos; | |
| 327 }; | |
| 328 | |
| 329 static unsigned long long usedHeapSize(v8::Isolate* isolate) | |
| 330 { | |
| 331 v8::HeapStatistics heapStatistics; | |
| 332 isolate->GetHeapStatistics(&heapStatistics); | |
| 333 return heapStatistics.used_heap_size(); | |
| 334 } | |
| 335 | |
| 336 void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags) | |
| 337 { | |
| 338 // FIXME: It would be nice if the GC callbacks passed the Isolate directly..
.. | |
| 339 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | |
| 340 TRACE_EVENT_BEGIN1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "GCEvent"
, "usedHeapSizeBefore", usedHeapSize(isolate)); | |
| 341 if (type == v8::kGCTypeScavenge) | |
| 342 minorGCPrologue(isolate); | |
| 343 else if (type == v8::kGCTypeMarkSweepCompact) | |
| 344 majorGCPrologue(flags & v8::kGCCallbackFlagConstructRetainedObjectInfos,
isolate); | |
| 345 } | |
| 346 | |
| 347 void V8GCController::minorGCPrologue(v8::Isolate* isolate) | |
| 348 { | |
| 349 TRACE_EVENT_BEGIN0("v8", "minorGC"); | |
| 350 if (isMainThread()) { | |
| 351 { | |
| 352 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "DOMMinorGC"); | |
| 353 v8::HandleScope scope(isolate); | |
| 354 MinorGCWrapperVisitor visitor(isolate); | |
| 355 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); | |
| 356 visitor.notifyFinished(); | |
| 357 } | |
| 358 V8PerIsolateData::from(isolate)->setPreviousSamplingState(TRACE_EVENT_GE
T_SAMPLING_STATE()); | |
| 359 TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8MinorGC"); | |
| 360 } | |
| 361 } | |
| 362 | |
| 363 // Create object groups for DOM tree nodes. | |
| 364 void V8GCController::majorGCPrologue(bool constructRetainedObjectInfos, v8::Isol
ate* isolate) | |
| 365 { | |
| 366 v8::HandleScope scope(isolate); | |
| 367 TRACE_EVENT_BEGIN0("v8", "majorGC"); | |
| 368 if (isMainThread()) { | |
| 369 { | |
| 370 TRACE_EVENT_SCOPED_SAMPLING_STATE("blink", "DOMMajorGC"); | |
| 371 MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos)
; | |
| 372 v8::V8::VisitHandlesWithClassIds(&visitor); | |
| 373 visitor.notifyFinished(); | |
| 374 } | |
| 375 V8PerIsolateData::from(isolate)->setPreviousSamplingState(TRACE_EVENT_GE
T_SAMPLING_STATE()); | |
| 376 TRACE_EVENT_SET_SAMPLING_STATE("v8", "V8MajorGC"); | |
| 377 } else { | |
| 378 MajorGCWrapperVisitor visitor(isolate, constructRetainedObjectInfos); | |
| 379 v8::V8::VisitHandlesWithClassIds(&visitor); | |
| 380 visitor.notifyFinished(); | |
| 381 } | |
| 382 } | |
| 383 | |
| 384 void V8GCController::gcEpilogue(v8::GCType type, v8::GCCallbackFlags flags) | |
| 385 { | |
| 386 // FIXME: It would be nice if the GC callbacks passed the Isolate directly..
.. | |
| 387 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | |
| 388 if (type == v8::kGCTypeScavenge) | |
| 389 minorGCEpilogue(isolate); | |
| 390 else if (type == v8::kGCTypeMarkSweepCompact) | |
| 391 majorGCEpilogue(isolate); | |
| 392 | |
| 393 // Forces a Blink heap garbage collection when a garbage collection | |
| 394 // was forced from V8. This is used for tests that force GCs from | |
| 395 // JavaScript to verify that objects die when expected. | |
| 396 if (flags & v8::kGCCallbackFlagForced) { | |
| 397 // This single GC is not enough for two reasons: | |
| 398 // (1) The GC is not precise because the GC scans on-stack pointers co
nservatively. | |
| 399 // (2) One GC is not enough to break a chain of persistent handles. It
's possible that | |
| 400 // some heap allocated objects own objects that contain persistent
handles | |
| 401 // pointing to other heap allocated objects. To break the chain, w
e need multiple GCs. | |
| 402 // | |
| 403 // Regarding (1), we force a precise GC at the end of the current event
loop. So if you want | |
| 404 // to collect all garbage, you need to wait until the next event loop. | |
| 405 // Regarding (2), it would be OK in practice to trigger only one GC per
gcEpilogue, because | |
| 406 // GCController.collectAll() forces 7 V8's GC. | |
| 407 Heap::collectGarbage(ThreadState::HeapPointersOnStack); | |
| 408 | |
| 409 // Forces a precise GC at the end of the current event loop. | |
| 410 Heap::setForcePreciseGCForTesting(); | |
| 411 } | |
| 412 | |
| 413 TRACE_EVENT_END1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "GCEvent",
"usedHeapSizeAfter", usedHeapSize(isolate)); | |
| 414 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Update
Counters", "data", InspectorUpdateCountersEvent::data()); | |
| 415 } | |
| 416 | |
| 417 void V8GCController::minorGCEpilogue(v8::Isolate* isolate) | |
| 418 { | |
| 419 TRACE_EVENT_END0("v8", "minorGC"); | |
| 420 if (isMainThread()) | |
| 421 TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(V8PerIsolateData::from(isolate)-
>previousSamplingState()); | |
| 422 } | |
| 423 | |
| 424 void V8GCController::majorGCEpilogue(v8::Isolate* isolate) | |
| 425 { | |
| 426 v8::HandleScope scope(isolate); | |
| 427 | |
| 428 TRACE_EVENT_END0("v8", "majorGC"); | |
| 429 if (isMainThread()) | |
| 430 TRACE_EVENT_SET_NONCONST_SAMPLING_STATE(V8PerIsolateData::from(isolate)-
>previousSamplingState()); | |
| 431 } | |
| 432 | |
| 433 void V8GCController::collectGarbage(v8::Isolate* isolate) | |
| 434 { | |
| 435 v8::HandleScope handleScope(isolate); | |
| 436 RefPtr<ScriptState> scriptState = ScriptState::create(v8::Context::New(isola
te), DOMWrapperWorld::create()); | |
| 437 ScriptState::Scope scope(scriptState.get()); | |
| 438 V8ScriptRunner::compileAndRunInternalScript(v8String(isolate, "if (gc) gc();
"), isolate); | |
| 439 scriptState->disposePerContextData(); | |
| 440 } | |
| 441 | |
| 442 void V8GCController::reportDOMMemoryUsageToV8(v8::Isolate* isolate) | |
| 443 { | |
| 444 if (!isMainThread()) | |
| 445 return; | |
| 446 | |
| 447 static size_t lastUsageReportedToV8 = 0; | |
| 448 | |
| 449 size_t currentUsage = Partitions::currentDOMMemoryUsage(); | |
| 450 int64_t diff = static_cast<int64_t>(currentUsage) - static_cast<int64_t>(las
tUsageReportedToV8); | |
| 451 isolate->AdjustAmountOfExternalAllocatedMemory(diff); | |
| 452 | |
| 453 lastUsageReportedToV8 = currentUsage; | |
| 454 } | |
| 455 | |
| 456 } // namespace WebCore | |
| OLD | NEW |