Title: [118483] trunk/Source
Revision
118483
Author
[email protected]
Date
2012-05-24 23:52:00 -0700 (Thu, 24 May 2012)

Log Message

WebKit should be lazy-finalization-safe (esp. the DOM)
https://bugs.webkit.org/show_bug.cgi?id=87456

Reviewed by Filip Pizlo.

../_javascript_Core: 

Lazy finalization adds one twist to weak pointer use:

        A HashMap of weak pointers may contain logically null entries.
        (Weak pointers behave as-if null once their payloads die.)
        Insertion must not assume that a pre-existing entry is
        necessarily valid, and iteration must not assume that all
        entries can be dereferenced.

(Previously, I thought that it also added a second twist:

        A demand-allocated weak pointer may replace a dead payload
        before the payload's finalizer runs. In that case, when the
        payload's finalizer runs, the payload has already been
        overwritten, and the finalizer should not clear the payload,
        which now points to something new.

But that's not the case here, since we cancel the old payload's
finalizer when we over-write it. I've added ASSERTs to verify this
assumption, in case it ever changes.)

* API/JSClassRef.cpp:
(OpaqueJSClass::prototype): No need to specify null; that's the default.

* API/JSWeakObjectMapRefPrivate.cpp: Use remove, since take() is gone.

* heap/PassWeak.h:
(WeakImplAccessor::was): This is no longer a debug-only function, since
it's required to reason about lazily finalized pointers.

* heap/Weak.h:
(JSC::weakAdd):
(JSC::weakRemove):
(JSC::weakClear): Added these helper functions for the common idioms of
what clients want to do in their weak pointer finalizers.

* jit/JITStubs.cpp:
(JSC::JITThunks::hostFunctionStub): Use the new idioms. Otherwise, we
would return NULL for a "zombie" executable weak pointer that was waiting
for finalization (item (2)), and finalizing a dead executable weak pointer
would potentially destroy a new, live one (item (1)).

* runtime/RegExpCache.cpp:
(JSC::RegExpCache::lookupOrCreate):
(JSC::RegExpCache::finalize): Ditto.

(JSC::RegExpCache::invalidateCode): Check for null while iterating. (See
item (2).)

* runtime/Structure.cpp:
(JSC::StructureTransitionTable::contains):
(JSC::StructureTransitionTable::add): Use get and set instead of add and
contains, since add and contains are not compatible with lazy finalization.

* runtime/WeakGCMap.h:
(WeakGCMap):
(JSC::WeakGCMap::clear):
(JSC::WeakGCMap::remove): Removed a bunch of code that was incompatible with
lazy finalization because I didn't feel like making it compatible, and I had
no way to test it.

../WebCore: 

* bindings/js/DOMWrapperWorld.cpp:
(WebCore::JSStringOwner::finalize):
* bindings/js/JSDOMBinding.cpp:
(WebCore::jsStringSlowCase):
* bindings/js/JSDOMBinding.h:
(WebCore::cacheWrapper):
(WebCore::uncacheWrapper): Use the new idioms.

(WebCore::jsString): Use get instead of find because get is simpler in
the case of entries that are logically null.

(WebCore::domObjectWrapperMapFor): Removed, since it was unused.

* bindings/js/ScriptWrappable.h:
(WebCore::ScriptWrappable::clearWrapper): Use the new idioms.

* bridge/runtime_root.cpp:
(JSC::Bindings::RootObject::invalidate): Check for null while iterating,
since that's possible now.

(JSC::Bindings::RootObject::addRuntimeObject):
(JSC::Bindings::RootObject::removeRuntimeObject):
(JSC::Bindings::RootObject::finalize): Use the new idioms.

* bridge/runtime_root.h:
(RootObject): Clarified the word "need".

../WebKit2: 

* WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
(WebKit::NPRuntimeObjectMap::getOrCreateJSObject): Use the new idioms.

(WebKit::NPRuntimeObjectMap::invalidate): Check for null while iterating,
since that's possible now.

