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