/home/travis/build/MoarVM/MoarVM/src/6model/6model.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | | /* Gets the HOW (meta-object), which may be lazily deserialized. */ |
4 | 528k | MVMObject * MVM_6model_get_how(MVMThreadContext *tc, MVMSTable *st) { |
5 | 528k | MVMObject *HOW = st->HOW; |
6 | 528k | if (!HOW) |
7 | 4.54k | st->HOW = HOW = MVM_sc_get_object(tc, st->HOW_sc, st->HOW_idx); |
8 | 528k | return HOW; |
9 | 528k | } |
10 | | |
11 | | /* Gets the HOW (meta-object), which may be lazily deserialized, through the |
12 | | * STable of the passed object. */ |
13 | 4 | MVMObject * MVM_6model_get_how_obj(MVMThreadContext *tc, MVMObject *obj) { |
14 | 4 | return MVM_6model_get_how(tc, STABLE(obj)); |
15 | 4 | } |
16 | | |
17 | | /* Obtains the method cache, lazily deserializing if it needed. */ |
18 | 12.0M | static MVMObject * get_method_cache(MVMThreadContext *tc, MVMSTable *st) { |
19 | 12.0M | if (!st->method_cache) |
20 | 4.31M | MVM_serialization_finish_deserialize_method_cache(tc, st); |
21 | 12.0M | return st->method_cache; |
22 | 12.0M | } |
23 | | |
24 | | /* Locates a method by name, checking in the method cache only. */ |
25 | 5.09M | MVMObject * MVM_6model_find_method_cache_only(MVMThreadContext *tc, MVMObject *obj, MVMString *name) { |
26 | 5.09M | MVMObject *cache; |
27 | 5.09M | |
28 | 5.09M | MVMROOT(tc, name, { |
29 | 5.09M | cache = get_method_cache(tc, STABLE(obj)); |
30 | 5.09M | }); |
31 | 5.09M | |
32 | 5.09M | if (cache && IS_CONCRETE(cache)) |
33 | 784k | return MVM_repr_at_key_o(tc, cache, name); |
34 | 4.31M | return NULL; |
35 | 5.09M | } |
36 | | |
37 | | /* Locates a method by name. Returns the method if it exists, or throws an |
38 | | * exception if it can not be found. */ |
39 | | typedef struct { |
40 | | MVMObject *obj; |
41 | | MVMString *name; |
42 | | MVMRegister *res; |
43 | | } FindMethodSRData; |
44 | 7 | static void die_over_missing_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name) { |
45 | 7 | MVMObject *handler = MVM_hll_current(tc)->method_not_found_error; |
46 | 7 | if (!MVM_is_null(tc, handler)) { |
47 | 0 | MVMCallsite *methnotfound_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_METH_NOT_FOUND); |
48 | 0 | handler = MVM_frame_find_invokee(tc, handler, NULL); |
49 | 0 | MVM_args_setup_thunk(tc, NULL, MVM_RETURN_VOID, methnotfound_callsite); |
50 | 0 | tc->cur_frame->args[0].o = obj; |
51 | 0 | tc->cur_frame->args[1].s = name; |
52 | 0 | STABLE(handler)->invoke(tc, handler, methnotfound_callsite, tc->cur_frame->args); |
53 | 0 | return; |
54 | 0 | } |
55 | 7 | else { |
56 | 7 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
57 | 7 | char *waste[] = { c_name, NULL }; |
58 | 7 | MVM_exception_throw_adhoc_free(tc, waste, |
59 | 7 | "Cannot find method '%s' on object of type %s", |
60 | 7 | c_name, STABLE(obj)->debug_name); |
61 | 7 | } |
62 | 7 | } |
63 | 4 | static void late_bound_find_method_return(MVMThreadContext *tc, void *sr_data) { |
64 | 4 | FindMethodSRData *fm = (FindMethodSRData *)sr_data; |
65 | 4 | if (MVM_is_null(tc, fm->res->o) || !IS_CONCRETE(fm->res->o)) { |
66 | 1 | MVMObject *obj = fm->obj; |
67 | 1 | MVMString *name = fm->name; |
68 | 1 | MVM_free(fm); |
69 | 1 | die_over_missing_method(tc, obj, name); |
70 | 1 | } |
71 | 3 | else { |
72 | 3 | MVM_free(fm); |
73 | 3 | } |
74 | 4 | } |
75 | 0 | static void mark_find_method_sr_data(MVMThreadContext *tc, MVMFrame *frame, MVMGCWorklist *worklist) { |
76 | 0 | FindMethodSRData *fm = (FindMethodSRData *)frame->special_return_data; |
77 | 0 | MVM_gc_worklist_add(tc, worklist, &fm->obj); |
78 | 0 | MVM_gc_worklist_add(tc, worklist, &fm->name); |
79 | 0 | } |
80 | 6.33M | void MVM_6model_find_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { |
81 | 6.33M | MVMObject *cache, *HOW, *find_method, *code; |
82 | 6.33M | MVMCallsite *findmeth_callsite; |
83 | 6.33M | |
84 | 6.33M | if (MVM_is_null(tc, obj)) { |
85 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
86 | 0 | char *waste[] = { c_name, NULL }; |
87 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
88 | 0 | "Cannot call method '%s' on a null object", |
89 | 0 | c_name); |
90 | 0 | } |
91 | 6.33M | |
92 | 6.33M | /* First try to find it in the cache. If we find it, we have a result. |
93 | 6.33M | * If we don't find it, but the cache is authoritative, then error. */ |
94 | 6.33M | MVMROOT(tc, obj, { |
95 | 6.33M | MVMROOT(tc, name, { |
96 | 6.33M | cache = get_method_cache(tc, STABLE(obj)); |
97 | 6.33M | }); |
98 | 6.33M | }); |
99 | 6.33M | |
100 | 6.33M | if (cache && IS_CONCRETE(cache)) { |
101 | 6.33M | MVMObject *meth = MVM_repr_at_key_o(tc, cache, name); |
102 | 6.33M | if (!MVM_is_null(tc, meth)) { |
103 | 6.33M | res->o = meth; |
104 | 6.33M | return; |
105 | 6.33M | } |
106 | 10 | if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) { |
107 | 6 | die_over_missing_method(tc, obj, name); |
108 | 6 | return; |
109 | 6 | } |
110 | 10 | } |
111 | 6.33M | |
112 | 6.33M | /* Otherwise, need to call the find_method method. We make the assumption |
113 | 6.33M | * that the invocant's meta-object's type is composed. */ |
114 | 5 | MVMROOT(tc, obj, { |
115 | 5 | MVMROOT(tc, name, { |
116 | 5 | HOW = MVM_6model_get_how(tc, STABLE(obj)); |
117 | 5 | MVMROOT(tc, HOW, { |
118 | 5 | find_method = MVM_6model_find_method_cache_only(tc, HOW, |
119 | 5 | tc->instance->str_consts.find_method); |
120 | 5 | }); |
121 | 5 | }); |
122 | 5 | }); |
123 | 5 | |
124 | 5 | if (MVM_is_null(tc, find_method)) { |
125 | 1 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
126 | 1 | char *waste[] = { c_name, NULL }; |
127 | 1 | MVM_exception_throw_adhoc_free(tc, waste, |
128 | 1 | "Cannot find method '%s': no method cache and no .^find_method", |
129 | 1 | c_name); |
130 | 1 | } |
131 | 5 | |
132 | 5 | /* Set up the call, using the result register as the target. */ |
133 | 5 | code = MVM_frame_find_invokee(tc, find_method, NULL); |
134 | 5 | findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD); |
135 | 5 | MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite); |
136 | 5 | { |
137 | 5 | FindMethodSRData *fm = MVM_malloc(sizeof(FindMethodSRData)); |
138 | 5 | fm->obj = obj; |
139 | 5 | fm->name = name; |
140 | 5 | fm->res = res; |
141 | 5 | tc->cur_frame->special_return = late_bound_find_method_return; |
142 | 5 | tc->cur_frame->special_return_data = fm; |
143 | 5 | tc->cur_frame->mark_special_return_data = mark_find_method_sr_data; |
144 | 5 | } |
145 | 5 | tc->cur_frame->args[0].o = HOW; |
146 | 5 | tc->cur_frame->args[1].o = obj; |
147 | 5 | tc->cur_frame->args[2].s = name; |
148 | 5 | STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args); |
149 | 5 | } |
150 | | |
151 | | MVMint32 MVM_6model_find_method_spesh(MVMThreadContext *tc, MVMObject *obj, MVMString *name, |
152 | 11.9k | MVMint32 ss_idx, MVMRegister *res) { |
153 | 11.9k | MVMObject *meth; |
154 | 11.9k | |
155 | 11.9k | /* Missed mono-morph; try cache-only lookup. */ |
156 | 11.9k | |
157 | 11.9k | MVMROOT(tc, obj, { |
158 | 11.9k | MVMROOT(tc, name, { |
159 | 11.9k | meth = MVM_6model_find_method_cache_only(tc, obj, name); |
160 | 11.9k | }); |
161 | 11.9k | }); |
162 | 11.9k | |
163 | 11.9k | if (!MVM_is_null(tc, meth)) { |
164 | 11.9k | /* Got it; cache. Must be careful due to threads |
165 | 11.9k | * reading, races, etc. */ |
166 | 11.9k | MVMStaticFrame *sf = tc->cur_frame->static_info; |
167 | 11.9k | uv_mutex_lock(&tc->instance->mutex_spesh_install); |
168 | 11.9k | if (!tc->cur_frame->effective_spesh_slots[ss_idx + 1]) { |
169 | 3.78k | MVM_ASSIGN_REF(tc, &(sf->common.header), |
170 | 3.78k | tc->cur_frame->effective_spesh_slots[ss_idx + 1], |
171 | 3.78k | (MVMCollectable *)meth); |
172 | 3.78k | MVM_barrier(); |
173 | 3.78k | MVM_ASSIGN_REF(tc, &(sf->common.header), |
174 | 3.78k | tc->cur_frame->effective_spesh_slots[ss_idx], |
175 | 3.78k | (MVMCollectable *)STABLE(obj)); |
176 | 3.78k | } |
177 | 11.9k | uv_mutex_unlock(&tc->instance->mutex_spesh_install); |
178 | 11.9k | res->o = meth; |
179 | 11.9k | return 0; |
180 | 11.9k | } |
181 | 0 | else { |
182 | 0 | /* Fully late-bound. */ |
183 | 0 | MVM_6model_find_method(tc, obj, name, res); |
184 | 0 | return 1; |
185 | 0 | } |
186 | 11.9k | } |
187 | | |
188 | | |
189 | | /* Locates a method by name. Returns 1 if it exists; otherwise 0. */ |
190 | 2 | static void late_bound_can_return(MVMThreadContext *tc, void *sr_data) { |
191 | 2 | /* Transform to an integer result. */ |
192 | 2 | MVMRegister *reg = (MVMRegister *)sr_data; |
193 | 1 | reg->i64 = !MVM_is_null(tc, reg->o) && IS_CONCRETE(reg->o) ? 1 : 0; |
194 | 2 | } |
195 | | |
196 | 638k | MVMint64 MVM_6model_can_method_cache_only(MVMThreadContext *tc, MVMObject *obj, MVMString *name) { |
197 | 638k | MVMObject *cache; |
198 | 638k | |
199 | 638k | if (MVM_is_null(tc, obj)) { |
200 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); |
201 | 0 | char *waste[] = { c_name, NULL }; |
202 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
203 | 0 | "Cannot look for method '%s' on a null object", |
204 | 0 | c_name); |
205 | 0 | } |
206 | 638k | |
207 | 638k | /* Consider the method cache. */ |
208 | 638k | |
209 | 638k | MVMROOT(tc, obj, { |
210 | 638k | MVMROOT(tc, name, { |
211 | 638k | cache = get_method_cache(tc, STABLE(obj)); |
212 | 638k | }); |
213 | 638k | }); |
214 | 638k | |
215 | 638k | if (cache && IS_CONCRETE(cache)) { |
216 | 638k | MVMObject *meth = MVM_repr_at_key_o(tc, cache, name); |
217 | 638k | if (!MVM_is_null(tc, meth)) { |
218 | 416k | return 1; |
219 | 416k | } |
220 | 222k | if (STABLE(obj)->mode_flags & MVM_METHOD_CACHE_AUTHORITATIVE) { |
221 | 222k | return 0; |
222 | 222k | } |
223 | 222k | } |
224 | 4 | return -1; |
225 | 638k | } |
226 | | |
227 | 637k | void MVM_6model_can_method(MVMThreadContext *tc, MVMObject *obj, MVMString *name, MVMRegister *res) { |
228 | 637k | MVMObject *HOW, *find_method, *code; |
229 | 637k | MVMCallsite *findmeth_callsite; |
230 | 637k | |
231 | 637k | MVMint64 can_cached; |
232 | 637k | |
233 | 637k | MVMROOT(tc, obj, { |
234 | 637k | MVMROOT(tc, name, { |
235 | 637k | can_cached = MVM_6model_can_method_cache_only(tc, obj, name); |
236 | 637k | }); |
237 | 637k | }); |
238 | 637k | |
239 | 637k | if (can_cached == 0 || can_cached == 1) { |
240 | 637k | res->i64 = can_cached; |
241 | 637k | return; |
242 | 637k | } |
243 | 637k | |
244 | 637k | /* If no method in cache and the cache is not authoritative, need to make |
245 | 637k | * a late-bound call to find_method. */ |
246 | 4 | MVMROOT(tc, obj, { |
247 | 4 | MVMROOT(tc, name, { |
248 | 4 | HOW = MVM_6model_get_how(tc, STABLE(obj)); |
249 | 4 | MVMROOT(tc, HOW, { |
250 | 4 | find_method = MVM_6model_find_method_cache_only(tc, HOW, |
251 | 4 | tc->instance->str_consts.find_method); |
252 | 4 | }); |
253 | 4 | }); |
254 | 4 | }); |
255 | 4 | |
256 | 4 | if (MVM_is_null(tc, find_method)) { |
257 | 2 | /* This'll count as a "no"... */ |
258 | 2 | res->i64 = 0; |
259 | 2 | return; |
260 | 2 | } |
261 | 4 | |
262 | 4 | /* Set up the call, using the result register as the target. A little bad |
263 | 4 | * as we're really talking about */ |
264 | 2 | code = MVM_frame_find_invokee(tc, find_method, NULL); |
265 | 2 | findmeth_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_FIND_METHOD); |
266 | 2 | MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, findmeth_callsite); |
267 | 2 | tc->cur_frame->special_return = late_bound_can_return; |
268 | 2 | tc->cur_frame->special_return_data = res; |
269 | 2 | tc->cur_frame->args[0].o = HOW; |
270 | 2 | tc->cur_frame->args[1].o = obj; |
271 | 2 | tc->cur_frame->args[2].s = name; |
272 | 2 | STABLE(code)->invoke(tc, code, findmeth_callsite, tc->cur_frame->args); |
273 | 2 | } |
274 | | |
275 | | /* Checks if an object has a given type, delegating to the type_check or |
276 | | * accepts_type methods as needed. */ |
277 | 4 | static void do_accepts_type_check(MVMThreadContext *tc, MVMObject *obj, MVMObject *type, MVMRegister *res) { |
278 | 4 | MVMObject *HOW, *meth; |
279 | 4 | |
280 | 4 | MVMROOT(tc, obj, { |
281 | 4 | MVMROOT(tc, type, { |
282 | 4 | HOW = MVM_6model_get_how(tc, STABLE(type)); |
283 | 4 | MVMROOT(tc, HOW, { |
284 | 4 | meth = MVM_6model_find_method_cache_only(tc, HOW, |
285 | 4 | tc->instance->str_consts.accepts_type); |
286 | 4 | }); |
287 | 4 | }); |
288 | 4 | }); |
289 | 4 | |
290 | 4 | if (!MVM_is_null(tc, meth)) { |
291 | 4 | /* Set up the call, using the result register as the target. */ |
292 | 4 | MVMObject *code = MVM_frame_find_invokee(tc, meth, NULL); |
293 | 4 | MVMCallsite *typecheck_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TYPECHECK); |
294 | 4 | |
295 | 4 | MVM_args_setup_thunk(tc, res, MVM_RETURN_INT, typecheck_callsite); |
296 | 4 | tc->cur_frame->args[0].o = HOW; |
297 | 4 | tc->cur_frame->args[1].o = type; |
298 | 4 | tc->cur_frame->args[2].o = obj; |
299 | 4 | STABLE(code)->invoke(tc, code, typecheck_callsite, tc->cur_frame->args); |
300 | 4 | return; |
301 | 4 | } |
302 | 0 | else { |
303 | 0 | MVM_exception_throw_adhoc(tc, |
304 | 0 | "Expected 'accepts_type' method, but none found in meta-object"); |
305 | 0 | } |
306 | 4 | } |
307 | | typedef struct { |
308 | | MVMObject *obj; |
309 | | MVMObject *type; |
310 | | MVMRegister *res; |
311 | | } AcceptsTypeSRData; |
312 | | |
313 | 3 | static void accepts_type_sr(MVMThreadContext *tc, void *sr_data) { |
314 | 3 | AcceptsTypeSRData *atd = (AcceptsTypeSRData *)sr_data; |
315 | 3 | MVMObject *obj = atd->obj; |
316 | 3 | MVMObject *type = atd->type; |
317 | 3 | MVMRegister *res = atd->res; |
318 | 3 | MVM_free(atd); |
319 | 3 | if (!res->i64) |
320 | 2 | do_accepts_type_check(tc, obj, type, res); |
321 | 3 | } |
322 | | |
323 | 0 | static void mark_sr_data(MVMThreadContext *tc, MVMFrame *frame, MVMGCWorklist *worklist) { |
324 | 0 | AcceptsTypeSRData *atd = (AcceptsTypeSRData *)frame->special_return_data; |
325 | 0 | MVM_gc_worklist_add(tc, worklist, &atd->obj); |
326 | 0 | MVM_gc_worklist_add(tc, worklist, &atd->type); |
327 | 0 | } |
328 | | |
329 | 1.18M | void MVM_6model_istype(MVMThreadContext *tc, MVMObject *obj, MVMObject *type, MVMRegister *res) { |
330 | 1.18M | MVMObject **cache; |
331 | 1.18M | MVMSTable *st; |
332 | 1.18M | MVMint64 mode; |
333 | 1.18M | |
334 | 1.18M | /* Null never type-checks. */ |
335 | 1.18M | if (MVM_is_null(tc, obj)) { |
336 | 1.50k | res->i64 = 0; |
337 | 1.50k | return; |
338 | 1.50k | } |
339 | 1.18M | |
340 | 1.18M | st = STABLE(obj); |
341 | 1.18M | mode = STABLE(type)->mode_flags & MVM_TYPE_CHECK_CACHE_FLAG_MASK; |
342 | 1.18M | cache = st->type_check_cache; |
343 | 1.18M | if (cache) { |
344 | 843k | /* We have the cache, so just look for the type object we |
345 | 843k | * want to be in there. */ |
346 | 843k | MVMint64 elems = STABLE(obj)->type_check_cache_length; |
347 | 843k | MVMint64 i; |
348 | 2.57M | for (i = 0; i < elems; i++) { |
349 | 2.22M | if (cache[i] == type) { |
350 | 491k | res->i64 = 1; |
351 | 491k | return; |
352 | 491k | } |
353 | 2.22M | } |
354 | 843k | |
355 | 843k | /* If the type check cache is definitive, we're done. */ |
356 | 351k | if ((mode & MVM_TYPE_CHECK_CACHE_THEN_METHOD) == 0 && |
357 | 351k | (mode & MVM_TYPE_CHECK_NEEDS_ACCEPTS) == 0) { |
358 | 351k | res->i64 = 0; |
359 | 351k | return; |
360 | 351k | } |
361 | 351k | } |
362 | 1.18M | |
363 | 1.18M | /* If we get here, need to call .^type_check on the value we're |
364 | 1.18M | * checking, unless it's an accepts check. */ |
365 | 338k | if (!cache || (mode & MVM_TYPE_CHECK_CACHE_THEN_METHOD)) { |
366 | 338k | MVMObject *HOW, *meth; |
367 | 338k | |
368 | 338k | MVMROOT(tc, obj, { |
369 | 338k | MVMROOT(tc, type, { |
370 | 338k | HOW = MVM_6model_get_how(tc, st); |
371 | 338k | MVMROOT(tc, HOW, { |
372 | 338k | meth = MVM_6model_find_method_cache_only(tc, HOW, |
373 | 338k | tc->instance->str_consts.type_check); |
374 | 338k | }); |
375 | 338k | }); |
376 | 338k | }); |
377 | 338k | if (!MVM_is_null(tc, meth)) { |
378 | 6 | /* Set up the call, using the result register as the target. */ |
379 | 6 | MVMObject *code = MVM_frame_find_invokee(tc, meth, NULL); |
380 | 6 | MVMCallsite *typecheck_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_TYPECHECK); |
381 | 6 | |
382 | 6 | MVM_args_setup_thunk(tc, res, MVM_RETURN_INT, typecheck_callsite); |
383 | 6 | tc->cur_frame->args[0].o = HOW; |
384 | 6 | tc->cur_frame->args[1].o = obj; |
385 | 6 | tc->cur_frame->args[2].o = type; |
386 | 6 | if (mode & MVM_TYPE_CHECK_NEEDS_ACCEPTS) { |
387 | 3 | AcceptsTypeSRData *atd = MVM_malloc(sizeof(AcceptsTypeSRData)); |
388 | 3 | atd->obj = obj; |
389 | 3 | atd->type = type; |
390 | 3 | atd->res = res; |
391 | 3 | tc->cur_frame->special_return = accepts_type_sr; |
392 | 3 | tc->cur_frame->special_return_data = atd; |
393 | 3 | tc->cur_frame->mark_special_return_data = mark_sr_data; |
394 | 3 | } |
395 | 6 | STABLE(code)->invoke(tc, code, typecheck_callsite, tc->cur_frame->args); |
396 | 6 | return; |
397 | 6 | } |
398 | 338k | } |
399 | 338k | |
400 | 338k | /* If the flag to call .accepts_type on the target value is set, do so. */ |
401 | 338k | if (mode & MVM_TYPE_CHECK_NEEDS_ACCEPTS) { |
402 | 2 | do_accepts_type_check(tc, obj, type, res); |
403 | 2 | } |
404 | 338k | else { |
405 | 338k | /* If all else fails... */ |
406 | 338k | res->i64 = 0; |
407 | 338k | } |
408 | 338k | } |
409 | | |
410 | | /* Checks if an object has a given type, using the cache only. */ |
411 | 0 | MVMint64 MVM_6model_istype_cache_only(MVMThreadContext *tc, MVMObject *obj, MVMObject *type) { |
412 | 0 | if (!MVM_is_null(tc, obj)) { |
413 | 0 | MVMuint16 i, elems = STABLE(obj)->type_check_cache_length; |
414 | 0 | MVMObject **cache = STABLE(obj)->type_check_cache; |
415 | 0 | if (cache) |
416 | 0 | for (i = 0; i < elems; i++) { |
417 | 0 | if (cache[i] == type) |
418 | 0 | return 1; |
419 | 0 | } |
420 | 0 | } |
421 | 0 |
|
422 | 0 | return 0; |
423 | 0 | } |
424 | | |
425 | | /* Tries to do a type check using the cache. If the type is in the cache, then |
426 | | * result will be set to a true value and a true value will be returned. If it |
427 | | * is not in the cache and the cache is authoritative, then we know the answer |
428 | | * too; result is set to zero and a true value is returned. Otherwise, we can |
429 | | * not tell and a false value is returned and result is undefined. */ |
430 | 368 | MVMint64 MVM_6model_try_cache_type_check(MVMThreadContext *tc, MVMObject *obj, MVMObject *type, MVMint32 *result) { |
431 | 368 | if (!MVM_is_null(tc, obj)) { |
432 | 281 | MVMuint16 i, elems = STABLE(obj)->type_check_cache_length; |
433 | 281 | MVMObject **cache = STABLE(obj)->type_check_cache; |
434 | 281 | if (cache) { |
435 | 1.43k | for (i = 0; i < elems; i++) { |
436 | 1.18k | if (cache[i] == type) { |
437 | 10 | *result = 1; |
438 | 10 | return 1; |
439 | 10 | } |
440 | 1.18k | } |
441 | 251 | if ((STABLE(obj)->mode_flags & MVM_TYPE_CHECK_CACHE_THEN_METHOD) == 0 && |
442 | 251 | (STABLE(type)->mode_flags & MVM_TYPE_CHECK_NEEDS_ACCEPTS) == 0) { |
443 | 251 | *result = 0; |
444 | 251 | return 1; |
445 | 251 | } |
446 | 251 | } |
447 | 281 | } |
448 | 107 | return 0; |
449 | 368 | } |
450 | | |
451 | | /* Default invoke function on STables; for non-invokable objects */ |
452 | 0 | void MVM_6model_invoke_default(MVMThreadContext *tc, MVMObject *invokee, MVMCallsite *callsite, MVMRegister *args) { |
453 | 0 | MVM_exception_throw_adhoc(tc, "Cannot invoke this object (REPR: %s; %s)", REPR(invokee)->name, STABLE(invokee)->debug_name); |
454 | 0 | } |
455 | | |
456 | | /* Clean up STable memory. */ |
457 | 0 | void MVM_6model_stable_gc_free(MVMThreadContext *tc, MVMSTable *st) { |
458 | 0 | /* First have it free its repr_data if it wants. */ |
459 | 0 | if (st->REPR->gc_free_repr_data) |
460 | 0 | st->REPR->gc_free_repr_data(tc, st); |
461 | 0 |
|
462 | 0 | /* free various storage. */ |
463 | 0 | MVM_free(st->type_check_cache); |
464 | 0 | if (st->container_spec && st->container_spec->gc_free_data) |
465 | 0 | st->container_spec->gc_free_data(tc, st); |
466 | 0 | MVM_free(st->invocation_spec); |
467 | 0 | MVM_free(st->boolification_spec); |
468 | 0 | MVM_free(st->debug_name); |
469 | 0 | } |
470 | | |
471 | | /* Get the next type cache ID for a newly created STable. */ |
472 | 28.6k | MVMuint64 MVM_6model_next_type_cache_id(MVMThreadContext *tc) { |
473 | 28.6k | return (MVMuint64)MVM_add(&tc->instance->cur_type_cache_id, MVM_TYPE_CACHE_ID_INCR) + MVM_TYPE_CACHE_ID_INCR; |
474 | 28.6k | } |
475 | | |
476 | 1 | void MVM_6model_never_repossess(MVMThreadContext *tc, MVMObject *obj) { |
477 | 1 | obj->header.flags |= MVM_CF_NEVER_REPOSSESS; |
478 | 1 | } |