(WebKit::NPRuntimeObjectMap::finalize): Use the new idioms.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/JSClassRef.cpp (118482 => 118483)


--- trunk/Source/_javascript_Core/API/JSClassRef.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/API/JSClassRef.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -219,6 +219,6 @@
             prototype->setPrototype(exec->globalData(), parentPrototype);
     }
 
-    jsClassData.cachedPrototype = PassWeak<JSObject>(prototype, 0);
+    jsClassData.cachedPrototype = PassWeak<JSObject>(prototype);
     return prototype;
 }

Modified: trunk/Source/_javascript_Core/API/JSWeakObjectMapRefPrivate.cpp (118482 => 118483)


--- trunk/Source/_javascript_Core/API/JSWeakObjectMapRefPrivate.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/API/JSWeakObjectMapRefPrivate.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -72,7 +72,7 @@
 {
     ExecState* exec = toJS(ctx);
     APIEntryShim entryShim(exec);
-    map->map().take(key);
+    map->map().remove(key);
 }
 
 // We need to keep this function in the build to keep the nightlies running.

Modified: trunk/Source/_javascript_Core/ChangeLog (118482 => 118483)


--- trunk/Source/_javascript_Core/ChangeLog	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-05-25 06:52:00 UTC (rev 118483)
@@ -1,3 +1,70 @@
+2012-05-24  Geoffrey Garen  <[email protected]>
+
+        WebKit should be lazy-finalization-safe (esp. the DOM)
+        https://bugs.webkit.org/show_bug.cgi?id=87456
+
+        Reviewed by Filip Pizlo.
+
+        Lazy finalization adds one twist to weak pointer use:
+
+                A HashMap of weak pointers may contain logically null entries.
+                (Weak pointers behave as-if null once their payloads die.)
+                Insertion must not assume that a pre-existing entry is
+                necessarily valid, and iteration must not assume that all
+                entries can be dereferenced.
+
+        (Previously, I thought that it also added a second twist:
+
+                A demand-allocated weak pointer may replace a dead payload
+                before the payload's finalizer runs. In that case, when the
+                payload's finalizer runs, the payload has already been
+                overwritten, and the finalizer should not clear the payload,
+                which now points to something new.
+
+        But that's not the case here, since we cancel the old payload's
+        finalizer when we over-write it. I've added ASSERTs to verify this
+        assumption, in case it ever changes.)
+
+        * API/JSClassRef.cpp:
+        (OpaqueJSClass::prototype): No need to specify null; that's the default.
+
+        * API/JSWeakObjectMapRefPrivate.cpp: Use remove, since take() is gone.
+
+        * heap/PassWeak.h:
+        (WeakImplAccessor::was): This is no longer a debug-only function, since
+        it's required to reason about lazily finalized pointers.
+
+        * heap/Weak.h:
+        (JSC::weakAdd):
+        (JSC::weakRemove):
+        (JSC::weakClear): Added these helper functions for the common idioms of
+        what clients want to do in their weak pointer finalizers.
+
+        * jit/JITStubs.cpp:
+        (JSC::JITThunks::hostFunctionStub): Use the new idioms. Otherwise, we
+        would return NULL for a "zombie" executable weak pointer that was waiting
+        for finalization (item (2)), and finalizing a dead executable weak pointer
+        would potentially destroy a new, live one (item (1)).
+
+        * runtime/RegExpCache.cpp:
+        (JSC::RegExpCache::lookupOrCreate):
+        (JSC::RegExpCache::finalize): Ditto.
+
+        (JSC::RegExpCache::invalidateCode): Check for null while iterating. (See
+        item (2).)
+
+        * runtime/Structure.cpp:
+        (JSC::StructureTransitionTable::contains):
+        (JSC::StructureTransitionTable::add): Use get and set instead of add and
+        contains, since add and contains are not compatible with lazy finalization.
+
+        * runtime/WeakGCMap.h:
+        (WeakGCMap):
+        (JSC::WeakGCMap::clear):
+        (JSC::WeakGCMap::remove): Removed a bunch of code that was incompatible with
+        lazy finalization because I didn't feel like making it compatible, and I had
+        no way to test it.
+
 2012-05-24  Filip Pizlo  <[email protected]>
 
         REGRESSION (r118013-r118031): Loops/Reloads under www.yahoo.com, quits after three tries with error

