X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/f9bf01c6616d5ddcf65b13b33cedf9e387ff7a63..14957cd040308e3eeec43d26bae5d76da13fcd85:/runtime/StructureTransitionTable.h diff --git a/runtime/StructureTransitionTable.h b/runtime/StructureTransitionTable.h index 320dbdd..adebad2 100644 --- a/runtime/StructureTransitionTable.h +++ b/runtime/StructureTransitionTable.h @@ -27,19 +27,21 @@ #define StructureTransitionTable_h #include "UString.h" +#include "WeakGCMap.h" #include -#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->existingHash(); @@ -53,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; @@ -67,98 +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: - StructureTransitionTable() { - m_transitions.m_singleTransition.set(0); - m_transitions.m_singleTransition.setFlag(usingSingleSlot); - } - - ~StructureTransitionTable() { - if (!usingSingleTransitionSlot()) - delete table(); - } - - // 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; - inline bool hasTransition(const StructureTransitionTableHash::Key& key) const; - void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) + struct WeakGCMapFinalizerCallback { + static void* finalizerContextFor(Hash::Key) { - if (usingSingleTransitionSlot()) { - ASSERT(contains(key, specificValue)); - setSingleTransition(0); - return; - } - TransitionTable::iterator find = table()->find(key); - if (!specificValue) - find->second.first = 0; - else - find->second.second = 0; - if (!find->second.first && !find->second.second) - table()->remove(find); + return 0; } - void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) + + static inline Hash::Key keyForFinalizer(void* context, Structure* structure) { - if (usingSingleTransitionSlot()) { - if (!singleTransition()) { - setSingleTransition(structure); - return; - } - reifySingleTransition(); - } - if (!specificValue) { - TransitionTable::iterator find = table()->find(key); - if (find == table()->end()) - 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(!table()->contains(key)); - table()->add(key, Transition(0, structure)); - } + return keyForWeakGCMapFinalizer(context, structure); } + }; - private: - TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; } - Structure* singleTransition() const { - ASSERT(usingSingleTransitionSlot()); - return m_transitions.m_singleTransition.get(); + 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()); } - bool usingSingleTransitionSlot() const { return m_transitions.m_singleTransition.isFlagSet(usingSingleSlot); } - void setSingleTransition(Structure* structure) - { - ASSERT(usingSingleTransitionSlot()); - m_transitions.m_singleTransition.set(structure); + 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); + } - void setTransitionTable(TransitionTable* table) - { - ASSERT(usingSingleTransitionSlot()); -#ifndef NDEBUG - setSingleTransition(0); -#endif - m_transitions.m_table = table; - // This implicitly clears the flag that indicates we're using a single transition - ASSERT(!usingSingleTransitionSlot()); - } - inline void reifySingleTransition(); - - enum UsingSingleSlot { - usingSingleSlot - }; - // Last bit indicates whether we are using the single transition optimisation - union { - TransitionTable* m_table; - PtrAndFlagsBase m_singleTransition; - } m_transitions; - }; + intptr_t m_data; +}; } // namespace JSC