diff options
author | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-26 18:17:25 +0000 |
---|---|---|
committer | asargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-26 18:17:25 +0000 |
commit | 2e0c886cbcc57aa775c23200e2037d680156d71d (patch) | |
tree | b17984a1ef40384cef0121e977e09bad2f41097a /webkit | |
parent | 47e4e1a0e7c75a188c7494643b8cc6258c405452 (diff) | |
download | chromium_src-2e0c886cbcc57aa775c23200e2037d680156d71d.zip chromium_src-2e0c886cbcc57aa775c23200e2037d680156d71d.tar.gz chromium_src-2e0c886cbcc57aa775c23200e2037d680156d71d.tar.bz2 |
Speedup event performance by caching V8EventListener on the wrapped object.
Review URL: http://codereview.chromium.org/49026
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12574 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.cpp | 113 | ||||
-rw-r--r-- | webkit/port/bindings/v8/v8_proxy.h | 34 |
2 files changed, 120 insertions, 27 deletions
diff --git a/webkit/port/bindings/v8/v8_proxy.cpp b/webkit/port/bindings/v8/v8_proxy.cpp index d830c40..e105419 100644 --- a/webkit/port/bindings/v8/v8_proxy.cpp +++ b/webkit/port/bindings/v8/v8_proxy.cpp @@ -217,6 +217,90 @@ namespace WebCore { +V8EventListenerList::V8EventListenerList(const char* name) +{ + ASSERT(strlen(name) <= kMaxKeyNameLength); + v8::HandleScope handleScope; + + // Write the name into a temporary buffer, leaving 1 space at the beginning + // for a prefix we'll vary between the inline and non-inline keys. + char keyBuffer[kMaxKeyNameLength + 2] = { 0 }; + strncpy(keyBuffer + 1, name, kMaxKeyNameLength); + keyBuffer[0] = '1'; + m_inlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); + keyBuffer[0] = '2'; + m_nonInlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); +} + +V8EventListenerList::~V8EventListenerList() +{ + m_inlineKey.Dispose(); + m_nonInlineKey.Dispose(); +} + +V8EventListenerList::iterator V8EventListenerList::begin() +{ + return m_list.begin(); +} + +V8EventListenerList::iterator V8EventListenerList::end() +{ + return m_list.end(); +} + +v8::Handle<v8::String> V8EventListenerList::getKey(bool isInline) +{ + if (isInline) + return m_inlineKey; + else + return m_nonInlineKey; +} + +// See comment in .h file for this function, and update accordingly if +// implementation details change here. +void V8EventListenerList::add(V8EventListener* listener) +{ + m_list.append(listener); + + v8::HandleScope handleScope; + v8::Local<v8::Object> object = listener->getListenerObject(); + v8::Local<v8::Value> value = v8::External::Wrap(listener); + object->SetHiddenValue(getKey(listener->isInline()), value); +} + +void V8EventListenerList::remove(V8EventListener* listener) +{ + v8::HandleScope handleScope; + for (size_t i = 0; i < m_list.size(); i++) { + V8EventListener* element = m_list.at(i); + if (element->isInline() == listener->isInline() && element == listener) { + v8::Local<v8::Object> object = listener->getListenerObject(); + object->DeleteHiddenValue(getKey(listener->isInline())); + m_list.remove(i); + break; + } + } +} + +void V8EventListenerList::clear() +{ + v8::HandleScope handleScope; + for (size_t i = 0; i < m_list.size(); i++) { + V8EventListener* element = m_list.at(i); + v8::Local<v8::Object> object = element->getListenerObject(); + object->DeleteHiddenValue(getKey(element->isInline())); + } + m_list.clear(); +} + +V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isInline) +{ + v8::Local<v8::Value> value = object->GetHiddenValue(getKey(isInline)); + if (value.IsEmpty()) + return 0; + return reinterpret_cast<V8EventListener*>(v8::External::Unwrap(value)); +} + // DOM binding algorithm: // @@ -1185,21 +1269,7 @@ static V8EventListener* FindEventListenerInList(V8EventListenerList& list, if (!listener->IsObject()) return 0; - V8EventListenerList::iterator p = list.begin(); - while (p != list.end()) { - V8EventListener* el = *p; - v8::Local<v8::Object> wrapper = el->getListenerObject(); - ASSERT(!wrapper.IsEmpty()); - // Since the listener is an object, it is safe to compare for - // strict equality (in the JS sense) by doing a simple equality - // check using the == operator on the handles. This is much, - // much faster than calling StrictEquals through the API in - // the negative case. - if (el->isInline() == isInline && listener == wrapper) - return el; - ++p; - } - return 0; + return list.find(listener->ToObject(), isInline); } // Find an existing wrapper for a JS event listener in the map. @@ -1224,7 +1294,7 @@ PassRefPtr<V8EventListener> V8Proxy::FindOrCreateV8EventListener(v8::Local<v8::V // Create a new one, and add to cache. RefPtr<V8EventListener> new_listener = V8EventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline); - m_event_listeners.push_back(new_listener.get()); + m_event_listeners.add(new_listener.get()); return new_listener; } @@ -1272,7 +1342,7 @@ PassRefPtr<V8EventListener> V8Proxy::FindOrCreateObjectEventListener( // Create a new one, and add to cache. RefPtr<V8EventListener> new_listener = V8ObjectEventListener::create(m_frame, v8::Local<v8::Object>::Cast(obj), isInline); - m_xhr_listeners.push_back(new_listener.get()); + m_xhr_listeners.add(new_listener.get()); return new_listener.release(); } @@ -1281,14 +1351,7 @@ PassRefPtr<V8EventListener> V8Proxy::FindOrCreateObjectEventListener( static void RemoveEventListenerFromList(V8EventListenerList& list, V8EventListener* listener) { - V8EventListenerList::iterator p = list.begin(); - while (p != list.end()) { - if (*p == listener) { - list.erase(p); - return; - } - ++p; - } + list.remove(listener); } diff --git a/webkit/port/bindings/v8/v8_proxy.h b/webkit/port/bindings/v8/v8_proxy.h index e403751..df93c5d 100644 --- a/webkit/port/bindings/v8/v8_proxy.h +++ b/webkit/port/bindings/v8/v8_proxy.h @@ -73,7 +73,36 @@ class SVGElementInstance; class V8EventListener; class V8ObjectEventListener; -typedef std::list<V8EventListener*> V8EventListenerList; + +// This is a container for V8EventListener objects that also does some +// caching to speed up finding entries by v8::Object. +class V8EventListenerList { + public: + static const size_t kMaxKeyNameLength = 254; + // The name should be distinct from any other V8EventListenerList + // within the same process, and <= kMaxKeyNameLength characters. + explicit V8EventListenerList(const char* name); + ~V8EventListenerList(); + + typedef Vector<V8EventListener*>::iterator iterator; + V8EventListenerList::iterator begin(); + iterator end(); + + // In addition to adding the listener to this list, this also caches the + // V8EventListener as a hidden property on its wrapped v8 listener object, + // so we can quickly look it up later. + void add(V8EventListener*); + void remove(V8EventListener*); + V8EventListener* find(v8::Local<v8::Object>, bool isInline); + void clear(); + + private: + v8::Handle<v8::String> getKey(bool isInline); + v8::Persistent<v8::String> m_inlineKey; + v8::Persistent<v8::String> m_nonInlineKey; + Vector<V8EventListener*> m_list; +}; + // TODO(fqian): use standard logging facilities in WebCore. void log_info(Frame* frame, const String& msg, const String& url); @@ -169,7 +198,8 @@ class V8Proxy { }; explicit V8Proxy(Frame* frame) - : m_frame(frame), m_inlineCode(false), + : m_frame(frame), m_event_listeners("m_event_listeners"), + m_xhr_listeners("m_xhr_listeners"), m_inlineCode(false), m_timerCallback(false), m_recursion(0) { } ~V8Proxy(); |