Modified: trunk/Source/_javascript_Core/heap/PassWeak.h (118482 => 118483)


--- trunk/Source/_javascript_Core/heap/PassWeak.h	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/heap/PassWeak.h	2012-05-25 06:52:00 UTC (rev 118483)
@@ -46,9 +46,7 @@
     T& operator*() const;
     GetType get() const;
 
-#if !ASSERT_DISABLED
     bool was(GetType) const;
-#endif
 };
 
 template<typename T> class PassWeak : public WeakImplAccessor<PassWeak<T>, T> {
@@ -102,12 +100,10 @@
     return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell());
 }
 
-#if !ASSERT_DISABLED
 template<typename Base, typename T> inline bool WeakImplAccessor<Base, T>::was(typename WeakImplAccessor<Base, T>::GetType other) const
 {
     return jsCast<T*>(static_cast<const Base*>(this)->m_impl->jsValue().asCell()) == other;
 }
-#endif
 
 template<typename T> inline PassWeak<T>::PassWeak()
     : m_impl(0)

Modified: trunk/Source/_javascript_Core/heap/Weak.h (118482 => 118483)


--- trunk/Source/_javascript_Core/heap/Weak.h	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/heap/Weak.h	2012-05-25 06:52:00 UTC (rev 118483)
@@ -26,9 +26,10 @@
 #ifndef Weak_h
 #define Weak_h
 
-#include <wtf/Assertions.h>
 #include "PassWeak.h"
 #include "WeakSetInlines.h"
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
 
 namespace JSC {
 
@@ -150,6 +151,32 @@
     return reinterpret_cast<WeakImpl*>(-1);
 }
 
+// This function helps avoid modifying a weak table while holding an iterator into it. (Object allocation
+// can run a finalizer that modifies the table. We avoid that by requiring a pre-constructed object as our value.)
+template<typename T, typename U> inline void weakAdd(HashMap<T, Weak<U> >& map, const T& key, PassWeak<U> value)
+{
+    ASSERT(!map.get(key));
+    map.set(key, value); // The table may still have a zombie for value.
+}
+
+template<typename T, typename U> inline void weakRemove(HashMap<T, Weak<U> >& map, const T& key, typename Weak<U>::GetType value)
+{
+    typename HashMap<T, Weak<U> >::iterator it = map.find(key);
+    ASSERT_UNUSED(value, value);
+    ASSERT(it != map.end());
+    ASSERT(it->second.was(value));
+    ASSERT(!it->second);
+    map.remove(it);
+}
+
+template<typename T> inline void weakClear(Weak<T>& weak, typename Weak<T>::GetType value)
+{
+    ASSERT_UNUSED(value, value);
+    ASSERT(weak.was(value));
+    ASSERT(!weak);
+    weak.clear();
+}
+
 } // namespace JSC
 
 namespace WTF {

Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (118482 => 118483)


--- trunk/Source/_javascript_Core/jit/JITStubs.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -3458,27 +3458,31 @@
 
 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, NativeFunction constructor)
 {
-    HostFunctionStubMap::AddResult result = m_hostFunctionStubMap->add(function, PassWeak<NativeExecutable>());
-    if (!result.iterator->second)
-        result.iterator->second = PassWeak<NativeExecutable>(NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, function), function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), constructor, NoIntrinsic));
-    return result.iterator->second.get();
+    if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(function))
+        return nativeExecutable;
+
+    NativeExecutable* nativeExecutable = NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, function), function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), constructor, NoIntrinsic);
+    weakAdd(*m_hostFunctionStubMap, function, PassWeak<NativeExecutable>(nativeExecutable));
+    return nativeExecutable;
 }
 
 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic)
 {
-    HostFunctionStubMap::AddResult entry = m_hostFunctionStubMap->add(function, PassWeak<NativeExecutable>());
-    if (!entry.iterator->second) {
-        MacroAssemblerCodeRef code;
-        if (generator) {
-            if (globalData->canUseJIT())
-                code = generator(globalData);
-            else
-                code = MacroAssemblerCodeRef();
-        } else
-            code = JIT::compileCTINativeCall(globalData, function);
-        entry.iterator->second = PassWeak<NativeExecutable>(NativeExecutable::create(*globalData, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor, intrinsic));
-    }
-    return entry.iterator->second.get();
+    if (NativeExecutable* nativeExecutable = m_hostFunctionStubMap->get(function))
+        return nativeExecutable;
+
+    MacroAssemblerCodeRef code;
+    if (generator) {
+        if (globalData->canUseJIT())
+            code = generator(globalData);
+        else
+            code = MacroAssemblerCodeRef();
+    } else
+        code = JIT::compileCTINativeCall(globalData, function);
+
+    NativeExecutable* nativeExecutable = NativeExecutable::create(*globalData, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor, intrinsic);
+    weakAdd(*m_hostFunctionStubMap, function, PassWeak<NativeExecutable>(nativeExecutable));
+    return nativeExecutable;
 }
 
 void JITThunks::clearHostFunctionStubs()

