Implement reference tracking in vm
This commit is contained in:
parent
c74ea3b417
commit
7452db55df
4
mod1.vml
4
mod1.vml
@ -1,4 +1,6 @@
|
|||||||
(use mod2)
|
(use mod2)
|
||||||
(use core)
|
(use core)
|
||||||
|
|
||||||
(print (f 1 2 3))
|
(define a (cons 1 (cons 2 (cons 3 (cons 4 nil)))))
|
||||||
|
|
||||||
|
(print (list-ref a 1))
|
||||||
|
16
mod2.vml
16
mod2.vml
@ -1,6 +1,12 @@
|
|||||||
(export sqr f)
|
(export
|
||||||
|
list-ref)
|
||||||
|
|
||||||
(define (sqr x) (* x x))
|
(define (list-ref xs i)
|
||||||
|
(if (null? xs)
|
||||||
(define (f x y z)
|
nil
|
||||||
(+ (sqr x) (sqr y) (sqr z)))
|
(if (= i 0)
|
||||||
|
(car xs)
|
||||||
|
(list-ref (cdr xs) (- i 1))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
@ -55,6 +55,21 @@ static inline int pair_q(uint64_t w) {
|
|||||||
return ref_q(w) && (!null_q(w) && getref(w)->type == VT_CONS);
|
return ref_q(w) && (!null_q(w) && getref(w)->type == VT_CONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vm_value_ref(struct vm_value *v);
|
||||||
|
int vm_value_unref(struct vm_value *v);
|
||||||
|
|
||||||
|
static inline void vm_ref(uint64_t w) {
|
||||||
|
if (ref_q(w)) {
|
||||||
|
vm_value_ref(getref(w));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline int vm_unref(uint64_t w) {
|
||||||
|
if (ref_q(w)) {
|
||||||
|
return vm_value_unref(getref(w));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void vm_value_free(struct vm_value *val);
|
void vm_value_free(struct vm_value *val);
|
||||||
|
|
||||||
struct vm_value *vm_cons(uint64_t w0, uint64_t w1);
|
struct vm_value *vm_cons(uint64_t w0, uint64_t w1);
|
||||||
|
@ -21,6 +21,7 @@ static int c_print(struct vm_state *vm) {
|
|||||||
}
|
}
|
||||||
vm_print(w);
|
vm_print(w);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
vm_unref(w);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ struct vm_func_entry *unit_add_function(struct vm_unit *u) {
|
|||||||
|
|
||||||
void unit_free(struct vm_unit *u) {
|
void unit_free(struct vm_unit *u) {
|
||||||
struct vm_func_entry *func;
|
struct vm_func_entry *func;
|
||||||
uint64_t w;
|
|
||||||
|
|
||||||
vector_free(&u->ref_table);
|
vector_free(&u->ref_table);
|
||||||
for (size_t i = 0; i < u->functions.size; ++i) {
|
for (size_t i = 0; i < u->functions.size; ++i) {
|
||||||
@ -23,10 +22,7 @@ void unit_free(struct vm_unit *u) {
|
|||||||
vector_free(&u->functions);
|
vector_free(&u->functions);
|
||||||
|
|
||||||
for (size_t i = 0; i < u->global_pool_size; ++i) {
|
for (size_t i = 0; i < u->global_pool_size; ++i) {
|
||||||
w = u->global_pool[i];
|
vm_unref(u->global_pool[i]);
|
||||||
if (ref_q(w)) {
|
|
||||||
vm_value_free(getref(w));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(u->global_pool);
|
free(u->global_pool);
|
||||||
|
70
vm/vmstate.c
70
vm/vmstate.c
@ -156,6 +156,7 @@ static int vm_eval_debug(struct vm_state *vm, struct vm_func_entry *func, uint32
|
|||||||
printf("trace: ");
|
printf("trace: ");
|
||||||
vm_print(w0);
|
vm_print(w0);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
vm_unref(w0);
|
||||||
return 0;
|
return 0;
|
||||||
default:
|
default:
|
||||||
return -ERR_OPCODE_UNDEFINED;
|
return -ERR_OPCODE_UNDEFINED;
|
||||||
@ -168,6 +169,7 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
ssize_t ii0;
|
ssize_t ii0;
|
||||||
size_t i0;
|
size_t i0;
|
||||||
struct vm_ref_entry *r0;
|
struct vm_ref_entry *r0;
|
||||||
|
struct vm_value *v0;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
assert(vm->lp < vm->units.size);
|
assert(vm->lp < vm->units.size);
|
||||||
@ -176,6 +178,7 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
struct vm_func_entry *func = vector_ref(&unit->functions, vm->fp);
|
struct vm_func_entry *func = vector_ref(&unit->functions, vm->fp);
|
||||||
uint32_t opcode = func->bytecode[vm->ip++];
|
uint32_t opcode = func->bytecode[vm->ip++];
|
||||||
|
|
||||||
|
printf("%02zx:%02zx:%02zx: %08x\n", vm->lp, vm->fp, vm->ip, opcode);
|
||||||
switch (opcode >> 24) {
|
switch (opcode >> 24) {
|
||||||
case OP_ADD:
|
case OP_ADD:
|
||||||
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
|
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
|
||||||
@ -185,6 +188,14 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return vm_push_integer(vm, sw0 + sw1);
|
return vm_push_integer(vm, sw0 + sw1);
|
||||||
|
case OP_SUB:
|
||||||
|
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if ((res = vm_pop_integer(vm, &sw1)) != 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return vm_push_integer(vm, sw0 - sw1);
|
||||||
case OP_MUL:
|
case OP_MUL:
|
||||||
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
|
if ((res = vm_pop_integer(vm, &sw0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
@ -197,7 +208,9 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return vm_push_bool(vm, null_q(w0));
|
res = vm_push_bool(vm, null_q(w0));
|
||||||
|
vm_unref(w0);
|
||||||
|
return res;
|
||||||
case OP_EQ:
|
case OP_EQ:
|
||||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
@ -209,7 +222,10 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
// TODO what do?
|
// TODO what do?
|
||||||
return -ERR_OPERAND_TYPE;
|
return -ERR_OPERAND_TYPE;
|
||||||
}
|
}
|
||||||
return vm_push_bool(vm, w0 == w1);
|
res = vm_push_bool(vm, w0 == w1);
|
||||||
|
vm_unref(w0);
|
||||||
|
vm_unref(w1);
|
||||||
|
return res;
|
||||||
//
|
//
|
||||||
case OP_LDNIL:
|
case OP_LDNIL:
|
||||||
return stack_push(&vm->data_stack, FLAG_REF);
|
return stack_push(&vm->data_stack, FLAG_REF);
|
||||||
@ -222,7 +238,10 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
if (!pair_q(w0)) {
|
if (!pair_q(w0)) {
|
||||||
return -ERR_OPERAND_TYPE;
|
return -ERR_OPERAND_TYPE;
|
||||||
}
|
}
|
||||||
return stack_push(&vm->data_stack, getref(w0)->v_cons.fat_ar);
|
vm_ref(getref(w0)->v_cons.fat_ar);
|
||||||
|
res = stack_push(&vm->data_stack, getref(w0)->v_cons.fat_ar);
|
||||||
|
vm_unref(w0);
|
||||||
|
return res;
|
||||||
case OP_CDR:
|
case OP_CDR:
|
||||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
@ -230,7 +249,10 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
if (!pair_q(w0)) {
|
if (!pair_q(w0)) {
|
||||||
return -ERR_OPERAND_TYPE;
|
return -ERR_OPERAND_TYPE;
|
||||||
}
|
}
|
||||||
return stack_push(&vm->data_stack, getref(w0)->v_cons.fat_dr);
|
vm_ref(getref(w0)->v_cons.fat_dr);
|
||||||
|
res = stack_push(&vm->data_stack, getref(w0)->v_cons.fat_dr);
|
||||||
|
vm_unref(w0);
|
||||||
|
return res;
|
||||||
case OP_CONS:
|
case OP_CONS:
|
||||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
@ -238,56 +260,74 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
if ((res = stack_pop(&vm->data_stack, &w1)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w1)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return vm_push_ref(vm, vm_cons(w0, w1));
|
v0 = vm_cons(w0, w1);
|
||||||
|
vm_value_ref(v0);
|
||||||
|
res = vm_push_ref(vm, v0);
|
||||||
|
vm_unref(w0);
|
||||||
|
vm_unref(w1);
|
||||||
|
return res;
|
||||||
//
|
//
|
||||||
case OP_LDARG:
|
case OP_LDARG:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= MAXARG) {
|
if (i0 >= MAXARG) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
return stack_push(&vm->data_stack, func->arg_regs[i0]);
|
w0 = func->arg_regs[i0];
|
||||||
|
vm_ref(w0);
|
||||||
|
return stack_push(&vm->data_stack, w0);
|
||||||
case OP_STARG:
|
case OP_STARG:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= MAXARG) {
|
if (i0 >= MAXARG) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
|
vm_unref(func->arg_regs[i0]);
|
||||||
return stack_pop(&vm->data_stack, &func->arg_regs[i0]);
|
return stack_pop(&vm->data_stack, &func->arg_regs[i0]);
|
||||||
case OP_LDG:
|
case OP_LDG:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= unit->global_pool_size) {
|
if (i0 >= unit->global_pool_size) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
return stack_push(&vm->data_stack, unit->global_pool[i0]);
|
w0 = unit->global_pool[i0];
|
||||||
|
vm_ref(w0);
|
||||||
|
return stack_push(&vm->data_stack, w0);
|
||||||
case OP_STG:
|
case OP_STG:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= unit->global_pool_size) {
|
if (i0 >= unit->global_pool_size) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
|
vm_unref(unit->global_pool[i0]);
|
||||||
return stack_pop(&vm->data_stack, &unit->global_pool[i0]);
|
return stack_pop(&vm->data_stack, &unit->global_pool[i0]);
|
||||||
case OP_LDF:
|
case OP_LDF:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= unit->functions.size) {
|
if (i0 >= unit->functions.size) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
return vm_push_ref(vm, vm_func(vm->lp, i0));
|
v0 = vm_func(vm->lp, i0);
|
||||||
|
vm_value_ref(v0);
|
||||||
|
return vm_push_ref(vm, v0);
|
||||||
case OP_STL:
|
case OP_STL:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= func->local_count) {
|
if (i0 >= func->local_count) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
|
vm_unref(func->local_regs[i0]);
|
||||||
return stack_pop(&vm->data_stack, &func->local_regs[i0]);
|
return stack_pop(&vm->data_stack, &func->local_regs[i0]);
|
||||||
case OP_LDL:
|
case OP_LDL:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
if (i0 >= func->local_count) {
|
if (i0 >= func->local_count) {
|
||||||
return -ERR_RANGE;
|
return -ERR_RANGE;
|
||||||
}
|
}
|
||||||
return stack_push(&vm->data_stack, func->local_regs[i0]);
|
w0 = func->local_regs[i0];
|
||||||
|
vm_ref(w0);
|
||||||
|
return stack_push(&vm->data_stack, w0);
|
||||||
//
|
//
|
||||||
case OP_ISZ:
|
case OP_ISZ:
|
||||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
return vm_push_bool(vm, null_q(w0));
|
res = vm_push_bool(vm, null_q(w0));
|
||||||
|
vm_unref(w0);
|
||||||
|
return res;
|
||||||
//
|
//
|
||||||
case OP_XCALL:
|
case OP_XCALL:
|
||||||
i0 = opcode & 0xFFFFFF;
|
i0 = opcode & 0xFFFFFF;
|
||||||
@ -327,7 +367,9 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
if (!func_q(w0)) {
|
if (!func_q(w0)) {
|
||||||
return -ERR_OPERAND_TYPE;
|
return -ERR_OPERAND_TYPE;
|
||||||
}
|
}
|
||||||
return vm_call_ref(vm, getref(w0));
|
res = vm_call_ref(vm, getref(w0));
|
||||||
|
vm_unref(w0);
|
||||||
|
return res;
|
||||||
case OP_BF:
|
case OP_BF:
|
||||||
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
|
||||||
return res;
|
return res;
|
||||||
@ -339,6 +381,7 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
}
|
}
|
||||||
vm->ip += ii0 - 1;
|
vm->ip += ii0 - 1;
|
||||||
}
|
}
|
||||||
|
vm_unref(w0);
|
||||||
return 0;
|
return 0;
|
||||||
case OP_JMP:
|
case OP_JMP:
|
||||||
ii0 = sximm(opcode & 0xFFFFFF);
|
ii0 = sximm(opcode & 0xFFFFFF);
|
||||||
@ -348,11 +391,16 @@ int vm_eval_step(struct vm_state *vm) {
|
|||||||
vm->ip += ii0 - 1;
|
vm->ip += ii0 - 1;
|
||||||
return 0;
|
return 0;
|
||||||
case OP_RET:
|
case OP_RET:
|
||||||
|
// Drop references to arguments
|
||||||
|
for (size_t i = 0; i < func->argc; ++i) {
|
||||||
|
vm_unref(func->arg_regs[i]);
|
||||||
|
}
|
||||||
return vm_pop_context(vm);
|
return vm_pop_context(vm);
|
||||||
//
|
//
|
||||||
case OP_DEBUG:
|
case OP_DEBUG:
|
||||||
return vm_eval_debug(vm, func, opcode & 0xFFFFFF);
|
return vm_eval_debug(vm, func, opcode & 0xFFFFFF);
|
||||||
default:
|
default:
|
||||||
|
fprintf(stderr, "Undefined opcode: %02x\n", opcode >> 24);
|
||||||
return -ERR_OPCODE_UNDEFINED;
|
return -ERR_OPCODE_UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
48
vm/vmval.c
48
vm/vmval.c
@ -56,14 +56,58 @@ static struct vm_value *vm_value_create(enum vm_type type) {
|
|||||||
if (!v) {
|
if (!v) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
printf("create %p\n", v);
|
||||||
v->type = type;
|
v->type = type;
|
||||||
v->refcount = 0;
|
v->refcount = 0;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_value_free(struct vm_value *v) {
|
void vm_value_free(struct vm_value *v) {
|
||||||
|
if (!v) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("free %p: ", v);
|
||||||
|
vm_print_ref(v, 0);
|
||||||
|
printf("\n");
|
||||||
assert(v->refcount == 0);
|
assert(v->refcount == 0);
|
||||||
free(v);
|
switch (v->type) {
|
||||||
|
case VT_CONS:
|
||||||
|
vm_unref(v->v_cons.fat_ar);
|
||||||
|
vm_unref(v->v_cons.fat_dr);
|
||||||
|
break;
|
||||||
|
case VT_STRING:
|
||||||
|
// TODO
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//free(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_value_ref(struct vm_value *v) {
|
||||||
|
if (!v) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("ref %p: ", v);
|
||||||
|
vm_print_ref(v, 0);
|
||||||
|
printf("\n");
|
||||||
|
++v->refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vm_value_unref(struct vm_value *v) {
|
||||||
|
if (!v) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
printf("unref %p: ", v);
|
||||||
|
vm_print_ref(v, 0);
|
||||||
|
printf("\n");
|
||||||
|
assert(v->refcount);
|
||||||
|
--v->refcount;
|
||||||
|
if (v->refcount == 0) {
|
||||||
|
vm_value_free(v);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vm_value *vm_cons(uint64_t w0, uint64_t w1) {
|
struct vm_value *vm_cons(uint64_t w0, uint64_t w1) {
|
||||||
@ -71,6 +115,8 @@ struct vm_value *vm_cons(uint64_t w0, uint64_t w1) {
|
|||||||
if (!v) {
|
if (!v) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
vm_ref(w0);
|
||||||
|
vm_ref(w1);
|
||||||
v->v_cons.fat_ar = w0;
|
v->v_cons.fat_ar = w0;
|
||||||
v->v_cons.fat_dr = w1;
|
v->v_cons.fat_dr = w1;
|
||||||
return v;
|
return v;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user