/* * 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. */ # define I←HIDE←POINTERS # include "gc.h" # include "gc←private.h" # ifdef ←←STDC←← typedef void * void←star; # else typedef char * void←star; # endif # define LOG←TSIZE 7 # define TSIZE (1 << LOG←TSIZE) # define HASH(addr) \ ((((word)(addr) >> 3) ↑ ((word)(addr) >> (3+LOG←TSIZE))) \ & (TSIZE - 1)) static struct disappearing←link { word dl←hidden←base; /* Pointer to object base */ word dl←offset; /* byte offset within object. */ struct disappearing←link * dl←next; } * dl←head[TSIZE] = {0}; static struct finalizable←object { word fo←hidden←base; /* Pointer to object base */ GC←finalization←proc fo←fn; /* Finalizer. */ ptr←t fo←client←data; word fo←object←size; /* In bytes. */ struct finalizable←object * fo←next; } * fo←head[TSIZE] = {0}; # define ALLOC(x, t) t *x = (t *)GC←malloc(sizeof (t)) int GC←register←disappearing←link(link) void←star * link; { ptr←t base; unsigned long offset; struct disappearing←link *curr←dl; int index; /* Allocate before acquiring lock */ ALLOC(new←dl, struct disappearing←link); DCL←LOCK←STATE; DISABLE←SIGNALS(); LOCK(); base = (ptr←t)GC←base((void←star)link); index = HASH(base); offset = (ptr←t)link - base; if (base == 0 || ((word)link & (ALIGNMENT-1))) ABORT("Bad arg to GC←register←disappearing←link"); curr←dl = dl←head[index]; for (curr←dl = dl←head[index]; curr←dl != 0; curr←dl = curr←dl -> dl←next) { if (curr←dl -> dl←hidden←base == HIDE←POINTER(base) && curr←dl -> dl←offset == offset) { UNLOCK(); ENABLE←SIGNALS(); GC←free((extern←ptr←t)new←dl); return(1); } } { new←dl -> dl←hidden←base = HIDE←POINTER(base); new←dl -> dl←offset = offset; new←dl -> dl←next = dl←head[index]; dl←head[index] = new←dl; UNLOCK(); ENABLE←SIGNALS(); return(0); } } int GC←unregister←disappearing←link(link) void←star * link; { ptr←t base; unsigned long offset; struct disappearing←link *curr←dl, *prev←dl; int index; DCL←LOCK←STATE; DISABLE←SIGNALS(); LOCK(); base = (ptr←t)GC←base((void←star)link); index = HASH(base); offset = (ptr←t)link - base; if (base == 0 || ((unsigned long)link & (ALIGNMENT-1))) return(0); prev←dl = 0; curr←dl = dl←head[index]; while (curr←dl != 0) { if (curr←dl -> dl←hidden←base == HIDE←POINTER(base) && curr←dl -> dl←offset == offset) { if (prev←dl == 0) { dl←head[index] = curr←dl -> dl←next; } else { prev←dl -> dl←next = curr←dl -> dl←next; } UNLOCK(); ENABLE←SIGNALS(); GC←free((extern←ptr←t)curr←dl); return(1); } curr←dl = curr←dl -> dl←next; prev←dl = curr←dl; } UNLOCK(); ENABLE←SIGNALS(); return(0); } bool GC←is←marked(p) ptr←t p; { register struct hblk *h = HBLKPTR(p); register hdr * hhdr = HDR(h); register int word←no = (word *)p - (word *)h; return(mark←bit←from←hdr(hhdr, word←no)); } void GC←set←mark←bit(p) ptr←t p; { register struct hblk *h = HBLKPTR(p); register hdr * hhdr = HDR(h); register int word←no = (word *)p - (word *)h; set←mark←bit←from←hdr(hhdr, word←no); } void GC←clear←mark←bit(p) ptr←t p; { register struct hblk *h = HBLKPTR(p); register hdr * hhdr = HDR(h); register int word←no = (word *)p - (word *)h; clear←mark←bit←from←hdr(hhdr, word←no); } void GC←register←finalizer(obj, fn, cd, ofn, ocd) void←star obj; GC←finalization←proc fn; void←star cd; GC←finalization←proc * ofn; void←star * ocd; { ptr←t base; struct finalizable←object * curr←fo, * prev←fo; int index; /* Allocate before acquiring lock */ ALLOC(new←fo, struct finalizable←object); DCL←LOCK←STATE; DISABLE←SIGNALS(); LOCK(); base = (ptr←t)GC←base((void←star)obj); index = HASH(base); if (base != obj) ABORT("Bad arg to GC←register←finalizer"); prev←fo = 0; curr←fo = fo←head[index]; while (curr←fo != 0) { if (curr←fo -> fo←hidden←base == HIDE←POINTER(base)) { if (ofn) *ofn = curr←fo -> fo←fn; if (ocd) *ocd = (void←star) curr←fo -> fo←client←data; if (fn == 0) { /* Delete the structure for base. */ if (prev←fo == 0) { fo←head[index] = curr←fo -> fo←next; } else { prev←fo -> fo←next = curr←fo -> fo←next; } UNLOCK(); ENABLE←SIGNALS(); GC←free((extern←ptr←t)curr←fo); } else { curr←fo -> fo←fn = fn; curr←fo -> fo←client←data = (ptr←t)cd; UNLOCK(); ENABLE←SIGNALS(); } GC←free((extern←ptr←t)new←fo); return; } curr←fo = curr←fo -> fo←next; prev←fo = curr←fo; } { if (ofn) *ofn = 0; if (ocd) *ocd = 0; if (fn == 0) { UNLOCK(); ENABLE←SIGNALS(); GC←free((extern←ptr←t)new←fo); return; } new←fo -> fo←hidden←base = (word)HIDE←POINTER(base); new←fo -> fo←fn = fn; new←fo -> fo←client←data = (ptr←t)cd; new←fo -> fo←object←size = GC←size(base); new←fo -> fo←next = fo←head[index]; fo←head[index] = new←fo; } UNLOCK(); ENABLE←SIGNALS(); } /* Called with world stopped. Cause disappearing links to disappear, */ /* and invoke finalizers. */ void GC←finalize() { struct disappearing←link * curr←dl, * prev←dl, * next←dl; struct finalizable←object * curr←fo, * prev←fo, * next←fo; ptr←t real←ptr; register int i; /* Make disappearing links disappear */ for (i = 0; i < TSIZE; i++) { curr←dl = dl←head[i]; prev←dl = 0; while (curr←dl != 0) { real←ptr = (ptr←t)REVEAL←POINTER(curr←dl -> dl←hidden←base); if (!GC←is←marked(real←ptr)) { *(word *)(real←ptr + curr←dl -> dl←offset) = 0; next←dl = curr←dl -> dl←next; if (prev←dl == 0) { dl←head[i] = next←dl; } else { prev←dl -> dl←next = next←dl; } GC←clear←mark←bit((ptr←t)curr←dl); curr←dl = next←dl; } else { prev←dl = curr←dl; curr←dl = curr←dl -> dl←next; } } } /* Mark all objects reachable via chains of 1 or more pointers */ /* from finalizable objects. */ for (i = 0; i < TSIZE; i++) { for (curr←fo = fo←head[i]; curr←fo != 0; curr←fo = curr←fo -> fo←next) { real←ptr = (ptr←t)REVEAL←POINTER(curr←fo -> fo←hidden←base); if (!GC←is←marked(real←ptr)) { GC←mark←all(real←ptr, real←ptr + curr←fo -> fo←object←size); } /* if (GC←is←marked(real←ptr)) { --> Report finalization cycle here, if desired } */ } } /* Invoke finalization code for all objects that are still */ /* unreachable. */ for (i = 0; i < TSIZE; i++) { curr←fo = fo←head[i]; prev←fo = 0; while (curr←fo != 0) { real←ptr = (ptr←t)REVEAL←POINTER(curr←fo -> fo←hidden←base); if (!GC←is←marked(real←ptr)) { (*(curr←fo -> fo←fn))(real←ptr, curr←fo -> fo←client←data); GC←set←mark←bit(real←ptr); next←fo = curr←fo -> fo←next; if (prev←fo == 0) { fo←head[i] = next←fo; } else { prev←fo -> fo←next = next←fo; } if (!GC←is←marked((ptr←t)curr←fo)) { ABORT("GC←finalize: found accessible unmarked object\n"); } GC←clear←mark←bit((ptr←t)curr←fo); curr←fo = next←fo; } else { prev←fo = curr←fo; curr←fo = curr←fo -> fo←next; } } } } # ifdef ←←STDC←← void←star GC←call←with←alloc←lock(GC←fn←type fn, void←star client←data) # else void←star GC←call←with←alloc←lock(fn, client←data) GC←fn←type fn; void←star client←data; # endif { DCL←LOCK←STATE; DISABLE←SIGNALS(); LOCK(); (*fn)(client←data); UNLOCK(); ENABLE←SIGNALS(); }