Skip to content

Commit

Permalink
Add boot-foreign-code dispatch terminal to replace native(call)invoke…
Browse files Browse the repository at this point in the history
… ops

With the new dispatch terminal, NativeCall will be able to benefit from the
more efficient argument passing conventions. It will also benefit from dispatch
programs tailored to the callsite, i.e. being able to replace more costly
checks for containers with cheap guards.
  • Loading branch information
niner committed Oct 11, 2021
1 parent 6da3b18 commit dd7560f
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 4 deletions.
8 changes: 8 additions & 0 deletions src/core/nativecall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1203,3 +1203,11 @@ 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));
MVMint64 num_args = invoke_args->callsite->num_pos;
for (MVMint64 i = 1; i < num_args; i++)
MVM_repr_push_o(tc, args_list, invoke_args->source[invoke_args->map[i]].o);
return args_list;
}
1 change: 1 addition & 0 deletions src/core/nativecall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
27 changes: 27 additions & 0 deletions src/disp/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/disp/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/disp/labels.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ static const void * const LABELS[] = {
&&MVMDispOpcodeUseArgsTail,
&&MVMDispOpcodeCopyArgsTail,
&&MVMDispOpcodeResultBytecode,
&&MVMDispOpcodeResultCFunction
&&MVMDispOpcodeResultCFunction,
&&MVMDispOpcodeResultForeignCode
};
78 changes: 77 additions & 1 deletion src/disp/program.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_FOREIGNCODE:
fprintf(stderr, " Run foreign function of value %d\n", record->rec.outcome_value);
break;
default:
printf(" Unknown\n");
}
Expand Down Expand Up @@ -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 MVMDispOpcodeResultForeignCode:
fprintf(stderr, " Invoke foreign function in temporary %d\n",
op->res_code.temp_invokee);
break;

default:
fprintf(stderr, " UNKNOWN OP %d\n", op->code);
Expand Down Expand Up @@ -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_FOREIGNCODE;
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. */
Expand Down Expand Up @@ -2688,6 +2713,22 @@ static void process_recording(MVMThreadContext *tc, MVMCallStackDispatchRecord *
MVM_VECTOR_PUSH(cs.ops, op);
break;
}
case MVM_DISP_OUTCOME_FOREIGNCODE: {
/* 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 = MVMDispOpcodeResultForeignCode;
op.res_code.temp_invokee = temp_invokee;
MVM_VECTOR_PUSH(cs.ops, op);
break;
}
default:
MVM_oops(tc, "Unimplemented dispatch outcome compilation");
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -2839,6 +2880,21 @@ 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_FOREIGNCODE:
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);

/* allocates, so must come before other local variables! */
MVMObject *args = MVM_nativecall_args(tc, &record->outcome.args);

MVMObject *site = (MVMObject *)record->outcome.site;
MVMObject *result_type = record->outcome.args.source[record->outcome.args.map[0]].o;
MVMObject *result = MVM_nativecall_invoke(tc, result_type, site, args);
tc->cur_frame->return_type = record->orig_return_type;
MVM_args_set_dispatch_result_obj(tc, tc->cur_frame, result);
return 1;
default:
MVM_oops(tc, "Unimplemented dispatch program outcome kind");
}
Expand Down Expand Up @@ -3219,6 +3275,21 @@ MVMint64 MVM_disp_program_run(MVMThreadContext *tc, MVMDispProgram *dp,
MVM_callstack_unwind_dispatch_run(tc);
goto accept;
}
OP(MVMDispOpcodeResultForeignCode): {
record->chosen_dp = dp;
if (spesh_cid)
MVM_spesh_log_dispatch_resolution_for_correlation_id(tc, spesh_cid,
bytecode_offset, dp_index);

/* allocates, so must come before other local variables! */
MVMObject *args = MVM_nativecall_args(tc, &invoke_args);

MVMObject *result_type = invoke_args.source[invoke_args.map[0]].o;
MVMObject *result = MVM_nativecall_invoke(tc, result_type, record->temps[op.res_code.temp_invokee].o, args);
MVM_args_set_dispatch_result_obj(tc, tc->cur_frame, result);
MVM_callstack_unwind_dispatch_run(tc);
goto accept;
}
#if !MVM_CGOTO
default:
MVM_oops(tc, "Unknown dispatch program op %d", op.code);
Expand Down Expand Up @@ -3384,6 +3455,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_FOREIGNCODE:
add_collectable(tc, worklist, snapshot, outcome->site,
"Dispatch outcome (foreign function)");
break;
}
}

Expand Down Expand Up @@ -3487,6 +3562,7 @@ const char *MVM_disp_opcode_to_name(MVMDispProgramOpcode op) {
case MVMDispOpcodeCopyArgsTail: return "MVMDispOpcodeCopyArgsTail";
case MVMDispOpcodeResultBytecode: return "MVMDispOpcodeResultBytecode";
case MVMDispOpcodeResultCFunction: return "MVMDispOpcodeResultCFunction";
case MVMDispOpcodeResultForeignCode: return "MVMDispOpcodeResultForeignCode";
default:
return "<unknown>";
}
Expand Down
15 changes: 13 additions & 2 deletions src/disp/program.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_FOREIGNCODE
} MVMDispProgramOutcomeKind;

/* The outcome of a dispatch program. Used only in the record case; the run
Expand All @@ -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). */
Expand Down Expand Up @@ -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. */
MVMDispOpcodeResultForeignCode
} MVMDispProgramOpcode;

/* An operation, with its operands, in a dispatch program. */
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/disp/registry.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
1 change: 1 addition & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ typedef struct MVMCallStackDispatchRun MVMCallStackDispatchRun;
typedef struct MVMCallStackBindControl MVMCallStackBindControl;
typedef struct MVMCallStackArgsFromC MVMCallStackArgsFromC;
typedef struct MVMCallStackDeoptedResumeInit MVMCallStackDeoptedResumeInit;
typedef struct MVMCallStackNestedRunloop MVMCallStackNestedRunloop;
typedef struct MVMCallStackRegion MVMCallStackRegion;
typedef struct MVMCallStackIterator MVMCallStackIterator;
typedef struct MVMCFunction MVMCFunction;
Expand Down

0 comments on commit dd7560f

Please sign in to comment.