Coverage Report

Created: 2018-07-03 15:31

/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
53.9k
#define MAX_POS_ARGS 8
5
6
/* Maximum number of named args we'll consider for optimization purposes. */
7
23.5k
#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
15.4k
                      MVMSpeshStatsType type_tuple_entry, MVMSpeshIns *arg_ins) {
12
15.4k
    /* Add appropriate facts from the arg type tuple. */
13
15.4k
    MVMint16 orig = arg_ins->operands[0].reg.orig;
14
15.4k
    MVMint16 i = arg_ins->operands[0].reg.i;
15
15.4k
    MVMObject *type = type_tuple_entry.type;
16
15.4k
    g->facts[orig][i].type = type;
17
15.4k
    g->facts[orig][i].flags |= MVM_SPESH_FACT_KNOWN_TYPE;
18
15.4k
    if (type_tuple_entry.type_concrete) {
19
13.7k
        g->facts[orig][i].flags |= MVM_SPESH_FACT_CONCRETE;
20
13.7k
        if (!type->st->container_spec)
21
13.7k
            g->facts[orig][i].flags |= MVM_SPESH_FACT_DECONTED;
22
13.7k
    }
23
1.71k
    else {
24
1.71k
        g->facts[orig][i].flags |= MVM_SPESH_FACT_TYPEOBJ | MVM_SPESH_FACT_DECONTED;
25
1.71k
    }
26
15.4k
27
15.4k
    /* Add any decontainerized type info. */
28
15.4k
    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
15.4k
}
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
906
                    const MVMOpInfo *arg_op, MVMuint8 kind) {
59
906
    MVMSpeshOperand  temp_bt, temp_arg;
60
906
    MVMSpeshIns     *hlltype, *box;
61
906
62
906
    /* Add HLL type op. */
63
906
    temp_bt              = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
64
906
    hlltype              = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
65
906
    hlltype->info        = hlltype_op;
66
906
    hlltype->operands    = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand));
67
906
    hlltype->operands[0] = temp_bt;
68
906
    MVM_spesh_manipulate_insert_ins(tc, bb, ins, hlltype);
69
906
70
906
    /* Add box op. */
71
906
    temp_arg         = MVM_spesh_manipulate_get_temp_reg(tc, g, kind);
72
906
    box              = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
73
906
    box->info        = box_op;
74
906
    box->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
75
906
    box->operands[0] = ins->operands[0];
76
906
    box->operands[1] = temp_arg;
77
906
    box->operands[2] = temp_bt;
78
906
    MVM_spesh_manipulate_insert_ins(tc, bb, hlltype, box);
79
906
80
906
    /* Update instruction to receive unboxed arg. */
81
906
    ins->info        = arg_op;
82
906
    ins->operands[0] = temp_arg;
83
906
84
906
    /* Release temporary registers. */
85
906
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp_bt);
86
906
    MVM_spesh_manipulate_release_temp_reg(tc, g, temp_arg);
87
906
}
88
89
/* Gets the primitive boxed by a type. */
90
181
static MVMuint16 prim_spec(MVMThreadContext *tc, MVMSpeshStatsType *type_tuple, MVMint32 i) {
91
0
    MVMObject *type = type_tuple ? type_tuple[i].type : NULL;
92
181
    return type
93
0
        ? REPR(type)->get_storage_spec(tc, STABLE(type))->boxed_primitive
94
181
        : 0;
95
181
}
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
72
                            MVMSpeshIns *hash_ins, MVMint32 named_idx) {
100
72
    MVMSpeshIns *key_ins;
101
72
102
72
    /* Look up arg flags and name, and compute index. */
103
72
    MVMCallsiteFlags flags = g->cs->arg_flags[g->cs->num_pos + named_idx];
104
72
    MVMString *name = g->cs->arg_names[named_idx];
105
72
    MVMuint16 arg_idx = g->cs->num_pos + 2 * named_idx + 1;
106
72
107
72
    /* Allocate temporary registers for the key and value. */
108
72
    MVMSpeshOperand key_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_str);
109
72
    MVMSpeshOperand value_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_obj);
