ValueProfile does not make it safe to introspect cell values
after garbage collection
https://bugs.webkit.org/show_bug.cgi?id=67354

Reviewed by Gavin Barraclough.

ValueProfile buckets are now weak references, implemented using a
light-weight weak reference mechanism that this patch also adds (the
WeakReferenceHarvester).  If a cell stored in a ValueProfile bucket
is not marked, then the bucket is transformed into a Structure
pointer.  If the Structure is not marked either, then it is turned
into a ClassInfo pointer.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::visitAggregate):
(JSC::CodeBlock::visitWeakReferences):
* bytecode/CodeBlock.h:
* bytecode/ValueProfile.h:
(JSC::ValueProfile::ValueProfile):
(JSC::ValueProfile::classInfo):
(JSC::ValueProfile::numberOfInt32s):
(JSC::ValueProfile::numberOfDoubles):
(JSC::ValueProfile::numberOfCells):
(JSC::ValueProfile::numberOfArrays):
(JSC::ValueProfile::probabilityOfArray):
(JSC::ValueProfile::WeakBucket::WeakBucket):
(JSC::ValueProfile::WeakBucket::operator!):
(JSC::ValueProfile::WeakBucket::isEmpty):
(JSC::ValueProfile::WeakBucket::isClassInfo):
(JSC::ValueProfile::WeakBucket::isStructure):
(JSC::ValueProfile::WeakBucket::asStructure):
(JSC::ValueProfile::WeakBucket::asClassInfo):
(JSC::ValueProfile::WeakBucket::getClassInfo):
* heap/Heap.cpp:
(JSC::Heap::harvestWeakReferences):
(JSC::Heap::markRoots):
* heap/Heap.h:
* heap/MarkStack.cpp:
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::harvestWeakReferences):
* heap/MarkStack.h:
(JSC::MarkStack::addWeakReferenceHarvester):
(JSC::MarkStack::MarkStack):
(JSC::MarkStack::appendUnbarrieredPointer):
* heap/SlotVisitor.h:
* heap/WeakReferenceHarvester.h: Added.
(JSC::WeakReferenceHarvester::WeakReferenceHarvester):
(JSC::WeakReferenceHarvester::~WeakReferenceHarvester):


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@94477 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index a0e5e95..e28addc 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,56 @@
+2011-09-02  Filip Pizlo  <fpizlo@apple.com>
+
+        ValueProfile does not make it safe to introspect cell values
+        after garbage collection
+        https://bugs.webkit.org/show_bug.cgi?id=67354
+
+        Reviewed by Gavin Barraclough.
+        
+        ValueProfile buckets are now weak references, implemented using a
+        light-weight weak reference mechanism that this patch also adds (the
+        WeakReferenceHarvester).  If a cell stored in a ValueProfile bucket
+        is not marked, then the bucket is transformed into a Structure
+        pointer.  If the Structure is not marked either, then it is turned
+        into a ClassInfo pointer.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::~CodeBlock):
+        (JSC::CodeBlock::visitAggregate):
+        (JSC::CodeBlock::visitWeakReferences):
+        * bytecode/CodeBlock.h:
+        * bytecode/ValueProfile.h:
+        (JSC::ValueProfile::ValueProfile):
+        (JSC::ValueProfile::classInfo):
+        (JSC::ValueProfile::numberOfInt32s):
+        (JSC::ValueProfile::numberOfDoubles):
+        (JSC::ValueProfile::numberOfCells):
+        (JSC::ValueProfile::numberOfArrays):
+        (JSC::ValueProfile::probabilityOfArray):
+        (JSC::ValueProfile::WeakBucket::WeakBucket):
+        (JSC::ValueProfile::WeakBucket::operator!):
+        (JSC::ValueProfile::WeakBucket::isEmpty):
+        (JSC::ValueProfile::WeakBucket::isClassInfo):
+        (JSC::ValueProfile::WeakBucket::isStructure):
+        (JSC::ValueProfile::WeakBucket::asStructure):
+        (JSC::ValueProfile::WeakBucket::asClassInfo):
+        (JSC::ValueProfile::WeakBucket::getClassInfo):
+        * heap/Heap.cpp:
+        (JSC::Heap::harvestWeakReferences):
+        (JSC::Heap::markRoots):
+        * heap/Heap.h:
+        * heap/MarkStack.cpp:
+        (JSC::SlotVisitor::drain):
+        (JSC::SlotVisitor::harvestWeakReferences):
+        * heap/MarkStack.h:
+        (JSC::MarkStack::addWeakReferenceHarvester):
+        (JSC::MarkStack::MarkStack):
+        (JSC::MarkStack::appendUnbarrieredPointer):
+        * heap/SlotVisitor.h:
+        * heap/WeakReferenceHarvester.h: Added.
+        (JSC::WeakReferenceHarvester::WeakReferenceHarvester):
+        (JSC::WeakReferenceHarvester::~WeakReferenceHarvester):
+
 2011-09-02  Michael Saboff  <msaboff@apple.com>
 
         Replace local implementation of string equals() methods with UString versions
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 43d8bf4..bf14f00 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -49,6 +49,7 @@
 		0BDFFAE00FC6192900D69EF4 /* CrossThreadRefCounted.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD40FC6171000D69EF4 /* CrossThreadRefCounted.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0BDFFAE10FC6193100D69EF4 /* OwnFastMallocPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD10FC616EC00D69EF4 /* OwnFastMallocPtr.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0BF28A2911A33DC300638F84 /* SizeLimits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0BF28A2811A33DC300638F84 /* SizeLimits.cpp */; };
