Skip to content

Commit

Permalink
Stub in the boot-syscall mechanism
Browse files Browse the repository at this point in the history
This provides a way to register such calls, and sets them up at startup.
A call has an unchecked implementation body that will pull received args
out without needing to validate them, along with metadata used to do the
validation. A boot-syscall, when it's fully implemented, will on its
first dispatch do these checks and set up the guards. The ultimate goal
is that we can do standard guard elimination on these in spesh, then
call the C function, providing a far more uniform interface for the VM
interanls.
  • Loading branch information
jnthn committed May 20, 2020
1 parent 3fd2bdb commit 9271443
Show file tree
Hide file tree
Showing 18 changed files with 152 additions and 7 deletions.
2 changes: 2 additions & 0 deletions build/Makefile.in
Expand Up @@ -195,6 +195,7 @@ OBJECTS2 = src/6model/reprs/MVMDLLSym@obj@ \
src/disp/registry@obj@ \
src/disp/inline_cache@obj@ \
src/disp/program@obj@ \
src/disp/syscall@obj@ \
src/spesh/dump@obj@ \
src/spesh/graph@obj@ \
src/spesh/codegen@obj@ \
Expand Down Expand Up @@ -366,6 +367,7 @@ HEADERS = src/moar.h \
src/disp/registry.h \
src/disp/inline_cache.h \
src/disp/program.h \
src/disp/syscall.h \
src/spesh/dump.h \
src/spesh/debug.h \
src/spesh/graph.h \
Expand Down
10 changes: 10 additions & 0 deletions src/6model/reprs/MVMCapture.c
Expand Up @@ -141,6 +141,16 @@ MVMObject * MVM_capture_arg_pos_o(MVMThreadContext *tc, MVMObject *capture_obj,
return capture->body.args[idx].o;
}

/* Access a positional string argument of an argument capture object. */
MVMString * MVM_capture_arg_pos_s(MVMThreadContext *tc, MVMObject *capture_obj, MVMuint32 idx) {
MVMCapture *capture = validate_capture(tc, capture_obj);
if (idx >= capture->body.callsite->num_pos)
MVM_exception_throw_adhoc(tc, "Capture argument index out of range");
if ((capture->body.callsite->arg_flags[idx] & MVM_CALLSITE_ARG_TYPE_MASK) != MVM_CALLSITE_ARG_STR)
MVM_exception_throw_adhoc(tc, "Capture argument is not a string argument");
return capture->body.args[idx].s;
}

