enum
{
	propagator	= 3,		/* gc marking color */

	/* STRUCTALIGN is the unit to which the compiler aligns structs. */
	/* It really should be defined somewhere else */
	STRUCTALIGN = sizeof(int)	/* must be >=2 because of Strings */
};

typedef struct GC GC;
typedef struct Heap Heap;
typedef struct Marker Marker;
typedef struct Type Type;

struct GC
{
	int	mutator;
	int	marker;
	int	sweeper;
	int	color;

	int	nprop;
	int	halt;
	int	visit;

	Marker	*markers;

	void		(*print)(char*, ...);
	void		(*panic)(char*, ...);

	/* throttling */
	long	heapb;
	long	heapbs[3];
	int	sweepc;

	/* statistics */
	int	aflags;
	int	broken;
	int	busy;
	int	halted;
	int	propped;
};

enum	/* gc.aflags */
{
	GCsweep = (1<<0),
	GCaudit = (1<<1),
	GCepoch = (1<<2),
	GCmark = (1<<3),
	GCcreate = (1<<4),
	GCdestroy = (1<<5)
};

struct Heap
{
	int	color;		/* Allocation color */
	ulong	ref;
	Type*	t;
};

struct Marker
{
	void	(*mark)(void*);
	void	*x;
	Marker	*next;
};

struct Type
{
	char	*name;
	int	ref;
	void	(*free)(Heap*, int);
	void	(*mark)(Type*, void*);
	char	*(*namefn)(Heap*, Type*, char*, char*);
	int	size;
	int	np;
	void*	destroy;
	void*	initialize;
	long	sig;
	uchar	map[STRUCTALIGN];
};

#define H2D(t, x)	((t)(((uchar*)(x))+sizeof(Heap)))
#define D2H(x)		((Heap*)(((uchar*)(x))-sizeof(Heap)))
#define H		((void*)(-1))
#define Setmark(h)	if((h)->color!=gc.mutator) { (h)->color = propagator; gc.nprop=1; }
#define gclock()	gc.halt++
#define gcunlock()	gc.halt--
#define gcruns()	(gc.halt == 0)

extern	Type	Tptr;
extern	GC	gc;

extern	void		addmarker(void (*)(void*), void*);
extern	void		destroy(void*);
extern	char*	defnamefn(Heap*, Type*, char*, char*);
extern	Type*	dtype(char*, char*(*)(Heap*, Type*, char*, char*), void (*)(Heap*, int), int, uchar*, int);
extern	void		freeheap(Heap*, int);
extern	void		freeptrs(void*, Type*);
extern	void		freetype(Type*);
extern	Heap*	heap(Type*);
extern	void		heapassign(void*, void*);
extern	int		heapmsize(Heap*);
extern	int		heapref(void*);
extern	void		heapstate(Heap*, char*);
extern	Heap*	heapz(Type*);
extern	void		initgc(void);
extern	void		incmem(void*, Type*);
extern	void		initmem(Type*, void*);
extern	void		markheap(Type*, void*);
extern	Heap*	nheap(int);
extern	void		noptrs(Type*, void*);
extern	char*	printtype(Heap*, Type*, char*, char*);
extern	void		ptradd(Heap*);
extern	void		ptrdel(Heap*);
extern	void		ptrmark(void*);
extern	void		rungc(void);
extern	void		safemem(void*, Type*, void (*)(void*));
