Coverage Report

Created: 2018-07-03 15:31

/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
}