Modified: trunk/Source/_javascript_Core/runtime/RegExpCache.cpp (118482 => 118483)


--- trunk/Source/_javascript_Core/runtime/RegExpCache.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/runtime/RegExpCache.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -36,17 +36,15 @@
 RegExp* RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags flags)
 {
     RegExpKey key(flags, patternString);
-    RegExpCacheMap::iterator result = m_weakCache.find(key);
-    if (result != m_weakCache.end())
-        return result->second.get();
+    if (RegExp* regExp = m_weakCache.get(key))
+        return regExp;
+
     RegExp* regExp = RegExp::createWithoutCaching(*m_globalData, patternString, flags);
 #if ENABLE(REGEXP_TRACING)
     m_globalData->addRegExpToTrace(regExp);
 #endif
-    // We need to do a second lookup to add the RegExp as
-    // allocating it may have caused a gc cycle, which in
-    // turn may have removed items from the cache.
-    m_weakCache.add(key, PassWeak<RegExp>(regExp, this));
+
+    weakAdd(m_weakCache, key, PassWeak<RegExp>(regExp, this));
     return regExp;
 }
 
@@ -59,7 +57,7 @@
 void RegExpCache::finalize(Handle<Unknown> handle, void*)
 {
     RegExp* regExp = static_cast<RegExp*>(handle.get().asCell());
-    m_weakCache.remove(regExp->key());
+    weakRemove(m_weakCache, regExp->key(), regExp);
     regExp->invalidateCode();
 }
 
@@ -79,9 +77,14 @@
     for (int i = 0; i < maxStrongCacheableEntries; i++)
         m_strongCache[i].clear();
     m_nextEntryInStrongCache = 0;
+
     RegExpCacheMap::iterator end = m_weakCache.end();
-    for (RegExpCacheMap::iterator ptr = m_weakCache.begin(); ptr != end; ++ptr)
-        ptr->second->invalidateCode();
+    for (RegExpCacheMap::iterator it = m_weakCache.begin(); it != end; ++it) {
+        RegExp* regExp = it->second.get();
+        if (!regExp) // Skip zombies.
+            continue;
+        regExp->invalidateCode();
+    }
 }
 
 }

Modified: trunk/Source/_javascript_Core/runtime/Structure.cpp (118482 => 118483)


--- trunk/Source/_javascript_Core/runtime/Structure.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/runtime/Structure.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -67,7 +67,7 @@
         Structure* transition = singleTransition();
         return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
     }
