2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
34 #include "DOMObjectsInclude.h"
38 #include <wtf/HashMap.h>
39 #include <wtf/MainThread.h>
40 #include <wtf/Noncopyable.h>
41 #include <wtf/StdLibExtras.h>
42 #include <wtf/Threading.h>
43 #include <wtf/ThreadSpecific.h>
44 #include <wtf/Vector.h>
46 #include "V8IsolatedWorld.h"
50 // DOM binding algorithm:
52 // There are two kinds of DOM objects:
53 // 1. DOM tree nodes, such as Document, HTMLElement, ...
54 // there classes implement TreeShared<T> interface;
55 // 2. Non-node DOM objects, such as CSSRule, Location, etc.
56 // these classes implement a ref-counted scheme.
58 // A DOM object may have a JS wrapper object. If a tree node
59 // is alive, its JS wrapper must be kept alive even it is not
60 // reachable from JS roots.
61 // However, JS wrappers of non-node objects can go away if
62 // not reachable from other JS objects. It works like a cache.
64 // DOM objects are ref-counted, and JS objects are traced from
65 // a set of root objects. They can create a cycle. To break
66 // cycles, we do following:
67 // Handles from DOM objects to JS wrappers are always weak,
68 // so JS wrappers of non-node object cannot create a cycle.
69 // Before starting a global GC, we create a virtual connection
70 // between nodes in the same tree in the JS heap. If the wrapper
71 // of one node in a tree is alive, wrappers of all nodes in
72 // the same tree are considered alive. This is done by creating
73 // object groups in GC prologue callbacks. The mark-compact
74 // collector will remove these groups after each GC.
76 // DOM objects should be deref-ed from the owning thread, not the GC thread
77 // that does not own them. In V8, GC can kick in from any thread. To ensure
78 // that DOM objects are always deref-ed from the owning thread when running
79 // V8 in multi-threading environment, we do following:
80 // 1. Maintain a thread specific DOM wrapper map for each object map.
81 // (We're using TLS support from WTF instead of base since V8Bindings
82 // does not depend on base. We further assume that all child threads
83 // running V8 instances are created by WTF and thus a destructor will
84 // be called to clean up all thread specific data.)
85 // 2. When GC happens:
86 // 2.1. If the dead object is in GC thread's map, remove the JS reference
87 // and deref the DOM object.
88 // 2.2. Otherwise, go through all thread maps to find the owning thread.
89 // Remove the JS reference from the owning thread's map and move the
90 // DOM object to a delayed queue. Post a task to the owning thread
91 // to have it deref-ed from the owning thread at later time.
92 // 3. When a thread is tearing down, invoke a cleanup routine to go through
93 // all objects in the delayed queue and the thread map and deref all of
96 static void weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
97 static void weakDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
98 void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
100 static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
101 // SVG non-node elements may have a reference to a context node which should be notified when the element is change.
102 static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
107 typedef WTF::Vector<DOMDataStore*> DOMDataList;
111 // DOMDataStore is the backing store that holds the maps between DOM objects
112 // and JavaScript objects. In general, each thread can have multiple backing
113 // stores, one per isolated world.
115 // This class doesn't manage the lifetime of the store. The data store
116 // lifetime is managed by subclasses.
118 class DOMDataStore : public Noncopyable {
120 enum DOMWrapperMapType {
125 DOMSVGElementInstanceMap,
126 DOMSVGObjectWithContextMap
130 template <class KeyType>
131 class InternalDOMWrapperMap : public DOMWrapperMap<KeyType> {
133 InternalDOMWrapperMap(DOMData* domData, v8::WeakReferenceCallback callback)
134 : DOMWrapperMap<KeyType>(callback)
135 , m_domData(domData) { }
137 virtual void forget(KeyType*);
139 void forgetOnly(KeyType* object)
141 DOMWrapperMap<KeyType>::forget(object);
148 // A list of all DOMDataStore objects. Traversed during GC to find a thread-specific map that
149 // contains the object - so we can schedule the object to be deleted on the thread which created it.
150 static DOMDataList& allStores()
152 DEFINE_STATIC_LOCAL(DOMDataList, staticDOMDataList, ());
153 return staticDOMDataList;
156 // Mutex to protect against concurrent access of DOMDataList.
157 static WTF::Mutex& allStoresMutex()
159 DEFINE_STATIC_LOCAL(WTF::Mutex, staticDOMDataListMutex, ());
160 return staticDOMDataListMutex;
163 DOMDataStore(DOMData* domData);
164 virtual ~DOMDataStore();
166 DOMData* domData() const { return m_domData; }
168 void* getDOMWrapperMap(DOMWrapperMapType type)
174 return m_domObjectMap;
175 case ActiveDOMObjectMap:
176 return m_activeDomObjectMap;
178 case DOMSVGElementInstanceMap:
179 return m_domSvgElementInstanceMap;
180 case DOMSVGObjectWithContextMap:
181 return m_domSvgObjectWithContextMap;
185 ASSERT_NOT_REACHED();
189 InternalDOMWrapperMap<Node>& domNodeMap() { return *m_domNodeMap; }
190 InternalDOMWrapperMap<void>& domObjectMap() { return *m_domObjectMap; }
191 InternalDOMWrapperMap<void>& activeDomObjectMap() { return *m_activeDomObjectMap; }
193 InternalDOMWrapperMap<SVGElementInstance>& domSvgElementInstanceMap() { return *m_domSvgElementInstanceMap; }
194 InternalDOMWrapperMap<void>& domSvgObjectWithContextMap() { return *m_domSvgObjectWithContextMap; }
198 InternalDOMWrapperMap<Node>* m_domNodeMap;
199 InternalDOMWrapperMap<void>* m_domObjectMap;
200 InternalDOMWrapperMap<void>* m_activeDomObjectMap;
202 InternalDOMWrapperMap<SVGElementInstance>* m_domSvgElementInstanceMap;
203 InternalDOMWrapperMap<void>* m_domSvgObjectWithContextMap;
207 // A back-pointer to the DOMData to which we belong.
211 // ScopedDOMDataStore
213 // ScopedDOMDataStore is a DOMDataStore that controls limits the lifetime of
214 // the store to the lifetime of the object itself. In other words, when the
215 // ScopedDOMDataStore object is deallocated, the maps that belong to the store
216 // are deallocated as well.
218 class ScopedDOMDataStore : public DOMDataStore {
220 ScopedDOMDataStore(DOMData* domData) : DOMDataStore(domData)
222 m_domNodeMap = new InternalDOMWrapperMap<Node>(domData, weakNodeCallback);
223 m_domObjectMap = new InternalDOMWrapperMap<void>(domData, weakDOMObjectCallback);
224 m_activeDomObjectMap = new InternalDOMWrapperMap<void>(domData, weakActiveDOMObjectCallback);
226 m_domSvgElementInstanceMap = new InternalDOMWrapperMap<SVGElementInstance>(domData, weakSVGElementInstanceCallback);
227 m_domSvgObjectWithContextMap = new InternalDOMWrapperMap<void>(domData, weakSVGObjectWithContextCallback);
231 // This can be called when WTF thread is tearing down.
232 // We assume that all child threads running V8 instances are created by WTF.
233 virtual ~ScopedDOMDataStore()
236 delete m_domObjectMap;
237 delete m_activeDomObjectMap;
239 delete m_domSvgElementInstanceMap;
240 delete m_domSvgObjectWithContextMap;
245 // StaticDOMDataStore
247 // StaticDOMDataStore is a DOMDataStore that manages the lifetime of the store
248 // statically. This encapsulates thread-specific DOM data for the main
249 // thread. All the maps in it are static. This is because we are unable to
250 // rely on WTF::ThreadSpecificThreadExit to do the cleanup since the place that
251 // tears down the main thread can not call any WTF functions.
252 class StaticDOMDataStore : public DOMDataStore {
254 StaticDOMDataStore(DOMData* domData)
255 : DOMDataStore(domData)
256 , m_staticDomNodeMap(domData, weakNodeCallback)
257 , m_staticDomObjectMap(domData, weakDOMObjectCallback)
258 , m_staticActiveDomObjectMap(domData, weakActiveDOMObjectCallback)
260 , m_staticDomSvgElementInstanceMap(domData, weakSVGElementInstanceCallback)
261 , m_staticDomSvgObjectWithContextMap(domData, weakSVGObjectWithContextCallback)
264 m_domNodeMap = &m_staticDomNodeMap;
265 m_domObjectMap = &m_staticDomObjectMap;
266 m_activeDomObjectMap = &m_staticActiveDomObjectMap;
268 m_domSvgElementInstanceMap = &m_staticDomSvgElementInstanceMap;
269 m_domSvgObjectWithContextMap = &m_staticDomSvgObjectWithContextMap;
274 InternalDOMWrapperMap<Node> m_staticDomNodeMap;
275 InternalDOMWrapperMap<void> m_staticDomObjectMap;
276 InternalDOMWrapperMap<void> m_staticActiveDomObjectMap;
277 InternalDOMWrapperMap<SVGElementInstance> m_staticDomSvgElementInstanceMap;
278 InternalDOMWrapperMap<void> m_staticDomSvgObjectWithContextMap;
281 typedef WTF::Vector<DOMDataStore*> DOMDataStoreList;
285 // DOMData represents the all the DOM wrappers for a given thread. In
286 // particular, DOMData holds wrappers for all the isolated worlds in the
287 // thread. The DOMData for the main thread and the DOMData for child threads
288 // use different subclasses.
290 class DOMData: public Noncopyable {
293 : m_delayedProcessingScheduled(false)
294 , m_isMainThread(WTF::isMainThread())
295 , m_owningThread(WTF::currentThread())
299 static DOMData* getCurrent();
300 static DOMData* getCurrentMainThread(); // Caller must be on the main thread.
301 virtual DOMDataStore& getStore() = 0;
304 static void handleWeakObject(DOMDataStore::DOMWrapperMapType mapType, v8::Handle<v8::Object> v8Object, T* domObject);
306 void forgetDelayedObject(void* object) { m_delayedObjectMap.take(object); }
308 // This is to ensure that we will deref DOM objects from the owning thread,
309 // not the GC thread. The helper function will be scheduled by the GC
310 // thread to get called from the owning thread.
311 static void derefDelayedObjectsInCurrentThread(void*);
312 void derefDelayedObjects();
315 static void removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap);
317 ThreadIdentifier owningThread() const { return m_owningThread; }
320 typedef WTF::HashMap<void*, V8ClassIndex::V8WrapperType> DelayedObjectMap;
322 void ensureDeref(V8ClassIndex::V8WrapperType type, void* domObject);
323 static void derefObject(V8ClassIndex::V8WrapperType type, void* domObject);
325 // Stores all the DOM objects that are delayed to be processed when the owning thread gains control.
326 DelayedObjectMap m_delayedObjectMap;
328 // The flag to indicate if the task to do the delayed process has already been posted.
329 bool m_delayedProcessingScheduled;
332 ThreadIdentifier m_owningThread;
335 class MainThreadDOMData : public DOMData {
337 MainThreadDOMData() : m_defaultStore(this) { }
339 DOMDataStore& getStore()
341 ASSERT(WTF::isMainThread());
342 V8IsolatedWorld* world = V8IsolatedWorld::getEntered();
344 return *world->getDOMDataStore();
345 return m_defaultStore;
349 StaticDOMDataStore m_defaultStore;
350 // Note: The DOMDataStores for isolated world are owned by the world object.
353 class ChildThreadDOMData : public DOMData {
355 ChildThreadDOMData() : m_defaultStore(this) { }
357 DOMDataStore& getStore() {
358 ASSERT(!WTF::isMainThread());
359 // Currently, child threads have only one world.
360 return m_defaultStore;
364 ScopedDOMDataStore m_defaultStore;
367 DOMDataStore::DOMDataStore(DOMData* domData)
370 , m_activeDomObjectMap(0)
372 , m_domSvgElementInstanceMap(0)
373 , m_domSvgObjectWithContextMap(0)
377 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
378 DOMDataStore::allStores().append(this);
381 DOMDataStore::~DOMDataStore()
383 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
384 DOMDataStore::allStores().remove(DOMDataStore::allStores().find(this));
387 DOMDataStoreHandle::DOMDataStoreHandle()
388 : m_store(new ScopedDOMDataStore(DOMData::getCurrent()))
392 DOMDataStoreHandle::~DOMDataStoreHandle()
396 template <class KeyType>
397 void DOMDataStore::InternalDOMWrapperMap<KeyType>::forget(KeyType* object)
399 DOMWrapperMap<KeyType>::forget(object);
400 m_domData->forgetDelayedObject(object);
403 DOMWrapperMap<Node>& getDOMNodeMap()
405 // Nodes only exist on the main thread.
406 return DOMData::getCurrentMainThread()->getStore().domNodeMap();
409 DOMWrapperMap<void>& getDOMObjectMap()
411 return DOMData::getCurrent()->getStore().domObjectMap();
414 DOMWrapperMap<void>& getActiveDOMObjectMap()
416 return DOMData::getCurrent()->getStore().activeDomObjectMap();
421 DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap()
423 return DOMData::getCurrent()->getStore().domSvgElementInstanceMap();
426 // Map of SVG objects with contexts to V8 objects
427 DOMWrapperMap<void>& getDOMSVGObjectWithContextMap()
429 return DOMData::getCurrent()->getStore().domSvgObjectWithContextMap();
432 #endif // ENABLE(SVG)
434 DOMData* DOMData::getCurrent()
436 if (WTF::isMainThread())
437 return getCurrentMainThread();
439 DEFINE_STATIC_LOCAL(WTF::ThreadSpecific<ChildThreadDOMData>, childThreadDOMData, ());
440 return childThreadDOMData;
443 DOMData* DOMData::getCurrentMainThread()
445 ASSERT(WTF::isMainThread());
446 DEFINE_STATIC_LOCAL(MainThreadDOMData, mainThreadDOMData, ());
447 return &mainThreadDOMData;
450 // Called when the dead object is not in GC thread's map. Go through all thread maps to find the one containing it.
451 // Then clear the JS reference and push the DOM object into the delayed queue for it to be deref-ed at later time from the owning thread.
452 // * This is called when the GC thread is not the owning thread.
453 // * This can be called on any thread that has GC running.
454 // * Only one V8 instance is running at a time due to V8::Locker. So we don't need to worry about concurrency.
456 void DOMData::handleWeakObject(DOMDataStore::DOMWrapperMapType mapType, v8::Handle<v8::Object> v8Object, T* domObject)
459 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
460 DOMDataList& list = DOMDataStore::allStores();
461 for (size_t i = 0; i < list.size(); ++i) {
462 DOMDataStore* store = list[i];
464 DOMDataStore::InternalDOMWrapperMap<T>* domMap = static_cast<DOMDataStore::InternalDOMWrapperMap<T>*>(store->getDOMWrapperMap(mapType));
466 v8::Handle<v8::Object> wrapper = domMap->get(domObject);
467 if (*wrapper == *v8Object) {
468 // Clear the JS reference.
469 domMap->forgetOnly(domObject);
470 store->domData()->ensureDeref(V8DOMWrapper::domWrapperType(v8Object), domObject);
475 void DOMData::ensureDeref(V8ClassIndex::V8WrapperType type, void* domObject)
477 if (m_owningThread == WTF::currentThread()) {
478 // No need to delay the work. We can deref right now.
479 derefObject(type, domObject);
483 // We need to do the deref on the correct thread.
484 m_delayedObjectMap.set(domObject, type);
486 // Post a task to the owning thread in order to process the delayed queue.
487 // FIXME: For now, we can only post to main thread due to WTF task posting limitation. We will fix this when we work on nested worker.
488 if (!m_delayedProcessingScheduled) {
489 m_delayedProcessingScheduled = true;
491 WTF::callOnMainThread(&derefDelayedObjectsInCurrentThread, 0);
495 // Called when the object is near death (not reachable from JS roots).
496 // It is time to remove the entry from the table and dispose the handle.
497 static void weakDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
499 v8::HandleScope scope;
500 ASSERT(v8Object->IsObject());
501 DOMData::handleWeakObject(DOMDataStore::DOMObjectMap, v8::Handle<v8::Object>::Cast(v8Object), domObject);
504 void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
506 v8::HandleScope scope;
507 ASSERT(v8Object->IsObject());
508 DOMData::handleWeakObject(DOMDataStore::ActiveDOMObjectMap, v8::Handle<v8::Object>::Cast(v8Object), domObject);
511 static void weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
513 v8::HandleScope scope;
514 ASSERT(v8Object->IsObject());
515 DOMData::handleWeakObject<Node>(DOMDataStore::DOMNodeMap, v8::Handle<v8::Object>::Cast(v8Object), static_cast<Node*>(domObject));
520 static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
522 v8::HandleScope scope;
523 ASSERT(v8Object->IsObject());
524 DOMData::handleWeakObject(DOMDataStore::DOMSVGElementInstanceMap, v8::Handle<v8::Object>::Cast(v8Object), static_cast<SVGElementInstance*>(domObject));
527 static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
529 v8::HandleScope scope;
530 ASSERT(v8Object->IsObject());
531 DOMData::handleWeakObject(DOMDataStore::DOMSVGObjectWithContextMap, v8::Handle<v8::Object>::Cast(v8Object), domObject);
534 #endif // ENABLE(SVG)
536 void DOMData::derefObject(V8ClassIndex::V8WrapperType type, void* domObject)
539 case V8ClassIndex::NODE:
540 static_cast<Node*>(domObject)->deref();
543 #define MakeCase(type, name) \
544 case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break;
545 DOM_OBJECT_TYPES(MakeCase) // This includes both active and non-active.
549 #define MakeCase(type, name) \
550 case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break;
551 SVG_OBJECT_TYPES(MakeCase) // This also includes SVGElementInstance.
554 #define MakeCase(type, name) \
555 case V8ClassIndex::type: \
556 static_cast<V8SVGPODTypeWrapper<name>*>(domObject)->deref(); break;
557 SVG_POD_NATIVE_TYPES(MakeCase)
562 ASSERT_NOT_REACHED();
567 void DOMData::derefDelayedObjects()
569 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
571 m_delayedProcessingScheduled = false;
573 for (DelayedObjectMap::iterator iter(m_delayedObjectMap.begin()); iter != m_delayedObjectMap.end(); ++iter)
574 derefObject(iter->second, iter->first);
576 m_delayedObjectMap.clear();
579 void DOMData::derefDelayedObjectsInCurrentThread(void*)
581 getCurrent()->derefDelayedObjects();
585 void DOMData::removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap)
587 for (typename WTF::HashMap<T*, v8::Object*>::iterator iter(domMap.impl().begin()); iter != domMap.impl().end(); ++iter) {
588 T* domObject = static_cast<T*>(iter->first);
589 v8::Persistent<v8::Object> v8Object(iter->second);
591 V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(v8::Handle<v8::Object>::Cast(v8Object));
593 // Deref the DOM object.
594 derefObject(type, domObject);
596 // Clear the JS wrapper.
599 domMap.impl().clear();
602 static void removeAllDOMObjectsInCurrentThreadHelper()
604 v8::HandleScope scope;
606 // Deref all objects in the delayed queue.
607 DOMData::getCurrent()->derefDelayedObjects();
609 // The DOM objects with the following types only exist on the main thread.
610 if (WTF::isMainThread()) {
611 // Remove all DOM nodes.
612 DOMData::removeObjectsFromWrapperMap<Node>(getDOMNodeMap());
615 // Remove all SVG element instances in the wrapper map.
616 DOMData::removeObjectsFromWrapperMap<SVGElementInstance>(getDOMSVGElementInstanceMap());
618 // Remove all SVG objects with context in the wrapper map.
619 DOMData::removeObjectsFromWrapperMap<void>(getDOMSVGObjectWithContextMap());
623 // Remove all DOM objects in the wrapper map.
624 DOMData::removeObjectsFromWrapperMap<void>(getDOMObjectMap());
626 // Remove all active DOM objects in the wrapper map.
627 DOMData::removeObjectsFromWrapperMap<void>(getActiveDOMObjectMap());
630 void removeAllDOMObjectsInCurrentThread()
632 // Use the locker only if it has already been invoked before, as by worker thread.
633 if (v8::Locker::IsActive()) {
635 removeAllDOMObjectsInCurrentThreadHelper();
637 removeAllDOMObjectsInCurrentThreadHelper();
641 void visitDOMNodesInCurrentThread(DOMWrapperMap<Node>::Visitor* visitor)
643 v8::HandleScope scope;
645 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
646 DOMDataList& list = DOMDataStore::allStores();
647 for (size_t i = 0; i < list.size(); ++i) {
648 DOMDataStore* store = list[i];
649 if (!store->domData()->owningThread() == WTF::currentThread())
652 HashMap<Node*, v8::Object*>& map = store->domNodeMap().impl();
653 for (HashMap<Node*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it)
654 visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second));
658 void visitDOMObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor)
660 v8::HandleScope scope;
662 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
663 DOMDataList& list = DOMDataStore::allStores();
664 for (size_t i = 0; i < list.size(); ++i) {
665 DOMDataStore* store = list[i];
666 if (!store->domData()->owningThread() == WTF::currentThread())
669 HashMap<void*, v8::Object*> & map = store->domObjectMap().impl();
670 for (HashMap<void*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it)
671 visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second));
675 void visitActiveDOMObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor)
677 v8::HandleScope scope;
679 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
680 DOMDataList& list = DOMDataStore::allStores();
681 for (size_t i = 0; i < list.size(); ++i) {
682 DOMDataStore* store = list[i];
683 if (!store->domData()->owningThread() == WTF::currentThread())
686 HashMap<void*, v8::Object*>& map = store->activeDomObjectMap().impl();
687 for (HashMap<void*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it)
688 visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second));
694 void visitDOMSVGElementInstancesInCurrentThread(DOMWrapperMap<SVGElementInstance>::Visitor* visitor)
696 v8::HandleScope scope;
698 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
699 DOMDataList& list = DOMDataStore::allStores();
700 for (size_t i = 0; i < list.size(); ++i) {
701 DOMDataStore* store = list[i];
702 if (!store->domData()->owningThread() == WTF::currentThread())
705 HashMap<SVGElementInstance*, v8::Object*> & map = store->domSvgElementInstanceMap().impl();
706 for (HashMap<SVGElementInstance*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it)
707 visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second));
711 void visitSVGObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor)
713 v8::HandleScope scope;
715 WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
716 DOMDataList& list = DOMDataStore::allStores();
717 for (size_t i = 0; i < list.size(); ++i) {
718 DOMDataStore* store = list[i];
719 if (!store->domData()->owningThread() == WTF::currentThread())
722 HashMap<void*, v8::Object*>& map = store->domSvgObjectWithContextMap().impl();
723 for (HashMap<void*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it)
724 visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second));
730 } // namespace WebCore