/home/travis/build/MoarVM/MoarVM/src/6model/sc.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Creates a new serialization context with the specified handle. If any |
4 | | * compilation units are waiting for an SC with this handle, removes it from |
5 | | * their to-resolve list after installing itself in the appropriate slot. */ |
6 | 2.88k | MVMObject * MVM_sc_create(MVMThreadContext *tc, MVMString *handle) { |
7 | 2.88k | MVMSerializationContext *sc; |
8 | 2.88k | MVMSerializationContextBody *scb = NULL; |
9 | 2.88k | |
10 | 2.88k | /* Allocate. */ |
11 | 2.88k | MVMROOT(tc, handle, { |
12 | 2.88k | sc = (MVMSerializationContext *)REPR(tc->instance->SCRef)->allocate(tc, STABLE(tc->instance->SCRef)); |
13 | 2.88k | MVMROOT(tc, sc, { |
14 | 2.88k | /* Add to weak lookup hash. */ |
15 | 2.88k | uv_mutex_lock(&tc->instance->mutex_sc_weakhash); |
16 | 2.88k | MVM_HASH_GET(tc, tc->instance->sc_weakhash, handle, scb); |
17 | 2.88k | if (!scb) { |
18 | 2.88k | sc->body = scb = MVM_calloc(1, sizeof(MVMSerializationContextBody)); |
19 | 2.88k | MVM_ASSIGN_REF(tc, &(sc->common.header), scb->handle, handle); |
20 | 2.88k | MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, scb); |
21 | 2.88k | /* Calling repr_init will allocate, BUT if it does so, and we |
22 | 2.88k | * get unlucky, the GC will try to acquire mutex_sc_weakhash. |
23 | 2.88k | * This deadlocks. Thus, we force allocation in gen2, which |
24 | 2.88k | * can never trigger GC. Note that releasing the mutex early |
25 | 2.88k | * is not a good way to fix this, as it leaves a race to |
26 | 2.88k | * test/set scb->sc (between the line doing it in this block, |
27 | 2.88k | * and in the else clauses beneath it). */ |
28 | 2.88k | MVM_gc_allocate_gen2_default_set(tc); |
29 | 2.88k | MVM_repr_init(tc, (MVMObject *)sc); |
30 | 2.88k | MVM_gc_allocate_gen2_default_clear(tc); |
31 | 2.88k | scb->sc = sc; |
32 | 2.88k | MVM_sc_add_all_scs_entry(tc, scb); |
33 | 2.88k | } |
34 | 2.88k | else if (scb->sc) { |
35 | 2.88k | /* we lost a race to create it! */ |
36 | 2.88k | sc = scb->sc; |
37 | 2.88k | } |
38 | 2.88k | else { |
39 | 2.88k | scb->sc = sc; |
40 | 2.88k | sc->body = scb; |
41 | 2.88k | MVM_ASSIGN_REF(tc, &(sc->common.header), scb->handle, handle); |
42 | 2.88k | MVM_gc_allocate_gen2_default_set(tc); |
43 | 2.88k | MVM_repr_init(tc, (MVMObject *)sc); |
44 | 2.88k | MVM_gc_allocate_gen2_default_clear(tc); |
45 | 2.88k | } |
46 | 2.88k | uv_mutex_unlock(&tc->instance->mutex_sc_weakhash); |
47 | 2.88k | }); |
48 | 2.88k | }); |
49 | 2.88k | |
50 | 2.88k | return (MVMObject *)sc; |
51 | 2.88k | } |
52 | | |
53 | | /* Makes an entry in all SCs list, the index of which is used to refer to |
54 | | * SCs in object headers. */ |
55 | 2.86k | void MVM_sc_add_all_scs_entry(MVMThreadContext *tc, MVMSerializationContextBody *scb) { |
56 | 2.86k | if (tc->instance->all_scs_next_idx == tc->instance->all_scs_alloc) { |
57 | 167 | tc->instance->all_scs_alloc += 32; |
58 | 167 | if (tc->instance->all_scs_next_idx == 0) { |
59 | 130 | /* First time; allocate, and NULL first slot as it is |
60 | 130 | * the "no SC" sentinel value. */ |
61 | 130 | tc->instance->all_scs = MVM_malloc(tc->instance->all_scs_alloc * sizeof(MVMSerializationContextBody *)); |
62 | 130 | tc->instance->all_scs[0] = NULL; |
63 | 130 | tc->instance->all_scs_next_idx++; |
64 | 130 | } |
65 | 37 | else { |
66 | 37 | tc->instance->all_scs = MVM_realloc(tc->instance->all_scs, |
67 | 37 | tc->instance->all_scs_alloc * sizeof(MVMSerializationContextBody *)); |
68 | 37 | } |
69 | 167 | } |
70 | 2.86k | scb->sc_idx = tc->instance->all_scs_next_idx; |
71 | 2.86k | tc->instance->all_scs[tc->instance->all_scs_next_idx] = scb; |
72 | 2.86k | tc->instance->all_scs_next_idx++; |
73 | 2.86k | } |
74 | | |
75 | | /* Given an SC, returns its unique handle. */ |
76 | 8.28k | MVMString * MVM_sc_get_handle(MVMThreadContext *tc, MVMSerializationContext *sc) { |
77 | 8.28k | return sc->body->handle; |
78 | 8.28k | } |
79 | | |
80 | | /* Given an SC, returns its description. */ |
81 | 172 | MVMString * MVM_sc_get_description(MVMThreadContext *tc, MVMSerializationContext *sc) { |
82 | 172 | return sc->body->description; |
83 | 172 | } |
84 | | |
85 | | /* Given an SC, sets its description. */ |
86 | 2.54k | void MVM_sc_set_description(MVMThreadContext *tc, MVMSerializationContext *sc, MVMString *desc) { |
87 | 2.54k | MVM_ASSIGN_REF(tc, &(sc->common.header), sc->body->description, desc); |
88 | 2.54k | } |
89 | | |
90 | | /* Given an SC, looks up the index of an object that is in its root set. */ |
91 | 8.50k | MVMint64 MVM_sc_find_object_idx(MVMThreadContext *tc, MVMSerializationContext *sc, MVMObject *obj) { |
92 | 8.50k | MVMObject **roots; |
93 | 8.50k | MVMint64 i, count; |
94 | 8.50k | MVMuint32 cached = MVM_sc_get_idx_in_sc(&obj->header); |
95 | 8.50k | if (cached != ~0 && MVM_sc_get_collectable_sc(tc, &obj->header) == sc) |
96 | 4.93k | return cached; |
97 | 3.56k | roots = sc->body->root_objects; |
98 | 3.56k | count = sc->body->num_objects; |
99 | 197k | for (i = 0; i < count; i++) |
100 | 197k | if (roots[i] == obj) |
101 | 3.56k | return i; |
102 | 0 | MVM_exception_throw_adhoc(tc, |
103 | 0 | "Object does not exist in serialization context"); |
104 | 0 | } |
105 | | |
106 | | /* Calls MVM_sc_find_object_idx, but first checks if the sc is actually an SCRef. */ |
107 | 3.57k | MVMint64 MVM_sc_find_object_idx_jit(MVMThreadContext *tc, MVMObject *sc, MVMObject *obj) { |
108 | 3.57k | if (REPR(sc)->ID != MVM_REPR_ID_SCRef) |
109 | 0 | MVM_exception_throw_adhoc(tc, |
110 | 0 | "Must provide an SCRef operand to scgetobjidx"); |
111 | 3.57k | return MVM_sc_find_object_idx(tc, (MVMSerializationContext *)sc, obj); |
112 | 3.57k | } |
113 | | |
114 | | /* Given an SC, looks up the index of an STable that is in its root set. */ |
115 | 332 | MVMint64 MVM_sc_find_stable_idx(MVMThreadContext *tc, MVMSerializationContext *sc, MVMSTable *st) { |
116 | 332 | MVMuint64 i; |
117 | 332 | MVMuint32 cached = MVM_sc_get_idx_in_sc(&st->header); |
118 | 332 | if (cached != ~0 && MVM_sc_get_collectable_sc(tc, &st->header) == sc) |
119 | 0 | return cached; |
120 | 5.42k | for (i = 0; i < sc->body->num_stables; i++) |
121 | 5.42k | if (sc->body->root_stables[i] == st) |
122 | 332 | return i; |
123 | 0 | MVM_exception_throw_adhoc(tc, |
124 | 0 | "STable does not exist in serialization context"); |
125 | 0 | } |
126 | | |
127 | | /* Given an SC, looks up the index of a code ref that is in its root set. */ |
128 | 28 | MVMint64 MVM_sc_find_code_idx(MVMThreadContext *tc, MVMSerializationContext *sc, MVMObject *obj) { |
129 | 28 | MVMObject *roots; |
130 | 28 | MVMint64 i, count; |
131 | 28 | roots = sc->body->root_codes; |
132 | 28 | count = MVM_repr_elems(tc, roots); |
133 | 46 | for (i = 0; i < count; i++) { |
134 | 46 | MVMObject *test = MVM_repr_at_pos_o(tc, roots, i); |
135 | 46 | if (test == obj) |
136 | 28 | return i; |
137 | 46 | } |
138 | 28 | |
139 | 0 | if (REPR(obj)->ID == MVM_REPR_ID_MVMCode) { |
140 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, ((MVMCode *)obj)->body.name); |
141 | 0 | char *waste[] = { c_name, NULL }; |
142 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
143 | 0 | "Code ref '%s' does not exist in serialization context", |
144 | 0 | c_name); |
145 | 0 | } |
146 | 0 | else { |
147 | 0 | MVM_exception_throw_adhoc(tc, |
148 | 0 | "Code ref '<NOT A CODE OBJECT>' does not exist in serialization context"); |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | | /* Given a compilation unit and dependency index, returns that SC. */ |
153 | 14.8M | MVMSerializationContext * MVM_sc_get_sc(MVMThreadContext *tc, MVMCompUnit *cu, MVMint16 dep) { |
154 | 14.8M | MVMSerializationContext *sc = cu->body.scs[dep]; |
155 | 14.8M | if (sc == NULL) { |
156 | 2.46k | MVMSerializationContextBody *scb = cu->body.scs_to_resolve[dep]; |
157 | 2.46k | if (!scb) |
158 | 0 | MVM_exception_throw_adhoc(tc, |
159 | 0 | "SC resolution: internal error"); |
160 | 2.46k | sc = scb->sc; |
161 | 2.46k | if (sc == NULL) |
162 | 0 | return NULL; |
163 | 2.46k | MVM_ASSIGN_REF(tc, &(cu->common.header), cu->body.scs[dep], sc); |
164 | 2.46k | scb->claimed = 1; |
165 | 2.46k | } |
166 | 14.8M | return sc; |
167 | 14.8M | } |
168 | | |
169 | | /* Checks if an SC is currently in the process of doing deserialization work. */ |
170 | 17.1M | MVM_STATIC_INLINE MVMint64 sc_working(MVMSerializationContext *sc) { |
171 | 17.1M | MVMSerializationReader *sr = sc->body->sr; |
172 | 17.0M | return sr && sr->working; |
173 | 17.1M | } |
174 | | |
175 | | /* Given an SC and an index, fetch the object stored there. */ |
176 | 16.0M | MVMObject * MVM_sc_get_object(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx) { |
177 | 16.0M | MVMObject **roots = sc->body->root_objects; |
178 | 16.0M | MVMint64 count = sc->body->num_objects; |
179 | 16.0M | if (idx >= 0 && idx < count) |
180 | 16.0M | return roots[idx] && !sc_working(sc) |
181 | 14.9M | ? roots[idx] |
182 | 1.13M | : MVM_serialization_demand_object(tc, sc, idx); |
183 | 0 | else { |
184 | 0 | char *c_description = MVM_string_utf8_encode_C_string(tc, sc->body->description); |
185 | 0 | char *waste[] = { c_description, NULL }; |
186 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
187 | 0 | "Probable version skew in pre-compiled '%s' (cause: no object at index %"PRId64")", |
188 | 0 | c_description, idx); |
189 | 0 | } |
190 | 16.0M | } |
191 | | |
192 | | MVMObject * MVM_sc_get_sc_object(MVMThreadContext *tc, MVMCompUnit *cu, |
193 | 14.7M | MVMint16 dep, MVMint64 idx) { |
194 | 14.7M | if (dep >= 0 && dep < cu->body.num_scs) { |
195 | 14.7M | MVMSerializationContext *sc = MVM_sc_get_sc(tc, cu, dep); |
196 | 14.7M | if (sc == NULL) |
197 | 0 | MVM_exception_throw_adhoc(tc, "SC not yet resolved; lookup failed"); |
198 | 14.7M | return MVM_sc_get_object(tc, sc, idx); |
199 | 14.7M | } |
200 | 0 | else { |
201 | 0 | MVM_exception_throw_adhoc(tc, "Invalid SC index in bytecode stream"); |
202 | 0 | } |
203 | 14.7M | } |
204 | | |
205 | | /* Given an SC and an index, fetch the object stored there, or return NULL if |
206 | | * there is none. Does not cause lazy deserialization. */ |
207 | 875k | MVMObject * MVM_sc_try_get_object(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx) { |
208 | 875k | MVMObject **roots = sc->body->root_objects; |
209 | 875k | MVMint64 count = sc->body->num_objects; |
210 | 875k | if (idx > 0 && idx < count && !sc_working(sc)) |
211 | 49.7k | return roots[idx]; |
212 | 875k | else |
213 | 825k | return NULL; |
214 | 875k | } |
215 | | |
216 | | /* Given an SC, an index, and an object, store the object at that index. */ |
217 | 827k | void MVM_sc_set_object(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx, MVMObject *obj) { |
218 | 827k | if (idx < 0) |
219 | 0 | MVM_exception_throw_adhoc(tc, "Invalid (negative) object root index %"PRId64"", idx); |
220 | 827k | if (idx < sc->body->num_objects) { |
221 | 822k | /* Just updating an existing one. */ |
222 | 822k | MVM_ASSIGN_REF(tc, &(sc->common.header), sc->body->root_objects[idx], obj); |
223 | 822k | } |
224 | 5.11k | else { |
225 | 5.11k | if (idx >= sc->body->alloc_objects) { |
226 | 2.64k | MVMint64 orig_size = sc->body->alloc_objects; |
227 | 2.64k | sc->body->alloc_objects *= 2; |
228 | 2.64k | if (sc->body->alloc_objects < idx + 1) |
229 | 1.31k | sc->body->alloc_objects = idx + 1; |
230 | 2.64k | sc->body->root_objects = MVM_realloc(sc->body->root_objects, |
231 | 2.64k | sc->body->alloc_objects * sizeof(MVMObject *)); |
232 | 2.64k | memset(sc->body->root_objects + orig_size, 0, |
233 | 2.64k | (sc->body->alloc_objects - orig_size) * sizeof(MVMObject *)); |
234 | 2.64k | } |
235 | 5.11k | MVM_ASSIGN_REF(tc, &(sc->common.header), sc->body->root_objects[idx], obj); |
236 | 5.11k | sc->body->num_objects = idx + 1; |
237 | 5.11k | } |
238 | 827k | MVM_sc_set_idx_in_sc(&obj->header, idx); |
239 | 827k | } |
240 | | |
241 | | /* Given an SC and an index, fetch the STable stored there. */ |
242 | 848k | MVMSTable * MVM_sc_get_stable(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx) { |
243 | 848k | if (idx >= 0 && idx < sc->body->num_stables) { |
244 | 848k | MVMSTable *got = sc->body->root_stables[idx]; |
245 | 825k | return got && !sc_working(sc) ? got : MVM_serialization_demand_stable(tc, sc, idx); |
246 | 848k | } |
247 | 0 | else { |
248 | 0 | char *c_description = MVM_string_utf8_encode_C_string(tc, sc->body->description); |
249 | 0 | char *waste[] = { c_description, NULL }; |
250 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
251 | 0 | "Probable version skew in pre-compiled '%s' (cause: no STable at index %"PRId64")", |
252 | 0 | c_description, idx); |
253 | 0 | } |
254 | 848k | } |
255 | | |
256 | | /* Given an SC and an index, fetch the STable stored there, or return NULL if there |
257 | | * is none. Does not cause lazy deserialization. */ |
258 | 22.6k | MVMSTable * MVM_sc_try_get_stable(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx) { |
259 | 22.6k | if (idx >= 0 && idx < sc->body->num_stables) |
260 | 22.6k | return sc->body->root_stables[idx]; |
261 | 22.6k | else |
262 | 0 | return NULL; |
263 | 22.6k | } |
264 | | |
265 | | /* Given an SC, an index, and an STable, store the STable at the index. */ |
266 | 23.9k | void MVM_sc_set_stable(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx, MVMSTable *st) { |
267 | 23.9k | if (idx < 0) |
268 | 0 | MVM_exception_throw_adhoc(tc, |
269 | 0 | "Invalid (negative) STable index %"PRId64, idx); |
270 | 23.9k | if (idx < sc->body->num_stables) { |
271 | 22.6k | /* Just updating an existing one. */ |
272 | 22.6k | MVM_ASSIGN_REF(tc, &(sc->common.header), sc->body->root_stables[idx], st); |
273 | 22.6k | } |
274 | 1.30k | else { |
275 | 1.30k | if (idx >= sc->body->alloc_stables) { |
276 | 130 | MVMint64 orig_size = sc->body->alloc_stables; |
277 | 130 | sc->body->alloc_stables += 32; |
278 | 130 | if (sc->body->alloc_stables < idx + 1) |
279 | 0 | sc->body->alloc_stables = idx + 1; |
280 | 130 | sc->body->root_stables = MVM_realloc(sc->body->root_stables, |
281 | 130 | sc->body->alloc_stables * sizeof(MVMSTable *)); |
282 | 130 | memset(sc->body->root_stables + orig_size, 0, |
283 | 130 | (sc->body->alloc_stables - orig_size) * sizeof(MVMSTable *)); |
284 | 130 | } |
285 | 1.30k | MVM_ASSIGN_REF(tc, &(sc->common.header), sc->body->root_stables[idx], st); |
286 | 1.30k | sc->body->num_stables = idx + 1; |
287 | 1.30k | } |
288 | 23.9k | } |
289 | | |
290 | | |
291 | | /* Given an SC and an STable, pushes the STable to the end of the root list. */ |
292 | 587 | void MVM_sc_push_stable(MVMThreadContext *tc, MVMSerializationContext *sc, MVMSTable *st) { |
293 | 587 | MVMint64 idx = sc->body->num_stables; |
294 | 587 | if (idx == sc->body->alloc_stables) { |
295 | 151 | sc->body->alloc_stables += 16; |
296 | 151 | sc->body->root_stables = MVM_realloc(sc->body->root_stables, |
297 | 151 | sc->body->alloc_stables * sizeof(MVMSTable *)); |
298 | 151 | } |
299 | 587 | MVM_ASSIGN_REF(tc, &(sc->common.header), sc->body->root_stables[idx], st); |
300 | 587 | sc->body->num_stables++; |
301 | 587 | } |
302 | | |
303 | | /* Given an SC and an index, fetch the code ref stored there. */ |
304 | 210k | MVMObject * MVM_sc_get_code(MVMThreadContext *tc, MVMSerializationContext *sc, MVMint64 idx) { |
305 | 210k | MVMObject *roots = sc->body->root_codes; |
306 | 210k | MVMuint64 count = MVM_repr_elems(tc, roots); |
307 | 210k | if (idx < count) { |
308 | 210k | MVMObject *found = MVM_repr_at_pos_o(tc, roots, idx); |
309 | 189k | return MVM_is_null(tc, found) || sc_working(sc) |
310 | 210k | ? MVM_serialization_demand_code(tc, sc, idx) |
311 | 260 | : found; |
312 | 210k | } |
313 | 0 | else { |
314 | 0 | char *c_description = MVM_string_utf8_encode_C_string(tc, sc->body->description); |
315 | 0 | char *waste[] = { c_description, NULL }; |
316 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
317 | 0 | "Probable version skew in pre-compiled '%s' (cause: no code ref at index %"PRId64")", |
318 | 0 | c_description, idx); |
319 | 0 | } |
320 | 210k | } |
321 | | |
322 | | /* Resolves an SC handle using the SC weakhash. */ |
323 | 6.68k | MVMSerializationContext * MVM_sc_find_by_handle(MVMThreadContext *tc, MVMString *handle) { |
324 | 6.68k | MVMSerializationContextBody *scb; |
325 | 6.68k | uv_mutex_lock(&tc->instance->mutex_sc_weakhash); |
326 | 6.68k | MVM_HASH_GET(tc, tc->instance->sc_weakhash, handle, scb); |
327 | 6.68k | uv_mutex_unlock(&tc->instance->mutex_sc_weakhash); |
328 | 6.68k | return scb && scb->sc ? scb->sc : NULL; |
329 | 6.68k | } |
330 | | |
331 | | /* Marks all objects, stables and codes that belong to this SC as free to be taken by another. */ |
332 | 0 | void MVM_sc_disclaim(MVMThreadContext *tc, MVMSerializationContext *sc) { |
333 | 0 | MVMObject **root_objects, *root_codes, *obj; |
334 | 0 | MVMSTable **root_stables, *stable; |
335 | 0 | MVMint64 i, count; |
336 | 0 | MVMCollectable *col; |
337 | 0 | if (REPR(sc)->ID != MVM_REPR_ID_SCRef) |
338 | 0 | MVM_exception_throw_adhoc(tc, |
339 | 0 | "Must provide an SCRef operand to scdisclaim"); |
340 | 0 |
|
341 | 0 | root_objects = sc->body->root_objects; |
342 | 0 | count = sc->body->num_objects; |
343 | 0 | for (i = 0; i < count; i++) { |
344 | 0 | obj = root_objects[i]; |
345 | 0 | col = &obj->header; |
346 | 0 | #ifdef MVM_USE_OVERFLOW_SERIALIZATION_INDEX |
347 | | if (col->flags & MVM_CF_SERIALZATION_INDEX_ALLOCATED) { |
348 | | struct MVMSerializationIndex *const sci = col->sc_forward_u.sci; |
349 | | col->sc_forward_u.sci = NULL; |
350 | | MVM_free(sci); |
351 | | } |
352 | | col->sc_forward_u.sc.sc_idx = 0; |
353 | | col->sc_forward_u.sc.idx = 0; |
354 | | #else |
355 | 0 | col->sc_forward_u.sc.sc_idx = 0; |
356 | 0 | col->sc_forward_u.sc.idx = 0; |
357 | 0 | #endif |
358 | 0 | } |
359 | 0 | sc->body->num_objects = 0; |
360 | 0 |
|
361 | 0 | root_stables = sc->body->root_stables; |
362 | 0 | count = sc->body->num_stables; |
363 | 0 | for (i = 0; i < count; i++) { |
364 | 0 | stable = root_stables[i]; |
365 | 0 | col = &stable->header; |
366 | 0 | col->sc_forward_u.sc.sc_idx = 0; |
367 | 0 | } |
368 | 0 | sc->body->num_stables = 0; |
369 | 0 |
|
370 | 0 | root_codes = sc->body->root_codes; |
371 | 0 | count = MVM_repr_elems(tc, root_codes); |
372 | 0 | for (i = 0; i < count; i++) { |
373 | 0 | obj = MVM_repr_at_pos_o(tc, root_codes, i); |
374 | 0 | if (MVM_is_null(tc, obj)) |
375 | 0 | obj = MVM_serialization_demand_code(tc, sc, i); |
376 | 0 | col = &obj->header; |
377 | 0 | col->sc_forward_u.sc.sc_idx = 0; |
378 | 0 | } |
379 | 0 | sc->body->root_codes = NULL; |
380 | 0 | } |
381 | | |
382 | | /* Called when an object triggers the SC repossession write barrier. */ |
383 | 18.8k | void MVM_sc_wb_hit_obj(MVMThreadContext *tc, MVMObject *obj) { |
384 | 18.8k | MVMSerializationContext *comp_sc; |
385 | 18.8k | |
386 | 18.8k | /* If the WB is disabled or we're not compiling, can exit quickly. */ |
387 | 18.8k | if (tc->sc_wb_disable_depth) |
388 | 11.1k | return; |
389 | 7.71k | if (!tc->compiling_scs || !MVM_repr_elems(tc, tc->compiling_scs)) |
390 | 5.06k | return; |
391 | 7.71k | |
392 | 7.71k | /* Same if the object is flagged as one to never repossess. */ |
393 | 2.65k | if (obj->header.flags & MVM_CF_NEVER_REPOSSESS) |
394 | 1 | return; |
395 | 2.65k | |
396 | 2.65k | /* Otherwise, check that the object's SC is different from the SC |
397 | 2.65k | * of the compilation we're currently in. Repossess if so. */ |
398 | 2.65k | comp_sc = (MVMSerializationContext *)MVM_repr_at_pos_o(tc, tc->compiling_scs, 0); |
399 | 2.65k | if (MVM_sc_get_obj_sc(tc, obj) != comp_sc) { |
400 | 597 | /* Get new slot ID. */ |
401 | 597 | MVMint64 new_slot = comp_sc->body->num_objects; |
402 | 597 | |
403 | 597 | /* See if the object is actually owned by another, and it's the |
404 | 597 | * owner we need to repossess. */ |
405 | 597 | if (obj->st->WHAT == tc->instance->boot_types.BOOTArray || |
406 | 597 | obj->st->WHAT == tc->instance->boot_types.BOOTHash) { |
407 | 130 | MVMObject *owned_objects = MVM_sc_get_obj_sc(tc, obj)->body->owned_objects; |
408 | 130 | MVMint64 n = MVM_repr_elems(tc, owned_objects); |
409 | 130 | MVMint64 found = 0; |
410 | 130 | MVMint64 i; |
411 | 8.34k | for (i = 0; i < n; i += 2) { |
412 | 8.21k | if (MVM_repr_at_pos_o(tc, owned_objects, i) == obj) { |
413 | 0 | MVMSerializationContext *real_sc; |
414 | 0 | obj = MVM_repr_at_pos_o(tc, owned_objects, i + 1); |
415 | 0 | real_sc = MVM_sc_get_obj_sc(tc, obj); |
416 | 0 | if (!real_sc) |
417 | 0 | return; /* Probably disclaimed. */ |
418 | 0 | if (real_sc == comp_sc) |
419 | 0 | return; |
420 | 0 | found = 1; |
421 | 0 | break; |
422 | 0 | } |
423 | 8.21k | } |
424 | 130 | if (!found) |
425 | 130 | return; |
426 | 130 | } |
427 | 597 | |
428 | 597 | /* Add to root set. */ |
429 | 467 | MVM_sc_set_object(tc, comp_sc, new_slot, obj); |
430 | 467 | |
431 | 467 | /* Add repossession entry. */ |
432 | 467 | MVM_repr_push_i(tc, comp_sc->body->rep_indexes, new_slot << 1); |
433 | 467 | MVM_repr_push_o(tc, comp_sc->body->rep_scs, (MVMObject *)MVM_sc_get_obj_sc(tc, obj)); |
434 | 467 | |
435 | 467 | /* Update SC of the object, claiming it, and update index too. */ |
436 | 467 | MVM_sc_set_obj_sc(tc, obj, comp_sc); |
437 | 467 | MVM_sc_set_idx_in_sc(&(obj->header), new_slot); |
438 | 467 | } |
439 | 2.65k | } |
440 | | |
441 | | /* Called when an STable triggers the SC repossession write barrier. */ |
442 | 765 | void MVM_sc_wb_hit_st(MVMThreadContext *tc, MVMSTable *st) { |
443 | 765 | MVMSerializationContext *comp_sc; |
444 | 765 | |
445 | 765 | /* If the WB is disabled or we're not compiling, can exit quickly. */ |
446 | 765 | if (tc->sc_wb_disable_depth) |
447 | 0 | return; |
448 | 765 | if (!tc->compiling_scs || !MVM_repr_elems(tc, tc->compiling_scs)) |
449 | 3 | return; |
450 | 765 | |
451 | 765 | /* Otherwise, check that the STable's SC is different from the SC |
452 | 765 | * of the compilation we're currently in. Repossess if so. */ |
453 | 762 | comp_sc = (MVMSerializationContext *)MVM_repr_at_pos_o(tc, tc->compiling_scs, 0); |
454 | 762 | if (MVM_sc_get_stable_sc(tc, st) != comp_sc) { |
455 | 1 | /* Add to root set. */ |
456 | 1 | MVMint64 new_slot = comp_sc->body->num_stables; |
457 | 1 | MVM_sc_push_stable(tc, comp_sc, st); |
458 | 1 | |
459 | 1 | /* Add repossession entry. */ |
460 | 1 | MVM_repr_push_i(tc, comp_sc->body->rep_indexes, (new_slot << 1) | 1); |
461 | 1 | MVM_repr_push_o(tc, comp_sc->body->rep_scs, (MVMObject *)MVM_sc_get_stable_sc(tc, st)); |
462 | 1 | |
463 | 1 | /* Update SC of the STable, claiming it. */ |
464 | 1 | MVM_sc_set_stable_sc(tc, st, comp_sc); |
465 | 1 | MVM_sc_set_idx_in_sc(&(st->header), new_slot); |
466 | 1 | } |
467 | 762 | } |