/home/travis/build/MoarVM/MoarVM/src/core/args.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "moar.h" |
2 | | |
3 | 12.6M | static void init_named_used(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint16 num) { |
4 | 12.6M | if (ctx->named_used && ctx->named_used_size >= num) { /* reuse the old one */ |
5 | 19.3k | memset(ctx->named_used, 0, ctx->named_used_size * sizeof(MVMuint8)); |
6 | 19.3k | } |
7 | 12.5M | else { |
8 | 12.5M | if (ctx->named_used) { |
9 | 31.2k | MVM_fixed_size_free(tc, tc->instance->fsa, ctx->named_used_size, |
10 | 31.2k | ctx->named_used); |
11 | 31.2k | ctx->named_used = NULL; |
12 | 31.2k | } |
13 | 12.5M | ctx->named_used_size = num; |
14 | 12.5M | ctx->named_used = ctx->named_used_size |
15 | 827k | ? MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, num) |
16 | 12.5M | : NULL; |
17 | 12.5M | } |
18 | 12.6M | } |
19 | | |
20 | | /* Initialize arguments processing context. */ |
21 | 12.4M | void MVM_args_proc_init(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMCallsite *callsite, MVMRegister *args) { |
22 | 12.4M | /* Stash callsite and argument counts/pointers. */ |
23 | 12.4M | ctx->callsite = callsite; |
24 | 12.4M | /* initial counts and values; can be altered by flatteners */ |
25 | 12.4M | init_named_used(tc, ctx, MVM_callsite_num_nameds(tc, callsite)); |
26 | 12.4M | ctx->args = args; |
27 | 12.4M | ctx->num_pos = callsite->num_pos; |
28 | 12.4M | ctx->arg_count = callsite->arg_count; |
29 | 12.4M | ctx->arg_flags = NULL; /* will be populated by flattener if needed */ |
30 | 12.4M | } |
31 | | |
32 | | /* Clean up an arguments processing context. */ |
33 | 12.4M | void MVM_args_proc_cleanup(MVMThreadContext *tc, MVMArgProcContext *ctx) { |
34 | 12.4M | if (ctx->arg_flags) { |
35 | 110k | MVM_free(ctx->arg_flags); |
36 | 110k | MVM_free(ctx->args); |
37 | 110k | } |
38 | 12.4M | if (ctx->named_used) { |
39 | 788k | MVM_fixed_size_free(tc, tc->instance->fsa, ctx->named_used_size, |
40 | 788k | ctx->named_used); |
41 | 788k | ctx->named_used = NULL; |
42 | 788k | } |
43 | 12.4M | } |
44 | | |
45 | 0 | MVMCallsite * MVM_args_copy_callsite(MVMThreadContext *tc, MVMArgProcContext *ctx) { |
46 | 0 | MVMCallsite *res = MVM_calloc(1, sizeof(MVMCallsite)); |
47 | 0 | MVMCallsiteEntry *flags = NULL; |
48 | 0 | MVMCallsiteEntry *src_flags; |
49 | 0 | MVMint32 fsize; |
50 | 0 |
|
51 | 0 | if (ctx->arg_flags) { |
52 | 0 | fsize = ctx->flag_count; |
53 | 0 | src_flags = ctx->arg_flags; |
54 | 0 | } |
55 | 0 | else { |
56 | 0 | fsize = ctx->callsite->flag_count; |
57 | 0 | src_flags = ctx->callsite->arg_flags; |
58 | 0 | } |
59 | 0 |
|
60 | 0 | if (fsize) { |
61 | 0 | flags = MVM_malloc(fsize * sizeof(MVMCallsiteEntry)); |
62 | 0 | memcpy(flags, src_flags, fsize * sizeof(MVMCallsiteEntry)); |
63 | 0 | } |
64 | 0 | res->flag_count = fsize; |
65 | 0 | res->arg_flags = flags; |
66 | 0 | res->arg_count = ctx->arg_count; |
67 | 0 | res->num_pos = ctx->num_pos; |
68 | 0 | return res; |
69 | 0 | } |
70 | | |
71 | | /* Turn an argument processing context into a callsite. In the case that no |
72 | | * flattening happened, this is the original call site. Otherwise, we make |
73 | | * one up. */ |
74 | 15.5k | MVMCallsite * MVM_args_proc_to_callsite(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint8 *owns_callsite) { |
75 | 15.5k | if (ctx->arg_flags) { |
76 | 0 | *owns_callsite = 1; |
77 | 0 | return MVM_args_copy_callsite(tc, ctx); |
78 | 0 | } |
79 | 15.5k | else { |
80 | 15.5k | *owns_callsite = 0; |
81 | 15.5k | return ctx->callsite; |
82 | 15.5k | } |
83 | 15.5k | } |
84 | | |
85 | 7.75k | MVMObject * MVM_args_use_capture(MVMThreadContext *tc, MVMFrame *f) { |
86 | 7.75k | /* We used to try and avoid some GC churn by keeping one call capture per |
87 | 7.75k | * thread that was mutated. However, its lifetime was difficult to manage, |
88 | 7.75k | * leading to leaks and subtle bugs. So, we use save_capture always now |
89 | 7.75k | * for this; we may later eliminate it using escape analysis, or treat |
90 | 7.75k | * it differently in the optimizer. */ |
91 | 7.75k | return MVM_args_save_capture(tc, f); |
92 | 7.75k | } |
93 | | |
94 | 15.5k | MVMObject * MVM_args_save_capture(MVMThreadContext *tc, MVMFrame *frame) { |
95 | 15.5k | MVMObject *cc_obj = MVM_repr_alloc_init(tc, tc->instance->CallCapture); |
96 | 15.5k | MVMCallCapture *cc = (MVMCallCapture *)cc_obj; |
97 | 15.5k | |
98 | 15.5k | /* Copy the arguments. */ |
99 | 15.5k | MVMuint32 arg_size = frame->params.arg_count * sizeof(MVMRegister); |
100 | 15.5k | MVMRegister *args = MVM_malloc(arg_size); |
101 | 15.5k | memcpy(args, frame->params.args, arg_size); |
102 | 15.5k | |
103 | 15.5k | /* Create effective callsite. */ |
104 | 15.5k | cc->body.effective_callsite = MVM_args_proc_to_callsite(tc, &frame->params, &cc->body.owns_callsite); |
105 | 15.5k | |
106 | 15.5k | /* Set up the call capture. */ |
107 | 15.5k | cc->body.mode = MVM_CALL_CAPTURE_MODE_SAVE; |
108 | 15.5k | cc->body.apc = (MVMArgProcContext *)MVM_calloc(1, sizeof(MVMArgProcContext)); |
109 | 15.5k | MVM_args_proc_init(tc, cc->body.apc, cc->body.effective_callsite, args); |
110 | 15.5k | return cc_obj; |
111 | 15.5k | } |
112 | | |
113 | | static void flatten_args(MVMThreadContext *tc, MVMArgProcContext *ctx); |
114 | | |
115 | | /* Checks that the passed arguments fall within the expected arity. */ |
116 | 0 | static void arity_fail(MVMThreadContext *tc, MVMuint16 got, MVMuint16 min, MVMuint16 max) { |
117 | 0 | char *problem = got > max ? "Too many" : "Too few"; |
118 | 0 | if (min == max) |
119 | 0 | MVM_exception_throw_adhoc(tc, "%s positionals passed; expected %d argument%s but got %d", |
120 | 0 | problem, min, (min == 1 ? "" : "s"), got); |
121 | 0 | else if (max == 0xFFFF) |
122 | 0 | MVM_exception_throw_adhoc(tc, "%s positionals passed; expected at least %d arguments but got only %d", |
123 | 0 | problem, min, got); |
124 | 0 | else |
125 | 0 | MVM_exception_throw_adhoc(tc, "%s positionals passed; expected %d %s %d arguments but got %d", |
126 | 0 | problem, min, (min + 1 == max ? "or" : "to"), max, got); |
127 | 0 | } |
128 | 4.04M | void MVM_args_checkarity(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint16 min, MVMuint16 max) { |
129 | 4.04M | MVMuint16 num_pos; |
130 | 4.04M | flatten_args(tc, ctx); |
131 | 4.04M | num_pos = ctx->num_pos; |
132 | 4.04M | if (num_pos < min || num_pos > max) |
133 | 0 | arity_fail(tc, num_pos, min, max); |
134 | 4.04M | } |
135 | | |
136 | | /* Get positional arguments. */ |
137 | 8.80M | #define find_pos_arg(ctx, pos, result) do { \ |
138 | 8.80M | if (pos < ctx->num_pos) { \ |
139 | 8.08M | result.arg = ctx->args[pos]; \ |
140 | 7.88M | result.flags = (ctx->arg_flags ? ctx->arg_flags : ctx->callsite->arg_flags)[pos]; \ |
141 | 8.08M | result.exists = 1; \ |
142 | 8.08M | } \ |
143 | 714k | else { \ |
144 | 714k | result.arg.s = NULL; \ |
145 | 714k | result.exists = 0; \ |
146 | 714k | } \ |
147 | 8.80M | } while (0) |
148 | | |
149 | 149k | static MVMObject * decont_arg(MVMThreadContext *tc, MVMObject *arg) { |
150 | 149k | MVMContainerSpec const *contspec = STABLE(arg)->container_spec; |
151 | 149k | if (contspec) { |
152 | 0 | if (contspec->fetch_never_invokes) { |
153 | 0 | MVMRegister r; |
154 | 0 | contspec->fetch(tc, arg, &r); |
155 | 0 | return r.o; |
156 | 0 | } |
157 | 0 | else { |
158 | 0 | MVM_exception_throw_adhoc(tc, "Cannot auto-decontainerize argument"); |
159 | 0 | } |
160 | 0 | } |
161 | 149k | else { |
162 | 149k | return arg; |
163 | 149k | } |
164 | 149k | } |
165 | 1.45M | #define autounbox(tc, type_flag, expected, result) do { \ |
166 | 1.45M | if (result.exists && !(result.flags & type_flag)) { \ |
167 | 149k | if (result.flags & MVM_CALLSITE_ARG_OBJ) { \ |
168 | 149k | MVMObject *obj = decont_arg(tc, result.arg.o); \ |
169 | 149k | switch (type_flag) { \ |
170 | 93.4k | case MVM_CALLSITE_ARG_INT: \ |
171 | 93.4k | result.arg.i64 = MVM_repr_get_int(tc, obj); \ |
172 | 93.4k | result.flags = MVM_CALLSITE_ARG_INT; \ |
173 | 93.4k | break; \ |
174 | 0 | case MVM_CALLSITE_ARG_NUM: \ |
175 | 0 | result.arg.n64 = MVM_repr_get_num(tc, obj); \ |
176 | 0 | result.flags = MVM_CALLSITE_ARG_NUM; \ |
177 | 0 | break; \ |
178 | 55.7k | case MVM_CALLSITE_ARG_STR: \ |
179 | 55.7k | result.arg.s = MVM_repr_get_str(tc, obj); \ |
180 | 55.7k | result.flags = MVM_CALLSITE_ARG_STR; \ |
181 | 55.7k | break; \ |
182 | 0 | default: \ |
183 | 0 | MVM_exception_throw_adhoc(tc, "Failed to unbox object to " expected); \ |
184 | 149k | } \ |
185 | 149k | } \ |
186 | 149k | if (!(result.flags & type_flag)) { \ |
187 | 0 | switch (type_flag) { \ |
188 | 0 | case MVM_CALLSITE_ARG_INT: \ |
189 | 0 | switch (result.flags & MVM_CALLSITE_ARG_MASK) { \ |
190 | 0 | case MVM_CALLSITE_ARG_NUM: \ |
191 | 0 | MVM_exception_throw_adhoc(tc, "Expected native int argument, but got num"); \ |
192 | 0 | case MVM_CALLSITE_ARG_STR: \ |
193 | 0 | MVM_exception_throw_adhoc(tc, "Expected native int argument, but got str"); \ |
194 | 0 | default: \ |
195 | 0 | MVM_exception_throw_adhoc(tc, "unreachable unbox 1"); \ |
196 | 0 | } \ |
197 | 0 | break; \ |
198 | 0 | case MVM_CALLSITE_ARG_NUM: \ |
199 | 0 | switch (result.flags & MVM_CALLSITE_ARG_MASK) { \ |
200 | 0 | case MVM_CALLSITE_ARG_INT: \ |
201 | 0 | MVM_exception_throw_adhoc(tc, "Expected native num argument, but got int"); \ |
202 | 0 | case MVM_CALLSITE_ARG_STR: \ |
203 | 0 | MVM_exception_throw_adhoc(tc, "Expected native num argument, but got str"); \ |
204 | 0 | default: \ |
205 | 0 | MVM_exception_throw_adhoc(tc, "unreachable unbox 2"); \ |
206 | 0 | } \ |
207 | 0 | break; \ |
208 | 0 | case MVM_CALLSITE_ARG_STR: \ |
209 | 0 | switch (result.flags & MVM_CALLSITE_ARG_MASK) { \ |
210 | 0 | case MVM_CALLSITE_ARG_INT: \ |
211 | 0 | MVM_exception_throw_adhoc(tc, "Expected native str argument, but got int"); \ |
212 | 0 | case MVM_CALLSITE_ARG_NUM: \ |
213 | 0 | MVM_exception_throw_adhoc(tc, "Expected native str argument, but got num"); \ |
214 | 0 | default: \ |
215 | 0 | MVM_exception_throw_adhoc(tc, "unreachable unbox 3"); \ |
216 | 0 | } \ |
217 | 0 | break; \ |
218 | 0 | default: \ |
219 | 0 | MVM_exception_throw_adhoc(tc, "unreachable unbox 4"); \ |
220 | 0 | } \ |
221 | 0 | } \ |
222 | 149k | } \ |
223 | 1.45M | } while (0) |
224 | | |
225 | 7.83M | #define args_get_pos(tc, ctx, pos, required, result) do { \ |
226 | 7.83M | find_pos_arg(ctx, pos, result); \ |
227 | 7.83M | if (!result.exists && required) { \ |
228 | 0 | MVM_exception_throw_adhoc(tc, "Not enough positional arguments; needed at least %u", pos + 1); \ |
229 | 0 | } \ |
230 | 7.83M | } while (0) |
231 | | |
232 | 1.51M | #define autobox(tc, target, result, box_type_obj, is_object, set_func, dest) do { \ |
233 | 1.51M | MVMObject *box, *box_type; \ |
234 | 1.51M | if (is_object) MVM_gc_root_temp_push(tc, (MVMCollectable **)&result); \ |
235 | 1.51M | box_type = target->static_info->body.cu->body.hll_config->box_type_obj; \ |
236 | 1.51M | box = REPR(box_type)->allocate(tc, STABLE(box_type)); \ |
237 | 1.51M | MVM_gc_root_temp_push(tc, (MVMCollectable **)&box); \ |
238 | 1.51M | if (REPR(box)->initialize) \ |
239 | 0 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); \ |
240 | 1.51M | REPR(box)->box_funcs.set_func(tc, STABLE(box), box, OBJECT_BODY(box), result); \ |
241 | 1.51M | if (is_object) MVM_gc_root_temp_pop_n(tc, 2); \ |
242 | 906k | else MVM_gc_root_temp_pop(tc); \ |
243 | 1.51M | dest = box; \ |
244 | 1.51M | } while (0) |
245 | | |
246 | 144k | #define autobox_int(tc, target, result, dest) do { \ |
247 | 144k | MVMObject *box, *box_type; \ |
248 | 144k | MVMint64 result_int = result; \ |
249 | 144k | box_type = target->static_info->body.cu->body.hll_config->int_box_type; \ |
250 | 144k | dest = MVM_intcache_get(tc, box_type, result_int); \ |
251 | 144k | if (!dest) { \ |
252 | 15.6k | box = REPR(box_type)->allocate(tc, STABLE(box_type)); \ |
253 | 15.6k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&box); \ |
254 | 15.6k | if (REPR(box)->initialize) \ |
255 | 0 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); \ |
256 | 15.6k | REPR(box)->box_funcs.set_int(tc, STABLE(box), box, OBJECT_BODY(box), result_int); \ |
257 | 15.6k | MVM_gc_root_temp_pop(tc); \ |
258 | 15.6k | dest = box; \ |
259 | 15.6k | } \ |
260 | 144k | } while (0) |
261 | | |
262 | 7.21M | #define autobox_switch(tc, result) do { \ |
263 | 7.21M | if (result.exists) { \ |
264 | 6.62M | switch (result.flags & MVM_CALLSITE_ARG_MASK) { \ |
265 | 6.21M | case MVM_CALLSITE_ARG_OBJ: \ |
266 | 6.21M | break; \ |
267 | 144k | case MVM_CALLSITE_ARG_INT: \ |
268 | 144k | autobox_int(tc, tc->cur_frame, result.arg.i64, result.arg.o); \ |
269 | 144k | break; \ |
270 | 16.3k | case MVM_CALLSITE_ARG_NUM: \ |
271 | 16.3k | autobox(tc, tc->cur_frame, result.arg.n64, num_box_type, 0, set_num, result.arg.o); \ |
272 | 16.3k | break; \ |
273 | 251k | case MVM_CALLSITE_ARG_STR: \ |
274 | 251k | autobox(tc, tc->cur_frame, result.arg.s, str_box_type, 1, set_str, result.arg.o); \ |
275 | 251k | break; \ |
276 | 0 | default: \ |
277 | 0 | MVM_exception_throw_adhoc(tc, "invalid type flag"); \ |
278 | 6.62M | } \ |
279 | 6.62M | } \ |
280 | 7.21M | } while (0) |
281 | | |
282 | 6.56M | MVMArgInfo MVM_args_get_pos_obj(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint32 pos, MVMuint8 required) { |
283 | 6.56M | MVMArgInfo result; |
284 | 6.56M | args_get_pos(tc, ctx, pos, required, result); |
285 | 6.56M | autobox_switch(tc, result); |
286 | 6.56M | return result; |
287 | 6.56M | } |
288 | 462k | MVMArgInfo MVM_args_get_pos_int(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint32 pos, MVMuint8 required) { |
289 | 462k | MVMArgInfo result; |
290 | 462k | args_get_pos(tc, ctx, pos, required, result); |
291 | 462k | autounbox(tc, MVM_CALLSITE_ARG_INT, "integer", result); |
292 | 462k | return result; |
293 | 462k | } |
294 | 0 | MVMArgInfo MVM_args_get_pos_num(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint32 pos, MVMuint8 required) { |
295 | 0 | MVMArgInfo result; |
296 | 0 | args_get_pos(tc, ctx, pos, required, result); |
297 | 0 | autounbox(tc, MVM_CALLSITE_ARG_NUM, "number", result); |
298 | 0 | return result; |
299 | 0 | } |
300 | 808k | MVMArgInfo MVM_args_get_pos_str(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint32 pos, MVMuint8 required) { |
301 | 808k | MVMArgInfo result; |
302 | 808k | args_get_pos(tc, ctx, pos, required, result); |
303 | 808k | autounbox(tc, MVM_CALLSITE_ARG_STR, "string", result); |
304 | 808k | return result; |
305 | 808k | } |
306 | 0 | MVMArgInfo MVM_args_get_pos_uint(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint32 pos, MVMuint8 required) { |
307 | 0 | MVMArgInfo result; |
308 | 0 | args_get_pos(tc, ctx, pos, required, result); |
309 | 0 | autounbox(tc, MVM_CALLSITE_ARG_INT, "unsigned integer", result); |
310 | 0 | return result; |
311 | 0 | } |
312 | | |
313 | 825k | #define args_get_named(tc, ctx, name, required) do { \ |
314 | 825k | \ |
315 | 825k | MVMuint32 flag_pos, arg_pos; \ |
316 | 825k | result.arg.s = NULL; \ |
317 | 825k | result.exists = 0; \ |
318 | 825k | \ |
319 | 1.19M | for (flag_pos = arg_pos = ctx->num_pos; arg_pos < ctx->arg_count; flag_pos++, arg_pos += 2) { \ |
320 | 829k | if (MVM_string_equal(tc, ctx->args[arg_pos].s, name)) { \ |
321 | 464k | if (ctx->named_used[(arg_pos - ctx->num_pos)/2]) { \ |
322 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); \ |
323 | 0 | char *waste[] = { c_name, NULL }; \ |
324 | 0 | MVM_exception_throw_adhoc_free(tc, waste, "Named argument '%s' already used", c_name); \ |
325 | 0 | } \ |
326 | 464k | result.arg = ctx->args[arg_pos + 1]; \ |
327 | 376k | result.flags = (ctx->arg_flags ? ctx->arg_flags : ctx->callsite->arg_flags)[flag_pos]; \ |
328 | 464k | result.exists = 1; \ |
329 | 464k | ctx->named_used[(arg_pos - ctx->num_pos)/2] = 1; \ |
330 | 464k | break; \ |
331 | 464k | } \ |
332 | 829k | } \ |
333 | 825k | if (!result.exists && required) { \ |
334 | 0 | char *c_name = MVM_string_utf8_encode_C_string(tc, name); \ |
335 | 0 | char *waste[] = { c_name, NULL }; \ |
336 | 0 | MVM_exception_throw_adhoc_free(tc, waste, "Required named parameter '%s' not passed", c_name); \ |
337 | 0 | } \ |
338 | 825k | } while (0) |
339 | | |
340 | 642k | MVMArgInfo MVM_args_get_named_obj(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMString *name, MVMuint8 required) { |
341 | 642k | MVMArgInfo result; |
342 | 642k | args_get_named(tc, ctx, name, required); |
343 | 642k | autobox_switch(tc, result); |
344 | 642k | return result; |
345 | 642k | } |
346 | 32.5k | MVMArgInfo MVM_args_get_named_int(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMString *name, MVMuint8 required) { |
347 | 32.5k | MVMArgInfo result; |
348 | 32.5k | args_get_named(tc, ctx, name, required); |
349 | 32.5k | autounbox(tc, MVM_CALLSITE_ARG_INT, "integer", result); |
350 | 32.5k | return result; |
351 | 32.5k | } |
352 | 0 | MVMArgInfo MVM_args_get_named_num(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMString *name, MVMuint8 required) { |
353 | 0 | MVMArgInfo result; |
354 | 0 | args_get_named(tc, ctx, name, required); |
355 | 0 | autounbox(tc, MVM_CALLSITE_ARG_NUM, "number", result); |
356 | 0 | return result; |
357 | 0 | } |
358 | 149k | MVMArgInfo MVM_args_get_named_str(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMString *name, MVMuint8 required) { |
359 | 149k | MVMArgInfo result; |
360 | 149k | args_get_named(tc, ctx, name, required); |
361 | 149k | autounbox(tc, MVM_CALLSITE_ARG_STR, "string", result); |
362 | 149k | return result; |
363 | 149k | } |
364 | 0 | MVMArgInfo MVM_args_get_named_uint(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMString *name, MVMuint8 required) { |
365 | 0 | MVMArgInfo result; |
366 | 0 | args_get_named(tc, ctx, name, required); |
367 | 0 | autounbox(tc, MVM_CALLSITE_ARG_INT, "unsigned integer", result); |
368 | 0 | return result; |
369 | 0 | } |
370 | 2 | MVMint64 MVM_args_has_named(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMString *name) { |
371 | 2 | MVMuint32 flag_pos, arg_pos; |
372 | 3 | for (flag_pos = arg_pos = ctx->num_pos; arg_pos < ctx->arg_count; flag_pos++, arg_pos += 2) |
373 | 2 | if (MVM_string_equal(tc, ctx->args[arg_pos].s, name)) |
374 | 1 | return 1; |
375 | 1 | return 0; |
376 | 2 | } |
377 | 308k | void MVM_args_assert_nameds_used(MVMThreadContext *tc, MVMArgProcContext *ctx) { |
378 | 308k | if (ctx->named_used) { |
379 | 308k | MVMuint16 size = (ctx->arg_count - ctx->num_pos) / 2; |
380 | 308k | MVMuint16 i; |
381 | 684k | for (i = 0; i < size; i++) |
382 | 376k | if (!ctx->named_used[i]) { |
383 | 0 | char *c_param = MVM_string_utf8_encode_C_string(tc, |
384 | 0 | ctx->args[ctx->num_pos + 2 * i].s); |
385 | 0 | char *waste[] = { c_param, NULL }; |
386 | 0 | MVM_exception_throw_adhoc_free(tc, waste, |
387 | 0 | "Unexpected named argument '%s' passed", |
388 | 0 | c_param); |
389 | 0 | } |
390 | 308k | } |
391 | 308k | } |
392 | | |
393 | | /* Result setting. The frameless flag indicates that the currently |
394 | | * executing code does not have a MVMFrame of its own. */ |
395 | 292 | static MVMObject * decont_result(MVMThreadContext *tc, MVMObject *result) { |
396 | 292 | MVMContainerSpec const *contspec = STABLE(result)->container_spec; |
397 | 292 | if (contspec) { |
398 | 0 | if (contspec->fetch_never_invokes) { |
399 | 0 | MVMRegister r; |
400 | 0 | contspec->fetch(tc, result, &r); |
401 | 0 | return r.o; |
402 | 0 | } |
403 | 0 | else { |
404 | 0 | MVM_exception_throw_adhoc(tc, "Cannot auto-decontainerize return value"); |
405 | 0 | } |
406 | 0 | } |
407 | 292 | else { |
408 | 292 | return result; |
409 | 292 | } |
410 | 292 | } |
411 | 10.8M | void MVM_args_set_result_obj(MVMThreadContext *tc, MVMObject *result, MVMint32 frameless) { |
412 | 10.8M | MVMFrame *target = frameless ? tc->cur_frame : tc->cur_frame->caller; |
413 | 10.8M | if (target) { |
414 | 10.8M | switch (target->return_type) { |
415 | 389k | case MVM_RETURN_VOID: |
416 | 389k | break; |
417 | 10.4M | case MVM_RETURN_OBJ: |
418 | 10.4M | target->return_value->o = result; |
419 | 10.4M | break; |
420 | 16 | case MVM_RETURN_INT: |
421 | 16 | target->return_value->i64 = MVM_repr_get_int(tc, decont_result(tc, result)); |
422 | 16 | break; |
423 | 0 | case MVM_RETURN_NUM: |
424 | 0 | target->return_value->n64 = MVM_repr_get_num(tc, decont_result(tc, result)); |
425 | 0 | break; |
426 | 276 | case MVM_RETURN_STR: |
427 | 276 | target->return_value->s = MVM_repr_get_str(tc, decont_result(tc, result)); |
428 | 276 | break; |
429 | 0 | default: |
430 | 0 | MVM_exception_throw_adhoc(tc, "Result return coercion from obj NYI; expects type %u", target->return_type); |
431 | 10.8M | } |
432 | 10.8M | } |
433 | 10.8M | } |
434 | | |
435 | 1.08M | void MVM_args_set_result_int(MVMThreadContext *tc, MVMint64 result, MVMint32 frameless) { |
436 | 1.08M | MVMFrame *target = frameless ? tc->cur_frame : tc->cur_frame->caller; |
437 | 1.08M | if (target) { |
438 | 1.08M | switch (target->return_type) { |
439 | 104k | case MVM_RETURN_VOID: |
440 | 104k | break; |
441 | 86.6k | case MVM_RETURN_INT: |
442 | 86.6k | target->return_value->i64 = result; |
443 | 86.6k | break; |
444 | 0 | case MVM_RETURN_NUM: |
445 | 0 | target->return_value->n64 = (MVMnum64)result; |
446 | 0 | break; |
447 | 890k | case MVM_RETURN_OBJ: |
448 | 890k | autobox(tc, target, result, int_box_type, 0, set_int, target->return_value->o); |
449 | 890k | break; |
450 | 0 | default: |
451 | 0 | MVM_exception_throw_adhoc(tc, "Result return coercion from int NYI; expects type %u", target->return_type); |
452 | 1.08M | } |
453 | 1.08M | } |
454 | 1.08M | } |
455 | 962 | void MVM_args_set_result_num(MVMThreadContext *tc, MVMnum64 result, MVMint32 frameless) { |
456 | 962 | MVMFrame *target = frameless ? tc->cur_frame : tc->cur_frame->caller; |
457 | 962 | if (target) { |
458 | 962 | switch (target->return_type) { |
459 | 0 | case MVM_RETURN_VOID: |
460 | 0 | break; |
461 | 533 | case MVM_RETURN_NUM: |
462 | 533 | target->return_value->n64 = result; |
463 | 533 | break; |
464 | 0 | case MVM_RETURN_INT: |
465 | 0 | target->return_value->i64 = (MVMint64)result; |
466 | 0 | break; |
467 | 429 | case MVM_RETURN_OBJ: |
468 | 429 | autobox(tc, target, result, num_box_type, 0, set_num, target->return_value->o); |
469 | 429 | break; |
470 | 0 | default: |
471 | 0 | MVM_exception_throw_adhoc(tc, "Result return coercion from num NYI; expects type %u", target->return_type); |
472 | 962 | } |
473 | 962 | } |
474 | 962 | } |
475 | 479k | void MVM_args_set_result_str(MVMThreadContext *tc, MVMString *result, MVMint32 frameless) { |
476 | 477k | MVMFrame *target = frameless ? tc->cur_frame : tc->cur_frame->caller; |
477 | 479k | if (target) { |
478 | 479k | switch (target->return_type) { |
479 | 0 | case MVM_RETURN_VOID: |
480 | 0 | break; |
481 | 125k | case MVM_RETURN_STR: |
482 | 125k | target->return_value->s = result; |
483 | 125k | break; |
484 | 354k | case MVM_RETURN_OBJ: |
485 | 354k | autobox(tc, target, result, str_box_type, 1, set_str, target->return_value->o); |
486 | 354k | break; |
487 | 0 | default: |
488 | 0 | MVM_exception_throw_adhoc(tc, "Result return coercion from str NYI; expects type %u", target->return_type); |
489 | 479k | } |
490 | 479k | } |
491 | 479k | } |
492 | 28.0k | void MVM_args_assert_void_return_ok(MVMThreadContext *tc, MVMint32 frameless) { |
493 | 28.0k | MVMFrame *target = frameless ? tc->cur_frame : tc->cur_frame->caller; |
494 | 28.0k | if (target && target->return_type != MVM_RETURN_VOID && tc->cur_frame != tc->thread_entry_frame) |
495 | 0 | MVM_exception_throw_adhoc(tc, "Void return not allowed to context requiring a return value"); |
496 | 28.0k | } |
497 | | |
498 | 10.4k | #define box_slurpy_pos(tc, type, result, box, value, reg, box_type_obj, name, set_func) do { \ |
499 | 10.4k | type = (*(tc->interp_cu))->body.hll_config->box_type_obj; \ |
500 | 10.4k | if (!type || IS_CONCRETE(type)) { \ |
501 | 0 | MVM_exception_throw_adhoc(tc, "Missing hll " name " box type"); \ |
502 | 0 | } \ |
503 | 10.4k | box = REPR(type)->allocate(tc, STABLE(type)); \ |
504 | 10.4k | if (REPR(box)->initialize) \ |
505 | 0 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); \ |
506 | 10.4k | REPR(box)->box_funcs.set_func(tc, STABLE(box), box, \ |
507 | 10.4k | OBJECT_BODY(box), value); \ |
508 | 10.4k | reg.o = box; \ |
509 | 10.4k | REPR(result)->pos_funcs.push(tc, STABLE(result), result, \ |
510 | 10.4k | OBJECT_BODY(result), reg, MVM_reg_obj); \ |
511 | 10.4k | } while (0) |
512 | | |
513 | 133 | #define box_slurpy_pos_int(tc, type, result, box, value, reg, box_type_obj, name, set_func) do { \ |
514 | 133 | type = (*(tc->interp_cu))->body.hll_config->box_type_obj; \ |
515 | 133 | if (!type || IS_CONCRETE(type)) { \ |
516 | 0 | MVM_exception_throw_adhoc(tc, "Missing hll " name " box type"); \ |
517 | 0 | } \ |
518 | 133 | box = MVM_intcache_get(tc, type, value); \ |
519 | 133 | if (!box) { \ |
520 | 36 | box = REPR(type)->allocate(tc, STABLE(type)); \ |
521 | 36 | if (REPR(box)->initialize) \ |
522 | 0 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); \ |
523 | 36 | REPR(box)->box_funcs.set_func(tc, STABLE(box), box, \ |
524 | 36 | OBJECT_BODY(box), value); \ |
525 | 36 | } \ |
526 | 133 | reg.o = box; \ |
527 | 133 | REPR(result)->pos_funcs.push(tc, STABLE(result), result, \ |
528 | 133 | OBJECT_BODY(result), reg, MVM_reg_obj); \ |
529 | 133 | } while (0) |
530 | | |
531 | 351k | MVMObject * MVM_args_slurpy_positional(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint16 pos) { |
532 | 351k | MVMObject *type = (*(tc->interp_cu))->body.hll_config->slurpy_array_type, *result = NULL, *box = NULL; |
533 | 351k | MVMArgInfo arg_info; |
534 | 351k | MVMRegister reg; |
535 | 351k | |
536 | 351k | if (!type || IS_CONCRETE(type)) { |
537 | 0 | MVM_exception_throw_adhoc(tc, "Missing hll slurpy array type"); |
538 | 0 | } |
539 | 351k | |
540 | 351k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&type); |
541 | 351k | result = REPR(type)->allocate(tc, STABLE(type)); |
542 | 351k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&result); |
543 | 351k | if (REPR(result)->initialize) |
544 | 0 | REPR(result)->initialize(tc, STABLE(result), result, OBJECT_BODY(result)); |
545 | 351k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&box); |
546 | 351k | |
547 | 351k | find_pos_arg(ctx, pos, arg_info); |
548 | 351k | pos++; |
549 | 964k | while (arg_info.exists) { |
550 | 612k | |
551 | 612k | if (arg_info.flags & MVM_CALLSITE_ARG_FLAT) { |
552 | 0 | MVM_exception_throw_adhoc(tc, "Arg has not been flattened in slurpy_positional"); |
553 | 0 | } |
554 | 612k | |
555 | 612k | /* XXX theoretically needs to handle native arrays I guess */ |
556 | 612k | switch (arg_info.flags & MVM_CALLSITE_ARG_MASK) { |
557 | 601k | case MVM_CALLSITE_ARG_OBJ: { |
558 | 601k | MVM_repr_push_o(tc, result, arg_info.arg.o); |
559 | 601k | break; |
560 | 601k | } |
561 | 133 | case MVM_CALLSITE_ARG_INT:{ |
562 | 133 | box_slurpy_pos_int(tc, type, result, box, arg_info.arg.i64, reg, int_box_type, "int", set_int); |
563 | 133 | break; |
564 | 601k | } |
565 | 0 | case MVM_CALLSITE_ARG_NUM: { |
566 | 0 | box_slurpy_pos(tc, type, result, box, arg_info.arg.n64, reg, num_box_type, "num", set_num); |
567 | 0 | break; |
568 | 601k | } |
569 | 10.4k | case MVM_CALLSITE_ARG_STR: { |
570 | 10.4k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&arg_info.arg.s); |
571 | 10.4k | box_slurpy_pos(tc, type, result, box, arg_info.arg.s, reg, str_box_type, "str", set_str); |
572 | 10.4k | MVM_gc_root_temp_pop(tc); |
573 | 10.4k | break; |
574 | 601k | } |
575 | 0 | default: |
576 | 0 | MVM_exception_throw_adhoc(tc, "arg flag is empty in slurpy positional"); |
577 | 612k | } |
578 | 612k | |
579 | 612k | find_pos_arg(ctx, pos, arg_info); |
580 | 612k | pos++; |
581 | 612k | if (pos == 1) break; /* overflow?! */ |
582 | 612k | } |
583 | 351k | |
584 | 351k | MVM_gc_root_temp_pop_n(tc, 3); |
585 | 351k | |
586 | 351k | return result; |
587 | 351k | } |
588 | | |
589 | 46.6k | #define box_slurpy_named(tc, type, result, box, value, reg, box_type_obj, name, set_func, key) do { \ |
590 | 46.6k | type = (*(tc->interp_cu))->body.hll_config->box_type_obj; \ |
591 | 46.6k | if (!type || IS_CONCRETE(type)) { \ |
592 | 0 | MVM_exception_throw_adhoc(tc, "Missing hll " name " box type"); \ |
593 | 0 | } \ |
594 | 46.6k | box = REPR(type)->allocate(tc, STABLE(type)); \ |
595 | 46.6k | if (REPR(box)->initialize) \ |
596 | 0 | REPR(box)->initialize(tc, STABLE(box), box, OBJECT_BODY(box)); \ |
597 | 46.6k | REPR(box)->box_funcs.set_func(tc, STABLE(box), box, \ |
598 | 46.6k | OBJECT_BODY(box), value); \ |
599 | 46.6k | reg.o = box; \ |
600 | 46.6k | REPR(result)->ass_funcs.bind_key(tc, STABLE(result), result, \ |
601 | 46.6k | OBJECT_BODY(result), (MVMObject *)key, reg, MVM_reg_obj); \ |
602 | 46.6k | } while (0) |
603 | | |
604 | 275k | MVMObject * MVM_args_slurpy_named(MVMThreadContext *tc, MVMArgProcContext *ctx) { |
605 | 275k | MVMObject *type = (*(tc->interp_cu))->body.hll_config->slurpy_hash_type, *result = NULL, *box = NULL; |
606 | 275k | MVMArgInfo arg_info; |
607 | 275k | MVMuint32 flag_pos, arg_pos; |
608 | 275k | MVMRegister reg; |
609 | 275k | arg_info.exists = 0; |
610 | 275k | |
611 | 275k | if (!type || IS_CONCRETE(type)) { |
612 | 0 | MVM_exception_throw_adhoc(tc, "Missing hll slurpy hash type"); |
613 | 0 | } |
614 | 275k | |
615 | 275k | result = REPR(type)->allocate(tc, STABLE(type)); |
616 | 275k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&result); |
617 | 275k | if (REPR(result)->initialize) |
618 | 0 | REPR(result)->initialize(tc, STABLE(result), result, OBJECT_BODY(result)); |
619 | 275k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&box); |
620 | 275k | |
621 | 701k | for (flag_pos = arg_pos = ctx->num_pos; arg_pos < ctx->arg_count; flag_pos++, arg_pos += 2) { |
622 | 425k | MVMString *key; |
623 | 425k | |
624 | 425k | if (ctx->named_used[flag_pos - ctx->num_pos]) continue; |
625 | 425k | |
626 | 191k | key = ctx->args[arg_pos].s; |
627 | 191k | |
628 | 191k | if (!key || !IS_CONCRETE(key)) { |
629 | 0 | MVM_exception_throw_adhoc(tc, "slurpy hash needs concrete key"); |
630 | 0 | } |
631 | 191k | arg_info.arg = ctx->args[arg_pos + 1]; |
632 | 105k | arg_info.flags = (ctx->arg_flags ? ctx->arg_flags : ctx->callsite->arg_flags)[flag_pos]; |
633 | 191k | arg_info.exists = 1; |
634 | 191k | |
635 | 191k | if (arg_info.flags & MVM_CALLSITE_ARG_FLAT) { |
636 | 0 | MVM_exception_throw_adhoc(tc, "Arg has not been flattened in slurpy_named"); |
637 | 0 | } |
638 | 191k | |
639 | 191k | switch (arg_info.flags & MVM_CALLSITE_ARG_MASK) { |
640 | 144k | case MVM_CALLSITE_ARG_OBJ: { |
641 | 144k | REPR(result)->ass_funcs.bind_key(tc, STABLE(result), |
642 | 144k | result, OBJECT_BODY(result), (MVMObject *)key, arg_info.arg, MVM_reg_obj); |
643 | 144k | break; |
644 | 144k | } |
645 | 21.2k | case MVM_CALLSITE_ARG_INT: { |
646 | 21.2k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&key); |
647 | 21.2k | box_slurpy_named(tc, type, result, box, arg_info.arg.i64, reg, int_box_type, "int", set_int, key); |
648 | 21.2k | MVM_gc_root_temp_pop(tc); |
649 | 21.2k | break; |
650 | 144k | } |
651 | 3 | case MVM_CALLSITE_ARG_NUM: { |
652 | 3 | MVM_gc_root_temp_push(tc, (MVMCollectable **)&key); |
653 | 3 | box_slurpy_named(tc, type, result, box, arg_info.arg.n64, reg, num_box_type, "num", set_num, key); |
654 | 3 | MVM_gc_root_temp_pop(tc); |
655 | 3 | break; |
656 | 144k | } |
657 | 25.3k | case MVM_CALLSITE_ARG_STR: { |
658 | 25.3k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&key); |
659 | 25.3k | MVM_gc_root_temp_push(tc, (MVMCollectable **)&arg_info.arg.s); |
660 | 25.3k | box_slurpy_named(tc, type, result, box, arg_info.arg.s, reg, str_box_type, "str", set_str, key); |
661 | 25.3k | MVM_gc_root_temp_pop_n(tc, 2); |
662 | 25.3k | break; |
663 | 144k | } |
664 | 0 | default: |
665 | 0 | MVM_exception_throw_adhoc(tc, "arg flag is empty in slurpy named"); |
666 | 191k | } |
667 | 191k | } |
668 | 275k | |
669 | 275k | MVM_gc_root_temp_pop_n(tc, 2); |
670 | 275k | |
671 | 275k | return result; |
672 | 275k | } |
673 | | |
674 | 172k | static MVMint32 seen_name(MVMThreadContext *tc, MVMString *name, MVMRegister *new_args, MVMint32 first_named, MVMint32 num_new_args) { |
675 | 172k | MVMint32 j; |
676 | 317k | for (j = first_named; j < num_new_args; j += 2) |
677 | 144k | if (MVM_string_equal(tc, new_args[j].s, name)) |
678 | 1 | return 1; |
679 | 172k | return 0; |
680 | 172k | } |
681 | 4.04M | static void flatten_args(MVMThreadContext *tc, MVMArgProcContext *ctx) { |
682 | 4.04M | MVMArgInfo arg_info; |
683 | 4.04M | MVMint32 flag_pos = 0, arg_pos = 0, new_arg_pos = 0, |
684 | 4.04M | new_arg_flags_size = ctx->arg_count > 0x7FFF ? ctx->arg_count : ctx->arg_count * 2, |
685 | 4.04M | new_args_size = new_arg_flags_size, i, new_flag_pos = 0, new_num_pos = 0; |
686 | 4.04M | MVMCallsiteEntry *new_arg_flags; |
687 | 4.04M | MVMRegister *new_args; |
688 | 4.04M | |
689 | 4.04M | if (!ctx->callsite->has_flattening) return; |
690 | 4.04M | |
691 | 110k | new_arg_flags = MVM_malloc(new_arg_flags_size * sizeof(MVMCallsiteEntry)); |
692 | 110k | new_args = MVM_malloc(new_args_size * sizeof(MVMRegister)); |
693 | 110k | |
694 | 110k | /* First flatten any positionals in amongst any non-flattening |
695 | 110k | * positionals. */ |
696 | 279k | for ( ; arg_pos < ctx->num_pos; arg_pos++) { |
697 | 168k | |
698 | 168k | arg_info.arg = ctx->args[arg_pos]; |
699 | 168k | arg_info.flags = ctx->callsite->arg_flags[arg_pos]; |
700 | 168k | arg_info.exists = 1; |
701 | 168k | |
702 | 168k | /* Skip it if it's not flattening or is null. The bytecode loader |
703 | 168k | * verifies it's a MVM_CALLSITE_ARG_OBJ. */ |
704 | 168k | if ((arg_info.flags & MVM_CALLSITE_ARG_FLAT) && arg_info.arg.o) { |
705 | 35.3k | MVMObject *list = arg_info.arg.o; |
706 | 35.3k | MVMint64 count = REPR(list)->elems(tc, STABLE(list), list, OBJECT_BODY(list)); |
707 | 35.3k | MVMStorageSpec lss = REPR(list)->pos_funcs.get_elem_storage_spec(tc, STABLE(list)); |
708 | 35.3k | |
709 | 35.3k | if ((MVMint64)new_arg_pos + count > 0xFFFF) { |
710 | 0 | MVM_exception_throw_adhoc(tc, "Too many arguments in flattening array."); |
711 | 0 | } |
712 | 35.3k | |
713 | 101k | for (i = 0; i < count; i++) { |
714 | 66.1k | if (new_arg_pos == new_args_size) { |
715 | 122 | new_args = MVM_realloc(new_args, (new_args_size *= 2) * sizeof(MVMRegister)); |
716 | 122 | } |
717 | 66.1k | if (new_flag_pos == new_arg_flags_size) { |
718 | 122 | new_arg_flags = MVM_realloc(new_arg_flags, (new_arg_flags_size *= 2) * sizeof(MVMCallsiteEntry)); |
719 | 122 | } |
720 | 66.1k | |
721 | 66.1k | switch (lss.inlineable ? lss.boxed_primitive : 0) { |
722 | 3 | case MVM_STORAGE_SPEC_BP_INT: |
723 | 3 | (new_args + new_arg_pos++)->i64 = MVM_repr_at_pos_i(tc, list, i); |
724 | 3 | new_arg_flags[new_flag_pos++] = MVM_CALLSITE_ARG_INT; |
725 | 3 | break; |
726 | 0 | case MVM_STORAGE_SPEC_BP_NUM: |
727 | 0 | (new_args + new_arg_pos++)->n64 = MVM_repr_at_pos_n(tc, list, i); |
728 | 0 | new_arg_flags[new_flag_pos++] = MVM_CALLSITE_ARG_NUM; |
729 | 0 | break; |
730 | 0 | case MVM_STORAGE_SPEC_BP_STR: |
731 | 0 | (new_args + new_arg_pos++)->s = MVM_repr_at_pos_s(tc, list, i); |
732 | 0 | new_arg_flags[new_flag_pos++] = MVM_CALLSITE_ARG_STR; |
733 | 0 | break; |
734 | 66.1k | default: |
735 | 66.1k | (new_args + new_arg_pos++)->o = MVM_repr_at_pos_o(tc, list, i); |
736 | 66.1k | new_arg_flags[new_flag_pos++] = MVM_CALLSITE_ARG_OBJ; |
737 | 66.1k | break; |
738 | 66.1k | } |
739 | 66.1k | } |
740 | 35.3k | } |
741 | 133k | else { |
742 | 133k | if (new_arg_pos == new_args_size) { |
743 | 0 | new_args = MVM_realloc(new_args, (new_args_size *= 2) * sizeof(MVMRegister)); |
744 | 0 | } |
745 | 133k | if (new_flag_pos == new_arg_flags_size) { |
746 | 0 | new_arg_flags = MVM_realloc(new_arg_flags, (new_arg_flags_size *= 2) * sizeof(MVMCallsiteEntry)); |
747 | 0 | } |
748 | 133k | |
749 | 133k | *(new_args + new_arg_pos++) = arg_info.arg; |
750 | 133k | new_arg_flags[new_flag_pos++] = arg_info.flags; |
751 | 133k | } |
752 | 168k | } |
753 | 110k | new_num_pos = new_arg_pos; |
754 | 110k | |
755 | 110k | /* Then flatten in any nameds, amongst non-flattening nameds, starting |
756 | 110k | * from the right and skipping duplicates. */ |
757 | 110k | flag_pos = ctx->callsite->flag_count; |
758 | 110k | arg_pos = ctx->arg_count; |
759 | 265k | while (flag_pos > ctx->num_pos) { |
760 | 154k | flag_pos--; |
761 | 154k | if (ctx->callsite->arg_flags[flag_pos] & MVM_CALLSITE_ARG_FLAT_NAMED) { |
762 | 75.5k | arg_info.flags = ctx->callsite->arg_flags[flag_pos]; |
763 | 75.5k | arg_pos--; |
764 | 75.5k | arg_info.arg = ctx->args[arg_pos]; |
765 | 75.5k | |
766 | 75.5k | if (arg_info.arg.o && REPR(arg_info.arg.o)->ID == MVM_REPR_ID_MVMHash) { |
767 | 75.5k | MVMHashBody *body = &((MVMHash *)arg_info.arg.o)->body; |
768 | 75.5k | MVMHashEntry *current, *tmp; |
769 | 75.5k | unsigned bucket_tmp; |
770 | 75.5k | |
771 | 93.4k | HASH_ITER(hash_handle, body->hash_head, current, tmp, bucket_tmp) { |
772 | 93.4k | MVMString *arg_name = MVM_HASH_KEY(current); |
773 | 93.4k | if (!seen_name(tc, arg_name, new_args, new_num_pos, new_arg_pos)) { |
774 | 93.4k | if (new_arg_pos + 1 >= new_args_size) { |
775 | 19.0k | new_args = MVM_realloc(new_args, (new_args_size *= 2) * sizeof(MVMRegister)); |
776 | 19.0k | } |
777 | 93.4k | if (new_flag_pos == new_arg_flags_size) { |
778 | 1.33k | new_arg_flags = MVM_realloc(new_arg_flags, (new_arg_flags_size *= 2) * sizeof(MVMCallsiteEntry)); |
779 | 1.33k | } |
780 | 93.4k | |
781 | 93.4k | (new_args + new_arg_pos++)->s = arg_name; |
782 | 93.4k | (new_args + new_arg_pos++)->o = current->value; |
783 | 93.4k | new_arg_flags[new_flag_pos++] = MVM_CALLSITE_ARG_NAMED | MVM_CALLSITE_ARG_OBJ; |
784 | 93.4k | } |
785 | 93.4k | } |
786 | 75.5k | } |
787 | 0 | else if (arg_info.arg.o) { |
788 | 0 | MVM_exception_throw_adhoc(tc, "flattening of other hash reprs NYI."); |
789 | 0 | } |
790 | 75.5k | } |
791 | 79.4k | else { |
792 | 79.4k | arg_pos -= 2; |
793 | 79.4k | if (!seen_name(tc, (ctx->args + arg_pos)->s, new_args, new_num_pos, new_arg_pos)) { |
794 | 79.4k | if (new_arg_pos + 1 >= new_args_size) { |
795 | 135 | new_args = MVM_realloc(new_args, (new_args_size *= 2) * sizeof(MVMRegister)); |
796 | 135 | } |
797 | 79.4k | if (new_flag_pos == new_arg_flags_size) { |
798 | 1 | new_arg_flags = MVM_realloc(new_arg_flags, (new_arg_flags_size *= 2) * sizeof(MVMCallsiteEntry)); |
799 | 1 | } |
800 | 79.4k | |
801 | 79.4k | (new_args + new_arg_pos++)->s = (ctx->args + arg_pos)->s; |
802 | 79.4k | *(new_args + new_arg_pos++) = *(ctx->args + arg_pos + 1); |
803 | 79.4k | new_arg_flags[new_flag_pos++] = ctx->callsite->arg_flags[flag_pos]; |
804 | 79.4k | } |
805 | 79.4k | } |
806 | 154k | } |
807 | 110k | |
808 | 110k | init_named_used(tc, ctx, (new_arg_pos - new_num_pos) / 2); |
809 | 110k | ctx->args = new_args; |
810 | 110k | ctx->arg_count = new_arg_pos; |
811 | 110k | ctx->num_pos = new_num_pos; |
812 | 110k | ctx->arg_flags = new_arg_flags; |
813 | 110k | ctx->flag_count = new_flag_pos; |
814 | 110k | } |
815 | | |
816 | | /* Does the common setup work when we jump the interpreter into a chosen |
817 | | * call from C-land. */ |
818 | 212k | void MVM_args_setup_thunk(MVMThreadContext *tc, MVMRegister *res_reg, MVMReturnType return_type, MVMCallsite *callsite) { |
819 | 212k | MVMFrame *cur_frame = tc->cur_frame; |
820 | 212k | cur_frame->return_value = res_reg; |
821 | 212k | cur_frame->return_type = return_type; |
822 | 212k | cur_frame->return_address = *(tc->interp_cur_op); |
823 | 212k | cur_frame->cur_args_callsite = callsite; |
824 | 212k | } |
825 | | |
826 | | /* Custom bind failure handling. Invokes the HLL's bind failure handler, with |
827 | | * an argument capture */ |
828 | 1 | static void bind_error_return(MVMThreadContext *tc, void *sr_data) { |
829 | 1 | MVMRegister *r = (MVMRegister *)sr_data; |
830 | 1 | MVMObject *res = r->o; |
831 | 1 | MVM_free(r); |
832 | 1 | if (tc->cur_frame->caller) |
833 | 1 | MVM_args_set_result_obj(tc, res, 0); |
834 | 1 | else |
835 | 0 | MVM_exception_throw_adhoc(tc, "No caller to return to after bind_error"); |
836 | 1 | MVM_frame_try_return(tc); |
837 | 1 | } |
838 | 0 | static void mark_sr_data(MVMThreadContext *tc, MVMFrame *frame, MVMGCWorklist *worklist) { |
839 | 0 | MVMRegister *r = (MVMRegister *)frame->special_return_data; |
840 | 0 | MVM_gc_worklist_add(tc, worklist, &r->o); |
841 | 0 | } |
842 | 2 | void MVM_args_bind_failed(MVMThreadContext *tc) { |
843 | 2 | MVMObject *bind_error; |
844 | 2 | MVMRegister *res; |
845 | 2 | MVMCallsite *inv_arg_callsite; |
846 | 2 | MVMFrame *cur_frame = tc->cur_frame; |
847 | 2 | |
848 | 2 | /* Create a new call capture object. */ |
849 | 2 | MVMObject *cc_obj = MVM_repr_alloc_init(tc, tc->instance->CallCapture); |
850 | 2 | MVMCallCapture *cc = (MVMCallCapture *)cc_obj; |
851 | 2 | |
852 | 2 | /* Copy the arguments. */ |
853 | 2 | MVMuint32 arg_size = tc->cur_frame->params.arg_count * sizeof(MVMRegister); |
854 | 2 | MVMRegister *args = MVM_malloc(arg_size); |
855 | 2 | memcpy(args, tc->cur_frame->params.args, arg_size); |
856 | 2 | |
857 | 2 | /* Create effective callsite. */ |
858 | 2 | cc->body.effective_callsite = MVM_args_proc_to_callsite(tc, &tc->cur_frame->params, &cc->body.owns_callsite); |
859 | 2 | |
860 | 2 | /* Set up the call capture. */ |
861 | 2 | cc->body.mode = MVM_CALL_CAPTURE_MODE_SAVE; |
862 | 2 | cc->body.apc = (MVMArgProcContext *)MVM_calloc(1, sizeof(MVMArgProcContext)); |
863 | 2 | MVM_args_proc_init(tc, cc->body.apc, cc->body.effective_callsite, args); |
864 | 2 | |
865 | 2 | /* Invoke the HLL's bind failure handler. */ |
866 | 2 | bind_error = MVM_hll_current(tc)->bind_error; |
867 | 2 | if (!bind_error) |
868 | 0 | MVM_exception_throw_adhoc(tc, "Bind error occurred, but HLL has no handler"); |
869 | 2 | bind_error = MVM_frame_find_invokee(tc, bind_error, NULL); |
870 | 2 | res = MVM_calloc(1, sizeof(MVMRegister)); |
871 | 2 | inv_arg_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG); |
872 | 2 | MVM_args_setup_thunk(tc, res, MVM_RETURN_OBJ, inv_arg_callsite); |
873 | 2 | cur_frame->special_return = bind_error_return; |
874 | 2 | cur_frame->special_return_data = res; |
875 | 2 | cur_frame->mark_special_return_data = mark_sr_data; |
876 | 2 | cur_frame->args[0].o = cc_obj; |
877 | 2 | STABLE(bind_error)->invoke(tc, bind_error, inv_arg_callsite, cur_frame->args); |
878 | 2 | } |