[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.4

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.3       noro      267: #ifdef MSWIN32
                    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 {
                    277: #endif
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.3       noro      398: #ifdef MSWIN32
                    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:   }
                    413: #endif /* MSWIN32 */
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  */
                    430: /* first page of a large object, return a pointer either to the                */
                    431: /* start of the large object or NIL.                                   */
                    432: /* In the latter case black list the address current.                  */
                    433: /* Returns NIL without black listing if current points to a block      */
                    434: /* with IGNORE_OFF_PAGE set.                                           */
                    435: /*ARGSUSED*/
                    436: # ifdef PRINT_BLACK_LIST
1.3       noro      437:   ptr_t GC_find_start(current, hhdr, source)
1.1       noro      438:   word source;
                    439: # else
1.3       noro      440:   ptr_t GC_find_start(current, hhdr)
1.1       noro      441: # define source 0
                    442: # endif
1.3       noro      443: register ptr_t current;
1.1       noro      444: register hdr * hhdr;
                    445: {
1.4     ! noro      446:     if (GC_all_interior_pointers) {
1.1       noro      447:        if (hhdr != 0) {
1.3       noro      448:            register ptr_t orig = current;
1.1       noro      449:
1.4     ! noro      450:            current = (ptr_t)HBLKPTR(current);
1.1       noro      451:            do {
                    452:              current = current - HBLKSIZE*(word)hhdr;
                    453:              hhdr = HDR(current);
                    454:            } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
                    455:            /* current points to the start of the large object */
                    456:            if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(0);
                    457:            if ((word *)orig - (word *)current
                    458:                 >= (ptrdiff_t)(hhdr->hb_sz)) {
                    459:                /* Pointer past the end of the block */
1.4     ! noro      460:                GC_ADD_TO_BLACK_LIST_NORMAL((word)orig, source);
1.1       noro      461:                return(0);
                    462:            }
                    463:            return(current);
                    464:        } else {
1.4     ! noro      465:            GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source);
1.1       noro      466:            return(0);
                    467:         }
1.4     ! noro      468:     } else {
        !           469:         GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source);
1.1       noro      470:         return(0);
1.4     ! noro      471:     }
1.1       noro      472: #   undef source
                    473: }
                    474:
                    475: void GC_invalidate_mark_state()
                    476: {
                    477:     GC_mark_state = MS_INVALID;
                    478:     GC_mark_stack_top = GC_mark_stack-1;
                    479: }
                    480:
                    481: mse * GC_signal_mark_stack_overflow(msp)
                    482: mse * msp;
                    483: {
                    484:     GC_mark_state = MS_INVALID;
                    485:     GC_mark_stack_too_small = TRUE;
1.4     ! noro      486: #   ifdef CONDPRINT
        !           487:       if (GC_print_stats) {
1.1       noro      488:        GC_printf1("Mark stack overflow; current size = %lu entries\n",
                    489:                    GC_mark_stack_size);
1.4     ! noro      490:       }
        !           491: #   endif
        !           492:     return(msp - GC_MARK_STACK_DISCARDS);
1.1       noro      493: }
                    494:
                    495: /*
                    496:  * Mark objects pointed to by the regions described by
                    497:  * mark stack entries between GC_mark_stack and GC_mark_stack_top,
                    498:  * inclusive.  Assumes the upper limit of a mark stack entry
                    499:  * is never 0.  A mark stack entry never has size 0.
                    500:  * We try to traverse on the order of a hblk of memory before we return.
                    501:  * Caller is responsible for calling this until the mark stack is empty.
1.3       noro      502:  * Note that this is the most performance critical routine in the
                    503:  * collector.  Hence it contains all sorts of ugly hacks to speed
                    504:  * things up.  In particular, we avoid procedure calls on the common
                    505:  * path, we take advantage of peculiarities of the mark descriptor
                    506:  * encoding, we optionally maintain a cache for the block address to
                    507:  * header mapping, we prefetch when an object is "grayed", etc.
1.1       noro      508:  */
1.4     ! noro      509: mse * GC_mark_from(mark_stack_top, mark_stack, mark_stack_limit)
        !           510: mse * mark_stack_top;
        !           511: mse * mark_stack;
        !           512: mse * mark_stack_limit;
1.1       noro      513: {
                    514:   int credit = HBLKSIZE;       /* Remaining credit for marking work    */
                    515:   register word * current_p;   /* Pointer to current candidate ptr.    */
                    516:   register word current;       /* Candidate pointer.                   */
                    517:   register word * limit;       /* (Incl) limit of current candidate    */
                    518:                                /* range                                */
                    519:   register word descr;
                    520:   register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
                    521:   register ptr_t least_ha = GC_least_plausible_heap_addr;
1.3       noro      522:   DECLARE_HDR_CACHE;
                    523:
1.1       noro      524: # define SPLIT_RANGE_WORDS 128  /* Must be power of 2.         */
                    525:
                    526:   GC_objects_are_marked = TRUE;
1.3       noro      527:   INIT_HDR_CACHE;
1.1       noro      528: # ifdef OS2 /* Use untweaked version to circumvent compiler problem */
1.4     ! noro      529:   while (mark_stack_top >= mark_stack && credit >= 0) {
1.1       noro      530: # else
1.4     ! noro      531:   while ((((ptr_t)mark_stack_top - (ptr_t)mark_stack) | credit)
1.1       noro      532:        >= 0) {
                    533: # endif
1.4     ! noro      534:     current_p = mark_stack_top -> mse_start;
        !           535:     descr = mark_stack_top -> mse_descr;
1.1       noro      536:   retry:
1.3       noro      537:     /* current_p and descr describe the current object.                */
1.4     ! noro      538:     /* *mark_stack_top is vacant.                              */
1.3       noro      539:     /* The following is 0 only for small objects described by a simple */
                    540:     /* length descriptor.  For many applications this is the common    */
                    541:     /* case, so we try to detect it quickly.                           */
1.4     ! noro      542:     if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | GC_DS_TAGS)) {
        !           543:       word tag = descr & GC_DS_TAGS;
1.1       noro      544:
                    545:       switch(tag) {
1.4     ! noro      546:         case GC_DS_LENGTH:
1.1       noro      547:           /* Large length.                                             */
                    548:           /* Process part of the range to avoid pushing too much on the        */
                    549:           /* stack.                                                    */
1.4     ! noro      550: #        ifdef PARALLEL_MARK
        !           551: #          define SHARE_BYTES 2048
        !           552:            if (descr > SHARE_BYTES && GC_parallel
        !           553:                && mark_stack_top < mark_stack_limit - 1) {
        !           554:              int new_size = (descr/2) & ~(sizeof(word)-1);
        !           555:              GC_ASSERT(descr < GC_greatest_plausible_heap_addr
        !           556:                                - GC_least_plausible_heap_addr);
        !           557:              mark_stack_top -> mse_start = current_p;
        !           558:              mark_stack_top -> mse_descr = new_size + sizeof(word);
        !           559:                                        /* makes sure we handle         */
        !           560:                                        /* misaligned pointers.         */
        !           561:              mark_stack_top++;
        !           562:              current_p = (word *) ((char *)current_p + new_size);
        !           563:              descr -= new_size;
        !           564:              goto retry;
        !           565:            }
        !           566: #        endif /* PARALLEL_MARK */
        !           567:           mark_stack_top -> mse_start =
1.1       noro      568:                limit = current_p + SPLIT_RANGE_WORDS-1;
1.4     ! noro      569:           mark_stack_top -> mse_descr =
1.3       noro      570:                        descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
1.1       noro      571:           /* Make sure that pointers overlapping the two ranges are    */
                    572:           /* considered.                                               */
                    573:           limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT);
                    574:           break;
1.4     ! noro      575:         case GC_DS_BITMAP:
        !           576:           mark_stack_top--;
        !           577:           descr &= ~GC_DS_TAGS;
1.1       noro      578:           credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */
                    579:           while (descr != 0) {
                    580:             if ((signed_word)descr < 0) {
                    581:               current = *current_p;
                    582:              if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
1.3       noro      583:                PREFETCH(current);
1.4     ! noro      584:                 HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
1.3       noro      585:                              mark_stack_limit, current_p, exit1);
1.1       noro      586:              }
                    587:             }
                    588:            descr <<= 1;
                    589:            ++ current_p;
                    590:           }
                    591:           continue;
