Skip to content

Instantly share code, notes, and snippets.

@niner
Created October 5, 2021 16:36
Show Gist options
  • Save niner/ce782bfcf5eeb96fbfef3fbe78e34375 to your computer and use it in GitHub Desktop.
Save niner/ce782bfcf5eeb96fbfef3fbe78e34375 to your computer and use it in GitHub Desktop.
diff --git a/src/core/nativecall.c b/src/core/nativecall.c
index 248b9c7c1..f6ec39450 100644
--- a/src/core/nativecall.c
+++ b/src/core/nativecall.c
@@ -1203,3 +1203,12 @@ void MVM_nativecall_invoke_jit(MVMThreadContext *tc, MVMObject *site) {
assert(jitcode->func_ptr);
jitcode->func_ptr(tc, *tc->interp_cu, jitcode->labels[0]);
}
+
+MVMObject *MVM_nativecall_args(MVMThreadContext *tc, MVMArgs *invoke_args) {
+ MVMObject *args_list = REPR(tc->instance->boot_types.BOOTArray)->allocate(tc, STABLE(tc->instance->boot_types.BOOTArray));
+ MVMCapture *args = invoke_args->source[invoke_args->map[0]].o;
+ MVMint64 num_args = MVM_capture_num_args(tc, args);
+ for (MVMint64 i = 1; i < num_args; i++)
+ MVM_repr_push_o(tc, args_list, MVM_capture_arg_pos_o(tc, args, i));
+ return args_list;
+}
diff --git a/src/core/nativecall.h b/src/core/nativecall.h
index f7325eb4e..fa75ef986 100644
--- a/src/core/nativecall.h
+++ b/src/core/nativecall.h
@@ -103,6 +103,7 @@ MVMObject * MVM_nativecall_cast(MVMThreadContext *tc, MVMObject *target_spec,
MVMObject *res_type, MVMObject *obj);
MVMint64 MVM_nativecall_sizeof(MVMThreadContext *tc, MVMObject *obj);
void MVM_nativecall_refresh(MVMThreadContext *tc, MVMObject *cthingy);
+MVMObject *MVM_nativecall_args(MVMThreadContext *tc, MVMArgs *invoke_args);
MVMObject * MVM_nativecall_make_cstruct(MVMThreadContext *tc, MVMObject *type, void *cstruct);
MVMObject * MVM_nativecall_make_cppstruct(MVMThreadContext *tc, MVMObject *type, void *cppstruct);
diff --git a/src/disp/boot.c b/src/disp/boot.c
index 2bf8b1ccf..11278db3f 100644
--- a/src/disp/boot.c
+++ b/src/disp/boot.c
@@ -80,6 +80,33 @@ MVMObject * MVM_disp_boot_code_constant_dispatch(MVMThreadContext *tc) {
return wrap(tc, boot_code_constant);
}
+static void boot_foreign_code(MVMThreadContext *tc, MVMArgs arg_info) {
+ MVMArgProcContext arg_ctx;
+ MVM_args_proc_setup(tc, &arg_ctx, arg_info);
+ MVM_args_checkarity(tc, &arg_ctx, 1, 1);
+ MVMObject *capture = MVM_args_get_required_pos_obj(tc, &arg_ctx, 0);
+ MVMROOT(tc, capture, {
+ /* Get a capture dropping the first argument, which is the callee. */
+ MVMObject *args_capture = MVM_disp_program_record_capture_drop_arg(tc, capture, 0);
+
+ /* Work out what the callee is, and set us up to invoke it. */
+ MVMObject *code = MVM_capture_arg_pos_o(tc, capture, 0);
+ if (REPR(code)->ID == MVM_REPR_ID_MVMNativeCall && IS_CONCRETE(code)) {
+ MVM_disp_program_record_foreign_code_constant(tc, (MVMNativeCall *)code, args_capture);
+ }
+ else {
+ MVM_exception_throw_adhoc(tc,
+ "boot-foreign-code dispatcher only works with MVMNativeCall, got %s", REPR(code)->name);
+ }
+ });
+
+ MVM_args_set_result_obj(tc, tc->instance->VMNull, MVM_RETURN_CURRENT_FRAME);
+}
+
+MVMObject * MVM_disp_boot_foreign_code_dispatch(MVMThreadContext *tc) {
+ return wrap(tc, boot_foreign_code);
+}
+
/* The boot-code dispatcher takes the first positional argument of the
* incoming argument capture, which should be either an MVMCode or an
* MVMCFunction. It establishes a type and concreteness guard on it,
diff --git a/src/disp/boot.h b/src/disp/boot.h
index 4d6517876..0a60ab705 100644
--- a/src/disp/boot.h
+++ b/src/disp/boot.h
@@ -2,6 +2,7 @@ MVMObject * MVM_disp_boot_constant_dispatch(MVMThreadContext *tc);
MVMObject * MVM_disp_boot_value_dispatch(MVMThreadContext *tc);
MVMObject * MVM_disp_boot_code_constant_dispatch(MVMThreadContext *tc);
MVMObject * MVM_disp_boot_code_dispatch(MVMThreadContext *tc);
+MVMObject * MVM_disp_boot_foreign_code_dispatch(MVMThreadContext *tc);
MVMObject * MVM_disp_boot_syscall_dispatch(MVMThreadContext *tc);
MVMObject * MVM_disp_boot_resume_dispatch(MVMThreadContext *tc);
MVMObject * MVM_disp_boot_resume_caller_dispatch(MVMThreadContext *tc);
diff --git a/src/disp/labels.h b/src/disp/labels.h
index 78f1e3b3a..a6a5ddcdb 100644
--- a/src/disp/labels.h
+++ b/src/disp/labels.h
@@ -51,5 +51,6 @@ static const void * const LABELS[] = {
&&MVMDispOpcodeUseArgsTail,
&&MVMDispOpcodeCopyArgsTail,
&&MVMDispOpcodeResultBytecode,
- &&MVMDispOpcodeResultCFunction
+ &&MVMDispOpcodeResultCFunction,
+ &&MVMDispOpcodeResultForeignFunction
};
diff --git a/src/disp/program.c b/src/disp/program.c
index 0fa2389a7..93829e41b 100644
--- a/src/disp/program.c
+++ b/src/disp/program.c
@@ -2,8 +2,8 @@
/* Debug dumping, to figure out what we're recording and what programs we are
* inferring from those recordings. */
-#define DUMP_RECORDINGS 0
-#define DUMP_PROGRAMS 0
+#define DUMP_RECORDINGS 1
+#define DUMP_PROGRAMS 1
#if DUMP_RECORDINGS
static void dump_recording_capture(MVMThreadContext *tc,
@@ -157,6 +157,9 @@ static void dump_recording(MVMThreadContext *tc, MVMCallStackDispatchRecord *rec
case MVM_DISP_OUTCOME_CFUNCTION:
fprintf(stderr, " Run C function of value %d\n", record->rec.outcome_value);
break;
+ case MVM_DISP_OUTCOME_FOREIGNFUNCTION:
+ fprintf(stderr, " Run foreign function of value %d\n", record->rec.outcome_value);
+ break;
default:
printf(" Unknown\n");
}
@@ -432,6 +435,10 @@ static void dump_program(MVMThreadContext *tc, MVMDispProgram *dp) {
fprintf(stderr, " Invoke MVMCFunction in temporary %d\n",
op->res_code.temp_invokee);
break;
+ case MVMDispOpcodeResultForeignFunction:
+ fprintf(stderr, " Invoke foreign function in temporary %d\n",
+ op->res_code.temp_invokee);
+ break;
default:
fprintf(stderr, " UNKNOWN OP %d\n", op->code);
@@ -1683,6 +1690,24 @@ void MVM_disp_program_record_c_code_constant(MVMThreadContext *tc, MVMCFunction
record->outcome.args.source = ((MVMCapture *)capture)->body.args;
}
+void MVM_disp_program_record_foreign_code_constant(MVMThreadContext *tc, MVMNativeCall *result, MVMObject *capture) {
+ /* Record the result action. */
+ MVMCallStackDispatchRecord *record = MVM_callstack_find_topmost_dispatch_recording(tc);
+ ensure_known_capture(tc, record, capture);
+ MVMRegister value = { .o = (MVMObject *)result };
+ record->rec.outcome_value = value_index_constant(tc, &(record->rec),
+ MVM_CALLSITE_ARG_OBJ, value);
+ record->rec.outcome_capture = capture;
+
+ /* Set up the invoke outcome. */
+ MVMCallsite *callsite = ((MVMCapture *)capture)->body.callsite;
+ record->outcome.kind = MVM_DISP_OUTCOME_FOREIGNFUNCTION;
+ record->outcome.site = result;
+ record->outcome.args.callsite = callsite;
+ record->outcome.args.map = MVM_args_identity_map(tc, callsite);
+ record->outcome.args.source = ((MVMCapture *)capture)->body.args;
+}
+
/* Record a program terminator that invokes bytecode from a tracked value (for
* example, from a capture or attribute read). Guards are established against
* the tracked value for both type and concreteness as a side-effect. */
@@ -2688,6 +2713,22 @@ static void process_recording(MVMThreadContext *tc, MVMCallStackDispatchRecord *
MVM_VECTOR_PUSH(cs.ops, op);
break;
}
+ case MVM_DISP_OUTCOME_FOREIGNFUNCTION: {
+ /* Make sure we load the invokee into a temporary before we go any
+ * further. This is the last temporary we add before dealing with
+ * args. Also put callsite into constant table. */
+ MVMuint32 temp_invokee = get_temp_holding_value(tc, &cs, record->rec.outcome_value);
+ MVMuint32 callsite_idx = add_program_constant_callsite(tc, &cs,
+ ((MVMCapture *)record->rec.outcome_capture)->body.callsite);
+
+ /* Produce the args op(s), and then add the dispatch op. */
+ emit_args_ops(tc, record, &cs, callsite_idx);
+ MVMDispProgramOp op;
+ op.code = MVMDispOpcodeResultForeignFunction;
+ op.res_code.temp_invokee = temp_invokee;
+ MVM_VECTOR_PUSH(cs.ops, op);
+ break;
+ }
default:
MVM_oops(tc, "Unimplemented dispatch outcome compilation");
}
@@ -2751,7 +2792,7 @@ MVMuint32 MVM_disp_program_record_end(MVMThreadContext *tc, MVMCallStackDispatch
run_dispatch(tc, record, record->outcome.delegate_disp,
record->outcome.delegate_capture, thunked);
else
- MVM_exception_throw_adhoc(tc, "Dispatch callback failed to delegate to a dispatcher");
+ MVM_oops(tc, "Dispatch callback failed to delegate to a dispatcher");
return 0;
case MVM_DISP_OUTCOME_RESUME: {
MVMDispProgramRecordingResumption *rec_resumption = get_current_resumption(tc, record);
@@ -2839,6 +2880,16 @@ MVMuint32 MVM_disp_program_record_end(MVMThreadContext *tc, MVMCallStackDispatch
tc->cur_frame->return_type = record->orig_return_type;
record->outcome.c_func(tc, record->outcome.args);
return 1;
+ case MVM_DISP_OUTCOME_FOREIGNFUNCTION:
+ process_recording(tc, record);
+ MVM_disp_program_recording_destroy(tc, &(record->rec));
+ record->common.kind = MVM_CALLSTACK_RECORD_DISPATCH_RECORDED;
+ tc->cur_frame = find_calling_frame(tc, tc->stack_top->prev);
+ tc->cur_frame->return_type = record->orig_return_type;
+ fprintf(stderr, "outcome foreign function result %s\n", REPR(record->outcome.args.source[record->outcome.args.map[0]].o)->name);
+ MVMObject *args = record->outcome.args.source[record->outcome.args.map[0]].o;
+ MVM_nativecall_invoke(tc, MVM_capture_arg_pos_o(tc, args, 0), (MVMObject *)record->outcome.site, MVM_nativecall_args(tc, &record->outcome.args));
+ return 1;
default:
MVM_oops(tc, "Unimplemented dispatch program outcome kind");
}
@@ -3219,6 +3270,18 @@ MVMint64 MVM_disp_program_run(MVMThreadContext *tc, MVMDispProgram *dp,
MVM_callstack_unwind_dispatch_run(tc);
goto accept;
}
+ OP(MVMDispOpcodeResultForeignFunction): {
+ record->chosen_dp = dp;
+ if (spesh_cid)
+ MVM_spesh_log_dispatch_resolution_for_correlation_id(tc, spesh_cid,
+ bytecode_offset, dp_index);
+ fprintf(stderr, "result foreign function result %s", REPR(invoke_args.source[invoke_args.map[0]].o)->name);
+ MVMObject *code = record->temps[op.res_code.temp_invokee].o;
+ MVMObject *args = invoke_args.source[invoke_args.map[0]].o;
+ MVM_nativecall_invoke(tc, MVM_capture_arg_pos_o(tc, args, 0), code, MVM_nativecall_args(tc, &invoke_args));
+ MVM_callstack_unwind_dispatch_run(tc);
+ goto accept;
+ }
#if !MVM_CGOTO
default:
MVM_oops(tc, "Unknown dispatch program op %d", op.code);
@@ -3384,6 +3447,10 @@ void MVM_disp_program_mark_outcome(MVMThreadContext *tc, MVMDispProgramOutcome *
add_collectable(tc, worklist, snapshot, outcome->code,
"Dispatch outcome (bytecode)");
break;
+ case MVM_DISP_OUTCOME_FOREIGNFUNCTION:
+ add_collectable(tc, worklist, snapshot, outcome->site,
+ "Dispatch outcome (foreign function)");
+ break;
}
}
@@ -3487,6 +3554,7 @@ const char *MVM_disp_opcode_to_name(MVMDispProgramOpcode op) {
case MVMDispOpcodeCopyArgsTail: return "MVMDispOpcodeCopyArgsTail";
case MVMDispOpcodeResultBytecode: return "MVMDispOpcodeResultBytecode";
case MVMDispOpcodeResultCFunction: return "MVMDispOpcodeResultCFunction";
+ case MVMDispOpcodeResultForeignFunction: return "MVMDispOpcodeResultForeignFunction";
default:
return "<unknown>";
}
diff --git a/src/disp/program.h b/src/disp/program.h
index 709632770..5ba7a7e57 100644
--- a/src/disp/program.h
+++ b/src/disp/program.h
@@ -45,7 +45,10 @@ typedef enum {
MVM_DISP_OUTCOME_BYTECODE,
/* Invoke a C function. */
- MVM_DISP_OUTCOME_CFUNCTION
+ MVM_DISP_OUTCOME_CFUNCTION,
+
+ /* Invoke a foreign C function. */
+ MVM_DISP_OUTCOME_FOREIGNFUNCTION
} MVMDispProgramOutcomeKind;
/* The outcome of a dispatch program. Used only in the record case; the run
@@ -68,6 +71,9 @@ struct MVMDispProgramOutcome {
MVMCode *code;
/* The C function to be invoked. */
void (*c_func) (MVMThreadContext *tc, MVMArgs arg_info);
+
+ /* The native call site to be invoked. */
+ MVMNativeCall *site;
};
/* Arguments for an invocation (must point into otherwise marked
* areas). */
@@ -482,7 +488,10 @@ typedef enum {
MVMDispOpcodeResultBytecode,
/* Set a C function object result, specifying invokee and callsite.
* The args should already have been set up. */
- MVMDispOpcodeResultCFunction
+ MVMDispOpcodeResultCFunction,
+ /* Set a foreign function object result, specifying invokee and callsite.
+ * The args should already have been set up. */
+ MVMDispOpcodeResultForeignFunction
} MVMDispProgramOpcode;
/* An operation, with its operands, in a dispatch program. */
@@ -647,6 +656,8 @@ void MVM_disp_program_record_result_tracked_value(MVMThreadContext *tc, MVMObjec
void MVM_disp_program_record_code_constant(MVMThreadContext *tc, MVMCode *result, MVMObject *capture);
void MVM_disp_program_record_c_code_constant(MVMThreadContext *tc, MVMCFunction *result,
MVMObject *capture);
+void MVM_disp_program_record_foreign_code_constant(MVMThreadContext *tc,
+ MVMNativeCall *result, MVMObject *capture);
void MVM_disp_program_record_tracked_code(MVMThreadContext *tc, MVMObject *tracked,
MVMObject *capture);
void MVM_disp_program_record_tracked_c_code(MVMThreadContext *tc, MVMObject *tracked,
diff --git a/src/disp/registry.c b/src/disp/registry.c
index 894ef8023..9ca3e2af8 100644
--- a/src/disp/registry.c
+++ b/src/disp/registry.c
@@ -92,6 +92,7 @@ void MVM_disp_registry_init(MVMThreadContext *tc) {
register_boot_dispatcher(tc, "boot-value", MVM_disp_boot_value_dispatch(tc));
register_boot_dispatcher(tc, "boot-code-constant", MVM_disp_boot_code_constant_dispatch(tc));
register_boot_dispatcher(tc, "boot-code", MVM_disp_boot_code_dispatch(tc));
+ register_boot_dispatcher(tc, "boot-foreign-code", MVM_disp_boot_foreign_code_dispatch(tc));
register_boot_dispatcher(tc, "boot-syscall", MVM_disp_boot_syscall_dispatch(tc));
register_boot_dispatcher(tc, "boot-resume", MVM_disp_boot_resume_dispatch(tc));
register_boot_dispatcher(tc, "boot-resume-caller", MVM_disp_boot_resume_caller_dispatch(tc));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment