2011-04-15  Oliver Hunt  <oliver@apple.com>

        GC allocate Structure
        https://bugs.webkit.org/show_bug.cgi?id=58483

        Rolling r83894 r83827 r83810 r83809 r83808 back in with
        a workaround for the gcc bug seen by the gtk bots

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@84052 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index da78e1b..adebad2 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -27,8 +27,8 @@
 #define StructureTransitionTable_h
 
 #include "UString.h"
+#include "WeakGCMap.h"
 #include <wtf/HashFunctions.h>
-#include <wtf/HashMap.h>
 #include <wtf/HashTraits.h>
 #include <wtf/OwnPtr.h>
 #include <wtf/RefPtr.h>
@@ -69,7 +69,21 @@
         static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
     };
 
-    typedef HashMap<Hash::Key, Structure*, Hash, HashTraits> TransitionMap;
+    struct WeakGCMapFinalizerCallback {
+        static void* finalizerContextFor(Hash::Key)
+        {
+            return 0;
+        }
+
+        static inline Hash::Key keyForFinalizer(void* context, Structure* structure)
+        {
+            return keyForWeakGCMapFinalizer(context, structure);
+        }
+    };
+
+    typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap;
+
+    static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*);
 
 public:
     StructureTransitionTable()
@@ -81,9 +95,11 @@
     {
         if (!isUsingSingleSlot())
             delete map();
+        else
+            clearSingleTransition();
     }
 
-    inline void add(Structure*);
+    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;
@@ -100,9 +116,18 @@
         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);
@@ -113,13 +138,31 @@
     Structure* singleTransition() const
     {
         ASSERT(isUsingSingleSlot());
-        return reinterpret_cast<Structure*>(m_data & ~UsingSingleSlotFlag);
+        if (HandleSlot slot = this->slot()) {
+            if (*slot)
+                return reinterpret_cast<Structure*>(slot->asCell());
+        }
+        return 0;
     }
-
-    void setSingleTransition(Structure* structure)
+    
+    void clearSingleTransition()
     {
         ASSERT(isUsingSingleSlot());
-        m_data = reinterpret_cast<intptr_t>(structure) | UsingSingleSlotFlag;
+        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);
     }
 
     intptr_t m_data;