#ifndef WeakGCMap_h
#define WeakGCMap_h
-#include "Handle.h"
-#include "JSGlobalData.h"
+#include "Weak.h"
+#include "WeakInlines.h"
#include <wtf/HashMap.h>
namespace JSC {
-// 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);
- }
+// A HashMap with Weak<JSCell> values, which automatically removes values once they're garbage collected.
- static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType)
- {
- return reinterpret_cast<KeyType>(context);
- }
-};
-
-template<typename KeyType, typename MappedType, typename FinalizerCallback = DefaultWeakGCMapFinalizerCallback<KeyType, MappedType>, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> >
-class WeakGCMap : private WeakHandleOwner {
+template<typename KeyArg, typename ValueArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
+ typename KeyTraitsArg = HashTraits<KeyArg>>
+class WeakGCMap {
WTF_MAKE_FAST_ALLOCATED;
- WTF_MAKE_NONCOPYABLE(WeakGCMap);
-
- typedef HashMap<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType;
- typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
- typedef typename MapType::iterator map_iterator;
+ typedef Weak<ValueArg> ValueType;
+ typedef HashMap<KeyArg, ValueType, HashArg, KeyTraitsArg> HashMapType;
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(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;
- };
+ typedef typename HashMapType::KeyType KeyType;
+ typedef typename HashMapType::AddResult AddResult;
+ typedef typename HashMapType::iterator iterator;
+ typedef typename HashMapType::const_iterator const_iterator;
WeakGCMap()
+ : m_gcThreshold(minGCThreshold)
{
}
- bool isEmpty() { return m_map.isEmpty(); }
- void clear()
+ ValueArg* get(const KeyType& key) const
{
- 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();
+ return m_map.get(key);
}
- bool contains(const KeyType& key) const
+ AddResult set(const KeyType& key, ValueType value)
{
- return m_map.contains(key);
+ gcMapIfNeeded();
+ return m_map.set(key, WTF::move(value));
}
- iterator find(const KeyType& key)
+ ALWAYS_INLINE AddResult add(const KeyType& key, ValueType value)
{
- return m_map.find(key);
+ gcMapIfNeeded();
+ AddResult addResult = m_map.fastAdd(key, nullptr);
+ if (!addResult.iterator->value) { // New value or found a zombie value.
+ addResult.isNewEntry = true;
+ addResult.iterator->value = WTF::move(value);
+ }
+ return addResult;
}
- void remove(iterator iter)
+ bool remove(const KeyType& key)
{
- ASSERT(iter.m_iterator != m_map.end());
- HandleSlot slot = iter.m_iterator->second;
- ASSERT(slot);
- HandleHeap::heapFor(slot)->deallocate(slot);
- m_map.remove(iter.m_iterator);
+ return m_map.remove(key);
}
- ExternalType get(const KeyType& key) const
+ void clear()
{
- return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
+ m_map.clear();
}
- HandleSlot getSlot(const KeyType& key) const
+ iterator find(const KeyType& key)
{
- return m_map.get(key);
+ iterator it = m_map.find(key);
+ iterator end = m_map.end();
+ if (it != end && !it->value) // Found a zombie value.
+ return end;
+ return it;
}
- pair<iterator, bool> add(JSGlobalData& globalData, const KeyType& key, ExternalType value)
- {
- pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
- if (iter.second) {
- HandleSlot slot = globalData.allocateGlobalHandle();
- iter.first->second = slot;
- HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key));
- HandleHeap::heapFor(slot)->writeBarrier(slot, value);
- *slot = value;
- }
- return iter;
- }
-
- void set(iterator iter, ExternalType value)
+ const_iterator find(const KeyType& key) const
{
- HandleSlot slot = iter.m_iterator->second;
- ASSERT(slot);
- HandleHeap::heapFor(slot)->writeBarrier(slot, value);
- *slot = value;
+ return const_cast<WeakGCMap*>(this)->find(key);
}
- void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ bool contains(const KeyType& key) const
{
- pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
- HandleSlot slot = iter.first->second;
- if (iter.second) {
- slot = globalData.allocateGlobalHandle();
- HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
- iter.first->second = slot;
- }
- HandleHeap::heapFor(slot)->writeBarrier(slot, value);
- *slot = value;
+ return find(key) != m_map.end();
}
- ExternalType take(const KeyType& key)
+private:
+ static const int minGCThreshold = 3;
+
+ NEVER_INLINE void gcMap()
{
- 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;
- }
+ Vector<KeyType, 4> zombies;
- size_t size() { return m_map.size(); }
+ for (iterator it = m_map.begin(), end = m_map.end(); it != end; ++it) {
+ if (!it->value)
+ zombies.append(it->key);
+ }
- iterator begin() { return iterator(m_map.begin()); }
- iterator end() { return iterator(m_map.end()); }
-
- ~WeakGCMap()
- {
- clear();
+ for (size_t i = 0; i < zombies.size(); ++i)
+ m_map.remove(zombies[i]);
}
-
-private:
- virtual void finalize(Handle<Unknown> handle, void* context)
+
+ void gcMapIfNeeded()
{
- HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
- ASSERT(slot);
- HandleHeap::heapFor(slot)->deallocate(slot);
+ if (m_map.size() < m_gcThreshold)
+ return;
+
+ gcMap();
+ m_gcThreshold = std::max(minGCThreshold, m_map.size() * 2 - 1);
}
- MapType m_map;
+ HashMapType m_map;
+ int m_gcThreshold;
};
+template<typename KeyArg, typename RawMappedArg, typename HashArg, typename KeyTraitsArg>
+const int WeakGCMap<KeyArg, RawMappedArg, HashArg, KeyTraitsArg>::minGCThreshold;
+
} // namespace JSC
#endif // WeakGCMap_h