Bug 54988 - Re-create StructureTransitionTable class, encapsulate transition table
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Feb 2011 21:49:59 +0000 (21:49 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 22 Feb 2011 21:49:59 +0000 (21:49 +0000)
Reviewed by Sam Weinig.

The Structure class keeps a table of transitions to derived Structure types. Since
this table commonly contains a single entry we employ an optimization where instead
of holding a map, we may hold a pointer directly to a single instance of the mapped
type. We use an additional bit of data to flag whether the pointer is currently
pointing to a table of transitions, or a singleton transition. Previously we had
commonly used a pattern of storing data in the low bits of pointers, but had moved
away from this since it causes false leaks to be reported by the leaks tool. However
in this case, the entries in the map are weak links - this pointer will never be
responsible for keeping an object alive.  As such we can use this approach provided
that the bit is set when a table is not in use (otherwise the table would appear to
be leaked).

Additionally, the transition table currently allows two entries to exist for a given
key - one specialized to a particular value, and one not specialized. This is
unnecessary, wasteful, and a little inconsistent. (If you create an entry for a
specialized value, then a non-specialized entry, both will exist.  If you create an
entry for a non-specialized value, then try to create a specialized entry, only a
non-specialized form will be allowed.)

This shows a small progression on v8.

* JavaScriptCore.exp:
* runtime/JSObject.h:
(JSC::JSObject::putDirectInternal):
* runtime/Structure.cpp:
(JSC::StructureTransitionTable::contains):
(JSC::StructureTransitionTable::get):
(JSC::StructureTransitionTable::remove):
(JSC::StructureTransitionTable::add):
(JSC::Structure::dumpStatistics):
(JSC::Structure::Structure):
(JSC::Structure::~Structure):
(JSC::Structure::addPropertyTransitionToExistingStructure):
(JSC::Structure::addPropertyTransition):
* runtime/Structure.h:
(JSC::Structure::get):
* runtime/StructureTransitionTable.h:
(JSC::StructureTransitionTable::Hash::hash):
(JSC::StructureTransitionTable::Hash::equal):
(JSC::StructureTransitionTable::HashTraits::emptyValue):
(JSC::StructureTransitionTable::HashTraits::constructDeletedValue):
(JSC::StructureTransitionTable::HashTraits::isDeletedValue):
(JSC::StructureTransitionTable::StructureTransitionTable):
(JSC::StructureTransitionTable::~StructureTransitionTable):
(JSC::StructureTransitionTable::isUsingSingleSlot):
(JSC::StructureTransitionTable::map):
(JSC::StructureTransitionTable::setMap):
(JSC::StructureTransitionTable::singleTransition):
(JSC::StructureTransitionTable::setSingleTransition):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@79355 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.exp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/Structure.cpp
Source/JavaScriptCore/runtime/Structure.h
Source/JavaScriptCore/runtime/StructureTransitionTable.h

index 7bfa1a7..5a906ea 100644 (file)
@@ -1,3 +1,59 @@
+2011-02-22  Gavin Barraclough  <barraclough@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        Bug 54988 - Re-create StructureTransitionTable class, encapsulate transition table
+
+        The Structure class keeps a table of transitions to derived Structure types. Since
+        this table commonly contains a single entry we employ an optimization where instead
+        of holding a map, we may hold a pointer directly to a single instance of the mapped
+        type. We use an additional bit of data to flag whether the pointer is currently
+        pointing to a table of transitions, or a singleton transition. Previously we had
+        commonly used a pattern of storing data in the low bits of pointers, but had moved
+        away from this since it causes false leaks to be reported by the leaks tool. However
+        in this case, the entries in the map are weak links - this pointer will never be
+        responsible for keeping an object alive.  As such we can use this approach provided
+        that the bit is set when a table is not in use (otherwise the table would appear to
+        be leaked).
+
+        Additionally, the transition table currently allows two entries to exist for a given
+        key - one specialized to a particular value, and one not specialized. This is
+        unnecessary, wasteful, and a little inconsistent. (If you create an entry for a
+        specialized value, then a non-specialized entry, both will exist.  If you create an
+        entry for a non-specialized value, then try to create a specialized entry, only a
+        non-specialized form will be allowed.)
+
+        This shows a small progression on v8.
+
+        * JavaScriptCore.exp:
+        * runtime/JSObject.h:
+        (JSC::JSObject::putDirectInternal):
+        * runtime/Structure.cpp:
+        (JSC::StructureTransitionTable::contains):
+        (JSC::StructureTransitionTable::get):
+        (JSC::StructureTransitionTable::remove):
+        (JSC::StructureTransitionTable::add):
+        (JSC::Structure::dumpStatistics):
+        (JSC::Structure::Structure):
+        (JSC::Structure::~Structure):
+        (JSC::Structure::addPropertyTransitionToExistingStructure):
+        (JSC::Structure::addPropertyTransition):
+        * runtime/Structure.h:
+        (JSC::Structure::get):
+        * runtime/StructureTransitionTable.h:
+        (JSC::StructureTransitionTable::Hash::hash):
+        (JSC::StructureTransitionTable::Hash::equal):
+        (JSC::StructureTransitionTable::HashTraits::emptyValue):
+        (JSC::StructureTransitionTable::HashTraits::constructDeletedValue):
+        (JSC::StructureTransitionTable::HashTraits::isDeletedValue):
+        (JSC::StructureTransitionTable::StructureTransitionTable):
+        (JSC::StructureTransitionTable::~StructureTransitionTable):
+        (JSC::StructureTransitionTable::isUsingSingleSlot):
+        (JSC::StructureTransitionTable::map):
+        (JSC::StructureTransitionTable::setMap):
+        (JSC::StructureTransitionTable::singleTransition):
+        (JSC::StructureTransitionTable::setSingleTransition):
+
 2011-02-22  Andras Becsi  <abecsi@webkit.org>
 
         Reviewed by Laszlo Gombos.
index dae6ec5..73d119b 100644 (file)
@@ -310,7 +310,6 @@ __ZN3JSC9CodeBlockD1Ev
 __ZN3JSC9CodeBlockD2Ev
 __ZN3JSC9MarkStack10s_pageSizeE
 __ZN3JSC9MarkStack18initializePagesizeEv
-__ZN3JSC9Structure13hasTransitionEPN3WTF10StringImplEj
 __ZN3JSC9Structure17stopIgnoringLeaksEv
 __ZN3JSC9Structure18startIgnoringLeaksEv
 __ZN3JSC9Structure21addPropertyTransitionEPS0_RKNS_10IdentifierEjPNS_6JSCellERm
index bbfd85a..4541f6c 100644 (file)
@@ -630,16 +630,6 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
         return true;
     }
 