+		0F242DA713F3B1E8007ADD4C /* WeakReferenceHarvester.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F7700921402FF3C0078EB39 /* SamplingCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7700911402FF280078EB39 /* SamplingCounter.cpp */; };
 		0F963B3813FC6FE90002D9B2 /* ValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0FC8150A14043BF500CFA603 /* WriteBarrierSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -770,6 +771,7 @@
 		0BDFFAD10FC616EC00D69EF4 /* OwnFastMallocPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OwnFastMallocPtr.h; sourceTree = "<group>"; };
 		0BDFFAD40FC6171000D69EF4 /* CrossThreadRefCounted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrossThreadRefCounted.h; sourceTree = "<group>"; };
 		0BF28A2811A33DC300638F84 /* SizeLimits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SizeLimits.cpp; sourceTree = "<group>"; };
+		0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakReferenceHarvester.h; sourceTree = "<group>"; };
 		0F77008E1402FDD60078EB39 /* SamplingCounter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SamplingCounter.h; sourceTree = "<group>"; };
 		0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
 		0F963B3613FC6FDE0002D9B2 /* ValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ValueProfile.h; sourceTree = "<group>"; };
@@ -1587,6 +1589,7 @@
 		142E312A134FF0A600AFADB5 /* heap */ = {
 			isa = PBXGroup;
 			children = (
+				0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */,
 				0FC815141405118D00CFA603 /* VTableSpectrum.h */,
 				0FC815121405118600CFA603 /* VTableSpectrum.cpp */,
 				0FC8150914043BD200CFA603 /* WriteBarrierSupport.h */,
@@ -2356,6 +2359,7 @@
 			isa = PBXHeadersBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				0F242DA713F3B1E8007ADD4C /* WeakReferenceHarvester.h in Headers */,
 				860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */,
 				BC18C3E40E16F5CD00B34460 /* AlwaysInline.h in Headers */,
 				BC18C3E50E16F5CD00B34460 /* APICast.h in Headers */,
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index f35d736..fb1f92b 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1433,19 +1433,21 @@
 CodeBlock::~CodeBlock()
 {
 #if ENABLE(VERBOSE_VALUE_PROFILE)
-    printf("ValueProfile for %p:\n", this);
+    fprintf(stderr, "ValueProfile for %p:\n", this);
     for (unsigned i = 0; i < numberOfValueProfiles(); ++i) {
         ValueProfile* profile = valueProfile(i);
         if (profile->bytecodeOffset < 0) {
             ASSERT(profile->bytecodeOffset == -1);
-            printf("   arg = %u: ", i + 1);
+            fprintf(stderr, "   arg = %u: ", i + 1);
         } else
-            printf("   bc = %d: ", profile->bytecodeOffset);
-        printf("samples = %u, int32 = %u, double = %u, cell = %u\n",
-               profile->numberOfSamples(),
-               profile->probabilityOfInt32(),
-               profile->probabilityOfDouble(),
-               profile->probabilityOfCell());
+            fprintf(stderr, "   bc = %d: ", profile->bytecodeOffset);
+        fprintf(stderr,
+                "samples = %u, int32 = %u, double = %u, cell = %u, array = %u\n",
+                profile->numberOfSamples(),
+                profile->probabilityOfInt32(),
+                profile->probabilityOfDouble(),
+                profile->probabilityOfCell(),
+                profile->probabilityOfArray());
     }
 #endif
 
@@ -1515,6 +1517,8 @@
 
 void CodeBlock::visitAggregate(SlotVisitor& visitor)
 {
+    bool handleWeakReferences = false;
+    
     visitor.append(&m_globalObject);
     visitor.append(&m_ownerExecutable);
     if (m_rareData) {
@@ -1562,6 +1566,64 @@
         }
     }
 #endif
+
+#if ENABLE(VALUE_PROFILER)
+    for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex) {
+        ValueProfile* profile = valueProfile(profileIndex);
+        
+        for (unsigned index = 0; index < ValueProfile::numberOfBuckets; ++index) {
+            if (!profile->buckets[index]) {
+                if (!!profile->weakBuckets[index])
+                    handleWeakReferences = true;
+                continue;
+            }
+            
+            if (!JSValue::decode(profile->buckets[index]).isCell()) {
+                profile->weakBuckets[index] = ValueProfile::WeakBucket();
+                continue;
+            }
+            
+            handleWeakReferences = true;
+        }
+    }
+#endif
+    
+    if (handleWeakReferences)
+        visitor.addWeakReferenceHarvester(this);
+}
+
+void CodeBlock::visitWeakReferences(SlotVisitor&)
+{
+#if ENABLE(VALUE_PROFILER)
+    for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex) {
+        ValueProfile* profile = valueProfile(profileIndex);
+        
+        for (unsigned index = 0; index < ValueProfile::numberOfBuckets; ++index) {
+            if (!!profile->buckets[index]) {
+                JSValue value = JSValue::decode(profile->buckets[index]);
+                if (!value.isCell())
+                    continue;
+                
+                JSCell* cell = value.asCell();
+                if (Heap::isMarked(cell))
+                    continue;
+                
+                profile->buckets[index] = JSValue::encode(JSValue());
+                profile->weakBuckets[index] = cell->structure();
+            }
+            
+            ValueProfile::WeakBucket weak = profile->weakBuckets[index];
+            if (!weak || weak.isClassInfo())
+                continue;
+            
+            ASSERT(weak.isStructure());
+            if (Heap::isMarked(weak.asStructure()))
+                continue;
+            
+            profile->weakBuckets[index] = weak.asStructure()->classInfo();
+        }
+    }
+#endif
 }
 
 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index 08cad63..5a61031 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -39,6 +39,7 @@
 #include "Nodes.h"
 #include "RegExpObject.h"
 #include "UString.h"
