C:/Users/Dennis/src/lang/russell.orig/src/gc/mark.c

Go to the documentation of this file.
00001 
00002 /*
00003  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00004  * Copyright (c) 1991,1992 by Xerox Corporation.  All rights reserved.
00005  *
00006  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00007  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00008  *
00009  * Permission is hereby granted to copy this garbage collector for any purpose,
00010  * provided the above notices are retained on all copies.
00011  *
00012  * This file contains the functions:
00013  *      GC_mark()  -  Mark from the mark stack
00014  *      GC_mark_reliable()  -  as above, but fix things up after
00015  *                                      a mark stack overflow.
00016  *      GC_mark_all(b,t)  - Mark from everything in a range
00017  *      GC_mark_all_stack(b,t)  - Mark from everything in a range,
00018  *                                          consider interior pointers as valid
00019  *      GC_remark()  -  Mark from all marked objects.  Used
00020  *                               only if we had to drop something.
00021  */
00022 
00023 
00024 # include <stdio.h>
00025 # include "gc_private.h"
00026 
00027 # define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
00028                 /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a    */
00029                 /* multiple of HBLKSIZE.                                */
00030 
00031 /*
00032  * Limits of stack for GC_mark routine.  Set by caller to GC_mark.
00033  * All items between GC_mark_stack_top and GC_mark_stack_bottom-1 still need
00034  * to be marked.  All items on the stack satisfy quicktest.  They do
00035  * not necessarily reference real objects.
00036  */
00037  
00038 mse * GC_mark_stack;
00039 
00040 word GC_mark_stack_size = 0;
00041  
00042 mse * GC_mark_stack_top;
00043 
00044 static bool dropped_some = FALSE;
00045                                 /* We ran out of space and were forced  */
00046                                 /* to drop some pointers during marking */
00047 
00048 /* Mark procedure for objects that may contain arbitrary pointers.      */
00049 /* Msp is the current mark stack pointer. Msl limits the stack.         */
00050 /* We return the new stack pointer value.                               */
00051 /* The object at addr has already been marked.  Our job is to make      */
00052 /* sure that its descendents are marked.                                */
00053 mse * GC_normal_mark_proc(addr, hhdr, msp, msl)
00054 register word * addr;
00055 register hdr * hhdr;
00056 register mse * msp, * msl;
00057 {
00058     register word sz = hhdr -> hb_sz;
00059     
00060     msp++;
00061     /* Push the contents of the object on the mark stack. */
00062         if (msp >= msl) {
00063             dropped_some = TRUE;
00064             return(msp-1);
00065         }
00066         msp -> mse_start = addr;
00067         msp -> mse_end = addr + sz;
00068 #   ifdef GATHERSTATS
00069         GC_composite_in_use += sz;
00070 #   endif
00071     return(msp);
00072 }
00073 
00074 /* Mark procedure for objects that are known to contain no pointers.    */
00075 /*ARGSUSED*/
00076 mse * GC_no_mark_proc(addr, hhdr, msp, msl)
00077 register word * addr;
00078 register hdr * hhdr;
00079 register mse * msp, * msl;
00080 {
00081 #   ifdef GATHERSTATS
00082         GC_atomic_in_use += hhdr -> hb_sz;
00083 #   endif
00084     return(msp);
00085 }
00086         
00087 
00088 /*
00089  * Mark all objects pointed to by the regions described by
00090  * mark stack entries between GC_mark_stack and GC_mark_stack_top,
00091  * inclusive.  We assume and preserve the invariant
00092  * that everything on the mark stack points into a hblk that has an
00093  * allocated header.  Assumes the upper limit of a mark stack entry
00094  * is never 0.
00095  */
00096 void GC_mark()
00097 {
00098   mse * GC_mark_stack_reg = GC_mark_stack;
00099   mse * GC_mark_stack_top_reg = GC_mark_stack_top;
00100   mse * mark_stack_limit = &(GC_mark_stack[GC_mark_stack_size]);
00101   register word * current_p;    /* Pointer to current candidate ptr.    */
00102   register word current;        /* Candidate pointer.                   */
00103   register word * limit;        /* (Incl) limit of current candidate    */
00104                                 /* range                                */
00105   register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
00106   register ptr_t least_ha = GC_least_plausible_heap_addr;
00107 # define SPLIT_RANGE_WORDS 128
00108 
00109   while (GC_mark_stack_top_reg >= GC_mark_stack_reg) {
00110     register int displ;  /* Displacement in block; first bytes, then words */
00111     register hdr * hhdr;
00112     register map_entry_type map_entry;
00113 
00114     current_p = GC_mark_stack_top_reg -> mse_start;
00115     limit = GC_mark_stack_top_reg -> mse_end;
00116     if (limit - current_p > SPLIT_RANGE_WORDS) {
00117       /* Process part of the range to avoid pushing too much on the     */
00118       /* stack.                                                         */
00119          GC_mark_stack_top_reg -> mse_start =
00120                 limit = current_p + SPLIT_RANGE_WORDS;
00121       /* Make sure that pointers overlapping the two ranges are         */
00122       /* considered.                                                    */
00123          limit += sizeof(word) - ALIGNMENT;
00124     } else {
00125       GC_mark_stack_top_reg--;
00126     }
00127     limit -= 1;
00128     
00129     while (current_p <= limit) {
00130       current = *current_p;
00131       current_p = (word *)((char *)current_p + ALIGNMENT);
00132       
00133       if ((ptr_t)current < least_ha) continue;
00134       if ((ptr_t)current >= greatest_ha) continue;
00135       hhdr = HDR(current);
00136       if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
00137 #       ifdef ALL_INTERIOR_POINTERS
00138           if (hhdr != 0) {
00139             register word orig = current;
00140             
00141             current = (word)HBLKPTR(current) + HDR_BYTES;
00142             do {
00143               current = current - HBLKSIZE*(int)hhdr;
00144               hhdr = HDR(current);
00145             } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
00146             /* current points to the start of the large object */
00147             if ((word *)orig - (word *)current
00148                  >= hhdr->hb_sz) {
00149                 /* Pointer past the end of the block */
00150                 GC_ADD_TO_BLACK_LIST_NORMAL(current);
00151                 continue;
00152             }
00153           } else {
00154             GC_ADD_TO_BLACK_LIST_NORMAL(current);
00155             continue;
00156           }
00157 #       else
00158           GC_ADD_TO_BLACK_LIST_NORMAL(current);
00159           continue;
00160 #       endif         
00161       }
00162       displ = HBLKDISPL(current);
00163       map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
00164       if (map_entry == OBJ_INVALID) {
00165           GC_ADD_TO_BLACK_LIST_NORMAL(current);
00166           continue;
00167       }
00168       displ = BYTES_TO_WORDS(displ);
00169       displ -= map_entry;
00170 
00171       {
00172           register word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(displ);
00173           register word mark_word = *mark_word_addr;
00174           register word mark_bit = 1 << modWORDSZ(displ);
00175           
00176           if (mark_word & mark_bit) {
00177               /* Mark bit is already set */
00178               continue;
00179           }
00180 
00181           *mark_word_addr = mark_word | mark_bit;
00182       }
00183     
00184       GC_mark_stack_top_reg =
00185           (* (hhdr -> hb_mark_proc))((word *)(HBLKPTR(current)) + displ, hhdr,
00186                                      GC_mark_stack_top_reg, mark_stack_limit);
00187     }
00188   }
00189   GC_mark_stack_top = GC_mark_stack_top_reg;
00190 }
00191 
00192 /* Allocate or reallocate space for mark stack of size s words  */
00193 /* May silently fail.                                           */
00194 static void alloc_mark_stack(n)
00195 word n;
00196 {
00197     mse * new_stack = (mse *)GET_MEM(n * sizeof(struct ms_entry));
00198     
00199     if (GC_mark_stack_size != 0) {
00200         if (new_stack != 0) {
00201           /* Recycle old space */
00202             GC_add_to_heap((struct hblk *)GC_mark_stack,
00203                            GC_mark_stack_size * sizeof(struct ms_entry));
00204           GC_mark_stack = new_stack;
00205           GC_mark_stack_size = n;
00206         }
00207     } else {
00208         if (new_stack == 0) {
00209             GC_err_printf0("No space for mark stack\n");
00210             EXIT();
00211         }
00212         GC_mark_stack = new_stack;
00213         GC_mark_stack_size = n;
00214     }
00215     GC_mark_stack_top = GC_mark_stack-1;
00216 }
00217 
00218 void GC_mark_init()
00219 {
00220     alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
00221 }
00222 
00223 /* Identical to GC_mark, but guarantee that dropped_some is false */
00224 /* when we finish.                                                */
00225 void GC_mark_reliable()
00226 {
00227     dropped_some = FALSE;
00228     GC_mark();
00229     while (dropped_some) {
00230         dropped_some = FALSE;
00231 #       ifdef PRINTSTATS
00232             GC_printf1("Mark stack overflow; current size = %lu entries\n",
00233                        GC_mark_stack_size);
00234 #       endif      
00235         alloc_mark_stack(2*GC_mark_stack_size);
00236         GC_remark();
00237     }
00238 }
00239 
00240 /*********************************************************************/
00241 /* Mark all locations reachable via pointers located between b and t */
00242 /* b is the first location to be checked. t is one past the last     */
00243 /* location to be checked.                                           */
00244 /*********************************************************************/
00245 void GC_mark_all(bottom, top)
00246 ptr_t bottom;
00247 ptr_t top;
00248 {
00249     word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
00250     word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
00251     
00252     if (GC_mark_stack_top != GC_mark_stack-1) {
00253         ABORT("GC_mark_all: bad mark stack\n");
00254     }
00255     if (top == 0) return;
00256     GC_mark_stack_top++;
00257     GC_mark_stack_top -> mse_start = b;
00258     GC_mark_stack_top -> mse_end = t;
00259     GC_mark_reliable();
00260 }
00261 
00262 word * GC_buffer;       /* Buffer for stack marking */
00263 # define BUFSIZE 1024
00264 
00265 /*
00266  * A version of GC_mark_all that treats all interior pointers as valid
00267  */
00268 void GC_mark_all_stack(bottom, top)
00269 ptr_t bottom;
00270 ptr_t top;
00271 {
00272 # ifdef ALL_INTERIOR_POINTERS
00273     GC_mark_all(bottom, top);
00274 # else
00275     word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
00276     word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
00277     register word *p;
00278     register word q;
00279     register word r;
00280     register word *lim;
00281     word * bufptr;
00282     word * limit;
00283     register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
00284     register ptr_t least_ha = GC_least_plausible_heap_addr;
00285 
00286     if (top == 0) return;
00287   /* Allocate GC_buffer someplace where collector won't accidentally    */
00288   /* see old sections.                                                  */
00289     if (GC_buffer == 0) {
00290         GC_buffer = (word *)GC_scratch_alloc((word)(BUFSIZE * sizeof(word)));
00291     }
00292     bufptr = GC_buffer;
00293     limit = GC_buffer+BUFSIZE;
00294   /* check all pointers in range and put in buffer if they appear */
00295   /* to be valid.                                                 */
00296     lim = t - 1 /* longword */;
00297     for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
00298         q = *p;
00299         if ((ptr_t)q < least_ha 
00300             || (ptr_t)q >= greatest_ha) {
00301             continue;
00302         }
00303 #       ifdef __STDC__
00304             r = (word)GC_base((void *)q);
00305 #       else
00306             r = (word)GC_base((char *)q);
00307 #       endif
00308         if (r == 0) {
00309             GC_add_to_black_list_stack(*p);
00310         } else {
00311             *(bufptr++) = r;
00312             if (bufptr == limit) {
00313                 GC_mark_all((ptr_t)GC_buffer, (ptr_t)limit);
00314                 bufptr = GC_buffer;
00315             }
00316         }
00317     }
00318     if (bufptr != GC_buffer) GC_mark_all((ptr_t)GC_buffer, (ptr_t)bufptr);
00319 # endif
00320 }
00321 
00322 /* Mark all objects reachable from marked objects in the given block */
00323 /*ARGSUSED*/
00324 static void remark_block(h, dummy)
00325 struct hblk *h;
00326 word dummy;
00327 {
00328     register hdr * hhdr = HDR(h);
00329     register int sz = hhdr -> hb_sz;
00330     register word * p;
00331     register int word_no;
00332     register word * lim;
00333     register mse * GC_mark_stack_top_reg = GC_mark_stack_top;
00334     
00335     if (sz < 0) return;
00336     if (sz > MAXOBJSZ) {
00337         lim = (word *)(h + 1);
00338     } else {
00339         lim = (word *)(h + 1) - sz;
00340     }
00341     
00342     for (p = (word *)h + HDR_WORDS, word_no = HDR_WORDS; p <= lim;
00343          p += sz, word_no += sz) {
00344          if (mark_bit_from_hdr(hhdr, word_no)) {
00345            /* Mark from fields inside the object */
00346              GC_mark_stack_top_reg++;
00347              GC_mark_stack_top_reg -> mse_start = p;
00348              GC_mark_stack_top_reg -> mse_end = p + sz;
00349          }
00350     }
00351     GC_mark();   
00352 }
00353 
00354 /*
00355  * Traverse the heap.  Mark all objects reachable from marked objects.
00356  */
00357 void GC_remark()
00358 {
00359     GC_apply_to_all_blocks(remark_block, 0);
00360 }
00361 

Generated on Fri Jan 25 10:39:45 2008 for russell by  doxygen 1.5.4