Coverage Report

Created: 2018-06-21 18:56

/home/travis/build/MoarVM/MoarVM/src/spesh/args.c
Line
Count
Source (jump to first uncovered line)
1
#include "moar.h"
2
3
/* Maximum number of positional args we'll consider for optimization purposes. */
4
58.0k
#define MAX_POS_ARGS 8
5
6
/* Maximum number of named args we'll consider for optimization purposes. */
7
25.4k
#define MAX_NAMED_ARGS 8
8
9
/* Adds facts for an object arg. */
10
static void add_facts(MVMThreadContext *tc, MVMSpeshGraph *g, MVMint32 slot,
11
16.5k
                      MVMSpeshStatsType type_tuple_entry, MVMSpeshIns *arg_ins) {
12
16.5k
    /* Add appropriate facts from the arg type tuple. */
13
16.5k
    MVMint16 orig = arg_ins->operands[0].reg.orig;
14
16.5k
    MVMint16 i = arg_ins->operands[0].reg.i;
15
16.5k
    MVMObject *type = type_tuple_entry.type;
16
16.5k
    g->facts[orig][i].type = type;
17
16.5k
    g->facts[orig][i].flags |= MVM_SPESH_FACT_KNOWN_TYPE;
18
16.5k
    if (type_tuple_entry.type_concrete) {
19
14.6k
        g->facts[orig][i].flags |= MVM_SPESH_FACT_CONCRETE;
20
14.6k
        if (!type->st->container_spec)
21
14.6k
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONTED;
22
14.6k
    }
23
1.95k
    else {
24
1.95k
        g->facts[orig][i].flags |= MVM_SPESH_FACT_TYPEOBJ | MVM_SPESH_FACT_DECONTED;
25
1.95k
    }
26
16.5k
27
16.5k
    /* Add any decontainerized type info. */
28
16.5k
    if (type_tuple_entry.decont_type) {
29
0
        g->facts[orig][i].decont_type  = type_tuple_entry.decont_type;
30
0
        g->facts[orig][i].flags       |= MVM_SPESH_FACT_KNOWN_DECONT_TYPE;
31
0
        if (type_tuple_entry.decont_type_concrete)
32
0
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONT_CONCRETE;
33
0
        else
34
0
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONT_TYPEOBJ;
35
0
        if (type_tuple_entry.rw_cont)
36
0
            g->facts[orig][i].flags |= MVM_SPESH_FACT_RW_CONT;
37
0
    }
38
16.5k
}
39
40
/* Handles a pos arg that needs unboxing. */
41
static void pos_unbox(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
42
0
                      MVMSpeshIns *ins, const MVMOpInfo *unbox_op) {
43
0
    MVMSpeshOperand  temp  = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
44
0
    MVMSpeshIns     *unbox = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
45
0
    unbox->info            = unbox_op;
46
0
    unbox->operands        = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
47
0
    unbox->operands[0]     = ins->operands[0];
48
0
    unbox->operands[1]     = temp;
49
0
    ins->info              = MVM_op_get_op(MVM_OP_sp_getarg_o);
50
0
    ins->operands[0]       = temp;
51
0
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, unbox);
52
0
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp);
53
0
}
54
55
/* Handles a pos arg that needs boxing. */
56
static void pos_box(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
57
                    MVMSpeshIns *ins, const MVMOpInfo *hlltype_op, const MVMOpInfo *box_op,
58
928
                    const MVMOpInfo *arg_op, MVMuint8 kind) {
59
928
    MVMSpeshOperand  temp_bt, temp_arg;
60
928
    MVMSpeshIns     *hlltype, *box;
61
928
62
928
    /* Add HLL type op. */
63
928
    temp_bt              = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
64
928
    hlltype              = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
65
928
    hlltype->info        = hlltype_op;
66
928
    hlltype->operands    = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand));
67
928
    hlltype->operands[0] = temp_bt;
68
928
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, hlltype);
69
928
70
928
    /* Add box op. */
71
928
    temp_arg         = MVM_spesh_manipulate_get_temp_reg(tc, g, kind);
72
928
    box              = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
73
928
    box->info        = box_op;
74
928
    box->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
75
928
    box->operands[0] = ins->operands[0];
76
928
    box->operands[1] = temp_arg;
77
928
    box->operands[2] = temp_bt;
78
928
    MVM_spesh_manipulate_insert_ins(tc, bb, hlltype, box);
79
928
80
928
    /* Update instruction to receive unboxed arg. */
81
928
    ins->info        = arg_op;
82
928
    ins->operands[0] = temp_arg;
83
928
84
928
    /* Release temporary registers. */
