fixes, some checks, made working on part of simple tests (functions, arrays, operations, read, write, loops)

This commit is contained in:
ProgramSnail 2024-11-04 01:43:43 +03:00
parent da050c082c
commit 1e38ffaefb
11 changed files with 333 additions and 220 deletions

2
byterun/.gitignore vendored
View file

@ -5,6 +5,8 @@ build/
.xmake/ .xmake/
.cache/ .cache/
tst/
compile_commands.json compile_commands.json
.cache/ .cache/
*.a *.a

View file

@ -99,9 +99,9 @@ void *Belem(void *p, aint i);
void *LmakeArray(aint length); void *LmakeArray(aint length);
void *LmakeString(aint length); void *LmakeString(aint length);
void *Bstring(aint *args /*void *p*/); void *Bstring(aint *p);
void *Lstringcat(aint *args /* void* p */); void *Lstringcat(aint *p);
void *Lstring(aint *args /* void *p */); void *Lstring(aint *p);
void *Bclosure(aint *args, aint bn); void *Bclosure(aint *args, aint bn);
void *Barray(aint *args, aint bn); void *Barray(aint *args, aint bn);

View file

@ -7,6 +7,11 @@
#include "stdlib.h" #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(struct State *s, void *val);
void s_push_i(struct State *s, aint val); void s_push_i(struct State *s, aint val);
void s_push_nil(struct State *s); 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 // where |> defines corresponding frame pointer, | is stack pointer
// location before / after new frame added // location before / after new frame added
void s_enter_f(struct State *s, char *func_ip, auint params_sz, void s_enter_f(struct State *s, char *rp, auint args_sz, auint locals_sz);
auint locals_sz);
void s_exit_f(struct State *s); void s_exit_f(struct State *s);

View file

