|
dvander@49
|
1 |
/* vim: set ts=4 sw=4 tw=99 et: |
|
dvander@49
|
2 |
* |
|
dvander@49
|
3 |
* Copyright (C) 2012 David Anderson |
|
dvander@49
|
4 |
* |
|
dvander@49
|
5 |
* This file is part of JITCraft. |
|
dvander@49
|
6 |
* |
|
dvander@49
|
7 |
* JITCraft is free software: you can redistribute it and/or modify it under |
|
dvander@49
|
8 |
* the terms of the GNU General Public License as published by the Free |
|
dvander@49
|
9 |
* Software Foundation, either version 3 of the License, or (at your option) |
|
dvander@49
|
10 |
* any later version. |
|
dvander@49
|
11 |
* |
|
dvander@49
|
12 |
* Foobar is distributed in the hope that it will be useful, but WITHOUT ANY |
|
dvander@49
|
13 |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
dvander@49
|
14 |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
|
dvander@49
|
15 |
* |
|
dvander@49
|
16 |
* You should have received a copy of the GNU General Public License along with |
|
dvander@49
|
17 |
* JITCraft. If not, see http://www.gnu.org/licenses/. |
|
dvander@49
|
18 |
*/ |
|
danderson@91
|
19 |
#include <string.h> |
|
dvander@53
|
20 |
#include "Zone.h" |
|
dvander@49
|
21 |
#include "Spaces.h" |
|
dvander@49
|
22 |
#include "Platform.h" |
|
dvander@49
|
23 |
#include "Spaces-inl.h" |
|
dvander@49
|
24 |
|
|
dvander@59
|
25 |
using namespace ke; |
|
dvander@49
|
26 |
|
|
dvander@49
|
27 |
HeapStack::HeapStack() |
|
dvander@51
|
28 |
: chunk_(NULL), |
|
dvander@51
|
29 |
cursor_(NULL) |
|
dvander@49
|
30 |
{ |
|
dvander@49
|
31 |
} |
|
dvander@49
|
32 |
|
|
dvander@49
|
33 |
HeapStack::~HeapStack() |
|
dvander@49
|
34 |
{ |
|
dvander@51
|
35 |
if (chunk_) |
|
dvander@51
|
36 |
HeapChunk::Destroy(chunk_); |
|
dvander@49
|
37 |
} |
|
dvander@49
|
38 |
|
|
dvander@49
|
39 |
bool |
|
dvander@49
|
40 |
HeapStack::initialize() |
|
dvander@49
|
41 |
{ |
|
dvander@51
|
42 |
chunk_ = HeapChunk::New(NULL, kStackSize); |
|
dvander@51
|
43 |
cursor_ = chunk_->first(); |
|
dvander@49
|
44 |
return true; |
|
dvander@49
|
45 |
} |
|
dvander@49
|
46 |
|
|
dvander@11
|
47 |
HeapChunk * |
|
dvander@11
|
48 |
HeapChunk::New(HeapChunk *prev, size_t size) |
|
dvander@11
|
49 |
{ |
|
dvander@11
|
50 |
OS::AlignableMapping map = |
|
dvander@11
|
51 |
OS::MapAlignedMemory(size, HeapChunk::kAlignment, OS::Map_Commit); |
|
dvander@11
|
52 |
|
|
dvander@11
|
53 |
if (!map.base()) |
|
dvander@11
|
54 |
return NULL; |
|
dvander@11
|
55 |
|
|
dvander@11
|
56 |
HeapChunk *chunk = reinterpret_cast<HeapChunk *>(map.aligned()); |
|
dvander@11
|
57 |
chunk->base_ = map.base(); |
|
dvander@11
|
58 |
chunk->end_ = map.base() + map.size(); |
|
dvander@11
|
59 |
if (prev) |
|
dvander@11
|
60 |
prev->next_ = chunk; |
|
dvander@11
|
61 |
|
|
dvander@11
|
62 |
return chunk; |
|
dvander@11
|
63 |
} |
|
dvander@11
|
64 |
|
|
dvander@11
|
65 |
void |
|
dvander@11
|
66 |
HeapChunk::Destroy(HeapChunk *chunk) |
|
dvander@11
|
67 |
{ |
|
dvander@11
|
68 |
OS::UnmapAlignedMemory(chunk->base(), chunk->size()); |
|
dvander@11
|
69 |
} |
|
dvander@11
|
70 |
|
|
dvander@53
|
71 |
void |
|
dvander@53
|
72 |
HeapChunk::resetMarkBits() |
|
dvander@53
|
73 |
{ |
|
dvander@53
|
74 |
memset(markBits(), 0, kMarkBytes); |
|
dvander@53
|
75 |
} |
|
dvander@53
|
76 |
|
|
dvander@53
|
77 |
FreeList::FreeList() |
|
dvander@53
|
78 |
: small_objects_(NULL), |
|
dvander@53
|
79 |
medium_objects_(NULL), |
|
dvander@53
|
80 |
large_objects_(NULL), |
|
dvander@53
|
81 |
huge_objects_(NULL) |
|
dvander@53
|
82 |
{ |
|
dvander@53
|
83 |
} |
|
dvander@53
|
84 |
|
|
dvander@53
|
85 |
void |
|
dvander@53
|
86 |
FreeList::add(FreedObject *obj) |
|
dvander@53
|
87 |
{ |
|
dvander@53
|
88 |
if (obj->size() < kMinObjectSize) |
|
dvander@53
|
89 |
return; |
|
dvander@53
|
90 |
|
|
dvander@53
|
91 |
FreedObject **list; |
|
dvander@53
|
92 |
if (obj->size() < kMaxSmallObject) |
|
dvander@53
|
93 |
list = &small_objects_; |
|
dvander@53
|
94 |
else if (obj->size() < kMaxMediumObject) |
|
dvander@53
|
95 |
list = &medium_objects_; |
|
dvander@53
|
96 |
else if (obj->size() < kMaxLargeObject) |
|
dvander@53
|
97 |
list = &large_objects_; |
|
dvander@53
|
98 |
else |
|
dvander@53
|
99 |
list = &huge_objects_; |
|
dvander@53
|
100 |
|
|
dvander@53
|
101 |
if (*list) |
|
dvander@53
|
102 |
(*list)->setNext(obj); |
|
dvander@53
|
103 |
*list = obj; |
|
dvander@53
|
104 |
} |
|
dvander@53
|
105 |
|
|
dvander@53
|
106 |
FreedObject * |
|
dvander@53
|
107 |
FreeList::pick(size_t size) |
|
dvander@53
|
108 |
{ |
|
dvander@53
|
109 |
if (size < kMinObjectSize && small_objects_) { |
|
dvander@53
|
110 |
FreedObject *obj = small_objects_; |
|
dvander@53
|
111 |
small_objects_ = small_objects_->next(); |
|
dvander@53
|
112 |
return obj; |
|
dvander@53
|
113 |
} |
|
dvander@53
|
114 |
if (size < kMaxSmallObject && medium_objects_) { |
|
dvander@53
|
115 |
FreedObject *obj = medium_objects_; |
|
dvander@53
|
116 |
medium_objects_ = medium_objects_->next(); |
|
dvander@53
|
117 |
return obj; |
|
dvander@53
|
118 |
} |
|
dvander@53
|
119 |
if (size < kMaxMediumObject && large_objects_) { |
|
dvander@53
|
120 |
FreedObject *obj = large_objects_; |
|
dvander@53
|
121 |
large_objects_ = large_objects_->next(); |
|
dvander@53
|
122 |
return obj; |
|
dvander@53
|
123 |
} |
|
dvander@53
|
124 |
if (huge_objects_) { |
|
dvander@53
|
125 |
FreedObject *obj = huge_objects_; |
|
dvander@53
|
126 |
huge_objects_ = huge_objects_->next(); |
|
dvander@53
|
127 |
return obj; |
|
dvander@53
|
128 |
} |
|
dvander@53
|
129 |
return NULL; |
|
dvander@53
|
130 |
} |
|
dvander@53
|
131 |
|
|
dvander@53
|
132 |
void |
|
dvander@53
|
133 |
FreeList::reset() |
|
dvander@53
|
134 |
{ |
|
dvander@53
|
135 |
small_objects_ = NULL; |
|
dvander@53
|
136 |
medium_objects_ = NULL; |
|
dvander@53
|
137 |
large_objects_ = NULL; |
|
dvander@53
|
138 |
huge_objects_ = NULL; |
|
dvander@53
|
139 |
} |
|
dvander@53
|
140 |
|
|
dvander@53
|
141 |
OldSpace::OldSpace(Zone *zone) |
|
dvander@53
|
142 |
: zone_(zone), |
|
dvander@53
|
143 |
first_(NULL), |
|
dvander@11
|
144 |
last_(NULL) |
|
dvander@11
|
145 |
{ |
|
dvander@11
|
146 |
} |
|
dvander@11
|
147 |
|
|
dvander@11
|
148 |
bool |
|
dvander@11
|
149 |
OldSpace::initialize() |
|
dvander@11
|
150 |
{ |
|
dvander@11
|
151 |
first_ = HeapChunk::New(first_, HeapChunk::kDefaultSize); |
|
dvander@11
|
152 |
last_ = first_; |
|
dvander@51
|
153 |
cursor_ = first_->first(); |
|
dvander@11
|
154 |
|
|
dvander@11
|
155 |
return !!first_; |
|
dvander@11
|
156 |
} |
|
dvander@11
|
157 |
|
|
dvander@53
|
158 |
OldSpace::~OldSpace() |
|
dvander@53
|
159 |
{ |
|
dvander@53
|
160 |
while (first_) { |
|
dvander@53
|
161 |
HeapChunk *temp = first_->next(); |
|
dvander@53
|
162 |
HeapChunk::Destroy(first_); |
|
dvander@53
|
163 |
first_ = temp; |
|
dvander@53
|
164 |
} |
|
dvander@53
|
165 |
} |
|
dvander@53
|
166 |
|
|
dvander@11
|
167 |
Address |
|
dvander@11
|
168 |
OldSpace::allocateSlow(size_t nbytes) |
|
dvander@11
|
169 |
{ |
|
dvander@53
|
170 |
if (FreedObject *obj = freelist_.pick(nbytes)) { |
|
dvander@53
|
171 |
Address address = reinterpret_cast<Address>(obj); |
|
dvander@53
|
172 |
size_t actual = obj->size(); |
|
dvander@53
|
173 |
assert(actual >= nbytes); |
|
dvander@53
|
174 |
if (actual != nbytes) |
|
dvander@53
|
175 |
markRegionFree(address + nbytes, actual - nbytes); |
|
dvander@53
|
176 |
|
|
dvander@53
|
177 |
return address; |
|
dvander@53
|
178 |
} |
|
dvander@53
|
179 |
|
|
dvander@53
|
180 |
// Free unused stuff at the end of the current chunk. |
|
dvander@53
|
181 |
if (cursor_ != last_->end()) |
|
dvander@53
|
182 |
markRegionFree(cursor_, last_->end() - cursor_); |
|
dvander@53
|
183 |
|
|
dvander@53
|
184 |
HeapChunk *chunk; |
|
dvander@53
|
185 |
if (last_->next()) { |
|
dvander@53
|
186 |
// The next chunk is guaranteed to be empty. |
|
dvander@53
|
187 |
chunk = last_->next(); |
|
dvander@53
|
188 |
} else { |
|
dvander@53
|
189 |
chunk = HeapChunk::New(last_, HeapChunk::kDefaultSize); |
|
dvander@53
|
190 |
if (!chunk) |
|
dvander@53
|
191 |
return NULL; |
|
dvander@53
|
192 |
} |
|
dvander@11
|
193 |
|
|
dvander@51
|
194 |
last_ = chunk; |
|
dvander@51
|
195 |
cursor_ = chunk->first(); |
|
dvander@51
|
196 |
|
|
dvander@51
|
197 |
assert(cursor_ + nbytes <= chunk->end()); |
|
dvander@51
|
198 |
|
|
dvander@51
|
199 |
Address address = cursor_; |
|
dvander@51
|
200 |
cursor_ += nbytes; |
|
dvander@51
|
201 |
return address; |
|
dvander@11
|
202 |
} |
|
dvander@11
|
203 |
|
|
dvander@53
|
204 |
void |
|
dvander@53
|
205 |
OldSpace::markRegionFree(Address start, size_t length) |
|
dvander@53
|
206 |
{ |
|
dvander@53
|
207 |
FreedObject *obj = reinterpret_cast<FreedObject *>(start); |
|
dvander@53
|
208 |
new (obj) FreedObject(zone_->getMap(MapKind_FreeRegion), length); |
|
dvander@53
|
209 |
|
|
dvander@53
|
210 |
if (length < sizeof(FreedObject)) { |
|
dvander@53
|
211 |
// Can't encode a list in this object, but it's marked free, so we're done. |
|
dvander@53
|
212 |
return; |
|
dvander@53
|
213 |
} |
|
dvander@53
|
214 |
|
|
dvander@53
|
215 |
freelist_.add(obj); |
|
dvander@53
|
216 |
} |
|
dvander@53
|
217 |
|
|
dvander@53
|
218 |
void |
|
dvander@53
|
219 |
OldSpace::freeUnusedPages() |
|
dvander@11
|
220 |
{ |
|
dvander@53
|
221 |
HeapChunk **prev = &first_; |
|
dvander@53
|
222 |
HeapChunk *empty = NULL; |
|
dvander@53
|
223 |
while (*prev) { |
|
dvander@53
|
224 |
HeapChunk *chunk = *prev; |
|
dvander@53
|
225 |
if (chunk->isEmpty()) { |
|
dvander@53
|
226 |
*prev = chunk->next(); |
|
dvander@53
|
227 |
if (empty) { |
|
dvander@53
|
228 |
// Remove this chunk. |
|
dvander@53
|
229 |
HeapChunk::Destroy(chunk); |
|
dvander@53
|
230 |
continue; |
|
dvander@53
|
231 |
} |
|
dvander@53
|
232 |
empty = chunk; |
|
dvander@53
|
233 |
} |
|
dvander@53
|
234 |
prev = chunk->nextp(); |
|
dvander@11
|
235 |
} |
|
dvander@53
|
236 |
|
|
dvander@53
|
237 |
if (empty) { |
|
dvander@53
|
238 |
*empty->nextp() = NULL; |
|
dvander@53
|
239 |
*last_->nextp() = empty; |
|
dvander@53
|
240 |
} |
|
dvander@53
|
241 |
} |
|
dvander@53
|
242 |
|
|
dvander@53
|
243 |
void |
|
dvander@53
|
244 |
OldSpace::resetFreeList() |
|
dvander@53
|
245 |
{ |
|
dvander@53
|
246 |
freelist_.reset(); |
|
dvander@11
|
247 |
} |
|
dvander@49
|
248 |
|
|
dvander@50
|
249 |
LargeObjectSpace::LargeObjectSpace() |
|
dvander@50
|
250 |
: first_(NULL), |
|
dvander@50
|
251 |
last_(NULL) |
|
dvander@50
|
252 |
{ |
|
dvander@50
|
253 |
} |
|
dvander@50
|
254 |
|
|
dvander@50
|
255 |
LargeObjectSpace::~LargeObjectSpace() |
|
dvander@50
|
256 |
{ |
|
dvander@50
|
257 |
while (first_) { |
|
dvander@50
|
258 |
HeapChunk *temp = first_->next(); |
|
dvander@50
|
259 |
HeapChunk::Destroy(first_); |
|
dvander@50
|
260 |
first_ = temp; |
|
dvander@50
|
261 |
} |
|
dvander@50
|
262 |
} |
|
dvander@50
|
263 |
|
|
dvander@50
|
264 |
bool |
|
dvander@50
|
265 |
LargeObjectSpace::initialize() |
|
dvander@50
|
266 |
{ |
|
dvander@50
|
267 |
return true; |
|
dvander@50
|
268 |
} |
|
dvander@49
|
269 |
|
|
dvander@49
|
270 |
Address |
|
dvander@49
|
271 |
LargeObjectSpace::allocate(size_t nbytes) |
|
dvander@49
|
272 |
{ |
|
dvander@49
|
273 |
assert(IsAligned(nbytes, kObjectAlignment)); |
|
dvander@49
|
274 |
|
|
dvander@50
|
275 |
// Always allocate a new chunk for large objects. |
|
dvander@50
|
276 |
HeapChunk *chunk = HeapChunk::New(last_, nbytes); |
|
dvander@50
|
277 |
if (!chunk) |
|
dvander@50
|
278 |
return NULL; |
|
dvander@49
|
279 |
|
|
dvander@50
|
280 |
if (!first_) |
|
dvander@50
|
281 |
first_ = chunk; |
|
dvander@50
|
282 |
last_ = chunk; |
|
dvander@49
|
283 |
|
|
dvander@51
|
284 |
return chunk->first(); |
|
dvander@49
|
285 |
} |
|
dvander@49
|
286 |
|
|
dvander@53
|
287 |
void |
|
dvander@53
|
288 |
LargeObjectSpace::sweep() |
|
dvander@53
|
289 |
{ |
|
dvander@53
|
290 |
if (!first_) |
|
dvander@53
|
291 |
return; |
|
dvander@53
|
292 |
|
|
dvander@53
|
293 |
HeapChunk **pprev = &first_; |
|
dvander@53
|
294 |
do { |
|
dvander@53
|
295 |
HeapChunk *chunk = *pprev; |
|
dvander@53
|
296 |
Object *obj = reinterpret_cast<Object *>(chunk->first()); |
|
dvander@53
|
297 |
MarkBit bit = HeapChunk::GetMarkBit(obj); |
|
dvander@53
|
298 |
if (HeapChunk::IsWhite(bit)) { |
|
dvander@53
|
299 |
*pprev = chunk->next(); |
|
dvander@53
|
300 |
HeapChunk::Destroy(chunk); |
|
dvander@53
|
301 |
} else { |
|
dvander@53
|
302 |
assert(HeapChunk::IsBlack(bit)); |
|
dvander@53
|
303 |
HeapChunk::Clear(bit); |
|
dvander@53
|
304 |
pprev = chunk->nextp(); |
|
dvander@53
|
305 |
last_ = chunk; |
|
dvander@53
|
306 |
} |
|
dvander@53
|
307 |
} while (*pprev); |
|
dvander@53
|
308 |
} |