X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..217a6308cd6a1dc049a0bb69263bd4c91f91c4d0:/runtime/WeakGCMap.h diff --git a/runtime/WeakGCMap.h b/runtime/WeakGCMap.h index 39a91c5..f741fa4 100644 --- a/runtime/WeakGCMap.h +++ b/runtime/WeakGCMap.h @@ -26,96 +26,103 @@ #ifndef WeakGCMap_h #define WeakGCMap_h -#include "Collector.h" +#include +#include #include namespace JSC { -class JSCell; +// A HashMap with Weak values, which automatically removes values once they're garbage collected. -// A HashMap whose get() function returns emptyValue() for cells awaiting destruction. -template -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::Hash, + typename KeyTraitsArg = HashTraits > +class WeakGCMap : public HashMap, HashArg, KeyTraitsArg> { + typedef Weak MappedType; + typedef HashMap Base; + typedef WeakGCMap Self; + typedef HashTraits MappedTraits; + typedef typename MappedTraits::PassInType MappedPassInType; public: - typedef typename HashMap::iterator iterator; - typedef typename HashMap::const_iterator const_iterator; - - bool isEmpty() { return m_map.isEmpty(); } + typedef typename Base::KeyType KeyType; + typedef typename Base::AddResult AddResult; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + using Base::begin; + using Base::end; + using Base::size; + using Base::remove; + + WeakGCMap() + : m_gcThreshold(minGCThreshold) + { + } - MappedType get(const KeyType& key) const; - pair set(const KeyType&, const MappedType&); - MappedType take(const KeyType& key); + AddResult set(const KeyType& key, MappedPassInType value) + { + gcMapIfNeeded(); + return Base::set(key, value); + } - // 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. + AddResult add(const KeyType& key, MappedPassInType value) + { + gcMapIfNeeded(); + AddResult addResult = Base::add(key, nullptr); + if (!addResult.iterator->value) { // New value or found a zombie value. + addResult.isNewEntry = true; + addResult.iterator->value = value; + } + return addResult; + } - MappedType uncheckedGet(const KeyType& key) const { return m_map.get(key); } - bool uncheckedRemove(const KeyType&, const MappedType&); + iterator find(const KeyType& key) + { + iterator it = Base::find(key); + iterator end = Base::end(); + if (it != end && !it->value) // Found a zombie value. + return end; + return it; + } - iterator uncheckedBegin() { return m_map.begin(); } - iterator uncheckedEnd() { return m_map.end(); } + const_iterator find(const KeyType& key) const + { + return const_cast(this)->find(key); + } - const_iterator uncheckedBegin() const { return m_map.begin(); } - const_iterator uncheckedEnd() const { return m_map.end(); } + bool contains(const KeyType& key) const + { + return find(key) != end(); + } private: - HashMap m_map; -}; + static const int minGCThreshold = 3; + + void gcMap() + { + Vector zombies; + iterator end = this->end(); + for (iterator it = begin(); it != end; ++it) { + if (!it->value) + zombies.append(it->key); + } + for (size_t i = 0; i < zombies.size(); ++i) + remove(zombies[i]); + } + + void gcMapIfNeeded() + { + if (size() < m_gcThreshold) + return; -template -inline MappedType WeakGCMap::get(const KeyType& key) const -{ - MappedType result = m_map.get(key); - if (result == HashTraits::emptyValue()) - return result; - if (!Heap::isCellMarked(result)) - return HashTraits::emptyValue(); - return result; -} - -template -MappedType WeakGCMap::take(const KeyType& key) -{ - MappedType result = m_map.take(key); - if (result == HashTraits::emptyValue()) - return result; - if (!Heap::isCellMarked(result)) - return HashTraits::emptyValue(); - return result; -} - -template -pair::iterator, bool> WeakGCMap::set(const KeyType& key, const MappedType& value) -{ - Heap::markCell(value); // If value is newly allocated, it's not marked, so mark it now. - pair result = m_map.add(key, value); - if (!result.second) { // pre-existing entry - result.second = !Heap::isCellMarked(result.first->second); - result.first->second = value; + gcMap(); + m_gcThreshold = std::max(minGCThreshold, size() * 2 - 1); } - return result; -} - -template -bool WeakGCMap::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; -} + + int m_gcThreshold; +}; + +template +const int WeakGCMap::minGCThreshold; } // namespace JSC