2 * Copyright (C) 2012 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "BlockAllocator.h"
29 #include "CopiedBlock.h"
30 #include "CopyWorkList.h"
31 #include "MarkedBlock.h"
32 #include "WeakBlock.h"
33 #include <wtf/CurrentTime.h>
37 BlockAllocator::BlockAllocator()
39 , m_copiedRegionSet(CopiedBlock::blockSize
)
40 , m_markedRegionSet(MarkedBlock::blockSize
)
41 , m_fourKBBlockRegionSet(WeakBlock::blockSize
)
42 , m_workListRegionSet(CopyWorkListSegment::blockSize
)
43 , m_numberOfEmptyRegions(0)
44 , m_isCurrentlyAllocating(false)
45 , m_blockFreeingThreadShouldQuit(false)
47 , m_blockFreeingThread(GCActivityCallback::s_shouldCreateGCTimer
?
48 createThread(blockFreeingThreadStartFunc
, this, "JavaScriptCore::BlockFree") : 0)
50 , m_blockFreeingThread(createThread(blockFreeingThreadStartFunc
, this, "JavaScriptCore::BlockFree"))
54 RELEASE_ASSERT(m_blockFreeingThread
|| !GCActivityCallback::s_shouldCreateGCTimer
);
56 RELEASE_ASSERT(m_blockFreeingThread
);
61 BlockAllocator::~BlockAllocator()
65 MutexLocker
locker(m_emptyRegionConditionLock
);
66 m_blockFreeingThreadShouldQuit
= true;
67 m_emptyRegionCondition
.broadcast();
70 if (GCActivityCallback::s_shouldCreateGCTimer
)
71 waitForThreadCompletion(m_blockFreeingThread
);
73 waitForThreadCompletion(m_blockFreeingThread
);
75 ASSERT(allRegionSetsAreEmpty());
76 ASSERT(m_emptyRegions
.isEmpty());
79 bool BlockAllocator::allRegionSetsAreEmpty() const
81 return m_copiedRegionSet
.isEmpty()
82 && m_markedRegionSet
.isEmpty()
83 && m_fourKBBlockRegionSet
.isEmpty()
84 && m_workListRegionSet
.isEmpty();
87 void BlockAllocator::releaseFreeRegions()
92 SpinLockHolder
locker(&m_regionLock
);
93 if (!m_numberOfEmptyRegions
)
96 region
= m_emptyRegions
.removeHead();
97 RELEASE_ASSERT(region
);
98 m_numberOfEmptyRegions
--;
109 void BlockAllocator::waitForRelativeTimeWhileHoldingLock(double relative
)
111 if (m_blockFreeingThreadShouldQuit
)
114 m_emptyRegionCondition
.timedWait(m_emptyRegionConditionLock
, currentTime() + relative
);
117 void BlockAllocator::waitForRelativeTime(double relative
)
119 // If this returns early, that's fine, so long as it doesn't do it too
120 // frequently. It would only be a bug if this function failed to return
121 // when it was asked to do so.
123 MutexLocker
locker(m_emptyRegionConditionLock
);
124 waitForRelativeTimeWhileHoldingLock(relative
);
127 void BlockAllocator::blockFreeingThreadStartFunc(void* blockAllocator
)
129 static_cast<BlockAllocator
*>(blockAllocator
)->blockFreeingThreadMain();
132 void BlockAllocator::blockFreeingThreadMain()
134 size_t currentNumberOfEmptyRegions
;
135 while (!m_blockFreeingThreadShouldQuit
) {
136 // Generally wait for one second before scavenging free blocks. This
137 // may return early, particularly when we're being asked to quit.
138 waitForRelativeTime(1.0);
139 if (m_blockFreeingThreadShouldQuit
)
142 if (m_isCurrentlyAllocating
) {
143 m_isCurrentlyAllocating
= false;
147 // Sleep until there is actually work to do rather than waking up every second to check.
149 MutexLocker
locker(m_emptyRegionConditionLock
);
150 SpinLockHolder
regionLocker(&m_regionLock
);
151 while (!m_numberOfEmptyRegions
&& !m_blockFreeingThreadShouldQuit
) {
152 m_regionLock
.Unlock();
153 m_emptyRegionCondition
.wait(m_emptyRegionConditionLock
);
156 currentNumberOfEmptyRegions
= m_numberOfEmptyRegions
;
159 size_t desiredNumberOfEmptyRegions
= currentNumberOfEmptyRegions
/ 2;
161 while (!m_blockFreeingThreadShouldQuit
) {
164 SpinLockHolder
locker(&m_regionLock
);
165 if (m_numberOfEmptyRegions
<= desiredNumberOfEmptyRegions
)
168 region
= m_emptyRegions
.removeHead();
169 RELEASE_ASSERT(region
);
170 m_numberOfEmptyRegions
--;