85
928
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp_bt);
86
928
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp_arg);
87
928
}
88
89
/* Gets the primitive boxed by a type. */
90
190
static MVMuint16 prim_spec(MVMThreadContext *tc, MVMSpeshStatsType *type_tuple, MVMint32 i) {
91
0
    MVMObject *type = type_tuple ? type_tuple[i].type : NULL;
92
190
    return type
93
0
        ? REPR(type)->get_storage_spec(tc, STABLE(type))->boxed_primitive
94
190
        : 0;
95
190
}
96
97
/* Puts a single named argument into a slurpy hash, boxing if needed. */
98
static void slurp_named_arg(MVMThreadContext *tc, MVMSpeshGraph *g, MVMSpeshBB *bb,
99
85
                            MVMSpeshIns *hash_ins, MVMint32 named_idx) {
100
85
    MVMSpeshIns *key_ins;
101
85
102
85
    /* Look up arg flags and name, and compute index. */
103
85
    MVMCallsiteFlags flags = g->cs->arg_flags[g->cs->num_pos + named_idx];
104
85
    MVMString *name = g->cs->arg_names[named_idx];
105
85
    MVMuint16 arg_idx = g->cs->num_pos + 2 * named_idx + 1;
106
85
107
85
    /* Allocate temporary registers for the key and value. */
108
85
    MVMSpeshOperand key_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_str);
109
85
    MVMSpeshOperand value_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
110
85
111
85
    /* Insert bind key instruction after slurpy hash creation instruction (we
112
85
     * do it first as below we prepend instructions to obtain the key and the
113
85
     * value. */
114
85
    MVMSpeshIns *bindkey_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
115
85
    bindkey_ins->info = MVM_op_get_op(MVM_OP_bindkey_o);
116
85
    bindkey_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
117
85
    bindkey_ins->operands[0] = hash_ins->operands[0];
118
85
    bindkey_ins->operands[1] = key_temp;
119
85
    bindkey_ins->operands[2] = value_temp;
120
85
    MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, bindkey_ins);
121
85
122
85
    /* Instruction to get value depends on argument type. */
123
85
    if ((flags & MVM_CALLSITE_ARG_MASK) == MVM_CALLSITE_ARG_OBJ) {
124
60
        /* It's already a boxed object, so just fetch it into the value
125
60
         * register. */
126
60
        MVMSpeshIns *fetch_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
127
60
        fetch_ins->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
128
60
        fetch_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
129
60
        fetch_ins->operands[0] = value_temp;
130
60
        fetch_ins->operands[1].lit_ui16 = arg_idx;
131
60
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, fetch_ins);
132
60
    }
133
25
    else {
134
25
        MVMSpeshIns *box_ins, *hlltype_ins, *fetch_ins;
135
25
136
25
        /* We need to box it. Get a temporary register to box into. To
137
25
         * only use one extra register, we will re-use the temp value
138
25
         * one to load the box type into, and only add a temporary for. */
139
25
        MVMSpeshOperand unboxed_temp;
140
25
        MVMuint16 box_op;
141
25
        MVMuint16 hlltype_op;
142
25
        MVMuint16 fetch_op;
143
25
        switch (flags & MVM_CALLSITE_ARG_MASK) {
144
23
            case MVM_CALLSITE_ARG_INT:
145
23
                unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_int64);
146
23
                box_op = MVM_OP_box_i;
147
23
                hlltype_op = MVM_OP_hllboxtype_i;
148
23
                fetch_op = MVM_OP_sp_getarg_i;
149
23
                break;
150
0
            case MVM_CALLSITE_ARG_NUM:
151
0
                unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_num64);
152
0
                box_op = MVM_OP_box_n;
153
0
                hlltype_op = MVM_OP_hllboxtype_n;
154
0
                fetch_op = MVM_OP_sp_getarg_n;
155
0
                break;
156
2
            case MVM_CALLSITE_ARG_STR:
157
2
                unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_str);
158
2
                box_op = MVM_OP_box_s;
159
2
                hlltype_op = MVM_OP_hllboxtype_s;
160
2
                fetch_op = MVM_OP_sp_getarg_s;
161
2
                break;
162
0
            default:
163
0
                MVM_panic(1, "Spesh args: unexpected named argument type %d", flags);
164
25
        }
165
25
166
25
        /* Emit instruction to box value. */
167
25
        box_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
168
25
        box_ins->info = MVM_op_get_op(box_op);
169
25
        box_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
170
25
        box_ins->operands[0] = value_temp;
171
25
        box_ins->operands[1] = unboxed_temp;
