/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991, 1992 by Xerox Corporation. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to copy this garbage collector for any purpose,
* provided the above notices are retained on all copies.
*/
/*
* This implements:
* 1. allocation of heap block headers
* 2. A map from addresses to heap block addresses to heap block headers
*
* Access speed is crucial. We implement an index structure based on a 2
* level tree.
* For 64 bit machines this will have to be rewritten. We expect that the
* winning strategy there is to use a hash table as a cache, with
* collisions resolved through a 4 or 5 level tree.
*/
# include "gc←private.h"
# if CPP←WORDSZ != 32
# if CPP←WORDSZ > 32
--> This needs to be reimplemented. See above.
# else
--> Get a real machine.
# endif
# endif
hdr ** GC←top←index [TOP←SZ];
typedef hdr * bottom←index[BOTTOM←SZ];
/*
* The bottom level index contains one of three kinds of values:
* 0 means we're not responsible for this block.
* 1 < (long)X <= MAX←JUMP means the block starts at least
* X * HBLKSIZE bytes before the current address.
* A valid pointer points to a hdr structure. (The above can't be
* valid pointers due to the GET←MEM return convention.)
*/
static bottom←index all←nils = { 0 };
/* Non-macro version of header location routine */
hdr * GC←find←header(h)
ptr←t h;
{
return(HDR(h));
}
/* Routines to dynamically allocate collector data structures that will */
/* never be freed. */
static char * scratch←free←ptr = 0;
static char * scratch←end←ptr = 0;
ptr←t GC←scratch←alloc(bytes)
register word bytes;
{
register char * result = scratch←free←ptr;
scratch←free←ptr += bytes;
if (scratch←free←ptr <= scratch←end←ptr) {
return(result);
}
{
long bytes←to←get = ((HINCR+1) * HBLKSIZE + bytes) & ~(HBLKSIZE - 1);
scratch←free←ptr = (char *)GET←MEM(bytes←to←get);
if (scratch←free←ptr == 0) {
GC←err←printf0("Out of memory - trying to allocate less\n");
result = (char *)GET←MEM(bytes);
if (result == 0) {
GC←err←printf0("Out of memory - giving up\n");
} else {
scratch←free←ptr -= bytes;
return(result);
}
}
scratch←end←ptr = scratch←free←ptr + bytes←to←get;
return(GC←scratch←alloc(bytes));
}
}
static hdr * hdr←free←list = 0;
/* Return an uninitialized header */
static hdr * alloc←hdr()
{
register hdr * result;
if (hdr←free←list == 0) {
result = (hdr *) GC←scratch←alloc((word)(sizeof(hdr)));
} else {
result = hdr←free←list;
hdr←free←list = (hdr *) (result -> hb←next);
}
return(result);
}
static void free←hdr(hhdr)
hdr * hhdr;
{
hhdr -> hb←next = (struct hblk *) hdr←free←list;
hdr←free←list = hhdr;
}
GC←init←headers()
{
register int i;
for (i = 0; i < TOP←SZ; i++) {
GC←top←index[i] = all←nils;
}
}
/* Make sure that there is a bottom level index block for address addr */
static void get←index(addr)
register word addr;
{
register word indx =
(word)(addr) >> (LOG←BOTTOM←SZ + LOG←HBLKSIZE);
if (GC←top←index[indx] == all←nils) {
GC←top←index[indx] = (hdr **)
GC←scratch←alloc((word)(sizeof (bottom←index)));
bzero((char *)(GC←top←index[indx]), (int)(sizeof (bottom←index)));
}
}
/* Install a header for block h. */
/* The header is uninitialized. */
void GC←install←header(h)
register struct hblk * h;
{
get←index((word) h);
HDR(h) = alloc←hdr();
}
/* Set up forwarding counts for block h of size sz */
void GC←install←counts(h, sz)
register struct hblk * h;
register word sz; /* bytes */
{
register struct hblk * hbp;
register int i;
for (hbp = h; (char *)hbp < (char *)h + sz; hbp += BOTTOM←SZ) {
get←index((word) hbp);
}
get←index((word)h + sz - 1);
for (hbp = h + 1; (char *)hbp < (char *)h + sz; hbp += 1) {
i = hbp - h;
HDR(hbp) = (hdr *)(i > MAX←JUMP? MAX←JUMP : i);
}
}
/* Remove the header for block h */
void GC←remove←header(h)
register struct hblk * h;
{
free←hdr(HDR(h));
HDR(h) = 0;
}
/* Remove forwarding counts for h */
void GC←remove←counts(h, sz)
register struct hblk * h;
register word sz; /* bytes */
{
register struct hblk * hbp;
for (hbp = h+1; (char *)hbp < (char *)h + sz; hbp += 1) {
HDR(hbp) = 0;
}
}
/* Apply fn to all allocated blocks */
/*VARARGS1*/
void GC←apply←to←all←blocks(fn, client←data)
void (*fn)(/* struct hblk *h, word client←data */);
word client←data;
{
register int i, j;
register hdr ** index←p;
for (i = 0; i < TOP←SZ; i++) {
index←p = GC←top←index[i];
if (index←p != all←nils) {
for (j = BOTTOM←SZ-1; j >= 0;) {
if (!IS←FORWARDING←ADDR←OR←NIL(index←p[j])) {
if (index←p[j]->hb←map != GC←invalid←map) {
(*fn)(((struct hblk *)
(((i << LOG←BOTTOM←SZ) + j) << LOG←HBLKSIZE)),
client←data);
}
j--;
} else if (index←p[j] == 0) {
j--;
} else {
j -= (int)(index←p[j]);
}
}
}
}
}