110
72
111
72
    /* Insert bind key instruction after slurpy hash creation instruction (we
112
72
     * do it first as below we prepend instructions to obtain the key and the
113
72
     * value. */
114
72
    MVMSpeshIns *bindkey_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
115
72
    bindkey_ins->info = MVM_op_get_op(MVM_OP_bindkey_o);
116
72
    bindkey_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
117
72
    bindkey_ins->operands[0] = hash_ins->operands[0];
118
72
    bindkey_ins->operands[1] = key_temp;
119
72
    bindkey_ins->operands[2] = value_temp;
120
72
    MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, bindkey_ins);
121
72
122
72
    /* Instruction to get value depends on argument type. */
123
72
    if ((flags & MVM_CALLSITE_ARG_MASK) == MVM_CALLSITE_ARG_OBJ) {
124
50
        /* It's already a boxed object, so just fetch it into the value
125
50
         * register. */
126
50
        MVMSpeshIns *fetch_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
127
50
        fetch_ins->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
128
50
        fetch_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
129
50
        fetch_ins->operands[0] = value_temp;
130
50
        fetch_ins->operands[1].lit_ui16 = arg_idx;
131
50
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, fetch_ins);
132
50
    }
133
22
    else {
134
22
        MVMSpeshIns *box_ins, *hlltype_ins, *fetch_ins;
135
22
136
22
        /* We need to box it. Get a temporary register to box into. To
137
22
         * only use one extra register, we will re-use the temp value
138
22
         * one to load the box type into, and only add a temporary for. */
139
22
        MVMSpeshOperand unboxed_temp;
140
22
        MVMuint16 box_op;
141
22
        MVMuint16 hlltype_op;
142
22
        MVMuint16 fetch_op;
143
22
        switch (flags & MVM_CALLSITE_ARG_MASK) {
144
20
            case MVM_CALLSITE_ARG_INT:
145
20
                unboxed_temp = MVM_spesh_manipulate_get_temp_reg(tc, g, MVM_reg_int64);
146
20
                box_op = MVM_OP_box_i;
147
20
                hlltype_op = MVM_OP_hllboxtype_i;
148
20
                fetch_op = MVM_OP_sp_getarg_i;
149
20
                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
22
        }
165
22
166
22
        /* Emit instruction to box value. */
167
22
        box_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
168
22
        box_ins->info = MVM_op_get_op(box_op);
169
22
        box_ins->operands = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
170
22
        box_ins->operands[0] = value_temp;
171
22
        box_ins->operands[1] = unboxed_temp;
172
22
        box_ins->operands[2] = value_temp;
173
22
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, box_ins);
174
22
175
22
        /* Prepend the instruction get box type. */
176
22
        hlltype_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
177
22
        hlltype_ins->info = MVM_op_get_op(hlltype_op);
178
22
        hlltype_ins->operands = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshOperand));
179
22
        hlltype_ins->operands[0] = value_temp;
180
22
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, hlltype_ins);
181
22
182
22
        /* Prepend fetch instruction. */
183
22
        fetch_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
184
22
        fetch_ins->info = MVM_op_get_op(fetch_op);
185
22
        fetch_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
186
22
        fetch_ins->operands[0] = unboxed_temp;
187
22
        fetch_ins->operands[1].lit_ui16 = arg_idx;
188
22
        MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, fetch_ins);
189
22
190
22
        /* Can release the temporary register now. */
191
22
        MVM_spesh_manipulate_release_temp_reg(tc, g, unboxed_temp);
192
22
    }
193
72
194
72
    /* Insert key fetching instruciton; we just store the string in a spesh
195
72
     * slot. */
196
72
    key_ins = MVM_spesh_alloc(tc, g, sizeof(MVMSpeshIns));
197
72
    key_ins->info = MVM_op_get_op(MVM_OP_sp_getspeshslot);
198
72
    key_ins->operands = MVM_spesh_alloc(tc, g, 2 * sizeof(MVMSpeshOperand));
199
72
    key_ins->operands[0] = key_temp;
200
72
    key_ins->operands[1].lit_i16 = MVM_spesh_add_spesh_slot(tc, g, (MVMCollectable *)name);
201
72
    MVM_spesh_manipulate_insert_ins(tc, bb, hash_ins, key_ins);
202
72
203
72
    /* Release temporary registers after. */
204
72
    MVM_spesh_manipulate_release_temp_reg(tc, g, key_temp);
205
72
    MVM_spesh_manipulate_release_temp_reg(tc, g, value_temp);
206
72
}
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.0k
                    MVMSpeshStatsType *type_tuple) {
212
11.0k
    /* We need to identify the various arg-related instructions in the graph,
213
11.0k
     * then manipulate them as a whole. */
214
11.0k
    MVMSpeshIns  *checkarity_ins     = NULL;
215
11.0k
    MVMSpeshBB   *checkarity_bb      = NULL;
216
11.0k
    MVMSpeshIns  *paramnamesused_ins = NULL;
217
11.0k
    MVMSpeshBB   *paramnamesused_bb  = NULL;
218
11.0k
    MVMSpeshIns  *param_sn_ins       = NULL;
219
11.0k
    MVMSpeshBB   *param_sn_bb        = NULL;
220
11.0k
221
11.0k
    MVMSpeshIns **pos_ins    = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshIns *));
222
11.0k
    MVMSpeshBB  **pos_bb     = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshBB *));
223
11.0k
    MVMuint8     *pos_added  = MVM_calloc(MAX_POS_ARGS, sizeof(MVMuint8));
224
11.0k
    MVMSpeshIns **named_ins  = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *));
225
11.0k
    MVMSpeshBB  **named_bb   = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshBB *));
226
11.0k
    MVMint32      req_max    = -1;
227
11.0k
    MVMint32      opt_min    = -1;
228
11.0k
    MVMint32      opt_max    = -1;
229
11.0k
    MVMint32      num_named  = 0;
230
11.0k
    MVMint32      named_used = 0;
231
11.0k
    MVMint32      named_passed = (cs->arg_count - cs->num_pos) / 2;
232
11.0k
    MVMint32      cs_flags   = cs->num_pos + named_passed;
233
11.0k
    MVMint32      cur_ins = 0;
234
11.0k
235
11.0k
    /* We use a bit field to track named argument use; on deopt we will put it
236
11.0k
     * into the deoptimized frame. */
237
11.0k
    MVMuint64 named_used_bit_field = 0;
238
11.0k
239
11.0k
    MVMSpeshBB *bb = g->entry;
240
11.0k
    g->cs = cs;
241
11.0k
242
11.0k
    /* Walk through the graph, looking for arg related instructions. */
