diff options
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h')
-rw-r--r-- | src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h | 159 |
1 files changed, 150 insertions, 9 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h index 804cbeb1de..0fa7b73c59 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/StructureTransitionTable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,8 @@ #include <wtf/HashFunctions.h> #include <wtf/HashMap.h> #include <wtf/HashTraits.h> +#include <wtf/PtrAndFlags.h> +#include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> namespace JSC { @@ -37,7 +39,7 @@ namespace JSC { class Structure; struct StructureTransitionTableHash { - typedef std::pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> > Key; + typedef std::pair<RefPtr<UString::Rep>, unsigned> Key; static unsigned hash(const Key& p) { return p.first->computedHash(); @@ -53,20 +55,159 @@ namespace JSC { struct StructureTransitionTableHashTraits { typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits; - typedef WTF::GenericHashTraits<unsigned> SecondFirstTraits; - typedef WTF::GenericHashTraits<JSCell*> SecondSecondTraits; - typedef std::pair<FirstTraits::TraitType, std::pair<SecondFirstTraits::TraitType, SecondSecondTraits::TraitType> > TraitType; + typedef WTF::GenericHashTraits<unsigned> SecondTraits; + typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType; - static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondFirstTraits::emptyValueIsZero && SecondSecondTraits::emptyValueIsZero; - static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), std::make_pair(SecondFirstTraits::emptyValue(), SecondSecondTraits::emptyValue())); } + static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; + static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); } - static const bool needsDestruction = FirstTraits::needsDestruction || SecondFirstTraits::needsDestruction || SecondSecondTraits::needsDestruction; + static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction; static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); } static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } }; - typedef HashMap<StructureTransitionTableHash::Key, Structure*, StructureTransitionTableHash, StructureTransitionTableHashTraits> StructureTransitionTable; + class StructureTransitionTable { + typedef std::pair<Structure*, Structure*> Transition; + struct TransitionTable : public HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> { + typedef HashMap<unsigned, Structure*> AnonymousSlotMap; + + void addSlotTransition(unsigned count, Structure* structure) + { + ASSERT(!getSlotTransition(count)); + if (!m_anonymousSlotTable) + m_anonymousSlotTable.set(new AnonymousSlotMap); + m_anonymousSlotTable->add(count, structure); + } + + void removeSlotTransition(unsigned count) + { + ASSERT(getSlotTransition(count)); + m_anonymousSlotTable->remove(count); + } + + Structure* getSlotTransition(unsigned count) + { + if (!m_anonymousSlotTable) + return 0; + + AnonymousSlotMap::iterator find = m_anonymousSlotTable->find(count); + if (find == m_anonymousSlotTable->end()) + return 0; + return find->second; + } + private: + OwnPtr<AnonymousSlotMap> m_anonymousSlotTable; + }; + 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) + { + 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); + } + void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) + { + 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)); + } + } + + Structure* getAnonymousSlotTransition(unsigned count) + { + if (usingSingleTransitionSlot()) + return 0; + return table()->getSlotTransition(count); + } + + void addAnonymousSlotTransition(unsigned count, Structure* structure) + { + if (usingSingleTransitionSlot()) + reifySingleTransition(); + ASSERT(!table()->getSlotTransition(count)); + table()->addSlotTransition(count, structure); + } + + void removeAnonymousSlotTransition(unsigned count) + { + ASSERT(!usingSingleTransitionSlot()); + table()->removeSlotTransition(count); + } + private: + TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; } + Structure* singleTransition() const { + ASSERT(usingSingleTransitionSlot()); + return m_transitions.m_singleTransition.get(); + } + bool usingSingleTransitionSlot() const { return m_transitions.m_singleTransition.isFlagSet(usingSingleSlot); } + void setSingleTransition(Structure* structure) + { + ASSERT(usingSingleTransitionSlot()); + m_transitions.m_singleTransition.set(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<Structure, UsingSingleSlot> m_singleTransition; + } m_transitions; + }; } // namespace JSC |