172
25
        box_ins->operands[2] = value_temp;
173
25
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, box_ins);
174
25
175
25
        /* Prepend the instruction get box type. */
176
25
        hlltype_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
177
25
        hlltype_ins->info = MVM_op_get_op(hlltype_op);
178
25
        hlltype_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand));
179
25
        hlltype_ins->operands[0] = value_temp;
180
25
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, hlltype_ins);
181
25
182
25
        /* Prepend fetch instruction. */
183
25
        fetch_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
184
25
        fetch_ins->info = MVM_op_get_op(fetch_op);
185
25
        fetch_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
186
25
        fetch_ins->operands[0] = unboxed_temp;
187
25
        fetch_ins->operands[1].lit_ui16 = arg_idx;
188
25
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, fetch_ins);
189
25
190
25
        /* Can release the temporary register now. */
191
25
        MVM_spesh_manipulate_release_temp_reg(tc, g, unboxed_temp);
192
25
    }
193
85
194
85
    /* Insert key fetching instruciton; we just store the string in a spesh
195
85
     * slot. */
196
85
    key_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
197
85
    key_ins->info = MVM_op_get_op(MVM_OP_sp_getspeshslot);
198
85
    key_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
199
85
    key_ins->operands[0] = key_temp;
200
85
    key_ins->operands[1].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)name);
201
85
    MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, key_ins);
202
85
203
85
    /* Release temporary registers after. */
204
85
    MVM_spesh_manipulate_release_temp_reg(tc, g, key_temp);
205
85
    MVM_spesh_manipulate_release_temp_reg(tc, g, value_temp);
206
85
}
207
208
/* Takes information about the incoming callsite and arguments, and performs
209
 * various optimizations based on that information. */
210
void MVM_spesh_args(MVMThreadContext *tc, MVMSpeshGraph *g, MVMCallsite *cs,
211
11.9k
                    MVMSpeshStatsType *type_tuple) {
212
11.9k
    /* We need to identify the various arg-related instructions in the graph,
213
11.9k
     * then manipulate them as a whole. */
214
11.9k
    MVMSpeshIns  *checkarity_ins     = NULL;
215
11.9k
    MVMSpeshBB   *checkarity_bb      = NULL;
216
11.9k
    MVMSpeshIns  *paramnamesused_ins = NULL;
217
11.9k
    MVMSpeshBB   *paramnamesused_bb  = NULL;
218
11.9k
    MVMSpeshIns  *param_sn_ins       = NULL;
219
11.9k
    MVMSpeshBB   *param_sn_bb        = NULL;
220
11.9k
221
11.9k
    MVMSpeshIns **pos_ins    = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshIns *));
222
11.9k
    MVMSpeshBB  **pos_bb     = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshBB *));
223
11.9k
    MVMuint8     *pos_added  = MVM_calloc(MAX_POS_ARGS, sizeof(MVMuint8));
224
11.9k
    MVMSpeshIns **named_ins  = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *));
225
11.9k
    MVMSpeshBB  **named_bb   = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshBB *));
226
11.9k
    MVMint32      req_max    = -1;
227
11.9k
    MVMint32      opt_min    = -1;
228
11.9k
    MVMint32      opt_max    = -1;
229
11.9k
    MVMint32      num_named  = 0;
230
11.9k
    MVMint32      named_used = 0;
231
11.9k
    MVMint32      named_passed = (cs->arg_count - cs->num_pos) / 2;
232
11.9k
    MVMint32      cs_flags   = cs->num_pos + named_passed;
233
11.9k
    MVMint32      cur_ins = 0;
234
11.9k
235
11.9k
    /* We use a bit field to track named argument use; on deopt we will put it
236
11.9k
     * into the deoptimized frame. */
237
11.9k
    MVMuint64 named_used_bit_field = 0;
238
11.9k
239
11.9k
    MVMSpeshBB *bb = g->entry;
240
11.9k
    g->cs = cs;
241
11.9k
242
11.9k
    /* Walk through the graph, looking for arg related instructions. */
