Skip to content

Commit

Permalink
JIT compile JITed native calls
Browse files Browse the repository at this point in the history
While we already generated machine code for performing the actual call to the
C function, we perform all deconting and unboxing of arguments in high level
code. This is so that spesh can optimize this code to what's actually
necessary for a given call site.

For JIT compilation of the specialized code, we compile the call to the C
function again, but this time instead of tailoring it to getting the return
type from the runloop, we use can access information gathered by spesh for
determining the register holding the return type. The generated JIT graph is
seamlessly included in the wrapper function body's graph.

A function call with a single argument thus results in JIT compiled code for:
<sp_getarg_o>, <set>, <decont_i>, invokish control guard, <set>, <PHI>, <PHI>,
<wval>, <wval>, MVM_gc_mark_thread_blocked, the actual call,
MVM_gc_mark_thread_unblocked, call to box the return value, <return_o>

Since at this stage the code calling the nativeinvoke_o op cannot change
anymore, we can access the WORK registers directly, saving the copying
of those to tc->cur_frame->args.
  • Loading branch information
niner committed Sep 19, 2017
1 parent 2d21965 commit ecdba29
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 11 deletions.
40 changes: 29 additions & 11 deletions src/core/nativecall.c
Expand Up @@ -388,17 +388,26 @@ void init_c_call_node(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMJitNode *node,
node->u.call.rv_idx = -1;
}

void init_box_call_node(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMJitNode *box_rv_node, void *func_ptr) {
void init_box_call_node(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMJitNode *box_rv_node, void *func_ptr, MVMint16 restype, MVMint16 dst) {
MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
{ MVM_JIT_REG_DYNIDX, { 2 } },
{ MVM_JIT_SAVED_RV, { 0 } }};
init_c_call_node(tc, sg, box_rv_node, func_ptr, 3, args);
box_rv_node->next = NULL;
box_rv_node->u.call.rv_mode = MVM_JIT_RV_DYNIDX;
box_rv_node->u.call.rv_idx = 0;
if (dst == -1) {
box_rv_node->u.call.rv_mode = MVM_JIT_RV_DYNIDX;
box_rv_node->u.call.rv_idx = 0;
}
else {
box_rv_node->u.call.args[1].type = MVM_JIT_REG_VAL;
box_rv_node->u.call.args[1].v.reg = restype;

box_rv_node->u.call.rv_mode = MVM_JIT_RV_PTR;
box_rv_node->u.call.rv_idx = dst;
}
}

MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMNativeCallBody *body) {
MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMNativeCallBody *body, MVMint16 restype, MVMint16 dst) {
MVMJitGraph *jg = MVM_spesh_alloc(tc, sg, sizeof(MVMJitGraph)); /* will actually calloc */
MVMJitNode *block_gc_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
MVMJitNode *unblock_gc_node = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
Expand Down Expand Up @@ -435,10 +444,10 @@ MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMS
case MVM_NATIVECALL_ARG_INT:
case MVM_NATIVECALL_ARG_LONG:
case MVM_NATIVECALL_ARG_LONGLONG:
arg_type = MVM_JIT_ARG_I64;
arg_type = dst == -1 ? MVM_JIT_ARG_I64 : MVM_JIT_PARAM_I64;
break;
case MVM_NATIVECALL_ARG_CPOINTER:
arg_type = MVM_JIT_ARG_PTR;
arg_type = dst == -1 ? MVM_JIT_ARG_PTR : MVM_JIT_PARAM_PTR;
break;
default:
goto fail;
Expand All @@ -458,10 +467,10 @@ MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMS
call_node->next = save_rv_node;
jg->last_node = unblock_gc_node->next = box_rv_node;

init_box_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_int);
init_box_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_int, restype, dst);
}
else if (body->ret_type == MVM_NATIVECALL_ARG_CPOINTER) {
init_box_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_cpointer);
init_box_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_cpointer, restype, dst);
}
else if (body->ret_type == MVM_NATIVECALL_ARG_UTF8STR) {
MVMJitCallArg args[] = { { MVM_JIT_INTERP_VAR , { MVM_JIT_INTERP_TC } },
Expand All @@ -470,8 +479,17 @@ MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMS
{ MVM_JIT_SAVED_RV, { 0 } }};
init_c_call_node(tc, sg, box_rv_node, &MVM_nativecall_make_str, 4, args);
box_rv_node->next = NULL;
box_rv_node->u.call.rv_mode = MVM_JIT_RV_DYNIDX;
box_rv_node->u.call.rv_idx = 0;
if (dst == -1) {
box_rv_node->u.call.rv_mode = MVM_JIT_RV_DYNIDX;
box_rv_node->u.call.rv_idx = 0;
}
else {
box_rv_node->u.call.args[1].type = MVM_JIT_REG_VAL;
box_rv_node->u.call.args[1].v.reg = restype;

box_rv_node->u.call.rv_mode = MVM_JIT_RV_PTR;
box_rv_node->u.call.rv_idx = dst;
}
}
else if (body->ret_type == MVM_NATIVECALL_ARG_VOID) {
call_node->next = unblock_gc_node;
Expand All @@ -489,7 +507,7 @@ MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMS

MVMJitCode *create_caller_code(MVMThreadContext *tc, MVMNativeCallBody *body) {
MVMSpeshGraph *sg = MVM_calloc(1, sizeof(MVMSpeshGraph));
MVMJitGraph *jg = MVM_nativecall_jit_graph_for_caller_code(tc, sg, body);
MVMJitGraph *jg = MVM_nativecall_jit_graph_for_caller_code(tc, sg, body, -1, -1);
MVMJitCode *jitcode;
if (jg != NULL) {
MVMJitNode *entry_label = MVM_spesh_alloc(tc, sg, sizeof(MVMJitNode));
Expand Down
1 change: 1 addition & 0 deletions src/core/nativecall.h
Expand Up @@ -128,3 +128,4 @@ void * MVM_nativecall_unmarshal_carray(MVMThreadContext *tc, MVMObject *value);
void * MVM_nativecall_unmarshal_vmarray(MVMThreadContext *tc, MVMObject *value);
void * MVM_nativecall_unmarshal_cunion(MVMThreadContext *tc, MVMObject *value);
MVMThreadContext * MVM_nativecall_find_thread_context(MVMInstance *instance);
MVMJitGraph *MVM_nativecall_jit_graph_for_caller_code(MVMThreadContext *tc, MVMSpeshGraph *sg, MVMNativeCallBody *body, MVMint16 restype, MVMint16 dst);
26 changes: 26 additions & 0 deletions src/jit/graph.c
Expand Up @@ -292,6 +292,7 @@ static void * op_to_func(MVMThreadContext *tc, MVMint16 opcode) {
case MVM_OP_isnanorinf: return MVM_num_isnanorinf;
case MVM_OP_nativecallcast: return MVM_nativecall_cast;
case MVM_OP_nativecallinvoke: return MVM_nativecall_invoke;
case MVM_OP_nativeinvoke_o: return MVM_nativecall_invoke_jit;
case MVM_OP_typeparameterized: return MVM_6model_parametric_type_parameterized;
case MVM_OP_typeparameters: return MVM_6model_parametric_type_parameters;
case MVM_OP_typeparameterat: return MVM_6model_parametric_type_parameter_at;
Expand Down Expand Up @@ -423,6 +424,30 @@ static MVMint32 consume_invoke(MVMThreadContext *tc, MVMJitGraph *jg,
spesh_cand = -1;
is_fast = 0;
goto checkargs;
case MVM_OP_nativeinvoke_o: {
MVMint16 dst = ins->operands[0].reg.orig;
MVMint16 site = ins->operands[1].reg.orig;
MVMint16 restype = ins->operands[2].reg.orig;
MVMNativeCallBody *body;
MVMJitGraph *nc_jg;
MVMObject *nc_site;

MVMSpeshFacts *object_facts = MVM_spesh_get_facts(tc, iter->graph, ins->operands[1]);

MVM_jit_log(tc, "Invoke instruction: <%s>\n", ins->info->name);

if (!(object_facts->flags & MVM_SPESH_FACT_KNOWN_VALUE)) {
MVM_oops(tc, "Can't find nc_site value on spesh ins <%s> %d", ins->info->name, object_facts->flags);
}

body = MVM_nativecall_get_nc_body(tc, object_facts->value.o);
nc_jg = MVM_nativecall_jit_graph_for_caller_code(tc, iter->graph, body, restype, dst);

jg->last_node->next = nc_jg->first_node;
jg->last_node = nc_jg->last_node;

goto success;
}
case MVM_OP_sp_fastinvoke_v:
return_type = MVM_RETURN_VOID;
return_register = -1;
Expand Down Expand Up @@ -490,6 +515,7 @@ static MVMint32 consume_invoke(MVMThreadContext *tc, MVMJitGraph *jg,

/* append reentry label */
jg_append_label(tc, jg, reentry_label);
success:
/* move forward to invoke ins */
iter->ins = ins;
return 1;
Expand Down
2 changes: 2 additions & 0 deletions src/jit/graph.h
Expand Up @@ -102,6 +102,8 @@ typedef enum {
MVM_JIT_SAVED_RV,
MVM_JIT_ARG_I64,
MVM_JIT_ARG_PTR,
MVM_JIT_PARAM_I64,
MVM_JIT_PARAM_PTR,
} MVMJitArgType;

struct MVMJitCallArg {
Expand Down
9 changes: 9 additions & 0 deletions src/jit/x64/emit.dasc
Expand Up @@ -1940,6 +1940,13 @@ static void load_call_arg(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJit
| mov TMP6, qword REGISTER:TMP6[arg.v.lit_i64];
| mov TMP6, aword STOOGE:TMP6->data;
break;
case MVM_JIT_PARAM_I64:
| mov TMP6, qword WORK[arg.v.lit_i64];
break;
case MVM_JIT_PARAM_PTR:
| mov TMP6, aword WORK[arg.v.lit_i64];
| mov TMP6, aword STOOGE:TMP6->data;
break;
default:
MVM_oops(tc, "JIT: Unknown JIT argument type %d", arg.type);
}
Expand Down Expand Up @@ -2059,6 +2066,8 @@ static void emit_posix_callargs(MVMThreadContext *tc, MVMJitCompiler *compiler,
case MVM_JIT_SAVED_RV:
case MVM_JIT_ARG_I64:
case MVM_JIT_ARG_PTR:
case MVM_JIT_PARAM_I64:
case MVM_JIT_PARAM_PTR:
if (num_gpr < 6) {
in_gpr[num_gpr++] = args[i];
} else {
Expand Down

0 comments on commit ecdba29

Please sign in to comment.