BlockAllocator should use regions as its VM allocation abstraction
[WebKit-https.git] / Source / JavaScriptCore / heap / MarkedAllocator.cpp
1 #include "config.h"
2 #include "MarkedAllocator.h"
3
4 #include "GCActivityCallback.h"
5 #include "Heap.h"
6 #include "IncrementalSweeper.h"
7 #include "JSGlobalData.h"
8 #include <wtf/CurrentTime.h>
9
10 namespace JSC {
11
12 bool MarkedAllocator::isPagedOut(double deadline)
13 {
14     unsigned itersSinceLastTimeCheck = 0;
15     MarkedBlock* block = m_blockList.head();
16     while (block) {
17         block = block->next();
18         ++itersSinceLastTimeCheck;
19         if (itersSinceLastTimeCheck >= Heap::s_timeCheckResolution) {
20             double currentTime = WTF::monotonicallyIncreasingTime();
21             if (currentTime > deadline)
22                 return true;
23             itersSinceLastTimeCheck = 0;
24         }
25     }
26
27     return false;
28 }
29
30 inline void* MarkedAllocator::tryAllocateHelper(size_t bytes)
31 {
32     if (!m_freeList.head) {
33         for (MarkedBlock*& block = m_blocksToSweep; block; block = block->next()) {
34             MarkedBlock::FreeList freeList = block->sweep(MarkedBlock::SweepToFreeList);
35             if (!freeList.head) {
36                 block->didConsumeFreeList();
37                 continue;
38             }
39
40             if (bytes > block->cellSize()) {
41                 block->canonicalizeCellLivenessData(freeList);
42                 continue;
43             }
44
45             m_currentBlock = block;
46             m_freeList = freeList;
47             break;
48         }
49         
50         if (!m_freeList.head) {
51             m_currentBlock = 0;
52             return 0;
53         }
54     }
55     
56     MarkedBlock::FreeCell* head = m_freeList.head;
57     m_freeList.head = head->next;
58     ASSERT(head);
59     return head;
60 }
61     
62 inline void* MarkedAllocator::tryAllocate(size_t bytes)
63 {
64     ASSERT(!m_heap->isBusy());
65     m_heap->m_operationInProgress = Allocation;
66     void* result = tryAllocateHelper(bytes);
67     m_heap->m_operationInProgress = NoOperation;
68     return result;
69 }
70     
71 void* MarkedAllocator::allocateSlowCase(size_t bytes)
72 {
73     ASSERT(m_heap->globalData()->apiLock().currentThreadIsHoldingLock());
74 #if COLLECT_ON_EVERY_ALLOCATION
75     m_heap->collectAllGarbage();
76     ASSERT(m_heap->m_operationInProgress == NoOperation);
77 #endif
78     
79     ASSERT(!m_freeList.head);
80     m_heap->didAllocate(m_freeList.bytes);
81     
82     void* result = tryAllocate(bytes);
83     
84     if (LIKELY(result != 0))
85         return result;
86     
87     if (m_heap->shouldCollect()) {
88         m_heap->collect(Heap::DoNotSweep);
89
90         result = tryAllocate(bytes);
91         if (result)
92             return result;
93     }
94
95     ASSERT(!m_heap->shouldCollect());
96     
97     MarkedBlock* block = allocateBlock(bytes);
98     ASSERT(block);
99     addBlock(block);
100         
101     result = tryAllocate(bytes);
102     ASSERT(result);
103     return result;
104 }
105
106 MarkedBlock* MarkedAllocator::allocateBlock(size_t bytes)
107 {
108     size_t minBlockSize = MarkedBlock::blockSize;
109     size_t minAllocationSize = WTF::roundUpToMultipleOf(WTF::pageSize(), sizeof(MarkedBlock) + bytes);
110     size_t blockSize = std::max(minBlockSize, minAllocationSize);
111
112     size_t cellSize = m_cellSize ? m_cellSize : WTF::roundUpToMultipleOf<MarkedBlock::atomSize>(bytes);
113
114     if (blockSize == MarkedBlock::blockSize)
115         return MarkedBlock::create(m_heap->blockAllocator().allocate<MarkedBlock>(), this, cellSize, m_destructorType);
116     return MarkedBlock::create(m_heap->blockAllocator().allocateCustomSize(blockSize, MarkedBlock::blockSize), this, cellSize, m_destructorType);
117 }
118
119 void MarkedAllocator::addBlock(MarkedBlock* block)
120 {
121     ASSERT(!m_currentBlock);
122     ASSERT(!m_freeList.head);
123     
124     m_blockList.append(block);
125     m_blocksToSweep = m_currentBlock = block;
126     m_freeList = block->sweep(MarkedBlock::SweepToFreeList);
127     m_markedSpace->didAddBlock(block);
128 }
129
130 void MarkedAllocator::removeBlock(MarkedBlock* block)
131 {
132     if (m_currentBlock == block) {
133         m_currentBlock = m_currentBlock->next();
134         m_freeList = MarkedBlock::FreeList();
135     }
136     if (m_blocksToSweep == block)
137         m_blocksToSweep = m_blocksToSweep->next();
138     m_blockList.remove(block);
139 }
140
141 } // namespace JSC