243
435k
    while (bb) {
244
423k
        MVMSpeshIns *ins = bb->first_ins;
245
2.44M
        while (ins) {
246
2.02M
            switch (ins->info->opcode) {
247
11.9k
            case MVM_OP_checkarity:
248
11.9k
                if (checkarity_ins)
249
0
                    goto cleanup; /* Dupe; weird; bail out! */
250
11.9k
                checkarity_ins = ins;
251
11.9k
                checkarity_bb  = bb;
252
11.9k
                break;
253
20.4k
            case MVM_OP_param_rp_i:
254
20.4k
            case MVM_OP_param_rp_n:
255
20.4k
            case MVM_OP_param_rp_s:
256
20.4k
            case MVM_OP_param_rp_o: {
257
20.4k
                /* Required positional. */
258
20.4k
                MVMint16 idx = ins->operands[1].lit_i16;
259
20.4k
                if (idx < 0 || idx >= MAX_POS_ARGS)
260
0
                    goto cleanup;
261
20.4k
                if (pos_ins[idx]) /* Dupe; weird. */
262
0
                    goto cleanup;
263
20.4k
                pos_ins[idx] = ins;
264
20.4k
                pos_bb[idx]  = bb;
265
20.4k
                if (idx > req_max)
266
20.4k
                    req_max = idx;
267
20.4k
                break;
268
20.4k
            }
269
1.86k
            case MVM_OP_param_op_i:
270
1.86k
            case MVM_OP_param_op_n:
271
1.86k
            case MVM_OP_param_op_s:
272
1.86k
            case MVM_OP_param_op_o: {
273
1.86k
                /* Optional Positional int/num/string/object */
274
1.86k
                MVMint16 idx = ins->operands[1].lit_i16;
275
1.86k
                if (idx < 0 || idx >= MAX_POS_ARGS)
276
0
                    goto cleanup;
277
1.86k
                if (pos_ins[idx]) /* Dupe; weird. */
278
0
                    goto cleanup;
279
1.86k
                pos_ins[idx] = ins;
280
1.86k
                pos_bb[idx]  = bb;
281
1.86k
                if (idx > opt_max)
282
1.86k
                    opt_max = idx;
283
1.86k
                if (opt_min == -1 || idx < opt_min)
284
1.86k
                    opt_min = idx;
285
1.86k
                break;
286
1.86k
            }
287
1.67k
            case MVM_OP_param_on_i:
288
1.67k
            case MVM_OP_param_on_n:
289
1.67k
            case MVM_OP_param_on_s:
290
1.67k
            case MVM_OP_param_on_o:
291
1.67k
            case MVM_OP_param_rn_i:
292
1.67k
            case MVM_OP_param_rn_n:
293
1.67k
            case MVM_OP_param_rn_s:
294
1.67k
            case MVM_OP_param_rn_o:
295
1.67k
                /* Named (optional or required). */
296
1.67k
                if (num_named == MAX_NAMED_ARGS)
297
0
                    goto cleanup;
298
1.67k
                named_ins[num_named] = ins;
299
1.67k
                named_bb[num_named]  = bb;
300
1.67k
                num_named++;
301
1.67k
                break;
302
205
            case MVM_OP_param_sp:
303
205
                break;
304
307
            case MVM_OP_param_sn:
305
307
                param_sn_ins = ins;
306
307
                param_sn_bb = bb;
307
307
                break;
308
0
            case MVM_OP_usecapture:
309
0
            case MVM_OP_savecapture:
310
0
                /* Require full args processing context for now; bail. */
311
0
                goto cleanup;
312
11.6k
            case MVM_OP_paramnamesused:
313
11.6k
                if (paramnamesused_ins)
314
0
                    goto cleanup; /* Dupe; weird; bail out! */
315
11.6k
                paramnamesused_ins = ins;
316
11.6k
                paramnamesused_bb  = bb;
317
11.6k
                break;
318
0
            case MVM_OP_param_rn2_i:
319
0
            case MVM_OP_param_rn2_n:
320
0
            case MVM_OP_param_rn2_s:
321
0
            case MVM_OP_param_rn2_o:
322
0
            case MVM_OP_param_on2_i:
323
0
            case MVM_OP_param_on2_n:
324
0
            case MVM_OP_param_on2_s:
325
0
            case MVM_OP_param_on2_o:
326
0
            case MVM_OP_param_rp_u:
327
0
            case MVM_OP_param_op_u:
328
0
            case MVM_OP_param_rn_u:
329
0
            case MVM_OP_param_on_u:
330
0
            case MVM_OP_param_rn2_u:
331
0
            case MVM_OP_param_on2_u:
332
0
                /* Don't understand how to specialize these yet. */
333
0
                goto cleanup;
334
1.97M
            default:
335
1.97M
                break;
336
2.02M
            }
337
2.02M
            cur_ins++;
338
2.02M
            ins = ins->next;
339
2.02M
        }
340
423k
        bb = bb->linear_next;
341
423k
    }
342
11.9k
343
11.9k
    /* If we didn't find a checkarity instruction, bail. */
344
11.9k
    if (!checkarity_ins)
345
0
        goto cleanup;
