コード例 #1
0
ファイル: callsite.c プロジェクト: Revlin/MoarVM
/* Checks if two callsiates are equal. */
static MVMint32 callsites_equal(MVMThreadContext *tc, MVMCallsite *cs1, MVMCallsite *cs2,
                                MVMint32 num_flags, MVMint32 num_nameds) {
    MVMint32 i;

    if (memcmp(cs1->arg_flags, cs2->arg_flags, num_flags))
        return 0;

    for (i = 0; i < num_nameds; i++)
        if (!MVM_string_equal(tc, cs1->arg_names[i], cs2->arg_names[i]))
            return 0;

    return 1;
}
コード例 #2
0
ファイル: sc.c プロジェクト: ryandietrich/MoarVM
/* Creates a new serialization context with the specified handle. If any
 * compilation units are waiting for an SC with this handle, removes it from
 * their to-resolve list after installing itself in the appropriate slot. */
MVMObject * MVM_sc_create(MVMThreadContext *tc, MVMString *handle) {
    MVMObject   *sc;
    MVMCompUnit *cur_cu;

    /* Allocate. */
    MVMROOT(tc, handle, {
        sc = REPR(tc->instance->SCRef)->allocate(tc, STABLE(tc->instance->SCRef));
        MVMROOT(tc, sc, {
            REPR(sc)->initialize(tc, STABLE(sc), sc, OBJECT_BODY(sc));

            /* Set handle. */
            MVM_ASSIGN_REF(tc, sc, ((MVMSerializationContext *)sc)->body->handle, handle);

            /* Add to weak lookup hash. */
            if (apr_thread_mutex_lock(tc->instance->mutex_sc_weakhash) != APR_SUCCESS)
                MVM_exception_throw_adhoc(tc, "Unable to lock SC weakhash");
            MVM_string_flatten(tc, handle);
            MVM_HASH_BIND(tc, tc->instance->sc_weakhash, handle, ((MVMSerializationContext *)sc)->body);
            if (apr_thread_mutex_unlock(tc->instance->mutex_sc_weakhash) != APR_SUCCESS)
                MVM_exception_throw_adhoc(tc, "Unable to unlock SC weakhash");

            /* Visit compilation units that need this SC and resolve it. */
            cur_cu = tc->instance->head_compunit;
            while (cur_cu) {
                if (cur_cu->scs_to_resolve) {
                    MVMuint32 i;
                    for (i = 0; i < cur_cu->num_scs; i++) {
                        MVMString *res = cur_cu->scs_to_resolve[i];
                        if (res && MVM_string_equal(tc, res, handle)) {
                            cur_cu->scs[i] = (MVMSerializationContext *)sc;
                            cur_cu->scs_to_resolve[i] = NULL;
                            break;
                        }
                    }
                }
                cur_cu = cur_cu->next_compunit;
            }
        });
    });
コード例 #3
0
ファイル: args.c プロジェクト: Revlin/MoarVM
/* Takes information about the incoming callsite and arguments, and performs
 * various optimizations based on that information. */
void MVM_spesh_args(MVMThreadContext *tc, MVMSpeshGraph *g, MVMCallsite *cs, MVMRegister *args) {
    /* We need to identify the various arg-related instructions in the graph,
     * then manipulate them as a whole. */
    MVMSpeshIns  *checkarity_ins     = NULL;
    MVMSpeshBB   *checkarity_bb      = NULL;
    MVMSpeshIns  *paramnamesused_ins = NULL;
    MVMSpeshBB   *paramnamesused_bb  = NULL;
    MVMSpeshIns  *param_sp_ins       = NULL;
    MVMSpeshBB   *param_sp_bb        = NULL;
    MVMSpeshIns  *param_sn_ins       = NULL;
    MVMSpeshBB   *param_sn_bb        = NULL;

    MVMSpeshIns **pos_ins    = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshIns *));
    MVMSpeshBB  **pos_bb     = MVM_calloc(MAX_POS_ARGS, sizeof(MVMSpeshBB *));
    MVMuint8     *pos_added  = MVM_calloc(MAX_POS_ARGS, sizeof(MVMuint8));
    MVMSpeshIns **named_ins  = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *));
    MVMSpeshBB  **named_bb   = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshBB *));
    MVMSpeshIns **used_ins   = MVM_calloc(MAX_NAMED_ARGS, sizeof(MVMSpeshIns *));
    MVMint32      req_max    = -1;
    MVMint32      opt_min    = -1;
    MVMint32      opt_max    = -1;
    MVMint32      num_named  = 0;
    MVMint32      named_used = 0;
    MVMint32      got_named  = cs->num_pos != cs->arg_count;

    /* Walk through the graph, looking for arg related instructions. */
    MVMSpeshBB *bb = g->entry;
    while (bb) {
        MVMSpeshIns *ins = bb->first_ins;
        while (ins) {
            switch (ins->info->opcode) {
            case MVM_OP_checkarity:
                if (checkarity_ins)
                    goto cleanup; /* Dupe; weird; bail out! */
                checkarity_ins = ins;
                checkarity_bb  = bb;
                break;
            case MVM_OP_param_rp_i:
            case MVM_OP_param_rp_n:
            case MVM_OP_param_rp_s:
            case MVM_OP_param_rp_o: {
                /* Required positional. */
                MVMint16 idx = ins->operands[1].lit_i16;
                if (idx < 0 || idx >= MAX_POS_ARGS)
                    goto cleanup;
                if (pos_ins[idx]) /* Dupe; weird. */
                    goto cleanup;
                pos_ins[idx] = ins;
                pos_bb[idx]  = bb;
                if (idx > req_max)
                    req_max = idx;
                break;
            }
            case MVM_OP_param_op_i:
            case MVM_OP_param_op_n:
            case MVM_OP_param_op_s:
            case MVM_OP_param_op_o: {
                /* Optional Positional int/num/string/object */
                MVMint16 idx = ins->operands[1].lit_i16;
                if (idx < 0 || idx >= MAX_POS_ARGS)
                    goto cleanup;
                if (pos_ins[idx]) /* Dupe; weird. */
                    goto cleanup;
                pos_ins[idx] = ins;
                pos_bb[idx]  = bb;
                if (idx > opt_max)
                    opt_max = idx;
                if (opt_min == -1 || idx < opt_min)
                    opt_min = idx;
                break;
            }
            case MVM_OP_param_on_i:
            case MVM_OP_param_on_n:
            case MVM_OP_param_on_s:
            case MVM_OP_param_on_o:
            case MVM_OP_param_rn_i:
            case MVM_OP_param_rn_n:
            case MVM_OP_param_rn_s:
            case MVM_OP_param_rn_o:
                /* Named (optional or required). */
                if (num_named == MAX_NAMED_ARGS)
                    goto cleanup;
                named_ins[num_named] = ins;
                named_bb[num_named]  = bb;
                num_named++;
                break;
            case MVM_OP_param_sp:
                param_sp_ins = ins;
                param_sp_bb  = bb;
                break;
            case MVM_OP_param_sn:
                param_sn_ins = ins;
                param_sn_bb  = bb;
                break;
            case MVM_OP_usecapture:
            case MVM_OP_savecapture:
                /* Require full args processing context for now; bail. */
                goto cleanup;
            case MVM_OP_paramnamesused:
                if (paramnamesused_ins)
                    goto cleanup; /* Dupe; weird; bail out! */
                paramnamesused_ins = ins;
                paramnamesused_bb  = bb;
                break;
            }
            ins = ins->next;
        }
        bb = bb->linear_next;
    }

    /* If we didn't find a checkarity instruction, bail. */
    if (!checkarity_ins)
        goto cleanup;

    /* If required and optional aren't contiguous, bail. */
    if (opt_min >= 0 && req_max + 1 != opt_min)
        goto cleanup;

    /* If the number of passed args is in range... */
    if (cs->num_pos >= req_max + 1 && (opt_max < 0 || cs->num_pos <= opt_max + 1)) {
        /* Ensure we've got all the arg fetch instructions we need, and that
         * types match or it's a box/unbox. */
        MVMint32 i;
        for (i = 0; i < cs->num_pos; i++) {
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
            if (!pos_ins[i])
                goto cleanup;
            switch (pos_ins[i]->info->opcode) {
            case MVM_OP_param_rp_i:
            case MVM_OP_param_op_i:
                if (arg_flag != MVM_CALLSITE_ARG_INT)
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ || 
                            prim_spec(tc, args[i].o) != MVM_STORAGE_SPEC_BP_INT)
                        goto cleanup;
                break;
            case MVM_OP_param_rp_n:
            case MVM_OP_param_op_n:
                if (arg_flag != MVM_CALLSITE_ARG_NUM)
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ || 
                            prim_spec(tc, args[i].o) != MVM_STORAGE_SPEC_BP_NUM)
                        goto cleanup;
                break;
            case MVM_OP_param_rp_s:
            case MVM_OP_param_op_s:
                if (arg_flag != MVM_CALLSITE_ARG_STR)
                    if (arg_flag != MVM_CALLSITE_ARG_OBJ || 
                            prim_spec(tc, args[i].o) != MVM_STORAGE_SPEC_BP_STR)
                        goto cleanup;
                break;
            case MVM_OP_param_rp_o:
            case MVM_OP_param_op_o:
                if (arg_flag != MVM_CALLSITE_ARG_OBJ && arg_flag != MVM_CALLSITE_ARG_INT &&
                    arg_flag != MVM_CALLSITE_ARG_NUM && arg_flag != MVM_CALLSITE_ARG_STR)
                    goto cleanup;
                break;
            }
        }

        /* If we know there's no incoming nameds we can always turn param_sn into a
         * simple hash creation. This will typically be further lowered in optimize. */
        if (param_sn_ins && !got_named) {
            MVMObject *hash_type = g->sf->body.cu->body.hll_config->slurpy_hash_type;
            if (REPR(hash_type)->ID == MVM_REPR_ID_MVMHash) {
                MVMSpeshOperand target    = param_sn_ins->operands[0];
                param_sn_ins->info        = MVM_op_get_op(MVM_OP_sp_fastcreate);
                param_sn_ins->operands    = MVM_spesh_alloc(tc, g, 3 * sizeof(MVMSpeshOperand));
                param_sn_ins->operands[0] = target;
                param_sn_ins->operands[1].lit_i16 = sizeof(MVMHash);
                param_sn_ins->operands[2].lit_i16 = MVM_spesh_add_spesh_slot(tc, g,
                    (MVMCollectable *)STABLE(hash_type));
            }
            else {
                goto cleanup;
            }
        }

        /* We can optimize. Toss checkarity. */
        MVM_spesh_manipulate_delete_ins(tc, g, checkarity_bb, checkarity_ins);

        /* Re-write the passed required positionals to spesh ops, and store
         * any gurads. */
        if (cs->arg_count)
            g->arg_guards = MVM_malloc(2 * cs->arg_count * sizeof(MVMSpeshGuard));
        for (i = 0; i < cs->num_pos; i++) {
            MVMCallsiteEntry arg_flag = cs->arg_flags[i];
            switch (pos_ins[i]->info->opcode) {
            case MVM_OP_param_rp_i:
            case MVM_OP_param_op_i:
                if (arg_flag == MVM_CALLSITE_ARG_INT) {
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
                }
                else {
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
                    pos_added[i]++;
                    if (args[i].o)
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
                }
                break;
            case MVM_OP_param_rp_n:
            case MVM_OP_param_op_n:
                if (arg_flag == MVM_CALLSITE_ARG_NUM) {
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
                }
                else {
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
                    pos_added[i]++;
                    if (args[i].o)
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
                }
                break;
            case MVM_OP_param_rp_s:
            case MVM_OP_param_op_s:
                if (arg_flag == MVM_CALLSITE_ARG_STR) {
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
                }
                else {
                    pos_unbox(tc, g, pos_bb[i], pos_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
                    pos_added[i]++;
                    if (args[i].o)
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
                }
                break;
            case MVM_OP_param_rp_o:
            case MVM_OP_param_op_o:
                if (arg_flag == MVM_CALLSITE_ARG_OBJ) {
                    pos_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
                    if (args[i].o)
                        add_guards_and_facts(tc, g, i, args[i].o, pos_ins[i]);
                }
                else if (arg_flag == MVM_CALLSITE_ARG_INT) {
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
                        MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
                        MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
                    pos_added[i] += 2;
                }
                else if (arg_flag == MVM_CALLSITE_ARG_NUM) {
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
                        MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
                        MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
                    pos_added[i] += 2;
                }
                else if (arg_flag == MVM_CALLSITE_ARG_STR) {
                    pos_box(tc, g, pos_bb[i], pos_ins[i],
                        MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
                        MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
                    pos_added[i] += 2;
                }
                break;
            }
            pos_ins[i]->operands[1].lit_i16 = (MVMint16)i;
        }

        /* Now consider any optionals. */
        if (opt_min >= 0) {
            for (i = opt_min; i <= opt_max; i++) {
                MVMuint8 passed = i < cs->num_pos;
                if (passed) {
                    /* If we know the argument has been passed, then add a goto
                     * to the "passed" code. */
                    MVMSpeshIns *after = pos_ins[i];
                    while (pos_added[i]--)
                        after = after->next;
                    MVM_spesh_manipulate_insert_goto(tc, g, pos_bb[i], after,
                        pos_ins[i]->operands[2].ins_bb);

                    /* Inserting an unconditional goto makes the linear_next BB
                    * unreachable, so we remove it from the succ list. */
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
                        pos_bb[i]->linear_next);
                } else {
                    /* If we didn't pass this, just fall through the original
                    * operation and we'll get the default value set. */
                    MVM_spesh_manipulate_delete_ins(tc, g, pos_bb[i], pos_ins[i]);
                    MVM_spesh_manipulate_remove_successor(tc, pos_bb[i],
                        pos_ins[i]->operands[2].ins_bb);
                }
            }
        }

        /* Now consider any nameds. */
        for (i = 0; i < num_named; i++) {
            /* See if the arg was passed. */
            MVMString *arg_name      = MVM_spesh_get_string(tc, g, named_ins[i]->operands[1]);
            MVMint32   passed_nameds = (cs->arg_count - cs->num_pos) / 2;
            MVMint32   cs_flags      = cs->num_pos + passed_nameds;
            MVMint32   cur_idx       = 0;
            MVMint32   cur_named     = 0;
            MVMuint8   found_flag    = 0;
            MVMint32   found_idx     = -1;
            MVMint32   j;
            for (j = 0; j < cs_flags; j++) {
                if (cs->arg_flags[j] & MVM_CALLSITE_ARG_NAMED) {
                    if (MVM_string_equal(tc, arg_name, cs->arg_names[cur_named])) {
                        /* Found it. */
                        found_flag = cs->arg_flags[j];
                        found_idx  = cur_idx;
                        break;
                    }
                    cur_idx += 2;
                    cur_named++;
                }
                else {
                    cur_idx++;
                }
            }

            /* Now go by instruction. */
            switch (named_ins[i]->info->opcode) {
            case MVM_OP_param_rn_i:
                if (found_idx == -1)
                    goto cleanup;
                if (found_flag & MVM_CALLSITE_ARG_INT) {
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_INT) {
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
                }
                named_used++;
                break;
            case MVM_OP_param_rn_n:
                if (found_idx == -1)
                    goto cleanup;
                if (found_flag & MVM_CALLSITE_ARG_NUM) {
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_NUM) {
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
                }
                named_used++;
                break;
            case MVM_OP_param_rn_s:
                if (found_idx == -1)
                    goto cleanup;
                if (found_flag & MVM_CALLSITE_ARG_STR) {
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_STR) {
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
                }
                named_used++;
                break;
            case MVM_OP_param_rn_o:
                if (found_idx == -1)
                    goto cleanup;
                if (found_flag & MVM_CALLSITE_ARG_OBJ) {
                    MVMuint16 arg_idx = found_idx + 1;
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                    if (args[arg_idx].o)
                        add_guards_and_facts(tc, g, arg_idx, args[arg_idx].o, named_ins[i]);
                }
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
                    MVMuint16 arg_idx = found_idx + 1;
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
                    if (found_flag & MVM_CALLSITE_ARG_INT)
                        pos_box(tc, g, named_bb[i], named_ins[i],
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
                        pos_box(tc, g, named_bb[i], named_ins[i],
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
                        pos_box(tc, g, named_bb[i], named_ins[i],
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next->next, cur_named);
                }
                named_used++;
                break;
            case MVM_OP_param_on_i:
                if (found_idx == -1) {
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
                }
                else if (found_flag & MVM_CALLSITE_ARG_INT) {
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_i);
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                    named_used++;
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_INT) {
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_i));
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
                    named_used++;
                }
                break;
            case MVM_OP_param_on_n:
                if (found_idx == -1) {
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
                }
                else if (found_flag & MVM_CALLSITE_ARG_NUM) {
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_n);
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                    named_used++;
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_NUM) {
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_n));
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
                    named_used++;
                }
                break;
            case MVM_OP_param_on_s:
                if (found_idx == -1) {
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
                }
                else if (found_flag & MVM_CALLSITE_ARG_STR) {
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_s);
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                    named_used++;
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ
                        && prim_spec(tc, args[found_idx].o) == MVM_STORAGE_SPEC_BP_STR) {
                    named_ins[i]->operands[1].lit_i16 = found_idx + 1;
                    pos_unbox(tc, g, named_bb[i], named_ins[i], MVM_op_get_op(MVM_OP_unbox_s));
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next,
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next, cur_named);
                    named_used++;
                }
                break;
            case MVM_OP_param_on_o:
                if (found_idx == -1) {
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], named_ins[i]);
                }
                else if (found_flag & MVM_CALLSITE_ARG_OBJ) {
                    MVMuint16 arg_idx = found_idx + 1;
                    named_ins[i]->info = MVM_op_get_op(MVM_OP_sp_getarg_o);
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i],
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i], cur_named);
                    if (args[arg_idx].o)
                        add_guards_and_facts(tc, g, arg_idx, args[arg_idx].o, named_ins[i]);
                    named_used++;
                }
                else if (found_flag & (MVM_CALLSITE_ARG_INT | MVM_CALLSITE_ARG_NUM | MVM_CALLSITE_ARG_STR)) {
                    MVMuint16 arg_idx = found_idx + 1;
                    named_ins[i]->operands[1].lit_i16 = arg_idx;
                    if (found_flag & MVM_CALLSITE_ARG_INT)
                        pos_box(tc, g, named_bb[i], named_ins[i],
                            MVM_op_get_op(MVM_OP_hllboxtype_i), MVM_op_get_op(MVM_OP_box_i),
                            MVM_op_get_op(MVM_OP_sp_getarg_i), MVM_reg_int64);
                    else if (found_flag & MVM_CALLSITE_ARG_NUM)
                        pos_box(tc, g, named_bb[i], named_ins[i],
                            MVM_op_get_op(MVM_OP_hllboxtype_n), MVM_op_get_op(MVM_OP_box_n),
                            MVM_op_get_op(MVM_OP_sp_getarg_n), MVM_reg_num64);
                    else if (found_flag & MVM_CALLSITE_ARG_STR)
                        pos_box(tc, g, named_bb[i], named_ins[i],
                            MVM_op_get_op(MVM_OP_hllboxtype_s), MVM_op_get_op(MVM_OP_box_s),
                            MVM_op_get_op(MVM_OP_sp_getarg_s), MVM_reg_str);
                    MVM_spesh_manipulate_insert_goto(tc, g, named_bb[i], named_ins[i]->next->next,
                        named_ins[i]->operands[2].ins_bb);
                    used_ins[i] = add_named_used_ins(tc, g, named_bb[i], named_ins[i]->next->next, cur_named);
                    named_used++;
                }
                break;
            }
        }

        /* If we had no nameds or we used them all, can toss namesused, and we
         * don't need to mark used after all. */
        if (paramnamesused_ins && num_named == named_used) {
            MVM_spesh_manipulate_delete_ins(tc, g, paramnamesused_bb, paramnamesused_ins);
            for (i = 0; i < num_named; i++)
                if (used_ins[i])
                    MVM_spesh_manipulate_delete_ins(tc, g, named_bb[i], used_ins[i]);
        }
    }

  cleanup:
    MVM_free(pos_ins);
    MVM_free(pos_bb);
    MVM_free(pos_added);
    MVM_free(named_ins);
    MVM_free(named_bb);
}