diff options
author | Steve Block <steveblock@google.com> | 2011-05-06 11:45:16 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-05-12 13:44:10 +0100 |
commit | cad810f21b803229eb11403f9209855525a25d57 (patch) | |
tree | 29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/bindings/v8/DOMDataStore.cpp | |
parent | 121b0cf4517156d0ac5111caf9830c51b69bae8f (diff) | |
download | external_webkit-cad810f21b803229eb11403f9209855525a25d57.zip external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2 |
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/bindings/v8/DOMDataStore.cpp')
-rw-r--r-- | Source/WebCore/bindings/v8/DOMDataStore.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/Source/WebCore/bindings/v8/DOMDataStore.cpp b/Source/WebCore/bindings/v8/DOMDataStore.cpp new file mode 100644 index 0000000..0d37dc0 --- /dev/null +++ b/Source/WebCore/bindings/v8/DOMDataStore.cpp @@ -0,0 +1,199 @@ +/* + * 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 "DOMDataStore.h" + +#include "DOMData.h" + +namespace WebCore { + +// DOM binding algorithm: +// +// There are two kinds of DOM objects: +// 1. DOM tree nodes, such as Document, HTMLElement, ... +// there classes implement 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. + + +DOMDataStore::DOMDataStore(DOMData* domData) + : m_domNodeMap(0) + , m_domObjectMap(0) + , m_activeDomObjectMap(0) +#if ENABLE(SVG) + , m_domSvgElementInstanceMap(0) +#endif + , m_domData(domData) +{ + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataStore::allStores().append(this); +} + +DOMDataStore::~DOMDataStore() +{ + WTF::MutexLocker locker(DOMDataStore::allStoresMutex()); + DOMDataStore::allStores().remove(DOMDataStore::allStores().find(this)); +} + +DOMDataList& DOMDataStore::allStores() +{ + DEFINE_STATIC_LOCAL(DOMDataList, staticDOMDataList, ()); + return staticDOMDataList; +} + +WTF::Mutex& DOMDataStore::allStoresMutex() +{ + DEFINE_STATIC_LOCAL(WTF::Mutex, staticDOMDataListMutex, ()); + return staticDOMDataListMutex; +} + +void* DOMDataStore::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; +#endif + } + + ASSERT_NOT_REACHED(); + return 0; +} + +// 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. +void DOMDataStore::weakDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject) +{ + v8::HandleScope scope; + ASSERT(v8Object->IsObject()); + DOMData::handleWeakObject(DOMDataStore::DOMObjectMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject); +} + +void DOMDataStore::weakActiveDOMObjectCallback(v8::Persistent<v8::Value> v8Object, void* domObject) +{ + v8::HandleScope scope; + ASSERT(v8Object->IsObject()); + DOMData::handleWeakObject(DOMDataStore::ActiveDOMObjectMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject); +} + +void DOMDataStore::weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* domObject) +{ + ASSERT(WTF::isMainThread()); + + Node* node = static_cast<Node*>(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->domNodeMap().removeIfPresent(node, v8Object)) { + ASSERT(store->domData()->owningThread() == WTF::currentThread()); + node->deref(); // Nobody overrides Node::deref so it's safe + return; // There might be at most one wrapper for the node in world's maps + } + } + + // If not found, it means map for the wrapper has been already destroyed, just dispose the + // handle and deref the object to fight memory leak. + v8Object.Dispose(); + node->deref(); // Nobody overrides Node::deref so it's safe +} + +bool DOMDataStore::IntrusiveDOMWrapperMap::removeIfPresent(Node* obj, v8::Persistent<v8::Data> value) +{ + ASSERT(obj); + v8::Persistent<v8::Object>* entry = obj->wrapper(); + if (!entry) + return false; + if (*entry != value) + return false; + obj->clearWrapper(); + m_table.remove(entry); + value.Dispose(); + return true; +} + +#if ENABLE(SVG) + +void DOMDataStore::weakSVGElementInstanceCallback(v8::Persistent<v8::Value> v8Object, void* domObject) +{ + v8::HandleScope scope; + ASSERT(v8Object->IsObject()); + DOMData::handleWeakObject(DOMDataStore::DOMSVGElementInstanceMap, v8::Persistent<v8::Object>::Cast(v8Object), static_cast<SVGElementInstance*>(domObject)); +} + +#endif // ENABLE(SVG) + +} // namespace WebCore |