-    return map()->contains(make_pair(rep, attributes));
+    return map()->get(make_pair(rep, attributes));
 }
 
 inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
@@ -101,13 +101,7 @@
     // Newer versions of the STL have an std::make_pair function that takes rvalue references.
     // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
     // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
-    TransitionMap::AddResult result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
-    if (!result.isNewEntry) {
-        // There already is an entry! - we should only hit this when despecifying.
-        ASSERT(result.iterator.get().second->m_specificValueInPrevious);
-        ASSERT(!structure->m_specificValueInPrevious);
-        map()->set(globalData, result.iterator.get().first, structure);
-    }
+    map()->set(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
 }
 
 void Structure::dumpStatistics()

Modified: trunk/Source/_javascript_Core/runtime/WeakGCMap.h (118482 => 118483)


--- trunk/Source/_javascript_Core/runtime/WeakGCMap.h	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/_javascript_Core/runtime/WeakGCMap.h	2012-05-25 06:52:00 UTC (rev 118483)
@@ -53,80 +53,25 @@
 
     typedef HashMap<KeyType, WeakImpl*, HashArg, KeyTraitsArg> MapType;
     typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
-    typedef typename MapType::iterator map_iterator;
 
 public:
-
-    struct iterator {
-        friend class WeakGCMap;
-        iterator(map_iterator iter)
-            : m_iterator(iter)
-        {
-        }
-        
-        std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_iterator->second->jsValue()))); }
-        
-        iterator& operator++() { ++m_iterator; return *this; }
-        
-        // postfix ++ intentionally omitted
-        
-        // Comparison.
-        bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
-        bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
-        
-    private:
-        map_iterator m_iterator;
-    };
-
-    typedef WTF::HashTableAddResult<iterator> AddResult;
-
     WeakGCMap()
     {
     }
 
-    bool isEmpty() { return m_map.isEmpty(); }
     void clear()
     {
-        map_iterator end = m_map.end();
-        for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
+        typename MapType::iterator end = m_map.end();
+        for (typename MapType::iterator ptr = m_map.begin(); ptr != end; ++ptr)
             WeakSet::deallocate(ptr->second);
         m_map.clear();
     }
 
-    bool contains(const KeyType& key) const
-    {
-        return m_map.contains(key);
-    }
-
-    iterator find(const KeyType& key)
-    {
-        return m_map.find(key);
-    }
-
-    void remove(iterator iter)
-    {
-        ASSERT(iter.m_iterator != m_map.end());
-        WeakImpl* impl = iter.m_iterator->second;
-        ASSERT(impl);
-        WeakSet::deallocate(impl);
-        m_map.remove(iter.m_iterator);
-    }
-
     ExternalType get(const KeyType& key) const
     {
         return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_map.get(key)->jsValue()));
     }
 
-    AddResult add(JSGlobalData&, const KeyType& key, ExternalType value)
-    {
-        typename MapType::AddResult result = m_map.add(key, 0);
-        if (result.isNewEntry)
-            result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
-
-        // WeakGCMap exposes a different iterator, so we need to wrap it and create our own AddResult.
-        return AddResult(iterator(result.iterator), result.isNewEntry);
-    }
-
     void set(JSGlobalData&, const KeyType& key, ExternalType value)
     {
         typename MapType::AddResult result = m_map.add(key, 0);
@@ -135,21 +80,14 @@
         result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
     }
 
-    ExternalType take(const KeyType& key)
+    void remove(const KeyType& key)
     {
         WeakImpl* impl = m_map.take(key);
         if (!impl)
-            return HashTraits<ExternalType>::emptyValue();
-        ExternalType result = HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&impl->jsValue()));
+            return;
         WeakSet::deallocate(impl);
-        return result;
     }
 
