Factored threaded block allocation into a separate object
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 29 Apr 2012 01:44:37 +0000 (01:44 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 29 Apr 2012 01:44:37 +0000 (01:44 +0000)
https://bugs.webkit.org/show_bug.cgi?id=85148

Reviewed by Sam Weinig.

99% of this patch just moves duplicated block allocation and
deallocation code into a new object named BlockAllocator, with these
exceptions:

* heap/BlockAllocator.h: Added.
(BlockAllocator::BlockAllocator): The order of declarations here now
guards us against an unlikely race condition during startup.

* heap/BlockAllocator.cpp:
JSC::BlockAllocator::blockFreeingThreadMain): Added a FIXME to
highlight a lack of clarity we have in our block deallocation routines.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@115590 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.gypi
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/Target.pri
Source/JavaScriptCore/heap/BlockAllocator.cpp [new file with mode: 0644]
Source/JavaScriptCore/heap/BlockAllocator.h [new file with mode: 0644]
Source/JavaScriptCore/heap/CopiedSpace.cpp
Source/JavaScriptCore/heap/CopiedSpaceInlineMethods.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/heap/MarkedAllocator.cpp
Source/JavaScriptCore/heap/MarkedSpace.cpp

index acc6598..bf48f97 100644 (file)
@@ -85,6 +85,7 @@ SET(JavaScriptCore_SOURCES
     dfg/DFGThunks.cpp
     dfg/DFGVirtualRegisterAllocationPhase.cpp
 
+    heap/BlockAllocator.cpp
     heap/CopiedSpace.cpp
     heap/ConservativeRoots.cpp
     heap/DFGCodeBlocks.cpp
index 7bc9fa2..6fa39cd 100644 (file)
@@ -1,3 +1,22 @@
+2012-04-28  Geoffrey Garen  <ggaren@apple.com>
+
+        Factored threaded block allocation into a separate object
+        https://bugs.webkit.org/show_bug.cgi?id=85148
+
+        Reviewed by Sam Weinig.
+
+        99% of this patch just moves duplicated block allocation and 
+        deallocation code into a new object named BlockAllocator, with these 
+        exceptions:
+
+        * heap/BlockAllocator.h: Added.
+        (BlockAllocator::BlockAllocator): The order of declarations here now 
+        guards us against an unlikely race condition during startup.
+
+        * heap/BlockAllocator.cpp:
+        JSC::BlockAllocator::blockFreeingThreadMain): Added a FIXME to 
+        highlight a lack of clarity we have in our block deallocation routines.
+
 2012-04-28  Sam Weinig  <sam@webkit.org>
 
         Try to fix the Qt build.
index f6055df..6f1370c 100644 (file)
@@ -226,6 +226,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/heap/HandleStack.cpp \
        Source/JavaScriptCore/heap/HandleStack.h \
        Source/JavaScriptCore/heap/HandleTypes.h \
+       Source/JavaScriptCore/heap/BlockAllocator.cpp \
        Source/JavaScriptCore/heap/Heap.cpp \
        Source/JavaScriptCore/heap/Heap.h \
        Source/JavaScriptCore/heap/ListableHandler.h \
index d3c6ec0..4a03be8 100644 (file)
             'heap/DFGCodeBlocks.cpp',
             'heap/HandleSet.cpp',
             'heap/HandleStack.cpp',
+            'heap/BlockAllocator.cpp',
             'heap/Heap.cpp',
             'heap/MachineStackMarker.cpp',
             'heap/MarkedAllocator.cpp',
index 50f97bf..e71b433 100644 (file)
                                >
                        </File>
                        <File
+                               RelativePath="..\..\heap\BlockAllocator.cpp"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\heap\BlockAllocator.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\heap\Heap.cpp"
                                >
                        </File>
index f39fab6..d5cf8de 100644 (file)
                147F39D5107EC37600427A48 /* JSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9B60E1842FA000F9297 /* JSString.cpp */; };
                147F39D6107EC37600427A48 /* JSValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8870255597D01FF60F7 /* JSValue.cpp */; };
                147F39D7107EC37600427A48 /* JSVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */; };
