]> git.saurik.com Git - apple/javascriptcore.git/blame - heap/CopiedSpace.cpp
JavaScriptCore-7600.1.4.17.5.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"
81345200 31#include "JSCInlines.h"
93a37866 32#include "Options.h"
6fe7ccc8
A
33
34namespace JSC {
35
36CopiedSpace::CopiedSpace(Heap* heap)
37 : m_heap(heap)
6fe7ccc8 38 , m_inCopyingPhase(false)
93a37866 39 , m_shouldDoCopyPhase(false)
6fe7ccc8
A
40 , m_numberOfLoanedBlocks(0)
41{
93a37866
A
42 m_toSpaceLock.Init();
43}
44
45CopiedSpace::~CopiedSpace()
46{
81345200
A
47 while (!m_oldGen.toSpace->isEmpty())
48 m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.toSpace->removeHead()));
93a37866 49
81345200
A
50 while (!m_oldGen.fromSpace->isEmpty())
51 m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.fromSpace->removeHead()));
93a37866 52
81345200
A
53 while (!m_oldGen.oversizeBlocks.isEmpty())
54 m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_oldGen.oversizeBlocks.removeHead()));
55
56 while (!m_newGen.toSpace->isEmpty())
57 m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.toSpace->removeHead()));
58
59 while (!m_newGen.fromSpace->isEmpty())
60 m_heap->blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.fromSpace->removeHead()));
61
62 while (!m_newGen.oversizeBlocks.isEmpty())
63 m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_newGen.oversizeBlocks.removeHead()));
64
65 ASSERT(m_oldGen.toSpace->isEmpty());
66 ASSERT(m_oldGen.fromSpace->isEmpty());
67 ASSERT(m_oldGen.oversizeBlocks.isEmpty());
68 ASSERT(m_newGen.toSpace->isEmpty());
69 ASSERT(m_newGen.fromSpace->isEmpty());
70 ASSERT(m_newGen.oversizeBlocks.isEmpty());
6fe7ccc8
A
71}
72
73void CopiedSpace::init()
74{
81345200
A
75 m_oldGen.toSpace = &m_oldGen.blocks1;
76 m_oldGen.fromSpace = &m_oldGen.blocks2;
6fe7ccc8 77
81345200
A
78 m_newGen.toSpace = &m_newGen.blocks1;
79 m_newGen.fromSpace = &m_newGen.blocks2;
80
93a37866 81 allocateBlock();
6fe7ccc8
A
82}
83
84CheckedBoolean CopiedSpace::tryAllocateSlowCase(size_t bytes, void** outPtr)
85{
86 if (isOversize(bytes))
87 return tryAllocateOversize(bytes, outPtr);
88
81345200 89 ASSERT(m_heap->vm()->currentThreadIsHoldingAPILock());
6fe7ccc8
A
90 m_heap->didAllocate(m_allocator.currentCapacity());
91
93a37866
A
92 allocateBlock();
93
94 *outPtr = m_allocator.forceAllocate(bytes);
6fe7ccc8
A
95 return true;
96}
97
98CheckedBoolean CopiedSpace::tryAllocateOversize(size_t bytes, void** outPtr)
99{
100 ASSERT(isOversize(bytes));
101
93a37866 102 CopiedBlock* block = CopiedBlock::create(m_heap->blockAllocator().allocateCustomSize(sizeof(CopiedBlock) + bytes, CopiedBlock::blockSize));
81345200
A
103 m_newGen.oversizeBlocks.push(block);
104 m_newGen.blockFilter.add(reinterpret_cast<Bits>(block));
93a37866 105 m_blockSet.add(block);
81345200 106 ASSERT(!block->isOld());
6fe7ccc8 107
93a37866
A
108 CopiedAllocator allocator;
109 allocator.setCurrentBlock(block);
110 *outPtr = allocator.forceAllocate(bytes);
111 allocator.resetCurrentBlock();
6fe7ccc8 112
93a37866 113 m_heap->didAllocate(block->region()->blockSize());
6fe7ccc8
A
114
115 return true;
116}
117
118CheckedBoolean CopiedSpace::tryReallocate(void** ptr, size_t oldSize, size_t newSize)
119{
120 if (oldSize >= newSize)
121 return true;
122
123 void* oldPtr = *ptr;
93a37866
A
124 ASSERT(!m_heap->vm()->isInitializingObject());
125
126 if (CopiedSpace::blockFor(oldPtr)->isOversize() || isOversize(newSize))
6fe7ccc8 127 return tryReallocateOversize(ptr, oldSize, newSize);
93a37866
A
128
129 if (m_allocator.tryReallocate(oldPtr, oldSize, newSize))
130 return true;
6fe7ccc8
A
131
132 void* result = 0;
133 if (!tryAllocate(newSize, &result)) {
134 *ptr = 0;
135 return false;
136 }
137 memcpy(result, oldPtr, oldSize);
138 *ptr = result;
139 return true;
140}
141
142CheckedBoolean CopiedSpace::tryReallocateOversize(void** ptr, size_t oldSize, size_t newSize)
143{
144 ASSERT(isOversize(oldSize) || isOversize(newSize));
145 ASSERT(newSize > oldSize);
146
147 void* oldPtr = *ptr;
148
149 void* newPtr = 0;
150 if (!tryAllocateOversize(newSize, &newPtr)) {
151 *ptr = 0;
152 return false;
153 }
154
155 memcpy(newPtr, oldPtr, oldSize);
156
93a37866
A
157 CopiedBlock* oldBlock = CopiedSpace::blockFor(oldPtr);
158 if (oldBlock->isOversize()) {
81345200
A
159 if (oldBlock->isOld())
160 m_oldGen.oversizeBlocks.remove(oldBlock);
161 else
162 m_newGen.oversizeBlocks.remove(oldBlock);
93a37866
A
163 m_blockSet.remove(oldBlock);
164 m_heap->blockAllocator().deallocateCustomSize(CopiedBlock::destroy(oldBlock));
6fe7ccc8
A
165 }
166
167 *ptr = newPtr;
168 return true;
169}
170
93a37866 171void CopiedSpace::doneFillingBlock(CopiedBlock* block, CopiedBlock** exchange)
6fe7ccc8 172{
6fe7ccc8 173 ASSERT(m_inCopyingPhase);
93a37866
A
174
175 if (exchange)
176 *exchange = allocateBlockForCopyingPhase();
177
178 if (!block)
179 return;
6fe7ccc8 180
93a37866
A
181 if (!block->dataSize()) {
182 recycleBorrowedBlock(block);
6fe7ccc8
A
183 return;
184 }
185
93a37866
A
186 block->zeroFillWilderness();
187
6fe7ccc8 188 {
81345200 189 // Always put the block into the old gen because it's being promoted!
93a37866 190 SpinLockHolder locker(&m_toSpaceLock);
81345200 191 m_oldGen.toSpace->push(block);
93a37866 192 m_blockSet.add(block);
81345200 193 m_oldGen.blockFilter.add(reinterpret_cast<Bits>(block));
6fe7ccc8
A
194 }
195
196 {
197 MutexLocker locker(m_loanedBlocksLock);
198 ASSERT(m_numberOfLoanedBlocks > 0);
93a37866 199 ASSERT(m_inCopyingPhase);
6fe7ccc8
A
200 m_numberOfLoanedBlocks--;
201 if (!m_numberOfLoanedBlocks)
202 m_loanedBlocksCondition.signal();
203 }
204}
205
81345200 206void CopiedSpace::didStartFullCollection()
6fe7ccc8 207{
81345200
A
208 ASSERT(heap()->operationInProgress() == FullCollection);
209 ASSERT(m_oldGen.fromSpace->isEmpty());
210 ASSERT(m_newGen.fromSpace->isEmpty());
6fe7ccc8 211
81345200
A
212#ifndef NDEBUG
213 for (CopiedBlock* block = m_newGen.toSpace->head(); block; block = block->next())
214 ASSERT(!block->liveBytes());
6fe7ccc8 215
81345200
A
216 for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block->next())
217 ASSERT(!block->liveBytes());
218#endif
219
220 for (CopiedBlock* block = m_oldGen.toSpace->head(); block; block = block->next())
221 block->didSurviveGC();
93a37866 222
81345200
A
223 for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block->next())
224 block->didSurviveGC();
6fe7ccc8
A
225}
226
93a37866 227void CopiedSpace::doneCopying()
6fe7ccc8 228{
93a37866
A
229 {
230 MutexLocker locker(m_loanedBlocksLock);
231 while (m_numberOfLoanedBlocks > 0)
232 m_loanedBlocksCondition.wait(m_loanedBlocksLock);
6fe7ccc8 233 }
6fe7ccc8 234
93a37866
A
235 ASSERT(m_inCopyingPhase == m_shouldDoCopyPhase);
236 m_inCopyingPhase = false;
6fe7ccc8 237
81345200
A
238 DoublyLinkedList<CopiedBlock>* toSpace;
239 DoublyLinkedList<CopiedBlock>* fromSpace;
240 TinyBloomFilter* blockFilter;
241 if (heap()->operationInProgress() == FullCollection) {
242 toSpace = m_oldGen.toSpace;
243 fromSpace = m_oldGen.fromSpace;
244 blockFilter = &m_oldGen.blockFilter;
245 } else {
246 toSpace = m_newGen.toSpace;
247 fromSpace = m_newGen.fromSpace;
248 blockFilter = &m_newGen.blockFilter;
249 }
250
251 while (!fromSpace->isEmpty()) {
252 CopiedBlock* block = fromSpace->removeHead();
93a37866
A
253 // We don't add the block to the blockSet because it was never removed.
254 ASSERT(m_blockSet.contains(block));
81345200
A
255 blockFilter->add(reinterpret_cast<Bits>(block));
256 block->didSurviveGC();
257 toSpace->push(block);
93a37866 258 }
6fe7ccc8 259
81345200
A
260 if (heap()->operationInProgress() == EdenCollection) {
261 m_oldGen.toSpace->append(*m_newGen.toSpace);
262 m_oldGen.oversizeBlocks.append(m_newGen.oversizeBlocks);
263 m_oldGen.blockFilter.add(m_newGen.blockFilter);
264 m_newGen.blockFilter.reset();
265 }
266
267 ASSERT(m_newGen.toSpace->isEmpty());
268 ASSERT(m_newGen.fromSpace->isEmpty());
269 ASSERT(m_newGen.oversizeBlocks.isEmpty());
270
271 allocateBlock();
93a37866
A
272
273 m_shouldDoCopyPhase = false;
6fe7ccc8
A
274}
275
276size_t CopiedSpace::size()
277{
278 size_t calculatedSize = 0;
279
81345200
A
280 for (CopiedBlock* block = m_oldGen.toSpace->head(); block; block = block->next())
281 calculatedSize += block->size();
282
283 for (CopiedBlock* block = m_oldGen.fromSpace->head(); block; block = block->next())
284 calculatedSize += block->size();
285
286 for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block->next())
6fe7ccc8
A
287 calculatedSize += block->size();
288
81345200 289 for (CopiedBlock* block = m_newGen.toSpace->head(); block; block = block->next())
6fe7ccc8
A
290 calculatedSize += block->size();
291
81345200
A
292 for (CopiedBlock* block = m_newGen.fromSpace->head(); block; block = block->next())
293 calculatedSize += block->size();
294
295 for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block->next())
6fe7ccc8
A
296 calculatedSize += block->size();
297
298 return calculatedSize;
299}
300
301size_t CopiedSpace::capacity()
302{
303 size_t calculatedCapacity = 0;
304
81345200
A
305 for (CopiedBlock* block = m_oldGen.toSpace->head(); block; block = block->next())
306 calculatedCapacity += block->capacity();
307
308 for (CopiedBlock* block = m_oldGen.fromSpace->head(); block; block = block->next())
309 calculatedCapacity += block->capacity();
310
311 for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block->next())
312 calculatedCapacity += block->capacity();
313
314 for (CopiedBlock* block = m_newGen.toSpace->head(); block; block = block->next())
6fe7ccc8
A
315 calculatedCapacity += block->capacity();
316
81345200 317 for (CopiedBlock* block = m_newGen.fromSpace->head(); block; block = block->next())
6fe7ccc8
A
318 calculatedCapacity += block->capacity();
319
81345200 320 for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block->next())
6fe7ccc8
A
321 calculatedCapacity += block->capacity();
322
323 return calculatedCapacity;
324}
325
93a37866 326static bool isBlockListPagedOut(double deadline, DoublyLinkedList<CopiedBlock>* list)
6fe7ccc8
A
327{
328 unsigned itersSinceLastTimeCheck = 0;
93a37866 329 CopiedBlock* current = list->head();
6fe7ccc8
A
330 while (current) {
331 current = current->next();
332 ++itersSinceLastTimeCheck;
333 if (itersSinceLastTimeCheck >= Heap::s_timeCheckResolution) {
334 double currentTime = WTF::monotonicallyIncreasingTime();
335 if (currentTime > deadline)
336 return true;
337 itersSinceLastTimeCheck = 0;
338 }
339 }
340
341 return false;
342}
343
344bool CopiedSpace::isPagedOut(double deadline)
345{
81345200
A
346 return isBlockListPagedOut(deadline, m_oldGen.toSpace)
347 || isBlockListPagedOut(deadline, m_oldGen.fromSpace)
348 || isBlockListPagedOut(deadline, &m_oldGen.oversizeBlocks)
349 || isBlockListPagedOut(deadline, m_newGen.toSpace)
350 || isBlockListPagedOut(deadline, m_newGen.fromSpace)
351 || isBlockListPagedOut(deadline, &m_newGen.oversizeBlocks);
6fe7ccc8
A
352}
353
354} // namespace JSC