blob: f3e217993a24bf72f7d4de995106e8af55384b8d [file] [log] [blame]
abarth@webkit.org96f78d42009-07-09 00:15:34 +00001/*
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 "V8GCController.h"
33
japhet@chromium.org553f87d2010-03-12 00:03:32 +000034#include "ActiveDOMObject.h"
35#include "Attr.h"
abarth@webkit.org09eb13c2009-07-28 06:05:44 +000036#include "DOMDataStore.h"
antonm@chromium.org8675b602011-03-15 01:19:14 +000037#include "DOMImplementation.h"
japhet@chromium.org553f87d2010-03-12 00:03:32 +000038#include "HTMLImageElement.h"
39#include "HTMLNames.h"
pilgrim@chromium.org493b3b22012-04-20 23:31:23 +000040#include "MemoryUsageSupport.h"
japhet@chromium.org553f87d2010-03-12 00:03:32 +000041#include "MessagePort.h"
abarth@webkit.org1fd5b9c2011-09-01 06:23:40 +000042#include "PlatformSupport.h"
mnaganov@chromium.org82aef342011-03-16 18:46:27 +000043#include "RetainedDOMInfo.h"
44#include "RetainedObjectInfo.h"
haraken@chromium.orge61a54b2012-08-23 07:35:47 +000045#include "V8AbstractEventListener.h"
antonm@chromium.orgba29d6c2010-06-16 12:42:29 +000046#include "V8Binding.h"
antonm@chromium.org8675b602011-03-15 01:19:14 +000047#include "V8CSSRule.h"
antonm@chromium.org17227a32010-12-13 13:34:00 +000048#include "V8CSSRuleList.h"
antonm@chromium.orgec5d5612010-12-15 10:57:52 +000049#include "V8CSSStyleDeclaration.h"
antonm@chromium.org8675b602011-03-15 01:19:14 +000050#include "V8DOMImplementation.h"
japhet@chromium.org41ba8412010-03-18 16:38:57 +000051#include "V8MessagePort.h"
haraken@chromium.org7dd84952012-08-21 00:02:03 +000052#include "V8RecursionScope.h"
antonm@chromium.org8675b602011-03-15 01:19:14 +000053#include "V8StyleSheet.h"
antonm@chromium.org17227a32010-12-13 13:34:00 +000054#include "V8StyleSheetList.h"
japhet@chromium.org41ba8412010-03-18 16:38:57 +000055#include "WrapperTypeInfo.h"
abarth@webkit.org96f78d42009-07-09 00:15:34 +000056
57#include <algorithm>
58#include <utility>
abarth@webkit.org96f78d42009-07-09 00:15:34 +000059#include <v8-debug.h>
60#include <wtf/HashMap.h>
61#include <wtf/StdLibExtras.h>
62#include <wtf/UnusedParam.h>
63
nduca@chromium.org17305762012-05-26 06:39:29 +000064#if PLATFORM(CHROMIUM)
65#include "TraceEvent.h"
66#endif
67
abarth@webkit.org96f78d42009-07-09 00:15:34 +000068namespace WebCore {
69
abarth@webkit.org96f78d42009-07-09 00:15:34 +000070typedef HashMap<Node*, v8::Object*> DOMNodeMap;
71typedef HashMap<void*, v8::Object*> DOMObjectMap;
72
73#ifndef NDEBUG
74
abarth@webkit.org96f78d42009-07-09 00:15:34 +000075class DOMObjectVisitor : public DOMWrapperMap<void>::Visitor {
76public:
antonm@chromium.org17227a32010-12-13 13:34:00 +000077 void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
abarth@webkit.org96f78d42009-07-09 00:15:34 +000078 {
japhet@chromium.org51089532010-03-10 20:33:37 +000079 WrapperTypeInfo* type = V8DOMWrapper::domWrapperType(wrapper);
abarth@webkit.org96f78d42009-07-09 00:15:34 +000080 UNUSED_PARAM(type);
81 UNUSED_PARAM(object);
82 }
83};
84
85class EnsureWeakDOMNodeVisitor : public DOMWrapperMap<Node>::Visitor {
86public:
antonm@chromium.org17227a32010-12-13 13:34:00 +000087 void visitDOMWrapper(DOMDataStore* store, Node* object, v8::Persistent<v8::Object> wrapper)
abarth@webkit.org96f78d42009-07-09 00:15:34 +000088 {
89 UNUSED_PARAM(object);
90 ASSERT(wrapper.IsWeak());
91 }
92};
93
94#endif // NDEBUG
95
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +000096class SpecialCasePrologueObjectHandler {
abarth@webkit.org96f78d42009-07-09 00:15:34 +000097public:
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +000098 static bool process(void* object, v8::Persistent<v8::Object> wrapper, WrapperTypeInfo* typeInfo)
abarth@webkit.org96f78d42009-07-09 00:15:34 +000099 {
japhet@chromium.org51089532010-03-10 20:33:37 +0000100 // Additional handling of message port ensuring that entangled ports also
101 // have their wrappers entangled. This should ideally be handled when the
102 // ports are actually entangled in MessagePort::entangle, but to avoid
103 // forking MessagePort.* this is postponed to GC time. Having this postponed
104 // has the drawback that the wrappers are "entangled/unentangled" for each
105 // GC even though their entaglement most likely is still the same.
japhet@chromium.org41ba8412010-03-18 16:38:57 +0000106 if (V8MessagePort::info.equals(typeInfo)) {
japhet@chromium.org51089532010-03-10 20:33:37 +0000107 // Mark each port as in-use if it's entangled. For simplicity's sake, we assume all ports are remotely entangled,
108 // since the Chromium port implementation can't tell the difference.
109 MessagePort* port1 = static_cast<MessagePort*>(object);
110 if (port1->isEntangled() || port1->hasPendingActivity())
111 wrapper.ClearWeak();
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000112 return true;
113 }
114 return false;
115 }
116};
117
118class SpecialCasePrologueNodeHandler {
119public:
120 static bool process(Node* object, v8::Persistent<v8::Object> wrapper, WrapperTypeInfo* typeInfo)
121 {
122 UNUSED_PARAM(object);
123 UNUSED_PARAM(wrapper);
124 UNUSED_PARAM(typeInfo);
125 return false;
126 }
127};
128
129template<typename T, typename S>
130class GCPrologueVisitor : public DOMWrapperMap<T>::Visitor {
131public:
132 void visitDOMWrapper(DOMDataStore* store, T* object, v8::Persistent<v8::Object> wrapper)
133 {
134 WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);
135
136 if (!S::process(object, wrapper, typeInfo)) {
japhet@chromium.org51089532010-03-10 20:33:37 +0000137 ActiveDOMObject* activeDOMObject = typeInfo->toActiveDOMObject(wrapper);
138 if (activeDOMObject && activeDOMObject->hasPendingActivity())
139 wrapper.ClearWeak();
140 }
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000141 }
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000142};
143
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000144// Implements v8::RetainedObjectInfo.
145class UnspecifiedGroup : public RetainedObjectInfo {
146public:
147 explicit UnspecifiedGroup(void* object)
148 : m_object(object)
149 {
150 ASSERT(m_object);
151 }
152
153 virtual void Dispose() { delete this; }
154
155 virtual bool IsEquivalent(v8::RetainedObjectInfo* other)
156 {
157 ASSERT(other);
158 return other == this || static_cast<WebCore::RetainedObjectInfo*>(other)->GetEquivalenceClass() == this->GetEquivalenceClass();
159 }
160
161 virtual intptr_t GetHash()
162 {
loislo@chromium.orgd4c26672012-03-08 13:24:28 +0000163 return PtrHash<void*>::hash(m_object);
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000164 }
165
166 virtual const char* GetLabel()
167 {
168 return "Object group";
169 }
170
171 virtual intptr_t GetEquivalenceClass()
172 {
173 return reinterpret_cast<intptr_t>(m_object);
174 }
175
176private:
177 void* m_object;
178};
179
180class GroupId {
181public:
182 GroupId() : m_type(NullType), m_groupId(0) {}
183 GroupId(Node* node) : m_type(NodeType), m_node(node) {}
184 GroupId(void* other) : m_type(OtherType), m_other(other) {}
185 bool operator!() const { return m_type == NullType; }
186 uintptr_t groupId() const { return m_groupId; }
187 RetainedObjectInfo* createRetainedObjectInfo() const
188 {
189 switch (m_type) {
190 case NullType:
191 return 0;
192 case NodeType:
193 return new RetainedDOMInfo(m_node);
194 case OtherType:
195 return new UnspecifiedGroup(m_other);
196 default:
197 return 0;
198 }
199 }
200
201private:
202 enum Type {
203 NullType,
204 NodeType,
205 OtherType
206 };
207 Type m_type;
208 union {
209 uintptr_t m_groupId;
210 Node* m_node;
211 void* m_other;
212 };
213};
214
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000215class GrouperItem {
216public:
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000217 GrouperItem(GroupId groupId, v8::Persistent<v8::Object> wrapper) : m_groupId(groupId), m_wrapper(wrapper) {}
218 uintptr_t groupId() const { return m_groupId.groupId(); }
219 RetainedObjectInfo* createRetainedObjectInfo() const { return m_groupId.createRetainedObjectInfo(); }
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000220 v8::Persistent<v8::Object> wrapper() const { return m_wrapper; }
221
222private:
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000223 GroupId m_groupId;
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000224 v8::Persistent<v8::Object> m_wrapper;
225};
226
227bool operator<(const GrouperItem& a, const GrouperItem& b)
228{
229 return a.groupId() < b.groupId();
230}
231
levin@chromium.org1c936dd2011-03-16 21:16:53 +0000232typedef Vector<GrouperItem> GrouperList;
233
antonm@chromium.org8675b602011-03-15 01:19:14 +0000234// If the node is in document, put it in the ownerDocument's object group.
235//
236// If an image element was created by JavaScript "new Image",
237// it is not in a document. However, if the load event has not
238// been fired (still onloading), it is treated as in the document.
239//
240// Otherwise, the node is put in an object group identified by the root
241// element of the tree to which it belongs.
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000242static GroupId calculateGroupId(Node* node)
antonm@chromium.org9765f572010-12-08 06:45:55 +0000243{
commit-queue@webkit.orgdbef5a52012-09-17 09:05:13 +0000244 if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity()))
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000245 return GroupId(node->document());
antonm@chromium.org9765f572010-12-08 06:45:55 +0000246
antonm@chromium.org8675b602011-03-15 01:19:14 +0000247 Node* root = node;
248 if (node->isAttributeNode()) {
249 root = static_cast<Attr*>(node)->ownerElement();
250 // If the attribute has no element, no need to put it in the group,
251 // because it'll always be a group of 1.
252 if (!root)
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000253 return GroupId();
antonm@chromium.org9765f572010-12-08 06:45:55 +0000254 }
dominicc@chromium.org3ff8da42012-06-01 06:37:02 +0000255 while (Node* parent = root->parentOrHostNode())
256 root = parent;
antonm@chromium.org8675b602011-03-15 01:19:14 +0000257
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000258 return GroupId(root);
antonm@chromium.org9765f572010-12-08 06:45:55 +0000259}
260
antonm@chromium.org8675b602011-03-15 01:19:14 +0000261class GrouperVisitor : public DOMWrapperMap<Node>::Visitor, public DOMWrapperMap<void>::Visitor {
antonm@chromium.org9765f572010-12-08 06:45:55 +0000262public:
antonm@chromium.org8675b602011-03-15 01:19:14 +0000263 void visitDOMWrapper(DOMDataStore* store, Node* node, v8::Persistent<v8::Object> wrapper)
antonm@chromium.org9765f572010-12-08 06:45:55 +0000264 {
vitalyr@chromium.org7f698662011-04-23 07:11:38 +0000265 if (node->hasEventListeners()) {
266 Vector<v8::Persistent<v8::Value> > listeners;
267 EventListenerIterator iterator(node);
268 while (EventListener* listener = iterator.nextListener()) {
269 if (listener->type() != EventListener::JSEventListenerType)
270 continue;
271 V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener);
272 if (!v8listener->hasExistingListenerObject())
273 continue;
274 listeners.append(v8listener->existingListenerObjectPersistentHandle());
275 }
276 if (!listeners.isEmpty())
277 v8::V8::AddImplicitReferences(wrapper, listeners.data(), listeners.size());
278 }
279
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000280 GroupId groupId = calculateGroupId(node);
antonm@chromium.org8675b602011-03-15 01:19:14 +0000281 if (!groupId)
282 return;
283 m_grouper.append(GrouperItem(groupId, wrapper));
antonm@chromium.org9765f572010-12-08 06:45:55 +0000284 }
285
antonm@chromium.org17227a32010-12-13 13:34:00 +0000286 void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
antonm@chromium.org9765f572010-12-08 06:45:55 +0000287 {
arv@chromium.orgad0ca0a2012-06-21 22:34:26 +0000288 WrapperTypeInfo* info = V8DOMWrapper::domWrapperType(wrapper);
arv@chromium.org37ad6212012-06-22 18:55:02 +0000289 info->visitDOMWrapper(store, object, wrapper);
antonm@chromium.org8675b602011-03-15 01:19:14 +0000290 }
291
292 void applyGrouping()
293 {
294 // Group by sorting by the group id.
295 std::sort(m_grouper.begin(), m_grouper.end());
296
297 for (size_t i = 0; i < m_grouper.size(); ) {
298 // Seek to the next key (or the end of the list).
299 size_t nextKeyIndex = m_grouper.size();
300 for (size_t j = i; j < m_grouper.size(); ++j) {
301 if (m_grouper[i].groupId() != m_grouper[j].groupId()) {
302 nextKeyIndex = j;
303 break;
antonm@chromium.orgec5d5612010-12-15 10:57:52 +0000304 }
305 }
antonm@chromium.org8675b602011-03-15 01:19:14 +0000306
307 ASSERT(nextKeyIndex > i);
308
309 // We only care about a group if it has more than one object. If it only
310 // has one object, it has nothing else that needs to be kept alive.
311 if (nextKeyIndex - i <= 1) {
312 i = nextKeyIndex;
313 continue;
314 }
315
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000316 size_t rootIndex = i;
317
antonm@chromium.org8675b602011-03-15 01:19:14 +0000318 Vector<v8::Persistent<v8::Value> > group;
319 group.reserveCapacity(nextKeyIndex - i);
320 for (; i < nextKeyIndex; ++i) {
321 v8::Persistent<v8::Value> wrapper = m_grouper[i].wrapper();
322 if (!wrapper.IsEmpty())
323 group.append(wrapper);
324 }
325
326 if (group.size() > 1)
mnaganov@chromium.org82aef342011-03-16 18:46:27 +0000327 v8::V8::AddObjectGroup(&group[0], group.size(), m_grouper[rootIndex].createRetainedObjectInfo());
antonm@chromium.org8675b602011-03-15 01:19:14 +0000328
329 ASSERT(i == nextKeyIndex);
antonm@chromium.org9765f572010-12-08 06:45:55 +0000330 }
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000331 }
332
333private:
334 GrouperList m_grouper;
335};
336
337// Create object groups for DOM tree nodes.
338void V8GCController::gcPrologue()
339{
340 v8::HandleScope scope;
341
nduca@chromium.org17305762012-05-26 06:39:29 +0000342#if PLATFORM(CHROMIUM)
343 TRACE_EVENT_BEGIN0("v8", "GC");
344#endif
345
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000346#ifndef NDEBUG
347 DOMObjectVisitor domObjectVisitor;
commit-queue@webkit.org9a6e3262011-06-08 17:31:03 +0000348 visitDOMObjects(&domObjectVisitor);
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000349#endif
350
351 // Run through all objects with possible pending activity making their
352 // wrappers non weak if there is pending activity.
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000353 GCPrologueVisitor<void, SpecialCasePrologueObjectHandler> prologueObjectVisitor;
354 visitActiveDOMObjects(&prologueObjectVisitor);
355 GCPrologueVisitor<Node, SpecialCasePrologueNodeHandler> prologueNodeVisitor;
356 visitActiveDOMNodes(&prologueNodeVisitor);
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000357
358 // Create object groups.
antonm@chromium.org8675b602011-03-15 01:19:14 +0000359 GrouperVisitor grouperVisitor;
commit-queue@webkit.org9a6e3262011-06-08 17:31:03 +0000360 visitDOMNodes(&grouperVisitor);
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000361 visitActiveDOMNodes(&grouperVisitor);
commit-queue@webkit.org9a6e3262011-06-08 17:31:03 +0000362 visitDOMObjects(&grouperVisitor);
antonm@chromium.org8675b602011-03-15 01:19:14 +0000363 grouperVisitor.applyGrouping();
antonm@chromium.orgba29d6c2010-06-16 12:42:29 +0000364
365 // Clean single element cache for string conversions.
haraken@chromium.org096be7a2012-08-09 22:52:17 +0000366 V8PerIsolateData* data = V8PerIsolateData::current();
commit-queue@webkit.org5a71da32011-06-21 23:09:15 +0000367 data->stringCache()->clearOnGC();
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000368}
369
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000370class SpecialCaseEpilogueObjectHandler {
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000371public:
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000372 static bool process(void* object, v8::Persistent<v8::Object> wrapper, WrapperTypeInfo* typeInfo)
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000373 {
japhet@chromium.org41ba8412010-03-18 16:38:57 +0000374 if (V8MessagePort::info.equals(typeInfo)) {
abarth@webkit.orgd575beb2009-08-01 07:37:15 +0000375 MessagePort* port1 = static_cast<MessagePort*>(object);
eric@webkit.orgea9b2c62009-11-25 20:04:19 +0000376 // We marked this port as reachable in GCPrologueVisitor. Undo this now since the
377 // port could be not reachable in the future if it gets disentangled (and also
378 // GCPrologueVisitor expects to see all handles marked as weak).
japhet@chromium.org51089532010-03-10 20:33:37 +0000379 if ((!wrapper.IsWeak() && !wrapper.IsNearDeath()) || port1->hasPendingActivity())
abarth@webkit.orgd575beb2009-08-01 07:37:15 +0000380 wrapper.MakeWeak(port1, &DOMDataStore::weakActiveDOMObjectCallback);
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000381 return true;
382 }
383 return false;
384 }
385};
386
387class SpecialCaseEpilogueNodeHandler {
388public:
389 static bool process(Node* object, v8::Persistent<v8::Object> wrapper, WrapperTypeInfo* typeInfo)
390 {
391 UNUSED_PARAM(object);
392 UNUSED_PARAM(wrapper);
393 UNUSED_PARAM(typeInfo);
394 return false;
395 }
396};
397
398template<typename T, typename S, v8::WeakReferenceCallback callback>
399class GCEpilogueVisitor : public DOMWrapperMap<T>::Visitor {
400public:
401 void visitDOMWrapper(DOMDataStore* store, T* object, v8::Persistent<v8::Object> wrapper)
402 {
403 WrapperTypeInfo* typeInfo = V8DOMWrapper::domWrapperType(wrapper);
404 if (!S::process(object, wrapper, typeInfo)) {
japhet@chromium.org51089532010-03-10 20:33:37 +0000405 ActiveDOMObject* activeDOMObject = typeInfo->toActiveDOMObject(wrapper);
406 if (activeDOMObject && activeDOMObject->hasPendingActivity()) {
407 ASSERT(!wrapper.IsWeak());
vitalyr@chromium.org77830a32010-04-27 17:58:56 +0000408 // NOTE: To re-enable weak status of the active object we use
409 // |object| from the map and not |activeDOMObject|. The latter
410 // may be a different pointer (in case ActiveDOMObject is not
411 // the main base class of the object's class) and pointer
412 // identity is required by DOM map functions.
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000413 wrapper.MakeWeak(object, callback);
japhet@chromium.org51089532010-03-10 20:33:37 +0000414 }
abarth@webkit.orgd575beb2009-08-01 07:37:15 +0000415 }
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000416 }
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000417};
418
dimich@chromium.org3bda7d42012-09-13 00:43:18 +0000419#if PLATFORM(CHROMIUM)
420static int workingSetEstimateMB = 0;
421
422static Mutex& workingSetEstimateMBMutex()
423{
424 AtomicallyInitializedStatic(Mutex&, mutex = *new Mutex);
425 return mutex;
426}
427#endif
eric@webkit.org9f6b9212009-11-10 20:00:33 +0000428
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000429void V8GCController::gcEpilogue()
430{
431 v8::HandleScope scope;
432
433 // Run through all objects with pending activity making their wrappers weak
434 // again.
commit-queue@webkit.orgc38ddde2011-11-15 20:13:53 +0000435 GCEpilogueVisitor<void, SpecialCaseEpilogueObjectHandler, &DOMDataStore::weakActiveDOMObjectCallback> epilogueObjectVisitor;
436 visitActiveDOMObjects(&epilogueObjectVisitor);
437 GCEpilogueVisitor<Node, SpecialCaseEpilogueNodeHandler, &DOMDataStore::weakNodeCallback> epilogueNodeVisitor;
438 visitActiveDOMNodes(&epilogueNodeVisitor);
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000439
dimich@chromium.org3bda7d42012-09-13 00:43:18 +0000440#if PLATFORM(CHROMIUM)
441 // The GC can happen on multiple threads in case of dedicated workers which run in-process.
442 {
443 MutexLocker locker(workingSetEstimateMBMutex());
444 workingSetEstimateMB = MemoryUsageSupport::actualMemoryUsageMB();
445 }
446#endif
eric@webkit.org9f6b9212009-11-10 20:00:33 +0000447
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000448#ifndef NDEBUG
449 // Check all survivals are weak.
450 DOMObjectVisitor domObjectVisitor;
commit-queue@webkit.org9a6e3262011-06-08 17:31:03 +0000451 visitDOMObjects(&domObjectVisitor);
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000452
453 EnsureWeakDOMNodeVisitor weakDOMNodeVisitor;
commit-queue@webkit.org9a6e3262011-06-08 17:31:03 +0000454 visitDOMNodes(&weakDOMNodeVisitor);
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000455#endif
nduca@chromium.org17305762012-05-26 06:39:29 +0000456
457#if PLATFORM(CHROMIUM)
458 TRACE_EVENT_END0("v8", "GC");
459#endif
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000460}
461
eric@webkit.org9f6b9212009-11-10 20:00:33 +0000462void V8GCController::checkMemoryUsage()
463{
commit-queue@webkit.orga37d9a4f2012-07-17 14:51:54 +0000464#if PLATFORM(CHROMIUM)
pilgrim@chromium.org051881b2012-04-28 00:34:57 +0000465 const int lowMemoryUsageMB = MemoryUsageSupport::lowMemoryUsageMB();
pilgrim@chromium.orgbbc511a2012-04-28 03:56:53 +0000466 const int highMemoryUsageMB = MemoryUsageSupport::highMemoryUsageMB();
pilgrim@chromium.org36e49c42012-04-29 08:58:05 +0000467 const int highUsageDeltaMB = MemoryUsageSupport::highUsageDeltaMB();
allan.jensen@nokia.comb619bbf22012-07-12 15:34:35 +0000468 int memoryUsageMB = MemoryUsageSupport::memoryUsageMB();
dimich@chromium.org3bda7d42012-09-13 00:43:18 +0000469 int workingSetEstimateMBCopy;
470 {
471 MutexLocker locker(workingSetEstimateMBMutex());
472 workingSetEstimateMBCopy = workingSetEstimateMB;
473 }
474
475 if ((memoryUsageMB > lowMemoryUsageMB && memoryUsageMB > 2 * workingSetEstimateMBCopy) || (memoryUsageMB > highMemoryUsageMB && memoryUsageMB > workingSetEstimateMBCopy + highUsageDeltaMB))
eric@webkit.org9f6b9212009-11-10 20:00:33 +0000476 v8::V8::LowMemoryNotification();
commit-queue@webkit.org990d1642011-11-24 03:24:26 +0000477#endif
eric@webkit.org9f6b9212009-11-10 20:00:33 +0000478}
479
haraken@chromium.orgc0971832012-08-21 02:47:21 +0000480void V8GCController::hintForCollectGarbage()
haraken@chromium.org9d61b0b2012-08-14 01:32:08 +0000481{
482 V8PerIsolateData* data = V8PerIsolateData::current();
483 if (!data->shouldCollectGarbageSoon())
484 return;
485 const int longIdlePauseInMS = 1000;
486 data->clearShouldCollectGarbageSoon();
487 v8::V8::ContextDisposedNotification();
488 v8::V8::IdleNotification(longIdlePauseInMS);
489}
eric@webkit.org9f6b9212009-11-10 20:00:33 +0000490
haraken@chromium.org7dd84952012-08-21 00:02:03 +0000491void V8GCController::collectGarbage()
492{
493 v8::HandleScope handleScope;
494
commit-queue@webkit.org7078bcd2012-09-11 01:22:17 +0000495 ScopedPersistent<v8::Context> context;
496
497 context.adopt(v8::Context::New());
498 if (context.isEmpty())
haraken@chromium.org7dd84952012-08-21 00:02:03 +0000499 return;
commit-queue@webkit.org7078bcd2012-09-11 01:22:17 +0000500
haraken@chromium.org7dd84952012-08-21 00:02:03 +0000501 {
commit-queue@webkit.org7078bcd2012-09-11 01:22:17 +0000502 v8::Context::Scope scope(context.get());
haraken@chromium.org7dd84952012-08-21 00:02:03 +0000503 v8::Local<v8::String> source = v8::String::New("if (gc) gc();");
504 v8::Local<v8::String> name = v8::String::New("gc");
505 v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
506 if (!script.IsEmpty()) {
507 V8RecursionScope::MicrotaskSuppression scope;
508 script->Run();
509 }
510 }
commit-queue@webkit.org7078bcd2012-09-11 01:22:17 +0000511
512 context.clear();
haraken@chromium.org7dd84952012-08-21 00:02:03 +0000513}
514
abarth@webkit.org96f78d42009-07-09 00:15:34 +0000515} // namespace WebCore