[BACK]Return to mark.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Annotation of OpenXM_contrib2/asir2000/gc/mark.c, Revision 1.6

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>