 Chromium Code Reviews
 Chromium Code Reviews Issue 180363004:
  Convert DOMWrapperMap to use PersistentValueMap  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master
    
  
    Issue 180363004:
  Convert DOMWrapperMap to use PersistentValueMap  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/blink.git@master| Index: Source/bindings/v8/DOMWrapperMap.h | 
| diff --git a/Source/bindings/v8/DOMWrapperMap.h b/Source/bindings/v8/DOMWrapperMap.h | 
| index 20fe7625f0422e27be900690c3e6efb90f0c9a62..c2a29bcd746067b25bd0860993127b19f933ad16 100644 | 
| --- a/Source/bindings/v8/DOMWrapperMap.h | 
| +++ b/Source/bindings/v8/DOMWrapperMap.h | 
| @@ -32,104 +32,171 @@ | 
| #define DOMWrapperMap_h | 
| #include "bindings/v8/UnsafePersistent.h" | 
| +#include "bindings/v8/V8NPObject.h" | 
| #include "bindings/v8/WrapperTypeInfo.h" | 
| #include <v8.h> | 
| #include "wtf/HashMap.h" | 
| +#include <stdio.h> | 
| namespace WebCore { | 
| template<class KeyType> | 
| class DOMWrapperMap { | 
| public: | 
| - typedef HashMap<KeyType*, UnsafePersistent<v8::Object> > MapType; | 
| - | 
| explicit DOMWrapperMap(v8::Isolate* isolate) | 
| : m_isolate(isolate) | 
| + , m_map(isolate) | 
| { | 
| } | 
| v8::Handle<v8::Object> newLocal(KeyType* key, v8::Isolate* isolate) | 
| { | 
| - return m_map.get(key).newLocal(isolate); | 
| + return v8::Local<v8::Object>::New(isolate, m_map.Get(key)); | 
| 
dcarney
2014/03/07 09:38:24
Get already returns a local, no need to double wra
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| } | 
| bool setReturnValueFrom(v8::ReturnValue<v8::Value> returnValue, KeyType* key) | 
| { | 
| - typename MapType::iterator it = m_map.find(key); | 
| - if (it == m_map.end()) | 
| - return false; | 
| - returnValue.Set(*(it->value.persistent())); | 
| - return true; | 
| + v8::Local<v8::Object> value = m_map.Get(key); | 
| 
dcarney
2014/03/07 09:38:24
we don't want to create a local for setting a retu
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| + bool hasValue = !value.IsEmpty(); | 
| + if (hasValue) { | 
| + returnValue.Set(value); | 
| + } | 
| + return hasValue; | 
| } | 
| void setReference(const v8::Persistent<v8::Object>& parent, KeyType* key, v8::Isolate* isolate) | 
| { | 
| - m_map.get(key).setReferenceFrom(parent, isolate); | 
| + v8::Persistent<v8::Object> ref(isolate, m_map.Get(key)); | 
| 
dcarney
2014/03/07 09:38:24
push to PersistentValueMap
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| + isolate->SetReference(parent, ref); | 
| } | 
| bool containsKey(KeyType* key) | 
| { | 
| - return m_map.find(key) != m_map.end(); | 
| + return !m_map.Get(key).IsEmpty(); | 
| 
dcarney
2014/03/07 09:38:24
too expensive - push to PersistentValueMap
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| } | 
| bool containsKeyAndValue(KeyType* key, v8::Handle<v8::Object> value) | 
| { | 
| - typename MapType::iterator it = m_map.find(key); | 
| - if (it == m_map.end()) | 
| - return false; | 
| - return *(it->value.persistent()) == value; | 
| + v8::Local<v8::Object> mapValue = m_map.Get(key); | 
| 
dcarney
2014/03/07 09:38:24
this function is stupid and only used in an assert
 
vogelheim
2014/03/07 18:01:34
Done.
Actually, it drops out with this change, si
 | 
| + return !mapValue.IsEmpty() && (mapValue == value); | 
| } | 
| void set(KeyType* key, v8::Handle<v8::Object> wrapper, const WrapperConfiguration& configuration) | 
| { | 
| ASSERT(static_cast<KeyType*>(toNative(wrapper)) == key); | 
| - v8::Persistent<v8::Object> persistent(m_isolate, wrapper); | 
| - configuration.configureWrapper(&persistent); | 
| - persistent.SetWeak(this, &setWeakCallback); | 
| - typename MapType::AddResult result = m_map.add(key, UnsafePersistent<v8::Object>()); | 
| - ASSERT(result.isNewEntry); | 
| - // FIXME: Stop handling this case once duplicate wrappers are guaranteed not to be created. | 
| - if (!result.isNewEntry) | 
| - result.storedValue->value.dispose(); | 
| - result.storedValue->value = UnsafePersistent<v8::Object>(persistent); | 
| + ASSERT(!wrapper.IsEmpty()); | 
| 
dcarney
2014/03/07 09:38:24
this is asserted in the line above, drop
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| + m_map.SetWithConfig(key, v8::Local<v8::Object>::New(m_isolate, wrapper), | 
| 
dcarney
2014/03/07 09:38:24
no need for local::new
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| + configuration.classId, configuration.lifetime); | 
| } | 
| void clear() | 
| { | 
| - v8::HandleScope scope(m_isolate); | 
| - while (!m_map.isEmpty()) { | 
| - // Swap out m_map on each iteration to ensure any wrappers added due to side effects of the loop are cleared. | 
| - MapType map; | 
| - map.swap(m_map); | 
| - for (typename MapType::iterator it = map.begin(); it != map.end(); ++it) { | 
| - releaseObject(it->value.newLocal(m_isolate)); | 
| - it->value.dispose(); | 
| - } | 
| - } | 
| + m_map.Clear(); | 
| } | 
| void removeAndDispose(KeyType* key) | 
| { | 
| - typename MapType::iterator it = m_map.find(key); | 
| - ASSERT_WITH_SECURITY_IMPLICATION(it != m_map.end()); | 
| - it->value.dispose(); | 
| - m_map.remove(it); | 
| + m_map.Remove(key); | 
| } | 
| private: | 
| - static void setWeakCallback(const v8::WeakCallbackData<v8::Object, DOMWrapperMap<KeyType> >&); | 
| + class PersistentValueMapTraits { | 
| + public: | 
| + typedef HashMap<KeyType*, v8::PersistentContainerValue> Impl; | 
| + typedef typename Impl::iterator Iterator; | 
| + | 
| + class WeakCallbackDataType { | 
| 
dcarney
2014/03/07 09:38:24
WeakCallbackDataType should just be a point to the
 
vogelheim
2014/03/07 18:01:34
Done.
I find this a weird design, though. This cl
 | 
| + public: | 
| + WeakCallbackDataType(Impl* impl, KeyType* key, v8::Local<v8::Object>& value) | 
| + : m_impl(impl) | 
| + , m_key(key) | 
| + , m_value(value) | 
| + { } | 
| + Impl* m_impl; | 
| + KeyType* m_key; | 
| + v8::Local<v8::Object> m_value; | 
| + }; | 
| + | 
| + static const bool kIsWeak = true; | 
| + | 
| + // Container API: Size/Empty/Swap/Begin/End/Value/Set/Get/Remove | 
| + static size_t Size(const Impl* impl) { return impl->size(); } | 
| + static bool Empty(Impl* impl) { return impl->isEmpty(); } | 
| + static void Swap(Impl& impl, Impl& other) { impl.swap(other); } | 
| + | 
| + static Iterator Begin(Impl* impl) { return impl->begin(); } | 
| + static Iterator End(Impl* impl) { return impl->end(); } | 
| + static v8::PersistentContainerValue Value(Iterator& iter) | 
| + { | 
| + return iter->value; | 
| + } | 
| + static KeyType* Key(Iterator& iter) { return iter->key; } | 
| + | 
| + static v8::PersistentContainerValue Set( | 
| + Impl* impl, KeyType* key, v8::PersistentContainerValue value) | 
| + { | 
| + v8::PersistentContainerValue oldValue = Get(impl, key); | 
| 
dcarney
2014/03/07 09:38:24
this function seems inefficient - is there a way t
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| + impl->add(key, value); | 
| + return oldValue; | 
| + } | 
| + | 
| + static v8::PersistentContainerValue Get(const Impl* impl, KeyType* key) | 
| + { | 
| + return impl->get(key); | 
| + } | 
| + | 
| + static v8::PersistentContainerValue Remove(Impl* impl, KeyType* key) | 
| + { | 
| + return impl->take(key); | 
| + } | 
| + | 
| + // Dispose callbacks: | 
| + static void DisposeByValue(v8::UniquePersistent<v8::Object> value, v8::Isolate* isolate) { } | 
| + static void DisposeByKey(Impl* impl, KeyType* key) { } | 
| + | 
| + // WeakCallbackDataType, create/dispose, conversion, callback. | 
| + static WeakCallbackDataType* WeakCallbackParameter(Impl* impl, KeyType* key, v8::Local<v8::Object>& value) | 
| + { | 
| + // ??? value is unused? | 
| + return new WeakCallbackDataType(impl, key, value); | 
| 
dcarney
2014/03/07 09:38:24
just return 'this'
 
vogelheim
2014/03/07 18:01:34
Done.
(Actually impl, but hat's probably what you
 | 
| + } | 
| + | 
| + static void DisposeCallbackData(WeakCallbackDataType* callbackData) | 
| + { | 
| + delete callbackData; | 
| 
dcarney
2014/03/07 09:38:24
should be empty
 
vogelheim
2014/03/07 18:01:34
Done.
 | 
| + } | 
| + | 
| + static Impl* ImplFromWeakCallbackData( | 
| + v8::WeakCallbackData<v8::Object, WeakCallbackDataType> data) | 
| + { | 
| + return data.GetParameter()->m_impl; | 
| + } | 
| + | 
| + static KeyType* KeyFromWeakCallbackData( | 
| + v8::WeakCallbackData<v8::Object, WeakCallbackDataType> data) | 
| + { | 
| + return data.GetParameter()->m_key; | 
| + } | 
| + }; | 
| v8::Isolate* m_isolate; | 
| - MapType m_map; | 
| + v8::PersistentValueMap<KeyType*, v8::Object, PersistentValueMapTraits> m_map; | 
| }; | 
| -template<> | 
| -inline void DOMWrapperMap<void>::setWeakCallback(const v8::WeakCallbackData<v8::Object, DOMWrapperMap<void> >& data) | 
| +template <> | 
| +inline void DOMWrapperMap<void>::PersistentValueMapTraits::DisposeByValue( | 
| + v8::UniquePersistent<v8::Object> value, | 
| + v8::Isolate* isolate) | 
| +{ | 
| + releaseObject(v8::Local<v8::Object>::New(isolate, value)); | 
| +} | 
| + | 
| +template <> | 
| +inline void DOMWrapperMap<NPObject>::PersistentValueMapTraits::DisposeByKey( | 
| + DOMWrapperMap<NPObject>::PersistentValueMapTraits::Impl* impl, | 
| + NPObject* key) | 
| 
dcarney
2014/03/07 09:38:24
this needs to go to the file where it's currently
 
vogelheim
2014/03/07 18:01:34
Done.
For my understanding: Why? I thought it rat
 | 
| { | 
| - void* key = static_cast<void*>(toNative(data.GetValue())); | 
| - ASSERT(*data.GetParameter()->m_map.get(key).persistent() == data.GetValue()); | 
| - data.GetParameter()->removeAndDispose(key); | 
| - releaseObject(data.GetValue()); | 
| + DOMWrapperMapDisposeHelper(key); | 
| } | 
| } // namespace WebCore |