1/*
2 *  Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 *
19 */
20
21#include "config.h"
22#include "MarkedSpace.h"
23
24#include "IncrementalSweeper.h"
25#include "JSGlobalObject.h"
26#include "JSLock.h"
27#include "JSObject.h"
28
29
30namespace JSC {
31
32class Structure;
33
34class Free {
35public:
36    typedef MarkedBlock* ReturnType;
37
38    enum FreeMode { FreeOrShrink, FreeAll };
39
40    Free(FreeMode, MarkedSpace*);
41    void operator()(MarkedBlock*);
42    ReturnType returnValue();
43
44private:
45    FreeMode m_freeMode;
46    MarkedSpace* m_markedSpace;
47    DoublyLinkedList<MarkedBlock> m_blocks;
48};
49
50inline Free::Free(FreeMode freeMode, MarkedSpace* newSpace)
51    : m_freeMode(freeMode)
52    , m_markedSpace(newSpace)
53{
54}
55
56inline void Free::operator()(MarkedBlock* block)
57{
58    if (m_freeMode == FreeOrShrink)
59        m_markedSpace->freeOrShrinkBlock(block);
60    else
61        m_markedSpace->freeBlock(block);
62}
63
64inline Free::ReturnType Free::returnValue()
65{
66    return m_blocks.head();
67}
68
69struct VisitWeakSet : MarkedBlock::VoidFunctor {
70    VisitWeakSet(HeapRootVisitor& heapRootVisitor) : m_heapRootVisitor(heapRootVisitor) { }
71    void operator()(MarkedBlock* block) { block->visitWeakSet(m_heapRootVisitor); }
72private:
73    HeapRootVisitor& m_heapRootVisitor;
74};
75
76struct ReapWeakSet : MarkedBlock::VoidFunctor {
77    void operator()(MarkedBlock* block) { block->reapWeakSet(); }
78};
79
80MarkedSpace::MarkedSpace(Heap* heap)
81    : m_heap(heap)
82{
83    for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
84        allocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::None);
85        normalDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::Normal);
86        immortalStructureDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::ImmortalStructure);
87    }
88
89    for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) {
90        allocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::None);
91        normalDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::Normal);
92        immortalStructureDestructorAllocatorFor(cellSize).init(heap, this, cellSize, MarkedBlock::ImmortalStructure);
93    }
94
95    m_normalSpace.largeAllocator.init(heap, this, 0, MarkedBlock::None);
96    m_normalDestructorSpace.largeAllocator.init(heap, this, 0, MarkedBlock::Normal);
97    m_immortalStructureDestructorSpace.largeAllocator.init(heap, this, 0, MarkedBlock::ImmortalStructure);
98}
99
100MarkedSpace::~MarkedSpace()
101{
102    Free free(Free::FreeAll, this);
103    forEachBlock(free);
104}
105
106struct LastChanceToFinalize : MarkedBlock::VoidFunctor {
107    void operator()(MarkedBlock* block) { block->lastChanceToFinalize(); }
108};
109
110void MarkedSpace::lastChanceToFinalize()
111{
112    canonicalizeCellLivenessData();
113    forEachBlock<LastChanceToFinalize>();
114}
115
116void MarkedSpace::sweep()
117{
118    m_heap->sweeper()->willFinishSweeping();
119    forEachBlock<Sweep>();
120}
121
122void MarkedSpace::resetAllocators()
123{
124    for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
125        allocatorFor(cellSize).reset();
126        normalDestructorAllocatorFor(cellSize).reset();
127        immortalStructureDestructorAllocatorFor(cellSize).reset();
128    }
129
130    for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) {
131        allocatorFor(cellSize).reset();
132        normalDestructorAllocatorFor(cellSize).reset();
133        immortalStructureDestructorAllocatorFor(cellSize).reset();
134    }
135
136    m_normalSpace.largeAllocator.reset();
137    m_normalDestructorSpace.largeAllocator.reset();
138    m_immortalStructureDestructorSpace.largeAllocator.reset();
139}
140
141void MarkedSpace::visitWeakSets(HeapRootVisitor& heapRootVisitor)
142{
143    VisitWeakSet visitWeakSet(heapRootVisitor);
144    forEachBlock(visitWeakSet);
145}
146
147void MarkedSpace::reapWeakSets()
148{
149    forEachBlock<ReapWeakSet>();
150}
151
152void MarkedSpace::canonicalizeCellLivenessData()
153{
154    for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
155        allocatorFor(cellSize).canonicalizeCellLivenessData();
156        normalDestructorAllocatorFor(cellSize).canonicalizeCellLivenessData();
157        immortalStructureDestructorAllocatorFor(cellSize).canonicalizeCellLivenessData();
158    }
159
160    for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) {
161        allocatorFor(cellSize).canonicalizeCellLivenessData();
162        normalDestructorAllocatorFor(cellSize).canonicalizeCellLivenessData();
163        immortalStructureDestructorAllocatorFor(cellSize).canonicalizeCellLivenessData();
164    }
165
166    m_normalSpace.largeAllocator.canonicalizeCellLivenessData();
167    m_normalDestructorSpace.largeAllocator.canonicalizeCellLivenessData();
168    m_immortalStructureDestructorSpace.largeAllocator.canonicalizeCellLivenessData();
169}
170
171bool MarkedSpace::isPagedOut(double deadline)
172{
173    for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) {
174        if (allocatorFor(cellSize).isPagedOut(deadline)
175            || normalDestructorAllocatorFor(cellSize).isPagedOut(deadline)
176            || immortalStructureDestructorAllocatorFor(cellSize).isPagedOut(deadline))
177            return true;
178    }
179
180    for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) {
181        if (allocatorFor(cellSize).isPagedOut(deadline)
182            || normalDestructorAllocatorFor(cellSize).isPagedOut(deadline)
183            || immortalStructureDestructorAllocatorFor(cellSize).isPagedOut(deadline))
184            return true;
185    }
186
187    if (m_normalSpace.largeAllocator.isPagedOut(deadline)
188        || m_normalDestructorSpace.largeAllocator.isPagedOut(deadline)
189        || m_immortalStructureDestructorSpace.largeAllocator.isPagedOut(deadline))
190        return true;
191
192    return false;
193}
194
195void MarkedSpace::freeBlock(MarkedBlock* block)
196{
197    block->allocator()->removeBlock(block);
198    m_blocks.remove(block);
199    if (block->capacity() == MarkedBlock::blockSize) {
200        m_heap->blockAllocator().deallocate(MarkedBlock::destroy(block));
201        return;
202    }
203    m_heap->blockAllocator().deallocateCustomSize(MarkedBlock::destroy(block));
204}
205
206void MarkedSpace::freeOrShrinkBlock(MarkedBlock* block)
207{
208    if (!block->isEmpty()) {
209        block->shrink();
210        return;
211    }
212
213    freeBlock(block);
214}
215
216struct Shrink : MarkedBlock::VoidFunctor {
217    void operator()(MarkedBlock* block) { block->shrink(); }
218};
219
220void MarkedSpace::shrink()
221{
222    Free freeOrShrink(Free::FreeOrShrink, this);
223    forEachBlock(freeOrShrink);
224}
225
226} // namespace JSC
227