summaryrefslogtreecommitdiffstats
path: root/vm.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-06-21 06:29:32 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-06-21 06:29:32 -0700
commit1439785d5659936d0c22273a85a7c6594429649f (patch)
tree745ea327d90de07412432d16864c813cec3c8488 /vm.c
parent793a8bd3995c0ecc272e7dce16c9d7c6ec85e9bb (diff)
downloadtxr-1439785d5659936d0c22273a85a7c6594429649f.tar.gz
txr-1439785d5659936d0c22273a85a7c6594429649f.tar.bz2
txr-1439785d5659936d0c22273a85a7c6594429649f.zip
vm: release cached bindings that become unbound.
When a function binding is removed using fmakunbound, virtual machine descriptions hang on to the previously cached binding in the ftab. When the symbol is newly bound, virtual machine descriptions keep pointing to the old function. To solve this, we put the vm_desc structures into a global list and provide a function that fmakunbound calls to scrub all the VM descriptors of that binding. * eval.c (makunbound, fmakunbound): Call new vm_invalidate_binding function. * vm.c (struct vm_desc_links): New structure. (struct vm_desc): New member lnk, with links. (vmd_list): New static variable: circular list of all VM descriptors. (vm_make_desc): Insert new VM descriptor into list. (vm_desc_destroy): Remove VM descriptor from list. (vm_invalidate_binding): New function. * vm.h (vm_invalidate_binding): Declared.
Diffstat (limited to 'vm.c')
-rw-r--r--vm.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/vm.c b/vm.c
index a679cbb3..6460bac8 100644
--- a/vm.c
+++ b/vm.c
@@ -53,7 +53,12 @@ typedef u32_t vm_word_t;
#define zalloca(size) memset(alloca(size), 0, size)
+struct vm_desc_links {
+ struct vm_desc *next, *prev;
+};
+
struct vm_desc {
+ struct vm_desc_links lnk;
val self;
int nlvl;
int nreg;
@@ -100,6 +105,10 @@ static_forward(struct cobj_ops vm_desc_ops);
static_forward(struct cobj_ops vm_closure_ops);
+static struct vm_desc_links vmd_list = {
+ coerce(struct vm_desc *, &vmd_list), coerce(struct vm_desc *, &vmd_list)
+};
+
static struct vm_desc *vm_desc_struct(val obj)
{
return coerce(struct vm_desc *, cobj_handle(obj, vm_desc_s));
@@ -125,6 +134,7 @@ val vm_make_desc(val nlevels, val nregs, val bytecode,
cnum ftsz = c_num(length_vec(symvec));
loc data_loc = if3(dvl != zero, vecref_l(datavec, zero), nulloc);
struct vm_desc *vd = coerce(struct vm_desc *, chk_malloc(sizeof *vd));
+ struct vm_desc *vtail = vmd_list.prev, *vnull = vtail->lnk.next;
struct vm_ftent *stab = if3(ftsz != 0,
coerce(struct vm_ftent *,
chk_calloc(ftsz, sizeof *stab)), 0);
@@ -152,6 +162,11 @@ val vm_make_desc(val nlevels, val nregs, val bytecode,
vd->symvec = symvec;
vd->self = desc;
+ vd->lnk.prev = vtail;
+ vd->lnk.next = vnull;
+ vnull->lnk.prev = vd;
+ vtail->lnk.next = vd;
+
return desc;
}
}
@@ -189,6 +204,10 @@ static val vm_desc_symvec(val desc)
static void vm_desc_destroy(val obj)
{
struct vm_desc *vd = coerce(struct vm_desc *, obj->co.handle);
+ struct vm_desc *vn = vd->lnk.next, *vp = vd->lnk.prev;
+ vp->lnk.next = vn;
+ vn->lnk.prev = vp;
+ vd->lnk.prev = vd->lnk.next = 0;
free(vd->stab);
free(vd);
}
@@ -1081,6 +1100,22 @@ static val vm_closure_entry(val closure)
return unum(vc->ip);
}
+void vm_invalidate_binding(val sym)
+{
+ struct vm_desc *vd = vmd_list.next, *vnull = vd->lnk.prev;
+
+ for (; vd != vnull; vd = vd->lnk.next) {
+ cnum i;
+ for (i = 0; i < vd->ftsz; i++) {
+ if (vecref(vd->symvec, num_fast(i)) == sym) {
+ struct vm_ftent *sti = &vd->stab[i];
+ sti->fb = nil;
+ sti->fbloc = nulloc;
+ }
+ }
+ }
+}
+
static_def(struct cobj_ops vm_desc_ops =
cobj_ops_init(eq,
cobj_print_op,