]> git.saurik.com Git - apple/javascriptcore.git/blame - heap/BlockAllocator.cpp
JavaScriptCore-1097.3.tar.gz
[apple/javascriptcore.git] / heap / BlockAllocator.cpp
CommitLineData
6fe7ccc8
A
1/*
2 * Copyright (C) 2012 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "BlockAllocator.h"
28
29#include "MarkedBlock.h"
30#include <wtf/CurrentTime.h>
31
32namespace JSC {
33
34BlockAllocator::BlockAllocator()
35 : m_numberOfFreeBlocks(0)
36 , m_isCurrentlyAllocating(false)
37 , m_blockFreeingThreadShouldQuit(false)
38 , m_blockFreeingThread(GCActivityCallback::s_shouldCreateGCTimer ?
39 createThread(blockFreeingThreadStartFunc, this, "JavaScriptCore::BlockFree") : 0)
40{
41 ASSERT(m_blockFreeingThread || !GCActivityCallback::s_shouldCreateGCTimer);
42}
43
44BlockAllocator::~BlockAllocator()
45{
46 releaseFreeBlocks();
47 {
48 MutexLocker locker(m_freeBlockLock);
49 m_blockFreeingThreadShouldQuit = true;
50 m_freeBlockCondition.broadcast();
51 }
52 if (GCActivityCallback::s_shouldCreateGCTimer)
53 waitForThreadCompletion(m_blockFreeingThread);
54}
55
56void BlockAllocator::releaseFreeBlocks()
57{
58 while (true) {
59 MarkedBlock* block;
60 {
61 MutexLocker locker(m_freeBlockLock);
62 if (!m_numberOfFreeBlocks)
63 block = 0;
64 else {
65 // FIXME: How do we know this is a MarkedBlock? It could be a CopiedBlock.
66 block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
67 ASSERT(block);
68 m_numberOfFreeBlocks--;
69 }
70 }
71
72 if (!block)
73 break;
74
75 MarkedBlock::destroy(block);
76 }
77}
78
79void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative)
80{
81 if (m_blockFreeingThreadShouldQuit)
82 return;
83 m_freeBlockCondition.timedWait(m_freeBlockLock, currentTime() + relative);
84}
85
86void BlockAllocator::waitForRelativeTime(double relative)
87{
88 // If this returns early, that's fine, so long as it doesn't do it too
89 // frequently. It would only be a bug if this function failed to return
90 // when it was asked to do so.
91
92 MutexLocker locker(m_freeBlockLock);
93 waitForRelativeTimeWhileHoldingLock(relative);
94}
95
96void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator)
97{
98 static_cast<BlockAllocator*>(blockAllocator)->blockFreeingThreadMain();
99}
100
101void BlockAllocator::blockFreeingThreadMain()
102{
103 while (!m_blockFreeingThreadShouldQuit) {
104 // Generally wait for one second before scavenging free blocks. This
105 // may return early, particularly when we're being asked to quit.
106 waitForRelativeTime(1.0);
107 if (m_blockFreeingThreadShouldQuit)
108 break;
109
110 if (m_isCurrentlyAllocating) {
111 m_isCurrentlyAllocating = false;
112 continue;
113 }
114
115 // Now process the list of free blocks. Keep freeing until half of the
116 // blocks that are currently on the list are gone. Assume that a size_t
117 // field can be accessed atomically.
118 size_t currentNumberOfFreeBlocks = m_numberOfFreeBlocks;
119 if (!currentNumberOfFreeBlocks)
120 continue;
121
122 size_t desiredNumberOfFreeBlocks = currentNumberOfFreeBlocks / 2;
123
124 while (!m_blockFreeingThreadShouldQuit) {
125 MarkedBlock* block;
126 {
127 MutexLocker locker(m_freeBlockLock);
128 if (m_numberOfFreeBlocks <= desiredNumberOfFreeBlocks)
129 block = 0;
130 else {
131 // FIXME: How do we know this is a MarkedBlock? It could be a CopiedBlock.
132 block = static_cast<MarkedBlock*>(m_freeBlocks.removeHead());
133 ASSERT(block);
134 m_numberOfFreeBlocks--;
135 }
136 }
137
138 if (!block)
139 break;
140
141 MarkedBlock::destroy(block);
142 }
143 }
144}
145
146} // namespace JSC