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