Created
October 5, 2021 16:36
-
-
Save niner/ce782bfcf5eeb96fbfef3fbe78e34375 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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