From: Petter Urkedal Date: Mon, 16 Jan 2012 20:51:35 +0000 (+0800) Subject: Move finalizer closure to the end of objects. X-Git-Tag: gc7_3alpha2~213 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=63fd11df9;p=gc Move finalizer closure to the end of objects. * fnlz_mlc.c: Move finalizer closure for finalized object kinds to the end of objects. This way, we don't require all interior pointers, and GC_base returns the expected address. * tests/disclaim_test.c: Improve test coverage. --- diff --git a/fnlz_mlc.c b/fnlz_mlc.c index 4c7a4501..e79605d7 100644 --- a/fnlz_mlc.c +++ b/fnlz_mlc.c @@ -29,8 +29,11 @@ STATIC int GC_finalized_kind = 0; STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj, void *cd GC_ATTR_UNUSED) { - struct GC_finalizer_closure *fc = *(void **)obj; - if (((word)fc & 1) != 0) { + void **fc_addr; + struct GC_finalizer_closure *fc; + fc_addr = &((void **)obj)[GC_size(obj) / sizeof(void *) - 1]; + fc = *fc_addr; + if (fc != NULL) { /* [1] The disclaim function may be passed fragments from the */ /* free-list, on which it should not run finalization. */ /* To recognize this case, we use the fact that the first word */ @@ -39,8 +42,8 @@ STATIC int GC_CALLBACK GC_finalized_disclaim(void *obj, /* which does not use the first word for storing finalization */ /* info, GC_reclaim_with_finalization must be extended to clear */ /* fragments so that the assumption holds for the selected word. */ - fc = (void *)((word)fc & ~(word)1); - (*fc->proc)((void **)obj + 1, fc->cd); + (*fc->proc)(obj, fc->cd); + *fc_addr = NULL; } return 0; } @@ -95,11 +98,12 @@ GC_API void GC_CALL GC_init_finalized_malloc(void) GC_bytes_allocd += GRANULES_TO_BYTES(lg); UNLOCK(); } + ((void **)op)[GRANULES_TO_WORDS(lg) - 1] = fclos; } else { op = GC_generic_malloc((word)lb, GC_finalized_kind); + ((void **)op)[GC_size(op) / sizeof(void *) - 1] = fclos; } - *(void **)op = (ptr_t)fclos + 1; /* See [1] */ - return GC_clear_stack(op + sizeof(void *)); + return GC_clear_stack(op); } #ifdef THREAD_LOCAL_ALLOC @@ -143,9 +147,10 @@ GC_API void GC_CALL GC_init_finalized_malloc(void) next = obj_link(my_entry); result = (void *)my_entry; *my_fl = next; - *(void **)result = (ptr_t)fclos + 1; + obj_link(result) = 0; + ((void **)result)[GRANULES_TO_WORDS(lg) - 1] = fclos; PREFETCH_FOR_WRITE(next); - return (void **)result + 1; + return result; } #endif /* THREAD_LOCAL_ALLOC */ diff --git a/tests/disclaim_test.c b/tests/disclaim_test.c index 8e71828c..bbd572ee 100644 --- a/tests/disclaim_test.c +++ b/tests/disclaim_test.c @@ -23,6 +23,35 @@ #include "gc_disclaim.h" +int memeq(void *s, int c, size_t len) +{ + while (len--) { + if (*(char *)s != c) + return 0; + s = (char *)s + 1; + } + return 1; +} + +void GC_CALLBACK misc_sizes_dct(void *obj, void *cd) +{ + size_t size = (size_t)1 << *(unsigned char *)obj; + assert(memeq((char *)obj + 1, 0x56, size - 1)); +} + +void +test_misc_sizes() +{ + static struct GC_finalizer_closure fc = { misc_sizes_dct, NULL }; + int i; + for (i = 1; i <= 20; ++i) { /* Up to 1 MiB. */ + void *p = GC_finalized_malloc((size_t)1 << i, &fc); + assert(memeq(p, 0, (size_t)1 << i)); + memset(p, 0x56, (size_t)1 << i); + *(unsigned char *)p = i; + } +} + typedef struct pair_s *pair_t; struct pair_s { @@ -65,6 +94,7 @@ pair_new(pair_t car, pair_t cdr) static struct GC_finalizer_closure fc = { pair_dct, NULL }; p = GC_finalized_malloc(sizeof(struct pair_s), &fc); + assert(memeq(p, 0, sizeof(struct pair_s))); p->is_valid = 1; p->checksum = 782 + (car? car->checksum : 0) + (cdr? cdr->checksum : 0); p->car = car; @@ -140,9 +170,12 @@ int main(void) int i; #endif + GC_set_all_interior_pointers(0); /* for a stricter test */ GC_INIT(); GC_init_finalized_malloc(); + test_misc_sizes(); + #if THREAD_CNT > 1 printf("Threaded disclaim test.\n"); for (i = 0; i < THREAD_CNT; ++i) {