From 39715334c7d73260503d222be7816f8ba7a8b5df Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Fri, 1 Nov 2024 20:54:48 +0300 Subject: [PATCH] types fix, frame fix to work with runtime --- byterun/include/stack.h | 3 +- byterun/include/types.h | 130 +++++++------------------------------- byterun/src/interpreter.c | 12 ++-- byterun/src/stack.c | 82 ++++++++++++------------ byterun/src/types.c | 41 ++++++------ 5 files changed, 92 insertions(+), 176 deletions(-) diff --git a/byterun/include/stack.h b/byterun/include/stack.h index 17fccc8b7..1679345e1 100644 --- a/byterun/include/stack.h +++ b/byterun/include/stack.h @@ -30,5 +30,4 @@ void s_enter_f(struct State *s, char *func_ip, size_t params_sz, void s_exit_f(struct State *s); -union VarT **var_by_category(struct State *s, enum VarCategory category, - int id); +void **var_by_category(struct State *s, enum VarCategory category, int id); diff --git a/byterun/include/types.h b/byterun/include/types.h index bcbd6e338..d0950d37c 100644 --- a/byterun/include/types.h +++ b/byterun/include/types.h @@ -1,131 +1,50 @@ #pragma once #include "../../runtime/runtime.h" +#include "../../runtime/runtime_common.h" #include "parser.h" #include -// ------ Var ------ +// ------ General ------ enum Type { - NIL_T = 0x00000000, - INT_T = 0x00000001, - BOX_T = 0x00000002, - STR_T = 0x00000003, - CLOJURE_T = 0x00000004, - ARRAY_T = 0x00000005, - SEXP_T = 0x00000006, - FUN_T = 0x00000007 + STR_T = STRING_TAG, + ARRAY_T = ARRAY_TAG, + SEXP_T = SEXP_TAG, + CLOJURE_T = CLOSURE_TAG, }; -struct NilT { // AnyVarT too - uint32_t data_header; -}; - -struct IntT { - uint32_t data_header; - int32_t value; -}; - -struct BoxT { - uint32_t data_header; - struct NilT **value; -}; - -struct StrT { - uint32_t data_header; // param - is not const (0 for const, 1 for not const) - const char *value; -}; - -struct ClojureT { // TODO - uint32_t data_header; - char *fun_ip; - struct ArrayT *vars; -}; - -// struct ListT { -// uint32_t data_header; -// struct NilT *value; -// struct NilT *next; -// }; - -struct ArrayT { - uint32_t data_header; - struct NilT **values; -}; static const size_t MAX_ARRAY_SIZE = 0x11111110; -struct SExpT { - uint32_t data_header; - const char *tag; - struct NilT **values; -}; - -struct FunT { - uint32_t data_header; - char *fun_ip; -}; - -union VarT { - struct NilT nil; - struct IntT int_t; - struct BoxT box; - struct StrT str; - struct ClojureT clojure; - // struct ListT list; - struct ArrayT array; - struct SExpT sexp; - struct FunT fun; -}; - -// same to TAG in runtime -static inline enum Type dh_type(int data_header) { - return (enum Type)(data_header & 0x00000007); -} - -// same to LEN in runtime -static inline int dh_param(int data_header) { - return (data_header & 0xFFFFFFF8) >> 3; -} - static inline union VarT *to_var(struct NilT *var) { return (union VarT *)var; } // ------ Frame ------ -// TODO: store boxed offsets instead struct Frame { - struct NilT *ret; // store returned value - char *rp; // ret instruction pointer - struct Frame *prev_fp; // ret function frame pointer - void **params; // store arguments - void **locals; // store locals - void **end; // store locals + void *ret; // store returned value [gc pointer] + char *rp; // ret instruction pointer [not gc pointer] + size_t to_prev_fp_box; // ret function frame pointer [boxed value, not gc + // pointer] + size_t args_sz_box; // store arguments [boxed value, not gc pointer] + size_t locals_sz_box; // store locals [boxed value, not gc pointer] }; -static inline uint64_t frame_locals_sz(struct Frame *frame) { - return frame->locals - frame->params; -} -static inline uint64_t frame_params_sz(struct Frame *frame) { - return frame->end - frame->locals; -} +size_t frame_sz(); +void **f_prev_fp(struct Frame *fp); +uint64_t f_locals_sz(struct Frame *fp); +uint64_t f_args_sz(struct Frame *fp); +void **f_locals(struct Frame *fp); +void **f_args(struct Frame *fp); // ------ State ------ -union StackValue { - union VarT *var; - union VarT **var_ptr; - struct Frame frame; // ?? - char *addr; -}; - -// static inline StackValue *to_sv(void *var) { return (StackValue *)var; } - struct State { void **stack; // vaid** - void **vp; // stack pointer + void **sp; // stack pointer struct Frame *fp; // function frame pointer char *ip; // instruction pointer - char *prev_ip; // prev instruction pointer + char *prev_ip; // prev instruction pointer (to remember jmp locations) }; struct State init_state(bytefile *bf); @@ -137,12 +56,7 @@ enum VarCategory { VAR_GLOBAL = 0, VAR_LOCAL = 1, VAR_ARGUMENT = 2, - VAR_C = 3 // TODO: constant ?? + VAR_C = 3 // TODO: constants ?? }; -static inline enum VarCategory to_var_category(uint8_t category) { - if (category > 3) { - failure("unexpected variable category"); - } - return (enum VarCategory)category; -} +enum VarCategory to_var_category(uint8_t category); diff --git a/byterun/src/interpreter.c b/byterun/src/interpreter.c index 684cbb818..03b93f39c 100644 --- a/byterun/src/interpreter.c +++ b/byterun/src/interpreter.c @@ -111,19 +111,19 @@ void run(bytefile *bf) { case 9: // DUP { // guess - if (s.vp == s.stack || (s.fp != NULL && s.vp == s.fp->end)) { + if (s.sp == s.stack || (s.fp != NULL && s.sp == s.fp->end)) { failure("can't DUP: no value on stack"); } - *s.vp = *(s.vp - 1); - ++s.vp; + *s.sp = *(s.sp - 1); + ++s.sp; break; } case 10: // SWAP { // guess - struct NilT* v = *s.vp; - *s.vp = *(s.vp - 1); - *(s.vp - 1) = v; + struct NilT* v = *s.sp; + *s.sp = *(s.sp - 1); + *(s.sp - 1) = v; } break; diff --git a/byterun/src/stack.c b/byterun/src/stack.c index f0251f8ab..07033b38b 100644 --- a/byterun/src/stack.c +++ b/byterun/src/stack.c @@ -4,12 +4,14 @@ extern size_t STACK_SIZE; +// ------ basic stack oprs ------ + void s_push(struct State *s, void *val) { - if (s->vp == s->stack) { + if (s->sp == s->stack) { failure("stack overflow"); } - --s->vp; - *s->vp = val; + --s->sp; + *s->sp = val; } void s_push_nil(struct State *s) { @@ -23,12 +25,12 @@ void s_pushn_nil(struct State *s, size_t n) { } void* s_pop(struct State *s) { - if (s->vp == s->stack + STACK_SIZE || (s->fp != NULL && s->vp == s->fp->end)) { + if (s->sp == s->stack + STACK_SIZE || (s->fp != NULL && s->sp == f_locals(s->fp))) { failure("take: no var"); } - void* value = *s->vp; - *s->vp = NULL; - ++s->vp; + void* value = *s->sp; + *s->sp = NULL; + ++s->sp; return value; } @@ -41,70 +43,64 @@ void s_popn(struct State *s, size_t n) { // ------ functions ------ -// TODO -// |> param_0 ... param_n | frame[ ret rp prev_fp ¶ms &locals &end ] -// |> local_0 ... local_m |> | ... -// -// where |> defines corresponding frame pointer, | is stack pointer location -// before / after new frame added -void s_enter_f(struct State *s, char *func_ip, size_t params_sz, +void s_enter_f(struct State *s, char *func_ip, size_t args_sz, size_t locals_sz) { - if (params_sz > s->vp - s->stack || - (s->fp != NULL && params_sz > s->vp - s->fp->end)) { + // check that params count is valid + if (args_sz > s->sp + STACK_SIZE - s->stack || + (s->fp != NULL && args_sz > s->sp + STACK_SIZE - f_locals(s->fp))) { failure("not enough parameters in stack"); } - size_t frame_sz_in_ptr = sizeof(struct Frame) / sizeof(void *); + + // create frame struct Frame frame = { .ret = NULL, // field in frame itself .rp = s->ip, - .prev_fp = s->fp, - .params = s->vp - params_sz, - .locals = s->vp + frame_sz_in_ptr, - .end = s->vp + frame_sz_in_ptr + locals_sz, + .to_prev_fp_box = BOX((void**)s->fp - s->sp), + .args_sz_box = BOX(args_sz), + .locals_sz_box = BOX(locals_sz), }; // put frame on stack - s->fp = (struct Frame *)s->vp; + s_push_nil(s); // sp contains value + s->fp = (struct Frame *)s->sp; + s_pushn_nil(s, frame_sz() - 1); (*s->fp) = frame; - // update stack pointer - s->vp = frame.end; + s_pushn_nil(s, locals_sz); // go to function body s->ip = func_ip; } -// TODO void s_exit_f(struct State *s) { if (s->fp == NULL) { failure("exit: no func"); } - // drop stack entities and locals - s_popn(s, f_locals_sz(s->fp)); + struct Frame frame = *s->fp; + push_extra_root((void **)&frame.ret); - // TODO: skip + // drop stack entities, locals, frame + s_popn(s, (void**)s->fp - s->sp + 1); // TODO:check +1 - // drop params - s->vp = (void **)s->fp; - s_popn(s, f_args_sz(s->fp)); + // drop args + s_popn(s, f_args_sz(&frame)); - // s->vp = s->fp->params; // done automatically + // save returned value + s_push(s, frame.ret); - // save ret_val - s_push(s, s->fp->ret); + s->ip = frame.rp; + s->fp = (struct Frame*)f_prev_fp(&frame); - s->ip = s->fp->rp; - s->fp = s->fp->prev_fp; + pop_extra_root((void **)&frame.ret); } -// TODO -union VarT **var_by_category(struct State *s, enum VarCategory category, +void **var_by_category(struct State *s, enum VarCategory category, int id) { if (id < 0) { failure("can't read variable: negative id %i", id); } - union VarT **var = NULL; + void **var = NULL; switch (category) { case VAR_GLOBAL: // TODO: FIXME @@ -113,11 +109,11 @@ union VarT **var_by_category(struct State *s, enum VarCategory category, if (s->fp == NULL) { failure("can't read local outside of function"); } - if (frame_args_sz(s->fp) <= id) { + if (f_args_sz(s->fp) <= id) { failure("can't read local: too big id, %i >= %ul", f_locals_sz(s->fp), id); } - var = (union VarT **)&f_locals_at(s->fp, id); + var = &f_locals(s->fp)[id]; break; case VAR_ARGUMENT: if (s->fp == NULL) { @@ -127,12 +123,14 @@ union VarT **var_by_category(struct State *s, enum VarCategory category, failure("can't read arguments: too big id, %i >= %ul", f_args_sz(s->fp), id); } - var = (union VarT **)&f_args_at(s->fp, id); + var = &f_args(s->fp)[id]; // TODO: check if not reversed order break; case VAR_C: // TODO: ?? break; } + // TODO: push extra root ?? + return var; } diff --git a/byterun/src/types.c b/byterun/src/types.c index f20f885b2..8307b7724 100644 --- a/byterun/src/types.c +++ b/byterun/src/types.c @@ -8,34 +8,31 @@ extern size_t __gc_stack_top, __gc_stack_bottom; const size_t STACK_SIZE = 100000; -// --- +// --- Frame --- -void st_stack_push(struct State* state, void* value) { - +// NOTE: stack is [top -> bottom] +size_t frame_sz() { + return sizeof(struct Frame) / sizeof(void *); } - -void st_stack_pop(struct State* state) { - if (state->vp == st->stack) +void **f_prev_fp(struct Frame *fp) { + return (void **)fp + UNBOX(fp->to_prev_fp_box); } +uint64_t f_locals_sz(struct Frame *fp) { return UNBOX(fp->locals_sz_box); } +uint64_t f_args_sz(struct Frame *fp) { return UNBOX(fp->args_sz_box); } +void **f_locals(struct Frame *fp) { return (void **)fp - f_locals_sz(fp) - frame_sz(); } +void **f_args(struct Frame *fp) { return (void **)fp + f_args_sz(fp); } -size_t st_stack_size(struct State* state) { - return (state->stack + STACK_SIZE) - state->vp; -} -void** st_stack_top(struct State* state) { - return state->vp; -} - -// --- +// --- State --- static struct State alloc_state(bytefile *bf) { struct State state = { - .stack = calloc(STACK_SIZE, sizeof(void*)), + .stack = calloc(STACK_SIZE + 1, sizeof(void*)), .ip = bf->code_ptr, .prev_ip = NULL, }; - state.vp = *state.stack + STACK_SIZE; // [top -> bottom] stack + state.sp = *state.stack + STACK_SIZE; // [top -> bottom] stack state.fp = NULL; return state; } @@ -43,14 +40,14 @@ static struct State alloc_state(bytefile *bf) { struct State init_state(bytefile *bf) { __init(); struct State state = alloc_state(bf); - __gc_stack_bottom = (size_t)state.vp; + __gc_stack_bottom = (size_t)state.sp; return state; } static void destruct_state(struct State* state) { free(state->stack); - state->vp = NULL; + state->sp = NULL; state->fp = NULL; state->ip = NULL; state->prev_ip = NULL; @@ -61,3 +58,11 @@ void cleanup_state(struct State* state) { __shutdown(); } +// --- VarCategory --- + +enum VarCategory to_var_category(uint8_t category) { + if (category > 3) { + failure("unexpected variable category"); + } + return (enum VarCategory)category; +}