Add error logs. Fix GC.

This commit is contained in:
CismonX 2020-02-17 00:36:49 +08:00
parent 443347e352
commit c47c3e36c7
No known key found for this signature in database
GPG Key ID: 315D6652268C5007
5 changed files with 99 additions and 48 deletions

View File

@ -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); 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_COLD void
u6a_info_verbose_(const char* format, ...) { u6a_info_verbose_(const char* format, ...) {
if (verbose) { if (verbose) {

View File

@ -80,6 +80,15 @@ u6a_err_bad_bc_ver(const char* stage, const char* filename, int ver_major, int v
void void
u6a_err_vm_pool_oom(const char* stage); 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 void
u6a_info_verbose_(const char* format, ...); u6a_info_verbose_(const char* format, ...);

View File

@ -48,17 +48,28 @@ static const char* info_runtime = "runtime";
#define CHECK_BC_HEADER_VER(file_header) \ #define CHECK_BC_HEADER_VER(file_header) \
( (file_header).ver_major == U6A_VER_MAJOR && (file_header).ver_minor == U6A_VER_MINOR ) ( (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_) \ #define ACC_FN_REF(fn_, ref_) \
vm_var_fn_free(acc); \
acc = U6A_VM_VAR_FN_REF(fn_, ref_); \ acc = U6A_VM_VAR_FN_REF(fn_, ref_); \
if (UNLIKELY(acc.ref == UINT32_MAX)) { \ if (UNLIKELY(acc.ref == UINT32_MAX)) { \
goto runtime_error; \ goto runtime_error; \
} }
#define CHECK_FORCE() \ #define CHECK_FORCE(log_func, err_val) \
if (!force_exec) { \ if (!force_exec) { \
log_func(err_runtime, err_val); \
goto runtime_error; \ goto runtime_error; \
} }
#define STACK_PUSH1(fn_0) \ #define STACK_PUSH1(fn_0) \
vm_var_fn_addref(fn_0); \
if (UNLIKELY(!u6a_vm_stack_push1(fn_0))) { \ if (UNLIKELY(!u6a_vm_stack_push1(fn_0))) { \
goto runtime_error; \ goto runtime_error; \
} }
@ -75,7 +86,8 @@ static const char* info_runtime = "runtime";
goto runtime_error; \ goto runtime_error; \
} }
#define STACK_POP() \ #define STACK_POP() \
u6a_vm_stack_top(); \ vm_var_fn_free(top); \
top = u6a_vm_stack_top(); \
if (UNLIKELY(!u6a_vm_stack_pop())) { \ if (UNLIKELY(!u6a_vm_stack_pop())) { \
goto runtime_error; \ goto runtime_error; \
} }
@ -191,10 +203,10 @@ u6a_runtime_init(struct u6a_runtime_options* options) {
U6A_HOT union u6a_vm_var U6A_HOT union u6a_vm_var
u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) { 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; struct u6a_vm_ins* ins = text + text_subst_len;
int current_char = EOF; 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; struct u6a_vm_var_tuple tuple;
void* ptr; void* ptr;
while (true) { while (true) {
@ -204,55 +216,67 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
func.token = ins->operand.fn.first; func.token = ins->operand.fn.first;
} else { } else {
func = acc; func = acc;
goto arg_from_ins;
} }
if (ins->operand.fn.second.fn) { if (ins->operand.fn.second.fn) {
arg_from_ins:
arg.token = ins->operand.fn.second; arg.token = ins->operand.fn.second;
} else { } else {
arg = acc; arg = acc;
} }
goto do_apply; goto do_apply;
case u6a_vo_la: case u6a_vo_la:
func = STACK_POP(); STACK_POP();
func = top;
arg = acc; arg = acc;
do_apply: do_apply:
switch (func.token.fn) { switch (func.token.fn) {
case u6a_vf_s: case u6a_vf_s:
vm_var_fn_addref(arg);
ACC_FN_REF(u6a_vf_s1, u6a_vm_pool_alloc1(arg)); ACC_FN_REF(u6a_vf_s1, u6a_vm_pool_alloc1(arg));
break; break;
case u6a_vf_s1: 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)); ACC_FN_REF(u6a_vf_s2, u6a_vm_pool_alloc2(u6a_vm_pool_get1(func.ref).fn, arg));
break; break;
case u6a_vf_s2: 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) { if (ins - text == 0x03) {
STACK_PUSH3(arg, u6a_vm_pool_get2(func.ref)); STACK_PUSH3(arg, tuple);
} else { } 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; ins = text;
continue; continue;
case u6a_vf_k: case u6a_vf_k:
vm_var_fn_addref(arg);
ACC_FN_REF(u6a_vf_k1, u6a_vm_pool_alloc1(arg)); ACC_FN_REF(u6a_vf_k1, u6a_vm_pool_alloc1(arg));
break; break;
case u6a_vf_k1: case u6a_vf_k1:
acc = u6a_vm_pool_get1(func.ref).fn; ACC_FN(u6a_vm_pool_get1(func.ref).fn);
break; break;
case u6a_vf_i: case u6a_vf_i:
acc = arg; ACC_FN(arg);
break; break;
case u6a_vf_out: case u6a_vf_out:
acc = arg; ACC_FN(arg);
fputc(func.token.ch, ostream); fputc(func.token.ch, ostream);
break; break;
case u6a_vf_j: case u6a_vf_j:
acc = arg; ACC_FN(arg);
ins = text + func.ref; ins = text + func.ref;
break; break;
case u6a_vf_f: case u6a_vf_f:
// Safe to assign IP here before jumping, as func won't be `j` or `f` // Safe to assign IP here before jumping, as func won't be `j` or `f`
ins = text + func.ref; ins = text + func.ref;
STACK_POP();
func = acc; func = acc;
arg = STACK_POP(); arg = top;
goto do_apply; goto do_apply;
case u6a_vf_c: case u6a_vf_c:
ptr = u6a_vm_stack_save(); ptr = u6a_vm_stack_save();
@ -267,30 +291,28 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
case u6a_vf_c1: case u6a_vf_c1:
tuple = u6a_vm_pool_get2_separate(func.ref); tuple = u6a_vm_pool_get2_separate(func.ref);
u6a_vm_stack_resume(tuple.v1.ptr); u6a_vm_stack_resume(tuple.v1.ptr);
u6a_vm_pool_free(func.ref);
ins = tuple.v2.ptr; ins = tuple.v2.ptr;
acc = arg; ACC_FN(arg);
break; break;
case u6a_vf_d1_c: case u6a_vf_d1_c:
func = u6a_vm_pool_get1(func.ref).fn; func = u6a_vm_pool_get1(func.ref).fn;
goto do_apply; goto do_apply;
case u6a_vf_d1_s: case u6a_vf_d1_s:
tuple = u6a_vm_pool_get2(func.ref); tuple = u6a_vm_pool_get2(func.ref);
u6a_vm_pool_free(func.ref);
STACK_PUSH1(tuple.v1.fn); STACK_PUSH1(tuple.v1.fn);
acc = tuple.v2.fn; ACC_FN(tuple.v2.fn);
ins = text + 0x03; ins = text + 0x03;
continue; continue;
case u6a_vf_d1_d: 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; ins = text + func.ref;
continue; continue;
case u6a_vf_v: case u6a_vf_v:
vm_var_fn_free(acc);
acc.token.fn = u6a_vf_v; acc.token.fn = u6a_vf_v;
vm_var_fn_free(arg);
break; break;
case u6a_vf_p: case u6a_vf_p:
acc = arg; ACC_FN(arg);
fputs(rodata + func.ref, ostream); fputs(rodata + func.ref, ostream);
break; break;
case u6a_vf_in: 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; arg.token.fn = current_char == EOF ? u6a_vf_v : u6a_vf_i;
goto do_apply; goto do_apply;
case u6a_vf_cmp: case u6a_vf_cmp:
acc = func; if (func.token.ch == current_char) {
func = arg; func = arg;
arg.token.fn = acc.token.ch == current_char ? u6a_vf_i : u6a_vf_v; arg.token.fn = u6a_vf_i;
} else {
func = arg;
arg.token.fn = u6a_vf_v;
}
goto do_apply; goto do_apply;
case u6a_vf_pipe: case u6a_vf_pipe:
func = arg; func = arg;
@ -315,7 +341,7 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
// Every program should terminate with explicit `e` function // Every program should terminate with explicit `e` function
return U6A_VM_VAR_FN(arg); return U6A_VM_VAR_FN(arg);
default: default:
CHECK_FORCE(); CHECK_FORCE(u6a_err_invalid_vm_func, func.token.fn);
} }
break; break;
case u6a_vo_sa: case u6a_vo_sa:
@ -326,8 +352,10 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
break; break;
case u6a_vo_xch: case u6a_vo_xch:
if (UNLIKELY(acc.token.fn == u6a_vf_d)) { if (UNLIKELY(acc.token.fn == u6a_vf_d)) {
func = STACK_POP(); STACK_POP();
arg = STACK_POP(); func = top;
STACK_POP();
arg = top;
ACC_FN_REF(u6a_vf_d1_s, u6a_vm_pool_alloc2(func, arg)); ACC_FN_REF(u6a_vf_d1_s, u6a_vm_pool_alloc2(func, arg));
} else { } else {
acc = u6a_vm_stack_xch(acc); acc = u6a_vm_stack_xch(acc);
@ -335,20 +363,20 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
break; break;
case u6a_vo_del: case u6a_vo_del:
delay: 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; ins = text + text_subst_len + ins->operand.offset;
continue; continue;
case u6a_vo_lc: case u6a_vo_lc:
switch (ins->opcode_ex) { switch (ins->opcode_ex) {
case u6a_vo_ex_print: 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; break;
default: default:
CHECK_FORCE(); CHECK_FORCE(u6a_err_invalid_ex_opcode, ins->opcode_ex);
} }
break; break;
default: default:
CHECK_FORCE(); CHECK_FORCE(u6a_err_invalid_opcode, ins->opcode);
} }
++ins; ++ins;
} }

View File

@ -53,20 +53,20 @@ enum u6a_vm_opcode_ex {
enum u6a_vm_fn { enum u6a_vm_fn {
u6a_vf_placeholder_, 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_k, u6a_vf_s, u6a_vf_i, u6a_vf_v, u6a_vf_c, u6a_vf_d, u6a_vf_e,
u6a_vf_in, /* @ */ u6a_vf_in, /* @ */
u6a_vf_pipe, /* | */ u6a_vf_pipe, /* | */
u6a_vf_out = U6A_VM_FN_CHAR, /* .X */ u6a_vf_out = U6A_VM_FN_CHAR, /* .X */
u6a_vf_cmp, /* ?X */ u6a_vf_cmp, /* ?X */
u6a_vf_k1 = U6A_VM_FN_REF, /* `kX */ u6a_vf_k1 = U6A_VM_FN_REF, /* `kX */
u6a_vf_s1, /* `sX */ u6a_vf_s1, /* `sX */
u6a_vf_s2, /* ``sXY */ u6a_vf_s2, /* ``sXY */
u6a_vf_c1, /* `cX */ u6a_vf_c1, /* `cX */
u6a_vf_d1_s = U6A_VM_FN_PROMISE, /* `d`XZ */ u6a_vf_d1_s = U6A_VM_FN_PROMISE | U6A_VM_FN_REF, /* `d`XZ */
u6a_vf_d1_c, /* `dX */ u6a_vf_d1_c, /* `dX */
u6a_vf_d1_d, /* `dF */ u6a_vf_d1_d = U6A_VM_FN_PROMISE, /* `dF */
u6a_vf_j = U6A_VM_FN_INTERNAL, /* (jump) */ u6a_vf_j = U6A_VM_FN_INTERNAL, /* (jump) */
u6a_vf_f, /* (finalize) */ u6a_vf_f, /* (finalize) */
u6a_vf_p /* (print) */ u6a_vf_p /* (print) */
}; };
struct u6a_vm_ins { struct u6a_vm_ins {

View File

@ -54,7 +54,7 @@ static inline struct vm_pool_elem*
vm_pool_elem_alloc() { vm_pool_elem_alloc() {
struct vm_pool_elem* new_elem; struct vm_pool_elem* new_elem;
if (holes->pos == UINT32_MAX) { 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); u6a_err_vm_pool_oom(err_stage);
return NULL; return NULL;
} }
@ -127,8 +127,7 @@ u6a_vm_pool_alloc1(struct u6a_vm_var_fn v1) {
if (UNLIKELY(elem == NULL)) { if (UNLIKELY(elem == NULL)) {
return UINT32_MAX; return UINT32_MAX;
} }
elem->values.v1.fn = v1; elem->values = (struct u6a_vm_var_tuple) { .v1.fn = v1, .v2.ptr = NULL };
elem->values.v2.fn.token.fn = ~U6A_VM_FN_REF;
elem->flags = 0; elem->flags = 0;
return elem - active_pool->elems; return elem - active_pool->elems;
} }
@ -192,8 +191,8 @@ u6a_vm_pool_free(uint32_t offset) {
// Continuation destroyed before used // Continuation destroyed before used
u6a_vm_stack_discard(elem->values.v1.ptr); u6a_vm_stack_discard(elem->values.v1.ptr);
} else { } else {
free_stack_push(elem->values.v1.fn);
free_stack_push(elem->values.v2.fn); free_stack_push(elem->values.v2.fn);
free_stack_push(elem->values.v1.fn);
} }
} }
} while ((elem = free_stack_pop())); } while ((elem = free_stack_pop()));