-    // If we have a specific function, we may have got to this point if there is
-    // already a transition with the correct property name and attributes, but
-    // specialized to a different function.  In this case we just want to give up
-    // and despecialize the transition.
-    // In this case we clear the value of specificFunction which will result
-    // in us adding a non-specific transition, and any subsequent lookup in
-    // Structure::addPropertyTransitionToExistingStructure will just use that.
-    if (specificFunction && m_structure->hasTransition(propertyName, attributes))
-        specificFunction = 0;
-
     RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
 
     if (currentCapacity != structure->propertyStorageCapacity())
index 784f83a..0476cb0 100644 (file)
@@ -79,103 +79,67 @@ static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
 
 static int comparePropertyMapEntryIndices(const void* a, const void* b);
 
-inline void Structure::setTransitionTable(TransitionTable* table)
+bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
 {
-    ASSERT(m_isUsingSingleSlot);
-#ifndef NDEBUG
-    setSingleTransition(0);
-#endif
-    m_isUsingSingleSlot = false;
-    m_transitions.m_table = table;
-    // This implicitly clears the flag that indicates we're using a single transition
-    ASSERT(!m_isUsingSingleSlot);
-}
-
-// 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 Structure::transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
-{
-    if (m_isUsingSingleSlot) {
-        Structure* existingTransition = singleTransition();
-        return existingTransition && existingTransition->m_nameInPrevious.get() == key.first
-               && existingTransition->m_attributesInPrevious == key.second
-               && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0);
-    }
-    TransitionTable::iterator find = transitionTable()->find(key);
-    if (find == transitionTable()->end())
-        return false;
-
-    return find->second.first || find->second.second->transitionedFor(specificValue);
-}
-
-inline Structure* Structure::transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const
-{
-    if (m_isUsingSingleSlot) {
-        Structure* existingTransition = singleTransition();
-        if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first
-            && existingTransition->m_attributesInPrevious == key.second
-            && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0))
-            return existingTransition;
-        return 0;
+    if (isUsingSingleSlot()) {
+        Structure* transition = singleTransition();
+        return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
     }
