/* 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; }
/* 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; } }); });
/* 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); }