123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /*
- * 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 "private/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 10000
- # 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 collector. */
- } 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);
- struct hblk *b;
-
- if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
- pe -> old_sum = pe -> new_sum;
- pe -> new_sum = GC_checksum(h);
- # if !defined(MSWIN32) && !defined(MSWINCE)
- if (pe -> new_sum != 0x80000000 && !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++;
- }
- b = h;
- while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) {
- b -= (word)hhdr;
- hhdr = HDR(b);
- }
- if (pe -> new_valid
- && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */
- && 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 ( 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 += HBLKSIZE-1;
- bytes &= ~(HBLKSIZE-1);
- GC_bytes_in_used_blocks += bytes;
- }
- void GC_check_blocks()
- {
- word bytes_in_free_blocks = GC_large_free_bytes;
-
- GC_bytes_in_used_blocks = 0;
- GC_apply_to_all_blocks(GC_add_block, (word)0);
- 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 */
|