]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - heap/MarkStack.h
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / heap / MarkStack.h
index 0695b1b32278342613c164ff1f2a3c44dbc4d97d..c97b6a73531417e598001748904ab9c554d88172 100644 (file)
 #ifndef MarkStack_h
 #define MarkStack_h
 
-#include "CopiedSpace.h"
-#include "HandleTypes.h"
-#include "Options.h"
-#include "JSValue.h"
-#include "Register.h"
-#include "UnconditionalFinalizer.h"
-#include "VTableSpectrum.h"
-#include "WeakReferenceHarvester.h"
-#include <wtf/HashMap.h>
-#include <wtf/HashSet.h>
-#include <wtf/Vector.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/OSAllocator.h>
-#include <wtf/PageBlock.h>
-
-namespace JSC {
-
-    class ConservativeRoots;
-    class JSGlobalData;
-    class MarkStack;
-    class ParallelModeEnabler;
-    class Register;
-    class SlotVisitor;
-    template<typename T> class WriteBarrierBase;
-    template<typename T> class JITWriteBarrier;
-    
-    struct MarkStackSegment {
-        MarkStackSegment* m_previous;
-#if !ASSERT_DISABLED
-        size_t m_top;
-#endif
-        
-        const JSCell** data()
-        {
-            return bitwise_cast<const JSCell**>(this + 1);
-        }
-        
-        static size_t capacityFromSize(size_t size)
-        {
-            return (size - sizeof(MarkStackSegment)) / sizeof(const JSCell*);
-        }
-        
-        static size_t sizeFromCapacity(size_t capacity)
-        {
-            return sizeof(MarkStackSegment) + capacity * sizeof(const JSCell*);
-        }
-    };
-
-    class MarkStackSegmentAllocator {
-    public:
-        MarkStackSegmentAllocator();
-        ~MarkStackSegmentAllocator();
-        
-        MarkStackSegment* allocate();
-        void release(MarkStackSegment*);
-        
-        void shrinkReserve();
-        
-    private:
-        Mutex m_lock;
-        MarkStackSegment* m_nextFreeSegment;
-    };
-
-    class MarkStackArray {
-    public:
-        MarkStackArray(MarkStackSegmentAllocator&);
-        ~MarkStackArray();
-
-        void append(const JSCell*);
-
-        bool canRemoveLast();
-        const JSCell* removeLast();
-        bool refill();
-        
-        bool isEmpty();
-        
-        bool canDonateSomeCells(); // Returns false if you should definitely not call doanteSomeCellsTo().
-        bool donateSomeCellsTo(MarkStackArray& other); // Returns true if some cells were donated.
-        
-        void stealSomeCellsFrom(MarkStackArray& other);
-
-        size_t size();
-
-    private:
-        MarkStackSegment* m_topSegment;
-        
-        JS_EXPORT_PRIVATE void expand();
-        
-        MarkStackSegmentAllocator& m_allocator;
-
-        size_t m_segmentCapacity;
-        size_t m_top;
-        size_t m_numberOfPreviousSegments;
-        
-        size_t postIncTop()
-        {
-            size_t result = m_top++;
-            ASSERT(result == m_topSegment->m_top++);
-            return result;
-        }
-        
-        size_t preDecTop()
-        {
-            size_t result = --m_top;
-            ASSERT(result == --m_topSegment->m_top);
-            return result;
-        }
-        
-        void setTopForFullSegment()
-        {
-            ASSERT(m_topSegment->m_top == m_segmentCapacity);
-            m_top = m_segmentCapacity;
-        }
-        
-        void setTopForEmptySegment()
-        {
-            ASSERT(!m_topSegment->m_top);
-            m_top = 0;
-        }
-        
-        size_t top()
-        {
-            ASSERT(m_top == m_topSegment->m_top);
-            return m_top;
-        }
-        
-#if ASSERT_DISABLED
-        void validatePrevious() { }
+#if ENABLE(OBJECT_MARK_LOGGING)
+#define MARK_LOG_MESSAGE0(message) dataLogF(message)
+#define MARK_LOG_MESSAGE1(message, arg1) dataLogF(message, arg1)
+#define MARK_LOG_MESSAGE2(message, arg1, arg2) dataLogF(message, arg1, arg2)
+#define MARK_LOG_ROOT(visitor, rootName) \
+    dataLogF("\n%s: ", rootName); \
+    (visitor).resetChildCount()
+#define MARK_LOG_PARENT(visitor, parent) \
+    dataLogF("\n%p (%s): ", parent, parent->className() ? parent->className() : "unknown"); \
+    (visitor).resetChildCount()
+#define MARK_LOG_CHILD(visitor, child) \
+    if ((visitor).childCount()) \
+    dataLogFString(", "); \
+    dataLogF("%p", child); \
+    (visitor).incrementChildCount()
 #else
-        void validatePrevious()
-        {
-            unsigned count = 0;
-            for (MarkStackSegment* current = m_topSegment->m_previous; current; current = current->m_previous)
-                count++;
-            ASSERT(count == m_numberOfPreviousSegments);
-        }
-#endif
-    };
-
-    class MarkStackThreadSharedData {
-    public:
-        MarkStackThreadSharedData(JSGlobalData*);
-        ~MarkStackThreadSharedData();
-        
-        void reset();
-    
-    private:
-        friend class MarkStack;
-        friend class SlotVisitor;
-
-#if ENABLE(PARALLEL_GC)
-        void markingThreadMain();
-        static void markingThreadStartFunc(void* heap);
+#define MARK_LOG_MESSAGE0(message) do { } while (false)
+#define MARK_LOG_MESSAGE1(message, arg1) do { } while (false)
+#define MARK_LOG_MESSAGE2(message, arg1, arg2) do { } while (false)
+#define MARK_LOG_ROOT(visitor, rootName) do { } while (false)
+#define MARK_LOG_PARENT(visitor, parent) do { } while (false)
+#define MARK_LOG_CHILD(visitor, child) do { } while (false)
 #endif
 
-        JSGlobalData* m_globalData;
-        CopiedSpace* m_copiedSpace;
-        
-        MarkStackSegmentAllocator m_segmentAllocator;
-        
-        Vector<ThreadIdentifier> m_markingThreads;
-        
-        Mutex m_markingLock;
-        ThreadCondition m_markingCondition;
-        MarkStackArray m_sharedMarkStack;
-        unsigned m_numberOfActiveParallelMarkers;
-        bool m_parallelMarkersShouldExit;
+#include "HeapBlock.h"
+#include <wtf/StdLibExtras.h>
 
-        Mutex m_opaqueRootsLock;
-        HashSet<void*> m_opaqueRoots;
-
-        ListableHandler<WeakReferenceHarvester>::List m_weakReferenceHarvesters;
-        ListableHandler<UnconditionalFinalizer>::List m_unconditionalFinalizers;
-    };
-
-    class MarkStack {
-        WTF_MAKE_NONCOPYABLE(MarkStack);
-        friend class HeapRootVisitor; // Allowed to mark a JSValue* or JSCell** directly.
-
-    public:
-        MarkStack(MarkStackThreadSharedData&);
-        ~MarkStack();
-
-        void append(ConservativeRoots&);
-        
-        template<typename T> void append(JITWriteBarrier<T>*);
-        template<typename T> void append(WriteBarrierBase<T>*);
-        void appendValues(WriteBarrierBase<Unknown>*, size_t count);
-        
-        template<typename T>
-        void appendUnbarrieredPointer(T**);
-        
-        void addOpaqueRoot(void*);
-        bool containsOpaqueRoot(void*);
-        int opaqueRootCount();
-        
-        bool isEmpty() { return m_stack.isEmpty(); }
-
-        void reset();
-
-        size_t visitCount() const { return m_visitCount; }
-
-#if ENABLE(SIMPLE_HEAP_PROFILING)
-        VTableSpectrum m_visitedTypeCounts;
-#endif
-
-        void addWeakReferenceHarvester(WeakReferenceHarvester* weakReferenceHarvester)
-        {
-            m_shared.m_weakReferenceHarvesters.addThreadSafe(weakReferenceHarvester);
-        }
-        
-        void addUnconditionalFinalizer(UnconditionalFinalizer* unconditionalFinalizer)
-        {
-            m_shared.m_unconditionalFinalizers.addThreadSafe(unconditionalFinalizer);
-        }
-
-    protected:
-        JS_EXPORT_PRIVATE static void validate(JSCell*);
+namespace JSC {
 
-        void append(JSValue*);
-        void append(JSValue*, size_t count);
-        void append(JSCell**);
+class BlockAllocator;
+class DeadBlock;
+class JSCell;
 
-        void internalAppend(JSCell*);
-        void internalAppend(JSValue);
-        
-        JS_EXPORT_PRIVATE void mergeOpaqueRoots();
-        
-        void mergeOpaqueRootsIfNecessary()
-        {
-            if (m_opaqueRoots.isEmpty())
-                return;
-            mergeOpaqueRoots();
-        }
-        
-        void mergeOpaqueRootsIfProfitable()
-        {
-            if (static_cast<unsigned>(m_opaqueRoots.size()) < Options::opaqueRootMergeThreshold)
-                return;
-            mergeOpaqueRoots();
-        }
-        
-        MarkStackArray m_stack;
-        HashSet<void*> m_opaqueRoots; // Handle-owning data structures not visible to the garbage collector.
-        
+class MarkStackSegment : public HeapBlock<MarkStackSegment> {
+public:
+    MarkStackSegment(Region* region)
+        : HeapBlock<MarkStackSegment>(region)
 #if !ASSERT_DISABLED
-    public:
-        bool m_isCheckingForDefaultMarkViolation;
-        bool m_isDraining;
+        , m_top(0)
 #endif
-    protected:
-        friend class ParallelModeEnabler;
-        
-        size_t m_visitCount;
-        bool m_isInParallelMode;
-        
-        MarkStackThreadSharedData& m_shared;
-    };
-
-    inline MarkStack::MarkStack(MarkStackThreadSharedData& shared)
-        : m_stack(shared.m_segmentAllocator)
-#if !ASSERT_DISABLED
-        , m_isCheckingForDefaultMarkViolation(false)
-        , m_isDraining(false)
-#endif
-        , m_visitCount(0)
-        , m_isInParallelMode(false)
-        , m_shared(shared)
     {
     }
 
-    inline MarkStack::~MarkStack()
-    {
-        ASSERT(m_stack.isEmpty());
-    }
+    static MarkStackSegment* create(DeadBlock*);
 
-    inline void MarkStack::addOpaqueRoot(void* root)
+    const JSCell** data()
     {
-#if ENABLE(PARALLEL_GC)
-        if (Options::numberOfGCMarkers == 1) {
-            // Put directly into the shared HashSet.
-            m_shared.m_opaqueRoots.add(root);
-            return;
-        }
-        // Put into the local set, but merge with the shared one every once in
-        // a while to make sure that the local sets don't grow too large.
-        mergeOpaqueRootsIfProfitable();
-        m_opaqueRoots.add(root);
-#else
-        m_opaqueRoots.add(root);
-#endif
+        return bitwise_cast<const JSCell**>(this + 1);
     }
 
-    inline bool MarkStack::containsOpaqueRoot(void* root)
-    {
-        ASSERT(!m_isInParallelMode);
-#if ENABLE(PARALLEL_GC)
-        ASSERT(m_opaqueRoots.isEmpty());
-        return m_shared.m_opaqueRoots.contains(root);
-#else
-        return m_opaqueRoots.contains(root);
-#endif
-    }
+    static const size_t blockSize = 4 * KB;
 
-    inline int MarkStack::opaqueRootCount()
-    {
-        ASSERT(!m_isInParallelMode);
-#if ENABLE(PARALLEL_GC)
-        ASSERT(m_opaqueRoots.isEmpty());
-        return m_shared.m_opaqueRoots.size();
-#else
-        return m_opaqueRoots.size();
+#if !ASSERT_DISABLED
+    size_t m_top;
 #endif
-    }
+};
 
-    inline void MarkStackArray::append(const JSCell* cell)
-    {
-        if (m_top == m_segmentCapacity)
-            expand();
-        m_topSegment->data()[postIncTop()] = cell;
-    }
+class MarkStackArray {
+public:
+    MarkStackArray(BlockAllocator&);
+    ~MarkStackArray();
 
-    inline bool MarkStackArray::canRemoveLast()
-    {
-        return !!m_top;
-    }
-
-    inline const JSCell* MarkStackArray::removeLast()
-    {
-        return m_topSegment->data()[preDecTop()];
-    }
-
-    inline bool MarkStackArray::isEmpty()
-    {
-        if (m_top)
-            return false;
-        if (m_topSegment->m_previous) {
-            ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
-            return false;
-        }
-        return true;
-    }
+    void append(const JSCell*);
 
-    inline bool MarkStackArray::canDonateSomeCells()
-    {
-        size_t numberOfCellsToKeep = Options::minimumNumberOfCellsToKeep;
-        // Another check: see if we have enough cells to warrant donation.
-        if (m_top <= numberOfCellsToKeep) {
-            // This indicates that we might not want to donate anything; check if we have
-            // another full segment. If not, then don't donate.
-            if (!m_topSegment->m_previous)
-                return false;
-            
-            ASSERT(m_topSegment->m_previous->m_top == m_segmentCapacity);
-        }
-        
-        return true;
-    }
+    bool canRemoveLast();
+    const JSCell* removeLast();
+    bool refill();
+    
+    void donateSomeCellsTo(MarkStackArray& other);
+    void stealSomeCellsFrom(MarkStackArray& other, size_t idleThreadCount);
 
-    inline size_t MarkStackArray::size()
-    {
-        return m_top + m_segmentCapacity * m_numberOfPreviousSegments;
-    }
+    size_t size();
+    bool isEmpty();
 
-    ALWAYS_INLINE void MarkStack::append(JSValue* slot, size_t count)
-    {
-        for (size_t i = 0; i < count; ++i) {
-            JSValue& value = slot[i];
-            if (!value)
-                continue;
-            internalAppend(value);
-        }
-    }
+private:
+    template <size_t size> struct CapacityFromSize {
+        static const size_t value = (size - sizeof(MarkStackSegment)) / sizeof(const JSCell*);
+    };
 
-    template<typename T>
-    inline void MarkStack::appendUnbarrieredPointer(T** slot)
-    {
-        ASSERT(slot);
-        JSCell* cell = *slot;
-        if (cell)
-            internalAppend(cell);
-    }
+    JS_EXPORT_PRIVATE void expand();
     
-    ALWAYS_INLINE void MarkStack::append(JSValue* slot)
-    {
-        ASSERT(slot);
-        internalAppend(*slot);
-    }
-
-    ALWAYS_INLINE void MarkStack::append(JSCell** slot)
-    {
-        ASSERT(slot);
-        internalAppend(*slot);
-    }
+    size_t postIncTop();
+    size_t preDecTop();
+    void setTopForFullSegment();
+    void setTopForEmptySegment();
+    size_t top();
+    
+    void validatePrevious();
 
-    ALWAYS_INLINE void MarkStack::internalAppend(JSValue value)
-    {
-        ASSERT(value);
-        if (!value.isCell())
-            return;
-        internalAppend(value.asCell());
-    }
+    DoublyLinkedList<MarkStackSegment> m_segments;
+    BlockAllocator& m_blockAllocator;
 
-    class ParallelModeEnabler {
-    public:
-        ParallelModeEnabler(MarkStack& stack)
-            : m_stack(stack)
-        {
-            ASSERT(!m_stack.m_isInParallelMode);
-            m_stack.m_isInParallelMode = true;
-        }
-        
-        ~ParallelModeEnabler()
-        {
-            ASSERT(m_stack.m_isInParallelMode);
-            m_stack.m_isInParallelMode = false;
-        }
-        
-    private:
-        MarkStack& m_stack;
-    };
+    JS_EXPORT_PRIVATE static const size_t s_segmentCapacity = CapacityFromSize<MarkStackSegment::blockSize>::value;
+    size_t m_top;
+    size_t m_numberOfSegments;
+   
+};
 
 } // namespace JSC