243
451k
    while (bb) {
244
440k
        MVMSpeshIns *ins = bb->first_ins;
245
2.55M
        while (ins) {
246
2.11M
            switch (ins->info->opcode) {
247
11.0k
            case MVM_OP_checkarity:
248
11.0k
                if (checkarity_ins)
249
0
                    goto cleanup; /* Dupe; weird; bail out! */
250
11.0k
                checkarity_ins = ins;
251
11.0k
                checkarity_bb  = bb;
252
11.0k
                break;
253
19.3k
            case MVM_OP_param_rp_i:
254
19.3k
            case MVM_OP_param_rp_n:
255
19.3k
            case MVM_OP_param_rp_s:
256
19.3k
            case MVM_OP_param_rp_o: {
257
19.3k
                /* Required positional. */
258
19.3k
                MVMint16 idx = ins->operands[1].lit_i16;
259
19.3k
                if (idx < 0 || idx >= MAX_POS_ARGS)
260
0
                    goto cleanup;
261
19.3k
                if (pos_ins[idx]) /* Dupe; weird. */
262
0
                    goto cleanup;
263
19.3k
                pos_ins[idx] = ins;
264
19.3k
                pos_bb[idx]  = bb;
265
19.3k
                if (idx > req_max)
266
19.3k
                    req_max = idx;
267
19.3k
                break;
268
19.3k
            }
269
1.65k
            case MVM_OP_param_op_i:
270
1.65k
            case MVM_OP_param_op_n:
271
1.65k
            case MVM_OP_param_op_s:
272
1.65k
            case MVM_OP_param_op_o: {
273
1.65k
                /* Optional Positional int/num/string/object */
274
1.65k
                MVMint16 idx = ins->operands[1].lit_i16;
275
1.65k
                if (idx < 0 || idx >= MAX_POS_ARGS)
276
0
                    goto cleanup;
277
1.65k
                if (pos_ins[idx]) /* Dupe; weird. */
278
0
                    goto cleanup;
279
1.65k
                pos_ins[idx] = ins;
280
1.65k
                pos_bb[idx]  = bb;
281
1.65k
                if (idx > opt_max)
282
1.65k
                    opt_max = idx;
283
1.65k
                if (opt_min == -1 || idx < opt_min)
284
1.65k
                    opt_min = idx;
285
1.65k
                break;
286
1.65k
            }
287
1.57k
            case MVM_OP_param_on_i:
288
1.57k
            case MVM_OP_param_on_n:
289
1.57k
            case MVM_OP_param_on_s:
290
1.57k
            case MVM_OP_param_on_o:
291
1.57k
            case MVM_OP_param_rn_i:
292
1.57k
            case MVM_OP_param_rn_n:
293
1.57k
            case MVM_OP_param_rn_s:
294
1.57k
            case MVM_OP_param_rn_o:
295
1.57k
                /* Named (optional or required). */
296
1.57k
                if (num_named == MAX_NAMED_ARGS)
297
0
                    goto cleanup;
298
1.57k
                named_ins[num_named] = ins;
299
1.57k
                named_bb[num_named]  = bb;
300
1.57k
                num_named++;
301
1.57k
                break;
302
158
            case MVM_OP_param_sp:
303
158
                break;
304
266
            case MVM_OP_param_sn:
305
266
                param_sn_ins = ins;
306
266
                param_sn_bb = bb;
307
266
                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
10.7k
            case MVM_OP_paramnamesused:
313
10.7k
                if (paramnamesused_ins)
314
0
                    goto cleanup; /* Dupe; weird; bail out! */
315
10.7k
                paramnamesused_ins = ins;
316
10.7k
                paramnamesused_bb  = bb;
317
10.7k
                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
2.06M
            default:
335
2.06M
                break;
336
2.11M
            }
337
2.11M
            cur_ins++;
338
2.11M
            ins = ins->next;
339
2.11M
        }
340
440k
        bb = bb->linear_next;
341
440k
    }
342
11.0k
343
11.0k
    /* If we didn't find a checkarity instruction, bail. */
344
11.0k
    if (!checkarity_ins)
345
0
        goto cleanup;
346
11.0k
347
11.0k
    /* If required and optional aren't contiguous, bail. */
348
11.0k
    if (opt_min >= 0 && req_max + 1 != opt_min)
349
0
        goto cleanup;
350
11.0k
351
11.0k
    /* If the number of passed args is in range... */
352
11.0k
    if (cs->num_pos >= req_max + 1 && (opt_max < 0 || cs->num_pos <= opt_max + 1)) {
353
11.0k
        /* Ensure we've got all the arg fetch instructions we need, and that
354
11.0k
         * types match or it's a box/unbox. */
355
11.0k
        MVMint32 i;
356
30.8k
        for (i = 0; i < cs->num_pos; i++) {
357
20.1k
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
358
20.1k
            if (!pos_ins[i])
359
102
                goto cleanup;
360
20.0k
            switch (pos_ins[i]->info->opcode) {
361
1.19k
            case MVM_OP_param_rp_i:
362
1.19k
            case MVM_OP_param_op_i:
363
1.19k
                if (arg_flag != MVM_CALLSITE_ARG_INT)
364
146
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
365
146
                            prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_INT)
366
146
                        goto cleanup;
367
1.05k
                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.73k
            case MVM_OP_param_rp_s:
376
1.73k
            case MVM_OP_param_op_s:
377
1.73k
                if (arg_flag != MVM_CALLSITE_ARG_STR)
378
25
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ ||
379
25
                            prim_spec(tc, type_tuple, i) != MVM_STORAGE_SPEC_BP_STR)
380
25
                        goto cleanup;
381
1.71k
                break;
382
17.1k
            case MVM_OP_param_rp_o:
383
17.1k
            case MVM_OP_param_op_o:
384
17.1k
                if (arg_flag != MVM_CALLSITE_ARG_OBJ && arg_flag != MVM_CALLSITE_ARG_INT &&
385
543
                    arg_flag != MVM_CALLSITE_ARG_NUM && arg_flag != MVM_CALLSITE_ARG_STR)
386
0
                    goto cleanup;
387
17.1k
                break;
388
0
            default:
389
0
                break;
390
20.0k
            }
