Changeset 43277 in webkit
- Timestamp:
- May 5, 2009, 10:23:30 PM (16 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r43275 r43277 1 2009-05-05 Antony Sargent <asargent@chromium.org> 2 3 Reviewed by Dimitri Glazkov. 4 5 Switch V8EventListenerList to use HashTable<T>. 6 https://bugs.webkit.org/show_bug.cgi?id=25496 7 8 This avoids some tricky issues with event listener removal in the 9 current implementation and has slightly better performance. 10 11 No new functionality so no new tests. 12 13 * bindings/v8/V8EventListenerList.cpp: Added V8EventListenerListIterator. 14 * bindings/v8/V8EventListenerList.h: 15 (WebCore::V8EventListenerList::size): 16 * bindings/v8/WorkerContextExecutionProxy.cpp: 17 (WebCore::WorkerContextExecutionProxy::initContextIfNeeded): 18 1 19 2009-05-05 Darin Fisher <darin@chromium.org> 2 20 -
trunk/WebCore/bindings/v8/V8EventListenerList.cpp
r42838 r43277 36 36 namespace WebCore { 37 37 38 V8EventListenerList::V8EventListenerList(const char* name) 38 V8EventListenerListIterator::V8EventListenerListIterator(V8EventListenerList* list) 39 : m_list(list) 40 , m_vectorIndex(0) 41 , m_iter(list->m_table.begin()) 39 42 { 40 ASSERT(strlen(name) <= maxKeyNameLength); 41 v8::HandleScope handleScope; 43 } 42 44 43 // Write the name into a temporary buffer, leaving 1 space at the beginning 44 // for a prefix we'll vary between the inline and non-inline keys. 45 char keyBuffer[maxKeyNameLength + 2] = { 0 }; 46 strncpy(keyBuffer + 1, name, maxKeyNameLength); 47 keyBuffer[0] = '1'; 48 m_inlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); 49 keyBuffer[0] = '2'; 50 m_nonInlineKey = v8::Persistent<v8::String>::New(v8::String::New(keyBuffer)); 45 V8EventListenerListIterator::V8EventListenerListIterator(V8EventListenerList* list, bool shouldSeekToEnd) 46 : m_list(list) 47 , m_vectorIndex(0) 48 , m_iter(list->m_table.begin()) 49 { 50 if (shouldSeekToEnd) 51 seekToEnd(); 52 } 53 54 V8EventListenerListIterator::~V8EventListenerListIterator() { } 55 56 void V8EventListenerListIterator::operator++() 57 { 58 if (m_iter != m_list->m_table.end()) { 59 Vector<V8EventListener*>* vector = m_iter->second; 60 if (m_vectorIndex + 1 < vector->size()) { 61 m_vectorIndex++; 62 return; 63 } 64 m_vectorIndex = 0; 65 ++m_iter; 66 } 67 } 68 69 bool V8EventListenerListIterator::operator==(const V8EventListenerListIterator& other) 70 { 71 return other.m_iter == m_iter && other.m_vectorIndex == m_vectorIndex && other.m_list == m_list; 72 } 73 74 bool V8EventListenerListIterator::operator!=(const V8EventListenerListIterator& other) 75 { 76 return !operator==(other); 77 } 78 79 V8EventListener* V8EventListenerListIterator::operator*() 80 { 81 if (m_iter != m_list->m_table.end()) { 82 Vector<V8EventListener*>* vector = m_iter->second; 83 if (m_vectorIndex < vector->size()) 84 return vector->at(m_vectorIndex); 85 } 86 return 0; 87 } 88 89 void V8EventListenerListIterator::seekToEnd() 90 { 91 m_iter = m_list->m_table.end(); 92 m_vectorIndex = 0; 93 } 94 95 96 V8EventListenerList::V8EventListenerList() 97 { 51 98 } 52 99 53 100 V8EventListenerList::~V8EventListenerList() 54 101 { 55 m_inlineKey.Dispose();56 m_nonInlineKey.Dispose();57 102 } 58 103 59 V8EventListenerList ::iterator V8EventListenerList::begin()104 V8EventListenerListIterator V8EventListenerList::begin() 60 105 { 61 return m_list.begin();106 return iterator(this); 62 107 } 63 108 64 V8EventListenerList ::iterator V8EventListenerList::end()109 V8EventListenerListIterator V8EventListenerList::end() 65 110 { 66 return m_list.end();111 return iterator(this, true); 67 112 } 68 113 69 v8::Handle<v8::String> V8EventListenerList::getKey(bool isInline) 114 115 static int getKey(v8::Local<v8::Object> object) 70 116 { 71 return isInline ? m_inlineKey : m_nonInlineKey; 117 // 0 is a sentinel value for the HashMap key, so we map it to 1. 118 int hash = object->GetIdentityHash(); 119 if (!hash) 120 return 1; 121 return hash; 72 122 } 73 123 74 // See comment in .h file for this function, and update accordingly if implementation details change here.75 124 void V8EventListenerList::add(V8EventListener* listener) 76 125 { 77 126 ASSERT(v8::Context::InContext()); 78 m_list.append(listener);127 v8::HandleScope handleScope; 79 128 80 v8::HandleScope handleScope;81 129 v8::Local<v8::Object> object = listener->getListenerObject(); 82 v8::Local<v8::Value> value = v8::External::Wrap(listener); 83 object->SetHiddenValue(getKey(listener->isAttribute()), value); 130 int key = getKey(object); 131 Vector<V8EventListener*>* vector = m_table.get(key); 132 if (!vector) { 133 vector = new Vector<V8EventListener*>(); 134 m_table.set(key, vector); 135 } 136 vector->append(listener); 137 m_reverseTable.set(listener, key); 84 138 } 85 139 86 140 void V8EventListenerList::remove(V8EventListener* listener) 87 141 { 88 ASSERT(v8::Context::InContext()); 89 v8::HandleScope handleScope; 90 v8::Handle<v8::String> key = getKey(listener->isAttribute()); 91 for (size_t i = 0; i < m_list.size(); i++) { 92 V8EventListener* element = m_list.at(i); 93 if (element->isAttribute() == listener->isAttribute() && element == listener) { 94 v8::Local<v8::Object> object = listener->getListenerObject(); 142 if (m_reverseTable.contains(listener)) { 143 int key = m_reverseTable.get(listener); 144 Vector<V8EventListener*>* vector = m_table.get(key); 145 if (!vector) 146 return; 147 for (size_t j = 0; j < vector->size(); j++) { 148 if (vector->at(j) == listener) { 149 vector->remove(j); 150 if (!vector->size()) 151 m_table.remove(key); 95 152 96 // FIXME(asargent) this check for hidden value being !empty is a workaround for 97 // http://code.google.com/p/v8/issues/detail?id=300 98 // Once the fix for that is pulled into chromium we can remove the check here. 99 if (!object->GetHiddenValue(key).IsEmpty()) 100 object->DeleteHiddenValue(getKey(listener->isAttribute())); 101 m_list.remove(i); 102 break; 153 m_reverseTable.remove(listener); 154 return; 155 } 103 156 } 104 157 } … … 107 160 void V8EventListenerList::clear() 108 161 { 109 ASSERT(v8::Context::InContext()); 110 v8::HandleScope handleScope; 111 for (size_t i = 0; i < m_list.size(); i++) { 112 V8EventListener* element = m_list.at(i); 113 v8::Local<v8::Object> object = element->getListenerObject(); 114 object->DeleteHiddenValue(getKey(element->isAttribute())); 115 } 116 m_list.clear(); 162 m_table.clear(); 163 m_reverseTable.clear(); 117 164 } 118 165 119 V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool is Inline)166 V8EventListener* V8EventListenerList::find(v8::Local<v8::Object> object, bool isAttribute) 120 167 { 121 v8::Local<v8::Value> value = object->GetHiddenValue(getKey(isInline)); 122 if (value.IsEmpty()) 168 ASSERT(v8::Context::InContext()); 169 int key = getKey(object); 170 171 Vector<V8EventListener*>* vector = m_table.get(key); 172 if (!vector) 123 173 return 0; 124 return reinterpret_cast<V8EventListener*>(v8::External::Unwrap(value)); 174 175 for (size_t i = 0; i < vector->size(); i++) { 176 V8EventListener* element = vector->at(i); 177 if (isAttribute == element->isAttribute() && object == element->getListenerObject()) 178 return element; 179 } 180 return 0; 125 181 } 126 182 -
trunk/WebCore/bindings/v8/V8EventListenerList.h
r42510 r43277 34 34 #include <v8.h> 35 35 #include <wtf/Vector.h> 36 #include <wtf/HashMap.h> 36 37 37 38 namespace WebCore { 38 39 class V8EventListener; 40 class V8EventListenerListIterator; 39 41 40 // This is a container for V8EventListener objects that also does some caching to speed up finding entries by v8::Object. 42 // This is a container for V8EventListener objects that uses the identity hash of the v8::Object to 43 // speed up lookups 41 44 class V8EventListenerList { 42 45 public: 43 static const size_t maxKeyNameLength = 254; 46 // Because v8::Object identity hashes are not guaranteed to be unique, we unfortunately can't just map 47 // an int to V8EventListener. Instead we define a HashMap of int to Vector of V8EventListener 48 // called a ListenerMultiMap. 49 typedef Vector<V8EventListener*>* Values; 50 struct ValuesTraits : HashTraits<Values> { 51 static const bool needsDestruction = true; 52 }; 53 typedef HashMap<int, Values, DefaultHash<int>::Hash, HashTraits<int>, ValuesTraits> ListenerMultiMap; 44 54 45 // The name should be distinct from any other V8EventListenerList within the same process, and <= maxKeyNameLength characters. 46 explicit V8EventListenerList(const char* name); 55 V8EventListenerList(); 47 56 ~V8EventListenerList(); 48 57 49 typedef Vector<V8EventListener*>::iterator iterator; 50 V8EventListenerList::iterator begin(); 58 friend class V8EventListenerListIterator; 59 typedef V8EventListenerListIterator iterator; 60 61 iterator begin(); 51 62 iterator end(); 52 63 53 // In addition to adding the listener to this list, this also caches the V8EventListener as a hidden property on its wrapped54 // v8 listener object, so we can quickly look it up later.55 64 void add(V8EventListener*); 56 65 void remove(V8EventListener*); 57 V8EventListener* find(v8::Local<v8::Object>, bool is Inline);66 V8EventListener* find(v8::Local<v8::Object>, bool isAttribute); 58 67 void clear(); 59 size_t size() { return m_ list.size(); }68 size_t size() { return m_table.size(); } 60 69 61 70 private: 62 v8::Handle<v8::String> getKey(bool isInline); 63 v8::Persistent<v8::String> m_inlineKey; 64 v8::Persistent<v8::String> m_nonInlineKey; 65 Vector<V8EventListener*> m_list; 71 ListenerMultiMap m_table; 72 73 // we also keep a reverse mapping of V8EventListener to v8::Object identity hash, 74 // in order to speed up removal by V8EventListener 75 HashMap<V8EventListener*, int> m_reverseTable; 76 }; 77 78 class V8EventListenerListIterator { 79 public: 80 ~V8EventListenerListIterator(); 81 void operator++(); 82 bool operator==(const V8EventListenerListIterator&); 83 bool operator!=(const V8EventListenerListIterator&); 84 V8EventListener* operator*(); 85 private: 86 friend class V8EventListenerList; 87 explicit V8EventListenerListIterator(V8EventListenerList*); 88 V8EventListenerListIterator(V8EventListenerList*, bool shouldSeekToEnd); 89 void seekToEnd(); 90 91 V8EventListenerList* m_list; 92 V8EventListenerList::ListenerMultiMap::iterator m_iter; 93 size_t m_vectorIndex; 66 94 }; 67 95 -
trunk/WebCore/bindings/v8/WorkerContextExecutionProxy.cpp
r42648 r43277 200 200 globalObject->Set(implicitProtoString, jsWorkerContext); 201 201 202 m_listeners.set(new V8EventListenerList( "m_listeners"));202 m_listeners.set(new V8EventListenerList()); 203 203 } 204 204
Note:
See TracChangeset
for help on using the changeset viewer.