1.4     ! noro      592:         case GC_DS_PROC:
        !           593:           mark_stack_top--;
        !           594:           credit -= GC_PROC_BYTES;
        !           595:           mark_stack_top =
1.1       noro      596:               (*PROC(descr))
1.4     ! noro      597:                    (current_p, mark_stack_top,
1.1       noro      598:                    mark_stack_limit, ENV(descr));
                    599:           continue;
1.4     ! noro      600:         case GC_DS_PER_OBJECT:
1.3       noro      601:          if ((signed_word)descr >= 0) {
                    602:            /* Descriptor is in the object.     */
1.4     ! noro      603:             descr = *(word *)((ptr_t)current_p + descr - GC_DS_PER_OBJECT);
1.3       noro      604:          } else {
                    605:            /* Descriptor is in type descriptor pointed to by first     */
                    606:            /* word in object.                                          */
                    607:            ptr_t type_descr = *(ptr_t *)current_p;
                    608:            /* type_descr is either a valid pointer to the descriptor   */
                    609:            /* structure, or this object was on a free list.  If it     */
                    610:            /* it was anything but the last object on the free list,    */
                    611:            /* we will misinterpret the next object on the free list as */
                    612:            /* the type descriptor, and get a 0 GC descriptor, which    */
                    613:            /* is ideal.  Unfortunately, we need to check for the last  */
                    614:            /* object case explicitly.                                  */
                    615:            if (0 == type_descr) {
                    616:                /* Rarely executed.     */
1.4     ! noro      617:                mark_stack_top--;
1.3       noro      618:                continue;
                    619:            }
                    620:             descr = *(word *)(type_descr
1.4     ! noro      621:                              - (descr - (GC_DS_PER_OBJECT
        !           622:                                          - GC_INDIR_PER_OBJ_BIAS)));
1.3       noro      623:          }
                    624:          if (0 == descr) {
1.4     ! noro      625:              /* Can happen either because we generated a 0 descriptor  */
        !           626:              /* or we saw a pointer to a free object.                  */
        !           627:              mark_stack_top--;
        !           628:              continue;
1.3       noro      629:          }
1.1       noro      630:           goto retry;
                    631:       }
1.3       noro      632:     } else /* Small object with length descriptor */ {
1.4     ! noro      633:       mark_stack_top--;
1.1       noro      634:       limit = (word *)(((ptr_t)current_p) + (word)descr);
                    635:     }
                    636:     /* The simple case in which we're scanning a range.        */
1.4     ! noro      637:     GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
1.1       noro      638:     credit -= (ptr_t)limit - (ptr_t)current_p;
                    639:     limit -= 1;
1.3       noro      640:     {
                    641: #     define PREF_DIST 4
                    642:
                    643: #     ifndef SMALL_CONFIG
                    644:         word deferred;
                    645:
                    646:        /* Try to prefetch the next pointer to be examined asap.        */
                    647:        /* Empirically, this also seems to help slightly without        */
                    648:        /* prefetches, at least on linux/X86.  Presumably this loop     */
                    649:        /* ends up with less register pressure, and gcc thus ends up    */
                    650:        /* generating slightly better code.  Overall gcc code quality   */
                    651:        /* for this loop is still not great.                            */
                    652:        for(;;) {
                    653:          PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
1.4     ! noro      654:          GC_ASSERT(limit >= current_p);
1.3       noro      655:          deferred = *limit;
                    656:          limit = (word *)((char *)limit - ALIGNMENT);
                    657:          if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {
                    658:            PREFETCH(deferred);
                    659:            break;
                    660:          }
                    661:          if (current_p > limit) goto next_object;
                    662:          /* Unroll once, so we don't do too many of the prefetches     */
                    663:          /* based on limit.                                            */
                    664:          deferred = *limit;
                    665:          limit = (word *)((char *)limit - ALIGNMENT);
                    666:          if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {
                    667:            PREFETCH(deferred);
                    668:            break;
                    669:          }
                    670:          if (current_p > limit) goto next_object;
                    671:        }
                    672: #     endif
                    673:
                    674:       while (current_p <= limit) {
                    675:        /* Empirically, unrolling this loop doesn't help a lot. */
                    676:        /* Since HC_PUSH_CONTENTS expands to a lot of code,     */
                    677:        /* we don't.                                            */
                    678:         current = *current_p;
                    679:         PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
                    680:         if ((ptr_t)current >= least_ha && (ptr_t)current <  greatest_ha) {
                    681:          /* Prefetch the contents of the object we just pushed.  It's  */
                    682:          /* likely we will need them soon.                             */
                    683:          PREFETCH(current);
1.4     ! noro      684:           HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
1.3       noro      685:                           mark_stack_limit, current_p, exit2);
                    686:         }
                    687:         current_p = (word *)((char *)current_p + ALIGNMENT);
1.1       noro      688:       }
1.3       noro      689:
                    690: #     ifndef SMALL_CONFIG
                    691:        /* We still need to mark the entry we previously prefetched.    */
                    692:        /* We alrady know that it passes the preliminary pointer        */
                    693:        /* validity test.                                               */
1.4     ! noro      694:         HC_PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
1.3       noro      695:                         mark_stack_limit, current_p, exit4);
                    696:        next_object:;
                    697: #     endif
1.1       noro      698:     }
                    699:   }
