2024-10-31 21:08:48 +03:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include "../../runtime/gc.h"
|
2025-01-08 23:52:39 +03:00
|
|
|
#include "module_manager.h"
|
2024-10-31 21:08:48 +03:00
|
|
|
#include "runtime_externs.h"
|
|
|
|
|
#include "types.h"
|
|
|
|
|
#include "utils.h"
|
|
|
|
|
|
|
|
|
|
#include "stdlib.h"
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
extern struct State s;
|
|
|
|
|
|
2024-11-12 02:12:28 +03:00
|
|
|
extern size_t __gc_stack_top, __gc_stack_bottom;
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void **s_top() {
|
2024-11-14 00:50:43 +03:00
|
|
|
return (void **)__gc_stack_bottom - s.bf->global_area_size;
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-04 01:43:43 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline bool s_is_empty() {
|
2024-11-14 00:50:43 +03:00
|
|
|
if ((void **)__gc_stack_top == s_top() ||
|
|
|
|
|
(s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp))) {
|
2024-11-12 01:56:09 +03:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-10-31 21:08:48 +03:00
|
|
|
|
2024-11-14 02:10:24 +03:00
|
|
|
static inline void **s_nth(size_t n) {
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 00:50:43 +03:00
|
|
|
if ((void **)__gc_stack_top + n >= s_top()) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "not enough elements in stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-14 00:50:43 +03:00
|
|
|
if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "not enough elements in function stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-14 00:50:43 +03:00
|
|
|
return (void **)__gc_stack_top + n;
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void **s_peek() {
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 00:50:43 +03:00
|
|
|
if ((void **)__gc_stack_top == s_top()) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "empty stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-14 00:50:43 +03:00
|
|
|
if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "empty function stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-14 00:50:43 +03:00
|
|
|
return (void **)__gc_stack_top;
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline aint *s_peek_i() { return (aint *)s_peek(); }
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void s_push(void *val) {
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 00:50:43 +03:00
|
|
|
if ((void **)__gc_stack_top == s.stack) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "stack overflow");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
#ifdef DEBUG_VERSION
|
|
|
|
|
printf("--> push\n");
|
|
|
|
|
#endif
|
2024-11-14 00:50:43 +03:00
|
|
|
__gc_stack_top -= sizeof(void *);
|
|
|
|
|
*(void **)__gc_stack_top = val;
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void s_push_i(aint val) { s_push((void *)val); }
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void s_push_nil() { s_push(NULL); }
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void s_pushn_nil(size_t n) {
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 00:59:36 +03:00
|
|
|
if ((void **)__gc_stack_top + (aint)n - 1 <= s.stack) {
|
|
|
|
|
s_failure(&s, "stack overflow");
|
|
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
for (size_t i = 0; i < n; ++i) {
|
2024-11-14 00:59:36 +03:00
|
|
|
__gc_stack_top -= sizeof(void *);
|
|
|
|
|
*(void **)__gc_stack_top = NULL;
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void *s_pop() {
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 00:50:43 +03:00
|
|
|
if ((void **)__gc_stack_top == s_top()) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "empty stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-14 00:50:43 +03:00
|
|
|
if (s.fp != NULL && (void **)__gc_stack_top == f_locals(s.fp)) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "empty function stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
#ifdef DEBUG_VERSION
|
|
|
|
|
printf("--> pop\n");
|
|
|
|
|
#endif
|
2024-11-14 00:50:43 +03:00
|
|
|
void *value = *(void **)__gc_stack_top;
|
|
|
|
|
__gc_stack_top += sizeof(void *);
|
2024-11-12 01:56:09 +03:00
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline aint s_pop_i() { return (aint)s_pop(); }
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void s_popn(size_t n) {
|
2024-11-14 00:59:36 +03:00
|
|
|
if ((void **)__gc_stack_top + (aint)n - 1 >= s_top()) {
|
|
|
|
|
s_failure(&s, "empty stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-14 00:59:36 +03:00
|
|
|
__gc_stack_top += n * sizeof(void *);
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-10-31 21:08:48 +03:00
|
|
|
|
2024-11-14 02:10:24 +03:00
|
|
|
// ------ complex operations ------
|
|
|
|
|
|
|
|
|
|
// for some reason does not work in sexp constructor, probably connected with gc
|
|
|
|
|
// behaviour
|
|
|
|
|
static inline void s_put_nth(size_t n, void *val) {
|
|
|
|
|
s_push_nil();
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 02:10:24 +03:00
|
|
|
if ((void **)__gc_stack_top + n >= s_top()) {
|
|
|
|
|
s_failure(&s, "not enough elements in stack");
|
|
|
|
|
}
|
|
|
|
|
if (s.fp != NULL && (void **)__gc_stack_top + n >= f_locals(s.fp)) {
|
|
|
|
|
s_failure(&s, "not enough elements in function stack");
|
|
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-14 02:10:24 +03:00
|
|
|
|
|
|
|
|
for (size_t i = 0; i < n; ++i) {
|
|
|
|
|
((void **)__gc_stack_top)[i] = ((void **)__gc_stack_top)[i + 1];
|
|
|
|
|
}
|
|
|
|
|
((void **)__gc_stack_top)[n] = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void s_rotate_n(size_t n) {
|
|
|
|
|
s_push_nil();
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-14 02:10:24 +03:00
|
|
|
if ((void **)__gc_stack_top + (aint)n - 1 >= s_top()) {
|
|
|
|
|
s_failure(&s, "not enough elements in stack");
|
|
|
|
|
}
|
|
|
|
|
if (s.fp != NULL && (void **)__gc_stack_top + (aint)n - 1 >= f_locals(s.fp)) {
|
|
|
|
|
s_failure(&s, "not enough elements in function stack");
|
|
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-14 02:10:24 +03:00
|
|
|
|
|
|
|
|
void *buf = NULL;
|
|
|
|
|
for (size_t i = 0; 2 * i < n; ++i) {
|
|
|
|
|
buf = ((void **)__gc_stack_top)[n - i];
|
|
|
|
|
((void **)__gc_stack_top)[n - i] = ((void **)__gc_stack_top)[i];
|
|
|
|
|
((void **)__gc_stack_top)[i] = buf;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-31 21:08:48 +03:00
|
|
|
// ------ functions ------
|
|
|
|
|
|
2025-01-08 23:52:39 +03:00
|
|
|
// |> param_0 ... param_n | frame[ ret rp prev_fp ... ¶ms &locals &end
|
2024-10-31 21:08:48 +03:00
|
|
|
// ]
|
|
|
|
|
// |> local_0 ... local_m |> | ...
|
|
|
|
|
//
|
|
|
|
|
// where |> defines corresponding frame pointer, | is stack pointer
|
|
|
|
|
// location before / after new frame added
|
2025-01-08 23:52:39 +03:00
|
|
|
static inline void s_enter_f(char *rp, aint ret_module_id, bool is_closure_call,
|
|
|
|
|
auint args_sz, auint locals_sz) {
|
2024-11-12 01:56:09 +03:00
|
|
|
#ifdef DEBUG_VERSION
|
|
|
|
|
printf("-> %i args sz\n", args_sz);
|
|
|
|
|
printf("-> %i locals sz\n", locals_sz);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// check that params count is valid
|
2024-11-14 00:50:43 +03:00
|
|
|
if ((void **)__gc_stack_top + (aint)args_sz - (is_closure_call ? 0 : 1) >=
|
|
|
|
|
s_top()) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "not enough parameters in stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.fp != NULL &&
|
2024-11-14 00:50:43 +03:00
|
|
|
(void **)__gc_stack_top + (aint)args_sz - (is_closure_call ? 0 : 1) >=
|
|
|
|
|
f_locals(s.fp)) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s, "not enough parameters in function stack");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2024-12-17 04:15:25 +03:00
|
|
|
void *closure = is_closure_call ? *s_nth(args_sz) : NULL;
|
|
|
|
|
// printf("is_closure_call: %i, closure: %li\n", is_closure_call,
|
|
|
|
|
// (aint)closure);
|
2024-11-12 01:56:09 +03:00
|
|
|
|
|
|
|
|
// s_push_nil(s); // sp contains value, frame starts with next value
|
2024-11-12 02:38:26 +03:00
|
|
|
s_pushn_nil(frame_sz());
|
2024-11-12 01:56:09 +03:00
|
|
|
|
|
|
|
|
// create frame
|
|
|
|
|
struct Frame frame = {
|
|
|
|
|
.closure = closure,
|
|
|
|
|
.ret = NULL, // field in frame itself
|
|
|
|
|
.rp = rp,
|
2024-11-12 02:38:26 +03:00
|
|
|
.prev_fp = (void **)s.fp,
|
2025-01-08 23:52:39 +03:00
|
|
|
.ret_module_box = BOX(ret_module_id),
|
2024-11-12 01:56:09 +03:00
|
|
|
.args_sz_box = BOX(args_sz),
|
|
|
|
|
.locals_sz_box = BOX(locals_sz),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// put frame on stack
|
2024-11-14 00:50:43 +03:00
|
|
|
s.fp = (struct Frame *)__gc_stack_top;
|
2024-11-12 02:38:26 +03:00
|
|
|
(*s.fp) = frame;
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
s_pushn_nil(locals_sz);
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
static inline void s_exit_f() {
|
2024-12-15 16:19:54 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.fp == NULL) {
|
|
|
|
|
s_failure(&s, "exit: no func");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 16:19:54 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
struct Frame frame = *s.fp;
|
2024-11-12 01:56:09 +03:00
|
|
|
|
|
|
|
|
// drop stack entities, locals, frame
|
2024-11-14 00:50:43 +03:00
|
|
|
size_t to_pop = f_args(s.fp) - (void **)__gc_stack_top;
|
2024-11-12 02:38:26 +03:00
|
|
|
s.fp = (struct Frame *)f_prev_fp(&frame);
|
2024-11-12 01:56:09 +03:00
|
|
|
#ifdef DEBUG_VERSION
|
|
|
|
|
printf("-> %zu to pop\n", to_pop);
|
|
|
|
|
#endif
|
2024-11-12 02:38:26 +03:00
|
|
|
s_popn(to_pop);
|
2024-11-12 01:56:09 +03:00
|
|
|
|
|
|
|
|
// drop args
|
|
|
|
|
#ifdef DEBUG_VERSION
|
|
|
|
|
printf("-> + %zu to pop\n", f_args_sz(&frame));
|
|
|
|
|
#endif
|
2024-11-12 02:38:26 +03:00
|
|
|
s_popn(f_args_sz(&frame));
|
2024-11-12 01:56:09 +03:00
|
|
|
|
|
|
|
|
// save returned value, not in main
|
|
|
|
|
if (frame.prev_fp != 0) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_push(frame.ret);
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2024-11-12 02:38:26 +03:00
|
|
|
s.ip = frame.rp;
|
2025-01-08 23:52:39 +03:00
|
|
|
|
|
|
|
|
s.current_module_id = UNBOX(frame.ret_module_box);
|
|
|
|
|
s.bf = mod_get(s.current_module_id);
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
|
|
|
|
|
2025-01-11 23:51:50 +03:00
|
|
|
static inline void print_stack(struct State *state) {
|
|
|
|
|
printf("stack (%li) is\n[",
|
|
|
|
|
state->stack + STACK_SIZE - (void **)__gc_stack_top);
|
|
|
|
|
for (void **x = state->stack + STACK_SIZE - 1; x >= (void **)__gc_stack_top;
|
|
|
|
|
--x) {
|
2024-11-12 01:56:09 +03:00
|
|
|
printf("%li ", (long)UNBOX(*x));
|
|
|
|
|
}
|
|
|
|
|
printf("]\n");
|
|
|
|
|
}
|
2024-10-31 21:08:48 +03:00
|
|
|
|
2024-11-12 01:56:09 +03:00
|
|
|
// --- category ---
|
2024-10-31 21:08:48 +03:00
|
|
|
|
2024-11-14 02:10:24 +03:00
|
|
|
static inline void **var_by_category(enum VarCategory category, size_t id) {
|
2024-11-12 01:56:09 +03:00
|
|
|
void **var = NULL;
|
|
|
|
|
switch (category) {
|
|
|
|
|
case VAR_GLOBAL:
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.bf->global_area_size <= id) {
|
|
|
|
|
s_failure(&s,
|
2024-11-12 01:56:09 +03:00
|
|
|
"can't read global: too big id"); //, %i >= %ul", id,
|
2024-11-12 02:38:26 +03:00
|
|
|
// s.bf->global_area_size);
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 02:38:26 +03:00
|
|
|
var = s.stack + STACK_SIZE - 1 - id;
|
2024-11-12 01:56:09 +03:00
|
|
|
break;
|
|
|
|
|
case VAR_LOCAL:
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.fp == NULL) {
|
|
|
|
|
s_failure(&s, "can't read local outside of function");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-12 02:38:26 +03:00
|
|
|
if (f_locals_sz(s.fp) <= id) {
|
|
|
|
|
s_failure(&s, "can't read local: too big id"); //, %i >= %ul", id,
|
|
|
|
|
// f_locals_sz(s.fp));
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 01:56:09 +03:00
|
|
|
// printf("id is %i, local is %i, %i\n", id,
|
2024-11-14 00:50:43 +03:00
|
|
|
// UNBOX((auint)*((void**)f_locals(s.fp) + id)), f_locals(s.fp) - (void
|
|
|
|
|
// **)__gc_stack_top);
|
2024-11-12 02:38:26 +03:00
|
|
|
var = f_locals(s.fp) + (f_locals_sz(s.fp) - id - 1);
|
2024-11-12 01:56:09 +03:00
|
|
|
break;
|
|
|
|
|
case VAR_ARGUMENT:
|
2024-12-15 03:33:46 +03:00
|
|
|
#ifndef WITH_CHECK
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.fp == NULL) {
|
|
|
|
|
s_failure(&s, "can't read argument outside of function");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-12 02:38:26 +03:00
|
|
|
if (f_args_sz(s.fp) <= id) {
|
|
|
|
|
s_failure(&s, "can't read arguments: too big id"); //, %i >= %ul", id,
|
|
|
|
|
// f_args_sz(s.fp));
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 03:33:46 +03:00
|
|
|
#endif
|
2024-11-12 02:38:26 +03:00
|
|
|
var = f_args(s.fp) + (f_args_sz(s.fp) - id - 1);
|
2024-11-12 01:56:09 +03:00
|
|
|
break;
|
2024-12-15 16:19:54 +03:00
|
|
|
case VAR_CLOSURE:
|
|
|
|
|
#ifndef WITH_CHECK
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.fp == NULL) {
|
|
|
|
|
s_failure(&s, "can't read closure parameter outside of function");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-12 02:38:26 +03:00
|
|
|
if (s.fp->closure == NULL) {
|
|
|
|
|
s_failure(&s, "can't read closure parameter not in closure");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-12-15 16:19:54 +03:00
|
|
|
#endif
|
2024-11-12 02:38:26 +03:00
|
|
|
if (UNBOXED(s.fp->closure)) {
|
|
|
|
|
s_failure(&s, "not boxed value expected in closure index");
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-12 02:38:26 +03:00
|
|
|
data *d = TO_DATA(s.fp->closure);
|
2024-12-17 04:15:25 +03:00
|
|
|
int count = get_len(d) - 1;
|
2024-11-12 01:56:09 +03:00
|
|
|
#ifdef DEBUG_VERSION
|
|
|
|
|
printf("id is %i, count is %i\n", id, count);
|
|
|
|
|
#endif
|
2024-12-17 04:15:25 +03:00
|
|
|
if ((int64_t)id >= count) {
|
2024-11-12 02:38:26 +03:00
|
|
|
s_failure(&s,
|
2024-11-12 01:56:09 +03:00
|
|
|
"can't read arguments: too big id"); //, %i >= %ul", id, count);
|
|
|
|
|
}
|
2024-12-17 04:15:25 +03:00
|
|
|
return ((void **)d->contents) + count - id; // order is not important
|
2024-11-12 01:56:09 +03:00
|
|
|
}
|
2024-11-06 02:28:46 +03:00
|
|
|
|
2024-11-12 01:56:09 +03:00
|
|
|
return var;
|
|
|
|
|
}
|