Add error logs. Fix GC.
This commit is contained in:
parent
443347e352
commit
c47c3e36c7
|
@ -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) {
|
||||
|
|
|
@ -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, ...);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()));
|
||||
|
|
Loading…
Reference in New Issue