/platform/external/webkit/WebCore/bindings/v8/DOMDataStore.cpp
https://github.com/aharish/totoro-gb-opensource-update2 · C++ · 209 lines · 110 code · 23 blank · 76 comment · 7 complexity · 0dd5080bfc0b839dee29c04f24dce0e5 MD5 · raw file
- /*
- * 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)
- , m_domSvgObjectWithContextMap(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::forgetDelayedObject(DOMData* domData, void* object)
- {
- domData->forgetDelayedObject(object);
- }
- 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;
- case DOMSVGObjectWithContextMap:
- return m_domSvgObjectWithContextMap;
- #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
- break; // There might be at most one wrapper for the node in world's maps
- }
- }
- }
- 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));
- }
- void DOMDataStore::weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject)
- {
- v8::HandleScope scope;
- ASSERT(v8Object->IsObject());
- DOMData::handleWeakObject(DOMDataStore::DOMSVGObjectWithContextMap, v8::Persistent<v8::Object>::Cast(v8Object), domObject);
- }
- #endif // ENABLE(SVG)
- } // namespace WebCore