# 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));
}