1.4     ! noro      700:   return mark_stack_top;
        !           701: }
        !           702:
        !           703: #ifdef PARALLEL_MARK
        !           704:
        !           705: /* We assume we have an ANSI C Compiler.       */
        !           706: GC_bool GC_help_wanted = FALSE;
        !           707: unsigned GC_helper_count = 0;
        !           708: unsigned GC_active_count = 0;
        !           709: mse * VOLATILE GC_first_nonempty;
        !           710: word GC_mark_no = 0;
        !           711:
        !           712: #define LOCAL_MARK_STACK_SIZE HBLKSIZE
        !           713:        /* Under normal circumstances, this is big enough to guarantee  */
        !           714:        /* We don't overflow half of it in a single call to             */
        !           715:        /* GC_mark_from.                                                */
        !           716:
        !           717:
        !           718: /* Steal mark stack entries starting at mse low into mark stack local  */
        !           719: /* until we either steal mse high, or we have max entries.             */
        !           720: /* Return a pointer to the top of the local mark stack.                        */
        !           721: /* *next is replaced by a pointer to the next unscanned mark stack     */
        !           722: /* entry.                                                              */
        !           723: mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
        !           724:                          unsigned max, mse **next)
        !           725: {
        !           726:     mse *p;
        !           727:     mse *top = local - 1;
        !           728:     unsigned i = 0;
        !           729:
        !           730:     GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
        !           731:     for (p = low; p <= high && i <= max; ++p) {
        !           732:        word descr = *(volatile word *) &(p -> mse_descr);
        !           733:        if (descr != 0) {
        !           734:            *(volatile word *) &(p -> mse_descr) = 0;
        !           735:            ++top;
        !           736:            top -> mse_descr = descr;
        !           737:            top -> mse_start = p -> mse_start;
        !           738:            GC_ASSERT(  top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
        !           739:                        top -> mse_descr < GC_greatest_plausible_heap_addr
        !           740:                                           - GC_least_plausible_heap_addr);
        !           741:            /* There is no synchronization here.  We assume that at     */
        !           742:            /* least one thread will see the original descriptor.       */
        !           743:            /* Otherwise we need a barrier.                             */
        !           744:            /* More than one thread may get this entry, but that's only */
        !           745:            /* a minor performance problem.                             */
        !           746:            /* If this is a big object, count it as                     */
        !           747:            /* size/256 + 1 objects.                                    */
        !           748:            ++i;
        !           749:            if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) i += (descr >> 8);
        !           750:        }
        !           751:     }
        !           752:     *next = p;
        !           753:     return top;
        !           754: }
        !           755:
        !           756: /* Copy back a local mark stack.       */
        !           757: /* low and high are inclusive bounds.  */
        !           758: void GC_return_mark_stack(mse * low, mse * high)
        !           759: {
        !           760:     mse * my_top;
        !           761:     mse * my_start;
        !           762:     size_t stack_size;
        !           763:
        !           764:     if (high < low) return;
        !           765:     stack_size = high - low + 1;
        !           766:     GC_acquire_mark_lock();
        !           767:     my_top = GC_mark_stack_top;
        !           768:     my_start = my_top + 1;
        !           769:     if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) {
        !           770: #     ifdef CONDPRINT
        !           771:        if (GC_print_stats) {
        !           772:          GC_printf0("No room to copy back mark stack.");
        !           773:        }
        !           774: #     endif
        !           775:       GC_mark_state = MS_INVALID;
        !           776:       GC_mark_stack_too_small = TRUE;
        !           777:       /* We drop the local mark stack.  We'll fix things later.        */
        !           778:     } else {
        !           779:       BCOPY(low, my_start, stack_size * sizeof(mse));
        !           780:       GC_ASSERT(GC_mark_stack_top = my_top);
        !           781: #     if !defined(IA64) && !defined(HP_PA)
        !           782:         GC_memory_write_barrier();
        !           783: #     endif
        !           784:        /* On IA64, the volatile write acts as a release barrier. */
        !           785:       GC_mark_stack_top = my_top + stack_size;
        !           786:     }
        !           787:     GC_release_mark_lock();
        !           788:     GC_notify_all_marker();
1.1       noro      789: }
                    790:
1.4     ! noro      791: /* Mark from the local mark stack.             */
        !           792: /* On return, the local mark stack is empty.   */
        !           793: /* But this may be achieved by copying the     */
        !           794: /* local mark stack back into the global one.  */
        !           795: void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
        !           796: {
        !           797:     unsigned n;
        !           798: #   define N_LOCAL_ITERS 1
        !           799:
        !           800: #   ifdef GC_ASSERTIONS
        !           801:       /* Make sure we don't hold mark lock. */
        !           802:        GC_acquire_mark_lock();
        !           803:        GC_release_mark_lock();
        !           804: #   endif
        !           805:     for (;;) {
        !           806:         for (n = 0; n < N_LOCAL_ITERS; ++n) {
        !           807:            local_top = GC_mark_from(local_top, local_mark_stack,
        !           808:                                     local_mark_stack + LOCAL_MARK_STACK_SIZE);
        !           809:            if (local_top < local_mark_stack) return;
        !           810:            if (local_top - local_mark_stack >= LOCAL_MARK_STACK_SIZE/2) {
        !           811:                GC_return_mark_stack(local_mark_stack, local_top);
        !           812:                return;
        !           813:            }
        !           814:        }
        !           815:        if (GC_mark_stack_top < GC_first_nonempty &&
        !           816:            GC_active_count < GC_helper_count
        !           817:            && local_top > local_mark_stack + 1) {
        !           818:            /* Try to share the load, since the main stack is empty,    */
        !           819:            /* and helper threads are waiting for a refill.             */
        !           820:            /* The entries near the bottom of the stack are likely      */
        !           821:            /* to require more work.  Thus we return those, eventhough  */
        !           822:            /* it's harder.                                             */
        !           823:            mse * p;
        !           824:            mse * new_bottom = local_mark_stack
        !           825:                                + (local_top - local_mark_stack)/2;
        !           826:            GC_ASSERT(new_bottom > local_mark_stack
        !           827:                      && new_bottom < local_top);
        !           828:            GC_return_mark_stack(local_mark_stack, new_bottom - 1);
        !           829:            memmove(local_mark_stack, new_bottom,
        !           830:                    (local_top - new_bottom + 1) * sizeof(mse));
        !           831:            local_top -= (new_bottom - local_mark_stack);
        !           832:        }
        !           833:     }
        !           834: }
        !           835:
        !           836: #define ENTRIES_TO_GET 5
        !           837:
        !           838: long GC_markers = 2;           /* Normally changed by thread-library-  */
        !           839:                                /* -specific code.                      */
        !           840:
        !           841: /* Mark using the local mark stack until the global mark stack is empty        */
        !           842: /* and ther are no active workers.  Update GC_first_nonempty to reflect        */
        !           843: /* progress.                                                           */
        !           844: /* Caller does not hold mark lock.                                     */
        !           845: /* Caller has already incremented GC_helper_count.  We decrement it,   */
        !           846: /* and maintain GC_active_count.                                       */
        !           847: void GC_mark_local(mse *local_mark_stack, int id)
        !           848: {
        !           849:     mse * my_first_nonempty;
        !           850:
        !           851:     GC_acquire_mark_lock();
        !           852:     GC_active_count++;
        !           853:     my_first_nonempty = GC_first_nonempty;
        !           854:     GC_ASSERT(GC_first_nonempty >= GC_mark_stack &&
        !           855:              GC_first_nonempty <= GC_mark_stack_top + 1);
        !           856: #   ifdef PRINTSTATS
        !           857:        GC_printf1("Starting mark helper %lu\n", (unsigned long)id);
        !           858: #   endif
        !           859:     GC_release_mark_lock();
        !           860:     for (;;) {
        !           861:        size_t n_on_stack;
        !           862:         size_t n_to_get;
        !           863:        mse *next;
        !           864:        mse * my_top;
        !           865:        mse * local_top;
        !           866:         mse * global_first_nonempty = GC_first_nonempty;
        !           867:
        !           868:        GC_ASSERT(my_first_nonempty >= GC_mark_stack &&
        !           869:                  my_first_nonempty <= GC_mark_stack_top + 1);
        !           870:        GC_ASSERT(global_first_nonempty >= GC_mark_stack &&
        !           871:                  global_first_nonempty <= GC_mark_stack_top + 1);
        !           872:        if (my_first_nonempty < global_first_nonempty) {
        !           873:            my_first_nonempty = global_first_nonempty;
        !           874:         } else if (global_first_nonempty < my_first_nonempty) {
        !           875:            GC_compare_and_exchange((word *)(&GC_first_nonempty),
        !           876:                                   (word) global_first_nonempty,
        !           877:                                   (word) my_first_nonempty);
        !           878:            /* If this fails, we just go ahead, without updating        */
        !           879:            /* GC_first_nonempty.                                       */
        !           880:        }
        !           881:        /* Perhaps we should also update GC_first_nonempty, if it */
        !           882:        /* is less.  But that would require using atomic updates. */
        !           883:        my_top = GC_mark_stack_top;
        !           884:        n_on_stack = my_top - my_first_nonempty + 1;
        !           885:         if (0 == n_on_stack) {
        !           886:            GC_acquire_mark_lock();
        !           887:             my_top = GC_mark_stack_top;
        !           888:             n_on_stack = my_top - my_first_nonempty + 1;
        !           889:            if (0 == n_on_stack) {
        !           890:                GC_active_count--;
        !           891:                GC_ASSERT(GC_active_count <= GC_helper_count);
        !           892:                /* Other markers may redeposit objects  */
        !           893:                /* on the stack.                                */
        !           894:                if (0 == GC_active_count) GC_notify_all_marker();
        !           895:                while (GC_active_count > 0
        !           896:                       && GC_first_nonempty > GC_mark_stack_top) {
        !           897:                    /* We will be notified if either GC_active_count    */
        !           898:                    /* reaches zero, or if more objects are pushed on   */
        !           899:                    /* the global mark stack.                           */
        !           900:                    GC_wait_marker();
        !           901:                }
        !           902:                if (GC_active_count == 0 &&
        !           903:                    GC_first_nonempty > GC_mark_stack_top) {
        !           904:                    GC_bool need_to_notify = FALSE;
        !           905:                    /* The above conditions can't be falsified while we */
        !           906:                    /* hold the mark lock, since neither                */
        !           907:                    /* GC_active_count nor GC_mark_stack_top can        */
        !           908:                    /* change.  GC_first_nonempty can only be           */
        !           909:                    /* incremented asynchronously.  Thus we know that   */
        !           910:                    /* both conditions actually held simultaneously.    */
        !           911:                    GC_helper_count--;
        !           912:                    if (0 == GC_helper_count) need_to_notify = TRUE;
        !           913: #                  ifdef PRINTSTATS
        !           914:                      GC_printf1(
        !           915:                        "Finished mark helper %lu\n", (unsigned long)id);
        !           916: #                  endif
        !           917:                    GC_release_mark_lock();
        !           918:                    if (need_to_notify) GC_notify_all_marker();
        !           919:                    return;
        !           920:                }
        !           921:                /* else there's something on the stack again, or        */
        !           922:                /* another help may push something.                     */
        !           923:                GC_active_count++;
        !           924:                GC_ASSERT(GC_active_count > 0);
        !           925:                GC_release_mark_lock();
        !           926:                continue;
        !           927:            } else {
        !           928:                GC_release_mark_lock();
        !           929:            }
        !           930:        }
        !           931:        n_to_get = ENTRIES_TO_GET;
        !           932:        if (n_on_stack < 2 * ENTRIES_TO_GET) n_to_get = 1;
        !           933:        local_top = GC_steal_mark_stack(my_first_nonempty, my_top,
        !           934:                                        local_mark_stack, n_to_get,
        !           935:                                        &my_first_nonempty);
        !           936:         GC_ASSERT(my_first_nonempty >= GC_mark_stack &&
        !           937:                  my_first_nonempty <= GC_mark_stack_top + 1);
        !           938:        GC_do_local_mark(local_mark_stack, local_top);
        !           939:     }
        !           940: }
        !           941:
        !           942: /* Perform Parallel mark.                      */
        !           943: /* We hold the GC lock, not the mark lock.     */
        !           944: /* Currently runs until the mark stack is      */
        !           945: /* empty.                                      */
        !           946: void GC_do_parallel_mark()
        !           947: {
        !           948:     mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
        !           949:     mse * local_top;
        !           950:     mse * my_top;
        !           951:
        !           952:     GC_acquire_mark_lock();
        !           953:     GC_ASSERT(I_HOLD_LOCK());
        !           954:     GC_ASSERT(!GC_help_wanted);
        !           955:     GC_ASSERT(GC_active_count == 0);
        !           956: #   ifdef PRINTSTATS
        !           957:        GC_printf1("Starting marking for mark phase number %lu\n",
        !           958:                   (unsigned long)GC_mark_no);
        !           959: #   endif
        !           960:     GC_first_nonempty = GC_mark_stack;
        !           961:     GC_active_count = 0;
        !           962:     GC_helper_count = 1;
        !           963:     GC_help_wanted = TRUE;
        !           964:     GC_release_mark_lock();
        !           965:     GC_notify_all_marker();
        !           966:        /* Wake up potential helpers.   */
        !           967:     GC_mark_local(local_mark_stack, 0);
        !           968:     GC_acquire_mark_lock();
        !           969:     GC_help_wanted = FALSE;
        !           970:     /* Done; clean up. */
        !           971:     while (GC_helper_count > 0) GC_wait_marker();
        !           972:     /* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
        !           973: #   ifdef PRINTSTATS
        !           974:        GC_printf1(
        !           975:            "Finished marking for mark phase number %lu\n",
        !           976:            (unsigned long)GC_mark_no);
        !           977: #   endif
        !           978:     GC_mark_no++;
        !           979:     GC_release_mark_lock();
        !           980:     GC_notify_all_marker();
        !           981: }
        !           982:
        !           983:
        !           984: /* Try to help out the marker, if it's running.                */
        !           985: /* We do not hold the GC lock, but the requestor does. */
        !           986: void GC_help_marker(word my_mark_no)
        !           987: {
        !           988:     mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
        !           989:     unsigned my_id;
        !           990:     mse * my_first_nonempty;
        !           991:
        !           992:     if (!GC_parallel) return;
        !           993:     GC_acquire_mark_lock();
        !           994:     while (GC_mark_no < my_mark_no
        !           995:            || !GC_help_wanted && GC_mark_no == my_mark_no) {
        !           996:       GC_wait_marker();
        !           997:     }
        !           998:     my_id = GC_helper_count;
        !           999:     if (GC_mark_no != my_mark_no || my_id >= GC_markers) {
        !          1000:       /* Second test is useful only if original threads can also       */
        !          1001:       /* act as helpers.  Under Linux they can't.                      */
        !          1002:       GC_release_mark_lock();
        !          1003:       return;
        !          1004:     }
        !          1005:     GC_helper_count = my_id + 1;
        !          1006:     GC_release_mark_lock();
        !          1007:     GC_mark_local(local_mark_stack, my_id);
        !          1008:     /* GC_mark_local decrements GC_helper_count. */
        !          1009: }
        !          1010:
        !          1011: #endif /* PARALLEL_MARK */
        !          1012:
1.1       noro     1013: /* Allocate or reallocate space for mark stack of size s words  */
                   1014: /* May silently fail.                                          */
                   1015: static void alloc_mark_stack(n)
                   1016: word n;
                   1017: {
1.4     ! noro     1018:     mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry));
1.1       noro     1019:
                   1020:     GC_mark_stack_too_small = FALSE;
                   1021:     if (GC_mark_stack_size != 0) {
                   1022:         if (new_stack != 0) {
                   1023:           word displ = (word)GC_mark_stack & (GC_page_size - 1);
1.4     ! noro     1024:           signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
1.1       noro     1025:
                   1026:           /* Recycle old space */
                   1027:              if (0 != displ) displ = GC_page_size - displ;
                   1028:              size = (size - displ) & ~(GC_page_size - 1);
                   1029:              if (size > 0) {
                   1030:                GC_add_to_heap((struct hblk *)
                   1031:                                ((word)GC_mark_stack + displ), (word)size);
                   1032:              }
                   1033:           GC_mark_stack = new_stack;
                   1034:           GC_mark_stack_size = n;
1.4     ! noro     1035:          GC_mark_stack_limit = new_stack + n;
        !          1036: #        ifdef CONDPRINT
        !          1037:            if (GC_print_stats) {
1.1       noro     1038:              GC_printf1("Grew mark stack to %lu frames\n",
                   1039:                         (unsigned long) GC_mark_stack_size);
1.4     ! noro     1040:            }
1.1       noro     1041: #        endif
                   1042:         } else {
1.4     ! noro     1043: #        ifdef CONDPRINT
        !          1044:            if (GC_print_stats) {
1.1       noro     1045:              GC_printf1("Failed to grow mark stack to %lu frames\n",
                   1046:                         (unsigned long) n);
1.4     ! noro     1047:            }
1.1       noro     1048: #        endif
                   1049:         }
                   1050:     } else {
                   1051:         if (new_stack == 0) {
                   1052:             GC_err_printf0("No space for mark stack\n");
                   1053:             EXIT();
                   1054:         }
                   1055:         GC_mark_stack = new_stack;
                   1056:         GC_mark_stack_size = n;
1.4     ! noro     1057:        GC_mark_stack_limit = new_stack + n;
1.1       noro     1058:     }
                   1059:     GC_mark_stack_top = GC_mark_stack-1;
                   1060: }
                   1061:
                   1062: void GC_mark_init()
                   1063: {
                   1064:     alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
                   1065: }
                   1066:
                   1067: /*
                   1068:  * Push all locations between b and t onto the mark stack.
                   1069:  * b is the first location to be checked. t is one past the last
                   1070:  * location to be checked.
                   1071:  * Should only be used if there is no possibility of mark stack
                   1072:  * overflow.
                   1073:  */
                   1074: void GC_push_all(bottom, top)
                   1075: ptr_t bottom;
                   1076: ptr_t top;
                   1077: {
                   1078:     register word length;
                   1079:
                   1080:     bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
                   1081:     top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
                   1082:     if (top == 0 || bottom == top) return;
                   1083:     GC_mark_stack_top++;
1.4     ! noro     1084:     if (GC_mark_stack_top >= GC_mark_stack_limit) {
1.1       noro     1085:        ABORT("unexpected mark stack overflow");
                   1086:     }
                   1087:     length = top - bottom;
1.4     ! noro     1088: #   if GC_DS_TAGS > ALIGNMENT - 1
        !          1089:        length += GC_DS_TAGS;
        !          1090:        length &= ~GC_DS_TAGS;
1.1       noro     1091: #   endif
                   1092:     GC_mark_stack_top -> mse_start = (word *)bottom;
                   1093:     GC_mark_stack_top -> mse_descr = length;
                   1094: }
                   1095:
                   1096: /*
1.4     ! noro     1097:  * Analogous to the above, but push only those pages h with dirty_fn(h) != 0.
1.1       noro     1098:  * We use push_fn to actually push the block.
1.4     ! noro     1099:  * Used both to selectively push dirty pages, or to push a block
        !          1100:  * in piecemeal fashion, to allow for more marking concurrency.
1.1       noro     1101:  * Will not overflow mark stack if push_fn pushes a small fixed number
                   1102:  * of entries.  (This is invoked only if push_fn pushes a single entry,
                   1103:  * or if it marks each object before pushing it, thus ensuring progress
                   1104:  * in the event of a stack overflow.)
                   1105:  */
