Incremetal sweeper added to improve memory usage
[framework/web/webkit-efl.git] / Source / JavaScriptCore / heap / IncrementalSweeper.cpp
1 /*
2  * Copyright (C) 2012 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 #include "config.h"
27 #include "IncrementalSweeper.h"
28
29 #include "APIShims.h"
30 #include "Heap.h"
31 #include "JSObject.h"
32 #include "JSString.h"
33 #include "MarkedBlock.h"
34 #include "ScopeChain.h"
35 #include <wtf/HashSet.h>
36 #include <wtf/WTFThreadData.h>
37
38 #if PLATFORM(EFL)
39 #include <wtf/MainThread.h>
40 #endif
41
42 namespace JSC {
43
44 #if USE(CF)
45
46 static const CFTimeInterval sweepTimeSlice = .01; // seconds
47 static const CFTimeInterval sweepTimeTotal = .10;
48 static const CFTimeInterval sweepTimeMultiplier = 1.0 / sweepTimeTotal;
49
50 void IncrementalSweeper::doWork()
51 {
52     doSweep(WTF::monotonicallyIncreasingTime());
53 }
54     
55 IncrementalSweeper::IncrementalSweeper(Heap* heap, CFRunLoopRef runLoop)
56     : HeapTimer(heap->globalData(), runLoop)
57     , m_currentBlockToSweepIndex(0)
58     , m_structuresCanBeSwept(false)
59 {
60 }
61
62 IncrementalSweeper* IncrementalSweeper::create(Heap* heap)
63 {
64     return new IncrementalSweeper(heap, CFRunLoopGetCurrent());
65 }
66
67 void IncrementalSweeper::scheduleTimer()
68 {
69     CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + (sweepTimeSlice * sweepTimeMultiplier));
70 }
71
72 void IncrementalSweeper::cancelTimer()
73 {
74     CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade);
75 }
76
77 void IncrementalSweeper::doSweep(double sweepBeginTime)
78 {
79     while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) {
80         sweepNextBlock();
81
82         CFTimeInterval elapsedTime = WTF::monotonicallyIncreasingTime() - sweepBeginTime;
83         if (elapsedTime < sweepTimeSlice)
84             continue;
85
86         scheduleTimer();
87         return;
88     }
89
90     m_blocksToSweep.clear();
91     cancelTimer();
92 }
93
94 void IncrementalSweeper::sweepNextBlock()
95 {
96     while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) {
97         MarkedBlock* block = m_blocksToSweep[m_currentBlockToSweepIndex++];
98         if (block->onlyContainsStructures())
99             m_structuresCanBeSwept = true;
100         else
101             ASSERT(!m_structuresCanBeSwept);
102
103         if (!block->needsSweeping())
104             continue;
105
106         block->sweep();
107         m_globalData->heap.objectSpace().freeOrShrinkBlock(block);
108         return;
109     }
110 }
111
112 void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>& blockSnapshot)
113 {
114     m_blocksToSweep.resize(blockSnapshot.size());
115     CopyFunctor functor(m_blocksToSweep);
116     m_globalData->heap.objectSpace().forEachBlock(functor);
117     m_currentBlockToSweepIndex = 0;
118     m_structuresCanBeSwept = false;
119     scheduleTimer();
120 }
121
122 void IncrementalSweeper::willFinishSweeping()
123 {
124     m_currentBlockToSweepIndex = 0;
125     m_structuresCanBeSwept = true;
126     m_blocksToSweep.clear();
127     if (m_globalData)
128         cancelTimer();
129 }
130
131 #elif PLATFORM(EFL)
132
133 static const double sweepTimeSlice = .01; // seconds
134 static const double sweepTimeTotal = .10;
135 static const double sweepTimeMultiplier = 1.0 / sweepTimeTotal;
136
137 IncrementalSweeper::IncrementalSweeper(JSGlobalData* globalData)
138     : HeapTimer(globalData)
139     , m_enabled(WTF::isMainThread())
140     , m_structuresCanBeSwept(false)
141 {
142 }
143
144 void IncrementalSweeper::doWork()
145 {
146     double startTime = WTF::monotonicallyIncreasingTime();
147     while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) {
148         sweepNextBlock();
149
150         double elapsedTime = WTF::monotonicallyIncreasingTime() - startTime;
151         if (elapsedTime < sweepTimeSlice)
152             continue;
153
154         scheduleTimer();
155         return;
156     }
157     m_blocksToSweep.clear();
158     cancelTimer();
159 }
160
161 void IncrementalSweeper::scheduleTimer()
162 {
163     cancelTimer();
164     m_timer = add(sweepTimeSlice * sweepTimeMultiplier, this);
165 }
166
167 void IncrementalSweeper::cancelTimer()
168 {
169     stop();
170 }
171
172 IncrementalSweeper* IncrementalSweeper::create(Heap* heap)
173 {
174     return new IncrementalSweeper(heap->globalData());
175 }
176
177 void IncrementalSweeper::sweepNextBlock()
178 {
179     while (m_currentBlockToSweepIndex < m_blocksToSweep.size()) {
180         MarkedBlock* block = m_blocksToSweep[m_currentBlockToSweepIndex++];
181         if (block->onlyContainsStructures())
182             m_structuresCanBeSwept = true;
183         else
184             ASSERT(!m_structuresCanBeSwept);
185
186         if (!block->needsSweeping())
187             continue;
188
189         block->sweep();
190         m_globalData->heap.objectSpace().freeOrShrinkBlock(block);
191         return;
192     }
193 }
194
195 void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>& blockSnapshot)
196 {
197     if (!isEnabled())
198         return;
199
200     m_blocksToSweep.resize(blockSnapshot.size());
201     CopyFunctor functor(m_blocksToSweep);
202     m_globalData->heap.objectSpace().forEachBlock(functor);
203     m_currentBlockToSweepIndex = 0;
204     m_structuresCanBeSwept = false;
205     scheduleTimer();
206 }
207
208 void IncrementalSweeper::willFinishSweeping()
209 {
210     m_currentBlockToSweepIndex = 0;
211     m_structuresCanBeSwept = true;
212     m_blocksToSweep.clear();
213     if (m_globalData)
214         cancelTimer();
215 }
216 #else
217
218 IncrementalSweeper::IncrementalSweeper(JSGlobalData* globalData)
219     : HeapTimer(globalData)
220     , m_structuresCanBeSwept(false)
221 {
222 }
223
224 void IncrementalSweeper::doWork()
225 {
226 }
227
228 IncrementalSweeper* IncrementalSweeper::create(Heap* heap)
229 {
230     return new IncrementalSweeper(heap->globalData());
231 }
232
233 void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>&)
234 {
235     m_structuresCanBeSwept = false;
236 }
237
238 void IncrementalSweeper::willFinishSweeping()
239 {
240     m_structuresCanBeSwept = true;
241 }
242
243 void IncrementalSweeper::sweepNextBlock()
244 {
245 }
246
247 #endif
248
249 bool IncrementalSweeper::structuresCanBeSwept()
250 {
251     return m_structuresCanBeSwept;
252 }
253
254 } // namespace JSC