+#include "WeakReferenceHarvester.h"
 #include "ValueProfile.h"
 #include <wtf/FastAllocBase.h>
 #include <wtf/PassOwnPtr.h>
@@ -205,7 +206,7 @@
     }
 #endif
 
-    class CodeBlock {
+    class CodeBlock: public WeakReferenceHarvester {
         WTF_MAKE_FAST_ALLOCATED;
         friend class JIT;
     protected:
@@ -218,6 +219,7 @@
         virtual ~CodeBlock();
 
         void visitAggregate(SlotVisitor&);
+        void visitWeakReferences(SlotVisitor&);
 
         static void dumpStatistics();
 
diff --git a/Source/JavaScriptCore/bytecode/ValueProfile.h b/Source/JavaScriptCore/bytecode/ValueProfile.h
index 3890f7a..a703f98 100644
--- a/Source/JavaScriptCore/bytecode/ValueProfile.h
+++ b/Source/JavaScriptCore/bytecode/ValueProfile.h
@@ -29,6 +29,8 @@
 #ifndef ValueProfile_h
 #define ValueProfile_h
 
+#include "JSArray.h"
+#include "Structure.h"
 #include "WriteBarrier.h"
 
 namespace JSC {
@@ -45,14 +47,25 @@
         : bytecodeOffset(bytecodeOffset)
     {
         for (unsigned i = 0; i < numberOfBuckets; ++i)
-            buckets[i].setWithoutWriteBarrier(JSValue());
+            buckets[i] = JSValue::encode(JSValue());
+    }
+    
+    const ClassInfo* classInfo(unsigned bucket) const
+    {
+        if (!!buckets[bucket]) {
+            JSValue value = JSValue::decode(buckets[bucket]);
+            if (!value.isCell())
+                return 0;
+            return value.asCell()->structure()->classInfo();
+        }
+        return weakBuckets[bucket].getClassInfo();
     }
     
     unsigned numberOfSamples() const
     {
         unsigned result = 0;
         for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i])
+            if (!!buckets[i] || !!weakBuckets[i])
                 result++;
         }
         return result;
@@ -69,7 +82,7 @@
     {
         unsigned result = 0;
         for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] && buckets[i].get().isInt32())
