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

Go to the documentation of this file.
00001 # include <stdio.h>
00002 # include "gc_private.h"
00003 
00004 # ifdef PCR
00005 #   define MAX_ROOT_SETS 1024
00006 #   include "pcr/il/PCR_IL.h"
00007 #   include "pcr/th/PCR_ThCtl.h"
00008 #   include "pcr/mm/PCR_MM.h"
00009 # else
00010 #   define MAX_ROOT_SETS 64
00011 # endif
00012 
00013 /* Data structure for list of root sets.                                */
00014 /* We keep a hash table, so that we can filter out duplicate additions. */
00015 struct roots {
00016         ptr_t r_start;
00017         ptr_t r_end;
00018         struct roots * r_next;
00019 };
00020 
00021 static struct roots static_roots[MAX_ROOT_SETS];
00022 
00023 static n_root_sets = 0;
00024 
00025         /* static_roots[0..n_root_sets) contains the valid root sets. */
00026 
00027 #define RT_SIZE 64  /* Power of 2, may be != MAX_ROOT_SETS */
00028 #define LOG_RT_SIZE 6
00029 
00030 static struct roots * root_index[RT_SIZE];
00031         /* Hash table header.  Used only to check whether a range is    */
00032         /* already present.                                             */
00033 
00034 static int rt_hash(addr)
00035 char * addr;
00036 {
00037     word result = (word) addr;
00038 #   if CPP_WORDSZ > 8*LOG_RT_SIZE
00039         result ^= result >> 8*LOG_RT_SIZE;
00040 #   endif
00041 #   if CPP_WORDSZ > 4*LOG_RT_SIZE
00042         result ^= result >> 4*LOG_RT_SIZE;
00043 #   endif
00044     result ^= result >> 2*LOG_RT_SIZE;
00045     result ^= result >> LOG_RT_SIZE;
00046     result &= (RT_SIZE-1);
00047     return(result);
00048 }
00049 
00050 /* Is a range starting at addr already in the table? */
00051 static bool roots_present(b, e)
00052 char *b, *e;
00053 {
00054     register int h = rt_hash(b);
00055     register struct roots *p = root_index[h];
00056     
00057     while (p != 0) {
00058         if (p -> r_start == (ptr_t)b && p -> r_end >= (ptr_t)e) return(TRUE);
00059         p = p -> r_next;
00060     }
00061     return(FALSE);
00062 }
00063 
00064 /* Add the given root structure to the index. */
00065 static void add_roots_to_index(p)
00066 struct roots *p;
00067 {
00068     register int h = rt_hash(p -> r_start);
00069     
00070     p -> r_next = root_index[h];
00071     root_index[h] = p;
00072 }
00073 
00074 
00075 word GC_root_size = 0;
00076 
00077 void GC_add_roots(b, e)
00078 char * b; char * e;
00079 {
00080     DCL_LOCK_STATE;
00081     
00082     DISABLE_SIGNALS();
00083     LOCK();
00084     GC_add_roots_inner(b, e);
00085     UNLOCK();
00086     ENABLE_SIGNALS();
00087 }
00088 
00089 
00090 /* Add [b,e) to the root set.  Adding the same interval a second time   */
00091 /* is a moderately fast noop, and hence benign.  We do not handle       */
00092 /* different but overlapping intervals efficiently.  (We do handle      */
00093 /* them correctly.)                                                     */
00094 void GC_add_roots_inner(b, e)
00095 char * b; char * e;
00096 {
00097     /* We exclude GC data structures from root sets.  It's usually safe */
00098     /* to mark from those, but it is a waste of time.                   */
00099     if ( (ptr_t)b < beginGC_arrays && (ptr_t)e > beginGC_arrays) {
00100         if ((ptr_t)e <= endGC_arrays) {
00101             e = (char *)beginGC_arrays;
00102         } else {
00103             GC_add_roots_inner(b, (char *)beginGC_arrays);
00104             GC_add_roots_inner((char *)endGC_arrays, e);
00105             return;
00106         }
00107     } else if ((ptr_t)b < endGC_arrays && (ptr_t)e > endGC_arrays) {
00108         b = (char *)endGC_arrays;
00109     }
00110     if (roots_present(b,e)) return;
00111     if (n_root_sets == MAX_ROOT_SETS) {
00112         ABORT("Too many root sets\n");
00113     }
00114     static_roots[n_root_sets].r_start = (ptr_t)b;
00115     static_roots[n_root_sets].r_end = (ptr_t)e;
00116     static_roots[n_root_sets].r_next = 0;
00117     add_roots_to_index(static_roots + n_root_sets);
00118     GC_root_size += (ptr_t)e - (ptr_t)b;
00119     n_root_sets++;
00120 }
00121 
00122 void GC_clear_roots()
00123 {
00124     DCL_LOCK_STATE;
00125     
00126     DISABLE_SIGNALS();
00127     LOCK();
00128     n_root_sets = 0;
00129     GC_root_size = 0;
00130     UNLOCK();
00131     ENABLE_SIGNALS();
00132 }
00133 
00134 # ifdef PCR
00135 PCR_ERes GC_mark_thread_stack(PCR_Th_T *t, PCR_Any dummy)
00136 {
00137     struct PCR_ThCtl_TInfoRep info;
00138     PCR_ERes result;
00139     
00140     info.ti_stkLow = info.ti_stkHi = 0;
00141     result = PCR_ThCtl_GetInfo(t, &info);
00142     GC_mark_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
00143     return(result);
00144 }
00145 
00146 PCR_ERes GC_mark_old_obj(void *p, size_t size, PCR_Any data)
00147 {
00148     GC_mark_all((ptr_t)p, (ptr_t)p + size);
00149     return(PCR_ERes_okay);
00150 }
00151 
00152 # else
00153 ptr_t GC_approx_sp()
00154 {
00155     word dummy;
00156     
00157     return((ptr_t)(&dummy));
00158 }
00159 # endif
00160 /*
00161  * Call the mark routines (GC_tl_mark for a single pointer, GC_mark_all
00162  * on groups of pointers) on every top level accessible pointer.
00163  * This is source language specific.  The following works for C.
00164  */
00165 
00166 GC_mark_roots()
00167 {
00168     register int i;
00169 
00170     /*
00171      * mark from registers - i.e., call GC_tl_mark(i) for each
00172      * register i
00173      */
00174         GC_mark_regs(); /* usually defined in machine_dep.c */
00175 
00176 
00177 #   ifdef PCR
00178         /* Traverse data allocated by previous memory managers.         */
00179         {
00180           extern struct PCR_MM_ProcsRep * GC_old_allocator;
00181           
00182           if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
00183                                                    GC_mark_old_obj, 0)
00184               != PCR_ERes_okay) {
00185               ABORT("Old object enumeration failed");
00186           }
00187         }
00188         
00189         /* Add new static data areas of dynamically loaded modules.     */
00190         {
00191           PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
00192           PCR_IL_LoadedSegment * q;
00193           
00194           /* Skip uncommited files */
00195           while (p != NIL && !(p -> lf_commitPoint)) {
00196               /* The loading of this file has not yet been committed    */
00197               /* Hence its description could be inconsistent.           */
00198               /* Furthermore, it hasn't yet been run.  Hence its data   */
00199               /* segments can't possibly reference heap allocated       */
00200               /* objects.                                               */
00201               p = p -> lf_prev;
00202           }
00203           for (; p != NIL; p = p -> lf_prev) {
00204             for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
00205               if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
00206                   == PCR_IL_SegFlags_Traced_on) {
00207                 GC_add_roots_inner
00208                         ((char *)(q -> ls_addr), 
00209                          (char *)(q -> ls_addr) + q -> ls_bytes);
00210               }
00211             }
00212           }
00213         }
00214         
00215         
00216         /* Traverse all thread stacks. */
00217           if (PCR_ERes_IsErr(
00218                 PCR_ThCtl_ApplyToAllOtherThreads(GC_mark_thread_stack,0))
00219               || PCR_ERes_IsErr(GC_mark_thread_stack(PCR_Th_CurrThread(), 0))) {
00220               ABORT("Thread stack marking failed\n");
00221           }
00222 #   else
00223         /* Mark everything on the stack.           */
00224 #         ifdef STACK_GROWS_DOWN
00225             GC_mark_all_stack( GC_approx_sp(), GC_stackbottom );
00226 #         else
00227             GC_mark_all_stack( GC_stackbottom, GC_approx_sp() );
00228 #         endif
00229 
00230 #   endif
00231 
00232     /* Reregister dynamic libraries, in case one got added.     */
00233        GC_register_dynamic_libraries();
00234     /* Mark everything in static data areas                             */
00235       for (i = 0; i < n_root_sets; i++) {
00236         GC_mark_all(static_roots[i].r_start, static_roots[i].r_end);
00237       }
00238 }
00239 
00240 /*
00241  * Top level GC_mark routine. Mark from the object pointed to by p.
00242  * GC_tl_mark is normally called by GC_mark_regs, and thus must be defined.
00243  */
00244 void GC_tl_mark(p)
00245 word p;
00246 {
00247     word q;
00248 
00249     q = p;
00250     GC_mark_all_stack((ptr_t)(&q), (ptr_t)((&q)+1));
00251 }

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