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