summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-05-02 20:59:49 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-05-02 20:59:49 -0700
commitfe3a2b33165ee0d7765ba4e838e9c4875d8fb195 (patch)
tree096c6400abe87d25793c4c8a1063fe78ce80f1f8
parent005b8909d995b699130ab97269cabab2bcf33a75 (diff)
downloadtxr-fe3a2b33165ee0d7765ba4e838e9c4875d8fb195.tar.gz
txr-fe3a2b33165ee0d7765ba4e838e9c4875d8fb195.tar.bz2
txr-fe3a2b33165ee0d7765ba4e838e9c4875d8fb195.zip
gc: use single allocation for prot_array.
* gc.c (prot_array): Add self pointer; arr member becomes flexible array. (prot_array_mark): We now check the handle itself for null, because the whole thing is freed. (prot_array_free): Function removed. (prot_array_ops): Wire cobj_destroy_free_op in place of prot_array_free. This fixes a memory leak because prot_array_free was not freeing the handle, only the array. (gc_prot_array_alloc): Fix to allocate everything in one swoop and store the self-pointer in the named member rather than arr[-1]. The self argument is not required; we drop it. The size argument cannot be anywhere near INT_PTR_MAX, because such an array wouldn't fit into virtual memory, so it is always safe to add a small value to the size. (prot_array_free): Obtain the self-pointer, and free the handle, replacing it with a null pointer. * gc.h (gc_prot_array_alloc): Declaration updated. * lib.c (ssort_vec): Don't pass self to gc_prot_array_alloc. * lib.h (container): New macro.
-rw-r--r--gc.c40
-rw-r--r--gc.h2
-rw-r--r--lib.c2
-rw-r--r--lib.h4
4 files changed, 21 insertions, 27 deletions
diff --git a/gc.c b/gc.c
index 2c61c914..eafc354c 100644
--- a/gc.c
+++ b/gc.c
@@ -138,7 +138,8 @@ val break_obj;
struct prot_array {
cnum size;
- val *arr;
+ val self;
+ val arr[FLEX_ARRAY];
};
struct cobj_class *prot_array_cls;
@@ -1260,48 +1261,37 @@ void gc_stack_overflow(void)
static void prot_array_mark(val obj)
{
struct prot_array *pa = coerce(struct prot_array *, obj->co.handle);
- cnum i;
- if (pa->arr)
+ if (pa) {
+ cnum i;
for (i = 0; i < pa->size; i++)
gc_mark(pa->arr[i]);
-}
-
-static void prot_array_free(val obj)
-{
- struct prot_array *pa = coerce(struct prot_array *, obj->co.handle);
-
- if (pa->arr) {
- free(pa->arr - 1);
- pa->arr = 0;
}
}
static struct cobj_ops prot_array_ops = cobj_ops_init(eq,
cobj_print_op,
- prot_array_free,
+ cobj_destroy_free_op,
prot_array_mark,
cobj_eq_hash_op);
-val *gc_prot_array_alloc(cnum size, val self)
+val *gc_prot_array_alloc(cnum size)
{
struct prot_array *pa = convert(struct prot_array *,
- chk_malloc(sizeof *pa));
-
- if (size >= INT_PTR_MAX)
- uw_throwf(error_s, lit("~s: array too large"), self, nao);
-
+ chk_calloc(offsetof(struct prot_array, arr) +
+ size * sizeof(val), 1));
pa->size = size;
- pa->arr = convert(val *,
- chk_calloc(sizeof *pa->arr, (size + 1))) + 1;
-
- pa->arr[-1] = cobj(convert(mem_t *, pa), prot_array_cls, &prot_array_ops);
+ pa->self = cobj(convert(mem_t *, pa), prot_array_cls, &prot_array_ops);
return pa->arr;
}
void gc_prot_array_free(val *arr)
{
- if (arr)
- prot_array_free(arr[-1]);
+ if (arr) {
+ struct prot_array *pa = container(arr, struct prot_array, arr);
+ val obj = pa->self;
+ obj->co.handle = 0;
+ free(pa);
+ }
}
diff --git a/gc.h b/gc.h
index 58d057db..e89e695a 100644
--- a/gc.h
+++ b/gc.h
@@ -87,5 +87,5 @@ INLINE void gc_stack_check(void)
gc_stack_overflow();
}
-val *gc_prot_array_alloc(cnum size, val self);
+val *gc_prot_array_alloc(cnum size);
void gc_prot_array_free(val *);
diff --git a/lib.c b/lib.c
index bea09ea3..2e9de482 100644
--- a/lib.c
+++ b/lib.c
@@ -10922,7 +10922,7 @@ static void mergesort(val vec, val lessfun, val keyfun, cnum from, cnum to,
static void ssort_vec(val vec, val lessfun, val keyfun, val self)
{
cnum len = c_fixnum(length(vec), self);
- val *aux = gc_prot_array_alloc(len, self);
+ val *aux = gc_prot_array_alloc(len);
mergesort(vec, lessfun, keyfun, 0, len, aux);
gc_prot_array_free(aux);
}
diff --git a/lib.h b/lib.h
index 9e71b5f9..dc90aa23 100644
--- a/lib.h
+++ b/lib.h
@@ -46,6 +46,10 @@ typedef double_uintptr_t dbl_ucnum;
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif
+#define container(PTR, TYPE, MEMB) \
+ convert(TYPE *, \
+ convert(mem_t *, (PTR)) - offsetof(TYPE, MEMB))
+
#if __STDC_VERSION__ >= 199901L
#define FLEX_ARRAY
#else