From fe3a2b33165ee0d7765ba4e838e9c4875d8fb195 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 2 May 2023 20:59:49 -0700 Subject: 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. --- gc.c | 40 +++++++++++++++------------------------- gc.h | 2 +- lib.c | 2 +- lib.h | 4 ++++ 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 -- cgit v1.2.3