Coverage Report

Created: 2018-07-03 15:31

/home/travis/build/MoarVM/MoarVM/src/gc/roots.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Adds a location holding a collectable object to the permanent list of GC
4
 * roots, so that it will always be marked and never die. Note that the
5
 * address of the collectable must be passed, since it will need to be
6
 * updated. */
7
35.2k
void MVM_gc_root_add_permanent_desc(MVMThreadContext *tc, MVMCollectable **obj_ref, char *description) {
8
35.2k
    if (obj_ref == NULL)
9
0
        MVM_panic(MVM_exitcode_gcroots, "Illegal attempt to add null object address as a permanent root");
10
35.2k
11
35.2k
    uv_mutex_lock(&tc->instance->mutex_permroots);
12
35.2k
    /* Allocate extra permanent root space if needed. */
13
35.2k
    if (tc->instance->num_permroots == tc->instance->alloc_permroots) {
14
583
        tc->instance->alloc_permroots *= 2;
15
583
        tc->instance->permroots = MVM_realloc(tc->instance->permroots,
16
583
            sizeof(MVMCollectable **) * tc->instance->alloc_permroots);
17
583
        tc->instance->permroot_descriptions = MVM_realloc(
18
583
            tc->instance->permroot_descriptions,
19
583
            sizeof(char *) * tc->instance->alloc_permroots);
20
583
    }
21
35.2k
22
35.2k
    /* Add this one to the list. */
23
35.2k
    tc->instance->permroots[tc->instance->num_permroots] = obj_ref;
24
35.2k
    tc->instance->permroot_descriptions[tc->instance->num_permroots] = description;
25
35.2k
    tc->instance->num_permroots++;
26
35.2k
27
35.2k
    uv_mutex_unlock(&tc->instance->mutex_permroots);
28
35.2k
}
29
30
0
void MVM_gc_root_add_permanent(MVMThreadContext *tc, MVMCollectable **obj_ref) {
31
0
    MVM_gc_root_add_permanent_desc(tc, obj_ref, "<\?\?>");
32
0
}
33
34
/* Adds the set of permanently registered roots to a GC worklist. */
35
338
void MVM_gc_root_add_permanents_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMHeapSnapshotState *snapshot) {
36
338
    MVMuint32         i, num_roots;
37
338
    MVMCollectable ***permroots;
38
338
    num_roots = tc->instance->num_permroots;
39
338
    permroots = tc->instance->permroots;
40
338
    if (worklist) {
41
82.6k
        for (i = 0; i < num_roots; i++)
42
82.2k
            MVM_gc_worklist_add(tc, worklist, permroots[i]);
43
338
    }
44
0
    else {
45
0
        char **permroot_descriptions = tc->instance->permroot_descriptions;
46
0
        for (i = 0; i < num_roots; i++)
47
0
            MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot,
48
0
                *(permroots[i]), permroot_descriptions[i]);
49
0
    }
50
338
}
51
52
/* This macro factors out the logic to check if we're adding to a GC worklist
53
 * or a heap snapshot, and does the appropriate thing. */
54
#define add_collectable(tc, worklist, snapshot, col, desc) \
55
56.4k
    do { \
56
56.4k
        if (worklist) { \
57
56.4k
            MVM_gc_worklist_add(tc, worklist, &(col)); \
58
56.4k
        } \
59
12
        else { \
60
12
            MVM_profile_heap_add_collectable_rel_const_cstr(tc, snapshot, \
61
12
                (MVMCollectable *)col, desc); \
62
12
        } \
63
56.4k
    } while (0)
64
65
/* Adds anything that is a root thanks to being referenced by instance,
66
 * but that isn't permanent. */
67
338
void MVM_gc_root_add_instance_roots_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMHeapSnapshotState *snapshot) {
68
338
    MVMSerializationContextBody *current, *tmp;
69
338
    MVMLoadedCompUnitName       *current_lcun, *tmp_lcun;
70
338
    unsigned                     bucket_tmp;
71
338
    MVMString                  **int_to_str_cache;
72
338
    MVMuint32                    i;
73
338
74
338
    add_collectable(tc, worklist, snapshot, tc->instance->threads, "Thread list");
75
338
    add_collectable(tc, worklist, snapshot, tc->instance->compiler_registry, "Compiler registry");
76
338
    add_collectable(tc, worklist, snapshot, tc->instance->hll_syms, "HLL symbols");
77
338
    add_collectable(tc, worklist, snapshot, tc->instance->clargs, "Command line args");
78
338
    add_collectable(tc, worklist, snapshot, tc->instance->event_loop_todo_queue,
79
338
        "Event loop todo queue");
80
338
    add_collectable(tc, worklist, snapshot, tc->instance->event_loop_permit_queue,
81
338
        "Event loop permit queue");
82
338
    add_collectable(tc, worklist, snapshot, tc->instance->event_loop_cancel_queue,
83
338
        "Event loop cancel queue");
84
338
    add_collectable(tc, worklist, snapshot, tc->instance->event_loop_active, "Event loop active");
85
338
86
338
    add_collectable(tc, worklist, snapshot, tc->instance->spesh_queue,
87
338
        "Specialization log queue");
88
338
    if (worklist)
89
338
        MVM_spesh_plan_gc_mark(tc, tc->instance->spesh_plan, worklist);
90
338
91
338
    int_to_str_cache = tc->instance->int_to_str_cache;
92
21.9k
    for (i = 0; i < MVM_INT_TO_STR_CACHE_SIZE; i++)
93
21.6k
        add_collectable(tc, worklist, snapshot, int_to_str_cache[i],
94
338
            "Integer to string cache entry");
95
338
96
338
    /* okay, so this makes the weak hash slightly less weak.. for certain
97
338
     * keys of it anyway... */
98
15.4k
    HASH_ITER(hash_handle, tc->instance->sc_weakhash, current, tmp, bucket_tmp) {
99
15.4k
        /* mark the string handle pointer iff it hasn't yet been resolved */
100
15.4k
        add_collectable(tc, worklist, snapshot, current->hash_handle.key,
101
15.4k
            "SC weakhash hash key");
102
15.4k
        if (!current->sc)
103
0
            add_collectable(tc, worklist, snapshot, current->handle,
104
15.4k
                "SC weakhash unresolved handle");
105
15.4k
        else if (!current->claimed)
106
1.06k
            add_collectable(tc, worklist, snapshot, current->sc,
107
15.4k
                "SC weakhash unclaimed SC");
108
15.4k
    }
109
338
110
3.38k
    HASH_ITER(hash_handle, tc->instance->loaded_compunits, current_lcun, tmp_lcun, bucket_tmp) {
111
3.38k
        add_collectable(tc, worklist, snapshot, current_lcun->hash_handle.key,
112
3.38k
            "Loaded compilation unit hash key");
113
3.38k
        add_collectable(tc, worklist, snapshot, current_lcun->filename,
114
3.38k
            "Loaded compilation unit filename");
115
3.38k
    }
116
338
117
338
    add_collectable(tc, worklist, snapshot, tc->instance->cached_backend_config,
118
338
        "Cached backend configuration hash");
119
338
120
338
    add_collectable(tc, worklist, snapshot, tc->instance->env_hash,
121
338
        "Cached environment variable hash");
122
338
123
338
    add_collectable(tc, worklist, snapshot, tc->instance->sig_arr,
124
338
        "Cached signal mapping array");
125
338
126
338
    MVM_debugserver_mark_handles(tc, worklist, snapshot);
127
338
}
128
129
/* Adds anything that is a root thanks to being referenced by a thread,
130
 * context, but that isn't permanent. */
