summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/heap/BlockAllocator.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/heap/BlockAllocator.cpp
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/heap/BlockAllocator.cpp')
-rw-r--r--Source/JavaScriptCore/heap/BlockAllocator.cpp172
1 files changed, 172 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/heap/BlockAllocator.cpp b/Source/JavaScriptCore/heap/BlockAllocator.cpp
new file mode 100644
index 000000000..7a7474913
--- /dev/null
+++ b/Source/JavaScriptCore/heap/BlockAllocator.cpp
@@ -0,0 +1,172 @@
+/*
+ * 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 "CopiedBlock.h"
+#include "CopyWorkList.h"
+#include "MarkedBlock.h"
+#include "WeakBlock.h"
+#include <wtf/CurrentTime.h>
+
+namespace JSC {
+
+inline ThreadIdentifier createBlockFreeingThread(BlockAllocator* allocator)
+{
+ if (!GCActivityCallback::s_shouldCreateGCTimer)
+ return 0; // No block freeing thread.
+ ThreadIdentifier identifier = createThread(allocator->blockFreeingThreadStartFunc, allocator, "JavaScriptCore::BlockFree");
+ RELEASE_ASSERT(identifier);
+ return identifier;
+}
+
+BlockAllocator::BlockAllocator()
+ : m_superRegion()
+ , m_copiedRegionSet(CopiedBlock::blockSize)
+ , m_markedRegionSet(MarkedBlock::blockSize)
+ , m_fourKBBlockRegionSet(WeakBlock::blockSize)
+ , m_workListRegionSet(CopyWorkListSegment::blockSize)
+ , m_numberOfEmptyRegions(0)
+ , m_isCurrentlyAllocating(false)
+ , m_blockFreeingThreadShouldQuit(false)
+ , m_blockFreeingThread(createBlockFreeingThread(this))
+{
+ m_regionLock.Init();
+}
+
+BlockAllocator::~BlockAllocator()
+{
+ releaseFreeRegions();
+ {
+ std::lock_guard<std::mutex> lock(m_emptyRegionConditionMutex);
+ m_blockFreeingThreadShouldQuit = true;
+ m_emptyRegionCondition.notify_all();
+ }
+ if (m_blockFreeingThread)
+ waitForThreadCompletion(m_blockFreeingThread);
+ ASSERT(allRegionSetsAreEmpty());
+ ASSERT(m_emptyRegions.isEmpty());
+}
+
+bool BlockAllocator::allRegionSetsAreEmpty() const
+{
+ return m_copiedRegionSet.isEmpty()
+ && m_markedRegionSet.isEmpty()
+ && m_fourKBBlockRegionSet.isEmpty()
+ && m_workListRegionSet.isEmpty();
+}
+
+void BlockAllocator::releaseFreeRegions()
+{
+ while (true) {
+ Region* region;
+ {
+ SpinLockHolder locker(&m_regionLock);
+ if (!m_numberOfEmptyRegions)
+ region = 0;
+ else {
+ region = m_emptyRegions.removeHead();
+ RELEASE_ASSERT(region);
+ m_numberOfEmptyRegions--;
+ }
+ }
+
+ if (!region)
+ break;
+
+ region->destroy();
+ }
+}
+
+void BlockAllocator::waitForDuration(std::chrono::milliseconds duration)
+{
+ std::unique_lock<std::mutex> lock(m_emptyRegionConditionMutex);
+
+ // 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.
+ if (m_blockFreeingThreadShouldQuit)
+ return;
+
+ m_emptyRegionCondition.wait_for(lock, duration);
+}
+
+void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator)
+{
+ static_cast<BlockAllocator*>(blockAllocator)->blockFreeingThreadMain();
+}
+
+void BlockAllocator::blockFreeingThreadMain()
+{
+ size_t currentNumberOfEmptyRegions;
+ while (!m_blockFreeingThreadShouldQuit) {
+ // Generally wait for one second before scavenging free blocks. This
+ // may return early, particularly when we're being asked to quit.
+ waitForDuration(std::chrono::seconds(1));
+ if (m_blockFreeingThreadShouldQuit)
+ break;
+
+ if (m_isCurrentlyAllocating) {
+ m_isCurrentlyAllocating = false;
+ continue;
+ }
+
+ // Sleep until there is actually work to do rather than waking up every second to check.
+ {
+ std::unique_lock<std::mutex> lock(m_emptyRegionConditionMutex);
+ SpinLockHolder regionLocker(&m_regionLock);
+ while (!m_numberOfEmptyRegions && !m_blockFreeingThreadShouldQuit) {
+ m_regionLock.Unlock();
+ m_emptyRegionCondition.wait(lock);
+ m_regionLock.Lock();
+ }
+ currentNumberOfEmptyRegions = m_numberOfEmptyRegions;
+ }
+
+ size_t desiredNumberOfEmptyRegions = currentNumberOfEmptyRegions / 2;
+
+ while (!m_blockFreeingThreadShouldQuit) {
+ Region* region;
+ {
+ SpinLockHolder locker(&m_regionLock);
+ if (m_numberOfEmptyRegions <= desiredNumberOfEmptyRegions)
+ region = 0;
+ else {
+ region = m_emptyRegions.removeHead();
+ RELEASE_ASSERT(region);
+ m_numberOfEmptyRegions--;
+ }
+ }
+
+ if (!region)
+ break;
+
+ region->destroy();
+ }
+ }
+}
+
+} // namespace JSC