From ecdba29f9f64c889c5314c6c2541979ab89d02fa Mon Sep 17 00:00:00 2001 From: Stefan Seifert Date: Sun, 3 Sep 2017 16:49:25 +0200 Subject: [PATCH] JIT compile JITed native calls 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: , , , invokish control guard, , , , , , MVM_gc_mark_thread_blocked, the actual call, MVM_gc_mark_thread_unblocked, call to box the return value, 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. --- src/core/nativecall.c | 40 +++++++++++++++++++++++++++++----------- src/core/nativecall.h | 1 + src/jit/graph.c | 26 ++++++++++++++++++++++++++ src/jit/graph.h | 2 ++ src/jit/x64/emit.dasc | 9 +++++++++ 5 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/core/nativecall.c b/src/core/nativecall.c index ab8c74d286..1c89fe18f9 100644 --- a/src/core/nativecall.c +++ b/src/core/nativecall.c @@ -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)); @@ -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; @@ -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 } }, @@ -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; @@ -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)); diff --git a/src/core/nativecall.h b/src/core/nativecall.h index 05015996f4..890bfe93cd 100644 --- a/src/core/nativecall.h +++ b/src/core/nativecall.h @@ -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); diff --git a/src/jit/graph.c b/src/jit/graph.c index 5b35112aa9..f58ed2e9d6 100644 --- a/src/jit/graph.c +++ b/src/jit/graph.c @@ -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; @@ -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; @@ -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; diff --git a/src/jit/graph.h b/src/jit/graph.h index 7319fa0732..70b09c3692 100644 --- a/src/jit/graph.h +++ b/src/jit/graph.h @@ -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 { diff --git a/src/jit/x64/emit.dasc b/src/jit/x64/emit.dasc index a248a0f23c..ae2ad75a42 100644 --- a/src/jit/x64/emit.dasc +++ b/src/jit/x64/emit.dasc @@ -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); } @@ -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 {