131
759
void MVM_gc_root_add_tc_roots_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMHeapSnapshotState *snapshot) {
132
759
    MVMNativeCallbackCacheHead *current_cbceh, *tmp_cbceh;
133
759
    unsigned bucket_tmp;
134
759
135
759
    /* Any active exception handlers and payload. */
136
759
    MVMActiveHandler *cur_ah = tc->active_handlers;
137
759
    while (cur_ah != NULL) {
138
0
        add_collectable(tc, worklist, snapshot, cur_ah->ex_obj, "Active handler exception object");
139
0
        if (!MVM_FRAME_IS_ON_CALLSTACK(tc, cur_ah->frame))
140
0
            add_collectable(tc, worklist, snapshot, cur_ah->frame, "Active handler frame");
141
0
        cur_ah = cur_ah->next_handler;
142
0
    }
143
759
    add_collectable(tc, worklist, snapshot, tc->last_payload,
144
759
        "Last exception payload");
145
759
146
759
    /* The thread object. */
147
759
    add_collectable(tc, worklist, snapshot, tc->thread_obj, "Thread object");
148
759
149
759
    /* The thread's entry frame. */
150
759
    if (tc->thread_entry_frame && !MVM_FRAME_IS_ON_CALLSTACK(tc, tc->thread_entry_frame))
151
0
        add_collectable(tc, worklist, snapshot, tc->thread_entry_frame, "Thread entry frame");
152
759
153
759
    /* Any exception handler result. */
154
759
    add_collectable(tc, worklist, snapshot, tc->last_handler_result, "Last handler result");
155
759
156
759
    /* List of SCs currently being compiled. */
157
759
    add_collectable(tc, worklist, snapshot, tc->compiling_scs, "Compiling serialization contexts");
158
759
159
759
    /* compunit variable pointer (and be null if thread finished) */
160
759
    if (tc->interp_cu)
161
701
        add_collectable(tc, worklist, snapshot, *(tc->interp_cu), "Current interpreter compilation unit");
162
759
    /* Current dispatcher. */
163
759
    add_collectable(tc, worklist, snapshot, tc->cur_dispatcher, "Current dispatcher");
164
759
    add_collectable(tc, worklist, snapshot, tc->cur_dispatcher_for, "Current dispatcher for");
165
759
166
759
    /* Callback cache. */
167
759
    HASH_ITER(hash_handle, tc->native_callback_cache, current_cbceh, tmp_cbceh, bucket_tmp) {
168
0
        MVMint32 i;
169
0
        MVMNativeCallback *entry = current_cbceh->head;
170
0
        add_collectable(tc, worklist, snapshot, current_cbceh->hash_handle.key,
171
0
            "Native callback cache key");
172
0
        while (entry) {
173
0
            for (i = 0; i < entry->num_types; i++)
174
0
                add_collectable(tc, worklist, snapshot, entry->types[i],
175
0
                    "Native callback cache type");
176
0
            add_collectable(tc, worklist, snapshot, entry->target,
177
0
                "Native callback cache target");
178
0
            entry = entry->next;
179
0
        }
180
0
    }
181
759
182
759
    /* Profiling data. */
183
759
    if (worklist)
184
755
        MVM_profile_instrumented_mark_data(tc, worklist);
185
759
186
759
    /* Serialized string heap, if any. */
187
759
    add_collectable(tc, worklist, snapshot, tc->serialized_string_heap,
188
759
        "Serialized string heap");
189
759
190
759
    /* Specialization log, stack simulation, and plugin state. */
191
759
    add_collectable(tc, worklist, snapshot, tc->spesh_log, "Specialization log");
192
759
    if (worklist)
193
755
        MVM_spesh_sim_stack_gc_mark(tc, tc->spesh_sim_stack, worklist);
194
4
    else {
195
4
        MVM_spesh_sim_stack_gc_describe(tc, snapshot, tc->spesh_sim_stack);
196
4
    }
197
759
    MVM_spesh_plugin_guard_list_mark(tc, tc->plugin_guards, tc->num_plugin_guards, worklist);
198
759
    add_collectable(tc, worklist, snapshot, tc->plugin_guard_args,
199
759
        "Plugin guard args");
200
759
201
759
    if (tc->step_mode_frame)
202
0
        add_collectable(tc, worklist, snapshot, tc->step_mode_frame,
203
759
                "Frame referenced for stepping mode");
204
759
}
205
206
/* Pushes a temporary root onto the thread-local roots list. */
207
0
void MVM_gc_root_temp_push_slow(MVMThreadContext *tc, MVMCollectable **obj_ref) {
208
0
    /* Allocate extra temporary root space if needed. */
209
0
    if (tc->num_temproots == tc->alloc_temproots) {
210
0
        tc->alloc_temproots *= 2;
211
0
        tc->temproots = MVM_realloc(tc->temproots,
212
0
            sizeof(MVMCollectable **) * tc->alloc_temproots);
213
0
    }
214
0
215
0
    /* Add this one to the list. */
216
0
    tc->temproots[tc->num_temproots] = obj_ref;
217
0
    tc->num_temproots++;
218
0
}
219
220
/* Marks the temporary root stack at its current height as the limit for
221
 * removing all roots. This is done so that in nested interpreter runs
222
 * (at present, just nativecall callbacks) we don't clear things that
223
 * are pushed by the native call itself. */
