1/*
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
26#ifndef MarkedAllocator_h
27#define MarkedAllocator_h
28
29#include "MarkedBlock.h"
30#include <wtf/DoublyLinkedList.h>
31
32namespace JSC {
33
34class Heap;
35class MarkedSpace;
36class LLIntOffsetsExtractor;
37
38class MarkedAllocator {
39 friend class LLIntOffsetsExtractor;
40
41public:
42 static ptrdiff_t offsetOfFreeListHead();
43
44 MarkedAllocator();
45 void lastChanceToFinalize();
46 void reset();
47 void stopAllocating();
48 void resumeAllocating();
49 size_t cellSize() { return m_cellSize; }
50 bool needsDestruction() { return m_needsDestruction; }
51 void* allocate(size_t);
52 Heap* heap() { return m_heap; }
53 MarkedBlock* takeLastActiveBlock()
54 {
55 MarkedBlock* block = m_lastActiveBlock;
56 m_lastActiveBlock = 0;
57 return block;
58 }
59
60 template<typename Functor> void forEachBlock(Functor&);
61
62 void addBlock(MarkedBlock*);
63 void removeBlock(MarkedBlock*);
64 void init(Heap*, MarkedSpace*, size_t cellSize, bool needsDestruction);
65
66 bool isPagedOut(double deadline);
67
68private:
69 JS_EXPORT_PRIVATE void* allocateSlowCase(size_t);
70 void* tryAllocate(size_t);
71 void* tryAllocateHelper(size_t);
72 void* tryPopFreeList(size_t);
73 MarkedBlock* allocateBlock(size_t);
74 ALWAYS_INLINE void doTestCollectionsIfNeeded();
75
76 MarkedBlock::FreeList m_freeList;
77 MarkedBlock* m_currentBlock;
78 MarkedBlock* m_lastActiveBlock;
79 MarkedBlock* m_nextBlockToSweep;
80 DoublyLinkedList<MarkedBlock> m_blockList;
81 DoublyLinkedList<MarkedBlock> m_retiredBlocks;
82 size_t m_cellSize;
83 bool m_needsDestruction { false };
84 Heap* m_heap;
85 MarkedSpace* m_markedSpace;
86};
87
88inline ptrdiff_t MarkedAllocator::offsetOfFreeListHead()
89{
90 return OBJECT_OFFSETOF(MarkedAllocator, m_freeList) + OBJECT_OFFSETOF(MarkedBlock::FreeList, head);
91}
92
93inline MarkedAllocator::MarkedAllocator()
94 : m_currentBlock(0)
95 , m_lastActiveBlock(0)
96 , m_nextBlockToSweep(0)
97 , m_cellSize(0)
98 , m_heap(0)
99 , m_markedSpace(0)
100{
101}
102
103inline void MarkedAllocator::init(Heap* heap, MarkedSpace* markedSpace, size_t cellSize, bool needsDestruction)
104{
105 m_heap = heap;
106 m_markedSpace = markedSpace;
107 m_cellSize = cellSize;
108 m_needsDestruction = needsDestruction;
109}
110
111inline void* MarkedAllocator::allocate(size_t bytes)
112{
113 MarkedBlock::FreeCell* head = m_freeList.head;
114 if (UNLIKELY(!head)) {
115 void* result = allocateSlowCase(bytes);
116#ifndef NDEBUG
117 memset(result, 0xCD, bytes);
118#endif
119 return result;
120 }
121
122 m_freeList.head = head->next;
123#ifndef NDEBUG
124 memset(head, 0xCD, bytes);
125#endif
126 return head;
127}
128
129inline void MarkedAllocator::stopAllocating()
130{
131 ASSERT(!m_lastActiveBlock);
132 if (!m_currentBlock) {
133 ASSERT(!m_freeList.head);
134 return;
135 }
136
137 m_currentBlock->stopAllocating(m_freeList);
138 m_lastActiveBlock = m_currentBlock;
139 m_currentBlock = 0;
140 m_freeList = MarkedBlock::FreeList();
141}
142
143inline void MarkedAllocator::resumeAllocating()
144{
145 if (!m_lastActiveBlock)
146 return;
147
148 m_freeList = m_lastActiveBlock->resumeAllocating();
149 m_currentBlock = m_lastActiveBlock;
150 m_lastActiveBlock = 0;
151}
152
153template <typename Functor> inline void MarkedAllocator::forEachBlock(Functor& functor)
154{
155 MarkedBlock* next;
156 for (MarkedBlock* block = m_blockList.head(); block; block = next) {
157 next = block->next();
158 functor(block);
159 }
160
161 for (MarkedBlock* block = m_retiredBlocks.head(); block; block = next) {
162 next = block->next();
163 functor(block);
164 }
165}
166
167} // namespace JSC
168
169#endif // MarkedAllocator_h
170