/* * 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]); } } } } }