global vars implementation, todo gc problems

This commit is contained in:
ProgramSnail 2025-05-11 11:02:07 +03:00
parent 474b0a8ed2
commit aff30ad7c1
12 changed files with 76 additions and 52 deletions

View file

@ -105,9 +105,7 @@ 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);
void *Barray_rev(aint *args, aint bn);
void *Bsexp(aint *args, aint bn); void *Bsexp(aint *args, aint bn);
void *Bsexp_rev(aint *args, aint bn);
aint Btag(void *d, aint t, aint n); aint Btag(void *d, aint t, aint n);
aint get_tag(data *d); aint get_tag(data *d);

View file

@ -1,2 +1,3 @@
I,Std; I,Std;
V,x;
F,f; F,f;

View file

@ -1 +1,3 @@
public x = 1;
public fun f(a, b) { a + b } public fun f(a, b) { a + b }

View file

@ -1,3 +1,4 @@
I,Std; I,Std;
V,x;
F,f; F,f;
F,g; F,g;

View file

View file

@ -0,0 +1,3 @@
import Dep;
f(x, 1)

View file

@ -397,7 +397,6 @@ void run_main(Bytefile* bf, int argc, char **argv) {
} }
#endif #endif
s_rotate_n(args_count); s_rotate_n(args_count);
// NOTE: call_offset < 0 => deal with closure of builtin function
s_push_i(BOX(call_offset)); s_push_i(BOX(call_offset));
void *closure = Bclosure((aint *)__gc_stack_top, BOX(args_count)); void *closure = Bclosure((aint *)__gc_stack_top, BOX(args_count));
@ -472,12 +471,10 @@ void run_main(Bytefile* bf, int argc, char **argv) {
call_builtin(builtin_id, args_count); call_builtin(builtin_id, args_count);
if (s.is_closure_call) { if (s.is_closure_call) {
// NOTE: all functions have returned value, some values undefined // NOTE: all functions have returned value, some values undefined
// if (is_builtin_with_ret(builtin_id)) { s_swap_tops();
s_swap_tops();
// }
s_pop(); s_pop();
} }
s.ip = s.call_ip; // TODO: check s.ip = s.call_ip;
break; break;
} }
default: default:

View file

