1 | /*
|
---|
2 | * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
---|
3 | * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
---|
4 | *
|
---|
5 | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
---|
6 | * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
---|
7 | *
|
---|
8 | * Permission is hereby granted to use or copy this program
|
---|
9 | * for any purpose, provided the above notices are retained on all copies.
|
---|
10 | * Permission to modify the code and to distribute modified code is granted,
|
---|
11 | * provided the above notices are retained, and a notice that the code was
|
---|
12 | * modified is included with the above copyright notice.
|
---|
13 | */
|
---|
14 | /* Boehm, August 9, 1995 6:09 pm PDT */
|
---|
15 | # include "private/gc_priv.h"
|
---|
16 |
|
---|
17 | /*
|
---|
18 | * We maintain several hash tables of hblks that have had false hits.
|
---|
19 | * Each contains one bit per hash bucket; If any page in the bucket
|
---|
20 | * has had a false hit, we assume that all of them have.
|
---|
21 | * See the definition of page_hash_table in gc_private.h.
|
---|
22 | * False hits from the stack(s) are much more dangerous than false hits
|
---|
23 | * from elsewhere, since the former can pin a large object that spans the
|
---|
24 | * block, eventhough it does not start on the dangerous block.
|
---|
25 | */
|
---|
26 |
|
---|
27 | /*
|
---|
28 | * Externally callable routines are:
|
---|
29 |
|
---|
30 | * GC_add_to_black_list_normal
|
---|
31 | * GC_add_to_black_list_stack
|
---|
32 | * GC_promote_black_lists
|
---|
33 | * GC_is_black_listed
|
---|
34 | *
|
---|
35 | * All require that the allocator lock is held.
|
---|
36 | */
|
---|
37 |
|
---|
38 | /* Pointers to individual tables. We replace one table by another by */
|
---|
39 | /* switching these pointers. */
|
---|
40 | word * GC_old_normal_bl;
|
---|
41 | /* Nonstack false references seen at last full */
|
---|
42 | /* collection. */
|
---|
43 | word * GC_incomplete_normal_bl;
|
---|
44 | /* Nonstack false references seen since last */
|
---|
45 | /* full collection. */
|
---|
46 | word * GC_old_stack_bl;
|
---|
47 | word * GC_incomplete_stack_bl;
|
---|
48 |
|
---|
49 | word GC_total_stack_black_listed;
|
---|
50 |
|
---|
51 | word GC_black_list_spacing = MINHINCR*HBLKSIZE; /* Initial rough guess */
|
---|
52 |
|
---|
53 | void GC_clear_bl();
|
---|
54 |
|
---|
55 | # if defined(__STDC__) || defined(__cplusplus)
|
---|
56 | void GC_default_print_heap_obj_proc(ptr_t p)
|
---|
57 | # else
|
---|
58 | void GC_default_print_heap_obj_proc(p)
|
---|
59 | ptr_t p;
|
---|
60 | # endif
|
---|
61 | {
|
---|
62 | ptr_t base = GC_base(p);
|
---|
63 |
|
---|
64 | GC_err_printf2("start: 0x%lx, appr. length: %ld", base, GC_size(base));
|
---|
65 | }
|
---|
66 |
|
---|
67 | void (*GC_print_heap_obj) GC_PROTO((ptr_t p)) =
|
---|
68 | GC_default_print_heap_obj_proc;
|
---|
69 |
|
---|
70 | void GC_print_source_ptr(p)
|
---|
71 | ptr_t p;
|
---|
72 | {
|
---|
73 | ptr_t base = GC_base(p);
|
---|
74 | if (0 == base) {
|
---|
75 | if (0 == p) {
|
---|
76 | GC_err_printf0("in register");
|
---|
77 | } else {
|
---|
78 | GC_err_printf0("in root set");
|
---|
79 | }
|
---|
80 | } else {
|
---|
81 | GC_err_printf0("in object at ");
|
---|
82 | (*GC_print_heap_obj)(base);
|
---|
83 | }
|
---|
84 | }
|
---|
85 |
|
---|
86 | void GC_bl_init()
|
---|
87 | {
|
---|
88 | if (!GC_all_interior_pointers) {
|
---|
89 | GC_old_normal_bl = (word *)
|
---|
90 | GC_scratch_alloc((word)(sizeof (page_hash_table)));
|
---|
91 | GC_incomplete_normal_bl = (word *)GC_scratch_alloc
|
---|
92 | ((word)(sizeof(page_hash_table)));
|
---|
93 | if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
|
---|
94 | GC_err_printf0("Insufficient memory for black list\n");
|
---|
95 | EXIT();
|
---|
96 | }
|
---|
97 | GC_clear_bl(GC_old_normal_bl);
|
---|
98 | GC_clear_bl(GC_incomplete_normal_bl);
|
---|
99 | }
|
---|
100 | GC_old_stack_bl = (word *)GC_scratch_alloc((word)(sizeof(page_hash_table)));
|
---|
101 | GC_incomplete_stack_bl = (word *)GC_scratch_alloc
|
---|
102 | ((word)(sizeof(page_hash_table)));
|
---|
103 | if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
|
---|
104 | GC_err_printf0("Insufficient memory for black list\n");
|
---|
105 | EXIT();
|
---|
106 | }
|
---|
107 | GC_clear_bl(GC_old_stack_bl);
|
---|
108 | GC_clear_bl(GC_incomplete_stack_bl);
|
---|
109 | }
|
---|
110 |
|
---|
111 | void GC_clear_bl(doomed)
|
---|
112 | word *doomed;
|
---|
113 | {
|
---|
114 | BZERO(doomed, sizeof(page_hash_table));
|
---|
115 | }
|
---|
116 |
|
---|
117 | void GC_copy_bl(old, new)
|
---|
118 | word *new, *old;
|
---|
119 | {
|
---|
120 | BCOPY(old, new, sizeof(page_hash_table));
|
---|
121 | }
|
---|
122 |
|
---|
123 | static word total_stack_black_listed();
|
---|
124 |
|
---|
125 | /* Signal the completion of a collection. Turn the incomplete black */
|
---|
126 | /* lists into new black lists, etc. */
|
---|
127 | void GC_promote_black_lists()
|
---|
128 | {
|
---|
129 | word * very_old_normal_bl = GC_old_normal_bl;
|
---|
130 | word * very_old_stack_bl = GC_old_stack_bl;
|
---|
131 |
|
---|
132 | GC_old_normal_bl = GC_incomplete_normal_bl;
|
---|
133 | GC_old_stack_bl = GC_incomplete_stack_bl;
|
---|
134 | if (!GC_all_interior_pointers) {
|
---|
135 | GC_clear_bl(very_old_normal_bl);
|
---|
136 | }
|
---|
137 | GC_clear_bl(very_old_stack_bl);
|
---|
138 | GC_incomplete_normal_bl = very_old_normal_bl;
|
---|
139 | GC_incomplete_stack_bl = very_old_stack_bl;
|
---|
140 | GC_total_stack_black_listed = total_stack_black_listed();
|
---|
141 | # ifdef PRINTSTATS
|
---|
142 | GC_printf1("%ld bytes in heap blacklisted for interior pointers\n",
|
---|
143 | (unsigned long)GC_total_stack_black_listed);
|
---|
144 | # endif
|
---|
145 | if (GC_total_stack_black_listed != 0) {
|
---|
146 | GC_black_list_spacing =
|
---|
147 | HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
|
---|
148 | }
|
---|
149 | if (GC_black_list_spacing < 3 * HBLKSIZE) {
|
---|
150 | GC_black_list_spacing = 3 * HBLKSIZE;
|
---|
151 | }
|
---|
152 | if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
|
---|
153 | GC_black_list_spacing = MAXHINCR * HBLKSIZE;
|
---|
154 | /* Makes it easier to allocate really huge blocks, which otherwise */
|
---|
155 | /* may have problems with nonuniform blacklist distributions. */
|
---|
156 | /* This way we should always succeed immediately after growing the */
|
---|
157 | /* heap. */
|
---|
158 | }
|
---|
159 | }
|
---|
160 |
|
---|
161 | void GC_unpromote_black_lists()
|
---|
162 | {
|
---|
163 | if (!GC_all_interior_pointers) {
|
---|
164 | GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
|
---|
165 | }
|
---|
166 | GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
|
---|
167 | }
|
---|
168 |
|
---|
169 | /* P is not a valid pointer reference, but it falls inside */
|
---|
170 | /* the plausible heap bounds. */
|
---|
171 | /* Add it to the normal incomplete black list if appropriate. */
|
---|
172 | #ifdef PRINT_BLACK_LIST
|
---|
173 | void GC_add_to_black_list_normal(p, source)
|
---|
174 | ptr_t source;
|
---|
175 | #else
|
---|
176 | void GC_add_to_black_list_normal(p)
|
---|
177 | #endif
|
---|
178 | word p;
|
---|
179 | {
|
---|
180 | if (!(GC_modws_valid_offsets[p & (sizeof(word)-1)])) return;
|
---|
181 | {
|
---|
182 | register int index = PHT_HASH(p);
|
---|
183 |
|
---|
184 | if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
|
---|
185 | # ifdef PRINT_BLACK_LIST
|
---|
186 | if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
|
---|
187 | GC_err_printf2(
|
---|
188 | "Black listing (normal) 0x%lx referenced from 0x%lx ",
|
---|
189 | (unsigned long) p, (unsigned long) source);
|
---|
190 | GC_print_source_ptr(source);
|
---|
191 | GC_err_puts("\n");
|
---|
192 | }
|
---|
193 | # endif
|
---|
194 | set_pht_entry_from_index(GC_incomplete_normal_bl, index);
|
---|
195 | } /* else this is probably just an interior pointer to an allocated */
|
---|
196 | /* object, and isn't worth black listing. */
|
---|
197 | }
|
---|
198 | }
|
---|
199 |
|
---|
200 | /* And the same for false pointers from the stack. */
|
---|
201 | #ifdef PRINT_BLACK_LIST
|
---|
202 | void GC_add_to_black_list_stack(p, source)
|
---|
203 | ptr_t source;
|
---|
204 | #else
|
---|
205 | void GC_add_to_black_list_stack(p)
|
---|
206 | #endif
|
---|
207 | word p;
|
---|
208 | {
|
---|
209 | register int index = PHT_HASH(p);
|
---|
210 |
|
---|
211 | if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
|
---|
212 | # ifdef PRINT_BLACK_LIST
|
---|
213 | if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
|
---|
214 | GC_err_printf2(
|
---|
215 | "Black listing (stack) 0x%lx referenced from 0x%lx ",
|
---|
216 | (unsigned long)p, (unsigned long)source);
|
---|
217 | GC_print_source_ptr(source);
|
---|
218 | GC_err_puts("\n");
|
---|
219 | }
|
---|
220 | # endif
|
---|
221 | set_pht_entry_from_index(GC_incomplete_stack_bl, index);
|
---|
222 | }
|
---|
223 | }
|
---|
224 |
|
---|
225 | /*
|
---|
226 | * Is the block starting at h of size len bytes black listed? If so,
|
---|
227 | * return the address of the next plausible r such that (r, len) might not
|
---|
228 | * be black listed. (R may not actually be in the heap. We guarantee only
|
---|
229 | * that every smaller value of r after h is also black listed.)
|
---|
230 | * If (h,len) is not black listed, return 0.
|
---|
231 | * Knows about the structure of the black list hash tables.
|
---|
232 | */
|
---|
233 | struct hblk * GC_is_black_listed(h, len)
|
---|
234 | struct hblk * h;
|
---|
235 | word len;
|
---|
236 | {
|
---|
237 | register int index = PHT_HASH((word)h);
|
---|
238 | register word i;
|
---|
239 | word nblocks = divHBLKSZ(len);
|
---|
240 |
|
---|
241 | if (!GC_all_interior_pointers) {
|
---|
242 | if (get_pht_entry_from_index(GC_old_normal_bl, index)
|
---|
243 | || get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
|
---|
244 | return(h+1);
|
---|
245 | }
|
---|
246 | }
|
---|
247 |
|
---|
248 | for (i = 0; ; ) {
|
---|
249 | if (GC_old_stack_bl[divWORDSZ(index)] == 0
|
---|
250 | && GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
|
---|
251 | /* An easy case */
|
---|
252 | i += WORDSZ - modWORDSZ(index);
|
---|
253 | } else {
|
---|
254 | if (get_pht_entry_from_index(GC_old_stack_bl, index)
|
---|
255 | || get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
|
---|
256 | return(h+i+1);
|
---|
257 | }
|
---|
258 | i++;
|
---|
259 | }
|
---|
260 | if (i >= nblocks) break;
|
---|
261 | index = PHT_HASH((word)(h+i));
|
---|
262 | }
|
---|
263 | return(0);
|
---|
264 | }
|
---|
265 |
|
---|
266 |
|
---|
267 | /* Return the number of blacklisted blocks in a given range. */
|
---|
268 | /* Used only for statistical purposes. */
|
---|
269 | /* Looks only at the GC_incomplete_stack_bl. */
|
---|
270 | word GC_number_stack_black_listed(start, endp1)
|
---|
271 | struct hblk *start, *endp1;
|
---|
272 | {
|
---|
273 | register struct hblk * h;
|
---|
274 | word result = 0;
|
---|
275 |
|
---|
276 | for (h = start; h < endp1; h++) {
|
---|
277 | register int index = PHT_HASH((word)h);
|
---|
278 |
|
---|
279 | if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
|
---|
280 | }
|
---|
281 | return(result);
|
---|
282 | }
|
---|
283 |
|
---|
284 |
|
---|
285 | /* Return the total number of (stack) black-listed bytes. */
|
---|
286 | static word total_stack_black_listed()
|
---|
287 | {
|
---|
288 | register unsigned i;
|
---|
289 | word total = 0;
|
---|
290 |
|
---|
291 | for (i = 0; i < GC_n_heap_sects; i++) {
|
---|
292 | struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
|
---|
293 | word len = (word) GC_heap_sects[i].hs_bytes;
|
---|
294 | struct hblk * endp1 = start + len/HBLKSIZE;
|
---|
295 |
|
---|
296 | total += GC_number_stack_black_listed(start, endp1);
|
---|
297 | }
|
---|
298 | return(total * HBLKSIZE);
|
---|
299 | }
|
---|
300 |
|
---|