summaryrefslogtreecommitdiffstats
path: root/webkit
diff options
context:
space:
mode:
authorasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 18:17:25 +0000
committerasargent@chromium.org <asargent@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-26 18:17:25 +0000
commit2e0c886cbcc57aa775c23200e2037d680156d71d (patch)
treeb17984a1ef40384cef0121e977e09bad2f41097a /webkit
parent47e4e1a0e7c75a188c7494643b8cc6258c405452 (diff)
downloadchromium_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.cpp113
-rw-r--r--webkit/port/bindings/v8/v8_proxy.h34
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();