Bug 54988 - Re-create StructureTransitionTable class, encapsulate transition table

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: http://svn.webkit.org/repository/webkit/trunk@79355 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index 7e9d7ff..da78e1b 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -35,9 +35,12 @@
 
 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 @@
         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 @@
         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