From c47c3e36c76244870eaf5167ed9202d21bbffa3e Mon Sep 17 00:00:00 2001 From: CismonX Date: Mon, 17 Feb 2020 00:36:49 +0800 Subject: [PATCH] Add error logs. Fix GC. --- src/logging.c | 15 +++++++++ src/logging.h | 9 ++++++ src/runtime.c | 88 +++++++++++++++++++++++++++++++++------------------ src/vm_defs.h | 28 ++++++++-------- src/vm_pool.c | 7 ++-- 5 files changed, 99 insertions(+), 48 deletions(-) diff --git a/src/logging.c b/src/logging.c index c249987..96146d5 100644 --- a/src/logging.c +++ b/src/logging.c @@ -129,6 +129,21 @@ u6a_err_vm_pool_oom(const char* stage) { fprintf(stderr, "%s: [%s] VM object pool memory exhausted.\n", stage, prog_name); } +U6A_COLD void +u6a_err_invalid_opcode(const char* stage, int opcode) { + fprintf(stderr, "%s: [%s] invalid opcode %d.\n", prog_name, stage, opcode); +} + +U6A_COLD void +u6a_err_invalid_ex_opcode(const char* stage, int ex_opcode) { + fprintf(stderr, "%s: [%s] invalid extended opcode %d.\n", prog_name, stage, ex_opcode); +} + +U6A_COLD void +u6a_err_invalid_vm_func(const char* stage, int fn) { + fprintf(stderr, "%s: [%s] invalid function %d.\n", prog_name, stage, fn); +} + U6A_COLD void u6a_info_verbose_(const char* format, ...) { if (verbose) { diff --git a/src/logging.h b/src/logging.h index 35e26c6..44a81e4 100644 --- a/src/logging.h +++ b/src/logging.h @@ -80,6 +80,15 @@ u6a_err_bad_bc_ver(const char* stage, const char* filename, int ver_major, int v void u6a_err_vm_pool_oom(const char* stage); +void +u6a_err_invalid_opcode(const char* stage, int opcode); + +void +u6a_err_invalid_ex_opcode(const char* stage, int ex_opcode); + +void +u6a_err_invalid_vm_func(const char* stage, int fn); + void u6a_info_verbose_(const char* format, ...); diff --git a/src/runtime.c b/src/runtime.c index f8a8ad8..5ec7472 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -48,17 +48,28 @@ static const char* info_runtime = "runtime"; #define CHECK_BC_HEADER_VER(file_header) \ ( (file_header).ver_major == U6A_VER_MAJOR && (file_header).ver_minor == U6A_VER_MINOR ) +// Addref before free, for acc may equal to fn +#define ACC_FN(fn_) \ + vm_var_fn_addref(fn_); \ + vm_var_fn_free(acc); \ + acc = fn_ +#define ACC_FN_INIT(fn_) \ + vm_var_fn_free(acc); \ + acc = fn_ #define ACC_FN_REF(fn_, ref_) \ + vm_var_fn_free(acc); \ acc = U6A_VM_VAR_FN_REF(fn_, ref_); \ if (UNLIKELY(acc.ref == UINT32_MAX)) { \ goto runtime_error; \ } -#define CHECK_FORCE() \ +#define CHECK_FORCE(log_func, err_val) \ if (!force_exec) { \ + log_func(err_runtime, err_val); \ goto runtime_error; \ } #define STACK_PUSH1(fn_0) \ + vm_var_fn_addref(fn_0); \ if (UNLIKELY(!u6a_vm_stack_push1(fn_0))) { \ goto runtime_error; \ } @@ -75,7 +86,8 @@ static const char* info_runtime = "runtime"; goto runtime_error; \ } #define STACK_POP() \ - u6a_vm_stack_top(); \ + vm_var_fn_free(top); \ + top = u6a_vm_stack_top(); \ if (UNLIKELY(!u6a_vm_stack_pop())) { \ goto runtime_error; \ } @@ -191,10 +203,10 @@ u6a_runtime_init(struct u6a_runtime_options* options) { U6A_HOT union u6a_vm_var u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { - struct u6a_vm_var_fn acc; + struct u6a_vm_var_fn acc = { 0 }, top = { 0 }; struct u6a_vm_ins* ins = text + text_subst_len; int current_char = EOF; - struct u6a_vm_var_fn func, arg; + struct u6a_vm_var_fn func = { 0 }, arg = { 0 }; struct u6a_vm_var_tuple tuple; void* ptr; while (true) { @@ -204,55 +216,67 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { func.token = ins->operand.fn.first; } else { func = acc; + goto arg_from_ins; } if (ins->operand.fn.second.fn) { + arg_from_ins: arg.token = ins->operand.fn.second; } else { arg = acc; } goto do_apply; case u6a_vo_la: - func = STACK_POP(); + STACK_POP(); + func = top; arg = acc; do_apply: switch (func.token.fn) { case u6a_vf_s: + vm_var_fn_addref(arg); ACC_FN_REF(u6a_vf_s1, u6a_vm_pool_alloc1(arg)); break; case u6a_vf_s1: + vm_var_fn_addref(arg); + vm_var_fn_addref(u6a_vm_pool_get1(func.ref).fn); ACC_FN_REF(u6a_vf_s2, u6a_vm_pool_alloc2(u6a_vm_pool_get1(func.ref).fn, arg)); break; case u6a_vf_s2: + tuple = u6a_vm_pool_get2(func.ref); + vm_var_fn_addref(tuple.v1.fn); + vm_var_fn_addref(tuple.v2.fn); + vm_var_fn_addref(arg); if (ins - text == 0x03) { - STACK_PUSH3(arg, u6a_vm_pool_get2(func.ref)); + STACK_PUSH3(arg, tuple); } else { - STACK_PUSH4(U6A_VM_VAR_FN_REF(u6a_vf_j, ins - text), arg, u6a_vm_pool_get2(func.ref)); + STACK_PUSH4(U6A_VM_VAR_FN_REF(u6a_vf_j, ins - text), arg, tuple); } - acc = vm_var_fn_addref(arg); + ACC_FN(arg); ins = text; continue; case u6a_vf_k: + vm_var_fn_addref(arg); ACC_FN_REF(u6a_vf_k1, u6a_vm_pool_alloc1(arg)); break; case u6a_vf_k1: - acc = u6a_vm_pool_get1(func.ref).fn; + ACC_FN(u6a_vm_pool_get1(func.ref).fn); break; case u6a_vf_i: - acc = arg; + ACC_FN(arg); break; case u6a_vf_out: - acc = arg; + ACC_FN(arg); fputc(func.token.ch, ostream); break; case u6a_vf_j: - acc = arg; + ACC_FN(arg); ins = text + func.ref; break; case u6a_vf_f: // Safe to assign IP here before jumping, as func won't be `j` or `f` ins = text + func.ref; + STACK_POP(); func = acc; - arg = STACK_POP(); + arg = top; goto do_apply; case u6a_vf_c: ptr = u6a_vm_stack_save(); @@ -267,30 +291,28 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { case u6a_vf_c1: tuple = u6a_vm_pool_get2_separate(func.ref); u6a_vm_stack_resume(tuple.v1.ptr); - u6a_vm_pool_free(func.ref); ins = tuple.v2.ptr; - acc = arg; + ACC_FN(arg); break; case u6a_vf_d1_c: func = u6a_vm_pool_get1(func.ref).fn; goto do_apply; case u6a_vf_d1_s: tuple = u6a_vm_pool_get2(func.ref); - u6a_vm_pool_free(func.ref); STACK_PUSH1(tuple.v1.fn); - acc = tuple.v2.fn; + ACC_FN(tuple.v2.fn); ins = text + 0x03; continue; case u6a_vf_d1_d: - STACK_PUSH2(arg, U6A_VM_VAR_FN_REF(u6a_vf_f, ins - text)); + STACK_PUSH2(vm_var_fn_addref(arg), U6A_VM_VAR_FN_REF(u6a_vf_f, ins - text)); ins = text + func.ref; continue; case u6a_vf_v: + vm_var_fn_free(acc); acc.token.fn = u6a_vf_v; - vm_var_fn_free(arg); break; case u6a_vf_p: - acc = arg; + ACC_FN(arg); fputs(rodata + func.ref, ostream); break; case u6a_vf_in: @@ -299,9 +321,13 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { arg.token.fn = current_char == EOF ? u6a_vf_v : u6a_vf_i; goto do_apply; case u6a_vf_cmp: - acc = func; - func = arg; - arg.token.fn = acc.token.ch == current_char ? u6a_vf_i : u6a_vf_v; + if (func.token.ch == current_char) { + func = arg; + arg.token.fn = u6a_vf_i; + } else { + func = arg; + arg.token.fn = u6a_vf_v; + } goto do_apply; case u6a_vf_pipe: func = arg; @@ -315,7 +341,7 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { // Every program should terminate with explicit `e` function return U6A_VM_VAR_FN(arg); default: - CHECK_FORCE(); + CHECK_FORCE(u6a_err_invalid_vm_func, func.token.fn); } break; case u6a_vo_sa: @@ -326,8 +352,10 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { break; case u6a_vo_xch: if (UNLIKELY(acc.token.fn == u6a_vf_d)) { - func = STACK_POP(); - arg = STACK_POP(); + STACK_POP(); + func = top; + STACK_POP(); + arg = top; ACC_FN_REF(u6a_vf_d1_s, u6a_vm_pool_alloc2(func, arg)); } else { acc = u6a_vm_stack_xch(acc); @@ -335,20 +363,20 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { break; case u6a_vo_del: delay: - acc = U6A_VM_VAR_FN_REF(u6a_vf_d1_d, ins + 1 - text); + ACC_FN_INIT(U6A_VM_VAR_FN_REF(u6a_vf_d1_d, ins + 1 - text)); ins = text + text_subst_len + ins->operand.offset; continue; case u6a_vo_lc: switch (ins->opcode_ex) { case u6a_vo_ex_print: - acc = U6A_VM_VAR_FN_REF(u6a_vf_p, ins->operand.offset); + ACC_FN_INIT(U6A_VM_VAR_FN_REF(u6a_vf_p, ins->operand.offset)); break; default: - CHECK_FORCE(); + CHECK_FORCE(u6a_err_invalid_ex_opcode, ins->opcode_ex); } break; default: - CHECK_FORCE(); + CHECK_FORCE(u6a_err_invalid_opcode, ins->opcode); } ++ins; } diff --git a/src/vm_defs.h b/src/vm_defs.h index 585ad34..fc06778 100644 --- a/src/vm_defs.h +++ b/src/vm_defs.h @@ -53,20 +53,20 @@ enum u6a_vm_opcode_ex { enum u6a_vm_fn { u6a_vf_placeholder_, u6a_vf_k, u6a_vf_s, u6a_vf_i, u6a_vf_v, u6a_vf_c, u6a_vf_d, u6a_vf_e, - u6a_vf_in, /* @ */ - u6a_vf_pipe, /* | */ - u6a_vf_out = U6A_VM_FN_CHAR, /* .X */ - u6a_vf_cmp, /* ?X */ - u6a_vf_k1 = U6A_VM_FN_REF, /* `kX */ - u6a_vf_s1, /* `sX */ - u6a_vf_s2, /* ``sXY */ - u6a_vf_c1, /* `cX */ - u6a_vf_d1_s = U6A_VM_FN_PROMISE, /* `d`XZ */ - u6a_vf_d1_c, /* `dX */ - u6a_vf_d1_d, /* `dF */ - u6a_vf_j = U6A_VM_FN_INTERNAL, /* (jump) */ - u6a_vf_f, /* (finalize) */ - u6a_vf_p /* (print) */ + u6a_vf_in, /* @ */ + u6a_vf_pipe, /* | */ + u6a_vf_out = U6A_VM_FN_CHAR, /* .X */ + u6a_vf_cmp, /* ?X */ + u6a_vf_k1 = U6A_VM_FN_REF, /* `kX */ + u6a_vf_s1, /* `sX */ + u6a_vf_s2, /* ``sXY */ + u6a_vf_c1, /* `cX */ + u6a_vf_d1_s = U6A_VM_FN_PROMISE | U6A_VM_FN_REF, /* `d`XZ */ + u6a_vf_d1_c, /* `dX */ + u6a_vf_d1_d = U6A_VM_FN_PROMISE, /* `dF */ + u6a_vf_j = U6A_VM_FN_INTERNAL, /* (jump) */ + u6a_vf_f, /* (finalize) */ + u6a_vf_p /* (print) */ }; struct u6a_vm_ins { diff --git a/src/vm_pool.c b/src/vm_pool.c index 6d192d5..eb2a88e 100644 --- a/src/vm_pool.c +++ b/src/vm_pool.c @@ -54,7 +54,7 @@ static inline struct vm_pool_elem* vm_pool_elem_alloc() { struct vm_pool_elem* new_elem; if (holes->pos == UINT32_MAX) { - if (UNLIKELY(++active_pool->pos >= pool_len)) { + if (UNLIKELY(++active_pool->pos == pool_len)) { u6a_err_vm_pool_oom(err_stage); return NULL; } @@ -127,8 +127,7 @@ u6a_vm_pool_alloc1(struct u6a_vm_var_fn v1) { if (UNLIKELY(elem == NULL)) { return UINT32_MAX; } - elem->values.v1.fn = v1; - elem->values.v2.fn.token.fn = ~U6A_VM_FN_REF; + elem->values = (struct u6a_vm_var_tuple) { .v1.fn = v1, .v2.ptr = NULL }; elem->flags = 0; return elem - active_pool->elems; } @@ -192,8 +191,8 @@ u6a_vm_pool_free(uint32_t offset) { // Continuation destroyed before used u6a_vm_stack_discard(elem->values.v1.ptr); } else { - free_stack_push(elem->values.v1.fn); free_stack_push(elem->values.v2.fn); + free_stack_push(elem->values.v1.fn); } } } while ((elem = free_stack_pop()));