blob: e95ee6b1ea60e054cbbe08074933c57c19f026c0 [file] [log] [blame]
fpizlo@apple.comb426f862014-02-10 02:51:13 +00001/*
fpizlo@apple.comaeddff92016-07-18 21:33:45 +00002 * Copyright (C) 2012, 2013, 2016 Apple Inc. All rights reserved.
fpizlo@apple.comb426f862014-02-10 02:51:13 +00003 *
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
fpizlo@apple.comaeddff92016-07-18 21:33:45 +0000189 // FIXME: Support allocating storage in marked blocks. This would mean that allocateBlock()
190 // takes a HeapCell::Kind, or something like that.
191 // https://bugs.webkit.org/show_bug.cgi?id=159658
192 return MarkedBlock::create(*m_heap, this, blockSize, cellSize, m_needsDestruction, HeapCell::JSCell);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000193}
194
195void MarkedAllocator::addBlock(MarkedBlock* block)
196{
197 ASSERT(!m_currentBlock);
mhahnenberg@apple.com8b5cfd32012-04-20 00:05:37 +0000198 ASSERT(!m_freeList.head);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000199
200 m_blockList.append(block);
mhahnenberg@apple.comfa811df2014-02-13 04:24:41 +0000201 m_nextBlockToSweep = block;
ggaren@apple.com6159e5f2012-09-11 03:02:46 +0000202 m_markedSpace->didAddBlock(block);
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000203}
204
205void MarkedAllocator::removeBlock(MarkedBlock* block)
206{
ggaren@apple.com4b67d0d2012-06-21 02:00:08 +0000207 if (m_currentBlock == block) {
ggaren@apple.comdd7793a2012-07-31 21:26:38 +0000208 m_currentBlock = m_currentBlock->next();
ggaren@apple.com4b67d0d2012-06-21 02:00:08 +0000209 m_freeList = MarkedBlock::FreeList();
210 }
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000211 if (m_nextBlockToSweep == block)
212 m_nextBlockToSweep = m_nextBlockToSweep->next();
213
mhahnenberg@apple.comb59501b2014-03-12 01:45:54 +0000214 block->willRemoveBlock();
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000215 m_blockList.remove(block);
216}
217
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000218void MarkedAllocator::reset()
219{
220 m_lastActiveBlock = 0;
221 m_currentBlock = 0;
222 m_freeList = MarkedBlock::FreeList();
223 if (m_heap->operationInProgress() == FullCollection)
mhahnenberg@apple.comb59501b2014-03-12 01:45:54 +0000224 m_blockList.append(m_retiredBlocks);
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000225
mhahnenberg@apple.comb59501b2014-03-12 01:45:54 +0000226 m_nextBlockToSweep = m_blockList.head();
ggaren@apple.com7535d922016-06-21 23:06:08 +0000227
228 if (UNLIKELY(Options::useImmortalObjects())) {
229 MarkedBlock* next;
230 for (MarkedBlock*& block = m_nextBlockToSweep; block; block = next) {
231 next = block->next();
232
233 MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
234 retire(block, freeList);
235 }
236 }
mhahnenberg@apple.com3ddd7ac2014-01-10 02:28:27 +0000237}
238
mhahnenberg@apple.com96b8cd12014-03-12 18:17:43 +0000239void MarkedAllocator::lastChanceToFinalize()
240{
241 m_blockList.append(m_retiredBlocks);
fpizlo@apple.comaeddff92016-07-18 21:33:45 +0000242 forEachBlock(
243 [&] (MarkedBlock* block) {
244 block->lastChanceToFinalize();
245 });
mhahnenberg@apple.com96b8cd12014-03-12 18:17:43 +0000246}
247
mhahnenberg@apple.comce85b932012-02-03 19:27:57 +0000248} // namespace JSC