346
11.9k
347
11.9k
    /* If required and optional aren't contiguous, bail. */
348
11.9k
    if (opt_min >= 0 && req_max + 1 != opt_min)
349
0
        goto cleanup;
350
11.9k
351
11.9k
    /* If the number of passed args is in range... */
352
11.9k
    if (cs->num_pos >= req_max + 1 && (opt_max < 0 || cs->num_pos <= opt_max + 1)) {
353
11.9k
        /* Ensure we've got all the arg fetch instructions we need, and that
354
11.9k
         * types match or it's a box/unbox. */
355
11.9k
        MVMint32 i;
356
33.0k
        for (i = 0; i < cs->num_pos; i++) {
357
21.4k
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
358
21.4k
            if (!pos_ins[i])
359
133
                goto cleanup;
360
21.2k
            switch (pos_ins[i]->info->opcode) {
361
1.16k
            case MVM_OP_param_rp_i:
362
1.16k
            case MVM_OP_param_op_i:
363
1.16k
                if (arg_flag != MVM_CALLSITE_ARG_INT)
364
149
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
365
149
                            prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_INT)
366
149
                        goto cleanup;
367
1.01k
                break;
368
0
            case MVM_OP_param_rp_n:
369
0
            case MVM_OP_param_op_n:
370
0
                if (arg_flag != MVM_CALLSITE_ARG_NUM)
371
0
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
372
0
                            prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_NUM)
373
0
                        goto cleanup;
374
0
                break;
375
1.79k
            case MVM_OP_param_rp_s:
376
1.79k
            case MVM_OP_param_op_s:
377
1.79k
                if (arg_flag != MVM_CALLSITE_ARG_STR)
378
28
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
379
28
                            prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_STR)
380
28
                        goto cleanup;
381
1.77k
                break;
382
18.3k
            case MVM_OP_param_rp_o:
383
18.3k
            case MVM_OP_param_op_o:
384
18.3k
                if (arg_flag != MVM_CALLSITE_ARG_OBJ && arg_flag != MVM_CALLSITE_ARG_INT &&
385
566
                    arg_flag != MVM_CALLSITE_ARG_NUM && arg_flag != MVM_CALLSITE_ARG_STR)
386
0
                    goto cleanup;
387
18.3k
                break;
388
0
            default:
389
0
                break;
390
21.2k
            }
391
21.2k
        }
392
11.9k
393
11.9k
        /* We can optimize. Toss checkarity. */
394
11.6k
        MVM_spesh_manipulate_delete_ins(tc, g, checkarity_bb, checkarity_ins);
395
11.6k
396
11.6k
        /* Re-write the passed required positionals to spesh ops, and add any
397
11.6k
         * facts. */
398
32.3k
        for (i = 0; i < cs->num_pos; i++) {
399
20.7k
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
400
20.7k
            switch (pos_ins[i]->info->opcode) {
401
1.01k
            case MVM_OP_param_rp_i:
402
1.01k
            case MVM_OP_param_op_i:
403
1.01k
                if (arg_flag == MVM_CALLSITE_ARG_INT) {
404
1.01k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
405
1.01k
                }
406
0
                else {
407
0
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
408
0
                    pos_added[i]++;
409
0
                    if (type_tuple && type_tuple[i].type)
410
0
                        add_facts(tc, g, i, type_tuple[i], pos_ins[i]);
411
0
                }
412
1.01k
                break;
413
0
            case MVM_OP_param_rp_n:
414
0
            case MVM_OP_param_op_n:
415
0
                if (arg_flag == MVM_CALLSITE_ARG_NUM) {
416
0
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
417
0
                }
418
0
                else {
419
0
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
420
0
                    pos_added[i]++;
421
0
                    if (type_tuple && type_tuple[i].type)
422
0
                        add_facts(tc, g, i, type_tuple[i], pos_ins[i]);
423
0
                }
424
0
                break;
425
1.71k
            case MVM_OP_param_rp_s:
426
1.71k
            case MVM_OP_param_op_s:
427
1.71k
                if (arg_flag == MVM_CALLSITE_ARG_STR) {
428
1.71k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
429
1.71k
                }
430
0
                else {
431
0
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
432
0
                    pos_added[i]++;
433
0
                    if (type_tuple && type_tuple[i].type)
434
0
                        add_facts(tc, g, i, type_tuple[i], pos_ins[i]);
435
0
                }
436
1.71k
                break;
437
17.9k
            case MVM_OP_param_rp_o:
438
17.9k
            case MVM_OP_param_op_o:
439
17.9k
                if (arg_flag == MVM_CALLSITE_ARG_OBJ) {
440
17.2k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
441
17.2k
                    if (type_tuple && type_tuple[i].type) {
442
16.2k
                        add_facts(tc, g, i, type_tuple[i], pos_ins[i]);
443
16.2k
                        if (i == 0)
444
10.9k
                            g->specialized_on_invocant = 1;
445
16.2k
                    }
446
17.2k
                }
447
756
                else if (arg_flag == MVM_CALLSITE_ARG_INT) {
448
190
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
449
190
                        MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
450
190
                        MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
451
190
                    pos_added[i] += 2;
452
190
                }
453
566
                else if (arg_flag == MVM_CALLSITE_ARG_NUM) {
454
8
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
455
8
                        MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
456
8
                        MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
457
8
                    pos_added[i] += 2;
458
8
                }
459
558
                else if (arg_flag == MVM_CALLSITE_ARG_STR) {
460
558
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
461
558
                        MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
462
558
                        MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
463
558
                    pos_added[i] += 2;
464
558
                }
465
17.9k
                break;
466
0
            default:
467
0
                break;
468
20.7k
            }
469
20.7k
            pos_ins[i]->operands[1].lit_i16 = (MVMint16)i;
470
20.7k
        }