+            if (!!buckets[i] && JSValue::decode(buckets[i]).isInt32())
                 result++;
         }
         return result;
@@ -79,7 +92,7 @@
     {
         unsigned result = 0;
         for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] && buckets[i].get().isDouble())
+            if (!!buckets[i] && JSValue::decode(buckets[i]).isDouble())
                 result++;
         }
         return result;
@@ -89,7 +102,17 @@
     {
         unsigned result = 0;
         for (unsigned i = 0; i < numberOfBuckets; ++i) {
-            if (!!buckets[i] && buckets[i].get().isCell())
+            if (!!classInfo(i))
+                result++;
+        }
+        return result;
+    }
+    
+    unsigned numberOfArrays() const
+    {
+        unsigned result = 0;
+        for (unsigned i = 0; i < numberOfBuckets; ++i) {
+            if (classInfo(i) == &JSArray::s_info)
                 result++;
         }
         return result;
@@ -115,8 +138,77 @@
         return computeProbability(numberOfCells(), numberOfSamples());
     }
     
+    unsigned probabilityOfArray() const
+    {
+        return computeProbability(numberOfArrays(), numberOfSamples());
+    }
+    
     int bytecodeOffset; // -1 for prologue
-    WriteBarrierBase<Unknown> buckets[numberOfBuckets];
+    EncodedJSValue buckets[numberOfBuckets];
+    
+    class WeakBucket {
+    public:
+        WeakBucket()
+            : m_value(0)
+        {
+        }
+        
+        WeakBucket(Structure* structure)
+            : m_value(reinterpret_cast<uintptr_t>(structure))
+        {
+        }
+        
+        WeakBucket(const ClassInfo* classInfo)
+            : m_value(reinterpret_cast<uintptr_t>(classInfo) | 1)
+        {
+        }
+        
+        bool operator!() const
+        {
+            return !m_value;
+        }
+        
+        bool isEmpty() const
+        {
+            return !m_value;
+        }
+        
+        bool isClassInfo() const
+        {
+            return !!(m_value & 1);
+        }
+        
+        bool isStructure() const
+        {
+            return !isEmpty() && !isClassInfo();
+        }
+        
+        Structure* asStructure() const
+        {
+            ASSERT(isStructure());
+            return reinterpret_cast<Structure*>(m_value);
+        }
+        
+        const ClassInfo* asClassInfo() const
+        {
+            ASSERT(isClassInfo());
+            return reinterpret_cast<ClassInfo*>(m_value & ~static_cast<uintptr_t>(1));
+        }
+        
+        const ClassInfo* getClassInfo() const
+        {
+            if (isEmpty())
+                return 0;
+            if (isClassInfo())
+                return asClassInfo();
+            return asStructure()->classInfo();
+        }
+        
+    private:
+        uintptr_t m_value;
+    };
+    
+    WeakBucket weakBuckets[numberOfBuckets]; // this is not covered by a write barrier because it is only set from GC
 };
 
 inline int getValueProfileBytecodeOffset(ValueProfile* valueProfile)
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 685a601..f56cc0a 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -513,6 +513,11 @@
     }
 }
 
+void Heap::harvestWeakReferences()
+{
+    m_slotVisitor.harvestWeakReferences();
+}
+
 inline RegisterFile& Heap::registerFile()
 {
     return m_globalData->interpreter->registerFile();
@@ -581,6 +586,8 @@
     m_handleStack.visit(heapRootVisitor);
     visitor.drain();
 
+    harvestWeakReferences();
+
     // Weak handles must be marked last, because their owners use the set of
     // opaque roots to determine reachability.
     int lastOpaqueRootCount;
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index 7b82364..961c184 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -152,6 +152,7 @@
         void markRoots();
         void markProtectedObjects(HeapRootVisitor&);
         void markTempSortVectors(HeapRootVisitor&);
+        void harvestWeakReferences();
 
         void* tryAllocate(NewSpace::SizeClass&);
         void* allocateSlowCase(NewSpace::SizeClass&);
diff --git a/Source/JavaScriptCore/heap/MarkStack.cpp b/Source/JavaScriptCore/heap/MarkStack.cpp
index d95978c..7a04e06 100644
--- a/Source/JavaScriptCore/heap/MarkStack.cpp
+++ b/Source/JavaScriptCore/heap/MarkStack.cpp
@@ -136,6 +136,17 @@
 #endif
 }
 
