]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/WeakGCMap.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / runtime / WeakGCMap.h
index 39a91c5fa59adb605ae37351eaec1723395b1987..e7e9447ab5d2fb53b95c4462f103a54a9dce437b 100644 (file)
 #ifndef WeakGCMap_h
 #define WeakGCMap_h
 
-#include "Collector.h"
+#include "Handle.h"
+#include "JSGlobalData.h"
 #include <wtf/HashMap.h>
 
 namespace JSC {
 
-class JSCell;
+// A HashMap for GC'd values that removes entries when the associated value
+// dies.
+template <typename KeyType, typename MappedType> struct DefaultWeakGCMapFinalizerCallback {
+    static void* finalizerContextFor(KeyType key)
+    {
+        return reinterpret_cast<void*>(key);
+    }
+
+    static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType)
+    {
+        return reinterpret_cast<KeyType>(context);
+    }
+};
 
-// A HashMap whose get() function returns emptyValue() for cells awaiting destruction.
-template<typename KeyType, typename MappedType>
-class WeakGCMap : public FastAllocBase {
-    /*
-    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.)
-    */
+template<typename KeyType, typename MappedType, typename FinalizerCallback = DefaultWeakGCMapFinalizerCallback<KeyType, MappedType>, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> >
+class WeakGCMap : private WeakHandleOwner {
+    WTF_MAKE_FAST_ALLOCATED;
+    WTF_MAKE_NONCOPYABLE(WeakGCMap);
+
+    typedef HashMap<KeyType, WeakImpl*, HashArg, KeyTraitsArg> MapType;
+    typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
+    typedef typename MapType::iterator map_iterator;
 
 public:
-    typedef typename HashMap<KeyType, MappedType>::iterator iterator;
-    typedef typename HashMap<KeyType, MappedType>::const_iterator const_iterator;
-    
+
+    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)
+            WeakSet::deallocate(ptr->second);
+        m_map.clear();
+    }
 
-    MappedType get(const KeyType& key) const;
-    pair<iterator, bool> set(const KeyType&, const MappedType&); 
-    MappedType take(const KeyType& key);
+    bool contains(const KeyType& key) const
+    {
+        return m_map.contains(key);
+    }
 
-    // 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.
+    iterator find(const KeyType& key)
+    {
+        return m_map.find(key);
+    }
 
-    MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); }
-    bool uncheckedRemove(const KeyType&, const MappedType&);
+    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);
+    }
 
-    iterator uncheckedBegin() { return m_map.begin(); }
-    iterator uncheckedEnd() { return m_map.end(); }
+    ExternalType get(const KeyType& key) const
+    {
+        return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_map.get(key)->jsValue()));
+    }
 
-    const_iterator uncheckedBegin() const { return m_map.begin(); }
-    const_iterator uncheckedEnd() const { return m_map.end(); }
+    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));
 
-private:
-    HashMap<KeyType, MappedType> m_map;
-};
+        // WeakGCMap exposes a different iterator, so we need to wrap it and create our own AddResult.
+        return AddResult(iterator(result.iterator), result.isNewEntry);
+    }
 
-template<typename KeyType, typename MappedType>
-inline MappedType WeakGCMap<KeyType, MappedType>::get(const KeyType& key) const
-{
-    MappedType result = m_map.get(key);
-    if (result == HashTraits<MappedType>::emptyValue())
-        return result;
-    if (!Heap::isCellMarked(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);
-    if (result == HashTraits<MappedType>::emptyValue())
+    void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+    {
+        ASSERT_UNUSED(globalData, globalData.apiLock().currentThreadIsHoldingLock());
+        typename MapType::AddResult result = m_map.add(key, 0);
+        if (!result.isNewEntry)
+            WeakSet::deallocate(result.iterator->second);
+        result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
+    }
+
+    ExternalType take(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()));
+        WeakSet::deallocate(impl);
         return result;
-    if (!Heap::isCellMarked(result))
-        return HashTraits<MappedType>::emptyValue();
-    return result;
-}
-
-template<typename KeyType, typename MappedType>
-pair<typename HashMap<KeyType, MappedType>::iterator, bool> WeakGCMap<KeyType, MappedType>::set(const KeyType& key, const MappedType& value)
-{
-    Heap::markCell(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::isCellMarked(result.first->second);
-        result.first->second = value;
     }
-    return result;
-}
-
-template<typename KeyType, typename MappedType>
-bool WeakGCMap<KeyType, MappedType>::uncheckedRemove(const KeyType& key, const MappedType& value)
-{
-    iterator it = m_map.find(key);
-    if (it == m_map.end())
-        return false;
-    if (it->second != value)
-        return false;
-    m_map.remove(it);
-    return true;
-}
+
+    size_t size() { return m_map.size(); }
+
+    iterator begin() { return iterator(m_map.begin()); }
+    iterator end() { return iterator(m_map.end()); }
+    
+    ~WeakGCMap()
+    {
+        clear();
+    }
+    
+private:
+    virtual void finalize(Handle<Unknown> handle, void* context)
+    {
+        WeakImpl* impl = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
+        ASSERT(impl);
+        WeakSet::deallocate(impl);
+    }
+
+    MapType m_map;
+};
 
 } // namespace JSC