Coverage Report

Created: 2017-04-15 07:07

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