224
0
MVMuint32 MVM_gc_root_temp_mark(MVMThreadContext *tc) {
225
0
    MVMint32 current = tc->mark_temproots;
226
0
    tc->mark_temproots = tc->num_temproots;
227
0
    return current;
228
0
}
229
230
/* Resets the temporary root stack mark to the provided height. */
231
0
void MVM_gc_root_temp_mark_reset(MVMThreadContext *tc, MVMuint32 mark) {
232
0
    tc->mark_temproots = mark;
233
0
}
234
235
/* Pops all temporary roots off the thread-local roots list. */
236
164
void MVM_gc_root_temp_pop_all(MVMThreadContext *tc) {
237
164
    tc->num_temproots = tc->mark_temproots;
238
164
}
239
240
/* Adds the set of thread-local temporary roots to a GC worklist. Note that we
241
 * may MVMROOT things that are actually frames on a therad local call stack as
242
 * they may be GC-able; check for this and make sure such roots do not get
243
 * added to the worklist. (Cheaper to do it here in the event we GC than to
244
 * do it on every stack push). */
245
1.82k
static MVMuint32 is_stack_frame(MVMThreadContext *tc, MVMCollectable **c) {
246
1.82k
    MVMCollectable *maybe_frame = *c;
247
1.78k
    return maybe_frame && maybe_frame->flags == 0 && maybe_frame->owner == 0;
248
1.82k
}
249
750
void MVM_gc_root_add_temps_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMHeapSnapshotState *snapshot) {
250
750
    MVMuint32         i, num_roots;
251
750
    MVMCollectable ***temproots;
252
750
    num_roots = tc->num_temproots;
253
750
    temproots = tc->temproots;
254
750
    if (worklist) {
255
2.57k
        for (i = 0; i < num_roots; i++)
256
1.82k
            if (!is_stack_frame(tc, temproots[i]))
257
1.82k
                MVM_gc_worklist_add(tc, worklist, temproots[i]);
258
750
    }
259
0
    else {
260
0
        for (i = 0; i < num_roots; i++)
261
0
            if (!is_stack_frame(tc, temproots[i]))
262
0
                MVM_profile_heap_add_collectable_rel_idx(tc, snapshot, *(temproots[i]), i);
263
0
    }
264
750
}
265
266
/* Pushes a collectable that is in generation 2, but now references a nursery
267
 * collectable, into the gen2 root set. */
