2009-07-23 Jian Li <jianli@chromium.org>
[WebKit-https.git] / WebCore / bindings / v8 / V8DOMMap.cpp
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 "V8DOMMap.h"
33
34 #include "DOMObjectsInclude.h"
35
36 #include <v8.h>
37
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>
45
46 #include "V8IsolatedWorld.h"
47
48 namespace WebCore {
49
50 // DOM binding algorithm:
51 //
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.
57 //
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.
63 //
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.
75 //
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
94 //    them.
95
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);
99 #if ENABLE(SVG)
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);
103 #endif
104
105 class DOMData;
106 class DOMDataStore;
107 typedef WTF::Vector<DOMDataStore*> DOMDataList;
108
109 // DOMDataStore
110 //
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.
114 //
115 // This class doesn't manage the lifetime of the store.  The data store
116 // lifetime is managed by subclasses.
117 //
118 class DOMDataStore : public Noncopyable {
119 public:
120     enum DOMWrapperMapType {
121         DOMNodeMap,
122         DOMObjectMap,
123         ActiveDOMObjectMap,
124 #if ENABLE(SVG)
125         DOMSVGElementInstanceMap,
126         DOMSVGObjectWithContextMap
127 #endif
128     };
129
130     template <class KeyType>
131     class InternalDOMWrapperMap : public DOMWrapperMap<KeyType> {
132     public:
133         InternalDOMWrapperMap(DOMData* domData, v8::WeakReferenceCallback callback)
134             : DOMWrapperMap<KeyType>(callback)
135             , m_domData(domData) { }
136
137         virtual void forget(KeyType*);
138
139         void forgetOnly(KeyType* object)
140         {
141             DOMWrapperMap<KeyType>::forget(object);
142         }
143
144     private:
145         DOMData* m_domData;
146     };
147
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()
151     {
152         DEFINE_STATIC_LOCAL(DOMDataList, staticDOMDataList, ());
153         return staticDOMDataList;
154     }
155
156     // Mutex to protect against concurrent access of DOMDataList.
157     static WTF::Mutex& allStoresMutex()
158     {
159         DEFINE_STATIC_LOCAL(WTF::Mutex, staticDOMDataListMutex, ());
160         return staticDOMDataListMutex;
161     }
162
163     DOMDataStore(DOMData* domData);
164     virtual ~DOMDataStore();
165
166     DOMData* domData() const { return m_domData; }
167
168     void* getDOMWrapperMap(DOMWrapperMapType type)
169     {
170         switch (type) {
171         case DOMNodeMap:
172             return m_domNodeMap;
173         case DOMObjectMap:
174             return m_domObjectMap;
175         case ActiveDOMObjectMap:
176             return m_activeDomObjectMap;
177 #if ENABLE(SVG)
178         case DOMSVGElementInstanceMap:
179             return m_domSvgElementInstanceMap;
180         case DOMSVGObjectWithContextMap:
181             return m_domSvgObjectWithContextMap;
182 #endif
183         }
184
185         ASSERT_NOT_REACHED();
186         return 0;
187     }
188
189     InternalDOMWrapperMap<Node>& domNodeMap() { return *m_domNodeMap; }
190     InternalDOMWrapperMap<void>& domObjectMap() { return *m_domObjectMap; }
191     InternalDOMWrapperMap<void>& activeDomObjectMap() { return *m_activeDomObjectMap; }
192 #if ENABLE(SVG)
193     InternalDOMWrapperMap<SVGElementInstance>& domSvgElementInstanceMap() { return *m_domSvgElementInstanceMap; }
194     InternalDOMWrapperMap<void>& domSvgObjectWithContextMap() { return *m_domSvgObjectWithContextMap; }
195 #endif
196
197 protected:
198     InternalDOMWrapperMap<Node>* m_domNodeMap;
199     InternalDOMWrapperMap<void>* m_domObjectMap;
200     InternalDOMWrapperMap<void>* m_activeDomObjectMap;
201 #if ENABLE(SVG)
202     InternalDOMWrapperMap<SVGElementInstance>* m_domSvgElementInstanceMap;
203     InternalDOMWrapperMap<void>* m_domSvgObjectWithContextMap;
204 #endif
205
206 private:
207     // A back-pointer to the DOMData to which we belong.
208     DOMData* m_domData;
209 };
210
211 // ScopedDOMDataStore
212 //
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.
217 //
218 class ScopedDOMDataStore : public DOMDataStore {
219 public:
220     ScopedDOMDataStore(DOMData* domData) : DOMDataStore(domData)
221     {
222         m_domNodeMap = new InternalDOMWrapperMap<Node>(domData, weakNodeCallback);
223         m_domObjectMap = new InternalDOMWrapperMap<void>(domData, weakDOMObjectCallback);
224         m_activeDomObjectMap = new InternalDOMWrapperMap<void>(domData, weakActiveDOMObjectCallback);
225 #if ENABLE(SVG)
226         m_domSvgElementInstanceMap = new InternalDOMWrapperMap<SVGElementInstance>(domData, weakSVGElementInstanceCallback);
227         m_domSvgObjectWithContextMap = new InternalDOMWrapperMap<void>(domData, weakSVGObjectWithContextCallback);
228 #endif
229     }
230
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()
234     {
235         delete m_domNodeMap;
236         delete m_domObjectMap;
237         delete m_activeDomObjectMap;
238 #if ENABLE(SVG)
239         delete m_domSvgElementInstanceMap;
240         delete m_domSvgObjectWithContextMap;
241 #endif
242     }
243 };
244
245 // StaticDOMDataStore
246 //
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 {
253 public:
254     StaticDOMDataStore(DOMData* domData)
255         : DOMDataStore(domData)
256         , m_staticDomNodeMap(domData, weakNodeCallback)
257         , m_staticDomObjectMap(domData, weakDOMObjectCallback)
258         , m_staticActiveDomObjectMap(domData, weakActiveDOMObjectCallback)
259 #if ENABLE(SVG)
260         , m_staticDomSvgElementInstanceMap(domData, weakSVGElementInstanceCallback)
261         , m_staticDomSvgObjectWithContextMap(domData, weakSVGObjectWithContextCallback)
262 #endif
263     {
264         m_domNodeMap = &m_staticDomNodeMap;
265         m_domObjectMap = &m_staticDomObjectMap;
266         m_activeDomObjectMap = &m_staticActiveDomObjectMap;
267 #if ENABLE(SVG)
268         m_domSvgElementInstanceMap = &m_staticDomSvgElementInstanceMap;
269         m_domSvgObjectWithContextMap = &m_staticDomSvgObjectWithContextMap;
270 #endif
271     }
272
273 private:
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;
279 };
280
281 typedef WTF::Vector<DOMDataStore*> DOMDataStoreList;
282
283 // DOMData
284 //
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.
289 //
290 class DOMData: public Noncopyable {
291 public:
292     DOMData()
293         : m_delayedProcessingScheduled(false)
294         , m_isMainThread(WTF::isMainThread())
295         , m_owningThread(WTF::currentThread())
296     {
297     }
298
299     static DOMData* getCurrent();
300     static DOMData* getCurrentMainThread(); // Caller must be on the main thread.
301     virtual DOMDataStore& getStore() = 0;
302
303     template<typename T>
304     static void handleWeakObject(DOMDataStore::DOMWrapperMapType mapType, v8::Handle<v8::Object> v8Object, T* domObject);
305
306     void forgetDelayedObject(void* object) { m_delayedObjectMap.take(object); }
307
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();
313
314     template<typename T>
315     static void removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap);
316
317     ThreadIdentifier owningThread() const { return m_owningThread; }
318
319 private:
320     typedef WTF::HashMap<void*, V8ClassIndex::V8WrapperType> DelayedObjectMap;
321
322     void ensureDeref(V8ClassIndex::V8WrapperType type, void* domObject);
323     static void derefObject(V8ClassIndex::V8WrapperType type, void* domObject);
324
325     // Stores all the DOM objects that are delayed to be processed when the owning thread gains control.
326     DelayedObjectMap m_delayedObjectMap;
327
328     // The flag to indicate if the task to do the delayed process has already been posted.
329     bool m_delayedProcessingScheduled;
330
331     bool m_isMainThread;
332     ThreadIdentifier m_owningThread;
333 };
334
335 class MainThreadDOMData : public DOMData {
336 public:
337     MainThreadDOMData() : m_defaultStore(this) { }
338
339     DOMDataStore& getStore()
340     {
341         ASSERT(WTF::isMainThread());
342         V8IsolatedWorld* world = V8IsolatedWorld::getEntered();
343         if (world)
344             return *world->getDOMDataStore();
345         return m_defaultStore;
346     }
347
348 private:
349     StaticDOMDataStore m_defaultStore;
350     // Note: The DOMDataStores for isolated world are owned by the world object.
351 };
352
353 class ChildThreadDOMData : public DOMData {
354 public:
355     ChildThreadDOMData() : m_defaultStore(this) { }
356
357     DOMDataStore& getStore() {
358         ASSERT(!WTF::isMainThread());
359         // Currently, child threads have only one world.
360         return m_defaultStore;
361     }
362
363 private:
364     ScopedDOMDataStore m_defaultStore;
365 };
366
367 DOMDataStore::DOMDataStore(DOMData* domData)
368     : m_domNodeMap(0)
369     , m_domObjectMap(0)
370     , m_activeDomObjectMap(0)
371 #if ENABLE(SVG)
372     , m_domSvgElementInstanceMap(0)
373     , m_domSvgObjectWithContextMap(0)
374 #endif
375     , m_domData(domData)
376 {
377     WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
378     DOMDataStore::allStores().append(this);
379 }
380
381 DOMDataStore::~DOMDataStore()
382 {
383     WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
384     DOMDataStore::allStores().remove(DOMDataStore::allStores().find(this));
385 }
386
387 DOMDataStoreHandle::DOMDataStoreHandle()
388     : m_store(new ScopedDOMDataStore(DOMData::getCurrent()))
389 {
390 }
391
392 DOMDataStoreHandle::~DOMDataStoreHandle()
393 {
394 }
395
396 template <class KeyType>
397 void DOMDataStore::InternalDOMWrapperMap<KeyType>::forget(KeyType* object)
398 {
399     DOMWrapperMap<KeyType>::forget(object);
400     m_domData->forgetDelayedObject(object);
401 }
402
403 DOMWrapperMap<Node>& getDOMNodeMap()
404 {
405     // Nodes only exist on the main thread.
406     return DOMData::getCurrentMainThread()->getStore().domNodeMap();
407 }
408
409 DOMWrapperMap<void>& getDOMObjectMap()
410 {
411     return DOMData::getCurrent()->getStore().domObjectMap();
412 }
413
414 DOMWrapperMap<void>& getActiveDOMObjectMap()
415 {
416     return DOMData::getCurrent()->getStore().activeDomObjectMap();
417 }
418
419 #if ENABLE(SVG)
420
421 DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap()
422 {
423     return DOMData::getCurrent()->getStore().domSvgElementInstanceMap();
424 }
425
426 // Map of SVG objects with contexts to V8 objects
427 DOMWrapperMap<void>& getDOMSVGObjectWithContextMap()
428 {
429     return DOMData::getCurrent()->getStore().domSvgObjectWithContextMap();
430 }
431
432 #endif // ENABLE(SVG)
433
434 DOMData* DOMData::getCurrent()
435 {
436     if (WTF::isMainThread())
437         return getCurrentMainThread();
438
439     DEFINE_STATIC_LOCAL(WTF::ThreadSpecific<ChildThreadDOMData>, childThreadDOMData, ());
440     return childThreadDOMData;
441 }
442
443 DOMData* DOMData::getCurrentMainThread()
444 {
445     ASSERT(WTF::isMainThread());
446     DEFINE_STATIC_LOCAL(MainThreadDOMData, mainThreadDOMData, ());
447     return &mainThreadDOMData;
448 }
449
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.
455 template<typename T>
456 void DOMData::handleWeakObject(DOMDataStore::DOMWrapperMapType mapType, v8::Handle<v8::Object> v8Object, T* domObject)
457 {
458
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];
463
464         DOMDataStore::InternalDOMWrapperMap<T>* domMap = static_cast<DOMDataStore::InternalDOMWrapperMap<T>*>(store->getDOMWrapperMap(mapType));
465
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);
471         }
472     }
473 }
474
475 void DOMData::ensureDeref(V8ClassIndex::V8WrapperType type, void* domObject)
476 {
477     if (m_owningThread == WTF::currentThread()) {
478         // No need to delay the work.  We can deref right now.
479         derefObject(type, domObject);
480         return;
481     }
482
483     // We need to do the deref on the correct thread.
484     m_delayedObjectMap.set(domObject, type);
485
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;
490         if (isMainThread())
491             WTF::callOnMainThread(&derefDelayedObjectsInCurrentThread, 0);
492     }
493 }
494
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)
498 {
499     v8::HandleScope scope;
500     ASSERT(v8Object->IsObject());
501     DOMData::handleWeakObject(DOMDataStore::DOMObjectMap, v8::Handle<v8::Object>::Cast(v8Object), domObject);
502 }
503
504 void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
505 {
506     v8::HandleScope scope;
507     ASSERT(v8Object->IsObject());
508     DOMData::handleWeakObject(DOMDataStore::ActiveDOMObjectMap, v8::Handle<v8::Object>::Cast(v8Object), domObject);
509 }
510
511 static void weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
512 {
513     v8::HandleScope scope;
514     ASSERT(v8Object->IsObject());
515     DOMData::handleWeakObject<Node>(DOMDataStore::DOMNodeMap, v8::Handle<v8::Object>::Cast(v8Object), static_cast<Node*>(domObject));
516 }
517
518 #if ENABLE(SVG)
519
520 static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
521 {
522     v8::HandleScope scope;
523     ASSERT(v8Object->IsObject());
524     DOMData::handleWeakObject(DOMDataStore::DOMSVGElementInstanceMap, v8::Handle<v8::Object>::Cast(v8Object), static_cast<SVGElementInstance*>(domObject));
525 }
526
527 static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
528 {
529     v8::HandleScope scope;
530     ASSERT(v8Object->IsObject());
531     DOMData::handleWeakObject(DOMDataStore::DOMSVGObjectWithContextMap, v8::Handle<v8::Object>::Cast(v8Object), domObject);
532 }
533
534 #endif  // ENABLE(SVG)
535
536 void DOMData::derefObject(V8ClassIndex::V8WrapperType type, void* domObject)
537 {
538     switch (type) {
539     case V8ClassIndex::NODE:
540         static_cast<Node*>(domObject)->deref();
541         break;
542
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.
546 #undef MakeCase
547
548 #if ENABLE(SVG)
549 #define MakeCase(type, name)     \
550         case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break;
551     SVG_OBJECT_TYPES(MakeCase)   // This also includes SVGElementInstance.
552 #undef MakeCase
553
554 #define MakeCase(type, name)     \
555         case V8ClassIndex::type:    \
556             static_cast<V8SVGPODTypeWrapper<name>*>(domObject)->deref(); break;
557     SVG_POD_NATIVE_TYPES(MakeCase)
558 #undef MakeCase
559 #endif
560
561     default:
562         ASSERT_NOT_REACHED();
563         break;
564     }
565 }
566
567 void DOMData::derefDelayedObjects()
568 {
569     WTF::MutexLocker locker(DOMDataStore::allStoresMutex());
570
571     m_delayedProcessingScheduled = false;
572
573     for (DelayedObjectMap::iterator iter(m_delayedObjectMap.begin()); iter != m_delayedObjectMap.end(); ++iter)
574         derefObject(iter->second, iter->first);
575
576     m_delayedObjectMap.clear();
577 }
578
579 void DOMData::derefDelayedObjectsInCurrentThread(void*)
580 {
581     getCurrent()->derefDelayedObjects();
582 }
583
584 template<typename T>
585 void DOMData::removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap)
586 {
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);
590
591         V8ClassIndex::V8WrapperType type = V8DOMWrapper::domWrapperType(v8::Handle<v8::Object>::Cast(v8Object));
592
593         // Deref the DOM object.
594         derefObject(type, domObject);
595
596         // Clear the JS wrapper.
597         v8Object.Dispose();
598     }
599     domMap.impl().clear();
600 }
601
602 static void removeAllDOMObjectsInCurrentThreadHelper()
603 {
604     v8::HandleScope scope;
605
606     // Deref all objects in the delayed queue.
607     DOMData::getCurrent()->derefDelayedObjects();
608
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());
613
614 #if ENABLE(SVG)
615         // Remove all SVG element instances in the wrapper map.
616         DOMData::removeObjectsFromWrapperMap<SVGElementInstance>(getDOMSVGElementInstanceMap());
617
618         // Remove all SVG objects with context in the wrapper map.
619         DOMData::removeObjectsFromWrapperMap<void>(getDOMSVGObjectWithContextMap());
620 #endif
621     }
622
623     // Remove all DOM objects in the wrapper map.
624     DOMData::removeObjectsFromWrapperMap<void>(getDOMObjectMap());
625
626     // Remove all active DOM objects in the wrapper map.
627     DOMData::removeObjectsFromWrapperMap<void>(getActiveDOMObjectMap());
628 }
629
630 void removeAllDOMObjectsInCurrentThread()
631 {
632     // Use the locker only if it has already been invoked before, as by worker thread.
633     if (v8::Locker::IsActive()) {
634         v8::Locker locker;
635         removeAllDOMObjectsInCurrentThreadHelper();
636     } else
637         removeAllDOMObjectsInCurrentThreadHelper();
638 }
639
640
641 void visitDOMNodesInCurrentThread(DOMWrapperMap<Node>::Visitor* visitor)
642 {
643     v8::HandleScope scope;
644
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())
650             continue;
651
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));
655     }
656 }
657
658 void visitDOMObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor)
659 {
660     v8::HandleScope scope;
661
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())
667             continue;
668
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));
672     }
673 }
674
675 void visitActiveDOMObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor)
676 {
677     v8::HandleScope scope;
678
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())
684             continue;
685
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));
689     }
690 }
691
692 #if ENABLE(SVG)
693
694 void visitDOMSVGElementInstancesInCurrentThread(DOMWrapperMap<SVGElementInstance>::Visitor* visitor)
695 {
696     v8::HandleScope scope;
697
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())
703             continue;
704
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));
708     }
709 }
710
711 void visitSVGObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor)
712 {
713     v8::HandleScope scope;
714
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())
720             continue;
721
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));
725     }
726 }
727
728 #endif
729
730 } // namespace WebCore