boehm-gc: revert all CACAO-specific modifications; this is now an exact copy of the...
[cacao.git] / src / mm / boehm-gc / checksums.c
1 /*
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
27 typedef 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
35 page_entry GC_sums [NSUMS];
36
37 STATIC word GC_faulted[NSUMS];  /* Record of pages on which we saw a write */
38                                 /* fault.                                  */
39 STATIC size_t GC_n_faulted = 0;
40
41 void GC_record_fault(struct hblk * h)
42 {
43     word page = (word)h;
44
45     page += GC_page_size - 1;
46     page &= ~(GC_page_size - 1);
47     if (GC_n_faulted >= NSUMS) ABORT("write fault log overflowed");
48     GC_faulted[GC_n_faulted++] = page;
49 }
50
51 STATIC GC_bool GC_was_faulted(struct hblk *h)
52 {
53     size_t i;
54     word page = (word)h;
55
56     page += GC_page_size - 1;
57     page &= ~(GC_page_size - 1);
58     for (i = 0; i < GC_n_faulted; ++i) {
59         if (GC_faulted[i] == page) return TRUE;
60     }
61     return FALSE;
62 }
63
64 STATIC word GC_checksum(struct hblk *h)
65 {
66     register word *p = (word *)h;
67     register word *lim = (word *)(h+1);
68     register word result = 0;
69     
70     while (p < lim) {
71         result += *p++;
72     }
73     return(result | 0x80000000 /* doesn't look like pointer */);
74 }
75
76 # ifdef STUBBORN_ALLOC
77 /* Check whether a stubborn object from the given block appears on      */
78 /* the appropriate free list.                                           */
79 STATIC GC_bool GC_on_free_list(struct hblk *h)
80 {
81     hdr * hhdr = HDR(h);
82     size_t sz = BYTES_TO_WORDS(hhdr -> hb_sz);
83     ptr_t p;
84     
85     if (sz > MAXOBJWORDS) return(FALSE);
86     for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) {
87         if (HBLKPTR(p) == h) return(TRUE);
88     }
89     return(FALSE);
90 }
91 # endif
92  
93 int GC_n_dirty_errors;
94 int GC_n_faulted_dirty_errors;
95 int GC_n_changed_errors;
96 int GC_n_clean;
97 int GC_n_dirty;
98
99 STATIC void GC_update_check_page(struct hblk *h, int index)
100 {
101     page_entry *pe = GC_sums + index;
102     register hdr * hhdr = HDR(h);
103     struct hblk *b;
104     
105     if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
106     pe -> old_sum = pe -> new_sum;
107     pe -> new_sum = GC_checksum(h);
108 #   if !defined(MSWIN32) && !defined(MSWINCE)
109         if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
110             GC_printf("GC_page_was_ever_dirty(%p) is wrong\n", h);
111         }
112 #   endif
113     if (GC_page_was_dirty(h)) {
114         GC_n_dirty++;
115     } else {
116         GC_n_clean++;
117     }
118     b = h;
119     while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) {
120         b -= (word)hhdr;
121         hhdr = HDR(b);
122     }
123     if (pe -> new_valid
124         && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */
125         && pe -> old_sum != pe -> new_sum) {
126         if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
127             GC_bool was_faulted = GC_was_faulted(h);
128             /* Set breakpoint here */GC_n_dirty_errors++;
129             if (was_faulted) GC_n_faulted_dirty_errors++;
130         }
131 #       ifdef STUBBORN_ALLOC
132           if (!HBLK_IS_FREE(hhdr)
133             && hhdr -> hb_obj_kind == STUBBORN
134             && !GC_page_was_changed(h)
135             && !GC_on_free_list(h)) {
136             /* if GC_on_free_list(h) then reclaim may have touched it   */
137             /* without any allocations taking place.                    */
138             /* Set breakpoint here */GC_n_changed_errors++;
139           }
140 #       endif
141     }
142     pe -> new_valid = TRUE;
143     pe -> block = h + OFFSET;
144 }
145
146 word GC_bytes_in_used_blocks;
147
148 /*ARGSUSED*/
149 STATIC void GC_add_block(struct hblk *h, word dummy)
150 {
151    hdr * hhdr = HDR(h);
152    size_t bytes = hhdr -> hb_sz;
153    
154    bytes += HBLKSIZE-1;
155    bytes &= ~(HBLKSIZE-1);
156    GC_bytes_in_used_blocks += bytes;
157 }
158
159 STATIC void GC_check_blocks(void)
160 {
161     word bytes_in_free_blocks = GC_large_free_bytes;
162     
163     GC_bytes_in_used_blocks = 0;
164     GC_apply_to_all_blocks(GC_add_block, (word)0);
165     GC_printf("GC_bytes_in_used_blocks = %lu, bytes_in_free_blocks = %lu ",
166               (unsigned long)GC_bytes_in_used_blocks,
167               (unsigned long)bytes_in_free_blocks);
168     GC_printf("GC_heapsize = %lu\n", (unsigned long)GC_heapsize);
169     if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
170         GC_printf("LOST SOME BLOCKS!!\n");
171     }
172 }
173
174 /* Should be called immediately after GC_read_dirty and GC_read_changed. */
175 void GC_check_dirty(void)
176 {
177     int index;
178     unsigned i;
179     struct hblk *h;
180     ptr_t start;
181     
182     GC_check_blocks();
183     
184     GC_n_dirty_errors = 0;
185     GC_n_faulted_dirty_errors = 0;
186     GC_n_changed_errors = 0;
187     GC_n_clean = 0;
188     GC_n_dirty = 0;
189     
190     index = 0;
191     for (i = 0; i < GC_n_heap_sects; i++) {
192         start = GC_heap_sects[i].hs_start;
193         for (h = (struct hblk *)start;
194              h < (struct hblk *)(start + GC_heap_sects[i].hs_bytes);
195              h++) {
196              GC_update_check_page(h, index);
197              index++;
198              if (index >= NSUMS) goto out;
199         }
200     }
201 out:
202     GC_printf("Checked %lu clean and %lu dirty pages\n",
203               (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty);
204     if (GC_n_dirty_errors > 0) {
205         GC_printf("Found %d dirty bit errors (%d were faulted)\n",
206                   GC_n_dirty_errors, GC_n_faulted_dirty_errors);
207     }
208     if (GC_n_changed_errors > 0) {
209         GC_printf("Found %lu changed bit errors\n",
210                   (unsigned long)GC_n_changed_errors);
211         GC_printf("These may be benign (provoked by nonpointer changes)\n");
212 #       ifdef THREADS
213             GC_printf(
214             "Also expect 1 per thread currently allocating a stubborn obj.\n");
215 #       endif
216     }
217     for (i = 0; i < GC_n_faulted; ++i) {
218         GC_faulted[i] = 0; /* Don't expose block pointers to GC */
219     }
220     GC_n_faulted = 0;
221 }
222
223 # else
224
225 extern int GC_quiet;
226         /* ANSI C doesn't allow translation units to be empty.  */
227         /* So we guarantee this one is nonempty.                */
228
229 # endif /* CHECKSUMS */