#ifndef StructureTransitionTable_h
#define StructureTransitionTable_h
-#include "UString.h"
+#include "IndexingType.h"
+#include "WeakGCMap.h"
#include <wtf/HashFunctions.h>
-#include <wtf/HashMap.h>
-#include <wtf/HashTraits.h>
+#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
+#include <wtf/text/StringImpl.h>
namespace JSC {
- class Structure;
+class JSCell;
+class Structure;
- struct StructureTransitionTableHash {
- typedef std::pair<RefPtr<UString::Rep>, 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<RefPtr<StringImpl>, 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)
static const bool safeToCompareToEmptyOrDeleted = true;
};
- struct StructureTransitionTableHashTraits {
- typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits;
- typedef WTF::GenericHashTraits<unsigned> SecondTraits;
- typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
+ typedef WeakGCMap<Hash::Key, Structure, Hash> 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<Structure*, Structure*> Transition;
- typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> 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<TransitionMap*>(m_data);
+ }
+
+ WeakImpl* weakImpl() const
+ {
+ ASSERT(isUsingSingleSlot());
+ return reinterpret_cast<WeakImpl*>(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<intptr_t>(map);
+
+ ASSERT(!isUsingSingleSlot());
+ }
+
+ Structure* singleTransition() const
+ {
+ ASSERT(isUsingSingleSlot());
+ if (WeakImpl* impl = this->weakImpl()) {
+ if (impl->state() == WeakImpl::Live)
+ return reinterpret_cast<Structure*>(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<JSCell*>(structure));
+ m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag;
+ }
+
+ intptr_t m_data;
+};
} // namespace JSC