Mercurial > emacs
comparison gc/checksums.c @ 51488:5de98dce4bd1
*** empty log message ***
author | Dave Love <fx@gnu.org> |
---|---|
date | Thu, 05 Jun 2003 17:49:22 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
51487:01d68b199093 | 51488:5de98dce4bd1 |
---|---|
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 "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 2000 | |
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 colector. */ | |
33 } page_entry; | |
34 | |
35 page_entry GC_sums [NSUMS]; | |
36 | |
37 word GC_checksum(h) | |
38 struct 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. */ | |
53 GC_bool GC_on_free_list(h) | |
54 struct hblk *h; | |
55 { | |
56 register hdr * hhdr = HDR(h); | |
57 register int sz = hhdr -> hb_sz; | |
58 ptr_t p; | |
59 | |
60 if (sz > MAXOBJSZ) 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 | |
68 int GC_n_dirty_errors; | |
69 int GC_n_changed_errors; | |
70 int GC_n_clean; | |
71 int GC_n_dirty; | |
72 | |
73 void GC_update_check_page(h, index) | |
74 struct hblk *h; | |
75 int index; | |
76 { | |
77 page_entry *pe = GC_sums + index; | |
78 register hdr * hhdr = HDR(h); | |
79 | |
80 if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed"); | |
81 pe -> old_sum = pe -> new_sum; | |
82 pe -> new_sum = GC_checksum(h); | |
83 # if !defined(MSWIN32) && !defined(MSWINCE) | |
84 if (pe -> new_sum != 0 && !GC_page_was_ever_dirty(h)) { | |
85 GC_printf1("GC_page_was_ever_dirty(0x%lx) is wrong\n", | |
86 (unsigned long)h); | |
87 } | |
88 # endif | |
89 if (GC_page_was_dirty(h)) { | |
90 GC_n_dirty++; | |
91 } else { | |
92 GC_n_clean++; | |
93 } | |
94 if (pe -> new_valid && pe -> old_sum != pe -> new_sum) { | |
95 if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) { | |
96 /* Set breakpoint here */GC_n_dirty_errors++; | |
97 } | |
98 # ifdef STUBBORN_ALLOC | |
99 if (!IS_FORWARDING_ADDR_OR_NIL(hhdr) | |
100 && hhdr -> hb_map != GC_invalid_map | |
101 && hhdr -> hb_obj_kind == STUBBORN | |
102 && !GC_page_was_changed(h) | |
103 && !GC_on_free_list(h)) { | |
104 /* if GC_on_free_list(h) then reclaim may have touched it */ | |
105 /* without any allocations taking place. */ | |
106 /* Set breakpoint here */GC_n_changed_errors++; | |
107 } | |
108 # endif | |
109 } | |
110 pe -> new_valid = TRUE; | |
111 pe -> block = h + OFFSET; | |
112 } | |
113 | |
114 word GC_bytes_in_used_blocks; | |
115 | |
116 void GC_add_block(h, dummy) | |
117 struct hblk *h; | |
118 word dummy; | |
119 { | |
120 register hdr * hhdr = HDR(h); | |
121 register bytes = WORDS_TO_BYTES(hhdr -> hb_sz); | |
122 | |
123 bytes += HDR_BYTES + HBLKSIZE-1; | |
124 bytes &= ~(HBLKSIZE-1); | |
125 GC_bytes_in_used_blocks += bytes; | |
126 } | |
127 | |
128 void GC_check_blocks() | |
129 { | |
130 word bytes_in_free_blocks = 0; | |
131 struct hblk * h = GC_hblkfreelist; | |
132 hdr * hhdr = HDR(h); | |
133 word sz; | |
134 | |
135 GC_bytes_in_used_blocks = 0; | |
136 GC_apply_to_all_blocks(GC_add_block, (word)0); | |
137 while (h != 0) { | |
138 sz = hhdr -> hb_sz; | |
139 bytes_in_free_blocks += sz; | |
140 h = hhdr -> hb_next; | |
141 hhdr = HDR(h); | |
142 } | |
143 GC_printf2("GC_bytes_in_used_blocks = %ld, bytes_in_free_blocks = %ld ", | |
144 GC_bytes_in_used_blocks, bytes_in_free_blocks); | |
145 GC_printf1("GC_heapsize = %ld\n", GC_heapsize); | |
146 if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) { | |
147 GC_printf0("LOST SOME BLOCKS!!\n"); | |
148 } | |
149 } | |
150 | |
151 /* Should be called immediately after GC_read_dirty and GC_read_changed. */ | |
152 void GC_check_dirty() | |
153 { | |
154 register int index; | |
155 register unsigned i; | |
156 register struct hblk *h; | |
157 register ptr_t start; | |
158 | |
159 GC_check_blocks(); | |
160 | |
161 GC_n_dirty_errors = 0; | |
162 GC_n_changed_errors = 0; | |
163 GC_n_clean = 0; | |
164 GC_n_dirty = 0; | |
165 | |
166 index = 0; | |
167 for (i = 0; i < GC_n_heap_sects; i++) { | |
168 start = GC_heap_sects[i].hs_start; | |
169 for (h = (struct hblk *)start; | |
170 h < (struct hblk *)(start + GC_heap_sects[i].hs_bytes); | |
171 h++) { | |
172 GC_update_check_page(h, index); | |
173 index++; | |
174 if (index >= NSUMS) goto out; | |
175 } | |
176 } | |
177 out: | |
178 GC_printf2("Checked %lu clean and %lu dirty pages\n", | |
179 (unsigned long) GC_n_clean, (unsigned long) GC_n_dirty); | |
180 if (GC_n_dirty_errors > 0) { | |
181 GC_printf1("Found %lu dirty bit errors\n", | |
182 (unsigned long)GC_n_dirty_errors); | |
183 } | |
184 if (GC_n_changed_errors > 0) { | |
185 GC_printf1("Found %lu changed bit errors\n", | |
186 (unsigned long)GC_n_changed_errors); | |
187 GC_printf0("These may be benign (provoked by nonpointer changes)\n"); | |
188 # ifdef THREADS | |
189 GC_printf0( | |
190 "Also expect 1 per thread currently allocating a stubborn obj.\n"); | |
191 # endif | |
192 } | |
193 } | |
194 | |
195 # else | |
196 | |
197 extern int GC_quiet; | |
198 /* ANSI C doesn't allow translation units to be empty. */ | |
199 /* So we guarantee this one is nonempty. */ | |
200 | |
201 # endif /* CHECKSUMS */ |