Coverage Report

Created: 2017-04-15 07:07

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