-    size_t size() { return m_map.size(); }
-
-    iterator begin() { return iterator(m_map.begin()); }
-    iterator end() { return iterator(m_map.end()); }
-    
     ~WeakGCMap()
     {
         clear();

Modified: trunk/Source/WebCore/ChangeLog (118482 => 118483)


--- trunk/Source/WebCore/ChangeLog	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/ChangeLog	2012-05-25 06:52:00 UTC (rev 118483)
@@ -1,3 +1,37 @@
+2012-05-24  Geoffrey Garen  <[email protected]>
+
+        WebKit should be lazy-finalization-safe (esp. the DOM)
+        https://bugs.webkit.org/show_bug.cgi?id=87456
+
+        Reviewed by Filip Pizlo.
+
+        * bindings/js/DOMWrapperWorld.cpp:
+        (WebCore::JSStringOwner::finalize):
+        * bindings/js/JSDOMBinding.cpp:
+        (WebCore::jsStringSlowCase):
+        * bindings/js/JSDOMBinding.h:
+        (WebCore::cacheWrapper):
+        (WebCore::uncacheWrapper): Use the new idioms.
+
+        (WebCore::jsString): Use get instead of find because get is simpler in
+        the case of entries that are logically null.
+
+        (WebCore::domObjectWrapperMapFor): Removed, since it was unused.
+
+        * bindings/js/ScriptWrappable.h:
+        (WebCore::ScriptWrappable::clearWrapper): Use the new idioms.
+
+        * bridge/runtime_root.cpp:
+        (JSC::Bindings::RootObject::invalidate): Check for null while iterating,
+        since that's possible now.
+
+        (JSC::Bindings::RootObject::addRuntimeObject):
+        (JSC::Bindings::RootObject::removeRuntimeObject):
+        (JSC::Bindings::RootObject::finalize): Use the new idioms.
+
+        * bridge/runtime_root.h:
+        (RootObject): Clarified the word "need".
+
 2012-05-24  Kent Tamura  <[email protected]>
 
         PAGE_POPUP: window.setValueAndClosePopup should be moved to a

Modified: trunk/Source/WebCore/bindings/js/DOMWrapperWorld.cpp (118482 => 118483)


--- trunk/Source/WebCore/bindings/js/DOMWrapperWorld.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/bindings/js/DOMWrapperWorld.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -34,8 +34,7 @@
 {
     JSString* jsString = jsCast<JSString*>(handle.get().asCell());
     StringImpl* stringImpl = static_cast<StringImpl*>(context);
-    ASSERT_UNUSED(jsString, m_world->m_stringCache.find(stringImpl)->second.was(jsString));
-    m_world->m_stringCache.remove(stringImpl);
+    weakRemove(m_world->m_stringCache, stringImpl, jsString);
 }
 
 DOMWrapperWorld::DOMWrapperWorld(JSC::JSGlobalData* globalData, bool isNormal)

Modified: trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp (118482 => 118483)


--- trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -49,7 +49,7 @@
 JSValue jsStringSlowCase(ExecState* exec, JSStringCache& stringCache, StringImpl* stringImpl)
 {
     JSString* wrapper = jsString(exec, UString(stringImpl));
-    stringCache.add(stringImpl, PassWeak<JSString>(wrapper, currentWorld(exec)->stringWrapperOwner(), stringImpl));
+    weakAdd(stringCache, stringImpl, PassWeak<JSString>(wrapper, currentWorld(exec)->stringWrapperOwner(), stringImpl));
     return wrapper;
 }
 

Modified: trunk/Source/WebCore/bindings/js/JSDOMBinding.h (118482 => 118483)


--- trunk/Source/WebCore/bindings/js/JSDOMBinding.h	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/bindings/js/JSDOMBinding.h	2012-05-25 06:52:00 UTC (rev 118483)
@@ -142,16 +142,14 @@
         if (setInlineCachedWrapper(world, domObject, wrapper))
             return;
         JSC::PassWeak<JSDOMWrapper> passWeak(wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject));