391
20.0k
        }
392
11.0k
393
11.0k
        /* We can optimize. Toss checkarity. */
394
10.7k
        MVM_spesh_manipulate_delete_ins(tc, g, checkarity_bb, checkarity_ins);
395
10.7k
396
10.7k
        /* Re-write the passed required positionals to spesh ops, and add any
397
10.7k
         * facts. */
398
30.2k
        for (i = 0; i < cs->num_pos; i++) {
399
19.5k
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
400
19.5k
            switch (pos_ins[i]->info->opcode) {
401
1.05k
            case MVM_OP_param_rp_i:
402
1.05k
            case MVM_OP_param_op_i:
403
1.05k
                if (arg_flag == MVM_CALLSITE_ARG_INT) {
404
1.05k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
405
1.05k
                }
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.05k
                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.67k
            case MVM_OP_param_rp_s:
426
1.67k
            case MVM_OP_param_op_s:
427
1.67k
                if (arg_flag == MVM_CALLSITE_ARG_STR) {
428
1.67k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
429
1.67k
                }
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.67k
                break;
437
16.7k
            case MVM_OP_param_rp_o:
438
16.7k
            case MVM_OP_param_op_o:
439
16.7k
                if (arg_flag == MVM_CALLSITE_ARG_OBJ) {
440
16.0k
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
441
16.0k
                    if (type_tuple && type_tuple[i].type) {
442
15.1k
                        add_facts(tc, g, i, type_tuple[i], pos_ins[i]);
443
15.1k
                        if (i == 0)
444
10.1k
                            g->specialized_on_invocant = 1;
445
15.1k
                    }
446
16.0k
                }
447
731
                else if (arg_flag == MVM_CALLSITE_ARG_INT) {
448
188
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
449
188
                        MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
450
188
                        MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
451
188
                    pos_added[i] += 2;
452
188
                }
453
543
                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
535
                else if (arg_flag == MVM_CALLSITE_ARG_STR) {
460
535
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
461
535
                        MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
462
535
                        MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
463
535
                    pos_added[i] += 2;
464
535
                }
465
16.7k
                break;
466
0
            default:
467
0
                break;
468
19.5k
            }
469
19.5k
            pos_ins[i]->operands[1].lit_i16 = (MVMint16)i;
470
19.5k
        }
471
10.7k
472
10.7k
        /* Now consider any optionals. */
473
10.7k
        if (opt_min >= 0) {
474
3.22k
            for (i = opt_min; i <= opt_max; i++) {
475
1.61k
                MVMuint8 passed = i < cs->num_pos;
476
1.61k
                if (passed) {
477
746
                    /* If we know the argument has been passed, then add a goto
478
746
                     * to the "passed" code. */
479
746
                    MVMSpeshIns *after = pos_ins[i];
480
926
                    while (pos_added[i]--)
481
180
                        after = after->next;
482
746
                    MVM_spesh_manipulate_insert_goto(tc, g, pos_bb[i], after,
483
746
                        pos_ins[i]->operands[2].ins_bb);
484
746
485
746
                    /* Inserting an unconditional goto makes the linear_next BB
486
746
                    * unreachable, so we remove it from the succ list. */
487
746
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
488
746
                        pos_bb[i]->linear_next);
489
864
                } else {
490
864
                    /* If we didn't pass this, just fall through the original
491
864
                    * operation and we'll get the default value set. */
492
864
                    MVM_spesh_manipulate_delete_ins(tc, g, pos_bb[i], pos_ins[i]);
493
864
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
494
864
                        pos_ins[i]->operands[2].ins_bb);
495
864
                }