/* Obtain a positional argument's value and type together. */
void MVM_capture_arg_pos(MVMThreadContext *tc, MVMObject *capture_obj, MVMuint32 idx,
MVMRegister *arg_out, MVMCallsiteFlags *arg_type_out) {
Expand Down
1 change: 1 addition & 0 deletions src/6model/reprs/MVMCapture.h
Expand Up @@ -22,6 +22,7 @@ MVMObject * MVM_capture_from_args(MVMThreadContext *tc, MVMArgs args);
void MVM_capture_arg_pos(MVMThreadContext *tc, MVMObject *capture, MVMuint32 idx,
MVMRegister *arg_out, MVMCallsiteFlags *arg_type_out);
MVMObject * MVM_capture_arg_pos_o(MVMThreadContext *tc, MVMObject *capture, MVMuint32 idx);
MVMString * MVM_capture_arg_pos_s(MVMThreadContext *tc, MVMObject *capture, MVMuint32 idx);

/* Operations for deriving a new MVMCapture from an existing one. */
MVMObject * MVM_capture_drop_arg(MVMThreadContext *tc, MVMObject *capture, MVMuint32 idx);
11 changes: 9 additions & 2 deletions src/core/callstack.c
Expand Up @@ -247,7 +247,7 @@ static void handle_end_of_dispatch_record(MVMThreadContext *tc) {
disp_record->common.kind = MVM_CALLSTACK_RECORD_DISPATCH_RECORDED;
}
}
MVMFrame * MVM_callstack_unwind_frame(MVMThreadContext *tc) {
MVMFrame * MVM_callstack_unwind_frame(MVMThreadContext *tc, MVMuint8 exceptional) {
do {
/* Ensure region and stack top are in a consistent state. */
assert(tc->stack_current_region->start <= (char *)tc->stack_top);
Expand Down Expand Up @@ -279,7 +279,14 @@ MVMFrame * MVM_callstack_unwind_frame(MVMThreadContext *tc) {
tc->stack_top = tc->stack_top->prev;
break;
case MVM_CALLSTACK_RECORD_DISPATCH_RECORD:
handle_end_of_dispatch_record(tc);
if (!exceptional) {
handle_end_of_dispatch_record(tc);
}
else {
/* There was an exception; just leave the frame behind. */
tc->stack_current_region->alloc = (char *)tc->stack_top;
tc->stack_top = tc->stack_top->prev;
}
break;
default:
MVM_panic(1, "Unknown call stack record type in unwind");
Expand Down
2 changes: 1 addition & 1 deletion src/core/callstack.h
Expand Up @@ -184,7 +184,7 @@ void MVM_callstack_continuation_append(MVMThreadContext *tc, MVMCallStackRegion
MVMCallStackRecord *stack_top, MVMObject *update_tag);
MVMFrame * MVM_callstack_first_frame_in_region(MVMThreadContext *tc, MVMCallStackRegion *region);
MVMCallStackDispatchRecord * MVM_callstack_find_topmost_dispatch_recording(MVMThreadContext *tc);
MVMFrame * MVM_callstack_unwind_frame(MVMThreadContext *tc);
MVMFrame * MVM_callstack_unwind_frame(MVMThreadContext *tc, MVMuint8 exceptional);
void MVM_callstack_unwind_dispatcher(MVMThreadContext *tc);
void MVM_callstack_mark_current_thread(MVMThreadContext *tc, MVMGCWorklist *worklist,
MVMHeapSnapshotState *snapshot);
Expand Down
2 changes: 1 addition & 1 deletion src/core/frame.c
Expand Up @@ -1080,7 +1080,7 @@ static MVMuint64 remove_one_frame(MVMThreadContext *tc, MVMuint8 unwind) {

/* Unwind call stack entries. From this, we find out the caller. This may
* actually *not* be the caller in the frame, because of lazy deopt. */
MVMFrame *caller = MVM_callstack_unwind_frame(tc);
MVMFrame *caller = MVM_callstack_unwind_frame(tc, unwind);

/* Switch back to the caller frame if there is one. */
if (caller && (returner != tc->thread_entry_frame || tc->nested_interpreter)) {
Expand Down
3 changes: 3 additions & 0 deletions src/core/instance.h
Expand Up @@ -281,6 +281,9 @@ struct MVMInstance {
/* Registry of dispatchers. */
MVMDispRegistry disp_registry;

/* MoarVM system calls hash (VM-provided functionality). */
MVMDispSysCall *syscalls;

/* Identity mapping for arguments (argument 0 is at position 0, argument
* 1 is at position 1, etc.) */
MVMuint16 *identity_arg_map;
Expand Down
29 changes: 29 additions & 0 deletions src/disp/boot.c
Expand Up @@ -75,3 +75,32 @@ static void boot_code_constant(MVMThreadContext *tc, MVMArgs arg_info) {
MVMObject * MVM_disp_boot_code_constant_dispatch(MVMThreadContext *tc) {
return wrap(tc, boot_code_constant);
}

/* The boot-syscall dispatcher expects the first argument to be a string,
* which will typically be a literal. It uses this to invoke functionality
* provided by the VM. The rest of the arguments are the arguments that go
* to that call. */
static void boot_syscall(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);

/* Look up the syscall information. */
MVMString *name = MVM_capture_arg_pos_s(tc, capture, 0);
MVMDispSysCall *syscall = MVM_disp_syscall_find(tc, name);
if (!syscall) {
char *c_name = MVM_string_utf8_encode_C_string(tc, name);
char *waste[] = { c_name, NULL };
MVM_exception_throw_adhoc_free(tc, waste,
"No MoarVM syscall with name '%s'", c_name);
}
MVM_panic(1, "boot-syscall NYI");

MVM_args_set_result_obj(tc, tc->instance->VMNull, MVM_RETURN_CURRENT_FRAME);
}

/* Gets the MVMCFunction object wrapping the boot syscall dispatcher. */
MVMObject * MVM_disp_boot_syscall_dispatch(MVMThreadContext *tc) {
return wrap(tc, boot_syscall);
}
1 change: 1 addition & 0 deletions src/disp/boot.h
@@ -1,3 +1,4 @@
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_syscall_dispatch(MVMThreadContext *tc);
1 change: 1 addition & 0 deletions src/disp/inline_cache.c
Expand Up @@ -71,6 +71,7 @@ static void dispatch_initial(MVMThreadContext *tc,
MVMCallStackDispatchRecord *record = MVM_callstack_allocate_dispatch_record(tc);
record->initial_capture.o = capture;
record->derived_captures = NULL;
record->outcome.kind = MVM_DISP_OUTCOME_FAILED;

/* Run the dispatcher. */
MVMCallsite *disp_callsite = MVM_callsite_get_common(tc, MVM_CALLSITE_ID_INV_ARG);
Expand Down
4 changes: 2 additions & 2 deletions src/disp/program.c
Expand Up @@ -106,6 +106,8 @@ MVMuint32 MVM_disp_program_record_end(MVMThreadContext *tc, MVMCallStackDispatch
/* Set the result in place. */
MVMFrame *caller = MVM_callstack_record_to_frame(record->common.prev);
switch (record->outcome.kind) {
case MVM_DISP_OUTCOME_FAILED:
return 1;
case MVM_DISP_OUTCOME_VALUE:
switch (record->outcome.result_kind) {
case MVM_reg_obj:
Expand All @@ -124,12 +126,10 @@ MVMuint32 MVM_disp_program_record_end(MVMThreadContext *tc, MVMCallStackDispatch
MVM_oops(tc, "Unknown result kind in dispatch value outcome");
}
return 1;
break;
case MVM_DISP_OUTCOME_BYTECODE:
tc->cur_frame = MVM_callstack_record_to_frame(tc->stack_top->prev);
MVM_frame_dispatch(tc, record->outcome.code, record->outcome.args, -1);
return 0;
break;
default:
MVM_oops(tc, "Unimplemented dispatch program outcome kind");
}
Expand Down
3 changes: 3 additions & 0 deletions src/disp/program.h
Expand Up @@ -24,6 +24,9 @@

/* Kinds of outcome of a dispatch program. */
typedef enum {
/* Indicates we failed to produce an outcome. */
MVM_DISP_OUTCOME_FAILED,

/* Return a value (produced by the dispatch program). */
MVM_DISP_OUTCOME_VALUE,

Expand Down
1 change: 1 addition & 0 deletions src/disp/registry.c
Expand Up @@ -91,6 +91,7 @@ void MVM_disp_registry_init(MVMThreadContext *tc) {
register_boot_dispatcher(tc, "boot-constant", MVM_disp_boot_constant_dispatch(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-syscall", MVM_disp_boot_syscall_dispatch(tc));
MVM_gc_allocate_gen2_default_clear(tc);
}

Expand Down
44 changes: 44 additions & 0 deletions src/disp/syscall.c
@@ -0,0 +1,44 @@
#include "moar.h"

#define EMPTY_HASH_HANDLE { 0, 0, 0, 0, 0 }

/* dispatcher-register */
static void dispatcher_register_impl(MVMThreadContext *tc, MVMArgs arg_info) {
MVM_panic(1, "in syscall but NYI");
}
static MVMDispSysCall dispatcher_register = {
.c_name = "dispatcher-register",
.implementation = dispatcher_register_impl,
.min_args = 2,
.max_args = 3,
.expected_kinds = { MVM_CALLSITE_ARG_STR, MVM_CALLSITE_ARG_OBJ, MVM_CALLSITE_ARG_OBJ },
.expected_reprs = { 0, MVM_REPR_ID_MVMCode, MVM_REPR_ID_MVMCode },
.expected_concrete = { 1, 1, 1 },
.hash_handle = EMPTY_HASH_HANDLE
};

/* Add all of the syscalls into the hash. */
MVM_STATIC_INLINE void add_to_hash(MVMThreadContext *tc, MVMDispSysCall *syscall) {
syscall->name = MVM_string_ascii_decode_nt(tc, tc->instance->VMString, syscall->c_name);
MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&(syscall->name), "MoarVM syscall name");

MVMObject *BOOTCCode = tc->instance->boot_types.BOOTCCode;
MVMObject *code_obj = REPR(BOOTCCode)->allocate(tc, STABLE(BOOTCCode));
((MVMCFunction *)code_obj)->body.func = syscall->implementation;
syscall->wrapper = code_obj;
MVM_gc_root_add_permanent_desc(tc, (MVMCollectable **)&(syscall->wrapper), "MoarVM syscall wrapper");

MVM_HASH_BIND(tc, tc->instance->syscalls, syscall->name, syscall);
}
void MVM_disp_syscall_setup(MVMThreadContext *tc) {
MVM_gc_allocate_gen2_default_set(tc);
add_to_hash(tc, &dispatcher_register);
MVM_gc_allocate_gen2_default_clear(tc);
}

/* Look up a syscall by name. Returns NULL if it's not found. */
MVMDispSysCall * MVM_disp_syscall_find(MVMThreadContext *tc, MVMString *name) {
MVMDispSysCall *syscall;
MVM_HASH_GET(tc, tc->instance->syscalls, name, syscall);
return syscall;
}
40 changes: 40 additions & 0 deletions src/disp/syscall.h
@@ -0,0 +1,40 @@
#define MVM_DISP_SYSCALL_MAX_ARGS 8

/* Information about a VM-provided call. */
struct MVMDispSysCall {
/* Syscall name. */
const char *c_name;
MVMString *name;

/* The implementation. This assumes it can pull out arguments without
* any validation being required on argument count, kinds, and
* representations, which are checked below (and their checks thus
* lifted out as guards, which may be eliminated in optimized code). */
void (*implementation) (MVMThreadContext *tc, MVMArgs arg_info);

/* The function wrapper around the implementation. */
MVMObject *wrapper;

/* Minimum and maximum acceptable number of positional arguments. */
MVMuint8 min_args;
MVMuint8 max_args;

/* Expected argument kinds. */
MVMCallsiteFlags expected_kinds[MVM_DISP_SYSCALL_MAX_ARGS];

/* Expected argument representations. 0 is used to mean "unimportant"
* (the number is actually given to MVMString, but that should always be
* in an s register, not an o register, and so this should never be
* an issue). Only relevant for obj kind registers. */
MVMuint8 expected_reprs[MVM_DISP_SYSCALL_MAX_ARGS];

/* Set to 1 if we expect it to be concrete, otherwise means we don't
* care. Only relevant for obj kind registers. */
MVMuint8 expected_concrete[MVM_DISP_SYSCALL_MAX_ARGS];

/* Inline handle to the hash we use to lookup the calls by name. */
UT_hash_handle hash_handle;
};

void MVM_disp_syscall_setup(MVMThreadContext *tc);
MVMDispSysCall * MVM_disp_syscall_find(MVMThreadContext *tc, MVMString *name);
3 changes: 2 additions & 1 deletion src/moar.c
Expand Up @@ -174,8 +174,9 @@ MVMInstance * MVM_vm_create_instance(void) {
/* Bootstrap 6model. It is assumed the GC will not be called during this. */
MVM_6model_bootstrap(instance->main_thread);

/* Set up the dispatcher registry and the boot dispatchers. */
/* Set up the dispatcher registry, boot dispatchers, and syscalls. */
MVM_disp_registry_init(instance->main_thread);
MVM_disp_syscall_setup(instance->main_thread);

/* Set up main thread's last_payload. */
instance->main_thread->last_payload = instance->VMNull;
Expand Down
1 change: 1 addition & 0 deletions src/moar.h
Expand Up @@ -107,6 +107,7 @@ MVM_PUBLIC MVMint32 MVM_jit_support(void);
#include "core/callsite.h"
#include "core/args.h"
#include "disp/program.h"
#include "disp/syscall.h"
#include "core/exceptions.h"
#include "core/alloc.h"
#include "core/frame.h"
Expand Down
1 change: 1 addition & 0 deletions src/types.h
Expand Up @@ -320,3 +320,4 @@ typedef struct MVMDispInlineCache MVMDispInlineCache;
typedef struct MVMDispInlineCacheEntry MVMDispInlineCacheEntry;
typedef struct MVMDispInlineCacheEntryResolvedGetLexStatic MVMDispInlineCacheEntryResolvedGetLexStatic;
typedef struct MVMDispProgramOutcome MVMDispProgramOutcome;
typedef struct MVMDispSysCall MVMDispSysCall;

0 comments on commit 9271443

Please sign in to comment.