@ -7,24 +7,26 @@
// ------ General ------ // ------ General ------
enum Type { // enum Type {
STR_T = STRING_TAG, // STR_T = STRING_TAG,
ARRAY_T = ARRAY_TAG, // ARRAY_T = ARRAY_TAG,
SEXP_T = SEXP_TAG, // SEXP_T = SEXP_TAG,
CLOJURE_T = CLOSURE_TAG, // CLOJURE_T = CLOSURE_TAG,
}; // };
#define STACK_SIZE 100000
static const size_t MAX_ARRAY_SIZE = 0x11111110; static const size_t MAX_ARRAY_SIZE = 0x11111110;
// ------ Frame ------ // ------ Frame ------
struct Frame { struct Frame {
void *ret; // store returned value [gc pointer] void *ret; // store returned value [gc pointer]
char *rp; // ret instruction pointer [not gc pointer] char *rp; // ret instruction pointer [not gc pointer]
aint to_prev_fp_box; // ret function frame pointer [boxed value, not gc void **prev_fp; // ret function frame pointer [boxed value, not gc
// pointer] // pointer]
aint args_sz_box; // store arguments [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] aint locals_sz_box; // store locals [boxed value, not gc pointer]
}; };
auint frame_sz(); auint frame_sz();
@ -37,12 +39,13 @@ void **f_args(struct Frame *fp);
// ------ State ------ // ------ State ------
struct State { struct State {
void **stack; // vaid** void **stack;
void **sp; // stack pointer void **sp; // stack pointer
struct Frame *fp; // function frame pointer struct Frame *fp; // function frame pointer
bytefile *bf;
char *ip; // instruction pointer 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); struct State init_state(bytefile *bf);
@ -58,3 +61,5 @@ enum VarCategory {
}; };
enum VarCategory to_var_category(uint8_t category); enum VarCategory to_var_category(uint8_t category);
void print_stack(struct State *s);

View file

@ -1,6 +1,10 @@
#pragma once #pragma once
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include "../../runtime/runtime_common.h"
/* The unpacked representation of bytecode file */ /* The unpacked representation of bytecode file */
typedef struct { typedef struct {
@ -15,12 +19,12 @@ typedef struct {
} bytefile; } bytefile;
/* Gets a string from a string table by an index */ /* 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 */ /* 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 */ /* 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);
// --- // ---

View file

@ -13,8 +13,8 @@ int main(int argc, char** argv) {
bytefile *f = read_file(argv[1]); bytefile *f = read_file(argv[1]);
dump_file (stdout, f);
run(f); run(f);
// dump_file (stdout, f);
free(f); free(f);

View file

@ -1,25 +1,21 @@
#include "interpreter.h" #include "interpreter.h"
#include "../../runtime/runtime.h"
#include "../../runtime/gc.h" #include "../../runtime/gc.h"
#include "../../runtime/runtime.h"
#include "utils.h"
#include "types.h"
#include "stack.h"
#include "runtime_externs.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); *ip += sizeof(int);
return *(int*)((*ip) - sizeof(int)); return *(int *)((*ip) - sizeof(int));
} }
char ip_read_byte(char** ip) { char ip_read_byte(char **ip) { return *(*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)); return get_string(bf, ip_read_int(ip));
} }
@ -27,35 +23,46 @@ char* ip_read_string(char** ip, bytefile* bf) {
void run(bytefile *bf) { void run(bytefile *bf) {
struct State s = init_state(bf); struct State s = init_state(bf);
print_stack(&s);
printf("--- interpreter run ---\n");
const size_t OPS_SIZE = 13; const size_t OPS_SIZE = 13;
const char *ops [] = {"+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"}; const char *ops[] = {
aint(*ops_func[])(void*, void*) = { "+", "-", "*", "/", "%", "<", "<=", ">", ">=", "==", "!=", "&&", "!!"};
&Ls__Infix_43, // + aint (*ops_func[])(void *, void *) = {
&Ls__Infix_45, // - &Ls__Infix_43, // +
&Ls__Infix_42, // * &Ls__Infix_45, // -
&Ls__Infix_47, // / &Ls__Infix_42, // *
&Ls__Infix_37, // % &Ls__Infix_47, // /
&Ls__Infix_60, // < &Ls__Infix_37, // %
&Ls__Infix_6061, // <= &Ls__Infix_60, // <
&Ls__Infix_62, // > &Ls__Infix_6061, // <=
&Ls__Infix_6261, // >= &Ls__Infix_62, // >
&Ls__Infix_6161, // == &Ls__Infix_6261, // >=
&Ls__Infix_3361, // != &Ls__Infix_6161, // ==
&Ls__Infix_3838, // && &Ls__Infix_3361, // !=
&Ls__Infix_3333, // !! &Ls__Infix_3838, // &&
&Ls__Infix_3333, // !!
}; };
const size_t PATS_SIZE = 7; const size_t PATS_SIZE = 7;
const char *pats[] = {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"}; const char *pats[] = {"=str", "#string", "#array", "#sexp",
"#ref", "#val", "#fun"};
// 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 { do {
char* before_op_ip = s.ip; // save to set s.prev_ip // char *before_op_ip = s.ip; // save to set s.prev_ip
char x = ip_read_byte(&s.ip), char x = ip_read_byte(&s.ip), h = (x & 0xF0) >> 4, l = x & 0x0F;
h = (x & 0xF0) >> 4,
l = x & 0x0F;
// fprintf (f, "0x%.8x:\t", ip-bf->code_ptr-1); printf("0x%.8x\n", s.ip - bf->code_ptr - 1);
switch (h) { switch (h) {
case 15: case 15:
@ -69,83 +76,98 @@ void run(bytefile *bf) {
if (l < 1) { if (l < 1) {
failure("BINOP: l < 1"); failure("BINOP: l < 1");
} }
void* left = s_pop(&s); void *left = s_pop(&s);
void* right = s_pop(&s); void *right = s_pop(&s);
s_push(&s, (void*)ops_func[l-1](left, right)); s_push(&s, (void *)ops_func[l - 1](right, left));
break; break;
case 1: case 1:
switch (l) { switch (l) {
case 0: // CONST %d case 0: // CONST %d
s_push_i(&s, BOX(ip_read_int(&s.ip))); s_push_i(&s, BOX(ip_read_int(&s.ip)));
break; break;
case 1: { // STRING %s case 1: { // STRING %s
void* str = ip_read_string(&s.ip, bf); void *str = ip_read_string(&s.ip, bf);
s_push(&s, Bstring((aint*)&str)); s_push(&s, Bstring((aint *)&str));
break; 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 // params read from stack
s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf))); 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; break;
case 3: // STI - write by ref (?) case 3: // STI - write by ref (?)
// TODO // TODO
break; break;
case 4: // STA - write to array elem case 4: // STA - write to array elem
// Bsta // TODO // Bsta // TODO
break; break;
case 5: // JMP 0x%.8x case 5: { // JMP 0x%.8x
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check 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
if (!s_is_empty(&s) && s.fp->prev_fp != 0) {
s.fp->ret = *s_peek(&s);
s_pop(&s);
}
s_exit_f(&s);
break; break;
case 6: // END case 7: // RET
s_exit_f(&s); // TODO: always ??, check that it is enough if (!s_is_empty(&s) && s.fp->prev_fp != 0) {
s.fp->ret = *s_peek(&s);
s_pop(&s);
}
s_exit_f(&s);
break; break;
case 7: // RET case 8: // DROP
// TODO
break;
case 8: // DROP
s_pop(&s); s_pop(&s);
break; break;
case 9: // DUP case 9: // DUP
{ {
if (s.sp == s.stack + STACK_SIZE || (s.fp != NULL && s.sp == f_locals(s.fp))) { if (s.sp == s.stack + STACK_SIZE ||
failure("can't DUP: no value on stack"); (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;
} }
*s.sp = *(s.sp - 1);
++s.sp;
break;
}
case 10: // SWAP case 10: // SWAP
{ // guess {
if (s.sp + 1 >= s.stack + STACK_SIZE || (s.fp != NULL && s.sp + 1 >= f_locals(s.fp))) { if (s.sp + 1 >= s.stack + STACK_SIZE ||
failure("can't SWAP: < 2 values on stack"); (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);
} }
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 case 11: // ELEM
{ {
void* array = s_pop(&s); void *array = s_pop(&s);
aint index = s_pop_i(&s); aint index = s_pop_i(&s);
s_push(&s, Belem(array, index)); s_push(&s, Belem(array, index));
} } break;
break;
default: default:
failure("invalid opcode %d-%d\n", h, l); failure("invalid opcode %d-%d\n", h, l);
@ -153,48 +175,66 @@ void run(bytefile *bf) {
break; break;
case 2: { // LD %d case 2: { // LD %d
int8_t category = ip_read_byte(&s.ip); void **var_ptr =
void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); var_by_category(&s, to_var_category(l), ip_read_int(&s.ip));
s_push(&s, *var_ptr); s_push(&s, *var_ptr);
break; break;
} }
case 3: { // LDA %d case 3: { // LDA %d
int8_t category = ip_read_byte(&s.ip); void **var_ptr =
void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); var_by_category(&s, to_var_category(l), ip_read_int(&s.ip));
// TODO s_push(&s, var_ptr);
break; break;
} }
case 4: { // ST %d case 4: { // ST %d
int8_t category = ip_read_byte(&s.ip); void **var_ptr =
void** var_ptr = var_by_category(&s, to_var_category(category), ip_read_int(&s.ip)); var_by_category(&s, to_var_category(l), ip_read_int(&s.ip));
*var_ptr = s_pop(&s); *var_ptr = *s_peek(&s);
break; break;
} }
case 5: case 5:
switch (l) { switch (l) {
case 0: { // CJMPz 0x%.8x case 0: { // CJMPz 0x%.8x
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check int jmp_p = ip_read_int(&s.ip);
if (s_pop_i(&s) != UNBOX(0)) {
s.ip = new_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; break;
} }
case 1: { // CJMPnz 0x%.8x case 1: { // CJMPnz 0x%.8x
char* new_ip = (char*)(long)ip_read_int(&s.ip); // TODO: check int jmp_p = ip_read_int(&s.ip);
if (s_pop_i(&s) == UNBOX(0)) {
s.ip = new_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; 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));
break;
case 3: // CBEGIN %d %d // TODO: clojure begin ?? 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)); 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; break;
}
case 4: // CLOSURE 0x%.8x 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
// TODO // TODO
{ {
int n = ip_read_int(&s.ip); int n = ip_read_int(&s.ip);
@ -211,29 +251,38 @@ void run(bytefile *bf) {
}; };
break; break;
case 5: // CALLC %d // call clojure case 5: // CALLC %d // call clojure
// TODO FIXME: call clojure // TODO FIXME: call clojure
// s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check // s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check
break; break;
case 6: // CALL 0x%.8x %d // call function case 6: { // CALL 0x%.8x %d // call function
// FIXME: second arg ?? int call_p = ip_read_int(&s.ip); // TODO: check
s.ip = (char*)(long)ip_read_int(&s.ip); // TODO: check ip_read_int(&s.ip);
break;
case 7: // TAG %s 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
s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf))); // TODO: check s_push_i(&s, LtagHash(ip_read_string(&s.ip, bf))); // TODO: check
break; break;
case 8: // ARRAY %d case 8: // ARRAY %d
Barray((aint*)s.sp, ip_read_int(&s.ip)); Barray((aint *)s.sp, ip_read_int(&s.ip));
break; 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)); failure("[FAIL]: %d-%d\n", ip_read_int(&s.ip), ip_read_int(&s.ip));
break; break;
case 10: // LINE %d case 10: // LINE %d
ip_read_int(&s.ip);
// maybe some metainfo should be collected // maybe some metainfo should be collected
break; break;
@ -242,10 +291,10 @@ void run(bytefile *bf) {
} }
break; break;
case 6: // PATT pats[l] case 6: // PATT pats[l] // TODO: check
// {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"} // {"=str", "#string", "#array", "#sexp", "#ref", "#val", "#fun"}
switch (l) { switch (l) {
case 0: // =str case 0: // =str
s_push_i(&s, Bstring_patt(s_pop(&s), s_pop(&s))); // TODO: order s_push_i(&s, Bstring_patt(s_pop(&s), s_pop(&s))); // TODO: order
break; break;
case 1: // #string case 1: // #string
@ -278,7 +327,7 @@ void run(bytefile *bf) {
break; break;
case 1: // CALL Lwrite case 1: // CALL Lwrite
Lwrite(s_pop_i(&s)); Lwrite(*s_peek_i(&s));
break; break;
case 2: // CALL Llength case 2: // CALL Llength
@ -286,15 +335,16 @@ void run(bytefile *bf) {
break; break;
case 3: { // CALL Lstring case 3: { // CALL Lstring
void* str = Lstring((aint*)s.sp); void *val = s_pop(&s);
s_pop(&s); void *str =
Lstring((aint *)&val); // FIXME: not working, GC extra root error
s_push(&s, str); s_push(&s, str);
break; break;
} }
case 4: { // CALL Barray %d case 4: { // CALL Barray %d
size_t n = ip_read_int(&s.ip); 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_popn(&s, n);
s_push(&s, array); s_push(&s, array);
break; break;
@ -303,16 +353,20 @@ void run(bytefile *bf) {
default: default:
failure("invalid opcode %d-%d\n", h, l); failure("invalid opcode %d-%d\n", h, l);
} }
} } break;
break;
default: default:
failure("invalid opcode %d-%d\n", h, l); failure("invalid opcode %d-%d\n", h, l);
} }
s.prev_ip = before_op_ip; // s.call_ip = before_op_ip;
}
while (1); if (s.fp == NULL) {
break;
}
print_stack(&s);
} while (1);
stop:; stop:;
printf("--- run end ---\n");
cleanup_state(&s); cleanup_state(&s);
} }

View file

@ -15,7 +15,6 @@ void *__stop_custom_data;
/* Reads a binary bytecode file by name and unpacks it */ /* Reads a binary bytecode file by name and unpacks it */
bytefile* read_file (char *fname) { bytefile* read_file (char *fname) {
FILE *f = fopen (fname, "rb"); FILE *f = fopen (fname, "rb");
long size;
bytefile *file; bytefile *file;
if (f == 0) { if (f == 0) {
@ -26,7 +25,8 @@ bytefile* read_file (char *fname) {
failure ("%s\n", strerror (errno)); 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) { if (file == 0) {
failure ("*** FAILURE: unable to allocate memory.\n"); 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->string_ptr = &file->buffer [file->public_symbols_number * 2 * sizeof(int)];
file->public_ptr = (int*) file->buffer; file->public_ptr = (int*) file->buffer;
file->code_ptr = &file->string_ptr [file->stringtab_size]; 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; return file;
} }
@ -256,7 +256,7 @@ void disassemble (FILE *f, bytefile *bf) {
/* Dumps the contents of the file */ /* Dumps the contents of the file */
void dump_file (FILE *f, bytefile *bf) { void dump_file (FILE *f, bytefile *bf) {
int i; size_t i;
fprintf (f, "String table size : %d\n", bf->stringtab_size); fprintf (f, "String table size : %d\n", bf->stringtab_size);
fprintf (f, "Global area size : %d\n", bf->global_area_size); fprintf (f, "Global area size : %d\n", bf->global_area_size);

View file

@ -2,28 +2,41 @@
#include "../../runtime/runtime.h" #include "../../runtime/runtime.h"
extern size_t STACK_SIZE;
extern size_t __gc_stack_top, __gc_stack_bottom; 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 ------ // ------ 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) { void s_push(struct State *s, void *val) {
if (s->sp == s->stack) { if (s->sp == s->stack) {
failure("stack overflow"); failure("stack overflow");
} }
printf("--> push\n");
--s->sp; --s->sp;
*s->sp = val; *s->sp = val;
} }
@ -43,9 +56,13 @@ void s_pushn_nil(struct State *s, size_t n) {
} }
void* s_pop(struct State *s) { void* s_pop(struct State *s) {
if (s->sp == s->stack + STACK_SIZE || (s->fp != NULL && s->sp == f_locals(s->fp))) { if (s->sp == s_top(s)) {
failure("take: no var"); failure("empty stack");
} }
if (s->fp != NULL && s->sp == f_locals(s->fp)) {
failure("empty function stack");
}
printf("--> pop\n");
void* value = *s->sp; void* value = *s->sp;
*s->sp = NULL; *s->sp = NULL;
++s->sp; ++s->sp;
@ -65,33 +82,35 @@ void s_popn(struct State *s, size_t n) {
// ------ functions ------ // ------ functions ------
void s_enter_f(struct State *s, char *func_ip, auint args_sz, void s_enter_f(struct State *s, char *rp, auint args_sz, auint locals_sz) {
auint locals_sz) { printf("-> %i args sz\n", args_sz);
printf("-> %i locals sz\n", locals_sz);
// check that params count is valid // check that params count is valid
if (s->sp + (aint)args_sz - 1 >= s->stack + STACK_SIZE || if (s->sp + (aint)args_sz - 1 >= s_top(s)) {
(s->fp != NULL && args_sz > s->sp + STACK_SIZE - f_locals(s->fp))) {
failure("not enough parameters in stack"); 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 // create frame
struct Frame frame = { struct Frame frame = {
.ret = NULL, // field in frame itself .ret = NULL, // field in frame itself
.rp = s->ip, .rp = rp,
.to_prev_fp_box = BOX((void**)s->fp - s->sp), .prev_fp = (void**)s->fp,
.args_sz_box = BOX(args_sz), .args_sz_box = BOX(args_sz),
.locals_sz_box = BOX(locals_sz), .locals_sz_box = BOX(locals_sz),
}; };
// put frame on stack // put frame on stack
s_push_nil(s); // sp contains value
s->fp = (struct Frame *)s->sp; s->fp = (struct Frame *)s->sp;
s_pushn_nil(s, frame_sz() - 1);
(*s->fp) = frame; (*s->fp) = frame;
s_pushn_nil(s, locals_sz); s_pushn_nil(s, locals_sz);
// go to function body
s->ip = func_ip;
} }
void s_exit_f(struct State *s) { void s_exit_f(struct State *s) {
@ -103,20 +122,33 @@ void s_exit_f(struct State *s) {
push_extra_root((void **)&frame.ret); push_extra_root((void **)&frame.ret);
// drop stack entities, locals, frame // 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 // drop args
printf("-> + %zu to pop\n", f_args_sz(&frame));
s_popn(s, f_args_sz(&frame)); s_popn(s, f_args_sz(&frame));
// save returned value // save returned value, not in main
s_push(s, frame.ret); if (frame.prev_fp != 0) {
s_push(s, frame.ret);
}
s->ip = frame.rp; s->ip = frame.rp;
s->fp = (struct Frame*)f_prev_fp(&frame);
pop_extra_root((void **)&frame.ret); 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, void **var_by_category(struct State *s, enum VarCategory category,
int id) { int id) {
if (id < 0) { if (id < 0) {
@ -125,34 +157,35 @@ void **var_by_category(struct State *s, enum VarCategory category,
void **var = NULL; void **var = NULL;
switch (category) { switch (category) {
case VAR_GLOBAL: 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; break;
case VAR_LOCAL: case VAR_LOCAL:
if (s->fp == NULL) { if (s->fp == NULL) {
failure("can't read local outside of function"); failure("can't read local outside of function");
} }
if (f_args_sz(s->fp) <= id) { if (f_locals_sz(s->fp) <= id) {
failure("can't read local: too big id, %i >= %ul", f_locals_sz(s->fp), failure("can't read local: too big id, %i >= %ul", id, f_locals_sz(s->fp));
id);
} }
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; break;
case VAR_ARGUMENT: case VAR_ARGUMENT:
if (s->fp == NULL) { if (s->fp == NULL) {
failure("can't read argument outside of function"); failure("can't read argument outside of function");
} }
if (f_args_sz(s->fp) <= id) { if (f_args_sz(s->fp) <= id) {
failure("can't read arguments: too big id, %i >= %ul", f_args_sz(s->fp), failure("can't read arguments: too big id, %i >= %ul", id, f_args_sz(s->fp));
id);
} }
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; break;
case VAR_C: case VAR_C: // clojure ??
// TODO: ?? // TODO: ??
break; break;
} }
// TODO: push extra root ??
return var; return var;
} }

View file

@ -1,13 +1,12 @@
#include "types.h" #include "types.h"
#include "stack.h"
#include "../../runtime/gc.h" #include "../../runtime/gc.h"
#include <stdlib.h> #include <stdlib.h>
extern size_t __gc_stack_top, __gc_stack_bottom; extern size_t __gc_stack_top, __gc_stack_bottom;
const size_t STACK_SIZE = 100000;
// --- Frame --- // --- Frame ---
// NOTE: stack is [top -> bottom] // NOTE: stack is [top -> bottom]
@ -15,12 +14,12 @@ size_t frame_sz() {
return sizeof(struct Frame) / sizeof(void *); return sizeof(struct Frame) / sizeof(void *);
} }
void **f_prev_fp(struct Frame *fp) { 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_locals_sz(struct Frame *fp) { return UNBOX(fp->locals_sz_box); }
auint f_args_sz(struct Frame *fp) { return UNBOX(fp->args_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_locals(struct Frame *fp) { return (void **)fp - f_locals_sz(fp); }
void **f_args(struct Frame *fp) { return (void **)fp + 1; } void **f_args(struct Frame *fp) { return (void **)fp + frame_sz(); }
// --- State --- // --- State ---
@ -29,10 +28,16 @@ static struct State alloc_state(bytefile *bf) {
struct State state = { struct State state = {
.stack = calloc(STACK_SIZE + 1, sizeof(void*)), .stack = calloc(STACK_SIZE + 1, sizeof(void*)),
.ip = bf->code_ptr, .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; state.fp = NULL;
return state; return state;
} }
@ -41,6 +46,12 @@ struct State init_state(bytefile *bf) {
__init(); __init();
struct State state = alloc_state(bf); struct State state = alloc_state(bf);
__gc_stack_bottom = (size_t)state.sp; __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; return state;
} }
@ -50,7 +61,7 @@ static void destruct_state(struct State* state) {
state->sp = NULL; state->sp = NULL;
state->fp = NULL; state->fp = NULL;
state->ip = NULL; state->ip = NULL;
state->prev_ip = NULL; state->call_ip = NULL;
} }
void cleanup_state(struct State* state) { void cleanup_state(struct State* state) {

View file

@ -5,17 +5,17 @@
#include <stdlib.h> #include <stdlib.h>
/* Gets a string from a string table by an index */ /* 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]; return &f->string_ptr[pos];
} }
/* Gets a name for a public symbol */ /* 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]); return get_string(f, f->public_ptr[i*2]);
} }
/* Gets an offset for a publie symbol */ /* 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]; return f->public_ptr[i*2+1];
} }