diff options
Diffstat (limited to 'WebCore/bindings/v8/V8DOMMap.cpp')
-rw-r--r-- | WebCore/bindings/v8/V8DOMMap.cpp | 322 |
1 files changed, 100 insertions, 222 deletions
diff --git a/WebCore/bindings/v8/V8DOMMap.cpp b/WebCore/bindings/v8/V8DOMMap.cpp index 4645c02..2d6639f 100644 --- a/WebCore/bindings/v8/V8DOMMap.cpp +++ b/WebCore/bindings/v8/V8DOMMap.cpp @@ -31,19 +31,14 @@ #include "config.h" #include "V8DOMMap.h" +#include "DOMData.h" +#include "DOMDataStore.h" #include "DOMObjectsInclude.h" - -#include <v8.h> -#include <wtf/HashMap.h> -#include <wtf/MainThread.h> -#include <wtf/Noncopyable.h> -#include <wtf/StdLibExtras.h> -#include <wtf/Threading.h> -#include <wtf/ThreadSpecific.h> -#include <wtf/Vector.h> +#include "ScopedDOMDataStore.h" namespace WebCore { +#ifdef MANUAL_MERGE_REQUIRED // DOM binding algorithm: // // There are two kinds of DOM objects: @@ -289,291 +284,174 @@ template<typename T> static void handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMWrapperMapType mapType, V8ClassIndex::V8WrapperType objectType, T*); ThreadSpecificDOMData& getThreadSpecificDOMData() +#else // MANUAL_MERGE_REQUIRED +DOMDataStoreHandle::DOMDataStoreHandle() + : m_store(new ScopedDOMDataStore(DOMData::getCurrent())) +#endif // MANUAL_MERGE_REQUIRED { - if (WTF::isMainThread()) { - DEFINE_STATIC_LOCAL(MainThreadSpecificDOMData, mainThreadSpecificDOMData, ()); - return mainThreadSpecificDOMData; - } - return *threadSpecificDOMData; } -template <class KeyType> -void ThreadSpecificDOMData::InternalDOMWrapperMap<KeyType>::forget(KeyType* object) +DOMDataStoreHandle::~DOMDataStoreHandle() { - DOMWrapperMap<KeyType>::forget(object); - - ThreadSpecificDOMData::DelayedObjectMap& delayedObjectMap = getThreadSpecificDOMData().delayedObjectMap(); - delayedObjectMap.take(object); } DOMWrapperMap<Node>& getDOMNodeMap() { - return getThreadSpecificDOMData().domNodeMap(); + // Nodes only exist on the main thread. + return DOMData::getCurrentMainThread()->getStore().domNodeMap(); } DOMWrapperMap<void>& getDOMObjectMap() { - return getThreadSpecificDOMData().domObjectMap(); + return DOMData::getCurrent()->getStore().domObjectMap(); } DOMWrapperMap<void>& getActiveDOMObjectMap() { - return getThreadSpecificDOMData().activeDomObjectMap(); + return DOMData::getCurrent()->getStore().activeDomObjectMap(); } #if ENABLE(SVG) -DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap() -{ - return getThreadSpecificDOMData().domSvgElementInstanceMap(); -} -static void weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject) +DOMWrapperMap<SVGElementInstance>& getDOMSVGElementInstanceMap() { - SVGElementInstance* instance = static_cast<SVGElementInstance*>(domObject); - - 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); + return DOMData::getCurrent()->getStore().domSvgElementInstanceMap(); } // Map of SVG objects with contexts to V8 objects DOMWrapperMap<void>& getDOMSVGObjectWithContextMap() { - return getThreadSpecificDOMData().domSvgObjectWithContextMap(); + return DOMData::getCurrent()->getStore().domSvgObjectWithContextMap(); } -static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject) -{ - v8::HandleScope scope; - ASSERT(v8Object->IsObject()); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(v8Object)); - - ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getDOMSVGObjectWithContextMap()); - if (map.contains(domObject)) { - // The forget function removes object from the map and disposes the wrapper. - map.forgetOnly(domObject); - - switch (type) { -#define MakeCase(type, name) \ - case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break; - SVG_OBJECT_TYPES(MakeCase) -#undef MakeCase -#define MakeCase(type, name) \ - case V8ClassIndex::type: \ - static_cast<V8SVGPODTypeWrapper<name>*>(domObject)->deref(); break; - SVG_POD_NATIVE_TYPES(MakeCase) -#undef MakeCase - default: - ASSERT_NOT_REACHED(); - break; - } - } else - handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMSVGObjectWithContextMap, type, domObject); -} #endif // ENABLE(SVG) -// 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 objectType, T* object) +static void removeAllDOMObjectsInCurrentThreadHelper() { - WTF::MutexLocker locker(domDataListMutex()); - DOMDataList& list = domDataList(); - for (size_t i = 0; i < list.size(); ++i) { - ThreadSpecificDOMData* threadData = list[i]; + v8::HandleScope scope; - ThreadSpecificDOMData::InternalDOMWrapperMap<T>* domMap = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<T>*>(threadData->getDOMWrapperMap(mapType)); - if (domMap->contains(object)) { - // Clear the JS reference. - domMap->forgetOnly(object); + // Deref all objects in the delayed queue. + DOMData::getCurrent()->derefDelayedObjects(); - // Push into the delayed queue. - threadData->delayedObjectMap().set(object, objectType); + // The DOM objects with the following types only exist on the main thread. + if (WTF::isMainThread()) { + // Remove all DOM nodes. + DOMData::removeObjectsFromWrapperMap<Node>(getDOMNodeMap()); - // Post a task to the owning thread in order to process the delayed queue. - // 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. - if (!threadData->delayedProcessingScheduled()) { - threadData->setDelayedProcessingScheduled(true); - if (threadData->isMainThread()) - WTF::callOnMainThread(&derefDelayedObjectsInCurrentThread, 0); - } +#if ENABLE(SVG) + // Remove all SVG element instances in the wrapper map. + DOMData::removeObjectsFromWrapperMap<SVGElementInstance>(getDOMSVGElementInstanceMap()); - break; - } + // Remove all SVG objects with context in the wrapper map. + DOMData::removeObjectsFromWrapperMap<void>(getDOMSVGObjectWithContextMap()); +#endif } -} - -// Called when the object 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> v8Object, void* domObject) -{ - v8::HandleScope scope; - ASSERT(v8Object->IsObject()); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(v8Object)); - ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getDOMObjectMap()); - if (map.contains(domObject)) { - // The forget function removes object from the map and disposes the wrapper. - map.forgetOnly(domObject); + // Remove all DOM objects in the wrapper map. + DOMData::removeObjectsFromWrapperMap<void>(getDOMObjectMap()); - switch (type) { -#define MakeCase(type, name) \ - case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break; - DOM_OBJECT_TYPES(MakeCase) -#undef MakeCase - default: - ASSERT_NOT_REACHED(); - break; - } - } else - handleWeakObjectInOwningThread(ThreadSpecificDOMData::DOMObjectMap, type, domObject); + // Remove all active DOM objects in the wrapper map. + DOMData::removeObjectsFromWrapperMap<void>(getActiveDOMObjectMap()); } -void weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject) +void removeAllDOMObjectsInCurrentThread() { - v8::HandleScope scope; - ASSERT(v8Object->IsObject()); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(v8Object)); - - ThreadSpecificDOMData::InternalDOMWrapperMap<void>& map = static_cast<ThreadSpecificDOMData::InternalDOMWrapperMap<void>&>(getActiveDOMObjectMap()); - if (map.contains(domObject)) { - // The forget function removes object from the map and disposes the wrapper. - map.forgetOnly(domObject); - - switch (type) { -#define MakeCase(type, name) \ - case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break; - ACTIVE_DOM_OBJECT_TYPES(MakeCase) -#undef MakeCase - default: - ASSERT_NOT_REACHED(); - break; - } + // Use the locker only if it has already been invoked before, as by worker thread. + if (v8::Locker::IsActive()) { + v8::Locker locker; + removeAllDOMObjectsInCurrentThreadHelper(); } else - handleWeakObjectInOwningThread(ThreadSpecificDOMData::ActiveDOMObjectMap, type, domObject); + removeAllDOMObjectsInCurrentThreadHelper(); } -static void weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject) + +void visitDOMNodesInCurrentThread(DOMWrapperMap<Node>::Visitor* visitor) { - Node* node = static_cast<Node*>(domObject); + v8::HandleScope scope; - 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); + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataList& list = DOMDataStore::allStores(); + for (size_t i = 0; i < list.size(); ++i) { + DOMDataStore* store = list[i]; + if (!store->domData()->owningThread() == WTF::currentThread()) + continue; + + HashMap<Node*, v8::Object*>& map = store->domNodeMap().impl(); + for (HashMap<Node*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it) + visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second)); + } } -static void derefObject(V8ClassIndex::V8WrapperType type, void* domObject) +void visitDOMObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor) { - switch (type) { - case V8ClassIndex::NODE: - static_cast<Node*>(domObject)->deref(); - break; - -#define MakeCase(type, name) \ - case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break; - DOM_OBJECT_TYPES(MakeCase) // This includes both active and non-active. -#undef MakeCase + v8::HandleScope scope; -#if ENABLE(SVG) -#define MakeCase(type, name) \ - case V8ClassIndex::type: static_cast<name*>(domObject)->deref(); break; - SVG_OBJECT_TYPES(MakeCase) // This also includes SVGElementInstance. -#undef MakeCase - -#define MakeCase(type, name) \ - case V8ClassIndex::type: \ - static_cast<V8SVGPODTypeWrapper<name>*>(domObject)->deref(); break; - SVG_POD_NATIVE_TYPES(MakeCase) -#undef MakeCase -#endif + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataList& list = DOMDataStore::allStores(); + for (size_t i = 0; i < list.size(); ++i) { + DOMDataStore* store = list[i]; + if (!store->domData()->owningThread() == WTF::currentThread()) + continue; - default: - ASSERT_NOT_REACHED(); - break; + HashMap<void*, v8::Object*> & map = store->domObjectMap().impl(); + for (HashMap<void*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it) + visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second)); } } -static void derefDelayedObjects() +void visitActiveDOMObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor) { - WTF::MutexLocker locker(domDataListMutex()); + v8::HandleScope scope; - getThreadSpecificDOMData().setDelayedProcessingScheduled(false); + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataList& list = DOMDataStore::allStores(); + for (size_t i = 0; i < list.size(); ++i) { + DOMDataStore* store = list[i]; + if (!store->domData()->owningThread() == WTF::currentThread()) + continue; - ThreadSpecificDOMData::DelayedObjectMap& delayedObjectMap = getThreadSpecificDOMData().delayedObjectMap(); - for (ThreadSpecificDOMData::DelayedObjectMap::iterator iter(delayedObjectMap.begin()); iter != delayedObjectMap.end(); ++iter) { - derefObject(iter->second, iter->first); + HashMap<void*, v8::Object*>& map = store->activeDomObjectMap().impl(); + for (HashMap<void*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it) + visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second)); } - delayedObjectMap.clear(); } -static void derefDelayedObjectsInCurrentThread(void*) -{ - derefDelayedObjects(); -} +#if ENABLE(SVG) -template<typename T> -static void removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap) +void visitDOMSVGElementInstancesInCurrentThread(DOMWrapperMap<SVGElementInstance>::Visitor* visitor) { - for (typename WTF::HashMap<T*, v8::Object*>::iterator iter(domMap.impl().begin()); iter != domMap.impl().end(); ++iter) { - T* domObject = static_cast<T*>(iter->first); - v8::Persistent<v8::Object> v8Object(iter->second); - - V8ClassIndex::V8WrapperType type = V8Proxy::GetDOMWrapperType(v8::Handle<v8::Object>::Cast(v8Object)); + v8::HandleScope scope; - // Deref the DOM object. - derefObject(type, domObject); + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataList& list = DOMDataStore::allStores(); + for (size_t i = 0; i < list.size(); ++i) { + DOMDataStore* store = list[i]; + if (!store->domData()->owningThread() == WTF::currentThread()) + continue; - // Clear the JS wrapper. - v8Object.Dispose(); + HashMap<SVGElementInstance*, v8::Object*> & map = store->domSvgElementInstanceMap().impl(); + for (HashMap<SVGElementInstance*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it) + visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second)); } - domMap.impl().clear(); } -static void removeAllDOMObjectsInCurrentThreadHelper() +void visitSVGObjectsInCurrentThread(DOMWrapperMap<void>::Visitor* visitor) { 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()); + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataList& list = DOMDataStore::allStores(); + for (size_t i = 0; i < list.size(); ++i) { + DOMDataStore* store = list[i]; + if (!store->domData()->owningThread() == WTF::currentThread()) + continue; - // Remove all SVG objects with context in the wrapper map. - removeObjectsFromWrapperMap<void>(getDOMSVGObjectWithContextMap()); -#endif + HashMap<void*, v8::Object*>& map = store->domSvgObjectWithContextMap().impl(); + for (HashMap<void*, v8::Object*>::iterator it = map.begin(); it != map.end(); ++it) + visitor->visitDOMWrapper(it->first, v8::Persistent<v8::Object>(it->second)); + } } -void removeAllDOMObjectsInCurrentThread() -{ - // Use the locker only if it has already been invoked before, as by worker thread. - if (v8::Locker::IsActive()) { - v8::Locker locker; - removeAllDOMObjectsInCurrentThreadHelper(); - } else - removeAllDOMObjectsInCurrentThreadHelper(); -} +#endif } // namespace WebCore |