]> granicus.if.org Git - gc/commitdiff
Move finalizer closure to the end of objects.
authorPetter Urkedal <paurkedal@gmail.com>
Mon, 16 Jan 2012 20:51:35 +0000 (04:51 +0800)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 18 Jan 2012 06:47:24 +0000 (14:47 +0800)
* 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.

fnlz_mlc.c
tests/disclaim_test.c

index 4c7a4501ab53af10e455455c2078a9aeea968650..e79605d7a5deafa0896b54aead3f44df1a72e33f 100644 (file)
@@ -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 */
 
index 8e71828c76240ef720982975fe9f2755cb0746bf..bbd572eebb0643f6935bc73662f2bb384bfaf82c 100644 (file)
 
 #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) {