+               14816E1B154CC56C00B8054C /* BlockAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14816E19154CC56C00B8054C /* BlockAllocator.cpp */; };
+               14816E1C154CC56C00B8054C /* BlockAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 14816E1A154CC56C00B8054C /* BlockAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B74C0A43032800517CFC /* JSStringRef.cpp */; };
                1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B7E20A43076000517CFC /* JSObjectRef.cpp */; };
                148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; };
                147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BatchedTransitionOptimizer.h; sourceTree = "<group>"; };
                147B84620E6DE6B1004775A4 /* PutPropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PutPropertySlot.h; sourceTree = "<group>"; };
                1480DB9B0DDC227F003CFDF2 /* DebuggerCallFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerCallFrame.h; sourceTree = "<group>"; };
+               14816E19154CC56C00B8054C /* BlockAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BlockAllocator.cpp; sourceTree = "<group>"; };
+               14816E1A154CC56C00B8054C /* BlockAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockAllocator.h; sourceTree = "<group>"; };
                1482B6EA0A4300B300517CFC /* JSValueRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueRef.h; sourceTree = "<group>"; };
                1482B74B0A43032800517CFC /* JSStringRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStringRef.h; sourceTree = "<group>"; };
                1482B74C0A43032800517CFC /* JSStringRef.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStringRef.cpp; sourceTree = "<group>"; };
                142E312A134FF0A600AFADB5 /* heap */ = {
                        isa = PBXGroup;
                        children = (
+                               14816E19154CC56C00B8054C /* BlockAllocator.cpp */,
+                               14816E1A154CC56C00B8054C /* BlockAllocator.h */,
                                A7521E121429169A003C8D0C /* CardSet.h */,
                                146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */,
                                149DAAF212EB559D0083B12B /* ConservativeRoots.h */,
                                0F1E3A461534CBAF000F9456 /* DFGArgumentPosition.h in Headers */,
                                0F1E3A471534CBB9000F9456 /* DFGDoubleFormatState.h in Headers */,
                                14150133154BB13F005D8C98 /* WeakSetInlines.h in Headers */,
+                               14816E1C154CC56C00B8054C /* BlockAllocator.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                8642C510151C06A90046D4EF /* RegExpCachedResult.cpp in Sources */,
                                8642C512151C083D0046D4EF /* RegExpMatchesArray.cpp in Sources */,
                                863C6D9C1521111A00585E4E /* YarrCanonicalizeUCS2.cpp in Sources */,
+                               14816E1B154CC56C00B8054C /* BlockAllocator.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index ffcba88..017f316 100644 (file)
@@ -76,6 +76,7 @@ SOURCES += \
     heap/WeakBlock.cpp \
     heap/HandleSet.cpp \
     heap/HandleStack.cpp \
+    heap/BlockAllocator.cpp \
     heap/Heap.cpp \
     heap/MachineStackMarker.cpp \
     heap/MarkStack.cpp \
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp
new file mode 100644 (file)
index 0000000..028c84c
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "BlockAllocator.h"
+
+#include "MarkedBlock.h"
+#include <wtf/CurrentTime.h>
+
+namespace JSC {
+
+BlockAllocator::BlockAllocator()
+    : m_numberOfFreeBlocks(0)
+    , m_blockFreeingThreadShouldQuit(false)
+    , m_blockFreeingThread(createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree"))
+{
+    ASSERT(m_blockFreeingThread);
+}
+
+BlockAllocator::~BlockAllocator()
+{
+    releaseFreeBlocks();
+    {
+        MutexLocker locker(m_freeBlockLock);
+        m_blockFreeingThreadShouldQuit = true;
+        m_freeBlockCondition.broadcast();
+    }
+    waitForThreadCompletion(m_blockFreeingThread);
+}
+
+void BlockAllocator::releaseFreeBlocks()
+{
+    while (true) {
+        MarkedBlock* block;
+        {
+            MutexLocker locker(m_freeBlockLock);
+            if (!m_numberOfFreeBlocks)
+                block = 0;
+            else {
+                // FIXME: How do we know this is a MarkedBlock? It could be a CopiedBlock.
+                block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
+                ASSERT(block);
+                m_numberOfFreeBlocks--;
+            }
+        }
+        
+        if (!block)
+            break;
+        
+        MarkedBlock::destroy(block);
+    }
+}
+
+void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative)
+{
+    if (m_blockFreeingThreadShouldQuit)
+        return;
+    m_freeBlockCondition.timedWait(m_freeBlockLock, currentTime() + relative);
+}
+
+void BlockAllocator::waitForRelativeTime(double relative)
+{
+    // If this returns early, that's fine, so long as it doesn't do it too
+    // frequently. It would only be a bug if this function failed to return
+    // when it was asked to do so.
+    
+    MutexLocker locker(m_freeBlockLock);
+    waitForRelativeTimeWhileHoldingLock(relative);
+}
+
+void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator)
+{
+    static_cast<BlockAllocator*>(blockAllocator)->blockFreeingThreadMain();
+}
+
+void BlockAllocator::blockFreeingThreadMain()
+{
+    while (!m_blockFreeingThreadShouldQuit) {
+        // Generally wait for one second before scavenging free blocks. This
+        // may return early, particularly when we're being asked to quit.
+        waitForRelativeTime(1.0);
+        if (m_blockFreeingThreadShouldQuit)
+            break;
+        
+        // Now process the list of free blocks. Keep freeing until half of the
+        // blocks that are currently on the list are gone. Assume that a size_t
+        // field can be accessed atomically.
+        size_t currentNumberOfFreeBlocks = m_numberOfFreeBlocks;
+        if (!currentNumberOfFreeBlocks)
+            continue;
+        
+        size_t desiredNumberOfFreeBlocks = currentNumberOfFreeBlocks / 2;
+        
+        while (!m_blockFreeingThreadShouldQuit) {
+            MarkedBlock* block;
+            {
+                MutexLocker locker(m_freeBlockLock);
+                if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks)
+                    block = 0;
+                else {
+                    // FIXME: How do we know this is a MarkedBlock? It could be a CopiedBlock.
+                    block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
+                    ASSERT(block);
+                    m_numberOfFreeBlocks--;
+                }
+            }
+            
+            if (!block)
+                break;
+            
+            MarkedBlock::destroy(block);
+        }
+    }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.h b/Source/JavaScriptCore/heap/BlockAllocator.h
new file mode 100644 (file)
index 0000000..4b90d28
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BlockAllocator_h
+#define BlockAllocator_h
+
+#include <wtf/DoublyLinkedList.h>
+#include <wtf/Forward.h>
+#include <wtf/Threading.h>
+
+namespace JSC {
+
+class HeapBlock;
+
+// Simple allocator to reduce VM cost by holding onto blocks of memory for
+// short periods of time and then freeing them on a secondary thread.
+
+class BlockAllocator {
+public:
+    BlockAllocator();
+    ~BlockAllocator();
+
+    HeapBlock* allocate();
+    void deallocate(HeapBlock*);
+
+private:
+    void waitForRelativeTimeWhileHoldingLock(double relative);
+    void waitForRelativeTime(double relative);
+
+    void blockFreeingThreadMain();
+    static void blockFreeingThreadStartFunc(void* heap);
+
+    void releaseFreeBlocks();
+
+    DoublyLinkedList<HeapBlock> m_freeBlocks;
+    size_t m_numberOfFreeBlocks;
+    bool m_blockFreeingThreadShouldQuit;
+    Mutex m_freeBlockLock;
+    ThreadCondition m_freeBlockCondition;
+    ThreadIdentifier m_blockFreeingThread;
+};
+
+inline HeapBlock* BlockAllocator::allocate()
+{
+    MutexLocker locker(m_freeBlockLock);
+    if (!m_numberOfFreeBlocks) {
+        ASSERT(m_freeBlocks.isEmpty());
+        return 0;
+    }
+
+    ASSERT(!m_freeBlocks.isEmpty());
+    m_numberOfFreeBlocks--;
+    return m_freeBlocks.removeHead();
+}
+
+inline void BlockAllocator::deallocate(HeapBlock* block)
+{
+    MutexLocker locker(m_freeBlockLock);
+    m_freeBlocks.push(block);
+    m_numberOfFreeBlocks++;
+}
+
+} // namespace JSC
+
+#endif // BlockAllocator_h
index ce073e2..07d247d 100644 (file)
@@ -188,11 +188,7 @@ void CopiedSpace::doneCopying()
         }
 
         m_toSpaceSet.remove(block);
-        {
-            MutexLocker locker(m_heap->m_freeBlockLock);
-            m_heap->m_freeBlocks.push(block);
-            m_heap->m_numberOfFreeBlocks++;
-        }
+        m_heap->blockAllocator().deallocate(block);
     }
 
     CopiedBlock* curr = static_cast<CopiedBlock*>(m_oversizeBlocks.head());
@@ -215,16 +211,8 @@ void CopiedSpace::doneCopying()
 
 CheckedBoolean CopiedSpace::getFreshBlock(AllocationEffort allocationEffort, CopiedBlock** outBlock)
 {
-    HeapBlock* heapBlock = 0;
     CopiedBlock* block = 0;
-    {
-        MutexLocker locker(m_heap->m_freeBlockLock);
-        if (!m_heap->m_freeBlocks.isEmpty()) {
-            heapBlock = m_heap->m_freeBlocks.removeHead();
-            m_heap->m_numberOfFreeBlocks--;
-        }
-    }
-    if (heapBlock)
+    if (HeapBlock* heapBlock = m_heap->blockAllocator().allocate())
         block = new (NotNull, heapBlock) CopiedBlock(heapBlock->m_allocation);
     else if (allocationEffort == AllocationMustSucceed) {
         if (!allocateNewBlock(&block)) {
@@ -251,24 +239,14 @@ CheckedBoolean CopiedSpace::getFreshBlock(AllocationEffort allocationEffort, Cop
 
 void CopiedSpace::freeAllBlocks()
 {
-    while (!m_toSpace->isEmpty()) {
-        CopiedBlock* block = static_cast<CopiedBlock*>(m_toSpace->removeHead());
-        MutexLocker locker(m_heap->m_freeBlockLock);
-        m_heap->m_freeBlocks.append(block);
-        m_heap->m_numberOfFreeBlocks++;
-    }
+    while (!m_toSpace->isEmpty())
+        m_heap->blockAllocator().deallocate(m_toSpace->removeHead());
 
-    while (!m_fromSpace->isEmpty()) {
-        CopiedBlock* block = static_cast<CopiedBlock*>(m_fromSpace->removeHead());
-        MutexLocker locker(m_heap->m_freeBlockLock);
-        m_heap->m_freeBlocks.append(block);
-        m_heap->m_numberOfFreeBlocks++;
-    }
+    while (!m_fromSpace->isEmpty())
+        m_heap->blockAllocator().deallocate(m_fromSpace->removeHead());
 
-    while (!m_oversizeBlocks.isEmpty()) {
-        CopiedBlock* block = static_cast<CopiedBlock*>(m_oversizeBlocks.removeHead());
-        block->m_allocation.deallocate();
-    }
+    while (!m_oversizeBlocks.isEmpty())
+        m_oversizeBlocks.removeHead()->m_allocation.deallocate();
 }
 
 size_t CopiedSpace::size()
index fc8081f..a8e4565 100644 (file)
@@ -63,11 +63,7 @@ inline void CopiedSpace::startedCopying()
 
 inline void CopiedSpace::recycleBlock(CopiedBlock* block)
 {
-    {
-        MutexLocker locker(m_heap->m_freeBlockLock);
-        m_heap->m_freeBlocks.push(block);
-        m_heap->m_numberOfFreeBlocks++;
-    }
+    m_heap->blockAllocator().deallocate(block);
 
     {
         MutexLocker locker(m_loanedBlocksLock);
index fb5161f..ed16a9c 100644 (file)
@@ -319,7 +319,6 @@ Heap::Heap(JSGlobalData* globalData, HeapSize heapSize)
     , m_operationInProgress(NoOperation)
     , m_objectSpace(this)
     , m_storageSpace(this)
-    , m_blockFreeingThreadShouldQuit(false)
     , m_markListSet(0)
     , m_activityCallback(DefaultGCActivityCallback::create(this))
     , m_machineThreads(this)
@@ -332,10 +331,6 @@ Heap::Heap(JSGlobalData* globalData, HeapSize heapSize)
     , m_lastGCLength(0)
     , m_lastCodeDiscardTime(WTF::currentTime())
 {
-    m_numberOfFreeBlocks = 0;
-    m_blockFreeingThread = createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree");
-    
-    ASSERT(m_blockFreeingThread);
     m_storageSpace.init();
 }
 
@@ -345,13 +340,6 @@ Heap::~Heap()
 
     m_objectSpace.shrink();
     m_storageSpace.freeAllBlocks();
-    releaseFreeBlocks();
-    {
-        MutexLocker locker(m_freeBlockLock);
-        m_blockFreeingThreadShouldQuit = true;
-        m_freeBlockCondition.broadcast();
-    }
-    waitForThreadCompletion(m_blockFreeingThread);
 
     ASSERT(!size());
     ASSERT(!capacity());
@@ -380,67 +368,6 @@ void Heap::lastChanceToFinalize()
 #endif
 }
 
-void Heap::waitForRelativeTimeWhileHoldingLock(double relative)
-{
-    if (m_blockFreeingThreadShouldQuit)
-        return;
-    m_freeBlockCondition.timedWait(m_freeBlockLock, currentTime() + relative);
-}
-
-void Heap::waitForRelativeTime(double relative)
-{
-    // If this returns early, that's fine, so long as it doesn't do it too
-    // frequently. It would only be a bug if this function failed to return
-    // when it was asked to do so.
-    
-    MutexLocker locker(m_freeBlockLock);
-    waitForRelativeTimeWhileHoldingLock(relative);
-}
-
-void Heap::blockFreeingThreadStartFunc(void* heap)
-{
-    static_cast<Heap*>(heap)->blockFreeingThreadMain();
-}
-
-void Heap::blockFreeingThreadMain()
-{
-    while (!m_blockFreeingThreadShouldQuit) {
-        // Generally wait for one second before scavenging free blocks. This
-        // may return early, particularly when we're being asked to quit.
-        waitForRelativeTime(1.0);
-        if (m_blockFreeingThreadShouldQuit)
-            break;
-        
-        // Now process the list of free blocks. Keep freeing until half of the
-        // blocks that are currently on the list are gone. Assume that a size_t
-        // field can be accessed atomically.
-        size_t currentNumberOfFreeBlocks = m_numberOfFreeBlocks;
-        if (!currentNumberOfFreeBlocks)
-            continue;
-        
-        size_t desiredNumberOfFreeBlocks = currentNumberOfFreeBlocks / 2;
-        
-        while (!m_blockFreeingThreadShouldQuit) {
-            MarkedBlock* block;
-            {
-                MutexLocker locker(m_freeBlockLock);
-                if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks)
-                    block = 0;
-                else {
-                    block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
-                    ASSERT(block);
-                    m_numberOfFreeBlocks--;
-                }
-            }
-            
-            if (!block)
-                break;
-            
-            MarkedBlock::destroy(block);
-        }
-    }
-}
-
 void Heap::reportExtraMemoryCostSlowCase(size_t cost)
 {
     // Our frequency of garbage collection tries to balance memory use against speed
@@ -912,33 +839,6 @@ bool Heap::isValidAllocation(size_t bytes)
     return true;
 }
 
-void Heap::freeBlocks(MarkedBlock* head)
-{
-    m_objectSpace.freeBlocks(head);
-}
-
-void Heap::releaseFreeBlocks()
-{
-    while (true) {
-        MarkedBlock* block;
-        {
-            MutexLocker locker(m_freeBlockLock);
-            if (!m_numberOfFreeBlocks)
-                block = 0;
-            else {
-                block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
-                ASSERT(block);
-                m_numberOfFreeBlocks--;
-            }
-        }
-        
-        if (!block)
-            break;
-        
-        MarkedBlock::destroy(block);
-    }
-}
-
 void Heap::addFinalizer(JSCell* cell, Finalizer finalizer)
 {
     WeakSet::allocate(cell, &m_finalizerOwner, reinterpret_cast<void*>(finalizer)); // Balanced by FinalizerOwner::finalize().
index e392fb2..7fe357d 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef Heap_h
 #define Heap_h
 
+#include "BlockAllocator.h"
 #include "DFGCodeBlocks.h"
 #include "HandleSet.h"
 #include "HandleStack.h"
@@ -33,8 +34,6 @@
 #include "WeakHandleOwner.h"
 #include "WeakSet.h"
 #include "WriteBarrierSupport.h"
-#include <wtf/DoublyLinkedList.h>
-#include <wtf/Forward.h>
 #include <wtf/HashCountedSet.h>
 #include <wtf/HashSet.h>
 
@@ -184,7 +183,6 @@ namespace JSC {
         void canonicalizeCellLivenessData();
 
         void resetAllocators();
-        void freeBlocks(MarkedBlock*);
 
         void clearMarks();
         void markRoots(bool fullGC);
@@ -193,16 +191,11 @@ namespace JSC {
         void harvestWeakReferences();
         void finalizeUnconditionalFinalizers();
         
-        void releaseFreeBlocks();
         void sweep();
 
         RegisterFile& registerFile();
+        BlockAllocator& blockAllocator();
 
-        void waitForRelativeTimeWhileHoldingLock(double relative);
-        void waitForRelativeTime(double relative);
-        void blockFreeingThreadMain();
-        static void blockFreeingThreadStartFunc(void* heap);
-        
         const HeapSize m_heapSize;
         const size_t m_minBytesPerCycle;
         size_t m_sizeAfterLastCollect;
@@ -214,13 +207,7 @@ namespace JSC {
         MarkedSpace m_objectSpace;
         CopiedSpace m_storageSpace;
 
-        DoublyLinkedList<HeapBlock> m_freeBlocks;
-        size_t m_numberOfFreeBlocks;
-        
-        ThreadIdentifier m_blockFreeingThread;
-        Mutex m_freeBlockLock;
-        ThreadCondition m_freeBlockCondition;
-        bool m_blockFreeingThreadShouldQuit;
+        BlockAllocator m_blockAllocator;
 
 #if ENABLE(SIMPLE_HEAP_PROFILING)
         VTableSpectrum m_destroyedTypeCounts;
@@ -372,6 +359,11 @@ namespace JSC {
         return m_storageSpace.tryReallocate(ptr, oldSize, newSize);
     }
 
+    inline BlockAllocator& Heap::blockAllocator()
+    {
+        return m_blockAllocator;
+    }
+
 } // namespace JSC
 
 #endif // Heap_h
index bf0c052..75ddf21 100644 (file)
@@ -82,17 +82,7 @@ void* MarkedAllocator::allocateSlowCase()
     
 MarkedBlock* MarkedAllocator::allocateBlock(AllocationEffort allocationEffort)
 {
-    MarkedBlock* block;
-    
-    {
-        MutexLocker locker(m_heap->m_freeBlockLock);
-        if (m_heap->m_numberOfFreeBlocks) {
-            block = static_cast<MarkedBlock*>(m_heap->m_freeBlocks.removeHead());
-            ASSERT(block);
-            m_heap->m_numberOfFreeBlocks--;
-        } else
-            block = 0;
-    }
+    MarkedBlock* block = static_cast<MarkedBlock*>(m_heap->blockAllocator().allocate());
     if (block)
         block = MarkedBlock::recycle(block, m_heap, m_cellSize, m_cellsNeedDestruction);
     else if (allocationEffort == AllocationCanFail)
index 565fa86..eb402ee 100644 (file)
@@ -79,9 +79,8 @@ void MarkedSpace::freeBlocks(MarkedBlock* head)
         
         m_blocks.remove(block);
         block->sweep();
-        MutexLocker locker(m_heap->m_freeBlockLock);
-        m_heap->m_freeBlocks.append(block);
-        m_heap->m_numberOfFreeBlocks++;
+
+        m_heap->blockAllocator().deallocate(block);
     }
 }