X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..14957cd040308e3eeec43d26bae5d76da13fcd85:/runtime/StructureTransitionTable.h diff --git a/runtime/StructureTransitionTable.h b/runtime/StructureTransitionTable.h index 5b4f4e6..adebad2 100644 --- a/runtime/StructureTransitionTable.h +++ b/runtime/StructureTransitionTable.h @@ -27,20 +27,24 @@ #define StructureTransitionTable_h #include "UString.h" +#include "WeakGCMap.h" #include -#include #include +#include #include namespace JSC { - class Structure; +class Structure; - struct StructureTransitionTableHash { - typedef std::pair, unsigned> Key; +class StructureTransitionTable { + static const intptr_t UsingSingleSlotFlag = 1; + + struct Hash { + typedef std::pair, unsigned> Key; static unsigned hash(const Key& p) { - return p.first->computedHash(); + return p.first->existingHash(); } static bool equal(const Key& a, const Key& b) @@ -51,8 +55,8 @@ namespace JSC { static const bool safeToCompareToEmptyOrDeleted = true; }; - struct StructureTransitionTableHashTraits { - typedef WTF::HashTraits > FirstTraits; + struct HashTraits { + typedef WTF::HashTraits > FirstTraits; typedef WTF::GenericHashTraits SecondTraits; typedef std::pair TraitType; @@ -65,48 +69,104 @@ namespace JSC { static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } }; - class StructureTransitionTable { - typedef std::pair Transition; - typedef HashMap TransitionTable; - public: - // The contains and get methods accept imprecise matches, so if an unspecialised transition exists - // for the given key they will consider that transition to be a match. If a specialised transition - // exists and it matches the provided specificValue, get will return the specific transition. - inline bool contains(const StructureTransitionTableHash::Key&, JSCell* specificValue); - inline Structure* get(const StructureTransitionTableHash::Key&, JSCell* specificValue) const; - bool hasTransition(const StructureTransitionTableHash::Key& key) + struct WeakGCMapFinalizerCallback { + static void* finalizerContextFor(Hash::Key) { - return m_table.contains(key); + return 0; } - void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) + + static inline Hash::Key keyForFinalizer(void* context, Structure* structure) { - TransitionTable::iterator find = m_table.find(key); - if (!specificValue) - find->second.first = 0; - else - find->second.second = 0; - if (!find->second.first && !find->second.second) - m_table.remove(find); + return keyForWeakGCMapFinalizer(context, structure); } - void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) - { - if (!specificValue) { - TransitionTable::iterator find = m_table.find(key); - if (find == m_table.end()) - m_table.add(key, Transition(structure, 0)); - else - find->second.first = structure; - } else { - // If we're adding a transition to a specific value, then there cannot be - // an existing transition - ASSERT(!m_table.contains(key)); - m_table.add(key, Transition(0, structure)); - } + }; + + typedef WeakGCMap TransitionMap; + + static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*); + +public: + StructureTransitionTable() + : m_data(UsingSingleSlotFlag) + { + } + + ~StructureTransitionTable() + { + if (!isUsingSingleSlot()) + delete map(); + else + clearSingleTransition(); + } + + inline void add(JSGlobalData&, Structure*); + inline void remove(Structure*); + inline bool contains(StringImpl* rep, unsigned attributes) const; + inline Structure* get(StringImpl* rep, unsigned attributes) const; +private: + bool isUsingSingleSlot() const + { + return m_data & UsingSingleSlotFlag; + } + + TransitionMap* map() const + { + ASSERT(!isUsingSingleSlot()); + return reinterpret_cast(m_data); + } + + HandleSlot slot() const + { + ASSERT(isUsingSingleSlot()); + return reinterpret_cast(m_data & ~UsingSingleSlotFlag); + } + + void setMap(TransitionMap* map) + { + ASSERT(isUsingSingleSlot()); + + if (HandleSlot slot = this->slot()) + HandleHeap::heapFor(slot)->deallocate(slot); + + // This implicitly clears the flag that indicates we're using a single transition + m_data = reinterpret_cast(map); + + ASSERT(!isUsingSingleSlot()); + } + + Structure* singleTransition() const + { + ASSERT(isUsingSingleSlot()); + if (HandleSlot slot = this->slot()) { + if (*slot) + return reinterpret_cast(slot->asCell()); } - private: - TransitionTable m_table; - }; + return 0; + } + + void clearSingleTransition() + { + ASSERT(isUsingSingleSlot()); + if (HandleSlot slot = this->slot()) + HandleHeap::heapFor(slot)->deallocate(slot); + } + + void setSingleTransition(JSGlobalData& globalData, Structure* structure) + { + ASSERT(isUsingSingleSlot()); + HandleSlot slot = this->slot(); + if (!slot) { + slot = globalData.allocateGlobalHandle(); + HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0); + m_data = reinterpret_cast(slot) | UsingSingleSlotFlag; + } + HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast(structure)); + *slot = reinterpret_cast(structure); + } + + intptr_t m_data; +}; } // namespace JSC