471
11.6k
472
11.6k
        /* Now consider any optionals. */
473
11.6k
        if (opt_min >= 0) {
474
3.65k
            for (i = opt_min; i <= opt_max; i++) {
475
1.82k
                MVMuint8 passed = i < cs->num_pos;
476
1.82k
                if (passed) {
477
818
                    /* If we know the argument has been passed, then add a goto
478
818
                     * to the "passed" code. */
479
818
                    MVMSpeshIns *after = pos_ins[i];
480
1.04k
                    while (pos_added[i]--)
481
228
                        after = after->next;
482
818
                    MVM_spesh_manipulate_insert_goto(tc, g, pos_bb[i], after,
483
818
                        pos_ins[i]->operands[2].ins_bb);
484
818
485
818
                    /* Inserting an unconditional goto makes the linear_next BB
486
818
                    * unreachable, so we remove it from the succ list. */
487
818
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
488
818
                        pos_bb[i]->linear_next);
489
1.00k
                } else {
490
1.00k
                    /* If we didn't pass this, just fall through the original
491
1.00k
                    * operation and we'll get the default value set. */
492
1.00k
                    MVM_spesh_manipulate_delete_ins(tc, g, pos_bb[i], pos_ins[i]);
493
1.00k
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
494
1.00k
                        pos_ins[i]->operands[2].ins_bb);
495
1.00k
                }
496
1.82k
            }
497
1.82k
        }
498
11.6k
499
11.6k
        /* Now consider any nameds. */
500
13.2k
        for (i = 0; i < num_named; i++) {
501
1.61k
            /* See if the arg was passed. */
502
1.61k
            MVMString *arg_name       = MVM_spesh_get_string(tc, g, named_ins[i]->operands[1]);
503
1.61k
            MVMint32   cur_idx        = 0;
504
1.61k
            MVMint32   cur_named      = 0;
505
1.61k
            MVMuint8   found_flag     = 0;
506
1.61k
            MVMint32   found_idx      = -1;
507
1.61k
            MVMint32   found_flag_idx = -1;
508
1.61k
            MVMint32   j;
509
5.23k
            for (j = 0; j < cs_flags; j++) {
510
4.31k
                if (cs->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) {
511
1.14k
                    if (MVM_string_equal(tc, arg_name, cs->arg_names[cur_named])) {
512
700
                        /* Found it. */
513
700
                        found_flag_idx = j;
514
700
                        found_flag = cs->arg_flags[j];
515
700
                        found_idx  = cur_idx;
516
700
                        break;
517
700
                    }
518
443
                    cur_idx += 2;
519
443
                    cur_named++;
520
443
                }
521
3.16k
                else {
522
3.16k
                    cur_idx++;
523
3.16k
                }
524
4.31k
            }
525
1.61k
526
1.61k
            /* Now go by instruction. */
527
1.61k
            switch (named_ins[i]->info->opcode) {
528
0
            case MVM_OP_param_rn_i:
529
0
                if (found_idx == -1)
530
0
                    goto cleanup;
531
0
                if (found_flag & MVM_CALLSITE_ARG_INT) {
532
0
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
533
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
534
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
535
0
                }
536
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
537
0
                        && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_INT) {
538
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
539
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
540
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
541
0
                }
542
0
                named_used++;
543
0
                break;
544
0
            case MVM_OP_param_rn_n:
545
0
                if (found_idx == -1)
546
0
                    goto cleanup;
547
0
                if (found_flag & MVM_CALLSITE_ARG_NUM) {
548
0
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
549
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
550
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
551
0
                }
552
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
553
0
                        && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_NUM) {
554
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
555
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
556
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
557
0
                }
