part of migration to gc

This commit is contained in:
ProgramSnail 2024-10-20 16:42:57 +03:00
parent fb1ec1c7ae
commit d782934f0c
5 changed files with 457 additions and 337 deletions

35
byterun/include/builtin.h Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#include <stdio.h>
#include "operations.h"
inline void f_read(struct State *s) {
int x = 0;
printf("> "); // TODO: ??
scanf("%i", &x);
s_put_i(s, x);
}
inline void f_write(struct State *s) {
int x = s_take_i(s);
printf("%i", x);
// put 0 ??
}
inline void f_length(struct State *s) {
// TODO
}
inline void f_string(struct State *s) {
// TODO
}
inline void f_array(struct State *s, int sz) {
// TODO
}
inline void f_cons(struct State *s) {
// TODO
}

View file

@ -0,0 +1,255 @@
#pragma once
#include "../../runtime/runtime.h"
#include "types.h"
#include <cstdlib>
// TODO: use gc
// ------ general ------
// TODO: use gc
inline void free_var_ptr(union VarT *var);
inline void free_var(union VarT var) {
switch (dh_type(var.nil.data_header)) {
case NIL_T:
break;
case INT_T:
break;
case CONST_STR_T:
break;
case STR_T:
free(var.str.value);
break;
case LIST_T:
if (var.list.value != NULL) {
free_var_ptr(to_var(var.list.value));
}
if (var.list.next != NULL) {
free_var_ptr(to_var(var.list.next));
}
break;
case ARRAY_T:
// dh param is size
for (size_t i = 0; i < dh_param(var.array.data_header); ++i) {
free_var_ptr(to_var(var.array.values[i]));
}
free(var.array.values);
break;
case SEXP_T:
// tag is const string, no need to free
if (var.sexp.next != NULL) {
free(var.sexp.next);
}
break;
case FUN_T:
break;
}
}
// TODO: use gc
inline void free_var_ptr(union VarT *var) {
free_var(*var);
free((void *)var);
}
//
inline NilT clear_var() { return NilT{.data_header = NIL_T}; }
// usually not required, because frame is located on shared stack
inline struct Frame clear_frame() {
struct Frame frame = {
.ret_ip = NULL,
.rp = NULL,
.ret = NULL,
.params = NULL,
.locals = NULL,
.end = NULL,
};
return frame;
}
// TODO: not required ??
// inline struct Var deep_copy_var(struct Var var) {
// switch (var.type) {
// case INT_T:
// break;
// case CONST_STR_T:
// break;
// case STR_T: {
// char *old_str = var.value.str_v;
// var.value.str_v = calloc(var.size + 1, sizeof(char));
// strcpy(var.value.str_v, old_str);
// break;
// }
// case LIST_T:
// if (var.value.list_v.elem != NULL) {
// struct Var *old_elem = var.value.list_v.elem;
// var.value.list_v.elem = calloc(1, sizeof(struct Var));
// *var.value.list_v.elem = deep_copy_var(*old_elem);
// }
// if (var.value.list_v.next != NULL) {
// struct Var *old_next = var.value.list_v.next;
// var.value.list_v.next = calloc(1, sizeof(struct Var));
// *var.value.list_v.next = deep_copy_var(*old_next);
// }
// break;
// case ARRAY_T: {
// struct Var *old_array = var.value.array_v;
// var.value.array_v = calloc(var.size, sizeof(char));
// for (size_t i = 0; i < var.size; ++i) {
// var.value.array_v[i] = deep_copy_var(*(old_array + i));
// }
// break;
// }
// case FUN_T:
// break;
// case NIL_T:
// break;
// }
// return var;
// }
// ------ put on stack ---
inline void s_put_var(struct State *s, struct NilT *val) { // any var
*s->vp = val;
++s->vp;
}
inline void s_put_nil(struct State *s) {
struct NilT *var = alloc();
var->data_header = NIL_T; // no param
s_put_var(s, var);
}
inline void s_putn_nil(struct State *s, size_t n) {
for (size_t i = 0; i < n; ++i) {
s_put_nil(s);
}
}
inline void s_put_i(struct State *s, int val) {
struct IntT *var = alloc();
var->data_header = INT_T; // no param
var->value = val;
s_put_var(s, (NilT *)var);
}
inline void s_put_const_str(struct State *s,
const char *val) { // memory controlled externally
struct ConstStrT *var = alloc();
var->data_header = CONST_STR_T; // no param
var->value = val;
s_put_var(s, (NilT *)var);
}
inline void s_put_str(struct State *s, char *val) { // memory controlled by var
struct StrT *var = alloc();
var->data_header = STR_T; // no param
var->value = val;
s_put_var(s, (NilT *)var);
}
// TODO
inline void s_put_array(struct State *s, int sz) { // memory controlled by var
struct Var var = {
.type = ARRAY_T,
.value.array_v = calloc(sz, sizeof(struct Var)),
.size = sz,
};
s_put_var(s, var);
// fill array with nils ?
}
inline void s_put_list(struct State *s,
struct NilT *first_elem) { // memory controlled by var
struct ListT *var;
var->data_header = LIST_T; // no param
var->value = first_elem;
var->next = NULL;
s_put_var(s, (NilT *)var);
*first_elem = clear_var();
}
// ------ take from stack ------
inline union VarT *s_take_var(struct State *s) {
if (s->vp == s->fp->end) {
failure("take: no var");
}
--s->vp;
union VarT *ret = *s->vp;
*s->vp = NULL; // clear top var
return ret;
}
inline int s_take_i(struct State *s) {
union VarT *v = s_take_var(s);
if (dh_type(v->nil.data_header) != INT_T) {
failure("take int: not int");
}
return v->int_t.value;
}
inline void s_drop_var(struct State *s) {
if (s->vp == s->fp->end) {
failure("drop: no var");
}
--s->vp;
free_var_ptr(*s->vp);
*s->vp = NULL;
}
inline void s_dropn_var(struct State *s, size_t n) {
for (size_t i = 0; i < n; ++i) {
s_drop_var(s);
}
}
// ------ functions ------
// TODO
inline void s_exit_f(struct State *s) {
if (s->fp == (void *)s->stack) {
failure("exit: no func");
}
--s->fp;
s_dropn_var(s, s->vp - s->fp->locals);
// drop local var stack and locals // TODO: check +-1
union VarT *ret = *s->vp;
--s->vp;
s_dropn_var(s, s->vp - s->fp->params);
// drop params // TODO: check +-1
s_put_var(s, ret);
s->ip = s->fp->rp;
// *s->fp = clear_frame(); // clear top frame
}
// TODO
inline void s_enter_f(struct State *s, char *func_ip, size_t params_sz,
size_t locals_sz) {
struct Frame frame = {
.rp = s->ip, // ??
.ret = s->vp,
.params = s->vp - params_sz, // TODO: check +-1
.locals = s->vp + 1,
.end = s->vp + locals_sz + 1, // ??
};
// TODO:
s_put_nil(s); // ret
s_putn_nil(s, locals_sz); // locals
s->ip = func_ip;
(*s->fp) = frame;
++s->fp;
}