1.4     ! noro     1106: void GC_push_selected(bottom, top, dirty_fn, push_fn)
1.1       noro     1107: ptr_t bottom;
                   1108: ptr_t top;
1.4     ! noro     1109: int (*dirty_fn) GC_PROTO((struct hblk * h));
        !          1110: void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top));
1.1       noro     1111: {
                   1112:     register struct hblk * h;
                   1113:
                   1114:     bottom = (ptr_t)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
                   1115:     top = (ptr_t)(((long) top) & ~(ALIGNMENT-1));
                   1116:
                   1117:     if (top == 0 || bottom == top) return;
                   1118:     h = HBLKPTR(bottom + HBLKSIZE);
                   1119:     if (top <= (ptr_t) h) {
                   1120:        if ((*dirty_fn)(h-1)) {
                   1121:            (*push_fn)(bottom, top);
                   1122:        }
                   1123:        return;
                   1124:     }
                   1125:     if ((*dirty_fn)(h-1)) {
                   1126:         (*push_fn)(bottom, (ptr_t)h);
                   1127:     }
                   1128:     while ((ptr_t)(h+1) <= top) {
                   1129:        if ((*dirty_fn)(h)) {
                   1130:            if ((word)(GC_mark_stack_top - GC_mark_stack)
                   1131:                > 3 * GC_mark_stack_size / 4) {
                   1132:                /* Danger of mark stack overflow */
                   1133:                (*push_fn)((ptr_t)h, top);
                   1134:                return;
                   1135:            } else {
                   1136:                (*push_fn)((ptr_t)h, (ptr_t)(h+1));
                   1137:            }
                   1138:        }
                   1139:        h++;
                   1140:     }
                   1141:     if ((ptr_t)h != top) {
                   1142:        if ((*dirty_fn)(h)) {
                   1143:             (*push_fn)((ptr_t)h, top);
                   1144:         }
                   1145:     }
1.4     ! noro     1146:     if (GC_mark_stack_top >= GC_mark_stack_limit) {
1.1       noro     1147:         ABORT("unexpected mark stack overflow");
                   1148:     }
                   1149: }
                   1150:
                   1151: # ifndef SMALL_CONFIG
1.4     ! noro     1152:
        !          1153: #ifdef PARALLEL_MARK
        !          1154:     /* Break up root sections into page size chunks to better spread   */
        !          1155:     /* out work.                                                       */
        !          1156:     GC_bool GC_true_func(struct hblk *h) { return TRUE; }
        !          1157: #   define GC_PUSH_ALL(b,t) GC_push_selected(b,t,GC_true_func,GC_push_all);
        !          1158: #else
        !          1159: #   define GC_PUSH_ALL(b,t) GC_push_all(b,t);
        !          1160: #endif
        !          1161:
        !          1162:
1.1       noro     1163: void GC_push_conditional(bottom, top, all)
                   1164: ptr_t bottom;
                   1165: ptr_t top;
                   1166: int all;
                   1167: {
                   1168:     if (all) {
                   1169:       if (GC_dirty_maintained) {
                   1170: #      ifdef PROC_VDB
                   1171:            /* Pages that were never dirtied cannot contain pointers    */
1.4     ! noro     1172:            GC_push_selected(bottom, top, GC_page_was_ever_dirty, GC_push_all);
1.1       noro     1173: #      else
                   1174:            GC_push_all(bottom, top);
                   1175: #      endif
                   1176:       } else {
                   1177:        GC_push_all(bottom, top);
                   1178:       }
                   1179:     } else {
1.4     ! noro     1180:        GC_push_selected(bottom, top, GC_page_was_dirty, GC_push_all);
1.1       noro     1181:     }
                   1182: }
                   1183: #endif
                   1184:
1.4     ! noro     1185: # if defined(MSWIN32) || defined(MSWINCE)
1.1       noro     1186:   void __cdecl GC_push_one(p)
                   1187: # else
                   1188:   void GC_push_one(p)
                   1189: # endif
                   1190: word p;
                   1191: {
1.3       noro     1192:     GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
1.1       noro     1193: }
                   1194:
