Annotation of OpenXM_contrib2/asir2000/gc/mark.c, Revision 1.7
1.1 noro 1:
2: /*
3: * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
4: * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
1.4 noro 5: * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
1.1 noro 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: *
16: */
17:
18:
19: # include <stdio.h>
1.4 noro 20: # include "private/gc_pmark.h"
1.1 noro 21:
1.7 ! noro 22: #if defined(MSWIN32) && defined(__GNUC__)
! 23: # include <excpt.h>
! 24: #endif
! 25:
1.1 noro 26: /* We put this here to minimize the risk of inlining. */
27: /*VARARGS*/
28: #ifdef __WATCOMC__
29: void GC_noop(void *p, ...) {}
30: #else
31: void GC_noop() {}
32: #endif
33:
34: /* Single argument version, robust against whole program analysis. */
35: void GC_noop1(x)
36: word x;
37: {
38: static VOLATILE word sink;
39:
40: sink = x;
41: }
42:
43: /* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
44:
1.3 noro 45: word GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
1.1 noro 46:
47: /* Initialize GC_obj_kinds properly and standard free lists properly. */
48: /* This must be done statically since they may be accessed before */
49: /* GC_init is called. */
50: /* It's done here, since we need to deal with mark descriptors. */
51: struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
52: /* PTRFREE */ { &GC_aobjfreelist[0], 0 /* filled in dynamically */,
1.4 noro 53: 0 | GC_DS_LENGTH, FALSE, FALSE },
1.1 noro 54: /* NORMAL */ { &GC_objfreelist[0], 0,
1.4 noro 55: 0 | GC_DS_LENGTH, /* Adjusted in GC_init_inner for EXTRA_BYTES */
1.1 noro 56: TRUE /* add length to descr */, TRUE },
57: /* UNCOLLECTABLE */
58: { &GC_uobjfreelist[0], 0,
1.4 noro 59: 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE },
1.1 noro 60: # ifdef ATOMIC_UNCOLLECTABLE
61: /* AUNCOLLECTABLE */
62: { &GC_auobjfreelist[0], 0,
1.4 noro 63: 0 | GC_DS_LENGTH, FALSE /* add length to descr */, FALSE },
1.1 noro 64: # endif
65: # ifdef STUBBORN_ALLOC
66: /*STUBBORN*/ { &GC_sobjfreelist[0], 0,
1.4 noro 67: 0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE },
1.1 noro 68: # endif
69: };
70:
71: # ifdef ATOMIC_UNCOLLECTABLE
72: # ifdef STUBBORN_ALLOC
73: int GC_n_kinds = 5;
74: # else
75: int GC_n_kinds = 4;
76: # endif
77: # else
78: # ifdef STUBBORN_ALLOC
79: int GC_n_kinds = 4;
80: # else
81: int GC_n_kinds = 3;
82: # endif
83: # endif
84:
85:
86: # ifndef INITIAL_MARK_STACK_SIZE
87: # define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
88: /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a */
89: /* multiple of HBLKSIZE. */
1.2 noro 90: /* The incremental collector actually likes a larger */
91: /* size, since it want to push all marked dirty objs */
92: /* before marking anything new. Currently we let it */
93: /* grow dynamically. */
1.1 noro 94: # endif
95:
96: /*
97: * Limits of stack for GC_mark routine.
98: * All ranges between GC_mark_stack(incl.) and GC_mark_stack_top(incl.) still
99: * need to be marked from.
100: */
101:
102: word GC_n_rescuing_pages; /* Number of dirty pages we marked from */
103: /* excludes ptrfree pages, etc. */
104:
105: mse * GC_mark_stack;
106:
1.4 noro 107: mse * GC_mark_stack_limit;
108:
1.1 noro 109: word GC_mark_stack_size = 0;
110:
1.4 noro 111: #ifdef PARALLEL_MARK
112: mse * VOLATILE GC_mark_stack_top;
113: #else
114: mse * GC_mark_stack_top;
115: #endif
1.1 noro 116:
117: static struct hblk * scan_ptr;
118:
119: mark_state_t GC_mark_state = MS_NONE;
120:
121: GC_bool GC_mark_stack_too_small = FALSE;
122:
123: GC_bool GC_objects_are_marked = FALSE; /* Are there collectable marked */
124: /* objects in the heap? */
125:
126: /* Is a collection in progress? Note that this can return true in the */
127: /* nonincremental case, if a collection has been abandoned and the */
128: /* mark state is now MS_INVALID. */
129: GC_bool GC_collection_in_progress()
130: {
131: return(GC_mark_state != MS_NONE);
132: }
133:
134: /* clear all mark bits in the header */
135: void GC_clear_hdr_marks(hhdr)
136: register hdr * hhdr;
137: {
1.4 noro 138: # ifdef USE_MARK_BYTES
139: BZERO(hhdr -> hb_marks, MARK_BITS_SZ);
140: # else
141: BZERO(hhdr -> hb_marks, MARK_BITS_SZ*sizeof(word));
142: # endif
1.1 noro 143: }
144:
145: /* Set all mark bits in the header. Used for uncollectable blocks. */
146: void GC_set_hdr_marks(hhdr)
147: register hdr * hhdr;
148: {
149: register int i;
150:
151: for (i = 0; i < MARK_BITS_SZ; ++i) {
1.4 noro 152: # ifdef USE_MARK_BYTES
153: hhdr -> hb_marks[i] = 1;
154: # else
1.1 noro 155: hhdr -> hb_marks[i] = ONES;
1.4 noro 156: # endif
1.1 noro 157: }
158: }
159:
160: /*
161: * Clear all mark bits associated with block h.
162: */
163: /*ARGSUSED*/
1.4 noro 164: # if defined(__STDC__) || defined(__cplusplus)
165: static void clear_marks_for_block(struct hblk *h, word dummy)
166: # else
167: static void clear_marks_for_block(h, dummy)
168: struct hblk *h;
169: word dummy;
170: # endif
1.1 noro 171: {
172: register hdr * hhdr = HDR(h);
173:
174: if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) return;
175: /* Mark bit for these is cleared only once the object is */
176: /* explicitly deallocated. This either frees the block, or */
177: /* the bit is cleared once the object is on the free list. */
178: GC_clear_hdr_marks(hhdr);
179: }
180:
181: /* Slow but general routines for setting/clearing/asking about mark bits */
182: void GC_set_mark_bit(p)
183: ptr_t p;
184: {
185: register struct hblk *h = HBLKPTR(p);
186: register hdr * hhdr = HDR(h);
187: register int word_no = (word *)p - (word *)h;
188:
189: set_mark_bit_from_hdr(hhdr, word_no);
190: }
191:
192: void GC_clear_mark_bit(p)
193: ptr_t p;
194: {
195: register struct hblk *h = HBLKPTR(p);
196: register hdr * hhdr = HDR(h);
197: register int word_no = (word *)p - (word *)h;
198:
199: clear_mark_bit_from_hdr(hhdr, word_no);
200: }
201:
202: GC_bool GC_is_marked(p)
203: ptr_t p;
204: {
205: register struct hblk *h = HBLKPTR(p);
206: register hdr * hhdr = HDR(h);
207: register int word_no = (word *)p - (word *)h;
208:
209: return(mark_bit_from_hdr(hhdr, word_no));
210: }
211:
212:
213: /*
214: * Clear mark bits in all allocated heap blocks. This invalidates
215: * the marker invariant, and sets GC_mark_state to reflect this.
216: * (This implicitly starts marking to reestablish the invariant.)
217: */
218: void GC_clear_marks()
219: {
220: GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
221: GC_objects_are_marked = FALSE;
222: GC_mark_state = MS_INVALID;
223: scan_ptr = 0;
224: # ifdef GATHERSTATS
225: /* Counters reflect currently marked objects: reset here */
226: GC_composite_in_use = 0;
227: GC_atomic_in_use = 0;
228: # endif
229:
230: }
231:
232: /* Initiate a garbage collection. Initiates a full collection if the */
233: /* mark state is invalid. */
234: /*ARGSUSED*/
235: void GC_initiate_gc()
236: {
237: if (GC_dirty_maintained) GC_read_dirty();
238: # ifdef STUBBORN_ALLOC
239: GC_read_changed();
240: # endif
241: # ifdef CHECKSUMS
242: {
243: extern void GC_check_dirty();
244:
245: if (GC_dirty_maintained) GC_check_dirty();
246: }
247: # endif
1.4 noro 248: GC_n_rescuing_pages = 0;
1.1 noro 249: if (GC_mark_state == MS_NONE) {
250: GC_mark_state = MS_PUSH_RESCUERS;
251: } else if (GC_mark_state != MS_INVALID) {
252: ABORT("unexpected state");
253: } /* else this is really a full collection, and mark */
254: /* bits are invalid. */
255: scan_ptr = 0;
256: }
257:
258:
259: static void alloc_mark_stack();
260:
261: /* Perform a small amount of marking. */
262: /* We try to touch roughly a page of memory. */
263: /* Return TRUE if we just finished a mark phase. */
264: /* Cold_gc_frame is an address inside a GC frame that */
265: /* remains valid until all marking is complete. */
266: /* A zero value indicates that it's OK to miss some */
267: /* register values. */
1.7 ! noro 268: /* We hold the allocation lock. In the case of */
! 269: /* incremental collection, the world may not be stopped.*/
! 270: #ifdef MSWIN32
! 271: /* For win32, this is called after we establish a structured */
! 272: /* exception handler, in case Windows unmaps one of our root */
! 273: /* segments. See below. In either case, we acquire the */
! 274: /* allocator lock long before we get here. */
! 275: GC_bool GC_mark_some_inner(cold_gc_frame)
! 276: ptr_t cold_gc_frame;
! 277: #else
! 278: GC_bool GC_mark_some(cold_gc_frame)
! 279: ptr_t cold_gc_frame;
! 280: #endif
1.1 noro 281: {
282: switch(GC_mark_state) {
283: case MS_NONE:
284: return(FALSE);
285:
286: case MS_PUSH_RESCUERS:
287: if (GC_mark_stack_top
1.4 noro 288: >= GC_mark_stack_limit - INITIAL_MARK_STACK_SIZE/2) {
1.2 noro 289: /* Go ahead and mark, even though that might cause us to */
290: /* see more marked dirty objects later on. Avoid this */
291: /* in the future. */
292: GC_mark_stack_too_small = TRUE;
1.4 noro 293: MARK_FROM_MARK_STACK();
1.1 noro 294: return(FALSE);
295: } else {
296: scan_ptr = GC_push_next_marked_dirty(scan_ptr);
297: if (scan_ptr == 0) {
1.4 noro 298: # ifdef CONDPRINT
299: if (GC_print_stats) {
1.1 noro 300: GC_printf1("Marked from %lu dirty pages\n",
301: (unsigned long)GC_n_rescuing_pages);
1.4 noro 302: }
1.1 noro 303: # endif
304: GC_push_roots(FALSE, cold_gc_frame);
305: GC_objects_are_marked = TRUE;
306: if (GC_mark_state != MS_INVALID) {
307: GC_mark_state = MS_ROOTS_PUSHED;
308: }
309: }
310: }
311: return(FALSE);
312:
313: case MS_PUSH_UNCOLLECTABLE:
314: if (GC_mark_stack_top
1.4 noro 315: >= GC_mark_stack + GC_mark_stack_size/4) {
316: # ifdef PARALLEL_MARK
317: /* Avoid this, since we don't parallelize the marker */
318: /* here. */
319: if (GC_parallel) GC_mark_stack_too_small = TRUE;
320: # endif
321: MARK_FROM_MARK_STACK();
1.1 noro 322: return(FALSE);
323: } else {
324: scan_ptr = GC_push_next_marked_uncollectable(scan_ptr);
325: if (scan_ptr == 0) {
326: GC_push_roots(TRUE, cold_gc_frame);
327: GC_objects_are_marked = TRUE;
328: if (GC_mark_state != MS_INVALID) {
329: GC_mark_state = MS_ROOTS_PUSHED;
330: }
331: }
332: }
333: return(FALSE);
334:
335: case MS_ROOTS_PUSHED:
1.4 noro 336: # ifdef PARALLEL_MARK
337: /* In the incremental GC case, this currently doesn't */
338: /* quite do the right thing, since it runs to */
339: /* completion. On the other hand, starting a */
340: /* parallel marker is expensive, so perhaps it is */
341: /* the right thing? */
342: /* Eventually, incremental marking should run */
343: /* asynchronously in multiple threads, without grabbing */
344: /* the allocation lock. */
345: if (GC_parallel) {
346: GC_do_parallel_mark();
347: GC_ASSERT(GC_mark_stack_top < GC_first_nonempty);
348: GC_mark_stack_top = GC_mark_stack - 1;
349: if (GC_mark_stack_too_small) {
350: alloc_mark_stack(2*GC_mark_stack_size);
351: }
352: if (GC_mark_state == MS_ROOTS_PUSHED) {
353: GC_mark_state = MS_NONE;
354: return(TRUE);
355: } else {
356: return(FALSE);
357: }
358: }
359: # endif
1.1 noro 360: if (GC_mark_stack_top >= GC_mark_stack) {
1.4 noro 361: MARK_FROM_MARK_STACK();
1.1 noro 362: return(FALSE);
363: } else {
364: GC_mark_state = MS_NONE;
365: if (GC_mark_stack_too_small) {
366: alloc_mark_stack(2*GC_mark_stack_size);
367: }
368: return(TRUE);
369: }
370:
371: case MS_INVALID:
372: case MS_PARTIALLY_INVALID:
373: if (!GC_objects_are_marked) {
374: GC_mark_state = MS_PUSH_UNCOLLECTABLE;
375: return(FALSE);
376: }
377: if (GC_mark_stack_top >= GC_mark_stack) {
1.4 noro 378: MARK_FROM_MARK_STACK();
1.1 noro 379: return(FALSE);
380: }
381: if (scan_ptr == 0 && GC_mark_state == MS_INVALID) {
382: /* About to start a heap scan for marked objects. */
383: /* Mark stack is empty. OK to reallocate. */
384: if (GC_mark_stack_too_small) {
385: alloc_mark_stack(2*GC_mark_stack_size);
386: }
387: GC_mark_state = MS_PARTIALLY_INVALID;
388: }
389: scan_ptr = GC_push_next_marked(scan_ptr);
390: if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) {
391: GC_push_roots(TRUE, cold_gc_frame);
392: GC_objects_are_marked = TRUE;
393: if (GC_mark_state != MS_INVALID) {
394: GC_mark_state = MS_ROOTS_PUSHED;
395: }
396: }
397: return(FALSE);
398: default:
399: ABORT("GC_mark_some: bad state");
400: return(FALSE);
401: }
1.7 ! noro 402: }
! 403:
! 404:
! 405: #ifdef MSWIN32
! 406:
! 407: # ifdef __GNUC__
! 408:
! 409: typedef struct {
! 410: EXCEPTION_REGISTRATION ex_reg;
! 411: void *alt_path;
! 412: } ext_ex_regn;
! 413:
! 414:
! 415: static EXCEPTION_DISPOSITION mark_ex_handler(
! 416: struct _EXCEPTION_RECORD *ex_rec,
! 417: void *est_frame,
! 418: struct _CONTEXT *context,
! 419: void *disp_ctxt)
! 420: {
! 421: if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) {
! 422: ext_ex_regn *xer = (ext_ex_regn *)est_frame;
! 423:
! 424: /* Unwind from the inner function assuming the standard */
! 425: /* function prologue. */
! 426: /* Assumes code has not been compiled with */
! 427: /* -fomit-frame-pointer. */
! 428: context->Esp = context->Ebp;
! 429: context->Ebp = *((DWORD *)context->Esp);
! 430: context->Esp = context->Esp - 8;
! 431:
! 432: /* Resume execution at the "real" handler within the */
! 433: /* wrapper function. */
! 434: context->Eip = (DWORD )(xer->alt_path);
! 435:
! 436: return ExceptionContinueExecution;
! 437:
! 438: } else {
! 439: return ExceptionContinueSearch;
! 440: }
! 441: }
! 442: # endif /* __GNUC__ */
! 443:
! 444:
! 445: GC_bool GC_mark_some(cold_gc_frame)
! 446: ptr_t cold_gc_frame;
! 447: {
! 448: GC_bool ret_val;
! 449:
! 450: # ifndef __GNUC__
! 451: /* Windows 98 appears to asynchronously create and remove */
! 452: /* writable memory mappings, for reasons we haven't yet */
! 453: /* understood. Since we look for writable regions to */
! 454: /* determine the root set, we may try to mark from an */
! 455: /* address range that disappeared since we started the */
! 456: /* collection. Thus we have to recover from faults here. */
! 457: /* This code does not appear to be necessary for Windows */
! 458: /* 95/NT/2000. Note that this code should never generate */
! 459: /* an incremental GC write fault. */
! 460:
! 461: __try {
! 462:
! 463: # else /* __GNUC__ */
! 464:
! 465: /* Manually install an exception handler since GCC does */
! 466: /* not yet support Structured Exception Handling (SEH) on */
! 467: /* Win32. */
! 468:
! 469: ext_ex_regn er;
! 470:
! 471: er.alt_path = &&handle_ex;
! 472: er.ex_reg.handler = mark_ex_handler;
! 473: asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
! 474: asm volatile ("movl %0, %%fs:0" : : "r" (&er));
! 475:
! 476: # endif /* __GNUC__ */
! 477:
! 478: ret_val = GC_mark_some_inner(cold_gc_frame);
! 479:
! 480: # ifndef __GNUC__
! 481:
! 482: } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
! 483: EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
! 484:
! 485: # else /* __GNUC__ */
! 486:
! 487: /* Prevent GCC from considering the following code unreachable */
! 488: /* and thus eliminating it. */
! 489: if (er.alt_path != 0)
! 490: goto rm_handler;
! 491:
! 492: handle_ex:
! 493: /* Execution resumes from here on an access violation. */
! 494:
! 495: # endif /* __GNUC__ */
! 496:
! 497: # ifdef CONDPRINT
! 498: if (GC_print_stats) {
! 499: GC_printf0("Caught ACCESS_VIOLATION in marker. "
! 500: "Memory mapping disappeared.\n");
! 501: }
! 502: # endif /* CONDPRINT */
! 503:
! 504: /* We have bad roots on the stack. Discard mark stack. */
! 505: /* Rescan from marked objects. Redetermine roots. */
! 506: GC_invalidate_mark_state();
! 507: scan_ptr = 0;
! 508:
! 509: ret_val = FALSE;
! 510:
! 511: # ifndef __GNUC__
! 512:
1.4 noro 513: }
1.7 ! noro 514:
! 515: # else /* __GNUC__ */
! 516:
! 517: rm_handler:
! 518: /* Uninstall the exception handler */
! 519: asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
! 520:
! 521: # endif /* __GNUC__ */
! 522:
! 523: return ret_val;
1.3 noro 524: }
1.7 ! noro 525: #endif /* MSWIN32 */
1.1 noro 526:
527:
528: GC_bool GC_mark_stack_empty()
529: {
530: return(GC_mark_stack_top < GC_mark_stack);
531: }
532:
533: #ifdef PROF_MARKER
534: word GC_prof_array[10];
535: # define PROF(n) GC_prof_array[n]++
536: #else
537: # define PROF(n)
538: #endif
539:
540: /* Given a pointer to someplace other than a small object page or the */
1.6 noro 541: /* first page of a large object, either: */
542: /* - return a pointer to somewhere in the first page of the large */
543: /* object, if current points to a large object. */
544: /* In this case *hhdr is replaced with a pointer to the header */
545: /* for the large object. */
546: /* - just return current if it does not point to a large object. */
1.1 noro 547: /*ARGSUSED*/
1.6 noro 548: ptr_t GC_find_start(current, hhdr, new_hdr_p)
1.3 noro 549: register ptr_t current;
1.6 noro 550: register hdr *hhdr, **new_hdr_p;
1.1 noro 551: {
1.4 noro 552: if (GC_all_interior_pointers) {
1.1 noro 553: if (hhdr != 0) {
1.3 noro 554: register ptr_t orig = current;
1.1 noro 555:
1.4 noro 556: current = (ptr_t)HBLKPTR(current);
1.1 noro 557: do {
558: current = current - HBLKSIZE*(word)hhdr;
559: hhdr = HDR(current);
560: } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
561: /* current points to the start of the large object */
562: if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(0);
563: if ((word *)orig - (word *)current
564: >= (ptrdiff_t)(hhdr->hb_sz)) {
565: /* Pointer past the end of the block */
1.6 noro 566: return(orig);
1.1 noro 567: }
1.6 noro 568: *new_hdr_p = hhdr;
1.1 noro 569: return(current);
570: } else {
1.6 noro 571: return(current);
1.1 noro 572: }
1.4 noro 573: } else {
1.6 noro 574: return(current);
1.4 noro 575: }
1.1 noro 576: }
577:
578: void GC_invalidate_mark_state()
579: {
580: GC_mark_state = MS_INVALID;
581: GC_mark_stack_top = GC_mark_stack-1;
582: }
583:
584: mse * GC_signal_mark_stack_overflow(msp)
585: mse * msp;
586: {
587: GC_mark_state = MS_INVALID;
588: GC_mark_stack_too_small = TRUE;
1.4 noro 589: # ifdef CONDPRINT
590: if (GC_print_stats) {
1.1 noro 591: GC_printf1("Mark stack overflow; current size = %lu entries\n",
592: GC_mark_stack_size);
1.4 noro 593: }
594: # endif
595: return(msp - GC_MARK_STACK_DISCARDS);
1.1 noro 596: }
597:
598: /*
599: * Mark objects pointed to by the regions described by
600: * mark stack entries between GC_mark_stack and GC_mark_stack_top,
601: * inclusive. Assumes the upper limit of a mark stack entry
602: * is never 0. A mark stack entry never has size 0.
603: * We try to traverse on the order of a hblk of memory before we return.
604: * Caller is responsible for calling this until the mark stack is empty.
1.3 noro 605: * Note that this is the most performance critical routine in the
606: * collector. Hence it contains all sorts of ugly hacks to speed
607: * things up. In particular, we avoid procedure calls on the common
608: * path, we take advantage of peculiarities of the mark descriptor
609: * encoding, we optionally maintain a cache for the block address to
610: * header mapping, we prefetch when an object is "grayed", etc.
1.1 noro 611: */
1.4 noro 612: mse * GC_mark_from(mark_stack_top, mark_stack, mark_stack_limit)
613: mse * mark_stack_top;
614: mse * mark_stack;
615: mse * mark_stack_limit;
1.1 noro 616: {
617: int credit = HBLKSIZE; /* Remaining credit for marking work */
618: register word * current_p; /* Pointer to current candidate ptr. */
619: register word current; /* Candidate pointer. */
620: register word * limit; /* (Incl) limit of current candidate */
621: /* range */
622: register word descr;
623: register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
624: register ptr_t least_ha = GC_least_plausible_heap_addr;
1.3 noro 625: DECLARE_HDR_CACHE;
626:
1.1 noro 627: # define SPLIT_RANGE_WORDS 128 /* Must be power of 2. */
628:
629: GC_objects_are_marked = TRUE;
1.3 noro 630: INIT_HDR_CACHE;
1.1 noro 631: # ifdef OS2 /* Use untweaked version to circumvent compiler problem */
1.4 noro 632: while (mark_stack_top >= mark_stack && credit >= 0) {
1.1 noro 633: # else
1.4 noro 634: while ((((ptr_t)mark_stack_top - (ptr_t)mark_stack) | credit)
1.1 noro 635: >= 0) {
636: # endif
1.4 noro 637: current_p = mark_stack_top -> mse_start;
638: descr = mark_stack_top -> mse_descr;
1.1 noro 639: retry:
1.3 noro 640: /* current_p and descr describe the current object. */
1.4 noro 641: /* *mark_stack_top is vacant. */
1.3 noro 642: /* The following is 0 only for small objects described by a simple */
643: /* length descriptor. For many applications this is the common */
644: /* case, so we try to detect it quickly. */
1.4 noro 645: if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | GC_DS_TAGS)) {
646: word tag = descr & GC_DS_TAGS;
1.1 noro 647:
648: switch(tag) {
1.4 noro 649: case GC_DS_LENGTH:
1.1 noro 650: /* Large length. */
651: /* Process part of the range to avoid pushing too much on the */
652: /* stack. */
1.7 ! noro 653: GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
! 654: - (word)GC_least_plausible_heap_addr);
1.4 noro 655: # ifdef PARALLEL_MARK
656: # define SHARE_BYTES 2048
657: if (descr > SHARE_BYTES && GC_parallel
658: && mark_stack_top < mark_stack_limit - 1) {
659: int new_size = (descr/2) & ~(sizeof(word)-1);
660: mark_stack_top -> mse_start = current_p;
661: mark_stack_top -> mse_descr = new_size + sizeof(word);
662: /* makes sure we handle */
663: /* misaligned pointers. */
664: mark_stack_top++;
665: current_p = (word *) ((char *)current_p + new_size);
666: descr -= new_size;
667: goto retry;
668: }
669: # endif /* PARALLEL_MARK */
670: mark_stack_top -> mse_start =
1.1 noro 671: limit = current_p + SPLIT_RANGE_WORDS-1;
1.4 noro 672: mark_stack_top -> mse_descr =
1.3 noro 673: descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
1.1 noro 674: /* Make sure that pointers overlapping the two ranges are */
675: /* considered. */
676: limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT);
677: break;
1.4 noro 678: case GC_DS_BITMAP:
679: mark_stack_top--;
680: descr &= ~GC_DS_TAGS;
1.1 noro 681: credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */
682: while (descr != 0) {
683: if ((signed_word)descr < 0) {
684: current = *current_p;
1.7 ! noro 685: FIXUP_POINTER(current);
1.1 noro 686: if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
1.3 noro 687: PREFETCH(current);
1.4 noro 688: HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
1.3 noro 689: mark_stack_limit, current_p, exit1);
1.1 noro 690: }
691: }
692: descr <<= 1;
693: ++ current_p;
694: }
695: continue;
1.4 noro 696: case GC_DS_PROC:
697: mark_stack_top--;
698: credit -= GC_PROC_BYTES;
699: mark_stack_top =
1.1 noro 700: (*PROC(descr))
1.4 noro 701: (current_p, mark_stack_top,
1.1 noro 702: mark_stack_limit, ENV(descr));
703: continue;
1.4 noro 704: case GC_DS_PER_OBJECT:
1.3 noro 705: if ((signed_word)descr >= 0) {
706: /* Descriptor is in the object. */
1.4 noro 707: descr = *(word *)((ptr_t)current_p + descr - GC_DS_PER_OBJECT);
1.3 noro 708: } else {
709: /* Descriptor is in type descriptor pointed to by first */
710: /* word in object. */
711: ptr_t type_descr = *(ptr_t *)current_p;
712: /* type_descr is either a valid pointer to the descriptor */
713: /* structure, or this object was on a free list. If it */
714: /* it was anything but the last object on the free list, */
715: /* we will misinterpret the next object on the free list as */
716: /* the type descriptor, and get a 0 GC descriptor, which */
717: /* is ideal. Unfortunately, we need to check for the last */
718: /* object case explicitly. */
719: if (0 == type_descr) {
720: /* Rarely executed. */
1.4 noro 721: mark_stack_top--;
1.3 noro 722: continue;
723: }
724: descr = *(word *)(type_descr
1.4 noro 725: - (descr - (GC_DS_PER_OBJECT
726: - GC_INDIR_PER_OBJ_BIAS)));
1.3 noro 727: }
728: if (0 == descr) {
1.4 noro 729: /* Can happen either because we generated a 0 descriptor */
730: /* or we saw a pointer to a free object. */
731: mark_stack_top--;
732: continue;
1.3 noro 733: }
1.1 noro 734: goto retry;
735: }
1.3 noro 736: } else /* Small object with length descriptor */ {
1.4 noro 737: mark_stack_top--;
1.1 noro 738: limit = (word *)(((ptr_t)current_p) + (word)descr);
739: }
740: /* The simple case in which we're scanning a range. */
1.4 noro 741: GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
1.1 noro 742: credit -= (ptr_t)limit - (ptr_t)current_p;
743: limit -= 1;
1.3 noro 744: {
745: # define PREF_DIST 4
746:
747: # ifndef SMALL_CONFIG
748: word deferred;
749:
750: /* Try to prefetch the next pointer to be examined asap. */
751: /* Empirically, this also seems to help slightly without */
752: /* prefetches, at least on linux/X86. Presumably this loop */
753: /* ends up with less register pressure, and gcc thus ends up */
754: /* generating slightly better code. Overall gcc code quality */
755: /* for this loop is still not great. */
756: for(;;) {
757: PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
1.4 noro 758: GC_ASSERT(limit >= current_p);
1.3 noro 759: deferred = *limit;
1.7 ! noro 760: FIXUP_POINTER(deferred);
1.3 noro 761: limit = (word *)((char *)limit - ALIGNMENT);
762: if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
763: PREFETCH(deferred);
764: break;
765: }
766: if (current_p > limit) goto next_object;
767: /* Unroll once, so we don't do too many of the prefetches */
768: /* based on limit. */
769: deferred = *limit;
1.7 ! noro 770: FIXUP_POINTER(deferred);
1.3 noro 771: limit = (word *)((char *)limit - ALIGNMENT);
772: if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
773: PREFETCH(deferred);
774: break;
775: }
776: if (current_p > limit) goto next_object;
777: }
778: # endif
779:
780: while (current_p <= limit) {
781: /* Empirically, unrolling this loop doesn't help a lot. */
782: /* Since HC_PUSH_CONTENTS expands to a lot of code, */
783: /* we don't. */
784: current = *current_p;
1.7 ! noro 785: FIXUP_POINTER(current);
1.3 noro 786: PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
787: if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
788: /* Prefetch the contents of the object we just pushed. It's */
789: /* likely we will need them soon. */
790: PREFETCH(current);
1.4 noro 791: HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
1.3 noro 792: mark_stack_limit, current_p, exit2);
793: }
794: current_p = (word *)((char *)current_p + ALIGNMENT);
1.1 noro 795: }
1.3 noro 796:
797: # ifndef SMALL_CONFIG
798: /* We still need to mark the entry we previously prefetched. */
799: /* We alrady know that it passes the preliminary pointer */
800: /* validity test. */
1.4 noro 801: HC_PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
1.3 noro 802: mark_stack_limit, current_p, exit4);
803: next_object:;
804: # endif
1.1 noro 805: }
806: }
1.4 noro 807: return mark_stack_top;
808: }
809:
810: #ifdef PARALLEL_MARK
811:
812: /* We assume we have an ANSI C Compiler. */
813: GC_bool GC_help_wanted = FALSE;
814: unsigned GC_helper_count = 0;
815: unsigned GC_active_count = 0;
816: mse * VOLATILE GC_first_nonempty;
817: word GC_mark_no = 0;
818:
819: #define LOCAL_MARK_STACK_SIZE HBLKSIZE
820: /* Under normal circumstances, this is big enough to guarantee */
821: /* We don't overflow half of it in a single call to */
822: /* GC_mark_from. */
823:
824:
825: /* Steal mark stack entries starting at mse low into mark stack local */
826: /* until we either steal mse high, or we have max entries. */
827: /* Return a pointer to the top of the local mark stack. */
828: /* *next is replaced by a pointer to the next unscanned mark stack */
829: /* entry. */
830: mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
831: unsigned max, mse **next)
832: {
833: mse *p;
834: mse *top = local - 1;
835: unsigned i = 0;
836:
1.7 ! noro 837: /* Make sure that prior writes to the mark stack are visible. */
! 838: /* On some architectures, the fact that the reads are */
! 839: /* volatile should suffice. */
! 840: # if !defined(IA64) && !defined(HP_PA) && !defined(I386)
! 841: GC_memory_barrier();
! 842: # endif
1.4 noro 843: GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
844: for (p = low; p <= high && i <= max; ++p) {
845: word descr = *(volatile word *) &(p -> mse_descr);
1.7 ! noro 846: /* In the IA64 memory model, the following volatile store is */
! 847: /* ordered after this read of descr. Thus a thread must read */
! 848: /* the original nonzero value. HP_PA appears to be similar, */
! 849: /* and if I'm reading the P4 spec correctly, X86 is probably */
! 850: /* also OK. In some other cases we need a barrier. */
! 851: # if !defined(IA64) && !defined(HP_PA) && !defined(I386)
! 852: GC_memory_barrier();
! 853: # endif
1.4 noro 854: if (descr != 0) {
855: *(volatile word *) &(p -> mse_descr) = 0;
1.7 ! noro 856: /* More than one thread may get this entry, but that's only */
! 857: /* a minor performance problem. */
1.4 noro 858: ++top;
859: top -> mse_descr = descr;
860: top -> mse_start = p -> mse_start;
861: GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
862: top -> mse_descr < GC_greatest_plausible_heap_addr
863: - GC_least_plausible_heap_addr);
864: /* If this is a big object, count it as */
865: /* size/256 + 1 objects. */
866: ++i;
867: if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (descr >> 8);
868: }
869: }
870: *next = p;
871: return top;
872: }
873:
874: /* Copy back a local mark stack. */
875: /* low and high are inclusive bounds. */
876: void GC_return_mark_stack(mse * low, mse * high)
877: {
878: mse * my_top;
879: mse * my_start;
880: size_t stack_size;
881:
882: if (high < low) return;
883: stack_size = high - low + 1;
884: GC_acquire_mark_lock();
885: my_top = GC_mark_stack_top;
886: my_start = my_top + 1;
887: if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) {
888: # ifdef CONDPRINT
889: if (GC_print_stats) {
890: GC_printf0("No room to copy back mark stack.");
891: }
892: # endif
893: GC_mark_state = MS_INVALID;
894: GC_mark_stack_too_small = TRUE;
895: /* We drop the local mark stack. We'll fix things later. */
896: } else {
897: BCOPY(low, my_start, stack_size * sizeof(mse));
898: GC_ASSERT(GC_mark_stack_top = my_top);
899: # if !defined(IA64) && !defined(HP_PA)
1.7 ! noro 900: GC_memory_barrier();
1.4 noro 901: # endif
902: /* On IA64, the volatile write acts as a release barrier. */
903: GC_mark_stack_top = my_top + stack_size;
904: }
905: GC_release_mark_lock();
906: GC_notify_all_marker();
1.1 noro 907: }
908:
1.4 noro 909: /* Mark from the local mark stack. */
910: /* On return, the local mark stack is empty. */
911: /* But this may be achieved by copying the */
912: /* local mark stack back into the global one. */
913: void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
914: {
915: unsigned n;
916: # define N_LOCAL_ITERS 1
917:
918: # ifdef GC_ASSERTIONS
919: /* Make sure we don't hold mark lock. */
920: GC_acquire_mark_lock();
921: GC_release_mark_lock();
922: # endif
923: for (;;) {
924: for (n = 0; n < N_LOCAL_ITERS; ++n) {
925: local_top = GC_mark_from(local_top, local_mark_stack,
926: local_mark_stack + LOCAL_MARK_STACK_SIZE);
927: if (local_top < local_mark_stack) return;
928: if (local_top - local_mark_stack >= LOCAL_MARK_STACK_SIZE/2) {
929: GC_return_mark_stack(local_mark_stack, local_top);
930: return;
931: }
932: }
933: if (GC_mark_stack_top < GC_first_nonempty &&
934: GC_active_count < GC_helper_count
935: && local_top > local_mark_stack + 1) {
936: /* Try to share the load, since the main stack is empty, */
937: /* and helper threads are waiting for a refill. */
938: /* The entries near the bottom of the stack are likely */
939: /* to require more work. Thus we return those, eventhough */
940: /* it's harder. */
941: mse * p;
942: mse * new_bottom = local_mark_stack
943: + (local_top - local_mark_stack)/2;
944: GC_ASSERT(new_bottom > local_mark_stack
945: && new_bottom < local_top);
946: GC_return_mark_stack(local_mark_stack, new_bottom - 1);
947: memmove(local_mark_stack, new_bottom,
948: (local_top - new_bottom + 1) * sizeof(mse));
949: local_top -= (new_bottom - local_mark_stack);
950: }
951: }
952: }
953:
954: #define ENTRIES_TO_GET 5
955:
956: long GC_markers = 2; /* Normally changed by thread-library- */
957: /* -specific code. */
958:
959: /* Mark using the local mark stack until the global mark stack is empty */
1.6 noro 960: /* and there are no active workers. Update GC_first_nonempty to reflect */
1.4 noro 961: /* progress. */
962: /* Caller does not hold mark lock. */
963: /* Caller has already incremented GC_helper_count. We decrement it, */
964: /* and maintain GC_active_count. */
965: void GC_mark_local(mse *local_mark_stack, int id)
966: {
967: mse * my_first_nonempty;
968:
969: GC_acquire_mark_lock();
970: GC_active_count++;
971: my_first_nonempty = GC_first_nonempty;
972: GC_ASSERT(GC_first_nonempty >= GC_mark_stack &&
973: GC_first_nonempty <= GC_mark_stack_top + 1);
974: # ifdef PRINTSTATS
975: GC_printf1("Starting mark helper %lu\n", (unsigned long)id);
976: # endif
977: GC_release_mark_lock();
978: for (;;) {
979: size_t n_on_stack;
980: size_t n_to_get;
981: mse *next;
982: mse * my_top;
983: mse * local_top;
984: mse * global_first_nonempty = GC_first_nonempty;
985:
986: GC_ASSERT(my_first_nonempty >= GC_mark_stack &&
987: my_first_nonempty <= GC_mark_stack_top + 1);
988: GC_ASSERT(global_first_nonempty >= GC_mark_stack &&
989: global_first_nonempty <= GC_mark_stack_top + 1);
990: if (my_first_nonempty < global_first_nonempty) {
991: my_first_nonempty = global_first_nonempty;
992: } else if (global_first_nonempty < my_first_nonempty) {
993: GC_compare_and_exchange((word *)(&GC_first_nonempty),
994: (word) global_first_nonempty,
995: (word) my_first_nonempty);
996: /* If this fails, we just go ahead, without updating */
997: /* GC_first_nonempty. */
998: }
999: /* Perhaps we should also update GC_first_nonempty, if it */
1000: /* is less. But that would require using atomic updates. */
1001: my_top = GC_mark_stack_top;
1002: n_on_stack = my_top - my_first_nonempty + 1;
1003: if (0 == n_on_stack) {
1004: GC_acquire_mark_lock();
1005: my_top = GC_mark_stack_top;
1006: n_on_stack = my_top - my_first_nonempty + 1;
1007: if (0 == n_on_stack) {
1008: GC_active_count--;
1009: GC_ASSERT(GC_active_count <= GC_helper_count);
1010: /* Other markers may redeposit objects */
1011: /* on the stack. */
1012: if (0 == GC_active_count) GC_notify_all_marker();
1013: while (GC_active_count > 0
1014: && GC_first_nonempty > GC_mark_stack_top) {
1015: /* We will be notified if either GC_active_count */
1016: /* reaches zero, or if more objects are pushed on */
1017: /* the global mark stack. */
1018: GC_wait_marker();
1019: }
1020: if (GC_active_count == 0 &&
1021: GC_first_nonempty > GC_mark_stack_top) {
1022: GC_bool need_to_notify = FALSE;
1023: /* The above conditions can't be falsified while we */
1024: /* hold the mark lock, since neither */
1025: /* GC_active_count nor GC_mark_stack_top can */
1026: /* change. GC_first_nonempty can only be */
1027: /* incremented asynchronously. Thus we know that */
1028: /* both conditions actually held simultaneously. */
1029: GC_helper_count--;
1030: if (0 == GC_helper_count) need_to_notify = TRUE;
1031: # ifdef PRINTSTATS
1032: GC_printf1(
1033: "Finished mark helper %lu\n", (unsigned long)id);
1034: # endif
1035: GC_release_mark_lock();
1036: if (need_to_notify) GC_notify_all_marker();
1037: return;
1038: }
1039: /* else there's something on the stack again, or */
1.6 noro 1040: /* another helper may push something. */
1.4 noro 1041: GC_active_count++;
1042: GC_ASSERT(GC_active_count > 0);
1043: GC_release_mark_lock();
1044: continue;
1045: } else {
1046: GC_release_mark_lock();
1047: }
1048: }
1049: n_to_get = ENTRIES_TO_GET;
1050: if (n_on_stack < 2 * ENTRIES_TO_GET) n_to_get = 1;
1051: local_top = GC_steal_mark_stack(my_first_nonempty, my_top,
1052: local_mark_stack, n_to_get,
1053: &my_first_nonempty);
1054: GC_ASSERT(my_first_nonempty >= GC_mark_stack &&
1055: my_first_nonempty <= GC_mark_stack_top + 1);
1056: GC_do_local_mark(local_mark_stack, local_top);
1057: }
1058: }
1059:
1060: /* Perform Parallel mark. */
1061: /* We hold the GC lock, not the mark lock. */
1062: /* Currently runs until the mark stack is */
1063: /* empty. */
1064: void GC_do_parallel_mark()
1065: {
1066: mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
1067: mse * local_top;
1068: mse * my_top;
1069:
1070: GC_acquire_mark_lock();
1071: GC_ASSERT(I_HOLD_LOCK());
1.6 noro 1072: /* This could be a GC_ASSERT, but it seems safer to keep it on */
1073: /* all the time, especially since it's cheap. */
1074: if (GC_help_wanted || GC_active_count != 0 || GC_helper_count != 0)
1075: ABORT("Tried to start parallel mark in bad state");
1.4 noro 1076: # ifdef PRINTSTATS
1077: GC_printf1("Starting marking for mark phase number %lu\n",
1078: (unsigned long)GC_mark_no);
1079: # endif
1080: GC_first_nonempty = GC_mark_stack;
1081: GC_active_count = 0;
1082: GC_helper_count = 1;
1083: GC_help_wanted = TRUE;
1084: GC_release_mark_lock();
1085: GC_notify_all_marker();
1086: /* Wake up potential helpers. */
1087: GC_mark_local(local_mark_stack, 0);
1088: GC_acquire_mark_lock();
1089: GC_help_wanted = FALSE;
1090: /* Done; clean up. */
1091: while (GC_helper_count > 0) GC_wait_marker();
1092: /* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
1093: # ifdef PRINTSTATS
1094: GC_printf1(
1095: "Finished marking for mark phase number %lu\n",
1096: (unsigned long)GC_mark_no);
1097: # endif
1098: GC_mark_no++;
1099: GC_release_mark_lock();
1100: GC_notify_all_marker();
1101: }
1102:
1103:
1104: /* Try to help out the marker, if it's running. */
1105: /* We do not hold the GC lock, but the requestor does. */
1106: void GC_help_marker(word my_mark_no)
1107: {
1108: mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
1109: unsigned my_id;
1110: mse * my_first_nonempty;
1111:
1112: if (!GC_parallel) return;
1113: GC_acquire_mark_lock();
1114: while (GC_mark_no < my_mark_no
1115: || !GC_help_wanted && GC_mark_no == my_mark_no) {
1116: GC_wait_marker();
1117: }
1118: my_id = GC_helper_count;
1119: if (GC_mark_no != my_mark_no || my_id >= GC_markers) {
1120: /* Second test is useful only if original threads can also */
1121: /* act as helpers. Under Linux they can't. */
1122: GC_release_mark_lock();
1123: return;
1124: }
1125: GC_helper_count = my_id + 1;
1126: GC_release_mark_lock();
1127: GC_mark_local(local_mark_stack, my_id);
1128: /* GC_mark_local decrements GC_helper_count. */
1129: }
1130:
1131: #endif /* PARALLEL_MARK */
1132:
1.1 noro 1133: /* Allocate or reallocate space for mark stack of size s words */
1134: /* May silently fail. */
1135: static void alloc_mark_stack(n)
1136: word n;
1137: {
1.4 noro 1138: mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry));
1.1 noro 1139:
1140: GC_mark_stack_too_small = FALSE;
1141: if (GC_mark_stack_size != 0) {
1142: if (new_stack != 0) {
1143: word displ = (word)GC_mark_stack & (GC_page_size - 1);
1.4 noro 1144: signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
1.1 noro 1145:
1146: /* Recycle old space */
1147: if (0 != displ) displ = GC_page_size - displ;
1148: size = (size - displ) & ~(GC_page_size - 1);
1149: if (size > 0) {
1150: GC_add_to_heap((struct hblk *)
1151: ((word)GC_mark_stack + displ), (word)size);
1152: }
1153: GC_mark_stack = new_stack;
1154: GC_mark_stack_size = n;
1.4 noro 1155: GC_mark_stack_limit = new_stack + n;
1156: # ifdef CONDPRINT
1157: if (GC_print_stats) {
1.1 noro 1158: GC_printf1("Grew mark stack to %lu frames\n",
1159: (unsigned long) GC_mark_stack_size);
1.4 noro 1160: }
1.1 noro 1161: # endif
1162: } else {
1.4 noro 1163: # ifdef CONDPRINT
1164: if (GC_print_stats) {
1.1 noro 1165: GC_printf1("Failed to grow mark stack to %lu frames\n",
1166: (unsigned long) n);
1.4 noro 1167: }
1.1 noro 1168: # endif
1169: }
1170: } else {
1171: if (new_stack == 0) {
1172: GC_err_printf0("No space for mark stack\n");
1173: EXIT();
1174: }
1175: GC_mark_stack = new_stack;
1176: GC_mark_stack_size = n;
1.4 noro 1177: GC_mark_stack_limit = new_stack + n;
1.1 noro 1178: }
1179: GC_mark_stack_top = GC_mark_stack-1;
1180: }
1181:
1182: void GC_mark_init()
1183: {
1184: alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
1185: }
1186:
1187: /*
1188: * Push all locations between b and t onto the mark stack.
1189: * b is the first location to be checked. t is one past the last
1190: * location to be checked.
1191: * Should only be used if there is no possibility of mark stack
1192: * overflow.
1193: */
1194: void GC_push_all(bottom, top)
1195: ptr_t bottom;
1196: ptr_t top;
1197: {
1198: register word length;
1199:
1200: bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
1201: top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
1202: if (top == 0 || bottom == top) return;
1203: GC_mark_stack_top++;
1.4 noro 1204: if (GC_mark_stack_top >= GC_mark_stack_limit) {
1.1 noro 1205: ABORT("unexpected mark stack overflow");
1206: }
1207: length = top - bottom;
1.4 noro 1208: # if GC_DS_TAGS > ALIGNMENT - 1
1209: length += GC_DS_TAGS;
1210: length &= ~GC_DS_TAGS;
1.1 noro 1211: # endif
1212: GC_mark_stack_top -> mse_start = (word *)bottom;
1213: GC_mark_stack_top -> mse_descr = length;
1214: }
1215:
1216: /*
1.4 noro 1217: * Analogous to the above, but push only those pages h with dirty_fn(h) != 0.
1.1 noro 1218: * We use push_fn to actually push the block.
1.4 noro 1219: * Used both to selectively push dirty pages, or to push a block
1220: * in piecemeal fashion, to allow for more marking concurrency.
1.1 noro 1221: * Will not overflow mark stack if push_fn pushes a small fixed number
1222: * of entries. (This is invoked only if push_fn pushes a single entry,
1223: * or if it marks each object before pushing it, thus ensuring progress
1224: * in the event of a stack overflow.)
1225: */
1.4 noro 1226: void GC_push_selected(bottom, top, dirty_fn, push_fn)
1.1 noro 1227: ptr_t bottom;
1228: ptr_t top;
1.4 noro 1229: int (*dirty_fn) GC_PROTO((struct hblk * h));
1230: void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top));
1.1 noro 1231: {
1232: register struct hblk * h;
1233:
1234: bottom = (ptr_t)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
1235: top = (ptr_t)(((long) top) & ~(ALIGNMENT-1));
1236:
1237: if (top == 0 || bottom == top) return;
1238: h = HBLKPTR(bottom + HBLKSIZE);
1239: if (top <= (ptr_t) h) {
1240: if ((*dirty_fn)(h-1)) {
1241: (*push_fn)(bottom, top);
1242: }
1243: return;
1244: }
1245: if ((*dirty_fn)(h-1)) {
1246: (*push_fn)(bottom, (ptr_t)h);
1247: }
1248: while ((ptr_t)(h+1) <= top) {
1249: if ((*dirty_fn)(h)) {
1250: if ((word)(GC_mark_stack_top - GC_mark_stack)
1251: > 3 * GC_mark_stack_size / 4) {
1252: /* Danger of mark stack overflow */
1253: (*push_fn)((ptr_t)h, top);
1254: return;
1255: } else {
1256: (*push_fn)((ptr_t)h, (ptr_t)(h+1));
1257: }
1258: }
1259: h++;
1260: }
1261: if ((ptr_t)h != top) {
1262: if ((*dirty_fn)(h)) {
1263: (*push_fn)((ptr_t)h, top);
1264: }
1265: }
1.4 noro 1266: if (GC_mark_stack_top >= GC_mark_stack_limit) {
1.1 noro 1267: ABORT("unexpected mark stack overflow");
1268: }
1269: }
1270:
1271: # ifndef SMALL_CONFIG
1.4 noro 1272:
1273: #ifdef PARALLEL_MARK
1274: /* Break up root sections into page size chunks to better spread */
1275: /* out work. */
1276: GC_bool GC_true_func(struct hblk *h) { return TRUE; }
1277: # define GC_PUSH_ALL(b,t) GC_push_selected(b,t,GC_true_func,GC_push_all);
1278: #else
1279: # define GC_PUSH_ALL(b,t) GC_push_all(b,t);
1280: #endif
1281:
1282:
1.1 noro 1283: void GC_push_conditional(bottom, top, all)
1284: ptr_t bottom;
1285: ptr_t top;
1286: int all;
1287: {
1288: if (all) {
1289: if (GC_dirty_maintained) {
1290: # ifdef PROC_VDB
1291: /* Pages that were never dirtied cannot contain pointers */
1.4 noro 1292: GC_push_selected(bottom, top, GC_page_was_ever_dirty, GC_push_all);
1.1 noro 1293: # else
1294: GC_push_all(bottom, top);
1295: # endif
1296: } else {
1297: GC_push_all(bottom, top);
1298: }
1299: } else {
1.4 noro 1300: GC_push_selected(bottom, top, GC_page_was_dirty, GC_push_all);
1.1 noro 1301: }
1302: }
1303: #endif
1304:
1.4 noro 1305: # if defined(MSWIN32) || defined(MSWINCE)
1.1 noro 1306: void __cdecl GC_push_one(p)
1307: # else
1308: void GC_push_one(p)
1309: # endif
1310: word p;
1311: {
1.3 noro 1312: GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
1.1 noro 1313: }
1314:
1.4 noro 1315: struct GC_ms_entry *GC_mark_and_push(obj, mark_stack_ptr, mark_stack_limit, src)
1316: GC_PTR obj;
1317: struct GC_ms_entry * mark_stack_ptr;
1318: struct GC_ms_entry * mark_stack_limit;
1319: GC_PTR *src;
1320: {
1321: PREFETCH(obj);
1322: PUSH_CONTENTS(obj, mark_stack_ptr /* modified */, mark_stack_limit, src,
1323: was_marked /* internally generated exit label */);
1324: return mark_stack_ptr;
1325: }
1326:
1.1 noro 1327: # ifdef __STDC__
1328: # define BASE(p) (word)GC_base((void *)(p))
1329: # else
1330: # define BASE(p) (word)GC_base((char *)(p))
1331: # endif
1332:
1.4 noro 1333: /* Mark and push (i.e. gray) a single object p onto the main */
1334: /* mark stack. Consider p to be valid if it is an interior */
1335: /* pointer. */
1336: /* The object p has passed a preliminary pointer validity */
1337: /* test, but we do not definitely know whether it is valid. */
1338: /* Mark bits are NOT atomically updated. Thus this must be the */
1339: /* only thread setting them. */
1.1 noro 1340: # if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
1.4 noro 1341: void GC_mark_and_push_stack(p, source)
1.1 noro 1342: ptr_t source;
1343: # else
1.4 noro 1344: void GC_mark_and_push_stack(p)
1.1 noro 1345: # define source 0
1346: # endif
1347: register word p;
1348: {
1349: register word r;
1350: register hdr * hhdr;
1351: register int displ;
1352:
1353: GET_HDR(p, hhdr);
1354: if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
1.4 noro 1355: if (hhdr != 0) {
1.1 noro 1356: r = BASE(p);
1357: hhdr = HDR(r);
1358: displ = BYTES_TO_WORDS(HBLKDISPL(r));
1359: }
1360: } else {
1361: register map_entry_type map_entry;
1362:
1363: displ = HBLKDISPL(p);
1364: map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
1.4 noro 1365: if (map_entry >= MAX_OFFSET) {
1366: if (map_entry == OFFSET_TOO_BIG || !GC_all_interior_pointers) {
1.1 noro 1367: r = BASE(p);
1368: displ = BYTES_TO_WORDS(HBLKDISPL(r));
1369: if (r == 0) hhdr = 0;
1.4 noro 1370: } else {
1371: /* Offset invalid, but map reflects interior pointers */
1.1 noro 1372: hhdr = 0;
1.4 noro 1373: }
1.1 noro 1374: } else {
1375: displ = BYTES_TO_WORDS(displ);
1376: displ -= map_entry;
1377: r = (word)((word *)(HBLKPTR(p)) + displ);
1378: }
1379: }
1380: /* If hhdr != 0 then r == GC_base(p), only we did it faster. */
1381: /* displ is the word index within the block. */
1382: if (hhdr == 0) {
1.4 noro 1383: # ifdef PRINT_BLACK_LIST
1384: GC_add_to_black_list_stack(p, source);
1385: # else
1386: GC_add_to_black_list_stack(p);
1387: # endif
1388: # undef source /* In case we had to define it. */
1.1 noro 1389: } else {
1390: if (!mark_bit_from_hdr(hhdr, displ)) {
1391: set_mark_bit_from_hdr(hhdr, displ);
1392: GC_STORE_BACK_PTR(source, (ptr_t)r);
1393: PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top,
1.4 noro 1394: GC_mark_stack_limit);
1.1 noro 1395: }
1396: }
1397: }
1398:
1399: # ifdef TRACE_BUF
1400:
1401: # define TRACE_ENTRIES 1000
1402:
1403: struct trace_entry {
1404: char * kind;
1405: word gc_no;
1406: word words_allocd;
1407: word arg1;
1408: word arg2;
1409: } GC_trace_buf[TRACE_ENTRIES];
1410:
1411: int GC_trace_buf_ptr = 0;
1412:
1413: void GC_add_trace_entry(char *kind, word arg1, word arg2)
1414: {
1415: GC_trace_buf[GC_trace_buf_ptr].kind = kind;
1416: GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
1417: GC_trace_buf[GC_trace_buf_ptr].words_allocd = GC_words_allocd;
1418: GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
1419: GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
1420: GC_trace_buf_ptr++;
1421: if (GC_trace_buf_ptr >= TRACE_ENTRIES) GC_trace_buf_ptr = 0;
1422: }
1423:
1424: void GC_print_trace(word gc_no, GC_bool lock)
1425: {
1426: int i;
1427: struct trace_entry *p;
1428:
1429: if (lock) LOCK();
1430: for (i = GC_trace_buf_ptr-1; i != GC_trace_buf_ptr; i--) {
1431: if (i < 0) i = TRACE_ENTRIES-1;
1432: p = GC_trace_buf + i;
1433: if (p -> gc_no < gc_no || p -> kind == 0) return;
1434: printf("Trace:%s (gc:%d,words:%d) 0x%X, 0x%X\n",
1435: p -> kind, p -> gc_no, p -> words_allocd,
1436: (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
1437: }
1438: printf("Trace incomplete\n");
1439: if (lock) UNLOCK();
1440: }
1441:
1442: # endif /* TRACE_BUF */
1443:
1444: /*
1445: * A version of GC_push_all that treats all interior pointers as valid
1446: * and scans the entire region immediately, in case the contents
1447: * change.
1448: */
1449: void GC_push_all_eager(bottom, top)
1450: ptr_t bottom;
1451: ptr_t top;
1452: {
1453: word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
1454: word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
1455: register word *p;
1456: register word q;
1457: register word *lim;
1458: register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1459: register ptr_t least_ha = GC_least_plausible_heap_addr;
1460: # define GC_greatest_plausible_heap_addr greatest_ha
1461: # define GC_least_plausible_heap_addr least_ha
1462:
1463: if (top == 0) return;
1.7 ! noro 1464: /* check all pointers in range and push if they appear */
! 1465: /* to be valid. */
1.1 noro 1466: lim = t - 1 /* longword */;
1467: for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
1468: q = *p;
1469: GC_PUSH_ONE_STACK(q, p);
1470: }
1471: # undef GC_greatest_plausible_heap_addr
1472: # undef GC_least_plausible_heap_addr
1473: }
1474:
1475: #ifndef THREADS
1476: /*
1477: * A version of GC_push_all that treats all interior pointers as valid
1478: * and scans part of the area immediately, to make sure that saved
1479: * register values are not lost.
1480: * Cold_gc_frame delimits the stack section that must be scanned
1481: * eagerly. A zero value indicates that no eager scanning is needed.
1482: */
1483: void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame)
1484: ptr_t bottom;
1485: ptr_t top;
1486: ptr_t cold_gc_frame;
1487: {
1.7 ! noro 1488: if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
1.1 noro 1489: # define EAGER_BYTES 1024
1490: /* Push the hot end of the stack eagerly, so that register values */
1491: /* saved inside GC frames are marked before they disappear. */
1492: /* The rest of the marking can be deferred until later. */
1493: if (0 == cold_gc_frame) {
1494: GC_push_all_stack(bottom, top);
1495: return;
1496: }
1.7 ! noro 1497: GC_ASSERT(bottom <= cold_gc_frame && cold_gc_frame <= top);
1.1 noro 1498: # ifdef STACK_GROWS_DOWN
1.6 noro 1499: GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
1.1 noro 1500: GC_push_all_eager(bottom, cold_gc_frame);
1501: # else /* STACK_GROWS_UP */
1.6 noro 1502: GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
1.1 noro 1503: GC_push_all_eager(cold_gc_frame, top);
1504: # endif /* STACK_GROWS_UP */
1.4 noro 1505: } else {
1.1 noro 1506: GC_push_all_eager(bottom, top);
1.4 noro 1507: }
1.1 noro 1508: # ifdef TRACE_BUF
1509: GC_add_trace_entry("GC_push_all_stack", bottom, top);
1510: # endif
1511: }
1512: #endif /* !THREADS */
1513:
1514: void GC_push_all_stack(bottom, top)
1515: ptr_t bottom;
1516: ptr_t top;
1517: {
1.7 ! noro 1518: if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
1.1 noro 1519: GC_push_all(bottom, top);
1.4 noro 1520: } else {
1.1 noro 1521: GC_push_all_eager(bottom, top);
1.4 noro 1522: }
1.1 noro 1523: }
1524:
1.4 noro 1525: #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1 noro 1526: /* Push all objects reachable from marked objects in the given block */
1527: /* of size 1 objects. */
1528: void GC_push_marked1(h, hhdr)
1529: struct hblk *h;
1530: register hdr * hhdr;
1531: {
1.4 noro 1532: word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 1533: register word *p;
1534: word *plim;
1535: register int i;
1536: register word q;
1537: register word mark_word;
1538: register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1539: register ptr_t least_ha = GC_least_plausible_heap_addr;
1.4 noro 1540: register mse * mark_stack_top = GC_mark_stack_top;
1541: register mse * mark_stack_limit = GC_mark_stack_limit;
1542: # define GC_mark_stack_top mark_stack_top
1543: # define GC_mark_stack_limit mark_stack_limit
1.1 noro 1544: # define GC_greatest_plausible_heap_addr greatest_ha
1545: # define GC_least_plausible_heap_addr least_ha
1546:
1547: p = (word *)(h->hb_body);
1548: plim = (word *)(((word)h) + HBLKSIZE);
1549:
1550: /* go through all words in block */
1551: while( p < plim ) {
1552: mark_word = *mark_word_addr++;
1553: i = 0;
1554: while(mark_word != 0) {
1555: if (mark_word & 1) {
1556: q = p[i];
1557: GC_PUSH_ONE_HEAP(q, p + i);
1558: }
1559: i++;
1560: mark_word >>= 1;
1561: }
1562: p += WORDSZ;
1563: }
1564: # undef GC_greatest_plausible_heap_addr
1565: # undef GC_least_plausible_heap_addr
1.4 noro 1566: # undef GC_mark_stack_top
1567: # undef GC_mark_stack_limit
1568: GC_mark_stack_top = mark_stack_top;
1.1 noro 1569: }
1570:
1571:
1572: #ifndef UNALIGNED
1573:
1574: /* Push all objects reachable from marked objects in the given block */
1575: /* of size 2 objects. */
1576: void GC_push_marked2(h, hhdr)
1577: struct hblk *h;
1578: register hdr * hhdr;
1579: {
1.4 noro 1580: word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 1581: register word *p;
1582: word *plim;
1583: register int i;
1584: register word q;
1585: register word mark_word;
1586: register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1587: register ptr_t least_ha = GC_least_plausible_heap_addr;
1.4 noro 1588: register mse * mark_stack_top = GC_mark_stack_top;
1589: register mse * mark_stack_limit = GC_mark_stack_limit;
1590: # define GC_mark_stack_top mark_stack_top
1591: # define GC_mark_stack_limit mark_stack_limit
1.1 noro 1592: # define GC_greatest_plausible_heap_addr greatest_ha
1593: # define GC_least_plausible_heap_addr least_ha
1594:
1595: p = (word *)(h->hb_body);
1596: plim = (word *)(((word)h) + HBLKSIZE);
1597:
1598: /* go through all words in block */
1599: while( p < plim ) {
1600: mark_word = *mark_word_addr++;
1601: i = 0;
1602: while(mark_word != 0) {
1603: if (mark_word & 1) {
1604: q = p[i];
1605: GC_PUSH_ONE_HEAP(q, p + i);
1606: q = p[i+1];
1607: GC_PUSH_ONE_HEAP(q, p + i);
1608: }
1609: i += 2;
1610: mark_word >>= 2;
1611: }
1612: p += WORDSZ;
1613: }
1614: # undef GC_greatest_plausible_heap_addr
1615: # undef GC_least_plausible_heap_addr
1.4 noro 1616: # undef GC_mark_stack_top
1617: # undef GC_mark_stack_limit
1618: GC_mark_stack_top = mark_stack_top;
1.1 noro 1619: }
1620:
1621: /* Push all objects reachable from marked objects in the given block */
1622: /* of size 4 objects. */
1623: /* There is a risk of mark stack overflow here. But we handle that. */
1624: /* And only unmarked objects get pushed, so it's not very likely. */
1625: void GC_push_marked4(h, hhdr)
1626: struct hblk *h;
1627: register hdr * hhdr;
1628: {
1.4 noro 1629: word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 1630: register word *p;
1631: word *plim;
1632: register int i;
1633: register word q;
1634: register word mark_word;
1635: register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1636: register ptr_t least_ha = GC_least_plausible_heap_addr;
1.4 noro 1637: register mse * mark_stack_top = GC_mark_stack_top;
1638: register mse * mark_stack_limit = GC_mark_stack_limit;
1639: # define GC_mark_stack_top mark_stack_top
1640: # define GC_mark_stack_limit mark_stack_limit
1.1 noro 1641: # define GC_greatest_plausible_heap_addr greatest_ha
1642: # define GC_least_plausible_heap_addr least_ha
1643:
1644: p = (word *)(h->hb_body);
1645: plim = (word *)(((word)h) + HBLKSIZE);
1646:
1647: /* go through all words in block */
1648: while( p < plim ) {
1649: mark_word = *mark_word_addr++;
1650: i = 0;
1651: while(mark_word != 0) {
1652: if (mark_word & 1) {
1653: q = p[i];
1654: GC_PUSH_ONE_HEAP(q, p + i);
1655: q = p[i+1];
1656: GC_PUSH_ONE_HEAP(q, p + i + 1);
1657: q = p[i+2];
1658: GC_PUSH_ONE_HEAP(q, p + i + 2);
1659: q = p[i+3];
1660: GC_PUSH_ONE_HEAP(q, p + i + 3);
1661: }
1662: i += 4;
1663: mark_word >>= 4;
1664: }
1665: p += WORDSZ;
1666: }
1667: # undef GC_greatest_plausible_heap_addr
1668: # undef GC_least_plausible_heap_addr
1.4 noro 1669: # undef GC_mark_stack_top
1670: # undef GC_mark_stack_limit
1671: GC_mark_stack_top = mark_stack_top;
1.1 noro 1672: }
1673:
1674: #endif /* UNALIGNED */
1675:
1676: #endif /* SMALL_CONFIG */
1677:
1678: /* Push all objects reachable from marked objects in the given block */
1679: void GC_push_marked(h, hhdr)
1680: struct hblk *h;
1681: register hdr * hhdr;
1682: {
1683: register int sz = hhdr -> hb_sz;
1.3 noro 1684: register int descr = hhdr -> hb_descr;
1.1 noro 1685: register word * p;
1686: register int word_no;
1687: register word * lim;
1688: register mse * GC_mark_stack_top_reg;
1.4 noro 1689: register mse * mark_stack_limit = GC_mark_stack_limit;
1.1 noro 1690:
1691: /* Some quick shortcuts: */
1.4 noro 1692: if ((0 | GC_DS_LENGTH) == descr) return;
1.1 noro 1693: if (GC_block_empty(hhdr)/* nothing marked */) return;
1.4 noro 1694: GC_n_rescuing_pages++;
1.1 noro 1695: GC_objects_are_marked = TRUE;
1696: if (sz > MAXOBJSZ) {
1.4 noro 1697: lim = (word *)h;
1.1 noro 1698: } else {
1699: lim = (word *)(h + 1) - sz;
1700: }
1701:
1702: switch(sz) {
1.4 noro 1703: # if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1 noro 1704: case 1:
1705: GC_push_marked1(h, hhdr);
1706: break;
1707: # endif
1.4 noro 1708: # if !defined(SMALL_CONFIG) && !defined(UNALIGNED) && \
1709: !defined(USE_MARK_BYTES)
1.1 noro 1710: case 2:
1711: GC_push_marked2(h, hhdr);
1712: break;
1713: case 4:
1714: GC_push_marked4(h, hhdr);
1715: break;
1716: # endif
1717: default:
1718: GC_mark_stack_top_reg = GC_mark_stack_top;
1.4 noro 1719: for (p = (word *)h, word_no = 0; p <= lim; p += sz, word_no += sz) {
1.1 noro 1720: if (mark_bit_from_hdr(hhdr, word_no)) {
1721: /* Mark from fields inside the object */
1722: PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
1723: # ifdef GATHERSTATS
1724: /* Subtract this object from total, since it was */
1725: /* added in twice. */
1726: GC_composite_in_use -= sz;
1727: # endif
1728: }
1729: }
1730: GC_mark_stack_top = GC_mark_stack_top_reg;
1731: }
1732: }
1733:
1734: #ifndef SMALL_CONFIG
1735: /* Test whether any page in the given block is dirty */
1736: GC_bool GC_block_was_dirty(h, hhdr)
1737: struct hblk *h;
1738: register hdr * hhdr;
1739: {
1740: register int sz = hhdr -> hb_sz;
1741:
1742: if (sz < MAXOBJSZ) {
1743: return(GC_page_was_dirty(h));
1744: } else {
1745: register ptr_t p = (ptr_t)h;
1746: sz = WORDS_TO_BYTES(sz);
1747: while (p < (ptr_t)h + sz) {
1748: if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
1749: p += HBLKSIZE;
1750: }
1751: return(FALSE);
1752: }
1753: }
1754: #endif /* SMALL_CONFIG */
1755:
1756: /* Similar to GC_push_next_marked, but return address of next block */
1757: struct hblk * GC_push_next_marked(h)
1758: struct hblk *h;
1759: {
1760: register hdr * hhdr;
1761:
1762: h = GC_next_used_block(h);
1763: if (h == 0) return(0);
1764: hhdr = HDR(h);
1765: GC_push_marked(h, hhdr);
1766: return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
1767: }
1768:
1769: #ifndef SMALL_CONFIG
1770: /* Identical to above, but mark only from dirty pages */
1771: struct hblk * GC_push_next_marked_dirty(h)
1772: struct hblk *h;
1773: {
1.2 noro 1774: register hdr * hhdr;
1.1 noro 1775:
1776: if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
1777: for (;;) {
1778: h = GC_next_used_block(h);
1779: if (h == 0) return(0);
1780: hhdr = HDR(h);
1781: # ifdef STUBBORN_ALLOC
1782: if (hhdr -> hb_obj_kind == STUBBORN) {
1783: if (GC_page_was_changed(h) && GC_block_was_dirty(h, hhdr)) {
1784: break;
1785: }
1786: } else {
1787: if (GC_block_was_dirty(h, hhdr)) break;
1788: }
1789: # else
1790: if (GC_block_was_dirty(h, hhdr)) break;
1791: # endif
1792: h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
1793: }
1794: GC_push_marked(h, hhdr);
1795: return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
1796: }
1797: #endif
1798:
1799: /* Similar to above, but for uncollectable pages. Needed since we */
1800: /* do not clear marks for such pages, even for full collections. */
1801: struct hblk * GC_push_next_marked_uncollectable(h)
1802: struct hblk *h;
1803: {
1804: register hdr * hhdr = HDR(h);
1805:
1806: for (;;) {
1807: h = GC_next_used_block(h);
1808: if (h == 0) return(0);
1809: hhdr = HDR(h);
1810: if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break;
1811: h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
1812: }
1813: GC_push_marked(h, hhdr);
1814: return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
1815: }
1816:
1817:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>