120
byterun/include/types.h Normal file
View file

@ -0,0 +1,120 @@
#pragma once
#include "parser.h"
#include <stdint.h>
// ------ Var ------
// TODO: clojures
enum Type {
NIL_T = 0x00000000,
INT_T = 0x00000001,
CONST_STR_T = 0x00000002,
STR_T = 0x00000003,
LIST_T = 0x00000004,
ARRAY_T = 0x00000005,
SEXP_T = 0x00000006,
FUN_T = 0x00000007
};
struct NilT { // AnyVarT too
int32_t data_header;
};
struct IntT {
int32_t data_header;
int32_t value; // int value => size = 1;
};
struct ConstStrT {
int32_t data_header;
const char *value;
};
struct StrT {
int32_t data_header;
char *value;
};
struct ListT {
int32_t data_header;
struct NilT *value;
struct NilT *next;
};
struct ArrayT {
int32_t data_header;
struct NilT **values;
};
struct SExpT {
int32_t data_header;
const char *tag;
struct NilT *next;
};
struct FunT {
int32_t data_header;
char *fun_ip;
};
union VarT {
struct NilT nil;
struct IntT int_t;
struct ConstStrT const_str;
struct StrT str;
struct ListT list;
struct ArrayT array;
struct SExpT sexp;
struct FunT fun;
};
// same to TAG in runtime
inline enum Type dh_type(int data_header) {
return (Type)(data_header & 0x00000007);
}
// same to LEN in runtime
inline int dh_param(int data_header) { return (data_header & 0xFFFFFFF8) >> 3; }
inline union VarT *to_var(struct NilT *var) { return (union VarT *)var; }
// ------ Frame ------
struct Frame {
char *rp; // ret instruction pointer
struct NilT **ret; // store returned value
struct NilT **params; // store arguments
struct NilT **locals; // store locals
struct NilT **end; // store locals
};
inline uint64_t frame_locals_sz(struct Frame *frame) {
return frame->locals - frame->params;
}
inline uint64_t frame_params_sz(struct Frame *frame) {
return frame->end - frame->locals;
}
// ------ State ------
union StackValue {
union VarT *var;
union VarT **var_ptr;
// struct Frame frame; // TODO
char *addr;
};
// inline StackValue *to_sv(void *var) { return (StackValue *)var; }
struct State {
union StackValue *stack; // vaid**
struct NilT **vp; // var pointer
struct Frame *fp; // function frame pointer
char *ip; // instruction pointer
char *prev_ip; // prev instruction pointer
};
struct State init_state(bytefile *bf);
void destruct_state(struct State *state);