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);
}
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) {

View File

@ -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, ...);

View File

@ -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;
}

View File

@ -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 {

View File

@ -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()));