-
-    Transition transition = transitionTable()->get(key);
-    if (transition.second && transition.second->transitionedFor(specificValue))
-        return transition.second;
-    return transition.first;
+    return map()->contains(make_pair(rep, attributes));
 }
 
-inline bool Structure::transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const
+inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
 {
-    if (m_isUsingSingleSlot) {
+    if (isUsingSingleSlot()) {
         Structure* transition = singleTransition();
-        return transition && transition->m_nameInPrevious == key.first
-        && transition->m_attributesInPrevious == key.second;
+        return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
     }
-    return transitionTable()->contains(key);
+    return map()->get(make_pair(rep, attributes));
 }
 
-inline void Structure::transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue)
+inline void StructureTransitionTable::remove(Structure* structure)
 {
-    if (m_isUsingSingleSlot) {
-        ASSERT(transitionTableContains(key, specificValue));
+    if (isUsingSingleSlot()) {
+        // If more than one transition had been added, then we wouldn't be in
+        // single slot mode (even despecifying a from a specific value triggers
+        // map mode).
+        // As such, the passed structure *must* be the existing transition.
+        ASSERT(singleTransition() == structure);
         setSingleTransition(0);
-        return;
+    } else {
+        // Check whether a mapping exists for structure's key, and whether the
+        // entry is structure (the latter check may fail if we initially had a
+        // transition with a specific value, and this has been despecified).
+        TransitionMap::iterator entry = map()->find(make_pair(structure->m_nameInPrevious, structure->m_attributesInPrevious));
+        if (entry != map()->end() && structure == entry->second)
+            map()->remove(entry);
     }
-    TransitionTable::iterator find = transitionTable()->find(key);
-    if (!specificValue)
-        find->second.first = 0;
-    else
-        find->second.second = 0;
-    if (!find->second.first && !find->second.second)
-        transitionTable()->remove(find);
 }
 
-inline void Structure::transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
+inline void StructureTransitionTable::add(Structure* structure)
 {
-    if (m_isUsingSingleSlot) {
-        if (!singleTransition()) {
+    if (isUsingSingleSlot()) {
+        Structure* existingTransition = singleTransition();
+
+        // This handles the first transition being added.
+        if (!existingTransition) {
             setSingleTransition(structure);
             return;
         }
-        Structure* existingTransition = singleTransition();
-        TransitionTable* transitionTable = new TransitionTable;
-        setTransitionTable(transitionTable);
-        if (existingTransition)
-            transitionTableAdd(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious);
+
+        // This handles the second transition being added
+        // (or the first transition being despecified!)
+        setMap(new TransitionMap());
+        add(existingTransition);
     }
-    if (!specificValue) {
-        TransitionTable::iterator find = transitionTable()->find(key);
-        if (find == transitionTable()->end())
-            transitionTable()->add(key, Transition(structure, static_cast<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(!transitionTable()->contains(key));
-        transitionTable()->add(key, Transition(static_cast<Structure*>(0), structure));
+
+    // Add the structure to the map.
+    std::pair<TransitionMap::iterator, bool> result = map()->add(make_pair(structure->m_nameInPrevious, structure->m_attributesInPrevious), structure);
+    if (!result.second) {
+        // There already is an entry! - we should only hit this when despecifying.
+        ASSERT(result.first->second->m_specificValueInPrevious);
+        ASSERT(!structure->m_specificValueInPrevious);
+        result.first->second = structure;
     }
 }
 
@@ -192,12 +156,12 @@ void Structure::dumpStatistics()
     for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
         Structure* structure = *it;
         if (structure->m_usingSingleTransitionSlot) {
-            if (!structure->m_transitions.singleTransition)
+            if (!structure->m_transitionTable.singleTransition())
                 ++numberLeaf;
             else
                 ++numberUsingSingleSlot;
 
-           if (!structure->m_previous && !structure->m_transitions.singleTransition)
+           if (!structure->m_previous && !structure->m_transitionTable.singleTransition())
                 ++numberSingletons;
         }
 
@@ -238,10 +202,7 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo, unsigned anony
     , m_attributesInPrevious(0)
     , m_specificFunctionThrashCount(0)
     , m_anonymousSlotCount(anonymousSlotCount)
-    , m_isUsingSingleSlot(true)
 {
-    m_transitions.m_singleTransition = 0;
-
     ASSERT(m_prototype);
     ASSERT(m_prototype->isObject() || m_prototype->isNull());
 
@@ -275,10 +236,7 @@ Structure::Structure(const Structure* previous)
     , m_attributesInPrevious(0)
     , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
     , m_anonymousSlotCount(previous->anonymousSlotCount())
-    , m_isUsingSingleSlot(true)
 {
-    m_transitions.m_singleTransition = 0;
-
     ASSERT(m_prototype);
     ASSERT(m_prototype->isObject() || m_prototype->isNull());
 
@@ -301,8 +259,7 @@ Structure::~Structure()
 {
     if (m_previous) {
         ASSERT(m_nameInPrevious);
-        m_previous->transitionTableRemove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious);
-
+        m_previous->m_transitionTable.remove(this);
     }
 
     if (m_propertyTable) {
@@ -316,9 +273,6 @@ Structure::~Structure()
         fastFree(m_propertyTable);
     }
 
-    if (!m_isUsingSingleSlot)
-        delete transitionTable();
-
 #ifndef NDEBUG
 #if ENABLE(JSC_MULTIPLE_THREADS)
     MutexLocker protect(ignoreSetMutex);
@@ -482,7 +436,10 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct
     ASSERT(!structure->isDictionary());
     ASSERT(structure->typeInfo().type() == ObjectType);
 
-    if (Structure* existingTransition = structure->transitionTableGet(make_pair(propertyName.impl(), attributes), specificValue)) {
+    if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) {
+        JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious;
+        if (specificValueInPrevious && specificValueInPrevious != specificValue)
+            return 0;
         ASSERT(existingTransition->m_offset != noOffset);
         offset = existingTransition->m_offset + existingTransition->m_anonymousSlotCount;
         ASSERT(offset >= structure->m_anonymousSlotCount);
@@ -495,6 +452,16 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct
 
 PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
 {
+    // If we have a specific function, we may have got to this point if there is
+    // already a transition with the correct property name and attributes, but
+    // specialized to a different function.  In this case we just want to give up
+    // and despecialize the transition.
+    // In this case we clear the value of specificFunction which will result
+    // in us adding a non-specific transition, and any subsequent lookup in
+    // Structure::addPropertyTransitionToExistingStructure will just use that.
+    if (specificValue && structure->m_transitionTable.contains(propertyName.impl(), attributes))
+        specificValue = 0;
+
     ASSERT(!structure->isDictionary());
     ASSERT(structure->typeInfo().type() == ObjectType);
     ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
@@ -543,7 +510,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con
 
     transition->m_offset = offset - structure->m_anonymousSlotCount;
     ASSERT(structure->anonymousSlotCount() == transition->anonymousSlotCount());
-    structure->transitionTableAdd(make_pair(propertyName.impl(), attributes), transition.get(), specificValue);
+    structure->m_transitionTable.add(transition.get());
     return transition.release();
 }
 
@@ -974,11 +941,6 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel
     return newOffset;
 }
 
-bool Structure::hasTransition(StringImpl* rep, unsigned attributes)
-{
-    return transitionTableHasTransition(make_pair(rep, attributes));
-}
-
 size_t Structure::remove(const Identifier& propertyName)
 {
     ASSERT(!propertyName.isNull());
index dec2616..ea860a0 100644 (file)
@@ -115,15 +115,6 @@ namespace JSC {
             ASSERT(!propertyName.isNull());
             return get(propertyName.impl(), attributes, specificValue);
         }
-        bool transitionedFor(const JSCell* specificValue)
-        {
-            return m_specificValueInPrevious == specificValue;
-        }
-        bool hasTransition(StringImpl*, unsigned attributes);
-        bool hasTransition(const Identifier& propertyName, unsigned attributes)
-        {
-            return hasTransition(propertyName.impl(), attributes);
-        }
 
         bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
@@ -190,20 +181,6 @@ namespace JSC {
             return m_offset == noOffset ? 0 : m_offset + 1;
         }
 
-        typedef std::pair<Structure*, Structure*> Transition;
-        typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
-
-        inline bool transitionTableContains(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
-        inline void transitionTableRemove(const StructureTransitionTableHash::Key& key, JSCell* specificValue);
-        inline void transitionTableAdd(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue);
-        inline bool transitionTableHasTransition(const StructureTransitionTableHash::Key& key) const;
-        inline Structure* transitionTableGet(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const;
-
-        TransitionTable* transitionTable() const { ASSERT(!m_isUsingSingleSlot); return m_transitions.m_table; }
-        inline void setTransitionTable(TransitionTable* table);
-        Structure* singleTransition() const { ASSERT(m_isUsingSingleSlot); return m_transitions.m_singleTransition; }
-        void setSingleTransition(Structure* structure) { ASSERT(m_isUsingSingleSlot); m_transitions.m_singleTransition = structure; }
-        
         bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
 
         static const unsigned emptyEntryIndex = 0;
@@ -225,11 +202,7 @@ namespace JSC {
 
         const ClassInfo* m_classInfo;
 
-        // 'm_isUsingSingleSlot' indicates whether we are using the single transition optimisation.
-        union {
-            TransitionTable* m_table;
-            Structure* m_singleTransition;
-        } m_transitions;
+        StructureTransitionTable m_transitionTable;
 
         WeakGCPtr<JSPropertyNameIterator> m_enumerationCache;
 
@@ -254,8 +227,7 @@ namespace JSC {
 #endif
         unsigned m_specificFunctionThrashCount : 2;
         unsigned m_anonymousSlotCount : 5;
-        unsigned m_isUsingSingleSlot : 1;
-        // 4 free bits
+        // 5 free bits
     };
 
     inline size_t Structure::get(const Identifier& propertyName)
index 7e9d7ff..da78e1b 100644 (file)
 
 namespace JSC {
 
-    class Structure;
+class Structure;
 
-    struct StructureTransitionTableHash {
+class StructureTransitionTable {
+    static const intptr_t UsingSingleSlotFlag = 1;
+
+    struct Hash {
         typedef std::pair<RefPtr<StringImpl>, unsigned> Key;
         static unsigned hash(const Key& p)
         {
@@ -52,7 +55,7 @@ namespace JSC {
         static const bool safeToCompareToEmptyOrDeleted = true;
     };
 
-    struct StructureTransitionTableHashTraits {
+    struct HashTraits {
         typedef WTF::HashTraits<RefPtr<StringImpl> > FirstTraits;
         typedef WTF::GenericHashTraits<unsigned> SecondTraits;
         typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
@@ -66,6 +69,62 @@ namespace JSC {
         static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
     };
 
+    typedef HashMap<Hash::Key, Structure*, Hash, HashTraits> TransitionMap;
+
+public:
+    StructureTransitionTable()
+        : m_data(UsingSingleSlotFlag)
+    {
+    }
+
+    ~StructureTransitionTable()
+    {
+        if (!isUsingSingleSlot())
+            delete map();
+    }
+
+    inline void add(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<TransitionMap*>(m_data);
+    }
+
+    void setMap(TransitionMap* map)
+    {
+        ASSERT(isUsingSingleSlot());
+
+        // 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());
+        return reinterpret_cast<Structure*>(m_data & ~UsingSingleSlotFlag);
+    }
+
+    void setSingleTransition(Structure* structure)
+    {
+        ASSERT(isUsingSingleSlot());
+        m_data = reinterpret_cast<intptr_t>(structure) | UsingSingleSlotFlag;
+    }
+
+    intptr_t m_data;
+};
+
 } // namespace JSC
 
 #endif // StructureTransitionTable_h