Ignore:
Timestamp:
May 24, 2012, 11:52:00 PM (13 years ago)
Author:
[email protected]
Message:

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

Reviewed by Filip Pizlo.

../JavaScriptCore:

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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/Weak.h

    r115545 r118483  
    2727#define Weak_h
    2828
    29 #include <wtf/Assertions.h>
    3029#include "PassWeak.h"
    3130#include "WeakSetInlines.h"
     31#include <wtf/Assertions.h>
     32#include <wtf/HashMap.h>
    3233
    3334namespace JSC {
     
    151152}
    152153
     154// This function helps avoid modifying a weak table while holding an iterator into it. (Object allocation
     155// can run a finalizer that modifies the table. We avoid that by requiring a pre-constructed object as our value.)
     156template<typename T, typename U> inline void weakAdd(HashMap<T, Weak<U> >& map, const T& key, PassWeak<U> value)
     157{
     158    ASSERT(!map.get(key));
     159    map.set(key, value); // The table may still have a zombie for value.
     160}
     161
     162template<typename T, typename U> inline void weakRemove(HashMap<T, Weak<U> >& map, const T& key, typename Weak<U>::GetType value)
     163{
     164    typename HashMap<T, Weak<U> >::iterator it = map.find(key);
     165    ASSERT_UNUSED(value, value);
     166    ASSERT(it != map.end());
     167    ASSERT(it->second.was(value));
     168    ASSERT(!it->second);
     169    map.remove(it);
     170}
     171
     172template<typename T> inline void weakClear(Weak<T>& weak, typename Weak<T>::GetType value)
     173{
     174    ASSERT_UNUSED(value, value);
     175    ASSERT(weak.was(value));
     176    ASSERT(!weak);
     177    weak.clear();
     178}
     179
    153180} // namespace JSC
    154181
Note: See TracChangeset for help on using the changeset viewer.