268
955k
void MVM_gc_root_gen2_add(MVMThreadContext *tc, MVMCollectable *c) {
269
955k
    /* Ensure the collectable is not null. */
270
955k
    if (c == NULL)
271
0
        MVM_panic(MVM_exitcode_gcroots, "Illegal attempt to add null collectable address as an inter-generational root");
272
955k
    assert(!(c->flags & MVM_CF_FORWARDER_VALID));
273
955k
274
955k
    /* Allocate extra gen2 aggregate space if needed. */
275
955k
    if (tc->num_gen2roots == tc->alloc_gen2roots) {
276
955
        tc->alloc_gen2roots *= 2;
277
955
        tc->gen2roots = MVM_realloc(tc->gen2roots,
278
955
            sizeof(MVMCollectable *) * tc->alloc_gen2roots);
279
955
    }
280
955k
281
955k
    /* Add this one to the list. */
282
955k
    tc->gen2roots[tc->num_gen2roots] = c;
283
955k
    tc->num_gen2roots++;
284
955k
285
955k
    /* Flag it as added, so we don't add it multiple times. */
286
955k
    c->flags |= MVM_CF_IN_GEN2_ROOT_LIST;
287
955k
}
288
289
/* Adds the set of thread-local inter-generational roots to a GC worklist. As
290
 * a side-effect, removes gen2 roots that no longer point to any nursery
291
 * items (usually because all the referenced objects also got promoted). */
292
750
void MVM_gc_root_add_gen2s_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist) {
293
750
    MVMCollectable **gen2roots = tc->gen2roots;
294
750
    MVMuint32        num_roots = tc->num_gen2roots;
295
750
    MVMuint32        i;
296
750
297
750
    /* We'll remove some entries from this list. The algorithm is simply to
298
750
     * slide all that stay towards the start of the array. */
299
750
    MVMuint32 insert_pos = 0;
300
750
301
750
    /* Guess that we'll end up with around num_roots entries, to avoid some
302
750
     * worklist growth reallocations. */
303
750
    MVM_gc_worklist_presize_for(tc, worklist, num_roots);
304
750
305
750
    /* Visit each gen2 root and... */
306
819k
    for (i = 0; i < num_roots; i++) {
307
818k
        /* Count items on worklist before we mark it. */
308
818k
        MVMuint32 items_before_mark  = worklist->items;
309
818k
310
818k
        /* Put things it references into the worklist; since the worklist will
311
818k
         * be set not to include gen2 things, only nursery things will make it
312
818k
         * in. */
313
818k
        assert(!(gen2roots[i]->flags & MVM_CF_FORWARDER_VALID));
314
818k
        MVM_gc_mark_collectable(tc, worklist, gen2roots[i]);
315
818k
316
818k
        /* If we added any nursery objects, or if we are a frame with ->work
317
818k
         * area, keep in this list. */
318
818k
        if (worklist->items != items_before_mark ||
319
679k
                (gen2roots[i]->flags & MVM_CF_FRAME && ((MVMFrame *)gen2roots[i])->work)) {
320
142k
            gen2roots[insert_pos] = gen2roots[i];
321
142k
            insert_pos++;
322
142k
        }
323
818k
324
818k
        /* Otherwise, clear the "in gen2 root list" flag. Note that another
325
818k
         * thread may also clear this flag if it also had the entry in its
326
818k
         * inter-gen list, so be careful to clear it, not just toggle. */
327
676k
        else {
328
676k
            gen2roots[i]->flags &= ~MVM_CF_IN_GEN2_ROOT_LIST;
329
676k
        }
330
818k
    }
331
750
332
750
    /* New number of entries after sliding is the final insert position. */
333
750
    tc->num_gen2roots = insert_pos;
334
750
}
335
336
/* Adds inter-generational roots to a heap snapshot. */
337
0
void MVM_gc_root_add_gen2s_to_snapshot(MVMThreadContext *tc, MVMHeapSnapshotState *snapshot) {
338
0
    MVMCollectable **gen2roots = tc->gen2roots;
339
0
    MVMuint32        num_roots = tc->num_gen2roots;
340
0
    MVMuint32        i;
341
0
    for (i = 0; i < num_roots; i++)
342
0
        MVM_profile_heap_add_collectable_rel_idx(tc, snapshot, gen2roots[i], i);
343
0
}
344
345
/* Visits all of the roots in the gen2 list and removes those that have been
346
 * collected. Applied after a full collection. */