496
1.61k
            }
497
1.61k
        }
498
10.7k
499
10.7k
        /* Now consider any nameds. */
500
12.2k
        for (i = 0; i < num_named; i++) {
501
1.52k
            /* See if the arg was passed. */
502
1.52k
            MVMString *arg_name       = MVM_spesh_get_string(tc, g, named_ins[i]->operands[1]);
503
1.52k
            MVMint32   cur_idx        = 0;
504
1.52k
            MVMint32   cur_named      = 0;
505
1.52k
            MVMuint8   found_flag     = 0;
506
1.52k
            MVMint32   found_idx      = -1;
507
1.52k
            MVMint32   found_flag_idx = -1;
508
1.52k
            MVMint32   j;
509
4.99k
            for (j = 0; j < cs_flags; j++) {
510
4.07k
                if (cs->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) {
511
985
                    if (MVM_string_equal(tc, arg_name, cs->arg_names[cur_named])) {
512
602
                        /* Found it. */
513
602
                        found_flag_idx = j;
514
602
                        found_flag = cs->arg_flags[j];
515
602
                        found_idx  = cur_idx;
516
602
                        break;
517
602
                    }
518
383
                    cur_idx += 2;
519
383
                    cur_named++;
520
383
                }
521
3.09k
                else {
522
3.09k
                    cur_idx++;
523
3.09k
                }
524
4.07k
            }
525
1.52k
526
1.52k
            /* Now go by instruction. */
527
1.52k
            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
44
            case MVM_OP_param_rn_s:
561
44
                if (found_idx == -1)
562
0
                    goto cleanup;
563
44
                if (found_flag & MVM_CALLSITE_ARG_STR) {
564
34
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
565
34
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
566
34
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
567
34
                }
568
10
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
569
10
                        && 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
44
                named_used++;
575
44
                break;
576
62
            case MVM_OP_param_rn_o:
577
62
                if (found_idx == -1)
578
0
                    goto cleanup;
579
62
                if (found_flag & MVM_CALLSITE_ARG_OBJ) {
580
57
                    MVMuint16 arg_idx = found_idx + 1;
581
57
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
582
57
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
583
57
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
584
57
                    if (type_tuple && type_tuple[found_flag_idx].type)
585
57
                        add_facts(tc, g, arg_idx, type_tuple[found_flag_idx], named_ins[i]);
586
57
                }
587
5
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
588
5
                    MVMuint16 arg_idx = found_idx + 1;
589
5
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
590
5
                    if (found_flag & MVM_CALLSITE_ARG_INT)
591
5
                        pos_box(tc, g, named_bb[i], named_ins[i],
592
5
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
593
5
                            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
5
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
603
5
                }
604
62
                named_used++;
605
62
                break;
606
220
            case MVM_OP_param_on_i:
607
220
                if (found_idx == -1) {
608
161
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
609
161
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
610
161
                }
611
59
                else if (found_flag & MVM_CALLSITE_ARG_INT) {
612
59
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
613
59
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
614
59
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
615
59
                        named_ins[i]->operands[2].ins_bb);
616
59
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
617
59
                        named_bb[i]->linear_next);
618
59
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
619
59
                    named_used++;
620
59
                }
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
220
                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
86
            case MVM_OP_param_on_s:
661
86
                if (found_idx == -1) {
662
53
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
663
53
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
664
53
                }
665
33
                else if (found_flag & MVM_CALLSITE_ARG_STR) {
666
33
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
667
33
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
668
33
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
669
33
                        named_ins[i]->operands[2].ins_bb);
670
33
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
671
33
                        named_bb[i]->linear_next);
672
33
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
673
33
                    named_used++;
674
33
                }
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
86
                break;
687
1.10k
            case MVM_OP_param_on_o:
688
1.10k
                if (found_idx == -1) {
689
704
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
690
704
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i], named_ins[i]->operands[2].ins_bb);
691
704
                }
