diff options
Diffstat (limited to 'gc/checksums.c')
-rw-r--r-- | gc/checksums.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/gc/checksums.c b/gc/checksums.c new file mode 100644 index 0000000..212655f --- /dev/null +++ b/gc/checksums.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 1992-1994 by Xerox Corporation. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ +/* Boehm, March 29, 1995 12:51 pm PST */ +# ifdef CHECKSUMS + +# include "gc_priv.h" + +/* This is debugging code intended to verify the results of dirty bit */ +/* computations. Works only in a single threaded environment. */ +/* We assume that stubborn objects are changed only when they are */ +/* enabled for writing. (Certain kinds of writing are actually */ +/* safe under other conditions.) */ +# define NSUMS 2000 + +# define OFFSET 0x10000 + +typedef struct { + GC_bool new_valid; + word old_sum; + word new_sum; + struct hblk * block; /* Block to which this refers + OFFSET */ + /* to hide it from colector. */ +} page_entry; + +page_entry GC_sums [NSUMS]; + +word GC_checksum(h) +struct hblk *h; +{ + register word *p = (word *)h; + register word *lim = (word *)(h+1); + register word result = 0; + + while (p < lim) { + result += *p++; + } + return(result | 0x80000000 /* doesn't look like pointer */); +} + +# ifdef STUBBORN_ALLOC +/* Check whether a stubborn object from the given block appears on */ +/* the appropriate free list. */ +GC_bool GC_on_free_list(h) +struct hblk *h; +{ + register hdr * hhdr = HDR(h); + register int sz = hhdr -> hb_sz; + ptr_t p; + + if (sz > MAXOBJSZ) return(FALSE); + for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) { + if (HBLKPTR(p) == h) return(TRUE); + } + return(FALSE); +} +# endif + +int GC_n_dirty_errors; +int GC_n_changed_errors; +int GC_n_clean; +int GC_n_dirty; + +void GC_update_check_page(h, index) +struct hblk *h; +int index; +{ + page_entry *pe = GC_sums + index; + register hdr * hhdr = HDR(h); + + if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed"); + pe -> old_sum = pe -> new_sum; + pe -> new_sum = GC_checksum(h); +# ifndef MSWIN32 + if (pe -> new_sum != 0 && !GC_page_was_ever_dirty(h)) { + GC_printf1("GC_page_was_ever_dirty(0x%lx) is wrong\n", + (unsigned long)h); + } +# endif + if (GC_page_was_dirty(h)) { + GC_n_dirty++; + } else { + GC_n_clean++; + } + if (pe -> new_valid && pe -> old_sum != pe -> new_sum) { + if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) { + /* Set breakpoint here */GC_n_dirty_errors++; + } +# ifdef STUBBORN_ALLOC + if (!IS_FORWARDING_ADDR_OR_NIL(hhdr) + && hhdr -> hb_map != GC_invalid_map + && hhdr -> hb_obj_kind == STUBBORN + && !GC_page_was_changed(h) + && !GC_on_free_list(h)) { + /* if GC_on_free_list(h) then reclaim may have touched it */ + /* without any allocations taking place. */ + /* Set breakpoint here */GC_n_changed_errors++; + } +# endif + } + pe -> new_valid = TRUE; + pe -> block = h + OFFSET; +} + +word GC_bytes_in_used_blocks; + +void GC_add_block(h, dummy) +struct hblk *h; +word dummy; +{ + register hdr * hhdr = HDR(h); + register bytes = WORDS_TO_BYTES(hhdr -> hb_sz); + + bytes += HDR_BYTES + HBLKSIZE-1; + bytes &= ~(HBLKSIZE-1); + GC_bytes_in_used_blocks += bytes; +} + +void GC_check_blocks() +{ + word bytes_in_free_blocks = 0; + struct hblk * h = GC_hblkfreelist; + hdr * hhdr = HDR(h); + word sz; + + GC_bytes_in_used_blocks = 0; + GC_apply_to_all_blocks(GC_add_block, (word)0); + while (h != 0) { + sz = hhdr -> hb_sz; + bytes_in_free_blocks += sz; + h = hhdr -> hb_next; + hhdr = HDR(h); + } + GC_printf2("GC_bytes_in_used_blocks = %ld, bytes_in_free_blocks = %ld ", + GC_bytes_in_used_blocks, bytes_in_free_blocks); + GC_printf1("GC_heapsize = %ld\n", GC_heapsize); + if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) { + GC_printf0("LOST SOME BLOCKS!!\n"); + } +} + +/* Should be called immediately after GC_read_dirty and GC_read_changed. */ +void GC_check_dirty() +{ + register int index; + register unsigned i; + register struct hblk *h; + register ptr_t start; + + GC_check_blocks(); + + GC_n_dirty_errors = 0; + GC_n_changed_errors = 0; + GC_n_clean = 0; + GC_n_dirty = 0; + + index = 0; + for (i = 0; i < GC_n_heap_sects; i++) { + start = GC_heap_sects[i].hs_start; + for (h = (struct hblk *)start; + h < (struct hblk *)(start + GC_heap_sects[i].hs_bytes); + h++) { + GC_update_check_page(h, index); + index++; + if (index >= NSUMS) goto out; + } + } +out: + GC_printf2("Checked %lu clean and %lu dirty pages\n", + (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty); + if (GC_n_dirty_errors > 0) { + GC_printf1("Found %lu dirty bit errors\n", + (unsigned long)GC_n_dirty_errors); + } + if (GC_n_changed_errors > 0) { + GC_printf1("Found %lu changed bit errors\n", + (unsigned long)GC_n_changed_errors); + GC_printf0("These may be benign (provoked by nonpointer changes)\n"); +# ifdef THREADS + GC_printf0( + "Also expect 1 per thread currently allocating a stubborn obj.\n"); +# endif + } +} + +# else + +extern int GC_quiet; + /* ANSI C doesn't allow translation units to be empty. */ + /* So we guarantee this one is nonempty. */ + +# endif /* CHECKSUMS */ |