diff options
Diffstat (limited to 'webkit/port/bindings/v8/V8DOMMap.cpp')
-rw-r--r-- | webkit/port/bindings/v8/V8DOMMap.cpp | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/webkit/port/bindings/v8/V8DOMMap.cpp b/webkit/port/bindings/v8/V8DOMMap.cpp deleted file mode 100644 index 912dad7..0000000 --- a/webkit/port/bindings/v8/V8DOMMap.cpp +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following disclaimer - * in the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" - -#include <v8.h> - -#include "DOMObjectsInclude.h" -#include "V8DOMMap.h" - -#include <wtf/HashMap.h> -#include <wtf/MainThread.h> -#include <wtf/Threading.h> -#include <wtf/ThreadSpecific.h> - -namespace WebCore { - -// DOM binding algorithm: -// -// There are two kinds of DOM objects: -// 1. DOM tree nodes, such as Document, HTMLElement, ... -// there classes implements TreeShared<T> interface; -// 2. Non-node DOM objects, such as CSSRule, Location, etc. -// these classes implement a ref-counted scheme. -// -// A DOM object may have a JS wrapper object. If a tree node -// is alive, its JS wrapper must be kept alive even it is not -// reachable from JS roots. -// However, JS wrappers of non-node objects can go away if -// not reachable from other JS objects. It works like a cache. -// -// DOM objects are ref-counted, and JS objects are traced from -// a set of root objects. They can create a cycle. To break -// cycles, we do following: -// Handles from DOM objects to JS wrappers are always weak, -// so JS wrappers of non-node object cannot create a cycle. -// Before starting a global GC, we create a virtual connection -// between nodes in the same tree in the JS heap. If the wrapper -// of one node in a tree is alive, wrappers of all nodes in -// the same tree are considered alive. This is done by creating -// object groups in GC prologue callbacks. The mark-compact -// collector will remove these groups after each GC. -// -// DOM objects should be deref-ed from the owning thread, not the GC thread -// that does not own them. In V8, GC can kick in from any thread. To ensure -// that DOM objects are always deref-ed from the owning thread when running -// V8 in multi-threading environment, we do following: -// 1. Maintain a thread specific DOM wrapper map for each object map. -// (We're using TLS support from WTF instead of base since V8Bindings -// does not depend on base. We further assume that all child threads -// running V8 instances are created by WTF and thus a destructor will -// be called to clean up all thread specific data.) -// 2. When GC happens: -// 2.1. If the dead object is in GC thread's map, remove the JS reference -// and deref the DOM object. -// 2.2. Otherwise, go through all thread maps to find the owning thread. -// Remove the JS reference from the owning thread's map and move the -// DOM object to a delayed queue. Post a task to the owning thread -// to have it deref-ed from the owning thread at later time. -// 3. When a thread is tearing down, invoke a cleanup routine to go through -// all objects in the delayed queue and the thread map and deref all of -// them. - -static void weakDOMObjectCallback(v8::Persistent<v8::Value> obj, void* param); -static void weakNodeCallback(v8::Persistent<v8::Value> obj, void* param); - -#if ENABLE(SVG) -static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> obj, void* param); - -// SVG non-node elements may have a reference to a context node which should be notified when the element is change -static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> obj, void* domObj); -#endif - -// This is to ensure that we will deref DOM objects from the owning thread, not the GC thread. -// The helper function will be scheduled by the GC thread to get called from the owning thread. -static void derefDelayedObjectsInCurrentThread(void*); - -// This should be called to remove all DOM objects associated with the current thread when it is tearing down. -static void removeAllDOMObjectsInCurrentThread(); - -// A map from a thread ID to thread's specific data. -class ThreadSpecificDOMData; -typedef WTF::HashMap<WTF::ThreadIdentifier, ThreadSpecificDOMData*> DOMThreadMap; -static DOMThreadMap domThreadMap; - -// Mutex to protect against concurrent access of domThreadMap. -static WTF::Mutex domThreadMapMutex; - -class ThreadSpecificDOMData { -public: - enum DOMWrapperMapType - { - DOMNodeMap, - DOMObjectMap, - ActiveDOMObjectMap, -#if ENABLE(SVG) - DOMSVGElementInstanceMap, - DOMSVGObjectWithContextMap -#endif - }; - - typedef WTF::HashMap<void*, V8ClassIndex::V8WrapperType> DelayedObjectMap; - - template <class KeyType> - class InternalDOMWrapperMap : public DOMWrapperMap<KeyType> { - public: - InternalDOMWrapperMap(v8::WeakReferenceCallback callback) - : DOMWrapperMap<KeyType>(callback) { } - - virtual void forget(KeyType* obj); - - void forgetOnly(KeyType* obj) - { - DOMWrapperMap<KeyType>::forget(obj); - } - }; - - ThreadSpecificDOMData() - : m_domNodeMap(new InternalDOMWrapperMap<Node>(&weakNodeCallback)) - , m_domObjectMap(new InternalDOMWrapperMap<void>(weakDOMObjectCallback)) - , m_activeDomObjectMap(new InternalDOMWrapperMap<void>(weakActiveDOMObjectCallback)) -#if ENABLE(SVG) - , m_domSvgElementInstanceMap(new InternalDOMWrapperMap<SVGElementInstance>(weakSVGElementInstanceCallback)) - , m_domSvgObjectWithContextMap(new InternalDOMWrapperMap<void>(weakSVGObjectWithContextCallback)) -#endif - , m_delayedProcessingScheduled(false) - , m_isMainThread(WTF::isMainThread()) - { - WTF::MutexLocker locker(domThreadMapMutex); - domThreadMap.set(WTF::currentThread(), this); - } - - // This is called when WTF thread is tearing down. - // We assume that all child threads running V8 instances are created by WTF. - ~ThreadSpecificDOMData() - { - removeAllDOMObjectsInCurrentThread(); - - delete m_domNodeMap; - delete m_domObjectMap; - delete m_activeDomObjectMap; -#if ENABLE(SVG) - delete m_domSvgElementInstanceMap; - delete m_domSvgObjectWithContextMap; -#endif - - WTF::MutexLocker locker(domThreadMapMutex); - domThreadMap.remove(WTF::currentThread()); - } - - void* getDOMWrapperMap(DOMWrapperMapType type) - { - switch (type) { - case DOMNodeMap: - return m_domNodeMap; - case DOMObjectMap: - return m_domObjectMap; - case ActiveDOMObjectMap: - return m_activeDomObjectMap; -#if ENABLE(SVG) - case DOMSVGElementInstanceMap: - return m_domSvgElementInstanceMap; - case DOMSVGObjectWithContextMap: - return m_domSvgObjectWithContextMap; -#endif - default: - ASSERT(false); - return NULL; - } - } - - InternalDOMWrapperMap<Node>& domNodeMap() { return *m_domNodeMap; } - InternalDOMWrapperMap<void>& domObjectMap() { return *m_domObjectMap; } - InternalDOMWrapperMap<void>& activeDomObjectMap() { return *m_activeDomObjectMap; } -#if ENABLE(SVG) - InternalDOMWrapperMap<SVGElementInstance>& domSvgElementInstanceMap() { return *m_domSvgElementInstanceMap; } - InternalDOMWrapperMap<void>& domSvgObjectWithContextMap() { return *m_domSvgObjectWithContextMap; } -#endif - - DelayedObjectMap& delayedObjectMap() { return m_delayedObjectMap; } - bool delayedProcessingScheduled() const { return m_delayedProcessingScheduled; } - void setDelayedProcessingScheduled(bool value) { m_delayedProcessingScheduled = value; } - bool isMainThread() const { return m_isMainThread; } - -private: - InternalDOMWrapperMap<Node>* m_domNodeMap; - InternalDOMWrapperMap<void>* m_domObjectMap; - InternalDOMWrapperMap<void>* m_activeDomObjectMap; -#if ENABLE(SVG) - InternalDOMWrapperMap<SVGElementInstance>* m_domSvgElementInstanceMap; - InternalDOMWrapperMap<void>* m_domSvgObjectWithContextMap; -#endif - - // Stores all the DOM objects that are delayed to be processed when the owning thread gains control. - DelayedObjectMap m_delayedObjectMap; - - // The flag to indicate if the task to do the delayed process has already been posted. - bool m_delayedProcessingScheduled; - - bool m_isMainThread; -}; - -static WTF::ThreadSpecific<ThreadSpecificDOMData> threadSpecificDOMData; - -template<typename T> -static void handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMWrapperMapType mapType, V8ClassIndex::V8WrapperType objType, T* obj); - -template <class KeyType> -void ThreadSpecificDOMData::InternalDOMWrapperMap<KeyType>::forget(KeyType* obj) -{ - DOMWrapperMap<KeyType>::forget(obj); - - ThreadSpecificDOMData::DelayedObjectMap& delayedObjectMap = (*threadSpecificDOMData).delayedObjectMap(); - delayedObjectMap.take(obj); -} - -DOMWrapperMap<Node>& getDOMNodeMap() -{ - return (*threadSpecificDOMData).domNodeMap(); -} - -DOMWrapperMap<void>& getDOMObjectMap() -{ - return (*threadSpecificDOMData).domObjectMap(); -} - -DOMWrapperMap<void>& getActiveDOMObjectMap() -{ - return (*threadSpecificDOMData).activeDomObjectMap(); -} - -#if ENABLE(SVG) -DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap() -{ - return (*threadSpecificDOMData).domSvgElementInstanceMap(); -} - -static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> obj, void* param) -{ - SVGElementInstance* instance = static_cast<SVGElementInstance*>(param); - - ThreadSpecificDOMData::InternalDOMWrapperMap<SVGElementInstance>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<SVGElementInstance>&>(getDOMSVGElementInstanceMap()); - if (map.contains(instance)) { - instance->deref(); - map.forgetOnly(instance); - } else { - handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMSVGElementInstanceMap, V8ClassIndex::SVGELEMENTINSTANCE, instance); - } -} - -// Map of SVG objects with contexts to V8 objects -DOMWrapperMap<void>& getDOMSVGObjectWithContextMap() -{ - return (*threadSpecificDOMData).domSvgObjectWithContextMap(); -} - -static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> obj, void* domObj) -{ - v8::HandleScope scope; - ASSERT(obj->IsObject()); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - - ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getDOMSVGObjectWithContextMap()); - if (map.contains(domObj)) { - // Forget function removes object from the map and dispose the wrapper. - map.forgetOnly(domObj); - - switch (type) { -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; - SVG_OBJECT_TYPES(MakeCase) -#undef MakeCase -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: \ - static_cast<V8SVGPODTypeWrapper<NAME>*>(domObj)->deref(); break; - SVG_POD_NATIVE_TYPES(MakeCase) -#undef MakeCase - default: - ASSERT(false); - } - } else { - handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMSVGObjectWithContextMap, type, domObj); - } -} -#endif - -// Called when the dead object is not in GC thread's map. Go through all thread maps to find the one containing it. -// 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. -// * This is called when the GC thread is not the owning thread. -// * This can be called on any thread that has GC running. -// * Only one V8 instance is running at a time due to V8::Locker. So we don't need to worry about concurrency. -template<typename T> -static void handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMWrapperMapType mapType, V8ClassIndex::V8WrapperType objType, T* obj) -{ - WTF::MutexLocker locker(domThreadMapMutex); - for (typename DOMThreadMap::iterator iter(domThreadMap.begin()); iter != domThreadMap.end(); ++iter) { - WTF::ThreadIdentifier threadID = iter->first; - ThreadSpecificDOMData* threadData = iter->second; - - // Skip the current thread that is GC thread. - if (threadID == WTF::currentThread()) { - ASSERT(!static_cast<DOMWrapperMap<T>*>(threadData->getDOMWrapperMap(mapType))->contains(obj)); - continue; - } - - ThreadSpecificDOMData::InternalDOMWrapperMap<T>* domMap = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<T>*>(threadData->getDOMWrapperMap(mapType)); - if (domMap->contains(obj)) { - // Clear the JS reference. - domMap->forgetOnly(obj); - - // Push into the delayed queue. - threadData->delayedObjectMap().set(obj, objType); - - // Post a task to the owning thread in order to process the delayed queue. - // FIXME(jianli): 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. - if (!threadData->delayedProcessingScheduled()) { - threadData->setDelayedProcessingScheduled(true); - if (threadData->isMainThread()) - WTF::callOnMainThread(&derefDelayedObjectsInCurrentThread, NULL); - } - - break; - } - } -} - -// Called when obj is near death (not reachable from JS roots). -// It is time to remove the entry from the table and dispose the handle. -static void weakDOMObjectCallback(v8::Persistent<v8::Value> obj, void* domObj) -{ - v8::HandleScope scope; - ASSERT(obj->IsObject()); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - - ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getDOMObjectMap()); - if (map.contains(domObj)) { - // Forget function removes object from the map and dispose the wrapper. - map.forgetOnly(domObj); - - switch (type) { -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; - DOM_OBJECT_TYPES(MakeCase) -#undef MakeCase - default: - ASSERT(false); - } - } else { - handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMObjectMap, type, domObj); - } -} - -void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> obj, void* domObj) -{ - v8::HandleScope scope; - ASSERT(obj->IsObject()); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - - ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getActiveDOMObjectMap()); - if (map.contains(domObj)) { - // Forget function removes object from the map and dispose the wrapper. - map.forgetOnly(domObj); - - switch (type) { -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; - ACTIVE_DOM_OBJECT_TYPES(MakeCase) -#undef MakeCase - default: - ASSERT(false); - } - } else { - handleWeakObjectInOwningThread(ThreadSpecificDOMData::ActiveDOMObjectMap, type, domObj); - } -} - -static void weakNodeCallback(v8::Persistent<v8::Value> obj, void* param) -{ - Node* node = static_cast<Node*>(param); - - ThreadSpecificDOMData::InternalDOMWrapperMap<Node>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<Node>&>(getDOMNodeMap()); - if (map.contains(node)) { - map.forgetOnly(node); - node->deref(); - } else { - handleWeakObjectInOwningThread<Node>(ThreadSpecificDOMData::DOMNodeMap, V8ClassIndex::NODE, node); - } -} - -static void derefObject(V8ClassIndex::V8WrapperType type, void* domObj) -{ - switch (type) { - case V8ClassIndex::NODE: - static_cast<Node*>(domObj)->deref(); - break; - -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; - DOM_OBJECT_TYPES(MakeCase) // This includes both active and non-active. -#undef MakeCase - -#if ENABLE(SVG) -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: static_cast<NAME*>(domObj)->deref(); break; - SVG_OBJECT_TYPES(MakeCase) // This also includes SVGElementInstance. -#undef MakeCase - -#define MakeCase(TYPE, NAME) \ - case V8ClassIndex::TYPE: \ - static_cast<V8SVGPODTypeWrapper<NAME>*>(domObj)->deref(); break; - SVG_POD_NATIVE_TYPES(MakeCase) -#undef MakeCase -#endif - - default: - ASSERT(false); - } -} - -static void derefDelayedObjects() -{ - WTF::MutexLocker locker(domThreadMapMutex); - ThreadSpecificDOMData::DelayedObjectMap& delayedObjectMap = (*threadSpecificDOMData).delayedObjectMap(); - for (ThreadSpecificDOMData::DelayedObjectMap::iterator iter(delayedObjectMap.begin()); iter != delayedObjectMap.end(); ++iter) { - derefObject(iter->second, iter->first); - } - delayedObjectMap.clear(); -} - -static void derefDelayedObjectsInCurrentThread(void*) -{ - (*threadSpecificDOMData).setDelayedProcessingScheduled(false); - derefDelayedObjects(); -} - -template<typename T> -static void removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap) -{ - for (typename WTF::HashMap<T*, v8::Object*>::iterator iter(domMap.impl().begin()); iter != domMap.impl().end(); ++iter) { - T* domObj = static_cast<T*>(iter->first); - v8::Persistent<v8::Object> obj(iter->second); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(obj)); - - // Deref the DOM object. - derefObject(type, domObj); - - // Clear the JS wrapper. - obj.Dispose(); - } - domMap.impl().clear(); -} - -static void removeAllDOMObjectsInCurrentThread() -{ - v8::Locker locker; - v8::HandleScope scope; - - // Deref all objects in the delayed queue. - derefDelayedObjects(); - - // Remove all DOM nodes. - removeObjectsFromWrapperMap<Node>(getDOMNodeMap()); - - // Remove all DOM objects in the wrapper map. - removeObjectsFromWrapperMap<void>(getDOMObjectMap()); - - // Remove all active DOM objects in the wrapper map. - removeObjectsFromWrapperMap<void>(getActiveDOMObjectMap()); - -#if ENABLE(SVG) - // Remove all SVG element instances in the wrapper map. - removeObjectsFromWrapperMap<SVGElementInstance>(getDOMSVGElementInstanceMap()); - - // Remove all SVG objects with context in the wrapper map. - removeObjectsFromWrapperMap<void>(getDOMSVGObjectWithContextMap()); -#endif -} - -} // namespace WebCore |