692
404
                else if (found_flag & MVM_CALLSITE_ARG_OBJ) {
693
234
                    MVMuint16 arg_idx = found_idx + 1;
694
234
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
695
234
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
696
234
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
697
234
                        named_ins[i]->operands[2].ins_bb);
698
234
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
699
234
                        named_bb[i]->linear_next);
700
234
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
701
234
                    if (type_tuple && type_tuple[found_flag_idx].type)
702
224
                        add_facts(tc, g, arg_idx, type_tuple[found_flag_idx], named_ins[i]);
703
234
                    named_used++;
704
234
                }
705
170
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
706
170
                    MVMuint16 arg_idx = found_idx + 1;
707
170
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
708
170
                    if (found_flag & MVM_CALLSITE_ARG_INT)
709
126
                        pos_box(tc, g, named_bb[i], named_ins[i],
710
126
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
711
126
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
712
44
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
713
25
                        pos_box(tc, g, named_bb[i], named_ins[i],
714
25
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
715
25
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
716
19
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
717
19
                        pos_box(tc, g, named_bb[i], named_ins[i],
718
19
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
719
19
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
720
170
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next->next,
721
170
                        named_ins[i]->operands[2].ins_bb);
722
170
                    MVM_spesh_manipulate_remove_successor(tc, named_bb[i],
723
170
                        named_bb[i]->linear_next);
724
170
                    named_used_bit_field |= (MVMuint64)1 << cur_named;
725
170
                    named_used++;
726
170
                }
727
1.10k
                break;
728
0
            default:
729
0
                break;
730
1.52k
            }
731
1.52k
        }
732
10.7k
733
10.7k
        /* If we have an instruction to check all nameds were used... */
734
10.7k
        if (paramnamesused_ins) {
735
10.4k
            /* Delete it if they were. */
736
10.4k
            if (named_passed == named_used) {
737
10.4k
                MVM_spesh_manipulate_delete_ins(tc, g, paramnamesused_bb, paramnamesused_ins);
738
10.4k
            }
739
10.4k
740
10.4k
            /* Otherwise, we have unexpected named arguments. Turn it into an
741
10.4k
             * 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
10.4k
        }
756
10.7k
757
10.7k
        /* If we have a slurpy hash... */
758
10.7k
        if (param_sn_ins) {
759
232
            /* Construct it as a hash. */
760
232
            MVMObject *hash_type = g->sf->body.cu->body.hll_config->slurpy_hash_type;
761
232
            if (REPR(hash_type)->ID == MVM_REPR_ID_MVMHash) {
762
232
                MVMSpeshOperand target    = param_sn_ins->operands[0];
763
232
                param_sn_ins->info        = MVM_op_get_op(MVM_OP_sp_fastcreate);
764
232
                param_sn_ins->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
765
232
                param_sn_ins->operands[0] = target;
766
232
                param_sn_ins->operands[1].lit_i16 = sizeof(MVMHash);
767
232
                param_sn_ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g,
768
232
                    (MVMCollectable *)STABLE(hash_type));
769
232
            }
770
0
            else {
771
0
                MVM_oops(tc, "Arg spesh: slurpy hash type was not a VMHash as expected");
772
0
            }
773
232
774
232
            /* Populate it with unused named args, if needed, boxing them on
775
232
             * the way. */
776
232
            if (named_passed > named_used)
777
176
                for (i = 0; i < named_passed; i++)
778
108
                    if (!(named_used_bit_field & ((MVMuint64)1 << i)))
779
72
                        slurp_named_arg(tc, g, param_sn_bb, param_sn_ins, i);
780
232
        }
781
10.7k
782
10.7k
        /* Stash the named used bit field in the graph; will need to make it
783
10.7k
         * into the candidate and all the way to deopt. */
784
10.7k
        g->deopt_named_used_bit_field = named_used_bit_field;
785
10.7k
    }
786
11.0k
787
11.0k
  cleanup:
788
11.0k
    MVM_free(pos_ins);
789
11.0k
    MVM_free(pos_bb);
790
11.0k
    MVM_free(pos_added);
791
11.0k
    MVM_free(named_ins);
792
11.0k
    MVM_free(named_bb);
793
11.0k
}