diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2018-06-21 06:29:32 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2018-06-21 06:29:32 -0700 |
commit | 1439785d5659936d0c22273a85a7c6594429649f (patch) | |
tree | 745ea327d90de07412432d16864c813cec3c8488 /vm.c | |
parent | 793a8bd3995c0ecc272e7dce16c9d7c6ec85e9bb (diff) | |
download | txr-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.c | 35 |
1 files changed, 35 insertions, 0 deletions
@@ -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, |