diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-12-31 06:53:02 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-12-31 06:53:02 -0800 |
commit | 7b508930b78766c14932847512824282aae59ec0 (patch) | |
tree | 123a3b75e0e1c36457b6f8381a78916a589f785c /gc.c | |
parent | ee8addba7324e8bd66f107360051a6f200203dc5 (diff) | |
download | txr-7b508930b78766c14932847512824282aae59ec0.tar.gz txr-7b508930b78766c14932847512824282aae59ec0.tar.bz2 txr-7b508930b78766c14932847512824282aae59ec0.zip |
gc: add finalization count to objects.
With the finalization count, we don't have to scan the
freshobj array for duplicates when calling finalizers.
However, the limited range of the counter limits how many
times we can register a finalizer against an object.
* gc.c (make_obj): Reset the new fincount field to zero
for a newly minted object.
(call_finalizers_impl): Decrement the fincount for
each object. Only run the freshobj-related logic when
the count hits zero.
(gc_finalize): Bump the fincount of a registered object. If
the counter overflows, throw an exception.
* lib.h (obj_common): Add new field fincount for the
finalization count.
* tree.c (tr_rebuild): Fix up dummy object initializer
to accommodate the new member.
* txr.1: Document that there is a limit on the number
of times an object can be registered for finalization.
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 34 |
1 files changed, 18 insertions, 16 deletions
@@ -220,6 +220,7 @@ val make_obj(void) #endif #if CONFIG_GEN_GC ret->t.gen = 0; + ret->t.fincount = 0; if (!full_gc) freshobj[freshobj_idx++] = ret; #endif @@ -783,24 +784,14 @@ static val call_finalizers_impl(val ctx, while (found) { struct fin_reg *next = found->next; - int dup, i, freshobj_idx_start = freshobj_idx; val obj = found->obj; funcall1(found->fun, obj); #if CONFIG_GEN_GC - if (inprogress && obj->t.gen == 0) { - for (dup = 0, i = freshobj_idx_start; i < freshobj_idx; i++) { - if (freshobj[i] == obj) { - dup = 1; - break; - } - } - - if (!dup) { - if (freshobj_idx < FRESHOBJ_VEC_SIZE) { - freshobj[freshobj_idx++] = obj; - } else { - full_gc = 1; - } + if (--obj->t.fincount == 0 && inprogress && obj->t.gen == 0) { + if (freshobj_idx < FRESHOBJ_VEC_SIZE) { + freshobj[freshobj_idx++] = obj; + } else { + full_gc = 1; } } #endif @@ -990,7 +981,8 @@ static val gc_wrap(val full) val gc_finalize(val obj, val fun, val rev_order_p) { - type_check(lit("gc-finalize"), fun, FUN); + val self = lit("gc-finalize"); + type_check(self, fun, FUN); rev_order_p = default_null_arg(rev_order_p); @@ -1000,6 +992,16 @@ val gc_finalize(val obj, val fun, val rev_order_p) f->fun = fun; f->reachable = 0; +#if CONFIG_GEN_GC + if (++obj->t.fincount == 0) { + obj->t.fincount--; + free(f); + uw_throwf(error_s, + lit("~a: too many finalizations registered against object ~s"), + self, obj, nao); + } +#endif + if (rev_order_p) { if (!final_list) final_tail = &f->next; |