X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..93a3786624b2768d89bfa27e46598dc64e2fb70a:/runtime/StructureTransitionTable.h diff --git a/runtime/StructureTransitionTable.h b/runtime/StructureTransitionTable.h index 5b4f4e6..6012020 100644 --- a/runtime/StructureTransitionTable.h +++ b/runtime/StructureTransitionTable.h @@ -26,21 +26,81 @@ #ifndef StructureTransitionTable_h #define StructureTransitionTable_h -#include "UString.h" +#include "IndexingType.h" +#include "WeakGCMap.h" #include -#include -#include +#include #include +#include namespace JSC { - class Structure; +class JSCell; +class Structure; - struct StructureTransitionTableHash { - typedef std::pair, unsigned> Key; +static const unsigned FirstInternalAttribute = 1 << 6; // Use for transitions that don't have to do with property additions. + +// Support for attributes used to indicate transitions not related to properties. +// If any of these are used, the string portion of the key should be 0. +enum NonPropertyTransition { + AllocateUndecided, + AllocateInt32, + AllocateDouble, + AllocateContiguous, + AllocateArrayStorage, + AllocateSlowPutArrayStorage, + SwitchToSlowPutArrayStorage, + AddIndexedAccessors +}; + +inline unsigned toAttributes(NonPropertyTransition transition) +{ + return transition + FirstInternalAttribute; +} + +inline IndexingType newIndexingType(IndexingType oldType, NonPropertyTransition transition) +{ + switch (transition) { + case AllocateUndecided: + ASSERT(!hasIndexedProperties(oldType)); + return oldType | UndecidedShape; + case AllocateInt32: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType)); + return (oldType & ~IndexingShapeMask) | Int32Shape; + case AllocateDouble: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType)); + return (oldType & ~IndexingShapeMask) | DoubleShape; + case AllocateContiguous: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType)); + return (oldType & ~IndexingShapeMask) | ContiguousShape; + case AllocateArrayStorage: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType)); + return (oldType & ~IndexingShapeMask) | ArrayStorageShape; + case AllocateSlowPutArrayStorage: + ASSERT(!hasIndexedProperties(oldType) || hasUndecided(oldType) || hasInt32(oldType) || hasDouble(oldType) || hasContiguous(oldType) || hasContiguous(oldType)); + return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; + case SwitchToSlowPutArrayStorage: + ASSERT(hasFastArrayStorage(oldType)); + return (oldType & ~IndexingShapeMask) | SlowPutArrayStorageShape; + case AddIndexedAccessors: + return oldType | MayHaveIndexedAccessors; + default: + RELEASE_ASSERT_NOT_REACHED(); + return oldType; + } +} + +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(); + unsigned result = p.second; + if (p.first) + result += p.first->existingHash(); + return result; } static bool equal(const Key& a, const Key& b) @@ -51,62 +111,83 @@ namespace JSC { static const bool safeToCompareToEmptyOrDeleted = true; }; - struct StructureTransitionTableHashTraits { - typedef WTF::HashTraits > FirstTraits; - typedef WTF::GenericHashTraits SecondTraits; - typedef std::pair TraitType; + typedef WeakGCMap TransitionMap; - static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; - static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); } +public: + StructureTransitionTable() + : m_data(UsingSingleSlotFlag) + { + } - static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction; + ~StructureTransitionTable() + { + if (!isUsingSingleSlot()) { + delete map(); + return; + } - static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); } - static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } - }; + WeakImpl* impl = this->weakImpl(); + if (!impl) + return; + WeakSet::deallocate(impl); + } - 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) - { - return m_table.contains(key); - } - void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) - { - 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); - } - 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)); - } + inline void add(VM&, 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); + } + + WeakImpl* weakImpl() const + { + ASSERT(isUsingSingleSlot()); + return reinterpret_cast(m_data & ~UsingSingleSlotFlag); + } + void setMap(TransitionMap* map) + { + ASSERT(isUsingSingleSlot()); + + if (WeakImpl* impl = this->weakImpl()) + WeakSet::deallocate(impl); + + // 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 (WeakImpl* impl = this->weakImpl()) { + if (impl->state() == WeakImpl::Live) + return reinterpret_cast(impl->jsValue().asCell()); } - private: - TransitionTable m_table; - }; + return 0; + } + + void setSingleTransition(VM&, Structure* structure) + { + ASSERT(isUsingSingleSlot()); + if (WeakImpl* impl = this->weakImpl()) + WeakSet::deallocate(impl); + WeakImpl* impl = WeakSet::allocate(reinterpret_cast(structure)); + m_data = reinterpret_cast(impl) | UsingSingleSlotFlag; + } + + intptr_t m_data; +}; } // namespace JSC