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