From: Ivan Maidanski Date: Tue, 31 Jan 2012 16:10:14 +0000 (+0400) Subject: Add assertions to check GC_large_free_bytes and GC_root_size values by X-Git-Tag: gc7_3alpha2~152 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f50c6cc54d81600ac2dacfac0bdbd5bcc3aedb05;p=gc Add assertions to check GC_large_free_bytes and GC_root_size values by GC_finish_collection even if GC_dump_regularly is off * allchblk.c (GC_compute_large_free_bytes): New inner function (defined only if GC_ASSERTIONS or not NO_DEBUGGING). * mark_rts.c (GC_compute_root_size): Likewise. * allchblk.c (GC_print_hblkfreelist): Call GC_compute_large_free_bytes instead of computing large_free_bytes itself (only if not USE_MUNMAP for now); remove "sz" local variable. * allchblk.c (GC_print_hblkfreelist): Refine logged messages (for total value). * mark_rts.c (GC_print_static_roots): Likewise. * include/private/gc_priv.h (GC_dump_regularly, COND_DUMP): Move definition down below GC_ASSERT one. * include/private/gc_priv.h (GC_compute_large_free_bytes, GC_compute_root_size): New function declaration (only if GC_ASSERTIONS). * include/private/gc_priv.h (COND_DUMP_CHECKS): New macro (invoke GC_ASSERT for GC_large_free_bytes and GC_root_size). * include/private/gc_priv.h (COND_DUMP): Invoke COND_DUMP_CHECKS unless GC_dump_regularly. * mark_rts.c (GC_print_static_roots): Call GC_compute_root_size instead of computing root size itself; rename "total" local variable to "size". --- diff --git a/allchblk.c b/allchblk.c index f6ea681e..f8cf2c2c 100644 --- a/allchblk.c +++ b/allchblk.c @@ -106,13 +106,34 @@ STATIC int GC_hblk_fl_from_blocks(word blocks_needed) # define IS_MAPPED(hhdr) 1 # endif /* USE_MUNMAP */ +#if (!defined(NO_DEBUGGING) && !defined(USE_MUNMAP)) || defined(GC_ASSERTIONS) + /* Should return the same value as GC_large_free_bytes. */ + GC_INNER word GC_compute_large_free_bytes(void) + { +# ifdef USE_MUNMAP + return GC_large_free_bytes; /* FIXME: unimplemented */ +# else + struct hblk * h; + hdr * hhdr; + word total_free = 0; + unsigned i; + + for (i = 0; i <= N_HBLK_FLS; ++i) { + for (h = GC_hblkfreelist[i]; h != 0; h = hhdr->hb_next) { + hhdr = HDR(h); + total_free += hhdr->hb_sz; + } + } + return total_free; +# endif + } +#endif /* !NO_DEBUGGING || GC_ASSERTIONS */ + # if !defined(NO_DEBUGGING) void GC_print_hblkfreelist(void) { struct hblk * h; - word total_free = 0; hdr * hhdr; - word sz; unsigned i; for (i = 0; i <= N_HBLK_FLS; ++i) { @@ -125,23 +146,25 @@ void GC_print_hblkfreelist(void) # endif while (h != 0) { hhdr = HDR(h); - sz = hhdr -> hb_sz; - total_free += sz; GC_printf("\t%p size %lu %s black listed\n", - (void *)h, (unsigned long)sz, + (void *)h, (unsigned long) hhdr -> hb_sz, GC_is_black_listed(h, HBLKSIZE) != 0 ? "start" : GC_is_black_listed(h, hhdr -> hb_sz) != 0 ? "partially" : "not"); h = hhdr -> hb_next; } } + GC_printf("GC_large_free_bytes: %lu\n", + (unsigned long)GC_large_free_bytes); + # ifndef USE_MUNMAP - if (total_free != GC_large_free_bytes) { - GC_printf("GC_large_free_bytes = %lu (INCONSISTENT!!)\n", - (unsigned long) GC_large_free_bytes); + { + word total; + if ((total = GC_compute_large_free_bytes()) != GC_large_free_bytes) + GC_err_printf("GC_large_free_bytes INCONSISTENT!! Should be: %lu\n", + (unsigned long)total); } # endif - GC_printf("Total of %lu bytes on free list\n", (unsigned long)total_free); } /* Return the free list index on which the block described by the header */ diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index e98e9d2d..09584afc 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -1873,14 +1873,6 @@ GC_EXTERN GC_bool GC_have_errors; /* We saw a smashed or leaked object. */ #endif #define VERBOSE 2 -#ifndef NO_DEBUGGING - GC_EXTERN GC_bool GC_dump_regularly; - /* Generate regular debugging dumps. */ -# define COND_DUMP if (EXPECT(GC_dump_regularly, FALSE)) GC_dump() -#else -# define COND_DUMP /* empty */ -#endif - #ifdef KEEP_BACK_PTRS GC_EXTERN long GC_backtraces; GC_INNER void GC_generate_random_backtrace_no_gc(void); @@ -2179,14 +2171,16 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str, #endif /* NEED_PROC_MAPS */ #ifdef GC_ASSERTIONS -# define GC_ASSERT(expr) \ +# define GC_ASSERT(expr) \ if (!(expr)) { \ GC_err_printf("Assertion failure: %s:%d\n", \ __FILE__, __LINE__); \ ABORT("assertion failure"); \ } + GC_INNER word GC_compute_large_free_bytes(void); + GC_INNER word GC_compute_root_size(void); #else -# define GC_ASSERT(expr) +# define GC_ASSERT(expr) #endif /* Check a compile time assertion at compile time. The error */ @@ -2200,6 +2194,19 @@ GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *str, # define GC_STATIC_ASSERT(expr) (void)sizeof(char[(expr)? 1 : -1]) #endif +#define COND_DUMP_CHECKS { \ + GC_ASSERT(GC_compute_large_free_bytes() == GC_large_free_bytes); \ + GC_ASSERT(GC_compute_root_size() == GC_root_size); } + +#ifndef NO_DEBUGGING + GC_EXTERN GC_bool GC_dump_regularly; + /* Generate regular debugging dumps. */ +# define COND_DUMP { if (EXPECT(GC_dump_regularly, FALSE)) GC_dump(); \ + else COND_DUMP_CHECKS; } +#else +# define COND_DUMP COND_DUMP_CHECKS +#endif + #if defined(PARALLEL_MARK) /* We need additional synchronization facilities from the thread */ /* support. We believe these are less performance critical */ diff --git a/mark_rts.c b/mark_rts.c index 348d6143..8bd9ddc2 100644 --- a/mark_rts.c +++ b/mark_rts.c @@ -39,25 +39,37 @@ int GC_no_dls = 0; /* Register dynamic library data segments. */ static int n_root_sets = 0; /* GC_static_roots[0..n_root_sets) contains the valid root sets. */ +#if !defined(NO_DEBUGGING) || defined(GC_ASSERTIONS) + /* Should return the same value as GC_root_size. */ + GC_INNER word GC_compute_root_size(void) + { + int i; + word size = 0; + + for (i = 0; i < n_root_sets; i++) { + size += GC_static_roots[i].r_end - GC_static_roots[i].r_start; + } + return size; + } +#endif /* !NO_DEBUGGING || GC_ASSERTIONS */ + #if !defined(NO_DEBUGGING) /* For debugging: */ void GC_print_static_roots(void) { int i; - size_t total = 0; + word size; for (i = 0; i < n_root_sets; i++) { GC_printf("From %p to %p%s\n", - GC_static_roots[i].r_start, - GC_static_roots[i].r_end, + GC_static_roots[i].r_start, GC_static_roots[i].r_end, GC_static_roots[i].r_tmp ? " (temporary)" : ""); - total += GC_static_roots[i].r_end - GC_static_roots[i].r_start; - } - GC_printf("Total size: %lu\n", (unsigned long) total); - if (GC_root_size != total) { - GC_err_printf("GC_root_size incorrect: %lu!!\n", - (unsigned long) GC_root_size); } + GC_printf("GC_root_size: %lu\n", (unsigned long)GC_root_size); + + if ((size = GC_compute_root_size()) != GC_root_size) + GC_err_printf("GC_root_size incorrect!! Should be: %lu\n", + (unsigned long)size); } #endif /* !NO_DEBUGGING */