347
0
void MVM_gc_root_gen2_cleanup(MVMThreadContext *tc) {
348
0
    MVMCollectable **gen2roots    = tc->gen2roots;
349
0
    MVMuint32        num_roots    = tc->num_gen2roots;
350
0
    MVMuint32        i = 0;
351
0
    MVMuint32        cur_survivor;
352
0
353
0
    /* Find the first collected object. */
354
0
    while (i < num_roots && gen2roots[i]->flags & MVM_CF_GEN2_LIVE)
355
0
        i++;
356
0
    cur_survivor = i;
357
0
358
0
    /* Slide others back so the alive ones are at the start of the list. */
359
0
    while (i < num_roots) {
360
0
        if (gen2roots[i]->flags & MVM_CF_GEN2_LIVE) {
361
0
            assert(!(gen2roots[i]->flags & MVM_CF_FORWARDER_VALID));
362
0
            gen2roots[cur_survivor++] = gen2roots[i];
363
0
        }
364
0
        i++;
365
0
    }
366
0
367
0
    tc->num_gen2roots = cur_survivor;
368
0
}
369
370
/* Walks frames and compilation units. Adds the roots it finds into the
371
 * GC worklist. */
372
static void scan_lexicals(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMFrame *frame);
373
182k
void MVM_gc_root_add_frame_roots_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMFrame *cur_frame) {
374
182k
    /* Add caller to worklist if it's heap-allocated. */
375
182k
    if (cur_frame->caller && !MVM_FRAME_IS_ON_CALLSTACK(tc, cur_frame->caller))
376
181k
        MVM_gc_worklist_add(tc, worklist, &cur_frame->caller);
377
182k
378
182k
    /* Add outer, code_ref and static info to work list. */
379
182k
    MVM_gc_worklist_add(tc, worklist, &cur_frame->outer);
380
182k
    MVM_gc_worklist_add(tc, worklist, &cur_frame->code_ref);
381
182k
    MVM_gc_worklist_add(tc, worklist, &cur_frame->static_info);
382
182k
383
182k
    /* Mark frame extras if needed. */
384
182k
    if (cur_frame->extra) {
385
1.56k
        MVMFrameExtra *e = cur_frame->extra;
386
1.56k
        if (e->special_return_data && e->mark_special_return_data)
387
0
            e->mark_special_return_data(tc, cur_frame, worklist);
388
1.56k
        if (e->continuation_tags) {
389
0
            MVMContinuationTag *tag = e->continuation_tags;
390
0
            while (tag) {
391
0
                MVM_gc_worklist_add(tc, worklist, &tag->tag);
392
0
                tag = tag->next;
393
0
            }
394
0
        }
395
1.56k
        MVM_gc_worklist_add(tc, worklist, &e->invoked_call_capture);
396
1.56k
        if (e->dynlex_cache_name)
397
1.21k
            MVM_gc_worklist_add(tc, worklist, &e->dynlex_cache_name);
398
1.56k
    }
399
182k
400
182k
    /* Scan the registers. */
401
182k
    MVM_gc_root_add_frame_registers_to_worklist(tc, worklist, cur_frame);
402
182k
    scan_lexicals(tc, worklist, cur_frame);
403
182k
}
404
405
/* Takes a frame, scans its registers and adds them to the roots. */
406
182k
void MVM_gc_root_add_frame_registers_to_worklist(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMFrame *frame) {
407
182k
    MVMuint16  i, count, flag;
408
182k
    MVMuint16 *type_map;
409
182k
    MVMuint8  *flag_map;
410
182k
    /* We only need to do any of this work if the frame is in dynamic scope. */
411
182k
    if (frame->work) {
412
8.34k
        /* Scan locals. */
413
8.34k
414
8.34k
        MVMSpeshCandidate *spesh_cand = frame->spesh_cand;
415
1.97k
        MVMJitCode *jitcode = spesh_cand ? spesh_cand->jitcode : NULL;
416
8.34k
        if (jitcode && jitcode->local_types) {
417
1.67k
            type_map = jitcode->local_types;
418
1.67k
            count    = jitcode->num_locals;
419
6.67k
        } else if (frame->spesh_cand && frame->spesh_cand->local_types) {
420
249
            type_map = frame->spesh_cand->local_types;
421
249
            count    = frame->spesh_cand->num_locals;
422
249
        }
423
6.42k
        else {
424
6.42k
            type_map = frame->static_info->body.local_types;
425
6.42k
            count    = frame->static_info->body.num_locals;
426
6.42k
        }
427
290k
        for (i = 0; i < count; i++)
428
281k
            if (type_map[i] == MVM_reg_str || type_map[i] == MVM_reg_obj)
429
223k
                MVM_gc_worklist_add(tc, worklist, &frame->work[i].o);
430
8.34k
431
8.34k
        /* Scan arg buffer if needed. */
432
8.34k
        if (frame->cur_args_callsite) {
433
8.17k
            flag_map = frame->cur_args_callsite->arg_flags;
434
8.17k
            count = frame->cur_args_callsite->arg_count;
435
24.3k
            for (i = 0, flag = 0; i < count; i++, flag++) {
436
16.1k
                if (flag_map[flag] & MVM_CALLSITE_ARG_NAMED) {
437
1.51k
                    /* Current position is name, then next is value. */
438
1.51k
                    MVM_gc_worklist_add(tc, worklist, &frame->args[i].s);
439
1.51k
                    i++;
440
1.51k
                }
441
16.1k
                if (flag_map[flag] & MVM_CALLSITE_ARG_STR || flag_map[flag] & MVM_CALLSITE_ARG_OBJ)
442
15.6k
                    MVM_gc_worklist_add(tc, worklist, &frame->args[i].o);
443
16.1k
            }
444
8.17k
        }
445
8.34k
446
8.34k
        /* Scan arguments in case there was a flattening. Don't need to if
447
8.34k
         * there wasn't a flattening because orig args is a subset of locals. */
448
8.34k
        if (frame->params.arg_flags && frame->params.callsite->has_flattening) {
449
2.35k
            MVMArgProcContext *ctx = &frame->params;
450
2.35k
            flag_map = ctx->arg_flags;
451
2.35k
            count = ctx->arg_count;
452
9.77k
            for (i = 0, flag = 0; i < count; i++, flag++) {
453
7.41k
                if (flag_map[flag] & MVM_CALLSITE_ARG_NAMED) {
454
2.97k
                    /* Current position is name, then next is value. */
455
2.97k
                    MVM_gc_worklist_add(tc, worklist, &ctx->args[i].s);
456
2.97k
                    i++;
457
2.97k
                }
458
7.41k
                if (flag_map[flag] & MVM_CALLSITE_ARG_STR || flag_map[flag] & MVM_CALLSITE_ARG_OBJ)
459
7.29k
                    MVM_gc_worklist_add(tc, worklist, &ctx->args[i].o);
460
7.41k
            }
461
2.35k
        }
462
8.34k
    }
463
182k
}
464
465
/* Takes a frame, scans its lexicals and adds them to the roots. */
466
182k
static void scan_lexicals(MVMThreadContext *tc, MVMGCWorklist *worklist, MVMFrame *frame) {
467
182k
    if (frame->env) {
468
94.7k
        MVMuint16  i, count;
469
94.7k
        MVMuint16 *type_map;
470
94.7k
        if (frame->spesh_cand && frame->spesh_cand->lexical_types) {
471
7.36k
            type_map = frame->spesh_cand->lexical_types;
472
7.36k
            count    = frame->spesh_cand->num_lexicals;
473
7.36k
        }
474
87.3k
        else {
475
87.3k
            type_map = frame->static_info->body.lexical_types;
476
87.3k
            count    = frame->static_info->body.num_lexicals;
477
87.3k
        }
478
463k
        for (i = 0; i < count; i++)
479
369k
            if (type_map[i] == MVM_reg_str || type_map[i] == MVM_reg_obj)
480
314k
                MVM_gc_worklist_add(tc, worklist, &frame->env[i].o);
481
94.7k
    }
482
182k
}