558
0
                named_used++;
559
0
                break;
560
57
            case MVM_OP_param_rn_s:
561
57
                if (found_idx == -1)
562
0
                    goto cleanup;
563
57
                if (found_flag & MVM_CALLSITE_ARG_STR) {
564
44
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
565
44
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
566
44
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
567
44
                }
568
13
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
569
13
                        && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_STR) {
570
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
571
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
572
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
573
0
                }
574
57
                named_used++;
575
57
                break;
576
100
            case MVM_OP_param_rn_o:
577
100
                if (found_idx == -1)
578
0
                    goto cleanup;
579
100
                if (found_flag & MVM_CALLSITE_ARG_OBJ) {
580
94
                    MVMuint16 arg_idx = found_idx + 1;
581
94
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
582
94
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
583
94
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
584
94
                    if (type_tuple && type_tuple[found_flag_idx].type)
585
94
                        add_facts(tc, g, arg_idx, type_tuple[found_flag_idx], named_ins[i]);
586
94
                }
587
6
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
588
6
                    MVMuint16 arg_idx = found_idx + 1;
589
6
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
590
6
                    if (found_flag & MVM_CALLSITE_ARG_INT)
591
6
                        pos_box(tc, g, named_bb[i], named_ins[i],
592
6
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
593
6
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
594
0
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
595
0
                        pos_box(tc, g, named_bb[i], named_ins[i],
596
0
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
597
0
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
598
0
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
599
0
                        pos_box(tc, g, named_bb[i], named_ins[i],
600
0
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
601
0
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
602
6
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
603
6
                }
604
100
                named_used++;
605
100
                break;
606
213
            case MVM_OP_param_on_i:
607
213
                if (found_idx == -1) {
608
159
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
609
159
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
610
159
                }
611
54
                else if (found_flag & MVM_CALLSITE_ARG_INT) {
612
54
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
613
54
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
614
54
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
615
54
                        named_ins[i]->operands[2].ins_bb);
616
54
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
617
54
                        named_bb[i]->linear_next);
618
54
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
619
54
                    named_used++;
620
54
                }
621
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
622
0
                        && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_INT) {
623
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
624
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
625
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
626
0
                        named_ins[i]->operands[2].ins_bb);
627
0
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
628
0
                        named_bb[i]->linear_next);
629
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
630
0
                    named_used++;
631
0
                }
632
213
                break;
633
0
            case MVM_OP_param_on_n:
634
0
                if (found_idx == -1) {
635
0
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
636
0
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
637
0
                }
638
0
                else if (found_flag & MVM_CALLSITE_ARG_NUM) {
639
0
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
640
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
641
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
642
0
                        named_ins[i]->operands[2].ins_bb);
643
0
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
644
0
                        named_bb[i]->linear_next);
645
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
646
0
                    named_used++;
647
0
                }
648
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
649
0
                        && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_NUM) {
650
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
651
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
652
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
653
0
                        named_ins[i]->operands[2].ins_bb);
654
0
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
655
0
                        named_bb[i]->linear_next);
656
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
657
0
                    named_used++;
658
0
                }
659
0
                break;
660
88
            case MVM_OP_param_on_s:
661
88
                if (found_idx == -1) {
662
54
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
663
54
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
664
54
                }
665
34
                else if (found_flag & MVM_CALLSITE_ARG_STR) {
666
34
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
667
34
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
668
34
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
669
34
                        named_ins[i]->operands[2].ins_bb);
670
34
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
671
34
                        named_bb[i]->linear_next);
672
34
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
673
34
                    named_used++;
674
34
                }
675
0
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
676
0
                        && prim_spec(tc, type_tuple, found_flag_idx) == MVM_STORAGE_SPEC_BP_STR) {
677
0
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
678
0
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
679
0
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
680
0
                        named_ins[i]->operands[2].ins_bb);
681
0
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
682
0
                        named_bb[i]->linear_next);
683
0
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
684
0
                    named_used++;
685
0
                }
686
88
                break;
687
1.16k
            case MVM_OP_param_on_o:
688
1.16k
                if (found_idx == -1) {
689
705
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
690
705
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
691
705
                }
692
455
                else if (found_flag & MVM_CALLSITE_ARG_OBJ) {
693
289
                    MVMuint16 arg_idx = found_idx + 1;
694
289
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
695
289
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
696
289
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
697
289
                        named_ins[i]->operands[2].ins_bb);
