]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - runtime/StructureTransitionTable.h
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / runtime / StructureTransitionTable.h
index 320dbddc9a41eb627c60ccde75459ecd086df777..adebad28480c24db39a5015da6cdad4add0747d3 100644 (file)
 #define StructureTransitionTable_h
 
 #include "UString.h"
+#include "WeakGCMap.h"
 #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 {
 
-    class Structure;
+class Structure;
 
-    struct StructureTransitionTableHash {
-        typedef std::pair<RefPtr<UString::Rep>, unsigned> Key;
+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->existingHash();
@@ -53,8 +55,8 @@ namespace JSC {
         static const bool safeToCompareToEmptyOrDeleted = true;
     };
 
-    struct StructureTransitionTableHashTraits {
-        typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits;
+    struct HashTraits {
+        typedef WTF::HashTraits<RefPtr<StringImpl> > FirstTraits;
         typedef WTF::GenericHashTraits<unsigned> SecondTraits;
         typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType;
 
@@ -67,98 +69,104 @@ namespace JSC {
         static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
     };
 
-    class StructureTransitionTable {
-        typedef std::pair<Structure*, Structure*> Transition;
-        typedef HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> TransitionTable;
-    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)
+    struct WeakGCMapFinalizerCallback {
+        static void* finalizerContextFor(Hash::Key)
         {
-            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);
+            return 0;
         }
-        void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue)
+
+        static inline Hash::Key keyForFinalizer(void* context, Structure* structure)
         {
-            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));
-            }
+            return keyForWeakGCMapFinalizer(context, structure);
         }
+    };
 
-    private:
-        TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; }
-        Structure* singleTransition() const {
-            ASSERT(usingSingleTransitionSlot());
-            return m_transitions.m_singleTransition.get();
+    typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap;
+
+    static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*);
+
+public:
+    StructureTransitionTable()
+        : m_data(UsingSingleSlotFlag)
+    {
+    }
+
+    ~StructureTransitionTable()
+    {
+        if (!isUsingSingleSlot())
+            delete map();
+        else
+            clearSingleTransition();
+    }
+
+    inline void add(JSGlobalData&, 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);
+    }
+
+    HandleSlot slot() const
+    {
+        ASSERT(isUsingSingleSlot());
+        return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag);
+    }
+
+    void setMap(TransitionMap* map)
+    {
+        ASSERT(isUsingSingleSlot());
+        
+        if (HandleSlot slot = this->slot())
+            HandleHeap::heapFor(slot)->deallocate(slot);
+
+        // 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 (HandleSlot slot = this->slot()) {
+            if (*slot)
+                return reinterpret_cast<Structure*>(slot->asCell());
         }
-        bool usingSingleTransitionSlot() const { return m_transitions.m_singleTransition.isFlagSet(usingSingleSlot); }
-        void setSingleTransition(Structure* structure)
-        { 
-            ASSERT(usingSingleTransitionSlot());
-            m_transitions.m_singleTransition.set(structure);
+        return 0;
+    }
+    
+    void clearSingleTransition()
+    {
+        ASSERT(isUsingSingleSlot());
+        if (HandleSlot slot = this->slot())
+            HandleHeap::heapFor(slot)->deallocate(slot);
+    }
+    
+    void setSingleTransition(JSGlobalData& globalData, Structure* structure)
+    {
+        ASSERT(isUsingSingleSlot());
+        HandleSlot slot = this->slot();
+        if (!slot) {
+            slot = globalData.allocateGlobalHandle();
+            HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0);
+            m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag;
         }
+        HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure));
+        *slot = reinterpret_cast<JSCell*>(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;
-    };
+    intptr_t m_data;
+};
 
 } // namespace JSC