1.4     ! noro     1195: struct GC_ms_entry *GC_mark_and_push(obj, mark_stack_ptr, mark_stack_limit, src)
        !          1196: GC_PTR obj;
        !          1197: struct GC_ms_entry * mark_stack_ptr;
        !          1198: struct GC_ms_entry * mark_stack_limit;
        !          1199: GC_PTR *src;
        !          1200: {
        !          1201:    PREFETCH(obj);
        !          1202:    PUSH_CONTENTS(obj, mark_stack_ptr /* modified */, mark_stack_limit, src,
        !          1203:                 was_marked /* internally generated exit label */);
        !          1204:    return mark_stack_ptr;
        !          1205: }
        !          1206:
1.1       noro     1207: # ifdef __STDC__
                   1208: #   define BASE(p) (word)GC_base((void *)(p))
                   1209: # else
                   1210: #   define BASE(p) (word)GC_base((char *)(p))
                   1211: # endif
                   1212:
1.4     ! noro     1213: /* Mark and push (i.e. gray) a single object p onto the main   */
        !          1214: /* mark stack.  Consider p to be valid if it is an interior    */
        !          1215: /* pointer.                                                    */
        !          1216: /* The object p has passed a preliminary pointer validity      */
        !          1217: /* test, but we do not definitely know whether it is valid.    */
        !          1218: /* Mark bits are NOT atomically updated.  Thus this must be the        */
        !          1219: /* only thread setting them.                                   */
1.1       noro     1220: # if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
1.4     ! noro     1221:     void GC_mark_and_push_stack(p, source)
1.1       noro     1222:     ptr_t source;
                   1223: # else
1.4     ! noro     1224:     void GC_mark_and_push_stack(p)
1.1       noro     1225: #   define source 0
                   1226: # endif
                   1227: register word p;
                   1228: {
                   1229:     register word r;
                   1230:     register hdr * hhdr;
                   1231:     register int displ;
                   1232:
                   1233:     GET_HDR(p, hhdr);
                   1234:     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
1.4     ! noro     1235:         if (hhdr != 0) {
1.1       noro     1236:           r = BASE(p);
                   1237:          hhdr = HDR(r);
                   1238:          displ = BYTES_TO_WORDS(HBLKDISPL(r));
                   1239:        }
                   1240:     } else {
                   1241:         register map_entry_type map_entry;
                   1242:
                   1243:         displ = HBLKDISPL(p);
                   1244:         map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
1.4     ! noro     1245:         if (map_entry >= MAX_OFFSET) {
        !          1246:           if (map_entry == OFFSET_TOO_BIG || !GC_all_interior_pointers) {
1.1       noro     1247:               r = BASE(p);
                   1248:              displ = BYTES_TO_WORDS(HBLKDISPL(r));
                   1249:              if (r == 0) hhdr = 0;
1.4     ! noro     1250:           } else {
        !          1251:              /* Offset invalid, but map reflects interior pointers     */
1.1       noro     1252:               hhdr = 0;
1.4     ! noro     1253:           }
1.1       noro     1254:         } else {
                   1255:           displ = BYTES_TO_WORDS(displ);
                   1256:           displ -= map_entry;
                   1257:           r = (word)((word *)(HBLKPTR(p)) + displ);
                   1258:         }
                   1259:     }
                   1260:     /* If hhdr != 0 then r == GC_base(p), only we did it faster. */
                   1261:     /* displ is the word index within the block.                */
                   1262:     if (hhdr == 0) {
1.4     ! noro     1263: #      ifdef PRINT_BLACK_LIST
        !          1264:          GC_add_to_black_list_stack(p, source);
        !          1265: #      else
        !          1266:          GC_add_to_black_list_stack(p);
        !          1267: #      endif
        !          1268: #      undef source  /* In case we had to define it. */
1.1       noro     1269:     } else {
                   1270:        if (!mark_bit_from_hdr(hhdr, displ)) {
                   1271:            set_mark_bit_from_hdr(hhdr, displ);
                   1272:            GC_STORE_BACK_PTR(source, (ptr_t)r);
                   1273:            PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top,
1.4     ! noro     1274:                     GC_mark_stack_limit);
1.1       noro     1275:        }
                   1276:     }
                   1277: }
                   1278:
                   1279: # ifdef TRACE_BUF
                   1280:
                   1281: # define TRACE_ENTRIES 1000
                   1282:
                   1283: struct trace_entry {
                   1284:     char * kind;
                   1285:     word gc_no;
                   1286:     word words_allocd;
                   1287:     word arg1;
                   1288:     word arg2;
                   1289: } GC_trace_buf[TRACE_ENTRIES];
                   1290:
                   1291: int GC_trace_buf_ptr = 0;
                   1292:
                   1293: void GC_add_trace_entry(char *kind, word arg1, word arg2)
                   1294: {
                   1295:     GC_trace_buf[GC_trace_buf_ptr].kind = kind;
                   1296:     GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
                   1297:     GC_trace_buf[GC_trace_buf_ptr].words_allocd = GC_words_allocd;
                   1298:     GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
                   1299:     GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
                   1300:     GC_trace_buf_ptr++;
                   1301:     if (GC_trace_buf_ptr >= TRACE_ENTRIES) GC_trace_buf_ptr = 0;
                   1302: }
                   1303:
                   1304: void GC_print_trace(word gc_no, GC_bool lock)
                   1305: {
                   1306:     int i;
                   1307:     struct trace_entry *p;
                   1308:
                   1309:     if (lock) LOCK();
                   1310:     for (i = GC_trace_buf_ptr-1; i != GC_trace_buf_ptr; i--) {
                   1311:        if (i < 0) i = TRACE_ENTRIES-1;
                   1312:        p = GC_trace_buf + i;
                   1313:        if (p -> gc_no < gc_no || p -> kind == 0) return;
                   1314:        printf("Trace:%s (gc:%d,words:%d) 0x%X, 0x%X\n",
                   1315:                p -> kind, p -> gc_no, p -> words_allocd,
                   1316:                (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
                   1317:     }
                   1318:     printf("Trace incomplete\n");
                   1319:     if (lock) UNLOCK();
                   1320: }
                   1321:
                   1322: # endif /* TRACE_BUF */
                   1323:
                   1324: /*
                   1325:  * A version of GC_push_all that treats all interior pointers as valid
                   1326:  * and scans the entire region immediately, in case the contents
                   1327:  * change.
                   1328:  */
                   1329: void GC_push_all_eager(bottom, top)
                   1330: ptr_t bottom;
                   1331: ptr_t top;
                   1332: {
                   1333:     word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
                   1334:     word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
                   1335:     register word *p;
                   1336:     register word q;
                   1337:     register word *lim;
                   1338:     register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
                   1339:     register ptr_t least_ha = GC_least_plausible_heap_addr;
                   1340: #   define GC_greatest_plausible_heap_addr greatest_ha
                   1341: #   define GC_least_plausible_heap_addr least_ha
                   1342:
                   1343:     if (top == 0) return;
                   1344:     /* check all pointers in range and put in push if they appear */
                   1345:     /* to be valid.                                              */
                   1346:       lim = t - 1 /* longword */;
                   1347:       for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
                   1348:        q = *p;
                   1349:        GC_PUSH_ONE_STACK(q, p);
                   1350:       }
                   1351: #   undef GC_greatest_plausible_heap_addr
                   1352: #   undef GC_least_plausible_heap_addr
                   1353: }
                   1354:
                   1355: #ifndef THREADS
                   1356: /*
                   1357:  * A version of GC_push_all that treats all interior pointers as valid
                   1358:  * and scans part of the area immediately, to make sure that saved
                   1359:  * register values are not lost.
                   1360:  * Cold_gc_frame delimits the stack section that must be scanned
                   1361:  * eagerly.  A zero value indicates that no eager scanning is needed.
                   1362:  */
                   1363: void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame)
                   1364: ptr_t bottom;
                   1365: ptr_t top;
                   1366: ptr_t cold_gc_frame;
                   1367: {
1.4     ! noro     1368:   if (GC_all_interior_pointers) {
1.1       noro     1369: #   define EAGER_BYTES 1024
                   1370:     /* Push the hot end of the stack eagerly, so that register values   */
                   1371:     /* saved inside GC frames are marked before they disappear.                */
                   1372:     /* The rest of the marking can be deferred until later.            */
                   1373:     if (0 == cold_gc_frame) {
                   1374:        GC_push_all_stack(bottom, top);
                   1375:        return;
                   1376:     }
                   1377: #   ifdef STACK_GROWS_DOWN
                   1378:        GC_push_all_eager(bottom, cold_gc_frame);
                   1379:        GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
                   1380: #   else /* STACK_GROWS_UP */
                   1381:        GC_push_all_eager(cold_gc_frame, top);
                   1382:        GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t));
                   1383: #   endif /* STACK_GROWS_UP */
