Synopsis - Cross-Reference
File: /src/Synopsis/gc/checksums.c1/* 2 * Copyright (c) 1992-1994 by Xerox Corporation. All rights reserved. 3 * 4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED 5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. 6 * 7 * Permission is hereby granted to use or copy this program 8 * for any purpose, provided the above notices are retained on all copies. 9 * Permission to modify the code and to distribute modified code is granted, 10 * provided the above notices are retained, and a notice that the code was 11 * modified is included with the above copyright notice. 12 */ 13/* Boehm, March 29, 1995 12:51 pm PST */ 14# ifdef CHECKSUMS 15 16# include "private/gc_priv.h" 17 18/* This is debugging code intended to verify the results of dirty bit */ 19/* computations. Works only in a single threaded environment. */ 20/* We assume that stubborn objects are changed only when they are */ 21/* enabled for writing. (Certain kinds of writing are actually */ 22/* safe under other conditions.) */ 23# define NSUMS 10000 24 25# define OFFSET 0x10000 26 27typedef struct { 28 GC_bool new_valid; 29 word old_sum; 30 word new_sum; 31 struct hblk * block; /* Block to which this refers + OFFSET */ 32 /* to hide it from collector. */ 33} page_entry; 34 35page_entry GC_sums [NSUMS]; 36 37word GC_checksum(h) 38struct hblk *h; 39{ 40 register word *p = (word *)h; 41 register word *lim = (word *)(h+1); 42 register word result = 0; 43 44 while (p < lim) { 45 result += *p++; 46 } 47 return(result | 0x80000000 /* doesn't look like pointer */); 48} 49 50# ifdef STUBBORN_ALLOC 51/* Check whether a stubborn object from the given block appears on */ 52/* the appropriate free list. */ 53GC_bool GC_on_free_list(struct hblk *h) 54struct hblk *h; 55{ 56 hdr * hhdr = HDR(h); 57 int sz = BYTES_TO_WORDS(hhdr -> hb_sz); 58 ptr_t p; 59 60 if (sz > MAXOBJWORDS) return(FALSE); 61 for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) { 62 if (HBLKPTR(p) == h) return(TRUE); 63 } 64 return(FALSE); 65} 66# endif 67 68int GC_n_dirty_errors; 69int GC_n_changed_errors; 70int GC_n_clean; 71int GC_n_dirty; 72 73void GC_update_check_page(struct hblk *h, int index) 74{ 75 page_entry *pe = GC_sums + index; 76 register hdr * hhdr = HDR(h); 77 struct hblk *b; 78 79 if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed"); 80 pe -> old_sum = pe -> new_sum; 81 pe -> new_sum = GC_checksum(h); 82# if !defined(MSWIN32) && !defined(MSWINCE) 83 if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) { 84 GC_printf("GC_page_was_ever_dirty(%p) is wrong\n", h); 85 } 86# endif 87 if (GC_page_was_dirty(h)) { 88 GC_n_dirty++; 89 } else { 90 GC_n_clean++; 91 } 92 b = h; 93 while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) { 94 b -= (word)hhdr; 95 hhdr = HDR(b); 96 } 97 if (pe -> new_valid 98 && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */ 99 && pe -> old_sum != pe -> new_sum) { 100 if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) { 101 /* Set breakpoint here */GC_n_dirty_errors++; 102 } 103# ifdef STUBBORN_ALLOC 104 if (!HBLK_IS_FREE(hhdr) 105 && hhdr -> hb_obj_kind == STUBBORN 106 && !GC_page_was_changed(h) 107 && !GC_on_free_list(h)) { 108 /* if GC_on_free_list(h) then reclaim may have touched it */ 109 /* without any allocations taking place. */ 110 /* Set breakpoint here */GC_n_changed_errors++; 111 } 112# endif 113 } 114 pe -> new_valid = TRUE; 115 pe -> block = h + OFFSET; 116} 117 118unsigned long GC_bytes_in_used_blocks; 119 120void GC_add_block(h, dummy) 121struct hblk *h; 122word dummy; 123{ 124 hdr * hhdr = HDR(h); 125 bytes = hhdr -> hb_sz; 126 127 bytes += HBLKSIZE-1; 128 bytes &= ~(HBLKSIZE-1); 129 GC_bytes_in_used_blocks += bytes; 130} 131 132void GC_check_blocks() 133{ 134 unsigned long bytes_in_free_blocks = GC_large_free_bytes; 135 136 GC_bytes_in_used_blocks = 0; 137 GC_apply_to_all_blocks(GC_add_block, (word)0); 138 GC_printf("GC_bytes_in_used_blocks = %lu, bytes_in_free_blocks = %lu ", 139 GC_bytes_in_used_blocks, bytes_in_free_blocks); 140 GC_printf("GC_heapsize = %lu\n", (unsigned long)GC_heapsize); 141 if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) { 142 GC_printf("LOST SOME BLOCKS!!\n"); 143 } 144} 145 146/* Should be called immediately after GC_read_dirty and GC_read_changed. */ 147void GC_check_dirty() 148{ 149 register int index; 150 register unsigned i; 151 register struct hblk *h; 152 register ptr_t start; 153 154 GC_check_blocks(); 155 156 GC_n_dirty_errors = 0; 157 GC_n_changed_errors = 0; 158 GC_n_clean = 0; 159 GC_n_dirty = 0; 160 161 index = 0; 162 for (i = 0; i < GC_n_heap_sects; i++) { 163 start = GC_heap_sects[i].hs_start; 164 for (h = (struct hblk *)start; 165 h < (struct hblk *)(start + GC_heap_sects[i].hs_bytes); 166 h++) { 167 GC_update_check_page(h, index); 168 index++; 169 if (index >= NSUMS) goto out; 170 } 171 } 172out: 173 GC_printf("Checked %lu clean and %lu dirty pages\n", 174 (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty); 175 if (GC_n_dirty_errors > 0) { 176 GC_printf("Found %lu dirty bit errors\n", 177 (unsigned long)GC_n_dirty_errors); 178 } 179 if (GC_n_changed_errors > 0) { 180 GC_printf("Found %lu changed bit errors\n", 181 (unsigned long)GC_n_changed_errors); 182 GC_printf("These may be benign (provoked by nonpointer changes)\n"); 183# ifdef THREADS 184 GC_printf( 185 "Also expect 1 per thread currently allocating a stubborn obj.\n"); 186# endif 187 } 188} 189 190# else 191 192extern int GC_quiet; 193 /* ANSI C doesn't allow translation units to be empty. */ 194 /* So we guarantee this one is nonempty. */ 195 196# endif /* CHECKSUMS */