@ -1,3 +1,4 @@
#include <cstring>
#include <iostream> #include <iostream>
extern "C" { extern "C" {
#include "interpreter.h" #include "interpreter.h"
@ -16,6 +17,9 @@ extern "C" {
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
static const constexpr char *GLOBAL_VAR_TAG = "global_";
static const size_t GLOBAL_VAR_TAG_LEN = std::strlen(GLOBAL_VAR_TAG);
template <size_t N, bool return_value, typename... Args> template <size_t N, bool return_value, typename... Args>
requires(N == 0) requires(N == 0)
void call_func(void (*f)(), size_t n, Args... args) { void call_func(void (*f)(), size_t n, Args... args) {
@ -35,7 +39,6 @@ template <size_t N, bool return_value, typename... Args>
void call_func(void (*f)(), size_t n, Args... args) { void call_func(void (*f)(), size_t n, Args... args) {
void *arg = s_pop(); void *arg = s_pop();
call_func<N - 1, return_value, Args..., void *>(f, n, arg, args...); call_func<N - 1, return_value, Args..., void *>(f, n, arg, args...);
// TODO: check that arg is added on the right position
} }
template <size_t N, bool return_value, bool do_check = true> template <size_t N, bool return_value, bool do_check = true>
@ -96,10 +99,10 @@ void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
size_t args_count = ip_read_int_unsafe(&read_ip); size_t args_count = ip_read_int_unsafe(&read_ip);
for (size_t i = 0; i < args_count; ++i) { for (size_t i = 0; i < args_count; ++i) {
uint8_t arg_type = ip_read_byte_unsafe(&read_ip); uint8_t arg_type = ip_read_byte_unsafe(&read_ip);
aint value = ip_read_int_unsafe(&read_ip); aint id = ip_read_int_unsafe(&read_ip);
if (to_var_category(arg_type) == VAR_GLOBAL) { if (to_var_category(arg_type) == VAR_GLOBAL) {
write_ip = read_ip; write_ip = read_ip;
ip_write_int_unsafe(write_ip, value + offsets.globals); ip_write_int_unsafe(write_ip, id + offsets.globals);
} }
} }
break; break;
@ -109,12 +112,7 @@ void rewrite_code_with_offsets(Bytefile *bytefile, const Offsets &offsets) {
case Cmd::ST: case Cmd::ST:
if (to_var_category(l) == VAR_GLOBAL) { if (to_var_category(l) == VAR_GLOBAL) {
aint id = ip_read_int_unsafe(&read_ip); aint id = ip_read_int_unsafe(&read_ip);
if (id > 0) { // NOTE: do not rewrite sysargs usages ip_write_int_unsafe(write_ip, id + offsets.globals);
ip_write_int_unsafe(
write_ip,
id - 1 + offsets.globals); // rewrite with exclusion of local
// module sysargs reference
}
} }
break; break;
default: default:
@ -227,25 +225,26 @@ void subst_in_code(Bytefile *bytefile,
*(uint32_t *)(bytefile->code_ptr + offset + sizeof(uint32_t)); *(uint32_t *)(bytefile->code_ptr + offset + sizeof(uint32_t));
*val_ptr = builtins.at({.id = builtin_id, .args_count = args_count}); *val_ptr = builtins.at({.id = builtin_id, .args_count = args_count});
continue; } else {
} // NOTE: works with globals too
const auto it = publics.find(name);
if (it == publics.end()) {
failure("public name for substitution is not found: <%s>\n", name);
}
const auto it = publics.find(name); *(uint32_t *)(bytefile->code_ptr + offset) = it->second;
if (it == publics.end()) {
failure("public name for substitution is not found: <%s>\n", name);
} }
*(uint32_t *)(bytefile->code_ptr + offset) = it->second;
// TODO: check: +4 to match ?
} }
} }
Offsets calc_merge_sizes(const std::vector<Bytefile *> &bytefiles) { Offsets calc_merge_sizes(const std::vector<Bytefile *> &bytefiles) {
Offsets sizes{.strings = 0, .globals = 0, .code = 0, .publics_num = 0}; Offsets sizes{.strings = 0,
.globals = 1, // NOTE: V,sysargs from, Std
.code = 0,
.publics_num = 0};
for (size_t i = 0; i < bytefiles.size(); ++i) { for (size_t i = 0; i < bytefiles.size(); ++i) {
sizes.strings += bytefiles[i]->stringtab_size; sizes.strings += bytefiles[i]->stringtab_size;
sizes.globals += bytefiles[i]->global_area_size - sizes.globals += bytefiles[i]->global_area_size;
1; // NOTE: exclude default variable sysargs
sizes.code += bytefiles[i]->code_size; sizes.code += bytefiles[i]->code_size;
// sizes.publics_num += bytefiles[i]->public_symbols_number; // sizes.publics_num += bytefiles[i]->public_symbols_number;
} }
@ -261,6 +260,13 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
Offsets sizes = calc_merge_sizes(bytefiles); Offsets sizes = calc_merge_sizes(bytefiles);
size_t public_symbols_size = calc_publics_size(sizes.publics_num); size_t public_symbols_size = calc_publics_size(sizes.publics_num);
#ifdef DEBUG_VERSION
std::cout << "- inputs:\n";
for (const auto &bf : bytefiles) {
print_file(*bf, std::cout);
}
#endif
// find all builtin variations ad extract them // find all builtin variations ad extract them
BuiltinSubstMap builtins_map; BuiltinSubstMap builtins_map;
{ {
@ -274,9 +280,6 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
gen_builtins(sizes.code, builtins_map); gen_builtins(sizes.code, builtins_map);
sizes.code += builtins_code_size; sizes.code += builtins_code_size;
// V,sysparams fro, Std
++sizes.globals;
Bytefile *result = Bytefile *result =
(Bytefile *)malloc(sizeof(Bytefile) + sizes.strings + sizes.code + (Bytefile *)malloc(sizeof(Bytefile) + sizes.strings + sizes.code +
public_symbols_size); // globals are on the stack public_symbols_size); // globals are on the stack
@ -285,8 +288,13 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
// TODO: add publics + updat name offsets too ?()) // TODO: add publics + updat name offsets too ?())
std::unordered_map<std::string, size_t> publics; std::unordered_map<std::string, size_t> publics;
std::vector<size_t> main_offsets; std::vector<size_t> main_offsets;
// NOTE: V,sysargs from, Std
publics.insert({"global_sysargs", 0});
{ {
size_t code_offset = 0; size_t code_offset = 0;
size_t globals_offset = 1; // NOTE: V,sysargs from, Std
for (size_t i = 0; i < bytefiles.size(); ++i) { for (size_t i = 0; i < bytefiles.size(); ++i) {
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("bytefile <%zu>\n", i); printf("bytefile <%zu>\n", i);
@ -297,11 +305,16 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
printf("symbol <%zu>:<%zu>\n", i, j); printf("symbol <%zu>:<%zu>\n", i, j);
#endif #endif
const char *name = get_public_name_unsafe(bytefiles[i], j); const char *name = get_public_name_unsafe(bytefiles[i], j);
size_t offset = get_public_offset_unsafe(bytefiles[i], j) + code_offset;
size_t offset =
get_public_offset_unsafe(bytefiles[i], j) +
(std::memcmp(name, GLOBAL_VAR_TAG, GLOBAL_VAR_TAG_LEN) == 0
? globals_offset // NOTE: is global id
: code_offset); // NOTE: is function offset in code
#ifdef DEBUG_VERSION #ifdef DEBUG_VERSION
printf("symbol %s : %zu (code offset %zu)\n", name, offset, printf("symbol %s : %zu (code offset %zu, globals offset %zu)\n", name,
code_offset); offset, code_offset, globals_offset);
#endif #endif
if (strcmp(name, "main") == 0) { if (strcmp(name, "main") == 0) {
main_offsets.push_back(offset); main_offsets.push_back(offset);
@ -310,6 +323,7 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
} }
} }
code_offset += bytefiles[i]->code_size; code_offset += bytefiles[i]->code_size;
globals_offset += bytefiles[i]->global_area_size;
} }
} }
@ -332,9 +346,9 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
// update & merge code segments // update & merge code segments
Offsets offsets{.strings = 0, Offsets offsets{.strings = 0,
.globals = 1, .globals = 1, // NOTE: V,sysargs from, Std
.code = 0, .code = 0,
.publics_num = 0}; // NOTE: one global: sysargs .publics_num = 0};
// REMOVE printf("merge bytefiles\n"); // REMOVE printf("merge bytefiles\n");
for (size_t i = 0; i < bytefiles.size(); ++i) { for (size_t i = 0; i < bytefiles.size(); ++i) {
// REMOVE printf("rewrite offsets %zu\n", i); // REMOVE printf("rewrite offsets %zu\n", i);
@ -358,8 +372,7 @@ MergeResult merge_files(std::vector<Bytefile *> &&bytefiles) {
// update offsets // update offsets
offsets.strings += bytefiles[i]->stringtab_size; offsets.strings += bytefiles[i]->stringtab_size;
offsets.globals += offsets.globals += bytefiles[i]->global_area_size;
bytefiles[i]->global_area_size - 1; // NOTE: exclude sysargs
offsets.code += bytefiles[i]->code_size; offsets.code += bytefiles[i]->code_size;
// offsets.publics_num += bytefiles[i]->public_symbols_number; // offsets.publics_num += bytefiles[i]->public_symbols_number;
@ -584,10 +597,10 @@ BUILTIN id_by_builtin(const char *name) {
// } // }
/* NOTE: from src/X86_64.ml: */ /* NOTE: from src/X86_64.ml: */
/* For vararg functions where we pass them in the stdlib function using va_list, /* For vararg functions where we pass them in the stdlib function using
we have to unbox values to print them correctly. va_list, we have to unbox values to print them correctly. For this we have
For this we have special assemply functions in `printf.S`. special assemply functions in `printf.S`. We additionally pass them amount
We additionally pass them amount of arguments to unbox using register r11. */ of arguments to unbox using register r11. */
void run_stdlib_func(BUILTIN id, size_t args_count) { void run_stdlib_func(BUILTIN id, size_t args_count) {
// std::cout << "RUN BUILTIN: " << id << '\n'; // TODO: TMP // std::cout << "RUN BUILTIN: " << id << '\n'; // TODO: TMP
void *ret = NULL; void *ret = NULL;

View file

@ -9,7 +9,7 @@ endif
DISABLE_WARNINGS=-Wno-shift-negative-value DISABLE_WARNINGS=-Wno-shift-negative-value
COMMON_FLAGS=$(DISABLE_WARNINGS) -g -fstack-protector-all $(ARCH) --std=c11 COMMON_FLAGS=$(DISABLE_WARNINGS) -g -fstack-protector-all $(ARCH) --std=c11
PROD_FLAGS=$(COMMON_FLAGS) -DLAMA_ENV PROD_FLAGS=$(COMMON_FLAGS)
TEST_FLAGS=$(COMMON_FLAGS) -DDEBUG_VERSION TEST_FLAGS=$(COMMON_FLAGS) -DDEBUG_VERSION
UNIT_TESTS_FLAGS=$(TEST_FLAGS) UNIT_TESTS_FLAGS=$(TEST_FLAGS)
INVARIANTS_CHECK_FLAGS=$(TEST_FLAGS) -DFULL_INVARIANT_CHECKS INVARIANTS_CHECK_FLAGS=$(TEST_FLAGS) -DFULL_INVARIANT_CHECKS

View file

@ -37,7 +37,7 @@
#define SET_FORWARD_ADDRESS(x, addr) (x = ((x & 3) | ((ptrt)(addr)))) #define SET_FORWARD_ADDRESS(x, addr) (x = ((x & 3) | ((ptrt)(addr))))
// if heap is full after gc shows in how many times it has to be extended // if heap is full after gc shows in how many times it has to be extended
#define EXTRA_ROOM_HEAP_COEFFICIENT 2 #define EXTRA_ROOM_HEAP_COEFFICIENT 2
#define MINIMUM_HEAP_CAPACITY (64) #define MINIMUM_HEAP_CAPACITY (640000)
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>

View file

@ -176,16 +176,21 @@ module ByteCode = struct
let externs = Stdlib.ref S.empty in let externs = Stdlib.ref S.empty in
let pubs = Stdlib.ref S.empty in let pubs = Stdlib.ref S.empty in
let imports = Stdlib.ref S.empty in let imports = Stdlib.ref S.empty in
let globals = Stdlib.ref @@ M.add "sysargs" 0 @@ M.empty in (* sysargs is a vaiable from Std *) let globals = Stdlib.ref @@ M.empty in
let glob_count = Stdlib.ref 1 in (* sysargs *) let glob_count = Stdlib.ref 1 in (* 0 is the placeholder for globals externs *)
let fixups = Stdlib.ref [] in let fixups = Stdlib.ref [] in
let func_fixups = Stdlib.ref [] in let func_fixups = Stdlib.ref [] in
let vars_substs = Stdlib.ref [] in
let add_lab l = lmap := M.add l (Buffer.length code) !lmap in let add_lab l = lmap := M.add l (Buffer.length code) !lmap in
let add_extern l = externs := S.add l !externs in let add_extern l =
if String.starts_with ~prefix:"global_" l
then globals := M.add l 0 !globals (* 0 is the placeholder for globals externs *)
else externs := S.add l !externs in
let add_public l = pubs := S.add l !pubs in let add_public l = pubs := S.add l !pubs in
let add_import l = imports := S.add l !imports in let add_import l = imports := S.add l !imports in
let add_fixup l = fixups := (Buffer.length code, l) :: !fixups in let add_fixup l = fixups := (Buffer.length code, l) :: !fixups in
let add_func_fixup l = func_fixups := (Buffer.length code, l) :: !func_fixups in let add_func_fixup l = func_fixups := (Buffer.length code, l) :: !func_fixups in
let add_var_subst l = vars_substs := (Buffer.length code, l) :: !vars_substs in
let add_bytes = List.iter (fun x -> Buffer.add_char code @@ Char.chr x) in let add_bytes = List.iter (fun x -> Buffer.add_char code @@ Char.chr x) in
let add_ints = let add_ints =
List.iter (fun x -> Buffer.add_int32_ne code @@ Int32.of_int x) List.iter (fun x -> Buffer.add_int32_ne code @@ Int32.of_int x)
@ -198,16 +203,17 @@ module ByteCode = struct
let b x = match n with None -> x | Some b -> (b * 16) + x in let b x = match n with None -> x | Some b -> (b * 16) + x in
List.iter (function List.iter (function
| Value.Global s -> | Value.Global s ->
let s' = "global_" ^ s in
let i = let i =
try M.find s !globals try M.find s' !globals
with Not_found -> with Not_found ->
let i = !glob_count in let i = !glob_count in
incr glob_count; incr glob_count;
globals := M.add s i !globals; globals := M.add s' i !globals;
i i
in in
add_bytes [ b 0 ]; add_bytes [ b 0 ];
add_ints [ i ] if i == 0 then (add_var_subst s'; add_ints [ 0 ]) else add_ints [ i - 1 ]
| Value.Local n -> | Value.Local n ->
add_bytes [ b 1 ]; add_bytes [ b 1 ];
add_ints [ n ] add_ints [ n ]
@ -341,6 +347,7 @@ module ByteCode = struct
let substs = Stdlib.ref [] in let substs = Stdlib.ref [] in
let add_subst c l = substs := (c, l) :: !substs in let add_subst c l = substs := (c, l) :: !substs in
List.iter insn_code insns; List.iter insn_code insns;
substs := !vars_substs;
add_bytes [ 255 ]; add_bytes [ 255 ];
let code = Buffer.to_bytes code in let code = Buffer.to_bytes code in
List.iter List.iter
@ -371,7 +378,9 @@ module ByteCode = struct
( Int32.of_int @@ StringTab.add st l, ( Int32.of_int @@ StringTab.add st l,
Int32.of_int Int32.of_int
@@ @@
try M.find l !lmap let is_global = String.starts_with ~prefix:"global_" l in
(* 0 was reserved for extern globals *)
try (if is_global then Int.max (M.find l !globals - 1) 0 else M.find l !lmap)
with Not_found -> with Not_found ->
failwith (Printf.sprintf "ERROR: undefined label of public '%s'" l) )) failwith (Printf.sprintf "ERROR: undefined label of public '%s'" l) ))
@@ S.elements !pubs @@ S.elements !pubs
@ -386,7 +395,7 @@ module ByteCode = struct
Buffer.add_char subst_table (Char.chr 0)) Buffer.add_char subst_table (Char.chr 0))
!substs; !substs;
Buffer.add_int32_ne file (Int32.of_int @@ Bytes.length str_table); Buffer.add_int32_ne file (Int32.of_int @@ Bytes.length str_table);
Buffer.add_int32_ne file (Int32.of_int @@ !glob_count); Buffer.add_int32_ne file (Int32.of_int @@ !glob_count - 1); (* 0 was reserved for extern globals *)
Buffer.add_int32_ne file (Int32.of_int @@ Buffer.length subst_table); Buffer.add_int32_ne file (Int32.of_int @@ Buffer.length subst_table);
Buffer.add_int32_ne file (Int32.of_int @@ List.length imports); Buffer.add_int32_ne file (Int32.of_int @@ List.length imports);
Buffer.add_int32_ne file (Int32.of_int @@ List.length pubs); Buffer.add_int32_ne file (Int32.of_int @@ List.length pubs);