# include <stdio.h> # include "gc←private.h" # ifdef PCR # define MAX←ROOT←SETS 1024 # include "pcr/il/PCR←IL.h" # include "pcr/th/PCR←ThCtl.h" # include "pcr/mm/PCR←MM.h" # else # define MAX←ROOT←SETS 64 # endif /* Data structure for list of root sets. */ /* We keep a hash table, so that we can filter out duplicate additions. */ struct roots { ptr←t r←start; ptr←t r←end; struct roots * r←next; }; static struct roots static←roots[MAX←ROOT←SETS]; static n←root←sets = 0; /* static←roots[0..n←root←sets) contains the valid root sets. */ #define RT←SIZE 64 /* Power of 2, may be != MAX←ROOT←SETS */ #define LOG←RT←SIZE 6 static struct roots * root←index[RT←SIZE]; /* Hash table header. Used only to check whether a range is */ /* already present. */ static int rt←hash(addr) char * addr; { word result = (word) addr; # if CPP←WORDSZ > 8*LOG←RT←SIZE result ↑= result >> 8*LOG←RT←SIZE; # endif # if CPP←WORDSZ > 4*LOG←RT←SIZE result ↑= result >> 4*LOG←RT←SIZE; # endif result ↑= result >> 2*LOG←RT←SIZE; result ↑= result >> LOG←RT←SIZE; result &= (RT←SIZE-1); return(result); } /* Is a range starting at addr already in the table? */ static bool roots←present(b, e) char *b, *e; { register int h = rt←hash(b); register struct roots *p = root←index[h]; while (p != 0) { if (p -> r←start == (ptr←t)b && p -> r←end >= (ptr←t)e) return(TRUE); p = p -> r←next; } return(FALSE); } /* Add the given root structure to the index. */ static void add←roots←to←index(p) struct roots *p; { register int h = rt←hash(p -> r←start); p -> r←next = root←index[h]; root←index[h] = p; } word GC←root←size = 0; void GC←add←roots(b, e) char * b; char * e; { DCL←LOCK←STATE; DISABLE←SIGNALS(); LOCK(); GC←add←roots←inner(b, e); UNLOCK(); ENABLE←SIGNALS(); } /* Add [b,e) to the root set. Adding the same interval a second time */ /* is a moderately fast noop, and hence benign. We do not handle */ /* different but overlapping intervals efficiently. (We do handle */ /* them correctly.) */ void GC←add←roots←inner(b, e) char * b; char * e; { /* We exclude GC data structures from root sets. It's usually safe */ /* to mark from those, but it is a waste of time. */ if ( (ptr←t)b < beginGC←arrays && (ptr←t)e > beginGC←arrays) { if ((ptr←t)e <= endGC←arrays) { e = (char *)beginGC←arrays; } else { GC←add←roots←inner(b, (char *)beginGC←arrays); GC←add←roots←inner((char *)endGC←arrays, e); return; } } else if ((ptr←t)b < endGC←arrays && (ptr←t)e > endGC←arrays) { b = (char *)endGC←arrays; } if (roots←present(b,e)) return; if (n←root←sets == MAX←ROOT←SETS) { ABORT("Too many root sets\n"); } static←roots[n←root←sets].r←start = (ptr←t)b; static←roots[n←root←sets].r←end = (ptr←t)e; static←roots[n←root←sets].r←next = 0; add←roots←to←index(static←roots + n←root←sets); GC←root←size += (ptr←t)e - (ptr←t)b; n←root←sets++; } void GC←clear←roots() { DCL←LOCK←STATE; DISABLE←SIGNALS(); LOCK(); n←root←sets = 0; GC←root←size = 0; UNLOCK(); ENABLE←SIGNALS(); } # ifdef PCR PCR←ERes GC←mark←thread←stack(PCR←Th←T *t, PCR←Any dummy) { struct PCR←ThCtl←TInfoRep info; PCR←ERes result; info.ti←stkLow = info.ti←stkHi = 0; result = PCR←ThCtl←GetInfo(t, &info); GC←mark←all←stack((ptr←t)(info.ti←stkLow), (ptr←t)(info.ti←stkHi)); return(result); } PCR←ERes GC←mark←old←obj(void *p, size←t size, PCR←Any data) { GC←mark←all((ptr←t)p, (ptr←t)p + size); return(PCR←ERes←okay); } # else ptr←t GC←approx←sp() { word dummy; return((ptr←t)(&dummy)); } # endif /* * Call the mark routines (GC←tl←mark for a single pointer, GC←mark←all * on groups of pointers) on every top level accessible pointer. * This is source language specific. The following works for C. */ GC←mark←roots() { register int i; /* * mark from registers - i.e., call GC←tl←mark(i) for each * register i */ GC←mark←regs(); /* usually defined in machine←dep.c */ # ifdef PCR /* Traverse data allocated by previous memory managers. */ { extern struct PCR←MM←ProcsRep * GC←old←allocator; if ((*(GC←old←allocator->mmp←enumerate))(PCR←Bool←false, GC←mark←old←obj, 0) != PCR←ERes←okay) { ABORT("Old object enumeration failed"); } } /* Add new static data areas of dynamically loaded modules. */ { PCR←IL←LoadedFile * p = PCR←IL←GetLastLoadedFile(); PCR←IL←LoadedSegment * q; /* Skip uncommited files */ while (p != NIL && !(p -> lf←commitPoint)) { /* The loading of this file has not yet been committed */ /* Hence its description could be inconsistent. */ /* Furthermore, it hasn't yet been run. Hence its data */ /* segments can't possibly reference heap allocated */ /* objects. */ p = p -> lf←prev; } for (; p != NIL; p = p -> lf←prev) { for (q = p -> lf←ls; q != NIL; q = q -> ls←next) { if ((q -> ls←flags & PCR←IL←SegFlags←Traced←MASK) == PCR←IL←SegFlags←Traced←on) { GC←add←roots←inner ((char *)(q -> ls←addr), (char *)(q -> ls←addr) + q -> ls←bytes); } } } } /* Traverse all thread stacks. */ if (PCR←ERes←IsErr( PCR←ThCtl←ApplyToAllOtherThreads(GC←mark←thread←stack,0)) || PCR←ERes←IsErr(GC←mark←thread←stack(PCR←Th←CurrThread(), 0))) { ABORT("Thread stack marking failed\n"); } # else /* Mark everything on the stack. */ # ifdef STACK←GROWS←DOWN GC←mark←all←stack( GC←approx←sp(), GC←stackbottom ); # else GC←mark←all←stack( GC←stackbottom, GC←approx←sp() ); # endif # endif /* Reregister dynamic libraries, in case one got added. */ GC←register←dynamic←libraries(); /* Mark everything in static data areas */ for (i = 0; i < n←root←sets; i++) { GC←mark←all(static←roots[i].r←start, static←roots[i].r←end); } } /* * Top level GC←mark routine. Mark from the object pointed to by p. * GC←tl←mark is normally called by GC←mark←regs, and thus must be defined. */ void GC←tl←mark(p) word p; { word q; q = p; GC←mark←all←stack((ptr←t)(&q), (ptr←t)((&q)+1)); }