-        DOMObjectWrapperMap::AddResult result = world->m_wrappers.add(domObject, passWeak);
-        ASSERT_UNUSED(result, result.isNewEntry);
+        weakAdd(world->m_wrappers, (void*)domObject, passWeak);
     }
 
     template <typename DOMClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, JSDOMWrapper* wrapper)
     {
         if (clearInlineCachedWrapper(world, domObject, wrapper))
             return;
-        ASSERT(world->m_wrappers.find(domObject)->second.was(wrapper));
-        world->m_wrappers.remove(domObject);
+        weakRemove(world->m_wrappers, (void*)domObject, wrapper);
     }
     
     #define CREATE_DOM_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
@@ -349,18 +347,12 @@
             return jsString(exec, stringToUString(s));
 
         JSStringCache& stringCache = currentWorld(exec)->m_stringCache;
-        JSStringCache::iterator it = stringCache.find(stringImpl);
-        if (it != stringCache.end())
-            return it->second.get();
+        if (JSC::JSString* string = stringCache.get(stringImpl))
+            return string;
 
         return jsStringSlowCase(exec, stringCache, stringImpl);
     }
 
-    inline DOMObjectWrapperMap& domObjectWrapperMapFor(JSC::ExecState* exec)
-    {
-        return currentWorld(exec)->m_wrappers;
-    }
-
     inline String ustringToString(const JSC::UString& u)
     {
         return u.impl();

Modified: trunk/Source/WebCore/bindings/js/ScriptWrappable.h (118482 => 118483)


--- trunk/Source/WebCore/bindings/js/ScriptWrappable.h	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/bindings/js/ScriptWrappable.h	2012-05-25 06:52:00 UTC (rev 118483)
@@ -51,8 +51,7 @@
 
     void clearWrapper(JSDOMWrapper* wrapper)
     {
-        ASSERT_UNUSED(wrapper, m_wrapper.was(wrapper));
-        m_wrapper.clear();
+        weakClear(m_wrapper, wrapper);
     }
 
 private:

Modified: trunk/Source/WebCore/bridge/runtime_root.cpp (118482 => 118483)


--- trunk/Source/WebCore/bridge/runtime_root.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/bridge/runtime_root.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -105,7 +105,10 @@
     {
         HashMap<RuntimeObject*, JSC::Weak<RuntimeObject> >::iterator end = m_runtimeObjects.end();
         for (HashMap<RuntimeObject*, JSC::Weak<RuntimeObject> >::iterator it = m_runtimeObjects.begin(); it != end; ++it) {
-            it->second.get()->invalidate();
+            RuntimeObject* runtimeObject = it->second.get();
+            if (!runtimeObject) // Skip zombies.
+                continue;
+            runtimeObject->invalidate();
         }
 
         m_runtimeObjects.clear();
@@ -179,29 +182,23 @@
 void RootObject::addRuntimeObject(JSGlobalData&, RuntimeObject* object)
 {
     ASSERT(m_isValid);
-    ASSERT(!m_runtimeObjects.get(object));
-
-    m_runtimeObjects.set(object, JSC::PassWeak<RuntimeObject>(object, this));
+    weakAdd(m_runtimeObjects, object, JSC::PassWeak<RuntimeObject>(object, this));
 }
 
 void RootObject::removeRuntimeObject(RuntimeObject* object)
 {
     if (!m_isValid)
         return;
-
-    ASSERT(m_runtimeObjects.get(object));
-
-    m_runtimeObjects.take(object);
+    weakRemove(m_runtimeObjects, object, object);
 }
 
 void RootObject::finalize(JSC::Handle<JSC::Unknown> handle, void*)
 {
     RuntimeObject* object = static_cast<RuntimeObject*>(asObject(handle.get()));
-    ASSERT(m_runtimeObjects.contains(object));
 
     RefPtr<RootObject> protect(this);
     object->invalidate();
-    m_runtimeObjects.remove(object);
+    weakRemove(m_runtimeObjects, object, object);
 }
 
 } } // namespace JSC::Bindings