1.4     ! noro     1384:   } else {
1.1       noro     1385:     GC_push_all_eager(bottom, top);
1.4     ! noro     1386:   }
1.1       noro     1387: # ifdef TRACE_BUF
                   1388:       GC_add_trace_entry("GC_push_all_stack", bottom, top);
                   1389: # endif
                   1390: }
                   1391: #endif /* !THREADS */
                   1392:
                   1393: void GC_push_all_stack(bottom, top)
                   1394: ptr_t bottom;
                   1395: ptr_t top;
                   1396: {
1.4     ! noro     1397:   if (GC_all_interior_pointers) {
1.1       noro     1398:     GC_push_all(bottom, top);
1.4     ! noro     1399:   } else {
1.1       noro     1400:     GC_push_all_eager(bottom, top);
1.4     ! noro     1401:   }
1.1       noro     1402: }
                   1403:
1.4     ! noro     1404: #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1       noro     1405: /* Push all objects reachable from marked objects in the given block */
                   1406: /* of size 1 objects.                                               */
                   1407: void GC_push_marked1(h, hhdr)
                   1408: struct hblk *h;
                   1409: register hdr * hhdr;
                   1410: {
1.4     ! noro     1411:     word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1       noro     1412:     register word *p;
                   1413:     word *plim;
                   1414:     register int i;
                   1415:     register word q;
                   1416:     register word mark_word;
                   1417:     register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
                   1418:     register ptr_t least_ha = GC_least_plausible_heap_addr;
1.4     ! noro     1419:     register mse * mark_stack_top = GC_mark_stack_top;
        !          1420:     register mse * mark_stack_limit = GC_mark_stack_limit;
        !          1421: #   define GC_mark_stack_top mark_stack_top
        !          1422: #   define GC_mark_stack_limit mark_stack_limit
1.1       noro     1423: #   define GC_greatest_plausible_heap_addr greatest_ha
                   1424: #   define GC_least_plausible_heap_addr least_ha
                   1425:
                   1426:     p = (word *)(h->hb_body);
                   1427:     plim = (word *)(((word)h) + HBLKSIZE);
                   1428:
                   1429:     /* go through all words in block */
                   1430:        while( p < plim )  {
                   1431:            mark_word = *mark_word_addr++;
                   1432:            i = 0;
                   1433:            while(mark_word != 0) {
                   1434:              if (mark_word & 1) {
                   1435:                  q = p[i];
                   1436:                  GC_PUSH_ONE_HEAP(q, p + i);
                   1437:              }
                   1438:              i++;
                   1439:              mark_word >>= 1;
                   1440:            }
                   1441:            p += WORDSZ;
                   1442:        }
                   1443: #   undef GC_greatest_plausible_heap_addr
                   1444: #   undef GC_least_plausible_heap_addr
1.4     ! noro     1445: #   undef GC_mark_stack_top
        !          1446: #   undef GC_mark_stack_limit
        !          1447:     GC_mark_stack_top = mark_stack_top;
1.1       noro     1448: }
                   1449:
                   1450:
                   1451: #ifndef UNALIGNED
                   1452:
                   1453: /* Push all objects reachable from marked objects in the given block */
                   1454: /* of size 2 objects.                                               */
                   1455: void GC_push_marked2(h, hhdr)
                   1456: struct hblk *h;
                   1457: register hdr * hhdr;
                   1458: {
1.4     ! noro     1459:     word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1       noro     1460:     register word *p;
                   1461:     word *plim;
                   1462:     register int i;
                   1463:     register word q;
                   1464:     register word mark_word;
                   1465:     register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
                   1466:     register ptr_t least_ha = GC_least_plausible_heap_addr;
1.4     ! noro     1467:     register mse * mark_stack_top = GC_mark_stack_top;
        !          1468:     register mse * mark_stack_limit = GC_mark_stack_limit;
        !          1469: #   define GC_mark_stack_top mark_stack_top
        !          1470: #   define GC_mark_stack_limit mark_stack_limit
1.1       noro     1471: #   define GC_greatest_plausible_heap_addr greatest_ha
                   1472: #   define GC_least_plausible_heap_addr least_ha
                   1473:
                   1474:     p = (word *)(h->hb_body);
                   1475:     plim = (word *)(((word)h) + HBLKSIZE);
                   1476:
                   1477:     /* go through all words in block */
                   1478:        while( p < plim )  {
                   1479:            mark_word = *mark_word_addr++;
                   1480:            i = 0;
                   1481:            while(mark_word != 0) {
                   1482:              if (mark_word & 1) {
                   1483:                  q = p[i];
                   1484:                  GC_PUSH_ONE_HEAP(q, p + i);
                   1485:                  q = p[i+1];
                   1486:                  GC_PUSH_ONE_HEAP(q, p + i);
                   1487:              }
                   1488:              i += 2;
                   1489:              mark_word >>= 2;
                   1490:            }
                   1491:            p += WORDSZ;
                   1492:        }
                   1493: #   undef GC_greatest_plausible_heap_addr
                   1494: #   undef GC_least_plausible_heap_addr
1.4     ! noro     1495: #   undef GC_mark_stack_top
        !          1496: #   undef GC_mark_stack_limit
        !          1497:     GC_mark_stack_top = mark_stack_top;
1.1       noro     1498: }
                   1499:
                   1500: /* Push all objects reachable from marked objects in the given block */
                   1501: /* of size 4 objects.                                               */
                   1502: /* There is a risk of mark stack overflow here.  But we handle that. */
                   1503: /* And only unmarked objects get pushed, so it's not very likely.    */
                   1504: void GC_push_marked4(h, hhdr)
                   1505: struct hblk *h;
                   1506: register hdr * hhdr;
                   1507: {
1.4     ! noro     1508:     word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1       noro     1509:     register word *p;
                   1510:     word *plim;
                   1511:     register int i;
                   1512:     register word q;
                   1513:     register word mark_word;
                   1514:     register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
                   1515:     register ptr_t least_ha = GC_least_plausible_heap_addr;
1.4     ! noro     1516:     register mse * mark_stack_top = GC_mark_stack_top;
        !          1517:     register mse * mark_stack_limit = GC_mark_stack_limit;
        !          1518: #   define GC_mark_stack_top mark_stack_top
        !          1519: #   define GC_mark_stack_limit mark_stack_limit
1.1       noro     1520: #   define GC_greatest_plausible_heap_addr greatest_ha
                   1521: #   define GC_least_plausible_heap_addr least_ha
                   1522:
                   1523:     p = (word *)(h->hb_body);
                   1524:     plim = (word *)(((word)h) + HBLKSIZE);
                   1525:
                   1526:     /* go through all words in block */
                   1527:        while( p < plim )  {
                   1528:            mark_word = *mark_word_addr++;
                   1529:            i = 0;
                   1530:            while(mark_word != 0) {
                   1531:              if (mark_word & 1) {
                   1532:                  q = p[i];
                   1533:                  GC_PUSH_ONE_HEAP(q, p + i);
                   1534:                  q = p[i+1];
                   1535:                  GC_PUSH_ONE_HEAP(q, p + i + 1);
                   1536:                  q = p[i+2];
                   1537:                  GC_PUSH_ONE_HEAP(q, p + i + 2);
                   1538:                  q = p[i+3];
                   1539:                  GC_PUSH_ONE_HEAP(q, p + i + 3);
                   1540:              }
                   1541:              i += 4;
                   1542:              mark_word >>= 4;
                   1543:            }
                   1544:            p += WORDSZ;
                   1545:        }
                   1546: #   undef GC_greatest_plausible_heap_addr
                   1547: #   undef GC_least_plausible_heap_addr
1.4     ! noro     1548: #   undef GC_mark_stack_top
        !          1549: #   undef GC_mark_stack_limit
        !          1550:     GC_mark_stack_top = mark_stack_top;
1.1       noro     1551: }
                   1552:
                   1553: #endif /* UNALIGNED */
                   1554:
                   1555: #endif /* SMALL_CONFIG */
                   1556:
                   1557: /* Push all objects reachable from marked objects in the given block */
                   1558: void GC_push_marked(h, hhdr)
                   1559: struct hblk *h;
                   1560: register hdr * hhdr;
                   1561: {
                   1562:     register int sz = hhdr -> hb_sz;
1.3       noro     1563:     register int descr = hhdr -> hb_descr;
1.1       noro     1564:     register word * p;
                   1565:     register int word_no;
                   1566:     register word * lim;
                   1567:     register mse * GC_mark_stack_top_reg;
1.4     ! noro     1568:     register mse * mark_stack_limit = GC_mark_stack_limit;
1.1       noro     1569:
                   1570:     /* Some quick shortcuts: */
1.4     ! noro     1571:        if ((0 | GC_DS_LENGTH) == descr) return;
1.1       noro     1572:         if (GC_block_empty(hhdr)/* nothing marked */) return;
1.4     ! noro     1573:     GC_n_rescuing_pages++;
1.1       noro     1574:     GC_objects_are_marked = TRUE;
                   1575:     if (sz > MAXOBJSZ) {
1.4     ! noro     1576:         lim = (word *)h;
1.1       noro     1577:     } else {
                   1578:         lim = (word *)(h + 1) - sz;
                   1579:     }
                   1580:
                   1581:     switch(sz) {
1.4     ! noro     1582: #   if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1       noro     1583:      case 1:
                   1584:        GC_push_marked1(h, hhdr);
                   1585:        break;
                   1586: #   endif
1.4     ! noro     1587: #   if !defined(SMALL_CONFIG) && !defined(UNALIGNED) && \
        !          1588:        !defined(USE_MARK_BYTES)
1.1       noro     1589:      case 2:
                   1590:        GC_push_marked2(h, hhdr);
                   1591:        break;
                   1592:      case 4:
                   1593:        GC_push_marked4(h, hhdr);
                   1594:        break;
                   1595: #   endif
                   1596:      default:
                   1597:       GC_mark_stack_top_reg = GC_mark_stack_top;
1.4     ! noro     1598:       for (p = (word *)h, word_no = 0; p <= lim; p += sz, word_no += sz) {
1.1       noro     1599:          if (mark_bit_from_hdr(hhdr, word_no)) {
                   1600:            /* Mark from fields inside the object */
                   1601:              PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
                   1602: #           ifdef GATHERSTATS
                   1603:                /* Subtract this object from total, since it was        */
                   1604:                /* added in twice.                                      */
                   1605:                GC_composite_in_use -= sz;
                   1606: #           endif
                   1607:          }
                   1608:       }
                   1609:       GC_mark_stack_top = GC_mark_stack_top_reg;
                   1610:     }
                   1611: }
                   1612:
                   1613: #ifndef SMALL_CONFIG
                   1614: /* Test whether any page in the given block is dirty   */
                   1615: GC_bool GC_block_was_dirty(h, hhdr)
                   1616: struct hblk *h;
                   1617: register hdr * hhdr;
                   1618: {
                   1619:     register int sz = hhdr -> hb_sz;
                   1620:
                   1621:     if (sz < MAXOBJSZ) {
                   1622:          return(GC_page_was_dirty(h));
                   1623:     } else {
                   1624:         register ptr_t p = (ptr_t)h;
                   1625:          sz = WORDS_TO_BYTES(sz);
                   1626:          while (p < (ptr_t)h + sz) {
                   1627:              if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
                   1628:              p += HBLKSIZE;
                   1629:          }
                   1630:          return(FALSE);
                   1631:     }
                   1632: }
                   1633: #endif /* SMALL_CONFIG */
                   1634:
                   1635: /* Similar to GC_push_next_marked, but return address of next block    */
                   1636: struct hblk * GC_push_next_marked(h)
                   1637: struct hblk *h;
                   1638: {
                   1639:     register hdr * hhdr;
                   1640:
                   1641:     h = GC_next_used_block(h);
                   1642:     if (h == 0) return(0);
                   1643:     hhdr = HDR(h);
                   1644:     GC_push_marked(h, hhdr);
                   1645:     return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
                   1646: }
                   1647:
                   1648: #ifndef SMALL_CONFIG
                   1649: /* Identical to above, but mark only from dirty pages  */
                   1650: struct hblk * GC_push_next_marked_dirty(h)
                   1651: struct hblk *h;
                   1652: {
1.2       noro     1653:     register hdr * hhdr;
1.1       noro     1654:
                   1655:     if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
                   1656:     for (;;) {
                   1657:         h = GC_next_used_block(h);
                   1658:         if (h == 0) return(0);
                   1659:         hhdr = HDR(h);
                   1660: #      ifdef STUBBORN_ALLOC
                   1661:           if (hhdr -> hb_obj_kind == STUBBORN) {
                   1662:             if (GC_page_was_changed(h) && GC_block_was_dirty(h, hhdr)) {
                   1663:                 break;
                   1664:             }
                   1665:           } else {
                   1666:             if (GC_block_was_dirty(h, hhdr)) break;
                   1667:           }
                   1668: #      else
                   1669:          if (GC_block_was_dirty(h, hhdr)) break;
                   1670: #      endif
                   1671:         h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
                   1672:     }
                   1673:     GC_push_marked(h, hhdr);
                   1674:     return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
                   1675: }
                   1676: #endif
                   1677:
                   1678: /* Similar to above, but for uncollectable pages.  Needed since we     */
                   1679: /* do not clear marks for such pages, even for full collections.       */
                   1680: struct hblk * GC_push_next_marked_uncollectable(h)
                   1681: struct hblk *h;
                   1682: {
                   1683:     register hdr * hhdr = HDR(h);
                   1684:
                   1685:     for (;;) {
                   1686:         h = GC_next_used_block(h);
                   1687:         if (h == 0) return(0);
                   1688:         hhdr = HDR(h);
                   1689:        if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break;
                   1690:         h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
                   1691:     }
                   1692:     GC_push_marked(h, hhdr);
                   1693:     return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
                   1694: }
                   1695:
                   1696:

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