From 1e38ffaefb97f309e30d00133d56273ff505d78e Mon Sep 17 00:00:00 2001 From: ProgramSnail Date: Mon, 4 Nov 2024 01:43:43 +0300 Subject: [PATCH] fixes, some checks, made working on part of simple tests (functions, arrays, operations, read, write, loops) --- byterun/.gitignore | 2 + byterun/include/runtime_externs.h | 6 +- byterun/include/stack.h | 8 +- byterun/include/types.h | 33 +-- byterun/include/utils.h | 10 +- byterun/src/cli.c | 2 +- byterun/src/interpreter.c | 334 +++++++++++++++++------------- byterun/src/parser.c | 8 +- byterun/src/stack.c | 117 +++++++---- byterun/src/types.c | 27 ++- byterun/src/utils.c | 6 +- 11 files changed, 333 insertions(+), 220 deletions(-) diff --git a/byterun/.gitignore b/byterun/.gitignore index b53f86413..a279bf827 100644 --- a/byterun/.gitignore +++ b/byterun/.gitignore @@ -5,6 +5,8 @@ build/ .xmake/ .cache/ +tst/ + compile_commands.json .cache/ *.a diff --git a/byterun/include/runtime_externs.h b/byterun/include/runtime_externs.h index aee167767..88ddba7b7 100644 --- a/byterun/include/runtime_externs.h +++ b/byterun/include/runtime_externs.h @@ -99,9 +99,9 @@ void *Belem(void *p, aint i); void *LmakeArray(aint length); void *LmakeString(aint length); -void *Bstring(aint *args /*void *p*/); -void *Lstringcat(aint *args /* void* p */); -void *Lstring(aint *args /* void *p */); +void *Bstring(aint *p); +void *Lstringcat(aint *p); +void *Lstring(aint *p); void *Bclosure(aint *args, aint bn); void *Barray(aint *args, aint bn); diff --git a/byterun/include/stack.h b/byterun/include/stack.h index ccdae9b9a..fd1187da0 100644 --- a/byterun/include/stack.h +++ b/byterun/include/stack.h @@ -7,6 +7,11 @@ #include "stdlib.h" +void **s_top(struct State *s); +bool s_is_empty(struct State *s); +void **s_peek(struct State *s); +aint *s_peek_i(struct State *s); + void s_push(struct State *s, void *val); void s_push_i(struct State *s, aint val); void s_push_nil(struct State *s); @@ -24,8 +29,7 @@ void s_popn(struct State *s, size_t n); // // where |> defines corresponding frame pointer, | is stack pointer // location before / after new frame added -void s_enter_f(struct State *s, char *func_ip, auint params_sz, - auint locals_sz); +void s_enter_f(struct State *s, char *rp, auint args_sz, auint locals_sz); void s_exit_f(struct State *s); diff --git a/byterun/include/types.h b/byterun/include/types.h index 33ba994c4..a8162b244 100644 --- a/byterun/include/types.h +++ b/byterun/include/types.h @@ -7,24 +7,26 @@ // ------ General ------ -enum Type { - STR_T = STRING_TAG, - ARRAY_T = ARRAY_TAG, - SEXP_T = SEXP_TAG, - CLOJURE_T = CLOSURE_TAG, -}; +// enum Type { +// STR_T = STRING_TAG, +// ARRAY_T = ARRAY_TAG, +// SEXP_T = SEXP_TAG, +// CLOJURE_T = CLOSURE_TAG, +// }; + +#define STACK_SIZE 100000 static const size_t MAX_ARRAY_SIZE = 0x11111110; // ------ Frame ------ struct Frame { - void *ret; // store returned value [gc pointer] - char *rp; // ret instruction pointer [not gc pointer] - aint to_prev_fp_box; // ret function frame pointer [boxed value, not gc - // pointer] - aint args_sz_box; // store arguments [boxed value, not gc pointer] - aint locals_sz_box; // store locals [boxed value, not gc pointer] + void *ret; // store returned value [gc pointer] + char *rp; // ret instruction pointer [not gc pointer] + void **prev_fp; // ret function frame pointer [boxed value, not gc + // pointer] + aint args_sz_box; // store arguments [boxed value, not gc pointer] + aint locals_sz_box; // store locals [boxed value, not gc pointer] }; auint frame_sz(); @@ -37,12 +39,13 @@ void **f_args(struct Frame *fp); // ------ State ------ struct State { - void **stack; // vaid** + void **stack; void **sp; // stack pointer struct Frame *fp; // function frame pointer + bytefile *bf; char *ip; // instruction pointer - char *prev_ip; // prev instruction pointer (to remember jmp locations) + char *call_ip; // prev instruction pointer (to remember jmp locations) }; struct State init_state(bytefile *bf); @@ -58,3 +61,5 @@ enum VarCategory { }; enum VarCategory to_var_category(uint8_t category); + +void print_stack(struct State *s); diff --git a/byterun/include/utils.h b/byterun/include/utils.h index d4443627c..1ac43de82 100644 --- a/byterun/include/utils.h +++ b/byterun/include/utils.h @@ -1,6 +1,10 @@ #pragma once #include +#include +#include + +#include "../../runtime/runtime_common.h" /* The unpacked representation of bytecode file */ typedef struct { @@ -15,12 +19,12 @@ typedef struct { } bytefile; /* Gets a string from a string table by an index */ -char *get_string(bytefile *f, int pos); +char *get_string(bytefile *f, size_t pos); /* Gets a name for a public symbol */ -char *get_public_name(bytefile *f, int i); +char *get_public_name(bytefile *f, size_t i); /* Gets an offset for a public symbol */ -int get_public_offset(bytefile *f, int i); +size_t get_public_offset(bytefile *f, size_t i); // --- diff --git a/byterun/src/cli.c b/byterun/src/cli.c index e5fd2934f..41dcfb873 100644 --- a/byterun/src/cli.c +++ b/byterun/src/cli.c @@ -13,8 +13,8 @@ int main(int argc, char** argv) { bytefile *f = read_file(argv[1]); + dump_file (stdout, f); run(f); -// dump_file (stdout, f); free(f); diff --git a/byterun/src/interpreter.c b/byterun/src/interpreter.c index 8874bb998..563db1aa3 100644 --- a/byterun/src/interpreter.c +++ b/byterun/src/interpreter.c @@ -1,25 +1,21 @@ #include "interpreter.h" -#include "../../runtime/runtime.h" #include "../../runtime/gc.h" +#include "../../runtime/runtime.h" -#include "utils.h" -#include "types.h" -#include "stack.h" #include "runtime_externs.h" +#include "stack.h" +#include "types.h" +#include "utils.h" -extern size_t STACK_SIZE; - -int ip_read_int(char** ip) { +int ip_read_int(char **ip) { *ip += sizeof(int); - return *(int*)((*ip) - sizeof(int)); + return *(int *)((*ip) - sizeof(int)); } -char ip_read_byte(char** ip) { - return *(*ip)++; -} +char ip_read_byte(char **ip) { return *(*ip)++; } -char* ip_read_string(char** ip, bytefile* bf) { +char *ip_read_string(char **ip, bytefile *bf) { return get_string(bf, ip_read_int(ip)); } @@ -27,40 +23,51 @@ char* ip_read_string(char** ip, bytefile* bf) { void run(bytefile *bf) { struct State s = init_state(bf); + print_stack(&s); + + printf("--- interpreter run ---\n"); const size_t OPS_SIZE = 13; - const char *ops [] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"}; - aint(*ops_func[])(void*, void*) = { - &Ls__Infix_43, // + - &Ls__Infix_45, // - - &Ls__Infix_42, // * - &Ls__Infix_47, // / - &Ls__Infix_37, // % - &Ls__Infix_60, // < - &Ls__Infix_6061, // <= - &Ls__Infix_62, // > - &Ls__Infix_6261, // >= - &Ls__Infix_6161, // == - &Ls__Infix_3361, // != - &Ls__Infix_3838, // && - &Ls__Infix_3333, // !! + const char *ops[] = { + "+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"}; + aint (*ops_func[])(void *, void *) = { + &Ls__Infix_43, // + + &Ls__Infix_45, // - + &Ls__Infix_42, // * + &Ls__Infix_47, // / + &Ls__Infix_37, // % + &Ls__Infix_60, // < + &Ls__Infix_6061, // <= + &Ls__Infix_62, // > + &Ls__Infix_6261, // >= + &Ls__Infix_6161, // == + &Ls__Infix_3361, // != + &Ls__Infix_3838, // && + &Ls__Infix_3333, // !! }; const size_t PATS_SIZE = 7; - const char *pats[] = {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"}; - do { - char* before_op_ip = s.ip; // save to set s.prev_ip - - char x = ip_read_byte(&s.ip), - h = (x & 0xF0) >> 4, - l = x & 0x0F; + const char *pats[] = {"=str", "#string", "#array", "#sexp", + "#ref", "#val", "#fun"}; - // fprintf (f, "0x%.8x:\t", ip-bf->code_ptr-1); + // TODO: actual argc, argv + s_push_i(&s, BOX(1)); // argc + const char *argv_0 = "interpreter"; + s_push(&s, Bstring((aint *)&argv_0)); // argv + + printf("- loop start\n"); + + do { + // char *before_op_ip = s.ip; // save to set s.prev_ip + + char x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F; + + printf("0x%.8x\n", s.ip - bf->code_ptr - 1); switch (h) { case 15: goto stop; - + /* BINOP */ case 0: // BINOP ops[l-1] if (l > OPS_SIZE) { @@ -69,132 +76,165 @@ void run(bytefile *bf) { if (l < 1) { failure("BINOP: l < 1"); } - void* left = s_pop(&s); - void* right = s_pop(&s); - s_push(&s, (void*)ops_func[l-1](left, right)); + void *left = s_pop(&s); + void *right = s_pop(&s); + s_push(&s, (void *)ops_func[l - 1](right, left)); break; - + case 1: switch (l) { - case 0: // CONST %d + case 0: // CONST %d s_push_i(&s, BOX(ip_read_int(&s.ip))); break; - - case 1: { // STRING %s - void* str = ip_read_string(&s.ip, bf); - s_push(&s, Bstring((aint*)&str)); + + case 1: { // STRING %s + void *str = ip_read_string(&s.ip, bf); + s_push(&s, Bstring((aint *)&str)); break; } - - case 2: // SEXP %s %d // create sexpr with tag=%s and %d elements from stack + + case 2: // SEXP %s %d // create sexpr with tag=%s and %d elements from + // stack // params read from stack s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf))); - Bsexp((aint*)s.sp, ip_read_int(&s.ip)); // TODO: check order + Bsexp((aint *)s.sp, ip_read_int(&s.ip)); // TODO: check order break; - - case 3: // STI - write by ref (?) + + case 3: // STI - write by ref (?) // TODO break; - - case 4: // STA - write to array elem + + case 4: // STA - write to array elem // Bsta // TODO break; - - case 5: // JMP 0x%.8x - s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check + + case 5: { // JMP 0x%.8x + int jmp_p = ip_read_int(&s.ip); // TODO: check + + if (jmp_p < 0) { + failure("negative file offset jumps are not allowed"); + } + s.ip = bf->code_ptr + jmp_p; break; - - case 6: // END - s_exit_f(&s); // TODO: always ??, check that it is enough + } + + case 6: // END + if (!s_is_empty(&s) && s.fp->prev_fp != 0) { + s.fp->ret = *s_peek(&s); + s_pop(&s); + } + s_exit_f(&s); break; - - case 7: // RET - // TODO + + case 7: // RET + if (!s_is_empty(&s) && s.fp->prev_fp != 0) { + s.fp->ret = *s_peek(&s); + s_pop(&s); + } + s_exit_f(&s); break; - - case 8: // DROP + + case 8: // DROP s_pop(&s); break; - - case 9: // DUP - { - if (s.sp == s.stack + STACK_SIZE || (s.fp != NULL && s.sp == f_locals(s.fp))) { - failure("can't DUP: no value on stack"); - } - *s.sp = *(s.sp - 1); - ++s.sp; - break; + + case 9: // DUP + { + if (s.sp == s.stack + STACK_SIZE || + (s.fp != NULL && s.sp == f_locals(s.fp))) { + failure("can't DUP: no value on stack"); } + *s.sp = *(s.sp - 1); + ++s.sp; + break; + } case 10: // SWAP - { // guess - if (s.sp + 1 >= s.stack + STACK_SIZE || (s.fp != NULL && s.sp + 1 >= f_locals(s.fp))) { - failure("can't SWAP: < 2 values on stack"); - } - void* v = *s.sp; - push_extra_root(v); - *s.sp = *(s.sp + 1); - *(s.sp + 1) = v; - pop_extra_root(v); + { + if (s.sp + 1 >= s.stack + STACK_SIZE || + (s.fp != NULL && s.sp + 1 >= f_locals(s.fp))) { + failure("can't SWAP: < 2 values on stack"); } - break; + void *v = *s.sp; + push_extra_root(v); + *s.sp = *(s.sp + 1); + *(s.sp + 1) = v; + pop_extra_root(v); + } break; case 11: // ELEM - { - void* array = s_pop(&s); - aint index = s_pop_i(&s); - s_push(&s, Belem(array, index)); - } - break; - + { + void *array = s_pop(&s); + aint index = s_pop_i(&s); + s_push(&s, Belem(array, index)); + } break; + default: failure("invalid opcode %d-%d\n", h, l); } break; - + case 2: { // LD %d - int8_t category = ip_read_byte(&s.ip); - void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); + void **var_ptr = + var_by_category(&s, to_var_category(l), ip_read_int(&s.ip)); s_push(&s, *var_ptr); break; } + case 3: { // LDA %d - int8_t category = ip_read_byte(&s.ip); - void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); - // TODO + void **var_ptr = + var_by_category(&s, to_var_category(l), ip_read_int(&s.ip)); + s_push(&s, var_ptr); break; } case 4: { // ST %d - int8_t category = ip_read_byte(&s.ip); - void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); - *var_ptr = s_pop(&s); + void **var_ptr = + var_by_category(&s, to_var_category(l), ip_read_int(&s.ip)); + *var_ptr = *s_peek(&s); break; } + case 5: switch (l) { - case 0: { // CJMPz 0x%.8x - char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check - if (s_pop_i(&s) != UNBOX(0)) { - s.ip = new_ip; + case 0: { // CJMPz 0x%.8x + int jmp_p = ip_read_int(&s.ip); + + if (jmp_p < 0) { + failure("negative file offset jumps are not allowed"); + } + if (UNBOX(s_pop_i(&s)) == 0) { + s.ip = bf->code_ptr + jmp_p; } break; } + case 1: { // CJMPnz 0x%.8x - char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check - if (s_pop_i(&s) == UNBOX(0)) { - s.ip = new_ip; + int jmp_p = ip_read_int(&s.ip); + + if (jmp_p < 0) { + failure("negative file offset jumps are not allowed"); + } + if (UNBOX(s_pop_i(&s)) != 0) { + s.ip = bf->code_ptr + jmp_p; } break; } - case 2: // BEGIN %d %d // function begin - s_enter_f(&s, s.prev_ip/*ip from call*/, ip_read_int(&s.ip), ip_read_int(&s.ip)); + + case 2: { // BEGIN %d %d // function begin + int args_sz = ip_read_int(&s.ip); + int locals_sz = ip_read_int(&s.ip); + s_enter_f(&s, s.call_ip /*ip from call*/, args_sz, locals_sz); break; - - case 3: // CBEGIN %d %d // TODO: clojure begin ?? - s_enter_f(&s, s.prev_ip/*ip from call*/, ip_read_int(&s.ip), ip_read_int(&s.ip)); + } + + case 3: { // CBEGIN %d %d // TODO: clojure begin ?? + int args_sz = ip_read_int(&s.ip); + int locals_sz = ip_read_int(&s.ip); + s_enter_f(&s, s.call_ip /*ip from call*/, args_sz, locals_sz); break; - - case 4: // CLOSURE 0x%.8x + } + + case 4: // CLOSURE 0x%.8x // TODO { int n = ip_read_int(&s.ip); @@ -210,30 +250,39 @@ void run(bytefile *bf) { } }; break; - - case 5: // CALLC %d // call clojure + + case 5: // CALLC %d // call clojure // TODO FIXME: call clojure // s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check break; - - case 6: // CALL 0x%.8x %d // call function - // FIXME: second arg ?? - s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check + + case 6: { // CALL 0x%.8x %d // call function + int call_p = ip_read_int(&s.ip); // TODO: check + ip_read_int(&s.ip); + + s.call_ip = s.ip; + + if (call_p < 0) { + failure("negative file offset jumps are not allowed"); + } + s.ip = bf->code_ptr + call_p; break; - - case 7: // TAG %s + } + + case 7: // TAG %s s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf))); // TODO: check break; - - case 8: // ARRAY %d - Barray((aint*)s.sp, ip_read_int(&s.ip)); + + case 8: // ARRAY %d + Barray((aint *)s.sp, ip_read_int(&s.ip)); break; - - case 9: // FAIL %d %d // TODO + + case 9: // FAIL %d %d // TODO failure("[FAIL]: %d-%d\n", ip_read_int(&s.ip), ip_read_int(&s.ip)); break; - + case 10: // LINE %d + ip_read_int(&s.ip); // maybe some metainfo should be collected break; @@ -241,11 +290,11 @@ void run(bytefile *bf) { failure("invalid opcode %d-%d\n", h, l); } break; - - case 6: // PATT pats[l] + + case 6: // PATT pats[l] // TODO: check // {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"} switch (l) { - case 0: // =str + case 0: // =str s_push_i(&s, Bstring_patt(s_pop(&s), s_pop(&s))); // TODO: order break; case 1: // #string @@ -276,9 +325,9 @@ void run(bytefile *bf) { case 0: // CALL Lread s_push_i(&s, Lread()); break; - + case 1: // CALL Lwrite - Lwrite(s_pop_i(&s)); + Lwrite(*s_peek_i(&s)); break; case 2: // CALL Llength @@ -286,15 +335,16 @@ void run(bytefile *bf) { break; case 3: { // CALL Lstring - void* str = Lstring((aint*)s.sp); - s_pop(&s); + void *val = s_pop(&s); + void *str = + Lstring((aint *)&val); // FIXME: not working, GC extra root error s_push(&s, str); break; } case 4: { // CALL Barray %d size_t n = ip_read_int(&s.ip); - void* array = Barray((aint*)s.sp, n); // TODO: are elems added (?) + void *array = Barray((aint *)s.sp, n); // TODO: are elems added (?) s_popn(&s, n); s_push(&s, array); break; @@ -303,16 +353,20 @@ void run(bytefile *bf) { default: failure("invalid opcode %d-%d\n", h, l); } - } - break; - + } break; + default: failure("invalid opcode %d-%d\n", h, l); } - s.prev_ip = before_op_ip; - } - while (1); + // s.call_ip = before_op_ip; + + if (s.fp == NULL) { + break; + } + print_stack(&s); + } while (1); stop:; + printf("--- run end ---\n"); cleanup_state(&s); } diff --git a/byterun/src/parser.c b/byterun/src/parser.c index 2b8d66ffa..9c4f2d9ad 100644 --- a/byterun/src/parser.c +++ b/byterun/src/parser.c @@ -15,7 +15,6 @@ void *__stop_custom_data; /* Reads a binary bytecode file by name and unpacks it */ bytefile* read_file (char *fname) { FILE *f = fopen (fname, "rb"); - long size; bytefile *file; if (f == 0) { @@ -26,7 +25,8 @@ bytefile* read_file (char *fname) { failure ("%s\n", strerror (errno)); } - file = (bytefile*) malloc (sizeof(int)*4 + (size = ftell (f))); + long size = ftell (f); + file = (bytefile*) malloc (size + sizeof(void*) * 4); if (file == 0) { failure ("*** FAILURE: unable to allocate memory.\n"); @@ -43,7 +43,7 @@ bytefile* read_file (char *fname) { file->string_ptr = &file->buffer [file->public_symbols_number * 2 * sizeof(int)]; file->public_ptr = (int*) file->buffer; file->code_ptr = &file->string_ptr [file->stringtab_size]; - file->global_ptr = (int*) malloc (file->global_area_size * sizeof (int)); + file->global_ptr = (int*) calloc (file->global_area_size, sizeof (int)); return file; } @@ -256,7 +256,7 @@ void disassemble (FILE *f, bytefile *bf) { /* Dumps the contents of the file */ void dump_file (FILE *f, bytefile *bf) { - int i; + size_t i; fprintf (f, "String table size : %d\n", bf->stringtab_size); fprintf (f, "Global area size : %d\n", bf->global_area_size); diff --git a/byterun/src/stack.c b/byterun/src/stack.c index b910f8b69..90bf70b6c 100644 --- a/byterun/src/stack.c +++ b/byterun/src/stack.c @@ -2,28 +2,41 @@ #include "../../runtime/runtime.h" -extern size_t STACK_SIZE; - extern size_t __gc_stack_top, __gc_stack_bottom; -#define PRE_GC() \ - bool flag = false; \ - flag = __gc_stack_top == 0; \ - if (flag) { __gc_stack_top = (size_t)__builtin_frame_address(0); } \ - assert(__gc_stack_top != 0); \ - assert((__gc_stack_top & 0xF) == 0); \ - assert(__builtin_frame_address(0) <= (void *)__gc_stack_top); - -#define POST_GC() \ - assert(__builtin_frame_address(0) <= (void *)__gc_stack_top); \ - if (flag) { __gc_stack_top = 0; } - // ------ basic stack oprs ------ +void** s_top(struct State* s) { + return s->stack + STACK_SIZE - s->bf->global_area_size; +} + +bool s_is_empty(struct State* s) { + if (s->sp == s_top(s) || (s->fp != NULL && s->sp == f_locals(s->fp))) { + return true; + } + return false; +} + +void** s_peek(struct State* s) { + if (s->sp == s_top(s)) { + failure("empty stack"); + } + if (s->fp != NULL && s->sp == f_locals(s->fp)) { + failure("empty function stack"); + } + + return s->sp; +} + +aint* s_peek_i(struct State* s) { + return (aint*)s_peek(s); +} + void s_push(struct State *s, void *val) { if (s->sp == s->stack) { failure("stack overflow"); } + printf("--> push\n"); --s->sp; *s->sp = val; } @@ -43,9 +56,13 @@ void s_pushn_nil(struct State *s, size_t n) { } void* s_pop(struct State *s) { - if (s->sp == s->stack + STACK_SIZE || (s->fp != NULL && s->sp == f_locals(s->fp))) { - failure("take: no var"); + if (s->sp == s_top(s)) { + failure("empty stack"); } + if (s->fp != NULL && s->sp == f_locals(s->fp)) { + failure("empty function stack"); + } + printf("--> pop\n"); void* value = *s->sp; *s->sp = NULL; ++s->sp; @@ -65,33 +82,35 @@ void s_popn(struct State *s, size_t n) { // ------ functions ------ -void s_enter_f(struct State *s, char *func_ip, auint args_sz, - auint locals_sz) { +void s_enter_f(struct State *s, char *rp, auint args_sz, auint locals_sz) { + printf("-> %i args sz\n", args_sz); + printf("-> %i locals sz\n", locals_sz); + // check that params count is valid - if (s->sp + (aint)args_sz - 1 >= s->stack + STACK_SIZE || - (s->fp != NULL && args_sz > s->sp + STACK_SIZE - f_locals(s->fp))) { + if (s->sp + (aint)args_sz - 1 >= s_top(s)) { failure("not enough parameters in stack"); } + if (s->fp != NULL && s->sp + (aint)args_sz - 1 >= f_locals(s->fp)) { + failure("not enough parameters in function stack"); + } + + // s_push_nil(s); // sp contains value, frame starts with next value + s_pushn_nil(s, frame_sz()); // create frame struct Frame frame = { .ret = NULL, // field in frame itself - .rp = s->ip, - .to_prev_fp_box = BOX((void**)s->fp - s->sp), + .rp = rp, + .prev_fp = (void**)s->fp, .args_sz_box = BOX(args_sz), .locals_sz_box = BOX(locals_sz), }; // put frame on stack - s_push_nil(s); // sp contains value s->fp = (struct Frame *)s->sp; - s_pushn_nil(s, frame_sz() - 1); (*s->fp) = frame; s_pushn_nil(s, locals_sz); - - // go to function body - s->ip = func_ip; } void s_exit_f(struct State *s) { @@ -103,20 +122,33 @@ void s_exit_f(struct State *s) { push_extra_root((void **)&frame.ret); // drop stack entities, locals, frame - s_popn(s, (void**)s->fp - s->sp + 1); // TODO:check +1 + size_t to_pop = f_args(s->fp) - s->sp; + s->fp = (struct Frame*)f_prev_fp(&frame); + printf("-> %zu to pop\n", to_pop); + s_popn(s, to_pop); // drop args + printf("-> + %zu to pop\n", f_args_sz(&frame)); s_popn(s, f_args_sz(&frame)); - // save returned value - s_push(s, frame.ret); + // save returned value, not in main + if (frame.prev_fp != 0) { + s_push(s, frame.ret); + } s->ip = frame.rp; - s->fp = (struct Frame*)f_prev_fp(&frame); pop_extra_root((void **)&frame.ret); } +void print_stack(struct State* s) { + printf("stack (%i) is\n[", s->stack + STACK_SIZE - s->sp); + for (void** x = s->stack + STACK_SIZE - 1; x >= s->sp; --x) { + printf("%li ", (long)UNBOX(*x)); + } + printf("]\n"); +} + void **var_by_category(struct State *s, enum VarCategory category, int id) { if (id < 0) { @@ -125,34 +157,35 @@ void **var_by_category(struct State *s, enum VarCategory category, void **var = NULL; switch (category) { case VAR_GLOBAL: - // TODO: FIXME + if (s->bf->global_area_size <= id) { + failure("can't read global: too big id, %i >= %ul", id, s->bf->global_area_size); + } + var = s->stack + STACK_SIZE - 1 - id; break; case VAR_LOCAL: if (s->fp == NULL) { failure("can't read local outside of function"); } - if (f_args_sz(s->fp) <= id) { - failure("can't read local: too big id, %i >= %ul", f_locals_sz(s->fp), - id); + if (f_locals_sz(s->fp) <= id) { + failure("can't read local: too big id, %i >= %ul", id, f_locals_sz(s->fp)); } - var = &f_locals(s->fp)[id]; + printf("id is %i, local is %i, %i\n", id, UNBOX((auint)*((void**)f_locals(s->fp) + id)), f_locals(s->fp) - s->sp); + var = f_locals(s->fp) + (f_locals_sz(s->fp) - id - 1); break; case VAR_ARGUMENT: if (s->fp == NULL) { failure("can't read argument outside of function"); } if (f_args_sz(s->fp) <= id) { - failure("can't read arguments: too big id, %i >= %ul", f_args_sz(s->fp), - id); + failure("can't read arguments: too big id, %i >= %ul", id, f_args_sz(s->fp)); } - var = &f_args(s->fp)[id]; // TODO: check if not reversed order + printf("id is %i, arg is %i, %i\n", id, UNBOX((auint)*((void**)f_args(s->fp) + id)), f_args(s->fp) - s->sp); + var = f_args(s->fp) + (f_args_sz(s->fp) - id - 1); // TODO: check if not reversed order break; - case VAR_C: + case VAR_C: // clojure ?? // TODO: ?? break; } - // TODO: push extra root ?? - return var; } diff --git a/byterun/src/types.c b/byterun/src/types.c index 944576478..06054ee8f 100644 --- a/byterun/src/types.c +++ b/byterun/src/types.c @@ -1,13 +1,12 @@ #include "types.h" +#include "stack.h" #include "../../runtime/gc.h" #include extern size_t __gc_stack_top, __gc_stack_bottom; -const size_t STACK_SIZE = 100000; - // --- Frame --- // NOTE: stack is [top -> bottom] @@ -15,12 +14,12 @@ size_t frame_sz() { return sizeof(struct Frame) / sizeof(void *); } void **f_prev_fp(struct Frame *fp) { - return (void **)fp + UNBOX(fp->to_prev_fp_box); + return fp->prev_fp; } auint f_locals_sz(struct Frame *fp) { return UNBOX(fp->locals_sz_box); } auint 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 + 1; } +void **f_locals(struct Frame *fp) { return (void **)fp - f_locals_sz(fp); } +void **f_args(struct Frame *fp) { return (void **)fp + frame_sz(); } // --- State --- @@ -29,10 +28,16 @@ static struct State alloc_state(bytefile *bf) { struct State state = { .stack = calloc(STACK_SIZE + 1, sizeof(void*)), .ip = bf->code_ptr, - .prev_ip = NULL, + .call_ip = NULL, + .bf = bf, }; - state.sp = *state.stack + STACK_SIZE; // [top -> bottom] stack + for (size_t i = 0; i < STACK_SIZE; ++i) { + state.stack[i] = NULL; + } + + state.sp = state.stack + STACK_SIZE; // [top -> bottom] stack + print_stack(&state); state.fp = NULL; return state; } @@ -41,6 +46,12 @@ struct State init_state(bytefile *bf) { __init(); struct State state = alloc_state(bf); __gc_stack_bottom = (size_t)state.sp; + // print_stack(&state); + + s_pushn_nil(&state, bf->global_area_size); + + // print_stack(&state); + printf("- state init done\n"); return state; } @@ -50,7 +61,7 @@ static void destruct_state(struct State* state) { state->sp = NULL; state->fp = NULL; state->ip = NULL; - state->prev_ip = NULL; + state->call_ip = NULL; } void cleanup_state(struct State* state) { diff --git a/byterun/src/utils.c b/byterun/src/utils.c index 2f915b1a1..66d528a17 100644 --- a/byterun/src/utils.c +++ b/byterun/src/utils.c @@ -5,17 +5,17 @@ #include /* Gets a string from a string table by an index */ -extern char* get_string(bytefile *f, int pos) { +extern char* get_string(bytefile *f, size_t pos) { return &f->string_ptr[pos]; } /* Gets a name for a public symbol */ -extern char* get_public_name (bytefile *f, int i) { +extern char* get_public_name (bytefile *f, size_t i) { return get_string(f, f->public_ptr[i*2]); } /* Gets an offset for a publie symbol */ -extern int get_public_offset (bytefile *f, int i) { +extern size_t get_public_offset (bytefile *f, size_t i) { return f->public_ptr[i*2+1]; }