Skip to content

Instantly share code, notes, and snippets.

@niner
Created July 30, 2021 16:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niner/f566f86fc525c151b904f392cbca20f9 to your computer and use it in GitHub Desktop.
Save niner/f566f86fc525c151b904f392cbca20f9 to your computer and use it in GitHub Desktop.
diff --git a/src/core/frame.c b/src/core/frame.c
index 129a24191..7e47bd199 100644
--- a/src/core/frame.c
+++ b/src/core/frame.c
@@ -556,6 +556,14 @@ void MVM_frame_invoke(MVMThreadContext *tc, MVMStaticFrame *static_frame,
}
/* Dispatches execution to the specified code object with the specified args. */
+void MVM_frame_dispatch_jit(MVMThreadContext *tc, MVMCode *code, MVMCallsite *callsite, MVMRegister *source, MVMuint16 *map, MVMint32 spesh_cand) {
+ MVMArgs args = {
+ .callsite = callsite,
+ .source = source,
+ .map = map
+ };
+ MVM_frame_dispatch(tc, code, args, spesh_cand);
+}
void MVM_frame_dispatch(MVMThreadContext *tc, MVMCode *code, MVMArgs args, MVMint32 spesh_cand) {
MVMFrame *frame;
MVMuint8 *chosen_bytecode;
diff --git a/src/core/frame.h b/src/core/frame.h
index 433e4e37a..2650d79d0 100644
--- a/src/core/frame.h
+++ b/src/core/frame.h
@@ -190,6 +190,7 @@ void MVM_frame_invoke(MVMThreadContext *tc, MVMStaticFrame *static_frame,
MVMCallsite *callsite, MVMRegister *args,
MVMFrame *outer, MVMObject *code_ref, MVMint32 spesh_cand);
void MVM_frame_dispatch(MVMThreadContext *tc, MVMCode *code, MVMArgs args, MVMint32 spesh_cand);
+void MVM_frame_dispatch_jit(MVMThreadContext *tc, MVMCode *code, MVMCallsite *callsite, MVMRegister *source, MVMuint16 *map, MVMint32 spesh_cand);
void MVM_frame_dispatch_zero_args(MVMThreadContext *tc, MVMCode *code);
MVMFrame * MVM_frame_create_context_only(MVMThreadContext *tc, MVMStaticFrame *static_frame,
MVMObject *code_ref);
diff --git a/src/jit/compile.c b/src/jit/compile.c
index f85e6fdb1..5d0cbdd30 100644
--- a/src/jit/compile.c
+++ b/src/jit/compile.c
@@ -97,6 +97,9 @@ MVMJitCode * MVM_jit_compile_graph(MVMThreadContext *tc, MVMJitGraph *jg) {
case MVM_JIT_NODE_INVOKE:
MVM_jit_emit_invoke(tc, &cl, jg, &node->u.invoke);
break;
+ case MVM_JIT_NODE_RUNCODE:
+ MVM_jit_emit_runcode(tc, &cl, jg, &node->u.runcode);
+ break;
case MVM_JIT_NODE_JUMPLIST:
MVM_jit_emit_jumplist(tc, &cl, jg, &node->u.jumplist);
break;
diff --git a/src/jit/graph.c b/src/jit/graph.c
index c007062cf..5cb3b2019 100644
--- a/src/jit/graph.c
+++ b/src/jit/graph.c
@@ -3709,6 +3709,27 @@ start:
jg_append_call_c(tc, jg, op_to_func(tc, op), 1, args, MVM_JIT_RV_PTR, dst);
break;
}
+ case MVM_OP_sp_runcfunc_i: {
+ MVMint16 dst = ins->operands[0].reg.orig;
+ MVMint16 code = ins->operands[1].reg.orig;
+ MVMCallsite *callsite = (MVMCallsite*)ins->operands[2].lit_ui64;
+
+ /* get label /after/ current (invoke) ins, where we'll need to reenter the JIT */
+ MVMint32 reentry_label = MVM_jit_label_after_ins(tc, jg, iter->bb, ins);
+ MVMJitNode *node = MVM_spesh_alloc(tc, jg->sg, sizeof(MVMJitNode));
+ node->type = MVM_JIT_NODE_RUNCODE;
+ node->u.runcode.callsite = callsite;
+ node->u.runcode.return_type = MVM_RETURN_INT;
+ node->u.runcode.return_register = dst;
+ node->u.runcode.code_register = code;
+ node->u.runcode.map = &ins->operands[3];
+ node->u.runcode.spesh_cand = -1;
+ node->u.runcode.reentry_label = reentry_label;
+ jg_append_node(jg, node);
+ /* append reentry label */
+ jg_append_label(tc, jg, reentry_label);
+ break;
+ }
default: {
/* Check if it's an extop. */
MVMint32 emitted_extop = 0;
diff --git a/src/jit/graph.h b/src/jit/graph.h
index 83f01ba51..ba322e0f3 100644
--- a/src/jit/graph.h
+++ b/src/jit/graph.h
@@ -189,6 +189,16 @@ struct MVMJitInvoke {
MVMint32 reentry_label;
};
+struct MVMJitRunCode {
+ MVMCallsite *callsite;
+ MVMReturnType return_type;
+ MVMint16 return_register;
+ MVMint16 code_register;
+ MVMint16 spesh_cand;
+ MVMSpeshOperand *map;
+ MVMint32 reentry_label;
+};
+
struct MVMJitJumpList {
MVMint64 num_labels;
MVMint16 reg;
@@ -221,6 +231,7 @@ typedef enum {
MVM_JIT_NODE_DATA,
MVM_JIT_NODE_EXPR_TREE,
MVM_JIT_NODE_DEOPT_CHECK,
+ MVM_JIT_NODE_RUNCODE,
} MVMJitNodeType;
struct MVMJitNode {
@@ -238,6 +249,7 @@ struct MVMJitNode {
MVMJitData data;
MVMJitExprTree *tree;
MVMJitStackSlot stack;
+ MVMJitRunCode runcode;
} u;
};
diff --git a/src/jit/x64/emit.dasc b/src/jit/x64/emit.dasc
index 360c3f46b..e0d0a12bc 100644
--- a/src/jit/x64/emit.dasc
+++ b/src/jit/x64/emit.dasc
@@ -121,6 +121,7 @@
|.type MPINT, mp_int
|.type MVMDISPINLINECACHEENTRY, MVMDispInlineCacheEntry
|.type MVMDISPINLINECACHE, MVMDispInlineCache
+|.type CFUNCTION, MVMCFunction
/* Static allocation of relevant types to registers. I pick
* callee-save registers for efficiency. It is likely we'll be calling
@@ -228,7 +229,6 @@ const unsigned char * MVM_jit_actions(void) {
|.define RVb, al
|.define RVF, xmm0
-
|.macro callp, funcptr
|.data
|5:
@@ -3024,6 +3024,59 @@ void MVM_jit_emit_guard(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGr
|2:
}
+void MVM_jit_emit_runcode(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitRunCode *runcode) {
+ MVMint16 i;
+ MVMuint64 callsite = (MVMuint64)runcode->callsite;
+ fprintf(stderr, "emit_runcode for %s %p return type %d code %d map %p reentry_label %d\n", MVM_string_utf8_maybe_encode_C_string(tc, jg->sg->sf->body.name), runcode->callsite, runcode->return_type, runcode->code_register, runcode->map, runcode->reentry_label);
+
+ |.data
+ |5:
+ for (i = 0; i < runcode->callsite->flag_count; i++) {
+ |.word (MVMuint16)runcode->map[i].lit_ui16;
+ }
+ |.code
+
+ /* The return address for the interpreter */
+ | get_cur_op TMP2;
+ | mov TMP5, TC->cur_frame;
+ | mov aword FRAME:TMP5->return_address, TMP2;
+
+ /* Store callsite in tmp6, which we use at the end of invoke */
+ | mov64 TMP6, callsite;
+
+ /* Store callsite in the frame. I use TMP5 as it never conflicts
+ * with argument passing (like TMP6, but unlike other TMP regs) */
+ | mov FRAME:TMP5->cur_args_callsite, TMP6;
+
+ /* Setup the frame for returning to our current position */
+ if (sizeof(MVMReturnType) == 1) {
+ | mov byte FRAME:TMP5->return_type, runcode->return_type;
+ } else {
+ MVM_panic(1, "JIT: MVMReturnType has unexpected size");
+ }
+
+ /* The register for our return value */
+ if (runcode->return_type == MVM_RETURN_VOID) {
+ | mov aword FRAME:TMP5->return_value, NULL;
+ } else {
+ | lea TMP2, WORK[runcode->return_register];
+ | mov aword FRAME:TMP5->return_value, TMP2;
+ }
+
+ | mov ARG1, TC;
+ /* TMP6 initialized by loadp callsite above */
+ emit_stack_arg(tc, compiler, jg, 8, 0);
+ | mov TMP6, TC->interp_reg_base;
+ | mov TMP6, [TMP6];
+ emit_stack_arg(tc, compiler, jg, 8, 8);
+ | lea TMP6, [<5];
+ emit_stack_arg(tc, compiler, jg, 8, 16);
+ | mov FUNCTION, qword WORK[runcode->code_register];
+ | mov FUNCTION, CFUNCTION:FUNCTION->body.func;
+ | call FUNCTION
+ | mov WORK[runcode->return_register], RV
+}
+
void MVM_jit_emit_invoke(MVMThreadContext *tc, MVMJitCompiler *compiler, MVMJitGraph *jg, MVMJitInvoke *invoke) {
MVMint16 i;
MVMuint16 callsite_idx = invoke->callsite_idx;
diff --git a/src/types.h b/src/types.h
index 03edfbcaf..268fa8fe1 100644
--- a/src/types.h
+++ b/src/types.h
@@ -263,6 +263,7 @@ typedef struct MVMJitJumpList MVMJitJumpList;
typedef struct MVMJitControl MVMJitControl;
typedef struct MVMJitData MVMJitData;
typedef struct MVMJitStackSlot MVMJitStackSlot;
+typedef struct MVMJitRunCode MVMJitRunCode;
typedef struct MVMJitCode MVMJitCode;
typedef struct MVMJitCompiler MVMJitCompiler;
typedef struct MVMJitExprTree MVMJitExprTree;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment