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/runtime/WeakGCMap.h

    r115545 r118483  
    5454    typedef HashMap<KeyType, WeakImpl*, HashArg, KeyTraitsArg> MapType;
    5555    typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
    56     typedef typename MapType::iterator map_iterator;
    5756
    5857public:
    59 
    60     struct iterator {
    61         friend class WeakGCMap;
    62         iterator(map_iterator iter)
    63             : m_iterator(iter)
    64         {
    65         }
    66        
    67         std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_iterator->second->jsValue()))); }
    68        
    69         iterator& operator++() { ++m_iterator; return *this; }
    70        
    71         // postfix ++ intentionally omitted
    72        
    73         // Comparison.
    74         bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
    75         bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
    76        
    77     private:
    78         map_iterator m_iterator;
    79     };
    80 
    81     typedef WTF::HashTableAddResult<iterator> AddResult;
    82 
    8358    WeakGCMap()
    8459    {
    8560    }
    8661
    87     bool isEmpty() { return m_map.isEmpty(); }
    8862    void clear()
    8963    {
    90         map_iterator end = m_map.end();
    91         for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
     64        typename MapType::iterator end = m_map.end();
     65        for (typename MapType::iterator ptr = m_map.begin(); ptr != end; ++ptr)
    9266            WeakSet::deallocate(ptr->second);
    9367        m_map.clear();
    94     }
    95 
    96     bool contains(const KeyType& key) const
    97     {
    98         return m_map.contains(key);
    99     }
    100 
    101     iterator find(const KeyType& key)
    102     {
    103         return m_map.find(key);
    104     }
    105 
    106     void remove(iterator iter)
    107     {
    108         ASSERT(iter.m_iterator != m_map.end());
    109         WeakImpl* impl = iter.m_iterator->second;
    110         ASSERT(impl);
    111         WeakSet::deallocate(impl);
    112         m_map.remove(iter.m_iterator);
    11368    }
    11469
     
    11671    {
    11772        return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_map.get(key)->jsValue()));
    118     }
    119 
    120     AddResult add(JSGlobalData&, const KeyType& key, ExternalType value)
    121     {
    122         typename MapType::AddResult result = m_map.add(key, 0);
    123         if (result.isNewEntry)
    124             result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
    125 
    126         // WeakGCMap exposes a different iterator, so we need to wrap it and create our own AddResult.
    127         return AddResult(iterator(result.iterator), result.isNewEntry);
    12873    }
    12974
     
    13681    }
    13782
    138     ExternalType take(const KeyType& key)
     83    void remove(const KeyType& key)
    13984    {
    14085        WeakImpl* impl = m_map.take(key);
    14186        if (!impl)
    142             return HashTraits<ExternalType>::emptyValue();
    143         ExternalType result = HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&impl->jsValue()));
     87            return;
    14488        WeakSet::deallocate(impl);
    145         return result;
    14689    }
    14790
    148     size_t size() { return m_map.size(); }
    149 
    150     iterator begin() { return iterator(m_map.begin()); }
    151     iterator end() { return iterator(m_map.end()); }
    152    
    15391    ~WeakGCMap()
    15492    {
Note: See TracChangeset for help on using the changeset viewer.