From 6b8f5f969e44b8f367e1e20ae547e8b9fe06d69b Mon Sep 17 00:00:00 2001 From: redoste Date: Sun, 27 Jun 2021 19:20:27 +0200 Subject: [PATCH] Introduce the memory_base field in the BM file metadata This makes BM bytecode compiled from Bang significantly smaller because the stack is no longer included in the file. Furthermore, debasm looks way cleaner because it doesn't print the stack anymore. --- bang/src/bang_compiler.c | 1 + basm/src/compiler.c | 23 +++++++++++++++++++++-- basm/src/compiler.h | 2 ++ basm/src/statement.c | 39 +++++++++++++++++++++++++++++++++++++++ basm/src/statement.h | 8 +++++++- bm/src/bm.c | 7 ++++--- bm/src/bm.h | 4 +++- debasm/src/debasm.c | 5 +++-- 8 files changed, 80 insertions(+), 9 deletions(-) diff --git a/bang/src/bang_compiler.c b/bang/src/bang_compiler.c index 67a08989..fdb017d1 100644 --- a/bang/src/bang_compiler.c +++ b/bang/src/bang_compiler.c @@ -683,6 +683,7 @@ void bang_prepare_var_stack(Bang *bang, Basm *basm, size_t stack_size) assert(sizeof(stack_start_addr) == ptr_def.size); bang->stack_frame_var_addr = basm_push_buffer_to_memory(basm, (uint8_t*) &stack_start_addr, ptr_def.size).as_u64; + basm->memory_base = stack_size; } void compile_var_def_into_basm(Bang *bang, Basm *basm, Bang_Var_Def var_def, Bang_Var_Storage storage) diff --git a/basm/src/compiler.c b/basm/src/compiler.c index 89f7c866..c9103f35 100644 --- a/basm/src/compiler.c +++ b/basm/src/compiler.c @@ -308,7 +308,8 @@ void basm_save_to_file_as_bm(Basm *basm, const char *file_path) .version = BM_FILE_VERSION, .entry = basm->entry, .program_size = basm->program_size, - .memory_size = basm->memory_size, + .memory_base = basm->memory_base, + .memory_size = basm->memory_size - basm->memory_base, .memory_capacity = basm->memory_capacity, .externals_size = basm->external_natives_size, }; @@ -327,7 +328,7 @@ void basm_save_to_file_as_bm(Basm *basm, const char *file_path) exit(1); } - fwrite(basm->memory, sizeof(basm->memory[0]), basm->memory_size, f); + fwrite(basm->memory + basm->memory_base, sizeof(basm->memory[0]), basm->memory_size - basm->memory_base, f); if (ferror(f)) { fprintf(stderr, "ERROR: Could not write to file `%s`: %s\n", file_path, strerror(errno)); @@ -403,6 +404,10 @@ void basm_translate_block_statement(Basm *basm, Block_Statement *block) basm_translate_macrodef_statement(basm, statement.value.as_macrodef, statement.location); break; + case STATEMENT_KIND_BASE: + basm_translate_base_statement(basm, statement.value.as_base, statement.location); + break; + case STATEMENT_KIND_MACROCALL: case STATEMENT_KIND_FUNCDEF: case STATEMENT_KIND_FOR: @@ -470,6 +475,7 @@ void basm_translate_block_statement(Basm *basm, Block_Statement *block) case STATEMENT_KIND_ASSERT: case STATEMENT_KIND_INCLUDE: case STATEMENT_KIND_CONST: + case STATEMENT_KIND_BASE: // NOTE: ignored at the second pass break; @@ -1288,6 +1294,19 @@ Macrodef *basm_resolve_macrodef(Basm *basm, String_View name) return NULL; } + +void basm_translate_base_statement(Basm *basm, Base_Statement base_statement, File_Location location) +{ + if (basm->memory_size != 0 || basm->memory_base != 0) { + fprintf(stderr, FL_Fmt": ERROR: %%base should precede every memory related statements\n", + FL_Arg(location)); + exit(1); + } + + basm_push_byte_array_to_memory(basm, base_statement.size, 0); + basm->memory_base = basm->memory_size; +} + Native_ID basm_push_external_native(Basm *basm, String_View native_name) { assert(basm->external_natives_size < BM_EXTERNAL_NATIVES_CAPACITY); diff --git a/basm/src/compiler.h b/basm/src/compiler.h index a9c0bb4e..d3cdba06 100644 --- a/basm/src/compiler.h +++ b/basm/src/compiler.h @@ -126,6 +126,7 @@ typedef struct { size_t string_lengths_size; uint8_t memory[BM_MEMORY_CAPACITY]; + size_t memory_base; size_t memory_size; size_t memory_capacity; @@ -179,6 +180,7 @@ bool basm_resolve_include_file_path(Basm *basm, Macrodef *basm_resolve_macrodef(Basm *basm, String_View name); void basm_translate_macrocall_statement(Basm *basm, Macrocall_Statement macrocall, File_Location location); void basm_translate_macrodef_statement(Basm *basm, Macrodef_Statement macrodef, File_Location location); +void basm_translate_base_statement(Basm *basm, Base_Statement base_statement, File_Location location); void basm_translate_block_statement(Basm *basm, Block_Statement *block); void basm_translate_const_statement(Basm *basm, Const_Statement konst, File_Location location); void basm_translate_native_statement(Basm *basm, Native_Statement native, File_Location location); diff --git a/basm/src/statement.c b/basm/src/statement.c index 55aa9516..4355581f 100644 --- a/basm/src/statement.c +++ b/basm/src/statement.c @@ -125,6 +125,14 @@ void dump_statement(FILE *stream, Statement statement, int level) exit(1); } break; + + case STATEMENT_KIND_BASE: { + uint64_t size = statement.value.as_base.size; + + fprintf(stream, "%*sBase:\n", level * 2, ""); + fprintf(stream, "%*s%"PRIu64"\n", (level + 1) * 2, "", size); + } + break; } } @@ -426,6 +434,20 @@ int dump_statement_as_dot_edges(FILE *stream, Statement statement, int *counter) } break; + case STATEMENT_KIND_BASE: { + int id = (*counter)++; + int child_id = (*counter)++; + + uint64_t size = statement.value.as_base.size; + + fprintf(stream, "Expr_%d [shape=diamond label=\"%%base\"]\n", id); + fprintf(stream, "Expr_%d [shape=circle label=\"%"PRIu64"\"]\n", + child_id, size); + fprintf(stream, "Expr_%d -> Expr_%d [style=dotted]\n", id, child_id); + return id; + } + break; + default: { assert(false && "dump_statement_as_dot_edges: unreachable"); exit(1); @@ -732,6 +754,23 @@ void parse_directive_from_line(Arena *arena, Linizer *linizer, Block_List *outpu exit(1); } + block_list_push(arena, output, statement); + } else if (sv_eq(name, sv_from_cstr("base"))) { + Statement statement = {0}; + statement.location = location; + statement.kind = STATEMENT_KIND_BASE; + + Tokenizer tokenizer = tokenizer_from_sv(body); + Expr base_size = parse_expr_from_tokens(arena, &tokenizer, location); + if (base_size.kind != EXPR_KIND_LIT_INT) { + fprintf(stderr, FL_Fmt": ERROR: expected memory base for %%base\n", + FL_Arg(location)); + exit(1); + } + + statement.value.as_base.size = base_size.value.as_lit_int; + expect_no_tokens(&tokenizer, location); + block_list_push(arena, output, statement); } else { Tokenizer tokenizer = tokenizer_from_sv(body); diff --git a/basm/src/statement.h b/basm/src/statement.h index 3b30da15..d667ae4e 100644 --- a/basm/src/statement.h +++ b/basm/src/statement.h @@ -24,7 +24,8 @@ typedef enum { STATEMENT_KIND_FOR, STATEMENT_KIND_FUNCDEF, STATEMENT_KIND_MACROCALL, - STATEMENT_KIND_MACRODEF + STATEMENT_KIND_MACRODEF, + STATEMENT_KIND_BASE } Statement_Kind; typedef struct { @@ -92,6 +93,10 @@ typedef struct { Block_Statement *body; } Macrodef_Statement; +typedef struct { + uint64_t size; +} Base_Statement; + typedef union { Emit_Inst_Statement as_emit_inst; Label_Statement as_label; @@ -108,6 +113,7 @@ typedef union { Fundef_Statement as_fundef; Macrocall_Statement as_macrocall; Macrodef_Statement as_macrodef; + Base_Statement as_base; } Statement_Value; struct Statement { diff --git a/bm/src/bm.c b/bm/src/bm.c index 505f4ea5..89ef7bb9 100644 --- a/bm/src/bm.c +++ b/bm/src/bm.c @@ -891,11 +891,11 @@ void bm_load_program_from_file(Bm *bm, const char *file_path) exit(1); } - if (meta.memory_size > meta.memory_capacity) { + if (meta.memory_base + meta.memory_size > meta.memory_capacity) { fprintf(stderr, "ERROR: %s: memory size %"PRIu64" is greater than declared memory capacity %"PRIu64"\n", file_path, - meta.memory_size, + meta.memory_base + meta.memory_size, meta.memory_capacity); exit(1); } @@ -919,8 +919,9 @@ void bm_load_program_from_file(Bm *bm, const char *file_path) exit(1); } - n = fread(bm->memory, sizeof(bm->memory[0]), meta.memory_size, f); + n = fread(bm->memory + meta.memory_base, sizeof(bm->memory[0]), meta.memory_size, f); bm->expected_memory_size = meta.memory_size; + bm->memory_base = meta.memory_base; if (n != meta.memory_size) { fprintf(stderr, "ERROR: %s: read %zd bytes of memory section, but expected %"PRIu64" bytes.\n", diff --git a/bm/src/bm.h b/bm/src/bm.h index af15b5bb..4e005874 100644 --- a/bm/src/bm.h +++ b/bm/src/bm.h @@ -188,6 +188,7 @@ struct Bm { // The program is allowed to access memory beyond the `expected_memory_size`. // This variable is needed for debasm to reliably recover the source code. size_t expected_memory_size; + size_t memory_base; bool halt; }; @@ -199,13 +200,14 @@ void bm_dump_stack(FILE *stream, const Bm *bm); void bm_load_program_from_file(Bm *bm, const char *file_path); #define BM_FILE_MAGIC 0xa4016d62 -#define BM_FILE_VERSION 7 +#define BM_FILE_VERSION 8 PACK(struct Bm_File_Meta { uint32_t magic; uint16_t version; uint64_t program_size; uint64_t entry; + uint64_t memory_base; uint64_t memory_size; uint64_t memory_capacity; uint64_t externals_size; diff --git a/debasm/src/debasm.c b/debasm/src/debasm.c index 3b97895a..ae53b9a5 100644 --- a/debasm/src/debasm.c +++ b/debasm/src/debasm.c @@ -20,8 +20,9 @@ int main(int argc, char *argv[]) printf("%%native %s\n", bm.externals[i].name); } + printf("%%base %zu\n", bm.memory_base); printf("%%const MEMORY = \""); - for (size_t i = 0; i < bm.expected_memory_size; ++i) { + for (size_t i = bm.memory_base; i < bm.expected_memory_size + bm.memory_base; ++i) { if (32 <= bm.memory[i] && bm.memory[i] < 127) { printf("%c", bm.memory[i]); } else { @@ -29,7 +30,7 @@ int main(int argc, char *argv[]) } } printf("\"\n"); - printf("%%assert MEMORY == 0\n"); + printf("%%assert MEMORY == %zu\n", bm.memory_base); for (Inst_Addr i = 0; i < bm.program_size; ++i) { if (i == bm.ip) {