/src/mozilla-central/js/src/gc/ArenaList-inl.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
2 | | * vim: set ts=8 sts=4 et sw=4 tw=99: |
3 | | * This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef gc_ArenaList_inl_h |
8 | | #define gc_ArenaList_inl_h |
9 | | |
10 | | #include "gc/ArenaList.h" |
11 | | |
12 | | #include "gc/Heap.h" |
13 | | |
14 | | void |
15 | | js::gc::SortedArenaListSegment::append(Arena* arena) |
16 | 198k | { |
17 | 198k | MOZ_ASSERT(arena); |
18 | 198k | MOZ_ASSERT_IF(head, head->getAllocKind() == arena->getAllocKind()); |
19 | 198k | *tailp = arena; |
20 | 198k | tailp = &arena->next; |
21 | 198k | } |
22 | | |
23 | | inline |
24 | | js::gc::ArenaList::ArenaList() |
25 | 270 | { |
26 | 270 | clear(); |
27 | 270 | } |
28 | | |
29 | | void |
30 | | js::gc::ArenaList::copy(const ArenaList& other) |
31 | 359 | { |
32 | 359 | other.check(); |
33 | 359 | head_ = other.head_; |
34 | 359 | cursorp_ = other.isCursorAtHead() ? &head_ : other.cursorp_; |
35 | 359 | check(); |
36 | 359 | } |
37 | | |
38 | | inline |
39 | | js::gc::ArenaList::ArenaList(const ArenaList& other) |
40 | | { |
41 | | copy(other); |
42 | | } |
43 | | |
44 | | js::gc::ArenaList& |
45 | | js::gc::ArenaList::operator=(const ArenaList& other) |
46 | 359 | { |
47 | 359 | copy(other); |
48 | 359 | return *this; |
49 | 359 | } |
50 | | |
51 | | inline |
52 | | js::gc::ArenaList::ArenaList(const SortedArenaListSegment& segment) |
53 | 359 | { |
54 | 359 | head_ = segment.head; |
55 | 359 | cursorp_ = segment.isEmpty() ? &head_ : segment.tailp; |
56 | 359 | check(); |
57 | 359 | } |
58 | | |
59 | | // This does checking just of |head_| and |cursorp_|. |
60 | | void |
61 | | js::gc::ArenaList::check() const |
62 | 597k | { |
63 | | #ifdef DEBUG |
64 | | // If the list is empty, it must have this form. |
65 | | MOZ_ASSERT_IF(!head_, cursorp_ == &head_); |
66 | | |
67 | | // If there's an arena following the cursor, it must not be full. |
68 | | Arena* cursor = *cursorp_; |
69 | | MOZ_ASSERT_IF(cursor, cursor->hasFreeThings()); |
70 | | #endif |
71 | | } |
72 | | |
73 | | void |
74 | | js::gc::ArenaList::clear() |
75 | 773 | { |
76 | 773 | head_ = nullptr; |
77 | 773 | cursorp_ = &head_; |
78 | 773 | check(); |
79 | 773 | } |
80 | | |
81 | | js::gc::ArenaList |
82 | | js::gc::ArenaList::copyAndClear() |
83 | 0 | { |
84 | 0 | ArenaList result = *this; |
85 | 0 | clear(); |
86 | 0 | return result; |
87 | 0 | } |
88 | | |
89 | | bool |
90 | | js::gc::ArenaList::isEmpty() const |
91 | 468 | { |
92 | 468 | check(); |
93 | 468 | return !head_; |
94 | 468 | } |
95 | | |
96 | | js::gc::Arena* |
97 | | js::gc::ArenaList::head() const |
98 | 943 | { |
99 | 943 | check(); |
100 | 943 | return head_; |
101 | 943 | } |
102 | | |
103 | | bool |
104 | | js::gc::ArenaList::isCursorAtHead() const |
105 | 718 | { |
106 | 718 | check(); |
107 | 718 | return cursorp_ == &head_; |
108 | 718 | } |
109 | | |
110 | | bool |
111 | | js::gc::ArenaList::isCursorAtEnd() const |
112 | 0 | { |
113 | 0 | check(); |
114 | 0 | return !*cursorp_; |
115 | 0 | } |
116 | | |
117 | | void |
118 | | js::gc::ArenaList::moveCursorToEnd() |
119 | 0 | { |
120 | 0 | while (!isCursorAtEnd()) { |
121 | 0 | cursorp_ = &(*cursorp_)->next; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | | js::gc::Arena* |
126 | | js::gc::ArenaList::arenaAfterCursor() const |
127 | 0 | { |
128 | 0 | check(); |
129 | 0 | return *cursorp_; |
130 | 0 | } |
131 | | |
132 | | js::gc::Arena* |
133 | | js::gc::ArenaList::takeNextArena() |
134 | 197k | { |
135 | 197k | check(); |
136 | 197k | Arena* arena = *cursorp_; |
137 | 197k | if (!arena) { |
138 | 197k | return nullptr; |
139 | 197k | } |
140 | 648 | cursorp_ = &arena->next; |
141 | 648 | check(); |
142 | 648 | return arena; |
143 | 648 | } |
144 | | |
145 | | void |
146 | | js::gc::ArenaList::insertAtCursor(Arena* a) |
147 | 0 | { |
148 | 0 | check(); |
149 | 0 | a->next = *cursorp_; |
150 | 0 | *cursorp_ = a; |
151 | 0 | // At this point, the cursor is sitting before |a|. Move it after |a| |
152 | 0 | // if necessary. |
153 | 0 | if (!a->hasFreeThings()) { |
154 | 0 | cursorp_ = &a->next; |
155 | 0 | } |
156 | 0 | check(); |
157 | 0 | } |
158 | | |
159 | | void |
160 | | js::gc::ArenaList::insertBeforeCursor(Arena* a) |
161 | 197k | { |
162 | 197k | check(); |
163 | 197k | a->next = *cursorp_; |
164 | 197k | *cursorp_ = a; |
165 | 197k | cursorp_ = &a->next; |
166 | 197k | check(); |
167 | 197k | } |
168 | | |
169 | | js::gc::ArenaList& |
170 | | js::gc::ArenaList::insertListWithCursorAtEnd(const ArenaList& other) |
171 | 359 | { |
172 | 359 | check(); |
173 | 359 | other.check(); |
174 | 359 | MOZ_ASSERT(other.isCursorAtEnd()); |
175 | 359 | if (other.isCursorAtHead()) { |
176 | 260 | return *this; |
177 | 260 | } |
178 | 99 | // Insert the full arenas of |other| after those of |this|. |
179 | 99 | *other.cursorp_ = *cursorp_; |
180 | 99 | *cursorp_ = other.head_; |
181 | 99 | cursorp_ = other.cursorp_; |
182 | 99 | check(); |
183 | 99 | return *this; |
184 | 99 | } |
185 | | |
186 | | js::gc::SortedArenaList::SortedArenaList(size_t thingsPerArena) |
187 | 272 | { |
188 | 272 | reset(thingsPerArena); |
189 | 272 | } |
190 | | |
191 | | void |
192 | | js::gc::SortedArenaList::setThingsPerArena(size_t thingsPerArena) |
193 | 560 | { |
194 | 560 | MOZ_ASSERT(thingsPerArena && thingsPerArena <= MaxThingsPerArena); |
195 | 560 | thingsPerArena_ = thingsPerArena; |
196 | 560 | } |
197 | | |
198 | | void |
199 | | js::gc::SortedArenaList::reset(size_t thingsPerArena) |
200 | 416 | { |
201 | 416 | setThingsPerArena(thingsPerArena); |
202 | 416 | // Initialize the segments. |
203 | 36.1k | for (size_t i = 0; i <= thingsPerArena; ++i) { |
204 | 35.7k | segments[i].clear(); |
205 | 35.7k | } |
206 | 416 | } |
207 | | |
208 | | void |
209 | | js::gc::SortedArenaList::insertAt(Arena* arena, size_t nfree) |
210 | 198k | { |
211 | 198k | MOZ_ASSERT(nfree <= thingsPerArena_); |
212 | 198k | segments[nfree].append(arena); |
213 | 198k | } |
214 | | |
215 | | void |
216 | | js::gc::SortedArenaList::extractEmpty(Arena** empty) |
217 | 323 | { |
218 | 323 | SortedArenaListSegment& segment = segments[thingsPerArena_]; |
219 | 323 | if (segment.head) { |
220 | 107 | *segment.tailp = *empty; |
221 | 107 | *empty = segment.head; |
222 | 107 | segment.clear(); |
223 | 107 | } |
224 | 323 | } |
225 | | |
226 | | js::gc::ArenaList |
227 | | js::gc::SortedArenaList::toArenaList() |
228 | 359 | { |
229 | 359 | // Link the non-empty segment tails up to the non-empty segment heads. |
230 | 359 | size_t tailIndex = 0; |
231 | 31.3k | for (size_t headIndex = 1; headIndex <= thingsPerArena_; ++headIndex) { |
232 | 30.9k | if (headAt(headIndex)) { |
233 | 789 | segments[tailIndex].linkTo(headAt(headIndex)); |
234 | 789 | tailIndex = headIndex; |
235 | 789 | } |
236 | 30.9k | } |
237 | 359 | // Point the tail of the final non-empty segment at null. Note that if |
238 | 359 | // the list is empty, this will just set segments[0].head to null. |
239 | 359 | segments[tailIndex].linkTo(nullptr); |
240 | 359 | // Create an ArenaList with head and cursor set to the head and tail of |
241 | 359 | // the first segment (if that segment is empty, only the head is used). |
242 | 359 | return ArenaList(segments[0]); |
243 | 359 | } |
244 | | |
245 | | #ifdef DEBUG |
246 | | |
247 | | bool |
248 | | js::gc::FreeLists::allEmpty() const |
249 | | { |
250 | | for (auto i : AllAllocKinds()) { |
251 | | if (!isEmpty(i)) { |
252 | | return false; |
253 | | } |
254 | | } |
255 | | return true; |
256 | | } |
257 | | |
258 | | bool |
259 | | js::gc::FreeLists::isEmpty(AllocKind kind) const |
260 | | { |
261 | | return freeLists_[kind]->isEmpty(); |
262 | | } |
263 | | |
264 | | #endif |
265 | | |
266 | | void |
267 | | js::gc::FreeLists::clear() |
268 | 36 | { |
269 | 1.04k | for (auto i : AllAllocKinds()) { |
270 | | #ifdef DEBUG |
271 | | auto old = freeLists_[i]; |
272 | | if (!old->isEmpty()) { |
273 | | old->getArena()->checkNoMarkedFreeCells(); |
274 | | } |
275 | | #endif |
276 | | freeLists_[i] = &emptySentinel; |
277 | 1.04k | } |
278 | 36 | } |
279 | | |
280 | | js::gc::TenuredCell* |
281 | | js::gc::FreeLists::allocate(AllocKind kind) |
282 | 16.2M | { |
283 | 16.2M | return freeLists_[kind]->allocate(Arena::thingSize(kind)); |
284 | 16.2M | } |
285 | | |
286 | | void |
287 | | js::gc::FreeLists::unmarkPreMarkedFreeCells(AllocKind kind) |
288 | 1.04k | { |
289 | 1.04k | FreeSpan* freeSpan = freeLists_[kind]; |
290 | 1.04k | if (!freeSpan->isEmpty()) { |
291 | 171 | freeSpan->getArena()->unmarkPreMarkedFreeCells(); |
292 | 171 | } |
293 | 1.04k | } |
294 | | |
295 | | JSRuntime* |
296 | | js::gc::ArenaLists::runtime() |
297 | 36 | { |
298 | 36 | return zone_->runtimeFromMainThread(); |
299 | 36 | } |
300 | | |
301 | | JSRuntime* |
302 | | js::gc::ArenaLists::runtimeFromAnyThread() |
303 | 197k | { |
304 | 197k | return zone_->runtimeFromAnyThread(); |
305 | 197k | } |
306 | | |
307 | | js::gc::Arena* |
308 | | js::gc::ArenaLists::getFirstArena(AllocKind thingKind) const |
309 | 8 | { |
310 | 8 | return arenaLists(thingKind).head(); |
311 | 8 | } |
312 | | |
313 | | js::gc::Arena* |
314 | | js::gc::ArenaLists::getFirstArenaToSweep(AllocKind thingKind) const |
315 | 8 | { |
316 | 8 | return arenaListsToSweep(thingKind); |
317 | 8 | } |
318 | | |
319 | | js::gc::Arena* |
320 | | js::gc::ArenaLists::getFirstSweptArena(AllocKind thingKind) const |
321 | 8 | { |
322 | 8 | if (thingKind != incrementalSweptArenaKind.ref()) { |
323 | 8 | return nullptr; |
324 | 8 | } |
325 | 0 | return incrementalSweptArenas.ref().head(); |
326 | 0 | } |
327 | | |
328 | | js::gc::Arena* |
329 | | js::gc::ArenaLists::getArenaAfterCursor(AllocKind thingKind) const |
330 | 0 | { |
331 | 0 | return arenaLists(thingKind).arenaAfterCursor(); |
332 | 0 | } |
333 | | |
334 | | bool |
335 | | js::gc::ArenaLists::arenaListsAreEmpty() const |
336 | 36 | { |
337 | 36 | for (auto i : AllAllocKinds()) { |
338 | 36 | /* |
339 | 36 | * The arena cannot be empty if the background finalization is not yet |
340 | 36 | * done. |
341 | 36 | */ |
342 | 36 | if (concurrentUse(i) == ConcurrentUse::BackgroundFinalize) { |
343 | 0 | return false; |
344 | 0 | } |
345 | 36 | if (!arenaLists(i).isEmpty()) { |
346 | 36 | return false; |
347 | 36 | } |
348 | 36 | } |
349 | 36 | return true; |
350 | 36 | } |
351 | | |
352 | | void |
353 | | js::gc::ArenaLists::unmarkAll() |
354 | 18 | { |
355 | 522 | for (auto i : AllAllocKinds()) { |
356 | 522 | /* The background finalization must have stopped at this point. */ |
357 | 522 | MOZ_ASSERT(concurrentUse(i) == ConcurrentUse::None); |
358 | 189k | for (Arena* arena = arenaLists(i).head(); arena; arena = arena->next) { |
359 | 189k | arena->unmarkAll(); |
360 | 189k | } |
361 | 522 | } |
362 | 18 | } |
363 | | |
364 | | bool |
365 | | js::gc::ArenaLists::doneBackgroundFinalize(AllocKind kind) const |
366 | 0 | { |
367 | 0 | return concurrentUse(kind) != ConcurrentUse::BackgroundFinalize; |
368 | 0 | } |
369 | | |
370 | | bool |
371 | | js::gc::ArenaLists::needBackgroundFinalizeWait(AllocKind kind) const |
372 | 0 | { |
373 | 0 | return concurrentUse(kind) == ConcurrentUse::BackgroundFinalize; |
374 | 0 | } |
375 | | |
376 | | void |
377 | | js::gc::ArenaLists::clearFreeLists() |
378 | 36 | { |
379 | 36 | freeLists().clear(); |
380 | 36 | } |
381 | | |
382 | | MOZ_ALWAYS_INLINE js::gc::TenuredCell* |
383 | | js::gc::ArenaLists::allocateFromFreeList(AllocKind thingKind) |
384 | 345 | { |
385 | 345 | return freeLists().allocate(thingKind); |
386 | 345 | } |
387 | | |
388 | | void |
389 | | js::gc::ArenaLists::unmarkPreMarkedFreeCells() |
390 | 36 | { |
391 | 1.04k | for (auto i : AllAllocKinds()) { |
392 | 1.04k | freeLists().unmarkPreMarkedFreeCells(i); |
393 | 1.04k | } |
394 | 36 | } |
395 | | |
396 | | void |
397 | | js::gc::ArenaLists::checkEmptyFreeLists() |
398 | 0 | { |
399 | 0 | MOZ_ASSERT(freeLists().allEmpty()); |
400 | 0 | } |
401 | | |
402 | | bool |
403 | | js::gc::ArenaLists::checkEmptyArenaLists() |
404 | 0 | { |
405 | 0 | bool empty = true; |
406 | 0 | #ifdef DEBUG |
407 | 0 | for (auto i : AllAllocKinds()) { |
408 | 0 | if (!checkEmptyArenaList(i)) { |
409 | 0 | empty = false; |
410 | 0 | } |
411 | 0 | } |
412 | 0 | #endif |
413 | 0 | return empty; |
414 | 0 | } |
415 | | |
416 | | #endif // gc_ArenaList_inl_h |