Commit 2e1771cf authored by eric@webkit.org's avatar eric@webkit.org

2010-01-27 Anton Muhin <antonm@google.com>

        Review by Adam Barth.

        Implement Node map in intrusive way for better speed.
        https://bugs.webkit.org/show_bug.cgi?id=33957

        * bindings/v8/DOMData.h:
        (WebCore::DOMData::removeObjectsFromWrapperMap):
        * bindings/v8/DOMDataStore.cpp:
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::get):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::set):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::removeIfPresent):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::contains):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::visit):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::clear):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::allocateTableEntry):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::freeTableEntry):
        * bindings/v8/DOMDataStore.h:
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::IntrusiveDOMWrapperMap):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::clearEntry):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::clearEntries):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::visitEntries):
        (WebCore::DOMDataStore::IntrusiveDOMWrapperMap::TableChunk::TableChunk):
        (WebCore::DOMDataStore::domNodeMap):
        * bindings/v8/StaticDOMDataStore.cpp:
        (WebCore::StaticDOMDataStore::StaticDOMDataStore):
        * bindings/v8/StaticDOMDataStore.h:
        * bindings/v8/V8DOMMap.cpp:
        (WebCore::getDOMNodeMap):
        * bindings/v8/V8DOMMap.h:
        (WebCore::AbstractWeakReferenceMap::AbstractWeakReferenceMap):
        (WebCore::AbstractWeakReferenceMap::weakReferenceCallback):
        (WebCore::WeakReferenceMap::WeakReferenceMap):
        (WebCore::WeakReferenceMap::set):
        (WebCore::WeakReferenceMap::visit):
        * bindings/v8/V8DOMWrapper.cpp:
        (WebCore::V8DOMWrapper::convertDocumentToV8Object):
        (WebCore::getWrapper):
        (WebCore::V8DOMWrapper::convertNodeToV8Object):
        (WebCore::V8DOMWrapper::convertNewNodeToV8Object):
        * bindings/v8/V8DOMWrapper.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@53944 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0ce9774c