Modified: trunk/Source/WebCore/bridge/runtime_root.h (118482 => 118483)


--- trunk/Source/WebCore/bridge/runtime_root.h	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebCore/bridge/runtime_root.h	2012-05-25 06:52:00 UTC (rev 118483)
@@ -93,7 +93,7 @@
     Strong<JSGlobalObject> m_globalObject;
 
     ProtectCountSet m_protectCountSet;
-    HashMap<RuntimeObject*, JSC::Weak<RuntimeObject> > m_runtimeObjects; // Really need a WeakGCSet, but this will do.
+    HashMap<RuntimeObject*, JSC::Weak<RuntimeObject> > m_runtimeObjects; // We use a map to implement a set.
 
     HashSet<InvalidationCallback*> m_invalidationCallbacks;
 };

Modified: trunk/Source/WebKit2/ChangeLog (118482 => 118483)


--- trunk/Source/WebKit2/ChangeLog	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebKit2/ChangeLog	2012-05-25 06:52:00 UTC (rev 118483)
@@ -1,3 +1,18 @@
+2012-05-24  Geoffrey Garen  <[email protected]>
+
+        WebKit should be lazy-finalization-safe (esp. the DOM)
+        https://bugs.webkit.org/show_bug.cgi?id=87456
+
+        Reviewed by Filip Pizlo.
+
+        * WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp:
+        (WebKit::NPRuntimeObjectMap::getOrCreateJSObject): Use the new idioms.
+
+        (WebKit::NPRuntimeObjectMap::invalidate): Check for null while iterating,
+        since that's possible now.
+
+        (WebKit::NPRuntimeObjectMap::finalize): Use the new idioms.
+
 2012-05-24  Brady Eidson  <[email protected]>
 
         Fix the build after http://trac.webkit.org/changeset/118441

Modified: trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp (118482 => 118483)


--- trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp	2012-05-25 06:50:38 UTC (rev 118482)
+++ trunk/Source/WebKit2/WebProcess/Plugins/Netscape/NPRuntimeObjectMap.cpp	2012-05-25 06:52:00 UTC (rev 118483)
@@ -104,8 +104,7 @@
         return jsNPObject;
 
     JSNPObject* jsNPObject = JSNPObject::create(globalObject, this, npObject);
-    m_jsNPObjects.set(npObject, JSC::PassWeak<JSNPObject>(jsNPObject, this, npObject));
-
+    weakAdd(m_jsNPObjects, npObject, JSC::PassWeak<JSNPObject>(jsNPObject, this, npObject));
     return jsNPObject;
 }
 
@@ -212,8 +211,12 @@
 
     Vector<NPObject*> objects;
 
-    for (HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator ptr = m_jsNPObjects.begin(), end = m_jsNPObjects.end(); ptr != end; ++ptr)
-        objects.append(ptr->second->leakNPObject());
+    for (HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator ptr = m_jsNPObjects.begin(), end = m_jsNPObjects.end(); ptr != end; ++ptr) {
+        JSNPObject* jsNPObject = ptr->second.get();
+        if (!jsNPObject) // Skip zombies.
+            continue;
+        objects.append(jsNPObject->leakNPObject());
+    }
 
     m_jsNPObjects.clear();
 
@@ -293,12 +296,7 @@
 void NPRuntimeObjectMap::finalize(JSC::Handle<JSC::Unknown> handle, void* context)
 {
     JSNPObject* object = jsCast<JSNPObject*>(asObject(handle.get()));
-
-    HashMap<NPObject*, JSC::Weak<JSNPObject> >::iterator found = m_jsNPObjects.find(static_cast<NPObject*>(context));
-    ASSERT(found != m_jsNPObjects.end());
-    ASSERT(found->second.was(object));
-    m_jsNPObjects.remove(found);
-
+    weakRemove(m_jsNPObjects, static_cast<NPObject*>(context), object);
     addToInvalidationQueue(object->leakNPObject());
 }
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to