+void SlotVisitor::harvestWeakReferences()
+{
+    while (m_firstWeakReferenceHarvester) {
+        WeakReferenceHarvester* current = m_firstWeakReferenceHarvester;
+        WeakReferenceHarvester* next = reinterpret_cast<WeakReferenceHarvester*>(current->m_nextAndFlag & ~1);
+        current->m_nextAndFlag = 0;
+        m_firstWeakReferenceHarvester = next;
+        current->visitWeakReferences(*this);
+    }
+}
+
 #if ENABLE(GC_VALIDATION)
 void MarkStack::validateSet(JSValue* values, size_t count)
 {
diff --git a/Source/JavaScriptCore/heap/MarkStack.h b/Source/JavaScriptCore/heap/MarkStack.h
index e70b30b..e1c249a 100644
--- a/Source/JavaScriptCore/heap/MarkStack.h
+++ b/Source/JavaScriptCore/heap/MarkStack.h
@@ -30,6 +30,7 @@
 #include "JSValue.h"
 #include "Register.h"
 #include "VTableSpectrum.h"
+#include "WeakReferenceHarvester.h"
 #include <wtf/HashMap.h>
 #include <wtf/HashSet.h>
 #include <wtf/Vector.h>
@@ -93,6 +94,9 @@
         template<typename T> inline void append(WriteBarrierBase<T>*);
         inline void appendValues(WriteBarrierBase<Unknown>*, size_t count);
         
+        template<typename T>
+        inline void appendUnbarrieredPointer(T**);
+        
         bool addOpaqueRoot(void*);
         bool containsOpaqueRoot(void*);
         int opaqueRootCount();
@@ -103,6 +107,14 @@
         VTableSpectrum m_visitedTypeCounts;
 #endif
 
+        void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
+        {
+            if (weakReferenceHarvester->m_nextAndFlag & 1)
+                return;
+            weakReferenceHarvester->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_firstWeakReferenceHarvester) | 1;
+            m_firstWeakReferenceHarvester = weakReferenceHarvester;
+        }
+
     protected:
 #if ENABLE(GC_VALIDATION)
         static void validateSet(JSValue*, size_t);
@@ -120,6 +132,7 @@
         MarkStackArray<MarkSet> m_markSets;
         MarkStackArray<JSCell*> m_values;
         HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
+        WeakReferenceHarvester* m_firstWeakReferenceHarvester;
         
 #if !ASSERT_DISABLED
     public:
@@ -130,6 +143,7 @@
 
     inline MarkStack::MarkStack(void* jsArrayVPtr)
         : m_jsArrayVPtr(jsArrayVPtr)
+        , m_firstWeakReferenceHarvester(0)
 #if !ASSERT_DISABLED
         , m_isCheckingForDefaultMarkViolation(false)
         , m_isDraining(false)
@@ -255,6 +269,15 @@
 #endif
         m_markSets.append(MarkSet(slot, slot + count));
     }
+
+    template<typename T>
+    inline void MarkStack::appendUnbarrieredPointer(T** slot)
+    {
+        ASSERT(slot);
+        JSCell* value = *slot;
+        if (value)
+            internalAppend(value);
+    }
     
     ALWAYS_INLINE void MarkStack::append(JSValue* value)
     {
diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h
index a2e1f90..9143b02 100644
--- a/Source/JavaScriptCore/heap/SlotVisitor.h
+++ b/Source/JavaScriptCore/heap/SlotVisitor.h
@@ -35,7 +35,8 @@
     SlotVisitor(void* jsArrayVPtr);
 
     void drain();
-
+    void harvestWeakReferences();
+    
 private:
     void visitChildren(JSCell*);
 };
diff --git a/Source/JavaScriptCore/heap/WeakReferenceHarvester.h b/Source/JavaScriptCore/heap/WeakReferenceHarvester.h
new file mode 100644
index 0000000..4716d9a
--- /dev/null
+++ b/Source/JavaScriptCore/heap/WeakReferenceHarvester.h
@@ -0,0 +1,51 @@
+/*
+ *  Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef WeakReferenceHarvester_h
+#define WeakReferenceHarvester_h
+
+#include <stdint.h>
+
+namespace JSC {
+
+class MarkStack;
+class SlotVisitor;
+
+class WeakReferenceHarvester {
+public:
+    virtual void visitWeakReferences(SlotVisitor&) = 0;
+    
+protected:
+    WeakReferenceHarvester()
+        : m_nextAndFlag(0)
+    {
+    }
+    
+    virtual ~WeakReferenceHarvester() { }
+
+private:
+    friend class MarkStack;
+    friend class SlotVisitor;
+    
+    uintptr_t m_nextAndFlag;
+};
+
+} // namespace JSC
+
+#endif // WeakReferenceHarvester_h