2010-01-27 Anton Muhin <antonm@google.com>
Review by Adam Barth.
Implement Node map in intrusive way for better speed.
https://bugs.webkit.org/show_bug.cgi?id=33957
* bindings/v8/DOMData.h:
(WebCore::DOMData::removeObjectsFromWrapperMap):
* bindings/v8/DOMDataStore.cpp:
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::get):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::set):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::removeIfPresent):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::contains):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::visit):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::clear):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::allocateTableEntry):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::freeTableEntry):
* bindings/v8/DOMDataStore.h:
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::IntrusiveDOMWrapperMap):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::clearEntry):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::clearEntries):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::visitEntries):
(WebCore::DOMDataStore::IntrusiveDOMWrapperMap::TableChunk::TableChunk):
(WebCore::DOMDataStore::domNodeMap):
* bindings/v8/StaticDOMDataStore.cpp:
(WebCore::StaticDOMDataStore::StaticDOMDataStore):
* bindings/v8/StaticDOMDataStore.h:
* bindings/v8/V8DOMMap.cpp:
(WebCore::getDOMNodeMap):
* bindings/v8/V8DOMMap.h:
(WebCore::AbstractWeakReferenceMap::AbstractWeakReferenceMap):
(WebCore::AbstractWeakReferenceMap::weakReferenceCallback):
(WebCore::WeakReferenceMap::WeakReferenceMap):
(WebCore::WeakReferenceMap::set):
(WebCore::WeakReferenceMap::visit):
* bindings/v8/V8DOMWrapper.cpp:
(WebCore::V8DOMWrapper::convertDocumentToV8Object):
(WebCore::getWrapper):
(WebCore::V8DOMWrapper::convertNodeToV8Object):
(WebCore::V8DOMWrapper::convertNewNodeToV8Object):
* bindings/v8/V8DOMWrapper.h:
2010-01-27 Kinuko Yasuda <kinuko@chromium.org>
Reviewed by Eric Seidel.
......@@ -62,7 +62,7 @@ namespace WebCore {
void derefDelayedObjects();
template<typename T>
static void removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap);
static void removeObjectsFromWrapperMap(AbstractWeakReferenceMap<T, v8::Object>& domMap);
ThreadIdentifier owningThread() const { return m_owningThread; }
......@@ -113,7 +113,7 @@ namespace WebCore {
}
template<typename T>
void DOMData::removeObjectsFromWrapperMap(DOMWrapperMap<T>& domMap)
void DOMData::removeObjectsFromWrapperMap(AbstractWeakReferenceMap<T, v8::Object>& domMap)
{
WrapperMapObjectRemover<T> remover;
domMap.visit(&remover);
......
......@@ -174,6 +174,20 @@ void DOMDataStore::weakNodeCallback(v8::Persistent<v8::Value> v8Object, void* do
}
}
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)
......
......@@ -32,6 +32,7 @@
#define DOMDataStore_h
#include "DOMObjectsInclude.h"
#include "V8Node.h"
#include <v8.h>
#include <wtf/HashMap.h>
......@@ -49,6 +50,95 @@ namespace WebCore {
typedef WTF::Vector<DOMDataStore*> DOMDataList;
template <class T, int CHUNK_SIZE, class Traits>
class ChunkedTable {
public:
ChunkedTable() : m_chunks(0), m_current(0), m_last(0) { }
T* add(T element)
{
if (m_current == m_last) {
m_chunks = new Chunk(m_chunks);
m_current = m_chunks->m_entries;
m_last = m_current + CHUNK_SIZE;
}
ASSERT((m_chunks->m_entries <= m_current) && (m_current < m_last));
T* p = m_current++;
*p = element;
return p;
}
void remove(T* element)
{
ASSERT(element);
ASSERT(m_current > m_chunks->m_entries);
m_current--;
if (element != m_current)
Traits::move(element, m_current);
if (m_current == m_chunks->m_entries) {
Chunk* toDelete = m_chunks;
m_chunks = toDelete->m_previous;
m_current = m_last = m_chunks ? m_chunks->m_entries + CHUNK_SIZE : 0;
delete toDelete;
}
ASSERT(!m_chunks || ((m_chunks->m_entries < m_current) && (m_current <= m_last)));
}
void clear()
{
if (!m_chunks)
return;
clearEntries(m_chunks->m_entries, m_current);
Chunk* last = m_chunks;
while (true) {
Chunk* previous = last->m_previous;
if (!previous)
break;
delete last;
clearEntries(previous->m_entries, previous->m_entries + CHUNK_SIZE);
last = previous;
}
m_chunks = last;
m_current = m_chunks->m_entries;
m_last = m_current + CHUNK_SIZE;
}
void visit(typename Traits::Visitor* visitor)
{
if (!m_chunks)
return;
visitEntries(m_chunks->m_entries, m_current, visitor);
for (Chunk* chunk = m_chunks->m_previous; chunk; chunk = chunk->m_previous)
visitEntries(chunk->m_entries, chunk->m_entries + CHUNK_SIZE, visitor);
}
private:
struct Chunk {
explicit Chunk(Chunk* previous) : m_previous(previous) { }
Chunk* const m_previous;
T m_entries[CHUNK_SIZE];
};
static void clearEntries(T* first, T* last)
{
for (T* entry = first; entry < last; entry++)
Traits::clear(entry);
}
static void visitEntries(T* first, T* last, typename Traits::Visitor* visitor)
{
for (T* entry = first; entry < last; entry++)
Traits::visit(entry, visitor);
}
Chunk* m_chunks;
T* m_current;
T* m_last;
};
// DOMDataStore
//
// DOMDataStore is the backing store that holds the maps between DOM objects
......@@ -86,6 +176,79 @@ namespace WebCore {
DOMData* m_domData;
};
class IntrusiveDOMWrapperMap : public AbstractWeakReferenceMap<Node, v8::Object> {
public:
IntrusiveDOMWrapperMap(v8::WeakReferenceCallback callback)
: AbstractWeakReferenceMap<Node, v8::Object>(callback) { }
virtual v8::Persistent<v8::Object> get(Node* obj)
{
v8::Persistent<v8::Object>* wrapper = obj->wrapper();
return wrapper ? *wrapper : v8::Persistent<v8::Object>();
}
virtual void set(Node* obj, v8::Persistent<v8::Object> wrapper)
{
ASSERT(obj);
ASSERT(!obj->wrapper());
v8::Persistent<v8::Object>* entry = m_table.add(wrapper);
obj->setWrapper(entry);
wrapper.MakeWeak(obj, weakReferenceCallback());
}
virtual bool contains(Node* obj)
{
return obj->wrapper();
}
virtual void visit(Visitor* visitor)
{
m_table.visit(visitor);
}
virtual bool removeIfPresent(Node* key, v8::Persistent<v8::Data> value);
virtual void clear()
{
m_table.clear();
}
private:
static int const numberOfEntries = (1 << 10) - 1;
struct ChunkedTableTraits {
typedef IntrusiveDOMWrapperMap::Visitor Visitor;
static void move(v8::Persistent<v8::Object>* target, v8::Persistent<v8::Object>* source)
{
*target = *source;
Node* node = V8Node::toNative(*target);
ASSERT(node);
node->setWrapper(target);
}
static void clear(v8::Persistent<v8::Object>* entry)
{
Node* node = V8Node::toNative(*entry);
ASSERT(node->wrapper() == entry);
node->clearWrapper();
entry->Dispose();
}
static void visit(v8::Persistent<v8::Object>* entry, Visitor* visitor)
{
Node* node = V8Node::toNative(*entry);
ASSERT(node->wrapper() == entry);
visitor->visitDOMWrapper(node, *entry);
}
};
typedef ChunkedTable<v8::Persistent<v8::Object>, numberOfEntries, ChunkedTableTraits> Table;
Table m_table;
};
DOMDataStore(DOMData*);
virtual ~DOMDataStore();
......@@ -102,7 +265,7 @@ namespace WebCore {
void* getDOMWrapperMap(DOMWrapperMapType);
InternalDOMWrapperMap<Node>& domNodeMap() { return *m_domNodeMap; }
DOMNodeMapping& domNodeMap() { return *m_domNodeMap; }
InternalDOMWrapperMap<void>& domObjectMap() { return *m_domObjectMap; }
InternalDOMWrapperMap<void>& activeDomObjectMap() { return *m_activeDomObjectMap; }
#if ENABLE(SVG)
......@@ -122,7 +285,7 @@ namespace WebCore {
static void weakSVGObjectWithContextCallback(v8::Persistent<v8::Value> v8Object, void* domObject);
#endif
InternalDOMWrapperMap<Node>* m_domNodeMap;
DOMNodeMapping* m_domNodeMap;
InternalDOMWrapperMap<void>* m_domObjectMap;
InternalDOMWrapperMap<void>* m_activeDomObjectMap;
#if ENABLE(SVG)
......
......@@ -35,7 +35,7 @@ namespace WebCore {
StaticDOMDataStore::StaticDOMDataStore(DOMData* domData)
: DOMDataStore(domData)
, m_staticDomNodeMap(domData, &DOMDataStore::weakNodeCallback)
, m_staticDomNodeMap(&DOMDataStore::weakNodeCallback)
, m_staticDomObjectMap(domData, &DOMDataStore::weakDOMObjectCallback)
, m_staticActiveDomObjectMap(domData, &DOMDataStore::weakActiveDOMObjectCallback)
#if ENABLE(SVG)
......
......@@ -48,7 +48,7 @@ public:
StaticDOMDataStore(DOMData*);
private:
InternalDOMWrapperMap<Node> m_staticDomNodeMap;
IntrusiveDOMWrapperMap m_staticDomNodeMap;
InternalDOMWrapperMap<void> m_staticDomObjectMap;
InternalDOMWrapperMap<void> m_staticActiveDomObjectMap;
#if ENABLE(SVG)
......
......@@ -65,7 +65,7 @@ void enableFasterDOMStoreAccess()
fasterDOMStoreAccess = true;
}
DOMWrapperMap<Node>& getDOMNodeMap()
DOMNodeMapping& getDOMNodeMap()
{
return getDOMDataStore().domNodeMap();
}
......
......@@ -41,12 +41,36 @@ namespace WebCore {
class SVGElementInstance;
#endif
template <class KeyType, class ValueType> class AbstractWeakReferenceMap {
public:
AbstractWeakReferenceMap(v8::WeakReferenceCallback callback) : m_weakReferenceCallback(callback) { }
class Visitor {
public:
virtual void visitDOMWrapper(KeyType* key, v8::Persistent<ValueType> object) = 0;
};
virtual v8::Persistent<ValueType> get(KeyType* obj) = 0;
virtual void set(KeyType* obj, v8::Persistent<ValueType> wrapper) = 0;
virtual bool contains(KeyType* obj) = 0;
virtual void visit(Visitor* visitor) = 0;
virtual bool removeIfPresent(KeyType* key, v8::Persistent<v8::Data> value) = 0;
virtual void clear() = 0;
v8::WeakReferenceCallback weakReferenceCallback() { return m_weakReferenceCallback; }
private:
v8::WeakReferenceCallback m_weakReferenceCallback;
};
typedef AbstractWeakReferenceMap<Node, v8::Object> DOMNodeMapping;
// A table of wrappers with weak pointers.
// This table allows us to avoid track wrapped objects for debugging
// and for ensuring that we don't double wrap the same object.
template<class KeyType, class ValueType> class WeakReferenceMap {
template<class KeyType, class ValueType> class WeakReferenceMap : public AbstractWeakReferenceMap<KeyType, ValueType> {
public:
WeakReferenceMap(v8::WeakReferenceCallback callback) : m_weakReferenceCallback(callback) { }
typedef AbstractWeakReferenceMap<KeyType, ValueType> Parent;
WeakReferenceMap(v8::WeakReferenceCallback callback) : Parent(callback) { }
virtual ~WeakReferenceMap()
{
#ifndef NDEBUG
......@@ -65,7 +89,7 @@ namespace WebCore {
virtual void set(KeyType* obj, v8::Persistent<ValueType> wrapper)
{
ASSERT(!m_map.contains(obj));
wrapper.MakeWeak(obj, m_weakReferenceCallback);
wrapper.MakeWeak(obj, Parent::weakReferenceCallback());
m_map.set(obj, *wrapper);
}
......@@ -99,14 +123,7 @@ namespace WebCore {
bool contains(KeyType* obj) { return m_map.contains(obj); }
class Visitor {
public:
virtual void visitDOMWrapper(KeyType*, v8::Persistent<ValueType>) = 0;
protected:
virtual ~Visitor() { }
};
virtual void visit(Visitor* visitor)
virtual void visit(typename Parent::Visitor* visitor)
{
typename HashMap<KeyType*, ValueType*>::iterator it = m_map.begin();
for (; it != m_map.end(); ++it)
......@@ -139,7 +156,7 @@ namespace WebCore {
};
// A map from DOM node to its JS wrapper.
DOMWrapperMap<Node>& getDOMNodeMap();
DOMNodeMapping& getDOMNodeMap();
void visitDOMNodesInCurrentThread(DOMWrapperMap<Node>::Visitor*);
// A map from a DOM object (non-node) to its JS wrapper. This map does not contain the DOM objects which can have pending activity (active dom objects).
......
......@@ -32,6 +32,7 @@
#include "V8DOMWrapper.h"
#include "CSSMutableStyleDeclaration.h"
#include "DOMDataStore.h"
#include "DOMObjectsInclude.h"
#include "DocumentLoader.h"
#include "FrameLoaderClient.h"
......@@ -1056,7 +1057,7 @@ v8::Handle<v8::Value> V8DOMWrapper::convertDocumentToV8Object(Document* document
if (proxy)
proxy->windowShell()->initContextIfNeeded();
DOMWrapperMap<Node>& domNodeMap = getDOMNodeMap();
DOMNodeMapping& domNodeMap = getDOMNodeMap();
v8::Handle<v8::Object> wrapper = domNodeMap.get(document);
if (wrapper.IsEmpty())
return convertNewNodeToV8Object(document, proxy, domNodeMap);
......@@ -1064,25 +1065,39 @@ v8::Handle<v8::Value> V8DOMWrapper::convertDocumentToV8Object(Document* document
return wrapper;
}
static v8::Handle<v8::Value> getWrapper(Node* node)
{
ASSERT(WTF::isMainThread());
V8IsolatedContext* context = V8IsolatedContext::getEntered();
if (LIKELY(!context)) {
v8::Persistent<v8::Object>* wrapper = node->wrapper();
if (!wrapper)
return v8::Handle<v8::Value>();
return *wrapper;
}
DOMNodeMapping& domNodeMap = context->world()->domDataStore()->domNodeMap();
return domNodeMap.get(node);
}
v8::Handle<v8::Value> V8DOMWrapper::convertNodeToV8Object(Node* node)
{
if (!node)
return v8::Null();
v8::Handle<v8::Value> wrapper = getWrapper(node);
if (!wrapper.IsEmpty())
return wrapper;
Document* document = node->document();
if (node == document)
return convertDocumentToV8Object(document);
DOMWrapperMap<Node>& domNodeMap = getDOMNodeMap();
v8::Handle<v8::Object> wrapper = domNodeMap.get(node);
if (wrapper.IsEmpty())
return convertNewNodeToV8Object(node, 0, domNodeMap);
return wrapper;
return convertNewNodeToV8Object(node, 0, getDOMNodeMap());
}
// Caller checks node is not null.
v8::Handle<v8::Value> V8DOMWrapper::convertNewNodeToV8Object(Node* node, V8Proxy* proxy, DOMWrapperMap<Node>& domNodeMap)
v8::Handle<v8::Value> V8DOMWrapper::convertNewNodeToV8Object(Node* node, V8Proxy* proxy, DOMNodeMapping& domNodeMap)
{
if (!proxy && node->document())
proxy = V8Proxy::retrieve(node->document()->frame());
......
......@@ -150,7 +150,7 @@ namespace WebCore {
return convertNewNodeToV8Object(node, 0, getDOMNodeMap());
}
static v8::Handle<v8::Value> convertNewNodeToV8Object(Node*, V8Proxy*, DOMWrapperMap<Node>&);
static v8::Handle<v8::Value> convertNewNodeToV8Object(Node*, V8Proxy*, DOMNodeMapping&);
static V8ClassIndex::V8WrapperType domWrapperType(v8::Handle<v8::Object>);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment