/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 | } |