]> git.saurik.com Git - apple/javascriptcore.git/blame - heap/CopiedSpace.cpp
JavaScriptCore-1218.35.tar.gz
[apple/javascriptcore.git] / heap / CopiedSpace.cpp
CommitLineData
6fe7ccc8
A
1/*
2 * Copyright (C) 2011 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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CopiedSpace.h"
28
93a37866 29#include "CopiedSpaceInlines.h"
6fe7ccc8 30#include "GCActivityCallback.h"
93a37866
A
31#include "Operations.h"
32#include "Options.h"
6fe7ccc8
A
33
34namespace JSC {
35
36CopiedSpace::CopiedSpace(Heap* heap)
37 : m_heap(heap)
38 , m_toSpace(0)
39 , m_fromSpace(0)
40 , m_inCopyingPhase(false)
93a37866 41 , m_shouldDoCopyPhase(false)
6fe7ccc8
A
42 , m_numberOfLoanedBlocks(0)
43{
93a37866
A
44 m_toSpaceLock.Init();
45}
46
47CopiedSpace::~CopiedSpace()
48{
49 while (!m_toSpace->isEmpty())
50 m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_toSpace->removeHead()));
51
52 while (!m_fromSpace->isEmpty())
53 m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_fromSpace->removeHead()));
54
55 while (!m_oversizeBlocks.isEmpty())
56 m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_oversizeBlocks.removeHead()));
6fe7ccc8
A
57}
58
59void CopiedSpace::init()
60{
61 m_toSpace = &m_blocks1;
62 m_fromSpace = &m_blocks2;
63
93a37866 64 allocateBlock();
6fe7ccc8
A
65}
66
67CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr)
68{
69 if (isOversize(bytes))
70 return tryAllocateOversize(bytes, outPtr);
71
93a37866 72 ASSERT(m_heap->vm()->apiLock().currentThreadIsHoldingLock());
6fe7ccc8
A
73 m_heap->didAllocate(m_allocator.currentCapacity());
74
93a37866
A
75 allocateBlock();
76
77 *outPtr = m_allocator.forceAllocate(bytes);
6fe7ccc8
A
78 return true;
79}
80
81CheckedBoolean CopiedSpace::tryAllocateOversize(size_t bytes, void** outPtr)
82{
83 ASSERT(isOversize(bytes));
84
93a37866 85 CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocateCustomSize(sizeof(CopiedBlock) + bytes, CopiedBlock::blockSize));
6fe7ccc8 86 m_oversizeBlocks.push(block);
93a37866
A
87 m_blockFilter.add(reinterpret_cast<Bits>(block));
88 m_blockSet.add(block);
6fe7ccc8 89
93a37866
A
90 CopiedAllocator allocator;
91 allocator.setCurrentBlock(block);
92 *outPtr = allocator.forceAllocate(bytes);
93 allocator.resetCurrentBlock();
6fe7ccc8 94
93a37866 95 m_heap->didAllocate(block->region()->blockSize());
6fe7ccc8
A
96
97 return true;
98}
99
100CheckedBoolean CopiedSpace::tryReallocate(void** ptr, size_t oldSize, size_t newSize)
101{
102 if (oldSize >= newSize)
103 return true;
104
105 void* oldPtr = *ptr;
93a37866
A
106 ASSERT(!m_heap->vm()->isInitializingObject());
107
108 if (CopiedSpace::blockFor(oldPtr)->isOversize() || isOversize(newSize))
6fe7ccc8 109 return tryReallocateOversize(ptr, oldSize, newSize);
93a37866
A
110
111 if (m_allocator.tryReallocate(oldPtr, oldSize, newSize))
112 return true;
6fe7ccc8
A
113
114 void* result = 0;
115 if (!tryAllocate(newSize, &result)) {
116 *ptr = 0;
117 return false;
118 }
119 memcpy(result, oldPtr, oldSize);
120 *ptr = result;
121 return true;
122}
123
124CheckedBoolean CopiedSpace::tryReallocateOversize(void** ptr, size_t oldSize, size_t newSize)
125{
126 ASSERT(isOversize(oldSize) || isOversize(newSize));
127 ASSERT(newSize > oldSize);
128
129 void* oldPtr = *ptr;
130
131 void* newPtr = 0;
132 if (!tryAllocateOversize(newSize, &newPtr)) {
133 *ptr = 0;
134 return false;
135 }
136
137 memcpy(newPtr, oldPtr, oldSize);
138
93a37866
A
139 CopiedBlock* oldBlock = CopiedSpace::blockFor(oldPtr);
140 if (oldBlock->isOversize()) {
6fe7ccc8 141 m_oversizeBlocks.remove(oldBlock);
93a37866
A
142 m_blockSet.remove(oldBlock);
143 m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(oldBlock));
6fe7ccc8
A
144 }
145
146 *ptr = newPtr;
147 return true;
148}
149
93a37866 150void CopiedSpace::doneFillingBlock(CopiedBlock* block, CopiedBlock** exchange)
6fe7ccc8 151{
6fe7ccc8 152 ASSERT(m_inCopyingPhase);
93a37866
A
153
154 if (exchange)
155 *exchange = allocateBlockForCopyingPhase();
156
157 if (!block)
158 return;
6fe7ccc8 159
93a37866
A
160 if (!block->dataSize()) {
161 recycleBorrowedBlock(block);
6fe7ccc8
A
162 return;
163 }
164
93a37866
A
165 block->zeroFillWilderness();
166
6fe7ccc8 167 {
93a37866 168 SpinLockHolder locker(&m_toSpaceLock);
6fe7ccc8 169 m_toSpace->push(block);
93a37866
A
170 m_blockSet.add(block);
171 m_blockFilter.add(reinterpret_cast<Bits>(block));
6fe7ccc8
A
172 }
173
174 {
175 MutexLocker locker(m_loanedBlocksLock);
176 ASSERT(m_numberOfLoanedBlocks > 0);
93a37866 177 ASSERT(m_inCopyingPhase);
6fe7ccc8
A
178 m_numberOfLoanedBlocks--;
179 if (!m_numberOfLoanedBlocks)
180 m_loanedBlocksCondition.signal();
181 }
182}
183
93a37866 184void CopiedSpace::startedCopying()
6fe7ccc8 185{
93a37866
A
186 std::swap(m_fromSpace, m_toSpace);
187
188 m_blockFilter.reset();
189 m_allocator.resetCurrentBlock();
190
191 CopiedBlock* next = 0;
192 size_t totalLiveBytes = 0;
193 size_t totalUsableBytes = 0;
194 for (CopiedBlock* block = m_fromSpace->head(); block; block = next) {
195 next = block->next();
196 if (!block->isPinned() && block->canBeRecycled()) {
197 recycleEvacuatedBlock(block);
6fe7ccc8
A
198 continue;
199 }
93a37866
A
200 totalLiveBytes += block->liveBytes();
201 totalUsableBytes += block->payloadCapacity();
6fe7ccc8
A
202 }
203
93a37866
A
204 CopiedBlock* block = m_oversizeBlocks.head();
205 while (block) {
206 CopiedBlock* next = block->next();
207 if (block->isPinned()) {
208 m_blockFilter.add(reinterpret_cast<Bits>(block));
209 totalLiveBytes += block->payloadCapacity();
210 totalUsableBytes += block->payloadCapacity();
211 block->didSurviveGC();
212 } else {
213 m_oversizeBlocks.remove(block);
214 m_blockSet.remove(block);
215 m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(block));
216 }
217 block = next;
6fe7ccc8
A
218 }
219
93a37866
A
220 double markedSpaceBytes = m_heap->objectSpace().capacity();
221 double totalFragmentation = ((double)totalLiveBytes + markedSpaceBytes) / ((double)totalUsableBytes + markedSpaceBytes);
222 m_shouldDoCopyPhase = totalFragmentation <= Options::minHeapUtilization();
223 if (!m_shouldDoCopyPhase)
224 return;
225
226 ASSERT(m_shouldDoCopyPhase);
227 ASSERT(!m_inCopyingPhase);
228 ASSERT(!m_numberOfLoanedBlocks);
229 m_inCopyingPhase = true;
6fe7ccc8
A
230}
231
93a37866 232void CopiedSpace::doneCopying()
6fe7ccc8 233{
93a37866
A
234 {
235 MutexLocker locker(m_loanedBlocksLock);
236 while (m_numberOfLoanedBlocks > 0)
237 m_loanedBlocksCondition.wait(m_loanedBlocksLock);
6fe7ccc8 238 }
6fe7ccc8 239
93a37866
A
240 ASSERT(m_inCopyingPhase == m_shouldDoCopyPhase);
241 m_inCopyingPhase = false;
6fe7ccc8 242
93a37866
A
243 while (!m_fromSpace->isEmpty()) {
244 CopiedBlock* block = m_fromSpace->removeHead();
245 // All non-pinned blocks in from-space should have been reclaimed as they were evacuated.
246 ASSERT(block->isPinned() || !m_shouldDoCopyPhase);
247 block->didSurviveGC();
248 // We don't add the block to the blockSet because it was never removed.
249 ASSERT(m_blockSet.contains(block));
250 m_blockFilter.add(reinterpret_cast<Bits>(block));
251 m_toSpace->push(block);
252 }
6fe7ccc8 253
93a37866
A
254 if (!m_toSpace->head())
255 allocateBlock();
256 else
257 m_allocator.setCurrentBlock(m_toSpace->head());
258
259 m_shouldDoCopyPhase = false;
6fe7ccc8
A
260}
261
262size_t CopiedSpace::size()
263{
264 size_t calculatedSize = 0;
265
93a37866 266 for (CopiedBlock* block = m_toSpace->head(); block; block = block->next())
6fe7ccc8
A
267 calculatedSize += block->size();
268
93a37866 269 for (CopiedBlock* block = m_fromSpace->head(); block; block = block->next())
6fe7ccc8
A
270 calculatedSize += block->size();
271
93a37866 272 for (CopiedBlock* block = m_oversizeBlocks.head(); block; block = block->next())
6fe7ccc8
A
273 calculatedSize += block->size();
274
275 return calculatedSize;
276}
277
278size_t CopiedSpace::capacity()
279{
280 size_t calculatedCapacity = 0;
281
93a37866 282 for (CopiedBlock* block = m_toSpace->head(); block; block = block->next())
6fe7ccc8
A
283 calculatedCapacity += block->capacity();
284
93a37866 285 for (CopiedBlock* block = m_fromSpace->head(); block; block = block->next())
6fe7ccc8
A
286 calculatedCapacity += block->capacity();
287
93a37866 288 for (CopiedBlock* block = m_oversizeBlocks.head(); block; block = block->next())
6fe7ccc8
A
289 calculatedCapacity += block->capacity();
290
291 return calculatedCapacity;
292}
293
93a37866 294static bool isBlockListPagedOut(double deadline, DoublyLinkedList<CopiedBlock>* list)
6fe7ccc8
A
295{
296 unsigned itersSinceLastTimeCheck = 0;
93a37866 297 CopiedBlock* current = list->head();
6fe7ccc8
A
298 while (current) {
299 current = current->next();
300 ++itersSinceLastTimeCheck;
301 if (itersSinceLastTimeCheck >= Heap::s_timeCheckResolution) {
302 double currentTime = WTF::monotonicallyIncreasingTime();
303 if (currentTime > deadline)
304 return true;
305 itersSinceLastTimeCheck = 0;
306 }
307 }
308
309 return false;
310}
311
312bool CopiedSpace::isPagedOut(double deadline)
313{
314 return isBlockListPagedOut(deadline, m_toSpace)
315 || isBlockListPagedOut(deadline, m_fromSpace)
316 || isBlockListPagedOut(deadline, &m_oversizeBlocks);
317}
318
319} // namespace JSC