2011-02-23 Oliver Hunt <oliver@apple.com>
Reviewed by Geoffrey Garen.
Make WeakGCMap use new handle infrastructure
https://bugs.webkit.org/show_bug.cgi?id=55100
Remove old WeakGCMap implementation and move over to new handle
based logic.
This has a number of benefits, most notably it makes a WeakGCMap
always reflect the true state of the world by as all entries are
removed at the first gc cycle that makes them dead. This allows
us to get rid of code in a wide variety of objects where the only
purpose was to remove themselves from maps.
It also means that we no longer need to have special "unchecked"
versions of any functions on WeakGCMap. Alas in order to maintain
compatibility with the JSWeakObjectMapClear API it is still
necessary to have an api that resembles uncheckedRemove, this is
now deprecatedRemove and will be dealt with in a later patch.
In order to get correct semantics in WeakGCMap we need more
contextual information in the finalizer, so we've added an
abstract class based finaliser and a context parameter to the
calls.
The new an improved WeakGCMap also results in sigificantly more
churn in the weak handle lists so exposed some potential problems
during the post mark phase which have been rectified as well.
* API/JSWeakObjectMapRefPrivate.cpp:
* API/JSWeakObjectMapRefPrivate.h:
* runtime/Heap.cpp:
(JSC::Heap::globalObjectCount):
(JSC::Heap::protectedGlobalObjectCount):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSGlobalData.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::~JSGlobalObject):
(JSC::JSGlobalObject::init):
* runtime/WeakGCMap.h:
(JSC::WeakGCMap::iterator::iterator):
(JSC::WeakGCMap::iterator::get):
(JSC::WeakGCMap::iterator::getSlot):
(JSC::WeakGCMap::iterator::operator++):
(JSC::WeakGCMap::iterator::operator==):
(JSC::WeakGCMap::iterator::operator!=):
(JSC::WeakGCMap::WeakGCMap):
(JSC::WeakGCMap::isEmpty):
(JSC::WeakGCMap::clear):
(JSC::WeakGCMap::get):
(JSC::WeakGCMap::getSlot):
(JSC::WeakGCMap::set):
(JSC::WeakGCMap::take):
(JSC::WeakGCMap::size):
(JSC::WeakGCMap::deprecatedRemove):
(JSC::WeakGCMap::begin):
(JSC::WeakGCMap::end):
(JSC::WeakGCMap::~WeakGCMap):
(JSC::WeakGCMap::finalize):
* runtime/WeakGCPtr.h:
(JSC::WeakGCPtr::WeakGCPtr):
(JSC::WeakGCPtr::set):
2011-02-23 Oliver Hunt <oliver@apple.com>
Reviewed by Geoffrey Garen.
Make WeakGCMap use new handle infrastructure
https://bugs.webkit.org/show_bug.cgi?id=55100
Update to new WeakGCMap APIs, this requires threading global
data to a few functions that did not need it in the past, but
also gets rid of a large number of destructors, as well as the
forgetDOMNode, etc APIs.
We can also drop the JSDebugWrapperSet as its only purpose was
to ensure that we retained correct semantics in the old WeakGCMap,
but happilly these semantics are now guaranteed by the map itself.
* CMakeLists.txt:
* GNUmakefile.am:
* WebCore.gypi:
* WebCore.pro:
* WebCore.vcproj/WebCore.vcproj:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMBinding.cpp:
(WebCore::hasCachedDOMObjectWrapperUnchecked):
(WebCore::cacheDOMObjectWrapper):
(WebCore::hasCachedDOMNodeWrapperUnchecked):
(WebCore::cacheDOMNodeWrapper):
(WebCore::isObservableThroughDOM):
(WebCore::markDOMNodesForDocument):
(WebCore::takeWrappers):
(WebCore::updateDOMNodeDocument):
(WebCore::markDOMObjectWrapper):
(WebCore::markDOMNodeWrapper):
(WebCore::stringWrapperDestroyed):
(WebCore::jsStringSlowCase):
* bindings/js/JSDOMBinding.h:
* bindings/js/JSDOMWrapper.cpp:
(WebCore::DOMObject::~DOMObject):
* bindings/js/JSDebugWrapperSet.cpp: Removed.
* bindings/js/JSDebugWrapperSet.h: Removed.
* bindings/scripts/CodeGeneratorJS.pm:
* bridge/jsc/BridgeJSC.cpp:
(JSC::Bindings::Instance::createRuntimeObject):
* bridge/jsc/BridgeJSC.h:
* bridge/runtime_object.cpp:
(JSC::Bindings::RuntimeObject::~RuntimeObject):
* bridge/runtime_root.cpp:
(JSC::Bindings::RootObject::invalidate):
(JSC::Bindings::RootObject::addRuntimeObject):
(JSC::Bindings::RootObject::removeRuntimeObject):
* bridge/runtime_root.h:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@79616 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
index 7bf4503..a40e684 100644
--- a/Source/JavaScriptCore/runtime/WeakGCMap.h
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -26,110 +26,127 @@
#ifndef WeakGCMap_h
#define WeakGCMap_h
-#include "Heap.h"
+#include "Handle.h"
+#include "JSGlobalData.h"
#include <wtf/HashMap.h>
namespace JSC {
-class JSCell;
-
-// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
-template<typename KeyType, typename MappedType>
-class WeakGCMap {
+// A HashMap for GC'd values that removes entries when the associated value
+// dies.
+template<typename KeyType, typename MappedType> class WeakGCMap : private Finalizer {
WTF_MAKE_FAST_ALLOCATED;
- /*
- Invariants:
- * A value enters the WeakGCMap marked. (Guaranteed by set().)
- * A value that becomes unmarked leaves the WeakGCMap before being recycled. (Guaranteed by the value's destructor removing it from the WeakGCMap.)
- * A value that becomes unmarked leaves the WeakGCMap before becoming marked again. (Guaranteed by all destructors running before the mark phase begins.)
- * During the mark phase, all values in the WeakGCMap are valid. (Guaranteed by all destructors running before the mark phase begins.)
- */
+ WTF_MAKE_NONCOPYABLE(WeakGCMap);
+
+ typedef HashMap<KeyType, HandleSlot> MapType;
+ typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
+ typedef typename MapType::iterator map_iterator;
public:
- typedef typename HashMap<KeyType, DeprecatedPtr<MappedType> >::iterator iterator;
- typedef typename HashMap<KeyType, DeprecatedPtr<MappedType> >::const_iterator const_iterator;
-
- bool isEmpty() { return m_map.isEmpty(); }
- void clear() { m_map.clear(); }
- MappedType* get(const KeyType&) const;
- pair<iterator, bool> set(const KeyType&, MappedType*);
- MappedType* take(const KeyType&);
+ struct iterator {
+ iterator(map_iterator iter)
+ : m_iterator(iter)
+ {
+ }
+
+ std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
+ std::pair<KeyType, HandleSlot> getSlot() const { return *m_iterator; }
+
+ 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;
+ };
- // These unchecked functions provide access to a value even if the value's
- // mark bit is not set. This is used, among other things, to retrieve values
- // during the GC mark phase, which begins by clearing all mark bits.
-
- size_t uncheckedSize() { return m_map.size(); }
-
- MappedType* uncheckedGet(const KeyType& key) const { return m_map.get(key).get(); }
- DeprecatedPtr<MappedType>* uncheckedGetSlot(const KeyType& key)
+ WeakGCMap()
{
- iterator iter = m_map.find(key);
+ }
+
+ bool isEmpty() { return m_map.isEmpty(); }
+ void clear()
+ {
+ map_iterator end = m_map.end();
+ for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
+ HandleHeap::heapFor(ptr->second)->deallocate(ptr->second);
+ m_map.clear();
+ }
+
+ ExternalType get(const KeyType& key) const
+ {
+ return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
+ }
+
+ HandleSlot getSlot(const KeyType& key) const
+ {
+ return m_map.get(key);
+ }
+
+ void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ {
+ pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
+ HandleSlot slot = iter.first->second;
+ if (iter.second) {
+ slot = globalData.allocateGlobalHandle();
+ iter.first->second = slot;
+ HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
+ }
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
+
+ ExternalType take(const KeyType& key)
+ {
+ HandleSlot slot = m_map.take(key);
+ if (!slot)
+ return HashTraits<ExternalType>::emptyValue();
+ ExternalType result = HandleTypes<MappedType>::getFromSlot(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ return result;
+ }
+
+ size_t size() { return m_map.size(); }
+
+ bool deprecatedRemove(const KeyType& key, ExternalType value)
+ {
+ // This only exists in order to allow some semblance of correctness to
+ // the JSWeakObjectMapClear API
+ typename MapType::iterator iter = m_map.find(key);
if (iter == m_map.end())
- return 0;
- return &iter->second;
+ return false;
+ HandleSlot slot = iter->second;
+ ExternalType inmap = HandleTypes<MappedType>::getFromSlot(slot);
+ if (inmap && inmap != value)
+ return false;
+ m_map.remove(iter);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ return true;
}
- bool uncheckedRemove(const KeyType&, MappedType*);
- iterator uncheckedBegin() { return m_map.begin(); }
- iterator uncheckedEnd() { return m_map.end(); }
-
- const_iterator uncheckedBegin() const { return m_map.begin(); }
- const_iterator uncheckedEnd() const { return m_map.end(); }
-
- bool isValid(iterator it) const { return Heap::isMarked(it->second.get()); }
- bool isValid(const_iterator it) const { return Heap::isMarked(it->second.get()); }
-
+ iterator begin() { return iterator(m_map.begin()); }
+ iterator end() { return iterator(m_map.end()); }
+
+ ~WeakGCMap()
+ {
+ clear();
+ }
+
private:
- HashMap<KeyType, DeprecatedPtr<MappedType> > m_map;
-};
-
-template<typename KeyType, typename MappedType>
-inline MappedType* WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const
-{
- MappedType* result = m_map.get(key).get();
- if (result == HashTraits<MappedType*>::emptyValue())
- return result;
- if (!Heap::isMarked(result))
- return HashTraits<MappedType*>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-MappedType* WeakGCMap<KeyType, MappedType>::take(const KeyType& key)
-{
- MappedType* result = m_map.take(key).get();
- if (result == HashTraits<MappedType*>::emptyValue())
- return result;
- if (!Heap::isMarked(result))
- return HashTraits<MappedType*>::emptyValue();
- return result;
-}
-
-template<typename KeyType, typename MappedType>
-pair<typename WeakGCMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, MappedType* value)
-{
- Heap::setMarked(value); // If value is newly allocated, it's not marked, so mark it now.
- pair<iterator, bool> result = m_map.add(key, value);
- if (!result.second) { // pre-existing entry
- result.second = !Heap::isMarked(result.first->second.get());
- result.first->second = value;
+ virtual void finalize(Handle<Unknown>, void* key)
+ {
+ HandleSlot slot = m_map.take(static_cast<KeyType>(key));
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
}
- return result;
-}
-template<typename KeyType, typename MappedType>
-bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, MappedType* value)
-{
- iterator it = m_map.find(key);
- if (it == m_map.end())
- return false;
- if (it->second.get() != value)
- return false;
- m_map.remove(it);
- return true;
-}
+ MapType m_map;
+};
} // namespace JSC