# define SILENT /* * 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. */ /* Machine specific parts contributed by various people. See README file. */ # ifndef GC←PRIVATE←H # define GC←PRIVATE←H # ifndef GC←H # include "gc.h" # endif # ifndef HEADERS←H # include "gc←headers.h" # endif typedef int bool; # define TRUE 1 # define FALSE 0 typedef char * ptr←t; /* A generic pointer to which we can add */ /* byte displacments. */ #ifdef ←←STDC←← # include <stddef.h> typedef void * extern←ptr←t; #else typedef char * extern←ptr←t; #endif /*********************************/ /* */ /* Definitions for conservative */ /* collector */ /* */ /*********************************/ /*********************************/ /* */ /* Easily changeable parameters */ /* */ /*********************************/ # if defined(sun) && defined(mc68000) # define M68K←SUN # define mach←type←known # endif # if defined(hp9000s300) # define M68K←HP # define mach←type←known # endif # if defined(vax) # define VAX # ifdef ultrix # define ULTRIX # else # define BSD # endif # define mach←type←known # endif # if defined(mips) # define MIPS # ifdef ultrix # define ULTRIX # else # define RISCOS # endif # define mach←type←known # endif # if defined(sequent) && defined(i386) # define I386 # define mach←type←known # endif # if defined(ibm032) # define RT # define mach←type←known # endif # if defined(sun) && defined(sparc) # define SPARC # define mach←type←known # endif # if defined(←IBMR2) # define IBMRS6000 # define mach←type←known # endif # if defined(SCO) /* define SCO */ # define mach←type←known /* --> incompletely implemented */ # endif # if defined(←AUX←SOURCE) # define M68K←SYSV # define mach←type←known # endif # if defined(←PA←RISC1←0) || defined(←PA←RISC1←1) # define HP←PA # define mach←type←known /* --> incompletely implemented */ # endif /* Feel free to add more clauses here */ /* Or manually define the machine type here. A machine type is */ /* characterized by the architecture and assembler syntax. Some */ /* machine types are further subdivided by OS. In that case, we use */ /* the macros ULTRIX, RISCOS, and BSD to distinguish. */ /* Note that SGI IRIX is treated identically to RISCOS. */ /* The distinction in these cases is usually the stack starting address */ # ifndef mach←type←known # define M68K←SUN /* Guess "Sun" */ /* Mapping is: M68K←SUN ==> Sun3 assembler, */ /* M68K←HP ==> HP9000/300, */ /* M68K←SYSV ==> A/UX, maybe others */ /* I386 ==> Sequent Symmetry, */ /* NS32K ==> Encore Multimax, */ /* MIPS ==> R2000 or R3000 */ /* (RISCOS, ULTRIX variants) */ /* VAX ==> DEC VAX */ /* (BSD, ULTRIX variants) */ /* SCO ==> SCO Unix 3.2 */ # endif #define PRINTSTATS /* Print garbage collection statistics */ /* For less verbose output, undefine in reclaim.c */ #define PRINTTIMES /* Print the amount of time consumed by each garbage */ /* collection. */ #define PRINTBLOCKS /* Print object sizes associated with heap blocks, */ /* whether the objects are atomic or composite, and */ /* whether or not the block was found to be empty */ /* duing the reclaim phase. Typically generates */ /* about one screenful per garbage collection. */ #undef PRINTBLOCKS #define PRINTBLACKLIST /* Print black listed blocks, i.e. values that */ /* cause the allocator to avoid allocating certain */ /* blocks in order to avoid introducing "false */ /* hits". */ #undef PRINTBLACKLIST #ifdef SILENT # ifdef PRINTSTATS # undef PRINTSTATS # endif # ifdef PRINTTIMES # undef PRINTTIMES # endif # ifdef PRINTNBLOCKS # undef PRINTNBLOCKS # endif #endif #if defined(PRINTSTATS) && !defined(GATHERSTATS) # define GATHERSTATS #endif #ifdef SPARC # define ALIGN←DOUBLE /* Align objects of size > 1 word on 2 word */ /* boundaries. Wasteful of memory, but */ /* apparently required by SPARC architecture. */ #endif #define MERGE←SIZES /* Round up some object sizes, so that fewer distinct */ /* free lists are actually maintained. This applies */ /* only to the top level routines in misc.c, not to */ /* user generated code that calls GC←allocobj and */ /* GC←allocaobj directly. */ /* Slows down average programs slightly. May however */ /* substantially reduce fragmentation if allocation */ /* request sizes are widely scattered. */ /* May save significant amounts of space for obj←map */ /* entries. */ /* ALIGN←DOUBLE requires MERGE←SIZES at present. */ # if defined(ALIGN←DOUBLE) && !defined(MERGE←SIZES) # define MERGE←SIZES # endif /* For PRINTTIMES to tell the truth, we need to know the value of HZ for this system. */ #include <time.h> #if !defined(CLOCKS←PER←SEC) && !defined(PCR) /* This is technically a bug in the implementation. ANSI requires that * CLOCKS←PER←SEC be defined. But at least under SunOS4.1.2, it isn't. */ # if defined(M68K←HP)||defined(M68K←SUN)||defined M68K←SYSV||defined(SPARC) # include <sys/param.h> # define FLOAT←HZ (double)HZ # else # define FLOAT←HZ 60.0 # endif #else # ifdef CLOCKS←PER←SEC # define FLOAT←HZ (double)CLOCKS←PER←SEC # else # define FLOAT←HZ 60.0 # endif #endif #if defined(M68K←SUN) || defined(M68K←SYSV) # define ALIGNMENT 2 /* Pointers are aligned on 2 byte boundaries */ /* by the Sun C compiler. */ #else # ifdef VAX # define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */ # else # ifdef RT # define ALIGNMENT 4 # else # ifdef SPARC # define ALIGNMENT 4 # else # ifdef I386 # define ALIGNMENT 4 /* Sequent compiler aligns pointers */ # else # ifdef NS32K # define ALIGNMENT 4 /* Pointers are aligned on NS32K */ # else # ifdef MIPS # define ALIGNMENT 4 /* MIPS hardware requires pointer */ /* alignment */ # else # ifdef M68K←HP # define ALIGNMENT 2 /* 2 byte alignment inside struct/union, */ /* 4 bytes elsewhere */ # else # ifdef IBMRS6000 # define ALIGNMENT 4 # else # ifdef HP←PA # define ALIGNMENT 4 # else --> specify alignment <-- # endif # endif # endif # endif # endif # endif # endif # endif # endif # endif /* STACKBOTTOM is the cool end of the stack, which is usually the */ /* highest address in the stack. */ /* Under PCR, we have other ways of finding thread stacks. */ #ifndef PCR # ifdef RT # define STACKBOTTOM ((ptr←t) 0x1fffd800) # else # ifdef I386 # define STACKBOTTOM ((ptr←t) 0x3ffff000) /* For Sequent */ # else # ifdef NS32K # define STACKBOTTOM ((ptr←t) 0xfffff000) /* for Encore */ # else # ifdef MIPS # ifdef ULTRIX # define STACKBOTTOM ((ptr←t) 0x7fffc000) # else # ifdef RISCOS # define STACKBOTTOM ((ptr←t) 0x7ffff000) /* Could probably be slightly lower since */ /* startup code allocates lots of junk */ # else --> fix it # endif # endif # else # ifdef M68K←HP # define STACKBOTTOM ((ptr←t) 0xffeffffc) /* empirically determined. seems to work. */ # else # ifdef IBMRS6000 # define STACKBOTTOM ((ptr←t) 0x2ff80000) # else # if defined(VAX) && defined(ULTRIX) # define STACKBOTTOM ((ptr←t) 0x7fffc800) # else # ifdef SCO # define STACKBOTTOM ((ptr←t) 0x7ffffffc) # else # ifdef M68K←SYSV # define STACKBOTTOM ((ptr←t)0xFFFFFFFC) /* The stack starts at the top of memory, */ /* near as I can figure. --Parag */ # else # ifdef HP←PA # include <sys/param.h> # include <sys/user.h> # define STACKBOTTOM ((ptr←t) (USRSTACK)) # define STACK←GROWS←UP # else /* other VAXes, SPARC, and various flavors of Sun 2s and Sun 3s use */ /* the default heuristic, which is to take the address of a local */ /* variable in gc←init, and round it up to the next multiple */ /* of 16 Meg. This is crucial on Suns, since various models */ /* that are supposed to be able to share executables, do not */ /* use the same stack base. In particular, Sun 3/80s are */ /* different from other Sun 3s. */ /* This probably works on some more of the above machines. */ # endif # endif # endif # endif # endif # endif # endif # endif # endif # endif #endif /* PCR */ # ifndef STACK←GROWS←UP # define STACK←GROWS←DOWN # endif /* Start of data segment for each of the above systems. Note that the */ /* default case works only for contiguous text and data, such as on a */ /* Vax. */ # ifdef M68K←SUN extern char etext; # define DATASTART ((ptr←t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff)) # else # ifdef RT # define DATASTART ((ptr←t) 0x10000000) # else # if defined(I386) || defined(SPARC) extern int etext; # define DATASTART ((ptr←t)((((word) (&etext)) + 0xfff) & ~0xfff)) /* On very old SPARCs this is too conservative. */ # else # ifdef NS32K extern char **environ; # define DATASTART ((ptr←t)(&environ)) /* hideous kludge: environ is the first */ /* word in crt0.o, and delimits the start */ /* of the data segment, no matter which */ /* ld options were passed through. */ # else # ifdef MIPS # define DATASTART 0x10000000 /* Could probably be slightly higher since */ /* startup code allocates lots of junk */ # else # ifdef M68K←HP extern char etext; # define DATASTART ((ptr←t)((((word) (&etext)) + 0xfff) & ~0xfff)) # else # ifdef IBMRS6000 # define DATASTART ((ptr←t)0x20000000) # else # ifdef SCO # define DATASTART ((ptr←t)(0x00400000 +((long)&etext & 0xFFC00000) +((long)&etext & 0xFFC00FFF))) # else # ifdef M68K←SYSV /* This only works for shared-text binaries with magic number 0413. The other sorts of SysV binaries put the data at the end of the text, in which case the default of &etext would work. Unfortunately, handling both would require having the magic-number available. -- Parag */ # define DATASTART ((ptr←t)(0x4000000)) # else # ifdef HP←PA extern int ←←data←start; # define DATASTART ((ptr←t)(&←←data←start)) # else extern char etext; # define DATASTART ((ptr←t)(&etext)) # endif # endif # endif # endif # endif # endif # endif # endif # endif # endif # define HINCR 16 /* Initial heap increment, in blocks of 4K */ # define MAXHINCR 512 /* Maximum heap increment, in blocks */ # define HINCR←MULT 3 /* After each new allocation, GC←hincr is multiplied */ # define HINCR←DIV 2 /* by HINCR←MULT/HINCR←DIV */ # define GC←MULT 3 /* Don't collect if the fraction of */ /* non-collectable memory in the heap */ /* exceeds GC←MUL/GC←DIV */ # define GC←DIV 4 # define NON←GC←HINCR ((word)8) /* Heap increment if most of heap if collection */ /* was suppressed because most of heap is not */ /* collectable */ /*********************************/ /* */ /* OS interface routines */ /* */ /*********************************/ /* HBLKSIZE aligned allocation. 0 is taken to mean failure */ /* space is assumed to be cleared. */ # ifdef PCR # ifdef ←←STDC←← void * real←malloc(size←t size); # else char * real←malloc(); # endif # define GET←MEM(bytes) HBLKPTR(real←malloc((size←t)bytes + HBLKSIZE) \ + HBLKSIZE-1); # define THREADS # else caddr←t sbrk(); # ifdef ←←STDC←← # define GET←MEM(bytes) HBLKPTR(sbrk((size←t)(bytes + HBLKSIZE)) \ + HBLKSIZE-1); # else # define GET←MEM(bytes) HBLKPTR(sbrk((int)(bytes + HBLKSIZE)) + HBLKSIZE-1); # endif # endif /* * Mutual exclusion between allocator/collector routines. * Needed if there is more than one allocator thread. * FASTLOCK() is assumed to try to acquire the lock in a cheap and * dirty way that is acceptable for a few instructions, e.g. by * inhibiting preemption. This is assumed to have succeeded only * if a subsequent call to FASTLOCK←SUCCEEDED() returns TRUE. * If signals cannot be tolerated with the FASTLOCK held, then * FASTLOCK should disable signals. The code executed under * FASTLOCK is otherwise immune to interruption, provided it is * not restarted. * DCL←LOCK←STATE declares any local variables needed by LOCK and UNLOCK * and/or DISABLE←SIGNALS and ENABLE←SIGNALS and/or FASTLOCK. * (There is currently no equivalent for FASTLOCK.) */ # ifdef PCR # include "pcr/th/PCR←Th.h" # include "pcr/th/PCR←ThCrSec.h" extern struct PCR←Th←MLRep GC←allocate←ml; # define DCL←LOCK←STATE PCR←sigset←t GC←old←sig←mask # define LOCK() PCR←Th←ML←Acquire(&GC←allocate←ml) # define UNLOCK() PCR←Th←ML←Release(&GC←allocate←ml) # define FASTLOCK() PCR←ThCrSec←EnterSys() /* Here we cheat (a lot): */ # define FASTLOCK←SUCCEEDED() (*(int *)(&GC←allocate←ml) == 0) /* TRUE if nobody currently holds the lock */ # define FASTUNLOCK() PCR←ThCrSec←ExitSys() # else # define DCL←LOCK←STATE # define LOCK() # define UNLOCK() # define FASTLOCK() LOCK() # define FASTLOCK←SUCCEEDED() TRUE # define FASTUNLOCK() UNLOCK() # endif /* Delay any interrupts or signals that may abort this thread. Data */ /* structures are in a consistent state outside this pair of calls. */ /* ANSI C allows both to be empty (though the standard isn't very */ /* clear on that point). Standard malloc implementations are usually */ /* neither interruptable nor thread-safe, and thus correspond to */ /* empty definitions. */ # ifdef PCR # define DISABLE←SIGNALS() \ PCR←Th←SetSigMask(PCR←allSigsBlocked,&GC←old←sig←mask) # define ENABLE←SIGNALS() \ PCR←Th←SetSigMask(&GC←old←sig←mask, NIL) # else # if 0 /* debugging */ # define DISABLE←SIGNALS() # define ENABLE←SIGNALS() # else # define DISABLE←SIGNALS() GC←disable←signals() void GC←disable←signals(); # define ENABLE←SIGNALS() GC←enable←signals() void GC←enable←signals(); # endif # endif /* * Stop and restart mutator threads. */ # ifdef PCR # include "pcr/th/PCR←ThCtl.h" # define STOP←WORLD() \ PCR←ThCtl←SetExclusiveMode(PCR←ThCtl←ExclusiveMode←stopNormal, \ PCR←allSigsBlocked, \ PCR←waitForever) # define START←WORLD() \ PCR←ThCtl←SetExclusiveMode(PCR←ThCtl←ExclusiveMode←null, \ PCR←allSigsBlocked, \ PCR←waitForever); # else # define STOP←WORLD() # define START←WORLD() # endif /* Abandon ship */ # ifdef PCR void PCR←Base←Panic(const char *fmt, ...); # define ABORT(s) PCR←Base←Panic(s) # else # define ABORT(s) abort(s) # endif /* Exit abnormally, but without making a mess (e.g. out of memory) */ # ifdef PCR void PCR←Base←Exit(int status); # define EXIT() PCR←Base←Exit(1) # else # ifndef ←←STDC←← void exit(); # endif # define EXIT() exit(1) # endif /*********************************/ /* */ /* Word-size-dependent defines */ /* */ /*********************************/ #define WORDS←TO←BYTES(x) ((x)<<2) #define BYTES←TO←WORDS(x) ((x)>>2) #define CPP←WORDSZ 32 #define WORDSZ ((word)CPP←WORDSZ) #define LOGWL ((word)5) /* log[2] of above */ #define BYTES←PER←WORD ((word)(sizeof (word))) #define ONES 0xffffffff #define MSBYTE 0xff000000 #define SIGNB 0x80000000 #define MAXSHORT 0x7fff #define modHALFWORDSZ(n) ((n) & 0xf) /* mod n by size of half word */ #define divHALFWORDSZ(n) ((n) >> 4) /* divide n by size of half word */ #define modWORDSZ(n) ((n) & 0x1f) /* mod n by size of word */ #define divWORDSZ(n) ((n) >> 5) /* divide n by size of word */ #define twice(n) ((n) << 1) /* double n */ /*********************/ /* */ /* Size Parameters */ /* */ /*********************/ /* heap block size, bytes. Should be power of 2 */ #define CPP←LOG←HBLKSIZE 12 #define LOG←HBLKSIZE ((word)CPP←LOG←HBLKSIZE) #define CPP←HBLKSIZE (1 << CPP←LOG←HBLKSIZE) #define HBLKSIZE ((word)CPP←HBLKSIZE) /* max size objects supported by freelist (larger objects may be */ /* allocated, but less efficiently) */ #define CPP←MAXOBJSZ BYTES←TO←WORDS(CPP←HBLKSIZE/2) #define MAXOBJSZ ((word)CPP←MAXOBJSZ) # define divHBLKSZ(n) ((n) >> LOG←HBLKSIZE) # define modHBLKSZ(n) ((n) & (HBLKSIZE-1)) # define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1))) # define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1)) /********************************************/ /* */ /* H e a p B l o c k s */ /* */ /********************************************/ /* heap block header */ #define HBLKMASK (HBLKSIZE-1) #define BITS←PER←HBLK (HBLKSIZE * 8) #define MARK←BITS←PER←HBLK (BITS←PER←HBLK/CPP←WORDSZ) /* upper bound */ /* We allocate 1 bit/word. Only the first word */ /* in each object is actually marked. */ # ifdef ALIGN←DOUBLE # define MARK←BITS←SZ (((MARK←BITS←PER←HBLK + 2*CPP←WORDSZ - 1) \ / (2*CPP←WORDSZ))*2) # else # define MARK←BITS←SZ ((MARK←BITS←PER←HBLK + CPP←WORDSZ - 1)/CPP←WORDSZ) # endif /* Upper bound on number of mark words per heap block */ /* Mark stack entries. */ typedef struct ms←entry { word * mse←start; /* inclusive */ word * mse←end; /* exclusive */ } mse; typedef mse * (*mark←proc)(/* word * addr, hdr * hhdr, mse * msp, mse * msl */); /* Procedure to arrange for the descendents of the object at */ /* addr to be marked. Msp points at the top entry on the */ /* mark stack. Msl delimits the hot end of the mark stack. */ /* hhdr is the hdr structure corresponding to addr. */ /* Returns the new mark stack pointer. */ struct hblkhdr { signed←word hb←sz; /* If in use, size in words, of objects in the block. */ /* if free, the size in bytes of the whole block */ struct hblk * hb←next; /* Link field for hblk free list */ /* and for lists of chunks waiting to be */ /* reclaimed. */ mark←proc hb←mark←proc; /* Procedure to mark objects. Can */ /* also be retrived through obj←kind. */ /* But one level of indirection matters */ /* here. */ char* hb←map; /* A pointer to a pointer validity map of the block. */ /* See GC←obj←map. */ /* Valid for all blocks with headers. */ int hb←obj←kind; /* Kind of objects in the block. Each kind */ /* identifies a mark procedure and a set of */ /* list headers. sometimes called regions. */ word hb←marks[MARK←BITS←SZ]; /* Bit i in the array refers to the */ /* object starting at the ith word (header */ /* INCLUDED) in the heap block. */ }; /* heap block body */ # define DISCARD←WORDS 0 /* Number of words to be dropped at the beginning of each block */ /* Must be a multiple of 32. May reasonably be nonzero */ /* on mcachines that don't guarantee longword alignment of */ /* pointers, so that the number of false hits is minimized. */ /* 0 and 32 are probably the only reasonable values. */ # define BODY←SZ ((HBLKSIZE-WORDS←TO←BYTES(DISCARD←WORDS))/sizeof(word)) struct hblk { # if (DISCARD←WORDS != 0) word garbage[DISCARD←WORDS]; # endif word hb←body[BODY←SZ]; }; # define HDR←WORDS ((word)DISCARD←WORDS) # define HDR←BYTES ((word)WORDS←TO←BYTES(DISCARD←WORDS)) /* Object free list link */ # define obj←link(p) (*(ptr←t *)(p)) /* lists of all heap blocks and free lists */ /* These are grouped together in a struct */ /* so that they can be easily skipped by the */ /* GC←mark routine. */ /* The ordering is weird to make GC←malloc */ /* faster by keeping the important fields */ /* sufficiently close together that a */ /* single load of a base register will do. */ struct ←GC←arrays { word ←heapsize; ptr←t ←last←heap←addr; ptr←t ←prev←heap←addr; word ←words←allocd; /* Number of words allocated during this collection cycle */ ptr←t ←objfreelist[MAXOBJSZ+1]; /* free list for objects */ # ifdef MERGE←SIZES unsigned ←size←map[WORDS←TO←BYTES(MAXOBJSZ+1)]; /* Number of words to allocate for a given allocation request in */ /* bytes. */ # endif ptr←t ←aobjfreelist[MAXOBJSZ+1]; /* free list for atomic objs*/ ptr←t ←obj←map[MAXOBJSZ+1]; /* If not NIL, then a pointer to a map of valid */ /* object addresses. hbh←map[sz][i] is j if the */ /* address block←start+i is a valid pointer */ /* to an object at block←start+i&~3 - 4*j. It */ /* is OBJ←INVALID if block←start+4*i is not */ /* valid as a pointer to an object. */ /* We assume that all values of j <= OBJ←INVALID */ /* The zeroth entry corresponds to large objects.*/ # define OBJ←INVALID 0x7f # define CPP←MAX←OFFSET (WORDS←TO←BYTES(OBJ←INVALID) - 1) # define MAX←OFFSET ((word)CPP←MAX←OFFSET) struct hblk * ←reclaim←list[MAXOBJSZ+1]; struct hblk * ←areclaim←list[MAXOBJSZ+1]; }; # define VALID←OFFSET←SZ \ (CPP←MAX←OFFSET > WORDS←TO←BYTES(CPP←MAXOBJSZ)? \ CPP←MAX←OFFSET+1 \ : WORDS←TO←BYTES(CPP←MAXOBJSZ)+1) extern char GC←valid←offsets[VALID←OFFSET←SZ]; /* GC←valid←offsets[i] == TRUE ==> i */ /* is registered as a displacement. */ extern char GC←modws←valid←offsets[sizeof(word)]; /* GC←valid←offsets[i] ==> */ /* GC←modws←valid←offsets[i%sizeof(word)] */ extern struct ←GC←arrays GC←arrays; # define GC←objfreelist GC←arrays.←objfreelist # define GC←aobjfreelist GC←arrays.←aobjfreelist # define GC←reclaim←list GC←arrays.←reclaim←list # define GC←areclaim←list GC←arrays.←areclaim←list # define GC←obj←map GC←arrays.←obj←map # define GC←last←heap←addr GC←arrays.←last←heap←addr # define GC←prev←heap←addr GC←arrays.←prev←heap←addr # define GC←words←allocd GC←arrays.←words←allocd # define GC←heapsize GC←arrays.←heapsize # ifdef MERGE←SIZES # define GC←size←map GC←arrays.←size←map # endif # define beginGC←arrays ((ptr←t)(&GC←arrays)) # define endGC←arrays (((ptr←t)(&GC←arrays)) + (sizeof GC←arrays)) # define MAXOBJKINDS 16 /* Object kinds: */ extern struct obj←kind { ptr←t *ok←freelist; /* Array of free listheaders for this kind of object */ /* Point either to GC←arrays or to storage allocated */ /* with GC←scratch←alloc. */ struct hblk **ok←reclaim←list; /* List headers for lists of blocks waiting to be */ /* swept. */ mark←proc ok←mark←proc; /* Procedure to either mark referenced objects, */ /* or push them on the mark stack. */ bool ok←init; /* Clear objects before putting them on the free list. */ } GC←obj←kinds[MAXOBJKINDS]; /* Predefined kinds: */ # define PTRFREE 0 # define NORMAL 1 extern int GC←n←kinds; extern char * GC←invalid←map; /* Pointer to the nowhere valid hblk map */ /* Blocks pointing to this map are free. */ extern struct hblk * GC←hblkfreelist; /* List of completely empty heap blocks */ /* Linked through hb←next field of */ /* header structure associated with */ /* block. */ extern bool GC←is←initialized; /* GC←init() has been run. */ extern word GC←words←allocd←before←gc; /* Number of words allocated before this */ /* collection cycle. */ # ifdef GATHERSTATS extern word GC←composite←in←use; /* Number of words in accessible composite */ /* objects. */ extern word GC←atomic←in←use; /* Number of words in accessible atomic */ /* objects. */ # endif # ifndef PCR extern ptr←t GC←stackbottom; /* Cool end of user stack */ # endif extern word GC←hincr; /* current heap increment, in blocks */ extern ptr←t GC←least←plausible←heap←addr; extern ptr←t GC←greatest←plausible←heap←addr; /* Bounds on the heap. Guaranteed valid */ /* Likely to include future heap expansion. */ /* Operations */ # define update←GC←hincr GC←hincr = (GC←hincr * HINCR←MULT)/HINCR←DIV; \ if (GC←hincr > MAXHINCR) {GC←hincr = MAXHINCR;} # define abs(x) ((x) < 0? (-(x)) : (x)) /****************************/ /* */ /* Objects */ /* */ /****************************/ /* Marks are in a reserved area in */ /* each heap block. Each word has one mark bit associated */ /* with it. Only those corresponding to the beginning of an */ /* object are used. */ /* Operations */ /* * Retrieve, set, clear the mark bit corresponding * to the nth word in a given heap block. * * (Recall that bit n corresponds to object beginning at word n * relative to the beginning of the block, including unused words) */ # define mark←bit←from←hdr(hhdr,n) (((hhdr)->hb←marks[divWORDSZ(n)] \ >> (modWORDSZ(n))) & 1) # define set←mark←bit←from←hdr(hhdr,n) (hhdr)->hb←marks[divWORDSZ(n)] \ |= 1 << modWORDSZ(n) # define clear←mark←bit←from←hdr(hhdr,n) (hhdr)->hb←marks[divWORDSZ(n)] \ &= ~(1 << modWORDSZ(n)) /* Important internal collector routines */ void GC←apply←to←all←blocks(/*fn, client←data*/); /* Invoke fn(hbp, client←data) for each */ /* allocated heap block. */ mse * GC←no←mark←proc(/*addr,hhdr,msp,msl*/); /* Mark procedure for PTRFREE objects. */ mse * GC←normal←mark←proc(/*addr,hhdr,msp,msl*/); /* Mark procedure for NORMAL objects. */ void GC←mark←init(); void GC←mark(); /* Mark from everything on the mark stack. */ void GC←mark←reliable(); /* as above, but fix things up after */ /* a mark stack overflow. */ void GC←mark←all(/*b,t*/); /* Mark from everything in a range. */ void GC←mark←all←stack(/*b,t*/); /* Mark from everything in a range, */ /* consider interior pointers as valid */ void GC←remark(); /* Mark from all marked objects. Used */ /* only if we had to drop something. */ void GC←tl←mark(/*p*/); /* Mark from a single root. */ void GC←add←to←black←list←normal(/* bits */); /* Register bits as a possible future false */ /* reference from the heap or static data */ void GC←add←to←black←list←stack(/* bits */); struct hblk * GC←is←black←listed(/* h, len */); /* If there are likely to be false references */ /* to a block starting at h of the indicated */ /* length, then return the next plausible */ /* starting location for h that might avoid */ /* these false references. */ void GC←promote←black←lists(); /* Declare an end to a black listing phase. */ ptr←t GC←scratch←alloc(/*bytes*/); /* GC internal memory allocation for */ /* small objects. Deallocation is not */ /* possible. */ void GC←invalidate←map(/* hdr */); /* Remove the object map associated */ /* with the block. This identifies */ /* the block as invalid to the mark */ /* routines. */ void GC←add←map←entry(/*sz*/); /* Add a heap block map for objects of */ /* size sz to obj←map. */ void GC←register←displacement←inner(/*offset*/); /* Version of GC←register←displacement */ /* that assumes lock is already held */ /* and signals are already disabled. */ void GC←init←inner(); void GC←new←hblk(/*size←in←words, kind*/); /* Allocate a new heap block, and build */ /* a free list in it. */ struct hblk * GC←allochblk(/*size←in←words, kind*/); /* Allocate a heap block, clear it if */ /* for composite objects, inform */ /* the marker that block is valid */ /* for objects of indicated size. */ /* sz < 0 ==> atomic. */ void GC←freehblk(); /* Deallocate a heap block and mark it */ /* as invalid. */ void GC←start←reclaim(/*abort←if←found*/); /* Restore unmarked objects to free */ /* lists, or (if abort←if←found is */ /* TRUE) report them. */ /* Sweeping of small object pages is */ /* largely deferred. */ void GC←continue←reclaim(/*size, kind*/); /* Sweep pages of the given size and */ /* kind, as long as possible, and */ /* as long as the corr. free list is */ /* empty. */ void GC←gcollect←inner(); /* Collect; caller must have acquired */ /* lock and disabled signals. */ void GC←init(); /* Initialize collector. */ ptr←t GC←generic←malloc(/* bytes, kind */); /* Allocate an object of the given */ /* kind. By default, there are only */ /* two kinds: composite, and atomic. */ /* We claim it's possible for clever */ /* client code that understands GC */ /* internals to add more, e.g. to */ /* communicate object layout info */ /* to the collector. */ ptr←t GC←generic←malloc←words←small(/*words, kind*/); /* As above, but size in units of words */ /* Bypasses MERGE←SIZES. Assumes */ /* words <= MAXOBJSZ. */ ptr←t GC←allocobj(/* sz←inn←words, kind */); /* Make the indicated */ /* free list nonempty, and return its */ /* head. */ void GC←install←header(/*h*/); /* Install a header for block h. */ void GC←install←counts(/*h, sz*/); /* Set up forwarding counts for block */ /* h of size sz. */ void GC←remove←header(/*h*/); /* Remove the header for block h. */ void GC←remove←counts(/*h, sz*/); /* Remove forwarding counts for h. */ hdr * GC←find←header(/*p*/); /* Debugging only. */ void GC←finalize(); /* Perform all indicated finalization actions */ /* on unmarked objects. */ void GC←add←to←heap(/*p, bytes*/); /* Add a HBLKSIZE aligned chunk to the heap. */ # endif /* GC←PRIVATE←H */