]>
Commit | Line | Data |
---|---|---|
73ffefd0 TT |
1 | /* |
2 | * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers | |
20bbd3cd TT |
3 | * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. |
4 | * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. | |
5 | * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. | |
73ffefd0 TT |
6 | * |
7 | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED | |
8 | * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. | |
9 | * | |
10 | * Permission is hereby granted to use or copy this program | |
11 | * for any purpose, provided the above notices are retained on all copies. | |
12 | * Permission to modify the code and to distribute modified code is granted, | |
13 | * provided the above notices are retained, and a notice that the code was | |
14 | * modified is included with the above copyright notice. | |
15 | */ | |
73ffefd0 TT |
16 | |
17 | #include <stdio.h> | |
9110a741 | 18 | #include "private/gc_priv.h" |
73ffefd0 TT |
19 | |
20 | signed_word GC_mem_found = 0; | |
21 | /* Number of words of memory reclaimed */ | |
22 | ||
5a2586cf | 23 | #if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
9110a741 BM |
24 | word GC_fl_builder_count = 0; |
25 | /* Number of threads currently building free lists without */ | |
26 | /* holding GC lock. It is not safe to collect if this is */ | |
27 | /* nonzero. */ | |
28 | #endif /* PARALLEL_MARK */ | |
29 | ||
30c3de1f JS |
30 | /* We defer printing of leaked objects until we're done with the GC */ |
31 | /* cycle, since the routine for printing objects needs to run outside */ | |
32 | /* the collector, e.g. without the allocation lock. */ | |
33 | #define MAX_LEAKED 40 | |
34 | ptr_t GC_leaked[MAX_LEAKED]; | |
35 | unsigned GC_n_leaked = 0; | |
36 | ||
37 | GC_bool GC_have_errors = FALSE; | |
38 | ||
39 | void GC_add_leaked(leaked) | |
40 | ptr_t leaked; | |
73ffefd0 | 41 | { |
30c3de1f JS |
42 | if (GC_n_leaked < MAX_LEAKED) { |
43 | GC_have_errors = TRUE; | |
44 | GC_leaked[GC_n_leaked++] = leaked; | |
45 | /* Make sure it's not reclaimed this cycle */ | |
46 | GC_set_mark_bit(leaked); | |
73ffefd0 | 47 | } |
73ffefd0 TT |
48 | } |
49 | ||
30c3de1f JS |
50 | static GC_bool printing_errors = FALSE; |
51 | /* Print all objects on the list after printing any smashed objs. */ | |
52 | /* Clear both lists. */ | |
53 | void GC_print_all_errors () | |
54 | { | |
55 | unsigned i; | |
56 | ||
57 | LOCK(); | |
58 | if (printing_errors) { | |
59 | UNLOCK(); | |
60 | return; | |
61 | } | |
62 | printing_errors = TRUE; | |
63 | UNLOCK(); | |
64 | if (GC_debugging_started) GC_print_all_smashed(); | |
65 | for (i = 0; i < GC_n_leaked; ++i) { | |
66 | ptr_t p = GC_leaked[i]; | |
67 | if (HDR(p) -> hb_obj_kind == PTRFREE) { | |
68 | GC_err_printf0("Leaked atomic object at "); | |
69 | } else { | |
70 | GC_err_printf0("Leaked composite object at "); | |
71 | } | |
72 | GC_print_heap_obj(p); | |
73 | GC_err_printf0("\n"); | |
74 | GC_free(p); | |
75 | GC_leaked[i] = 0; | |
76 | } | |
77 | GC_n_leaked = 0; | |
78 | printing_errors = FALSE; | |
79 | } | |
80 | ||
81 | ||
73ffefd0 | 82 | # define FOUND_FREE(hblk, word_no) \ |
20bbd3cd | 83 | { \ |
30c3de1f | 84 | GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \ |
73ffefd0 | 85 | } |
73ffefd0 TT |
86 | |
87 | /* | |
88 | * reclaim phase | |
89 | * | |
90 | */ | |
91 | ||
92 | ||
93 | /* | |
94 | * Test whether a block is completely empty, i.e. contains no marked | |
95 | * objects. This does not require the block to be in physical | |
96 | * memory. | |
97 | */ | |
98 | ||
99 | GC_bool GC_block_empty(hhdr) | |
100 | register hdr * hhdr; | |
101 | { | |
9110a741 BM |
102 | /* We treat hb_marks as an array of words here, even if it is */ |
103 | /* actually an array of bytes. Since we only check for zero, there */ | |
104 | /* are no endian-ness issues. */ | |
73ffefd0 TT |
105 | register word *p = (word *)(&(hhdr -> hb_marks[0])); |
106 | register word * plim = | |
9110a741 | 107 | (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); |
73ffefd0 TT |
108 | while (p < plim) { |
109 | if (*p++) return(FALSE); | |
110 | } | |
111 | return(TRUE); | |
112 | } | |
113 | ||
20bbd3cd TT |
114 | /* The following functions sometimes return a DONT_KNOW value. */ |
115 | #define DONT_KNOW 2 | |
116 | ||
117 | #ifdef SMALL_CONFIG | |
118 | # define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW | |
119 | # define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW | |
120 | # define GC_block_nearly_full(hhdr) DONT_KNOW | |
9110a741 BM |
121 | #endif |
122 | ||
123 | #if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES) | |
124 | ||
125 | # define GC_block_nearly_full1(hhdr, pat1) GC_block_nearly_full(hhdr) | |
126 | # define GC_block_nearly_full3(hhdr, pat1, pat2) GC_block_nearly_full(hhdr) | |
127 | ||
128 | ||
129 | GC_bool GC_block_nearly_full(hhdr) | |
130 | register hdr * hhdr; | |
131 | { | |
132 | /* We again treat hb_marks as an array of words, even though it */ | |
133 | /* isn't. We first sum up all the words, resulting in a word */ | |
134 | /* containing 4 or 8 separate partial sums. */ | |
135 | /* We then sum the bytes in the word of partial sums. */ | |
136 | /* This is still endian independant. This fails if the partial */ | |
137 | /* sums can overflow. */ | |
138 | # if (BYTES_TO_WORDS(MARK_BITS_SZ)) >= 256 | |
139 | --> potential overflow; fix the code | |
140 | # endif | |
141 | register word *p = (word *)(&(hhdr -> hb_marks[0])); | |
142 | register word * plim = | |
143 | (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); | |
144 | word sum_vector = 0; | |
145 | unsigned sum; | |
146 | while (p < plim) { | |
147 | sum_vector += *p; | |
148 | ++p; | |
149 | } | |
150 | sum = 0; | |
151 | while (sum_vector > 0) { | |
152 | sum += sum_vector & 0xff; | |
153 | sum_vector >>= 8; | |
154 | } | |
155 | return (sum > BYTES_TO_WORDS(7*HBLKSIZE/8)/(hhdr -> hb_sz)); | |
156 | } | |
157 | #endif /* USE_MARK_BYTES */ | |
158 | ||
159 | #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) | |
20bbd3cd TT |
160 | |
161 | /* | |
162 | * Test whether nearly all of the mark words consist of the same | |
163 | * repeating pattern. | |
164 | */ | |
165 | #define FULL_THRESHOLD (MARK_BITS_SZ/16) | |
166 | ||
167 | GC_bool GC_block_nearly_full1(hhdr, pat1) | |
168 | hdr *hhdr; | |
169 | word pat1; | |
170 | { | |
171 | unsigned i; | |
172 | unsigned misses = 0; | |
173 | GC_ASSERT((MARK_BITS_SZ & 1) == 0); | |
174 | for (i = 0; i < MARK_BITS_SZ; ++i) { | |
175 | if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { | |
176 | if (++misses > FULL_THRESHOLD) return FALSE; | |
177 | } | |
178 | } | |
179 | return TRUE; | |
180 | } | |
181 | ||
182 | /* | |
183 | * Test whether the same repeating 3 word pattern occurs in nearly | |
184 | * all the mark bit slots. | |
185 | * This is used as a heuristic, so we're a bit sloppy and ignore | |
186 | * the last one or two words. | |
187 | */ | |
188 | GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3) | |
189 | hdr *hhdr; | |
190 | word pat1, pat2, pat3; | |
191 | { | |
192 | unsigned i; | |
193 | unsigned misses = 0; | |
194 | ||
195 | if (MARK_BITS_SZ < 4) { | |
196 | return DONT_KNOW; | |
197 | } | |
198 | for (i = 0; i < MARK_BITS_SZ - 2; i += 3) { | |
199 | if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { | |
200 | if (++misses > FULL_THRESHOLD) return FALSE; | |
201 | } | |
202 | if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) { | |
203 | if (++misses > FULL_THRESHOLD) return FALSE; | |
204 | } | |
205 | if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) { | |
206 | if (++misses > FULL_THRESHOLD) return FALSE; | |
207 | } | |
208 | } | |
209 | return TRUE; | |
210 | } | |
211 | ||
212 | /* Check whether a small object block is nearly full by looking at only */ | |
213 | /* the mark bits. */ | |
214 | /* We manually precomputed the mark bit patterns that need to be */ | |
215 | /* checked for, and we give up on the ones that are unlikely to occur, */ | |
216 | /* or have period > 3. */ | |
217 | /* This would be a lot easier with a mark bit per object instead of per */ | |
218 | /* word, but that would rewuire computing object numbers in the mark */ | |
219 | /* loop, which would require different data structures ... */ | |
220 | GC_bool GC_block_nearly_full(hhdr) | |
221 | hdr *hhdr; | |
222 | { | |
223 | int sz = hhdr -> hb_sz; | |
224 | ||
225 | # if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 | |
226 | return DONT_KNOW; /* Shouldn't be used in any standard config. */ | |
227 | # endif | |
20bbd3cd TT |
228 | # if CPP_WORDSZ == 32 |
229 | switch(sz) { | |
230 | case 1: | |
231 | return GC_block_nearly_full1(hhdr, 0xffffffffl); | |
232 | case 2: | |
233 | return GC_block_nearly_full1(hhdr, 0x55555555l); | |
234 | case 4: | |
235 | return GC_block_nearly_full1(hhdr, 0x11111111l); | |
236 | case 6: | |
237 | return GC_block_nearly_full3(hhdr, 0x41041041l, | |
238 | 0x10410410l, | |
239 | 0x04104104l); | |
240 | case 8: | |
241 | return GC_block_nearly_full1(hhdr, 0x01010101l); | |
242 | case 12: | |
243 | return GC_block_nearly_full3(hhdr, 0x01001001l, | |
244 | 0x10010010l, | |
245 | 0x00100100l); | |
246 | case 16: | |
247 | return GC_block_nearly_full1(hhdr, 0x00010001l); | |
248 | case 32: | |
249 | return GC_block_nearly_full1(hhdr, 0x00000001l); | |
250 | default: | |
251 | return DONT_KNOW; | |
252 | } | |
253 | # endif | |
254 | # if CPP_WORDSZ == 64 | |
255 | switch(sz) { | |
256 | case 1: | |
257 | return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl); | |
258 | case 2: | |
259 | return GC_block_nearly_full1(hhdr, 0x5555555555555555l); | |
260 | case 4: | |
261 | return GC_block_nearly_full1(hhdr, 0x1111111111111111l); | |
262 | case 6: | |
263 | return GC_block_nearly_full3(hhdr, 0x1041041041041041l, | |
264 | 0x4104104104104104l, | |
265 | 0x0410410410410410l); | |
266 | case 8: | |
267 | return GC_block_nearly_full1(hhdr, 0x0101010101010101l); | |
268 | case 12: | |
269 | return GC_block_nearly_full3(hhdr, 0x1001001001001001l, | |
270 | 0x0100100100100100l, | |
271 | 0x0010010010010010l); | |
272 | case 16: | |
273 | return GC_block_nearly_full1(hhdr, 0x0001000100010001l); | |
274 | case 32: | |
275 | return GC_block_nearly_full1(hhdr, 0x0000000100000001l); | |
276 | default: | |
277 | return DONT_KNOW; | |
278 | } | |
279 | # endif | |
280 | } | |
9110a741 | 281 | #endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
20bbd3cd | 282 | |
9110a741 BM |
283 | /* We keep track of reclaimed memory if we are either asked to, or */ |
284 | /* we are using the parallel marker. In the latter case, we assume */ | |
285 | /* that most allocation goes through GC_malloc_many for scalability. */ | |
286 | /* GC_malloc_many needs the count anyway. */ | |
287 | # if defined(GATHERSTATS) || defined(PARALLEL_MARK) | |
73ffefd0 | 288 | # define INCR_WORDS(sz) n_words_found += (sz) |
9110a741 BM |
289 | # define COUNT_PARAM , count |
290 | # define COUNT_ARG , count | |
291 | # define COUNT_DECL signed_word * count; | |
292 | # define NWORDS_DECL signed_word n_words_found = 0; | |
293 | # define COUNT_UPDATE *count += n_words_found; | |
294 | # define MEM_FOUND_ADDR , &GC_mem_found | |
73ffefd0 TT |
295 | # else |
296 | # define INCR_WORDS(sz) | |
9110a741 BM |
297 | # define COUNT_PARAM |
298 | # define COUNT_ARG | |
299 | # define COUNT_DECL | |
300 | # define NWORDS_DECL | |
301 | # define COUNT_UPDATE | |
302 | # define MEM_FOUND_ADDR | |
73ffefd0 TT |
303 | # endif |
304 | /* | |
305 | * Restore unmarked small objects in h of size sz to the object | |
306 | * free list. Returns the new list. | |
307 | * Clears unmarked objects. | |
308 | */ | |
309 | /*ARGSUSED*/ | |
9110a741 | 310 | ptr_t GC_reclaim_clear(hbp, hhdr, sz, list COUNT_PARAM) |
73ffefd0 TT |
311 | register struct hblk *hbp; /* ptr to current heap block */ |
312 | register hdr * hhdr; | |
73ffefd0 TT |
313 | register ptr_t list; |
314 | register word sz; | |
9110a741 | 315 | COUNT_DECL |
73ffefd0 TT |
316 | { |
317 | register int word_no; | |
318 | register word *p, *q, *plim; | |
9110a741 | 319 | NWORDS_DECL |
73ffefd0 | 320 | |
9110a741 | 321 | GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp)); |
73ffefd0 | 322 | p = (word *)(hbp->hb_body); |
9110a741 | 323 | word_no = 0; |
73ffefd0 TT |
324 | plim = (word *)((((word)hbp) + HBLKSIZE) |
325 | - WORDS_TO_BYTES(sz)); | |
326 | ||
327 | /* go through all words in block */ | |
328 | while( p <= plim ) { | |
329 | if( mark_bit_from_hdr(hhdr, word_no) ) { | |
330 | p += sz; | |
331 | } else { | |
73ffefd0 TT |
332 | INCR_WORDS(sz); |
333 | /* object is available - put on list */ | |
334 | obj_link(p) = list; | |
335 | list = ((ptr_t)p); | |
336 | /* Clear object, advance p to next object in the process */ | |
337 | q = p + sz; | |
9110a741 BM |
338 | # ifdef USE_MARK_BYTES |
339 | GC_ASSERT(!(sz & 1) | |
340 | && !((word)p & (2 * sizeof(word) - 1))); | |
341 | p[1] = 0; | |
342 | p += 2; | |
343 | while (p < q) { | |
344 | CLEAR_DOUBLE(p); | |
345 | p += 2; | |
346 | } | |
347 | # else | |
348 | p++; /* Skip link field */ | |
349 | while (p < q) { | |
73ffefd0 | 350 | *p++ = 0; |
9110a741 BM |
351 | } |
352 | # endif | |
73ffefd0 TT |
353 | } |
354 | word_no += sz; | |
355 | } | |
9110a741 | 356 | COUNT_UPDATE |
73ffefd0 TT |
357 | return(list); |
358 | } | |
359 | ||
9110a741 | 360 | #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
73ffefd0 TT |
361 | |
362 | /* | |
363 | * A special case for 2 word composite objects (e.g. cons cells): | |
364 | */ | |
365 | /*ARGSUSED*/ | |
9110a741 | 366 | ptr_t GC_reclaim_clear2(hbp, hhdr, list COUNT_PARAM) |
73ffefd0 TT |
367 | register struct hblk *hbp; /* ptr to current heap block */ |
368 | hdr * hhdr; | |
73ffefd0 | 369 | register ptr_t list; |
9110a741 | 370 | COUNT_DECL |
73ffefd0 | 371 | { |
9110a741 | 372 | register word * mark_word_addr = &(hhdr->hb_marks[0]); |
73ffefd0 | 373 | register word *p, *plim; |
73ffefd0 TT |
374 | register word mark_word; |
375 | register int i; | |
9110a741 | 376 | NWORDS_DECL |
73ffefd0 TT |
377 | # define DO_OBJ(start_displ) \ |
378 | if (!(mark_word & ((word)1 << start_displ))) { \ | |
73ffefd0 TT |
379 | p[start_displ] = (word)list; \ |
380 | list = (ptr_t)(p+start_displ); \ | |
381 | p[start_displ+1] = 0; \ | |
382 | INCR_WORDS(2); \ | |
383 | } | |
384 | ||
385 | p = (word *)(hbp->hb_body); | |
386 | plim = (word *)(((word)hbp) + HBLKSIZE); | |
387 | ||
388 | /* go through all words in block */ | |
389 | while( p < plim ) { | |
390 | mark_word = *mark_word_addr++; | |
391 | for (i = 0; i < WORDSZ; i += 8) { | |
392 | DO_OBJ(0); | |
393 | DO_OBJ(2); | |
394 | DO_OBJ(4); | |
395 | DO_OBJ(6); | |
396 | p += 8; | |
397 | mark_word >>= 8; | |
398 | } | |
399 | } | |
9110a741 | 400 | COUNT_UPDATE |
73ffefd0 TT |
401 | return(list); |
402 | # undef DO_OBJ | |
403 | } | |
404 | ||
405 | /* | |
406 | * Another special case for 4 word composite objects: | |
407 | */ | |
408 | /*ARGSUSED*/ | |
9110a741 | 409 | ptr_t GC_reclaim_clear4(hbp, hhdr, list COUNT_PARAM) |
73ffefd0 TT |
410 | register struct hblk *hbp; /* ptr to current heap block */ |
411 | hdr * hhdr; | |
73ffefd0 | 412 | register ptr_t list; |
9110a741 | 413 | COUNT_DECL |
73ffefd0 | 414 | { |
9110a741 | 415 | register word * mark_word_addr = &(hhdr->hb_marks[0]); |
73ffefd0 | 416 | register word *p, *plim; |
73ffefd0 | 417 | register word mark_word; |
9110a741 | 418 | NWORDS_DECL |
73ffefd0 TT |
419 | # define DO_OBJ(start_displ) \ |
420 | if (!(mark_word & ((word)1 << start_displ))) { \ | |
73ffefd0 TT |
421 | p[start_displ] = (word)list; \ |
422 | list = (ptr_t)(p+start_displ); \ | |
423 | p[start_displ+1] = 0; \ | |
93002327 | 424 | CLEAR_DOUBLE(p + start_displ + 2); \ |
73ffefd0 TT |
425 | INCR_WORDS(4); \ |
426 | } | |
427 | ||
428 | p = (word *)(hbp->hb_body); | |
429 | plim = (word *)(((word)hbp) + HBLKSIZE); | |
430 | ||
431 | /* go through all words in block */ | |
432 | while( p < plim ) { | |
433 | mark_word = *mark_word_addr++; | |
434 | DO_OBJ(0); | |
435 | DO_OBJ(4); | |
436 | DO_OBJ(8); | |
437 | DO_OBJ(12); | |
438 | DO_OBJ(16); | |
439 | DO_OBJ(20); | |
440 | DO_OBJ(24); | |
441 | DO_OBJ(28); | |
442 | # if CPP_WORDSZ == 64 | |
443 | DO_OBJ(32); | |
444 | DO_OBJ(36); | |
445 | DO_OBJ(40); | |
446 | DO_OBJ(44); | |
447 | DO_OBJ(48); | |
448 | DO_OBJ(52); | |
449 | DO_OBJ(56); | |
450 | DO_OBJ(60); | |
451 | # endif | |
452 | p += WORDSZ; | |
453 | } | |
9110a741 | 454 | COUNT_UPDATE |
73ffefd0 TT |
455 | return(list); |
456 | # undef DO_OBJ | |
457 | } | |
458 | ||
9110a741 | 459 | #endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
73ffefd0 TT |
460 | |
461 | /* The same thing, but don't clear objects: */ | |
462 | /*ARGSUSED*/ | |
9110a741 | 463 | ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_PARAM) |
73ffefd0 TT |
464 | register struct hblk *hbp; /* ptr to current heap block */ |
465 | register hdr * hhdr; | |
73ffefd0 TT |
466 | register ptr_t list; |
467 | register word sz; | |
9110a741 | 468 | COUNT_DECL |
73ffefd0 | 469 | { |
9110a741 | 470 | register int word_no = 0; |
73ffefd0 | 471 | register word *p, *plim; |
9110a741 | 472 | NWORDS_DECL |
73ffefd0 TT |
473 | |
474 | p = (word *)(hbp->hb_body); | |
73ffefd0 TT |
475 | plim = (word *)((((word)hbp) + HBLKSIZE) |
476 | - WORDS_TO_BYTES(sz)); | |
477 | ||
478 | /* go through all words in block */ | |
479 | while( p <= plim ) { | |
480 | if( !mark_bit_from_hdr(hhdr, word_no) ) { | |
73ffefd0 TT |
481 | INCR_WORDS(sz); |
482 | /* object is available - put on list */ | |
483 | obj_link(p) = list; | |
484 | list = ((ptr_t)p); | |
485 | } | |
486 | p += sz; | |
487 | word_no += sz; | |
488 | } | |
9110a741 | 489 | COUNT_UPDATE |
73ffefd0 TT |
490 | return(list); |
491 | } | |
492 | ||
20bbd3cd TT |
493 | /* Don't really reclaim objects, just check for unmarked ones: */ |
494 | /*ARGSUSED*/ | |
495 | void GC_reclaim_check(hbp, hhdr, sz) | |
496 | register struct hblk *hbp; /* ptr to current heap block */ | |
497 | register hdr * hhdr; | |
498 | register word sz; | |
499 | { | |
9110a741 | 500 | register int word_no = 0; |
20bbd3cd TT |
501 | register word *p, *plim; |
502 | # ifdef GATHERSTATS | |
503 | register int n_words_found = 0; | |
504 | # endif | |
505 | ||
506 | p = (word *)(hbp->hb_body); | |
20bbd3cd TT |
507 | plim = (word *)((((word)hbp) + HBLKSIZE) |
508 | - WORDS_TO_BYTES(sz)); | |
509 | ||
510 | /* go through all words in block */ | |
511 | while( p <= plim ) { | |
512 | if( !mark_bit_from_hdr(hhdr, word_no) ) { | |
513 | FOUND_FREE(hbp, word_no); | |
514 | } | |
515 | p += sz; | |
516 | word_no += sz; | |
517 | } | |
518 | } | |
519 | ||
9110a741 | 520 | #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
73ffefd0 TT |
521 | /* |
522 | * Another special case for 2 word atomic objects: | |
523 | */ | |
524 | /*ARGSUSED*/ | |
9110a741 | 525 | ptr_t GC_reclaim_uninit2(hbp, hhdr, list COUNT_PARAM) |
73ffefd0 TT |
526 | register struct hblk *hbp; /* ptr to current heap block */ |
527 | hdr * hhdr; | |
73ffefd0 | 528 | register ptr_t list; |
9110a741 | 529 | COUNT_DECL |
73ffefd0 | 530 | { |
9110a741 | 531 | register word * mark_word_addr = &(hhdr->hb_marks[0]); |
73ffefd0 | 532 | register word *p, *plim; |
73ffefd0 TT |
533 | register word mark_word; |
534 | register int i; | |
9110a741 | 535 | NWORDS_DECL |
73ffefd0 TT |
536 | # define DO_OBJ(start_displ) \ |
537 | if (!(mark_word & ((word)1 << start_displ))) { \ | |
73ffefd0 TT |
538 | p[start_displ] = (word)list; \ |
539 | list = (ptr_t)(p+start_displ); \ | |
540 | INCR_WORDS(2); \ | |
541 | } | |
542 | ||
543 | p = (word *)(hbp->hb_body); | |
544 | plim = (word *)(((word)hbp) + HBLKSIZE); | |
545 | ||
546 | /* go through all words in block */ | |
547 | while( p < plim ) { | |
548 | mark_word = *mark_word_addr++; | |
549 | for (i = 0; i < WORDSZ; i += 8) { | |
550 | DO_OBJ(0); | |
551 | DO_OBJ(2); | |
552 | DO_OBJ(4); | |
553 | DO_OBJ(6); | |
554 | p += 8; | |
555 | mark_word >>= 8; | |
556 | } | |
557 | } | |
9110a741 | 558 | COUNT_UPDATE |
73ffefd0 TT |
559 | return(list); |
560 | # undef DO_OBJ | |
561 | } | |
562 | ||
563 | /* | |
564 | * Another special case for 4 word atomic objects: | |
565 | */ | |
566 | /*ARGSUSED*/ | |
9110a741 | 567 | ptr_t GC_reclaim_uninit4(hbp, hhdr, list COUNT_PARAM) |
73ffefd0 TT |
568 | register struct hblk *hbp; /* ptr to current heap block */ |
569 | hdr * hhdr; | |
73ffefd0 | 570 | register ptr_t list; |
9110a741 | 571 | COUNT_DECL |
73ffefd0 | 572 | { |
9110a741 | 573 | register word * mark_word_addr = &(hhdr->hb_marks[0]); |
73ffefd0 | 574 | register word *p, *plim; |
73ffefd0 | 575 | register word mark_word; |
9110a741 | 576 | NWORDS_DECL |
73ffefd0 TT |
577 | # define DO_OBJ(start_displ) \ |
578 | if (!(mark_word & ((word)1 << start_displ))) { \ | |
73ffefd0 TT |
579 | p[start_displ] = (word)list; \ |
580 | list = (ptr_t)(p+start_displ); \ | |
581 | INCR_WORDS(4); \ | |
582 | } | |
583 | ||
584 | p = (word *)(hbp->hb_body); | |
585 | plim = (word *)(((word)hbp) + HBLKSIZE); | |
586 | ||
587 | /* go through all words in block */ | |
588 | while( p < plim ) { | |
589 | mark_word = *mark_word_addr++; | |
590 | DO_OBJ(0); | |
591 | DO_OBJ(4); | |
592 | DO_OBJ(8); | |
593 | DO_OBJ(12); | |
594 | DO_OBJ(16); | |
595 | DO_OBJ(20); | |
596 | DO_OBJ(24); | |
597 | DO_OBJ(28); | |
598 | # if CPP_WORDSZ == 64 | |
599 | DO_OBJ(32); | |
600 | DO_OBJ(36); | |
601 | DO_OBJ(40); | |
602 | DO_OBJ(44); | |
603 | DO_OBJ(48); | |
604 | DO_OBJ(52); | |
605 | DO_OBJ(56); | |
606 | DO_OBJ(60); | |
607 | # endif | |
608 | p += WORDSZ; | |
609 | } | |
9110a741 | 610 | COUNT_UPDATE |
73ffefd0 TT |
611 | return(list); |
612 | # undef DO_OBJ | |
613 | } | |
614 | ||
615 | /* Finally the one word case, which never requires any clearing: */ | |
616 | /*ARGSUSED*/ | |
9110a741 | 617 | ptr_t GC_reclaim1(hbp, hhdr, list COUNT_PARAM) |
73ffefd0 TT |
618 | register struct hblk *hbp; /* ptr to current heap block */ |
619 | hdr * hhdr; | |
73ffefd0 | 620 | register ptr_t list; |
9110a741 | 621 | COUNT_DECL |
73ffefd0 | 622 | { |
9110a741 | 623 | register word * mark_word_addr = &(hhdr->hb_marks[0]); |
73ffefd0 | 624 | register word *p, *plim; |
73ffefd0 TT |
625 | register word mark_word; |
626 | register int i; | |
9110a741 | 627 | NWORDS_DECL |
73ffefd0 TT |
628 | # define DO_OBJ(start_displ) \ |
629 | if (!(mark_word & ((word)1 << start_displ))) { \ | |
73ffefd0 TT |
630 | p[start_displ] = (word)list; \ |
631 | list = (ptr_t)(p+start_displ); \ | |
632 | INCR_WORDS(1); \ | |
633 | } | |
634 | ||
635 | p = (word *)(hbp->hb_body); | |
636 | plim = (word *)(((word)hbp) + HBLKSIZE); | |
637 | ||
638 | /* go through all words in block */ | |
639 | while( p < plim ) { | |
640 | mark_word = *mark_word_addr++; | |
641 | for (i = 0; i < WORDSZ; i += 4) { | |
642 | DO_OBJ(0); | |
643 | DO_OBJ(1); | |
644 | DO_OBJ(2); | |
645 | DO_OBJ(3); | |
646 | p += 4; | |
647 | mark_word >>= 4; | |
648 | } | |
649 | } | |
9110a741 | 650 | COUNT_UPDATE |
73ffefd0 TT |
651 | return(list); |
652 | # undef DO_OBJ | |
653 | } | |
654 | ||
9110a741 | 655 | #endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
73ffefd0 TT |
656 | |
657 | /* | |
9110a741 BM |
658 | * Generic procedure to rebuild a free list in hbp. |
659 | * Also called directly from GC_malloc_many. | |
73ffefd0 | 660 | */ |
9110a741 BM |
661 | ptr_t GC_reclaim_generic(hbp, hhdr, sz, init, list COUNT_PARAM) |
662 | struct hblk *hbp; /* ptr to current heap block */ | |
663 | hdr * hhdr; | |
664 | GC_bool init; | |
665 | ptr_t list; | |
666 | word sz; | |
667 | COUNT_DECL | |
73ffefd0 | 668 | { |
9110a741 | 669 | ptr_t result = list; |
73ffefd0 | 670 | |
9110a741 | 671 | GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr); |
79f777fd | 672 | GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */); |
9110a741 | 673 | if (init) { |
73ffefd0 | 674 | switch(sz) { |
9110a741 | 675 | # if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
73ffefd0 | 676 | case 1: |
9110a741 BM |
677 | /* We now issue the hint even if GC_nearly_full returned */ |
678 | /* DONT_KNOW. */ | |
9110a741 | 679 | result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); |
73ffefd0 TT |
680 | break; |
681 | case 2: | |
9110a741 | 682 | result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG); |
73ffefd0 TT |
683 | break; |
684 | case 4: | |
9110a741 | 685 | result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG); |
73ffefd0 | 686 | break; |
9110a741 | 687 | # endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
73ffefd0 | 688 | default: |
9110a741 | 689 | result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG); |
73ffefd0 TT |
690 | break; |
691 | } | |
692 | } else { | |
79f777fd | 693 | GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */); |
73ffefd0 | 694 | switch(sz) { |
9110a741 | 695 | # if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
73ffefd0 | 696 | case 1: |
9110a741 | 697 | result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); |
73ffefd0 TT |
698 | break; |
699 | case 2: | |
9110a741 | 700 | result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG); |
73ffefd0 TT |
701 | break; |
702 | case 4: | |
9110a741 | 703 | result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG); |
73ffefd0 | 704 | break; |
9110a741 | 705 | # endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
73ffefd0 | 706 | default: |
9110a741 | 707 | result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG); |
73ffefd0 TT |
708 | break; |
709 | } | |
710 | } | |
9110a741 BM |
711 | if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr); |
712 | return result; | |
713 | } | |
714 | ||
715 | /* | |
716 | * Restore unmarked small objects in the block pointed to by hbp | |
717 | * to the appropriate object free list. | |
718 | * If entirely empty blocks are to be completely deallocated, then | |
719 | * caller should perform that check. | |
720 | */ | |
721 | void GC_reclaim_small_nonempty_block(hbp, report_if_found COUNT_PARAM) | |
722 | register struct hblk *hbp; /* ptr to current heap block */ | |
723 | int report_if_found; /* Abort if a reclaimable object is found */ | |
724 | COUNT_DECL | |
725 | { | |
726 | hdr *hhdr = HDR(hbp); | |
727 | word sz = hhdr -> hb_sz; | |
728 | int kind = hhdr -> hb_obj_kind; | |
729 | struct obj_kind * ok = &GC_obj_kinds[kind]; | |
730 | ptr_t * flh = &(ok -> ok_freelist[sz]); | |
731 | ||
732 | hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no; | |
733 | ||
734 | if (report_if_found) { | |
735 | GC_reclaim_check(hbp, hhdr, sz); | |
736 | } else { | |
4c7726b1 BM |
737 | *flh = GC_reclaim_generic(hbp, hhdr, sz, |
738 | (ok -> ok_init || GC_debugging_started), | |
9110a741 BM |
739 | *flh MEM_FOUND_ADDR); |
740 | } | |
73ffefd0 TT |
741 | } |
742 | ||
743 | /* | |
744 | * Restore an unmarked large object or an entirely empty blocks of small objects | |
745 | * to the heap block free list. | |
746 | * Otherwise enqueue the block for later processing | |
747 | * by GC_reclaim_small_nonempty_block. | |
20bbd3cd TT |
748 | * If report_if_found is TRUE, then process any block immediately, and |
749 | * simply report free objects; do not actually reclaim them. | |
73ffefd0 | 750 | */ |
9110a741 BM |
751 | # if defined(__STDC__) || defined(__cplusplus) |
752 | void GC_reclaim_block(register struct hblk *hbp, word report_if_found) | |
753 | # else | |
754 | void GC_reclaim_block(hbp, report_if_found) | |
755 | register struct hblk *hbp; /* ptr to current heap block */ | |
756 | word report_if_found; /* Abort if a reclaimable object is found */ | |
757 | # endif | |
73ffefd0 TT |
758 | { |
759 | register hdr * hhdr; | |
760 | register word sz; /* size of objects in current block */ | |
761 | register struct obj_kind * ok; | |
762 | struct hblk ** rlh; | |
763 | ||
764 | hhdr = HDR(hbp); | |
765 | sz = hhdr -> hb_sz; | |
766 | ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; | |
767 | ||
768 | if( sz > MAXOBJSZ ) { /* 1 big object */ | |
9110a741 | 769 | if( !mark_bit_from_hdr(hhdr, 0) ) { |
20bbd3cd | 770 | if (report_if_found) { |
9110a741 | 771 | FOUND_FREE(hbp, 0); |
20bbd3cd | 772 | } else { |
9110a741 BM |
773 | word blocks = OBJ_SZ_TO_BLOCKS(sz); |
774 | if (blocks > 1) { | |
775 | GC_large_allocd_bytes -= blocks * HBLKSIZE; | |
776 | } | |
20bbd3cd | 777 | # ifdef GATHERSTATS |
73ffefd0 | 778 | GC_mem_found += sz; |
20bbd3cd TT |
779 | # endif |
780 | GC_freehblk(hbp); | |
781 | } | |
73ffefd0 TT |
782 | } |
783 | } else { | |
784 | GC_bool empty = GC_block_empty(hhdr); | |
20bbd3cd | 785 | if (report_if_found) { |
9110a741 BM |
786 | GC_reclaim_small_nonempty_block(hbp, (int)report_if_found |
787 | MEM_FOUND_ADDR); | |
73ffefd0 TT |
788 | } else if (empty) { |
789 | # ifdef GATHERSTATS | |
790 | GC_mem_found += BYTES_TO_WORDS(HBLKSIZE); | |
791 | # endif | |
792 | GC_freehblk(hbp); | |
9110a741 | 793 | } else if (TRUE != GC_block_nearly_full(hhdr)){ |
73ffefd0 TT |
794 | /* group of smaller objects, enqueue the real work */ |
795 | rlh = &(ok -> ok_reclaim_list[sz]); | |
796 | hhdr -> hb_next = *rlh; | |
797 | *rlh = hbp; | |
9110a741 BM |
798 | } /* else not worth salvaging. */ |
799 | /* We used to do the nearly_full check later, but we */ | |
800 | /* already have the right cache context here. Also */ | |
801 | /* doing it here avoids some silly lock contention in */ | |
802 | /* GC_malloc_many. */ | |
73ffefd0 TT |
803 | } |
804 | } | |
805 | ||
806 | #if !defined(NO_DEBUGGING) | |
807 | /* Routines to gather and print heap block info */ | |
808 | /* intended for debugging. Otherwise should be called */ | |
809 | /* with lock. */ | |
4c7726b1 BM |
810 | |
811 | struct Print_stats | |
812 | { | |
813 | size_t number_of_blocks; | |
814 | size_t total_bytes; | |
815 | }; | |
73ffefd0 | 816 | |
9110a741 BM |
817 | #ifdef USE_MARK_BYTES |
818 | ||
819 | /* Return the number of set mark bits in the given header */ | |
820 | int GC_n_set_marks(hhdr) | |
821 | hdr * hhdr; | |
822 | { | |
823 | register int result = 0; | |
824 | register int i; | |
825 | ||
826 | for (i = 0; i < MARK_BITS_SZ; i++) { | |
827 | result += hhdr -> hb_marks[i]; | |
828 | } | |
829 | return(result); | |
830 | } | |
831 | ||
832 | #else | |
833 | ||
73ffefd0 TT |
834 | /* Number of set bits in a word. Not performance critical. */ |
835 | static int set_bits(n) | |
836 | word n; | |
837 | { | |
838 | register word m = n; | |
839 | register int result = 0; | |
840 | ||
841 | while (m > 0) { | |
842 | if (m & 1) result++; | |
843 | m >>= 1; | |
844 | } | |
845 | return(result); | |
846 | } | |
847 | ||
848 | /* Return the number of set mark bits in the given header */ | |
849 | int GC_n_set_marks(hhdr) | |
850 | hdr * hhdr; | |
851 | { | |
852 | register int result = 0; | |
853 | register int i; | |
854 | ||
855 | for (i = 0; i < MARK_BITS_SZ; i++) { | |
856 | result += set_bits(hhdr -> hb_marks[i]); | |
857 | } | |
858 | return(result); | |
859 | } | |
860 | ||
9110a741 BM |
861 | #endif /* !USE_MARK_BYTES */ |
862 | ||
73ffefd0 | 863 | /*ARGSUSED*/ |
9110a741 BM |
864 | # if defined(__STDC__) || defined(__cplusplus) |
865 | void GC_print_block_descr(struct hblk *h, word dummy) | |
866 | # else | |
867 | void GC_print_block_descr(h, dummy) | |
868 | struct hblk *h; | |
869 | word dummy; | |
870 | # endif | |
73ffefd0 TT |
871 | { |
872 | register hdr * hhdr = HDR(h); | |
873 | register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz); | |
4c7726b1 | 874 | struct Print_stats *ps; |
73ffefd0 TT |
875 | |
876 | GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind), | |
877 | (unsigned long)bytes, | |
878 | (unsigned long)(GC_n_set_marks(hhdr))); | |
9110a741 | 879 | bytes += HBLKSIZE-1; |
73ffefd0 | 880 | bytes &= ~(HBLKSIZE-1); |
4c7726b1 BM |
881 | |
882 | ps = (struct Print_stats *)dummy; | |
883 | ps->total_bytes += bytes; | |
884 | ps->number_of_blocks++; | |
73ffefd0 TT |
885 | } |
886 | ||
887 | void GC_print_block_list() | |
888 | { | |
4c7726b1 BM |
889 | struct Print_stats pstats; |
890 | ||
73ffefd0 | 891 | GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n"); |
4c7726b1 BM |
892 | pstats.number_of_blocks = 0; |
893 | pstats.total_bytes = 0; | |
894 | GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats); | |
73ffefd0 | 895 | GC_printf2("\nblocks = %lu, bytes = %lu\n", |
4c7726b1 BM |
896 | (unsigned long)pstats.number_of_blocks, |
897 | (unsigned long)pstats.total_bytes); | |
73ffefd0 TT |
898 | } |
899 | ||
900 | #endif /* NO_DEBUGGING */ | |
901 | ||
4d6ac542 HB |
902 | /* |
903 | * Clear all obj_link pointers in the list of free objects *flp. | |
904 | * Clear *flp. | |
905 | * This must be done before dropping a list of free gcj-style objects, | |
906 | * since may otherwise end up with dangling "descriptor" pointers. | |
30c3de1f | 907 | * It may help for other pointer-containing objects. |
4d6ac542 HB |
908 | */ |
909 | void GC_clear_fl_links(flp) | |
910 | ptr_t *flp; | |
911 | { | |
912 | ptr_t next = *flp; | |
913 | ||
914 | while (0 != next) { | |
915 | *flp = 0; | |
916 | flp = &(obj_link(next)); | |
917 | next = *flp; | |
918 | } | |
919 | } | |
920 | ||
73ffefd0 | 921 | /* |
20bbd3cd TT |
922 | * Perform GC_reclaim_block on the entire heap, after first clearing |
923 | * small object free lists (if we are not just looking for leaks). | |
73ffefd0 | 924 | */ |
20bbd3cd TT |
925 | void GC_start_reclaim(report_if_found) |
926 | int report_if_found; /* Abort if a GC_reclaimable object is found */ | |
73ffefd0 TT |
927 | { |
928 | int kind; | |
929 | ||
5a2586cf TT |
930 | # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
931 | GC_ASSERT(0 == GC_fl_builder_count); | |
932 | # endif | |
73ffefd0 TT |
933 | /* Clear reclaim- and free-lists */ |
934 | for (kind = 0; kind < GC_n_kinds; kind++) { | |
4d6ac542 HB |
935 | ptr_t *fop; |
936 | ptr_t *lim; | |
937 | struct hblk ** rlp; | |
938 | struct hblk ** rlim; | |
939 | struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; | |
940 | GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0); | |
73ffefd0 TT |
941 | |
942 | if (rlist == 0) continue; /* This kind not used. */ | |
20bbd3cd | 943 | if (!report_if_found) { |
73ffefd0 TT |
944 | lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]); |
945 | for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) { | |
4d6ac542 HB |
946 | if (*fop != 0) { |
947 | if (should_clobber) { | |
948 | GC_clear_fl_links(fop); | |
949 | } else { | |
950 | *fop = 0; | |
951 | } | |
952 | } | |
73ffefd0 TT |
953 | } |
954 | } /* otherwise free list objects are marked, */ | |
955 | /* and its safe to leave them */ | |
956 | rlim = rlist + MAXOBJSZ+1; | |
957 | for( rlp = rlist; rlp < rlim; rlp++ ) { | |
958 | *rlp = 0; | |
959 | } | |
960 | } | |
961 | ||
962 | # ifdef PRINTBLOCKS | |
963 | GC_printf0("GC_reclaim: current block sizes:\n"); | |
964 | GC_print_block_list(); | |
965 | # endif | |
966 | ||
967 | /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ | |
968 | /* or enqueue the block for later processing. */ | |
20bbd3cd | 969 | GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found); |
93002327 BM |
970 | |
971 | # ifdef EAGER_SWEEP | |
972 | /* This is a very stupid thing to do. We make it possible anyway, */ | |
973 | /* so that you can convince yourself that it really is very stupid. */ | |
974 | GC_reclaim_all((GC_stop_func)0, FALSE); | |
975 | # endif | |
5a2586cf TT |
976 | # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
977 | GC_ASSERT(0 == GC_fl_builder_count); | |
978 | # endif | |
73ffefd0 TT |
979 | |
980 | } | |
981 | ||
982 | /* | |
983 | * Sweep blocks of the indicated object size and kind until either the | |
984 | * appropriate free list is nonempty, or there are no more blocks to | |
985 | * sweep. | |
986 | */ | |
987 | void GC_continue_reclaim(sz, kind) | |
988 | word sz; /* words */ | |
989 | int kind; | |
990 | { | |
991 | register hdr * hhdr; | |
992 | register struct hblk * hbp; | |
993 | register struct obj_kind * ok = &(GC_obj_kinds[kind]); | |
994 | struct hblk ** rlh = ok -> ok_reclaim_list; | |
995 | ptr_t *flh = &(ok -> ok_freelist[sz]); | |
996 | ||
997 | if (rlh == 0) return; /* No blocks of this kind. */ | |
998 | rlh += sz; | |
999 | while ((hbp = *rlh) != 0) { | |
1000 | hhdr = HDR(hbp); | |
1001 | *rlh = hhdr -> hb_next; | |
9110a741 | 1002 | GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR); |
73ffefd0 TT |
1003 | if (*flh != 0) break; |
1004 | } | |
1005 | } | |
1006 | ||
1007 | /* | |
1008 | * Reclaim all small blocks waiting to be reclaimed. | |
1009 | * Abort and return FALSE when/if (*stop_func)() returns TRUE. | |
1010 | * If this returns TRUE, then it's safe to restart the world | |
1011 | * with incorrectly cleared mark bits. | |
93002327 | 1012 | * If ignore_old is TRUE, then reclaim only blocks that have been |
73ffefd0 TT |
1013 | * recently reclaimed, and discard the rest. |
1014 | * Stop_func may be 0. | |
1015 | */ | |
1016 | GC_bool GC_reclaim_all(stop_func, ignore_old) | |
1017 | GC_stop_func stop_func; | |
1018 | GC_bool ignore_old; | |
1019 | { | |
1020 | register word sz; | |
1021 | register int kind; | |
1022 | register hdr * hhdr; | |
1023 | register struct hblk * hbp; | |
1024 | register struct obj_kind * ok; | |
1025 | struct hblk ** rlp; | |
1026 | struct hblk ** rlh; | |
1027 | # ifdef PRINTTIMES | |
1028 | CLOCK_TYPE start_time; | |
1029 | CLOCK_TYPE done_time; | |
1030 | ||
1031 | GET_TIME(start_time); | |
1032 | # endif | |
1033 | ||
1034 | for (kind = 0; kind < GC_n_kinds; kind++) { | |
1035 | ok = &(GC_obj_kinds[kind]); | |
1036 | rlp = ok -> ok_reclaim_list; | |
1037 | if (rlp == 0) continue; | |
1038 | for (sz = 1; sz <= MAXOBJSZ; sz++) { | |
1039 | rlh = rlp + sz; | |
1040 | while ((hbp = *rlh) != 0) { | |
1041 | if (stop_func != (GC_stop_func)0 && (*stop_func)()) { | |
1042 | return(FALSE); | |
1043 | } | |
1044 | hhdr = HDR(hbp); | |
1045 | *rlh = hhdr -> hb_next; | |
1046 | if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) { | |
1047 | /* It's likely we'll need it this time, too */ | |
1048 | /* It's been touched recently, so this */ | |
1049 | /* shouldn't trigger paging. */ | |
9110a741 | 1050 | GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR); |
73ffefd0 TT |
1051 | } |
1052 | } | |
1053 | } | |
1054 | } | |
1055 | # ifdef PRINTTIMES | |
1056 | GET_TIME(done_time); | |
1057 | GC_printf1("Disposing of reclaim lists took %lu msecs\n", | |
1058 | MS_TIME_DIFF(done_time,start_time)); | |
1059 | # endif | |
1060 | return(TRUE); | |
1061 | } |