Coverage Report

Created: 2018-09-25 14:53

/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