blob: ef0e77f36f1337ec0006bc8396529d869e1714d1 [file] [log] [blame]
fpizlo@apple.comb426f862014-02-10 02:51:13 +00001/*
2 * Copyright (C) 2012, 2013 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
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +000026#include "config.h"
27#include "MarkedAllocator.h"
28
mhahnenberg@apple.com2b64eec02012-04-18 16:18:32 +000029#include "GCActivityCallback.h"
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +000030#include "Heap.h"
mhahnenberg@apple.com59c64f12012-07-31 23:05:12 +000031#include "IncrementalSweeper.h"
fpizlo@apple.comfb7eff22014-02-11 01:45:50 +000032#include "JSCInlines.h"
ggaren@apple.com9a9a4b52013-04-18 19:32:17 +000033#include "VM.h"
mhahnenberg@apple.com2e132e42012-05-03 00:14:05 +000034#include <wtf/CurrentTime.h>
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +000035
36namespace JSC {
37
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +000038static bool isListPagedOut(double deadline, DoublyLinkedList<MarkedBlock>& list)
mhahnenberg@apple.com2e132e42012-05-03 00:14:05 +000039{
40 unsigned itersSinceLastTimeCheck = 0;
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +000041 MarkedBlock* block = list.head();
mhahnenberg@apple.com2e132e42012-05-03 00:14:05 +000042 while (block) {
43 block = block->next();
44 ++itersSinceLastTimeCheck;
45 if (itersSinceLastTimeCheck >= Heap::s_timeCheckResolution) {
46 double currentTime = WTF::monotonicallyIncreasingTime();
47 if (currentTime > deadline)
48 return true;
49 itersSinceLastTimeCheck = 0;
50 }
51 }
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +000052 return false;
53}
mhahnenberg@apple.com2e132e42012-05-03 00:14:05 +000054
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +000055bool MarkedAllocator::isPagedOut(double deadline)
56{
57 if (isListPagedOut(deadline, m_blockList))
58 return true;
mhahnenberg@apple.com2e132e42012-05-03 00:14:05 +000059 return false;
60}
61
ggaren@apple.com7535d922016-06-21 23:06:08 +000062void MarkedAllocator::retire(MarkedBlock* block, MarkedBlock::FreeList& freeList)
63{
64 m_blockList.remove(block);
65 m_retiredBlocks.push(block);
66 block->didRetireBlock(freeList);
67}
68
ggaren@apple.com6159e5f2012-09-11 03:02:46 +000069inline void* MarkedAllocator::tryAllocateHelper(size_t bytes)
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +000070{
msaboff@apple.com84946d42015-02-06 01:12:00 +000071 if (m_currentBlock) {
72 ASSERT(m_currentBlock == m_nextBlockToSweep);
73 m_currentBlock->didConsumeFreeList();
74 m_nextBlockToSweep = m_currentBlock->next();
75 }
mhahnenberg@apple.combee96a32013-09-16 19:48:48 +000076
msaboff@apple.com84946d42015-02-06 01:12:00 +000077 MarkedBlock* next;
78 for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) {
79 next = block->next();
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +000080
msaboff@apple.com84946d42015-02-06 01:12:00 +000081 MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +000082
msaboff@apple.com84946d42015-02-06 01:12:00 +000083 double utilization = ((double)MarkedBlock::blockSize - (double)freeList.bytes) / (double)MarkedBlock::blockSize;
84 if (utilization >= Options::minMarkedBlockUtilization()) {
85 ASSERT(freeList.bytes || !freeList.head);
ggaren@apple.com7535d922016-06-21 23:06:08 +000086 retire(block, freeList);
msaboff@apple.com84946d42015-02-06 01:12:00 +000087 continue;
mhahnenberg@apple.com7f5b9592012-07-27 22:59:14 +000088 }
msaboff@apple.com84946d42015-02-06 01:12:00 +000089
90 if (bytes > block->cellSize()) {
91 block->stopAllocating(freeList);
92 continue;
93 }
94
95 m_currentBlock = block;
96 m_freeList = freeList;
97 break;
98 }
99
100 if (!m_freeList.head) {
101 m_currentBlock = 0;
102 return 0;
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000103 }
mhahnenberg@apple.com3f62e722013-12-19 04:30:02 +0000104
105 ASSERT(m_freeList.head);
mhahnenberg@apple.comfa811df2014-02-13 04:24:41 +0000106 void* head = tryPopFreeList(bytes);
mhahnenberg@apple.com8b5cfd32012-04-20 00:05:37 +0000107 ASSERT(head);
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000108 m_markedSpace->didAllocateInBlock(m_currentBlock);
mhahnenberg@apple.com8b5cfd32012-04-20 00:05:37 +0000109 return head;
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000110}
mhahnenberg@apple.comfa811df2014-02-13 04:24:41 +0000111
112inline void* MarkedAllocator::tryPopFreeList(size_t bytes)
113{
114 ASSERT(m_currentBlock);
115 if (bytes > m_currentBlock->cellSize())
116 return 0;
117
118 MarkedBlock::FreeCell* head = m_freeList.head;
119 m_freeList.head = head->next;
120 return head;
121}
122
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000123inline void* MarkedAllocator::tryAllocate(size_t bytes)
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000124{
mhahnenberg@apple.com47c9c532012-06-05 20:38:21 +0000125 ASSERT(!m_heap->isBusy());
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000126 m_heap->m_operationInProgress = Allocation;
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000127 void* result = tryAllocateHelper(bytes);
mhahnenberg@apple.comfa811df2014-02-13 04:24:41 +0000128
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000129 m_heap->m_operationInProgress = NoOperation;
mhahnenberg@apple.comfa811df2014-02-13 04:24:41 +0000130 ASSERT(result || !m_currentBlock);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000131 return result;
132}
mark.lam@apple.coma2a9f662014-04-24 21:12:56 +0000133
134ALWAYS_INLINE void MarkedAllocator::doTestCollectionsIfNeeded()
135{
136 if (!Options::slowPathAllocsBetweenGCs())
137 return;
138
139 static unsigned allocationCount = 0;
140 if (!allocationCount) {
141 if (!m_heap->isDeferred())
142 m_heap->collectAllGarbage();
143 ASSERT(m_heap->m_operationInProgress == NoOperation);
144 }
145 if (++allocationCount >= Options::slowPathAllocsBetweenGCs())
146 allocationCount = 0;
147}
148
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000149void* MarkedAllocator::allocateSlowCase(size_t bytes)
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000150{
andersca@apple.comb987aae2013-07-26 00:13:13 +0000151 ASSERT(m_heap->vm()->currentThreadIsHoldingAPILock());
mark.lam@apple.coma2a9f662014-04-24 21:12:56 +0000152 doTestCollectionsIfNeeded();
153
mhahnenberg@apple.combee96a32013-09-16 19:48:48 +0000154 ASSERT(!m_markedSpace->isIterating());
mhahnenberg@apple.com8b5cfd32012-04-20 00:05:37 +0000155 ASSERT(!m_freeList.head);
156 m_heap->didAllocate(m_freeList.bytes);
mhahnenberg@apple.com2b64eec02012-04-18 16:18:32 +0000157
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000158 void* result = tryAllocate(bytes);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000159
160 if (LIKELY(result != 0))
161 return result;
162
oliver@apple.com284cc3d2013-07-25 04:00:33 +0000163 if (m_heap->collectIfNecessaryOrDefer()) {
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000164 result = tryAllocate(bytes);
mhahnenberg@apple.com3e7e4e02012-05-09 02:44:39 +0000165 if (result)
166 return result;
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000167 }
mhahnenberg@apple.com3e7e4e02012-05-09 02:44:39 +0000168
mhahnenberg@apple.com8b5cfd32012-04-20 00:05:37 +0000169 ASSERT(!m_heap->shouldCollect());
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000170
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000171 MarkedBlock* block = allocateBlock(bytes);
mhahnenberg@apple.com3e7e4e02012-05-09 02:44:39 +0000172 ASSERT(block);
173 addBlock(block);
174
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000175 result = tryAllocate(bytes);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000176 ASSERT(result);
177 return result;
178}
ggaren@apple.coma68a6502012-05-22 23:59:51 +0000179
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000180MarkedBlock* MarkedAllocator::allocateBlock(size_t bytes)
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000181{
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000182 size_t minBlockSize = MarkedBlock::blockSize;
saambarati1@gmail.com64bf94c2015-08-27 05:54:21 +0000183 size_t minAllocationSize = WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(sizeof(MarkedBlock)) + WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(bytes);
184 minAllocationSize = WTF::roundUpToMultipleOf(WTF::pageSize(), minAllocationSize);
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000185 size_t blockSize = std::max(minBlockSize, minAllocationSize);
186
187 size_t cellSize = m_cellSize ? m_cellSize : WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(bytes);
188
akling@apple.com43fb3522015-11-01 02:29:47 +0000189 return MarkedBlock::create(*m_heap, this, blockSize, cellSize, m_needsDestruction);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000190}
191
192void MarkedAllocator::addBlock(MarkedBlock* block)
193{
194 ASSERT(!m_currentBlock);
mhahnenberg@apple.com8b5cfd32012-04-20 00:05:37 +0000195 ASSERT(!m_freeList.head);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000196
197 m_blockList.append(block);
mhahnenberg@apple.comfa811df2014-02-13 04:24:41 +0000198 m_nextBlockToSweep = block;
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000199 m_markedSpace->didAddBlock(block);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000200}
201
202void MarkedAllocator::removeBlock(MarkedBlock* block)
203{
ggaren@apple.com4b67d0d2012-06-21 02:00:08 +0000204 if (m_currentBlock == block) {
ggaren@apple.comdd7793a2012-07-31 21:26:38 +0000205 m_currentBlock = m_currentBlock->next();
ggaren@apple.com4b67d0d2012-06-21 02:00:08 +0000206 m_freeList = MarkedBlock::FreeList();
207 }
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000208 if (m_nextBlockToSweep == block)
209 m_nextBlockToSweep = m_nextBlockToSweep->next();
210
mhahnenberg@apple.comb59501b2014-03-12 01:45:54 +0000211 block->willRemoveBlock();
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000212 m_blockList.remove(block);
213}
214
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000215void MarkedAllocator::reset()
216{
217 m_lastActiveBlock = 0;
218 m_currentBlock = 0;
219 m_freeList = MarkedBlock::FreeList();
220 if (m_heap->operationInProgress() == FullCollection)
mhahnenberg@apple.comb59501b2014-03-12 01:45:54 +0000221 m_blockList.append(m_retiredBlocks);
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000222
mhahnenberg@apple.comb59501b2014-03-12 01:45:54 +0000223 m_nextBlockToSweep = m_blockList.head();
ggaren@apple.com7535d922016-06-21 23:06:08 +0000224
225 if (UNLIKELY(Options::useImmortalObjects())) {
226 MarkedBlock* next;
227 for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) {
228 next = block->next();
229
230 MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
231 retire(block, freeList);
232 }
233 }
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000234}
235
mhahnenberg@apple.com96b8cd12014-03-12 18:17:43 +0000236struct LastChanceToFinalize : MarkedBlock::VoidFunctor {
237 void operator()(MarkedBlock* block) { block->lastChanceToFinalize(); }
238};
239
240void MarkedAllocator::lastChanceToFinalize()
241{
242 m_blockList.append(m_retiredBlocks);
243 LastChanceToFinalize functor;
244 forEachBlock(functor);
245}
246
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000247} // namespace JSC