698
289
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
699
289
                        named_bb[i]->linear_next);
700
289
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
701
289
                    if (type_tuple && type_tuple[found_flag_idx].type)
702
275
                        add_facts(tc, g, arg_idx, type_tuple[found_flag_idx], named_ins[i]);
703
289
                    named_used++;
704
289
                }
705
166
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
706
166
                    MVMuint16 arg_idx = found_idx + 1;
707
166
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
708
166
                    if (found_flag & MVM_CALLSITE_ARG_INT)
709
119
                        pos_box(tc, g, named_bb[i], named_ins[i],
710
119
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
711
119
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
712
47
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
713
27
                        pos_box(tc, g, named_bb[i], named_ins[i],
714
27
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
715
27
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
716
20
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
717
20
                        pos_box(tc, g, named_bb[i], named_ins[i],
718
20
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
719
20
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
720
166
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next->next,
721
166
                        named_ins[i]->operands[2].ins_bb);
722
166
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
723
166
                        named_bb[i]->linear_next);
724
166
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
725
166
                    named_used++;
726
166
                }
727
1.16k
                break;
728
0
            default:
729
0
                break;
730
1.61k
            }
731
1.61k
        }
732
11.6k
733
11.6k
        /* If we have an instruction to check all nameds were used... */
734
11.6k
        if (paramnamesused_ins) {
735
11.3k
            /* Delete it if they were. */
736
11.3k
            if (named_passed == named_used) {
737
11.3k
                MVM_spesh_manipulate_delete_ins(tc, g, paramnamesused_bb, paramnamesused_ins);
738
11.3k
            }
739
11.3k
740
11.3k
            /* Otherwise, we have unexpected named arguments. Turn it into an
741
11.3k
             * error. */
742
0
            else {
743
0
                MVMuint16 i;
744
0
                for (i = 0; i < named_passed; i++) {
745
0
                    if (!(named_used_bit_field & ((MVMuint64)1 << i))) {
746
0
                        paramnamesused_ins->info = MVM_op_get_op(MVM_OP_sp_paramnamesused);
747
0
                        paramnamesused_ins->operands = MVM_spesh_alloc(tc,
748
0
                            g, sizeof(MVMSpeshOperand));
749
0
                        paramnamesused_ins->operands[0].lit_i16 = MVM_spesh_add_spesh_slot(tc,
750
0
                            g, (MVMCollectable *)g->cs->arg_names[i]);
751
0
                        break;
752
0
                    }
753
0
                }
754
0
            }
755
11.3k
        }
756
11.6k
757
11.6k
        /* If we have a slurpy hash... */
758
11.6k
        if (param_sn_ins) {
759
262
            /* Construct it as a hash. */
760
262
            MVMObject *hash_type = g->sf->body.cu->body.hll_config->slurpy_hash_type;
761
262
            if (REPR(hash_type)->ID == MVM_REPR_ID_MVMHash) {
762
262
                MVMSpeshOperand target    = param_sn_ins->operands[0];
763
262
                param_sn_ins->info        = MVM_op_get_op(MVM_OP_sp_fastcreate);
764
262
                param_sn_ins->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
765
262
                param_sn_ins->operands[0] = target;
766
262
                param_sn_ins->operands[1].lit_i16 = sizeof(MVMHash);
767
262
                param_sn_ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g,
768
262
                    (MVMCollectable *)STABLE(hash_type));
769
262
            }
770
0
            else {
771
0
                MVM_oops(tc, "Arg spesh: slurpy hash type was not a VMHash as expected");
772
0
            }
773
262
774
262
            /* Populate it with unused named args, if needed, boxing them on
775
262
             * the way. */
776
262
            if (named_passed > named_used)
777
198
                for (i = 0; i < named_passed; i++)
778
121
                    if (!(named_used_bit_field & ((MVMuint64)1 << i)))
779
85
                        slurp_named_arg(tc, g, param_sn_bb, param_sn_ins, i);
780
262
        }
781
11.6k
782
11.6k
        /* Stash the named used bit field in the graph; will need to make it
783
11.6k
         * into the candidate and all the way to deopt. */
784
11.6k
        g->deopt_named_used_bit_field = named_used_bit_field;
785
11.6k
    }
786
11.9k
787
11.9k
  cleanup:
788
11.9k
    MVM_free(pos_ins);
789
11.9k
    MVM_free(pos_bb);
790
11.9k
    MVM_free(pos_added);
791
11.9k
    MVM_free(named_ins);
792
11.9k
    MVM_free(named_bb);
793
11.9k
}