/* 
 * 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.
 */
# include "gc←private.h"

# ifdef PCR
/*
 * Note that POSIX PCR requires an ANSI C compiler.  Hence we are allowed
 * to make the same assumption here.
 * We wrap all of the allocator functions to avoid questions of
 * compatibility between the prototyped and nonprototyped versions of the f
 */
# include "pcr/mm/PCR←MM.h"

# define MY←MAGIC 17L

void * GC←AllocProc(size←t size, PCR←Bool ptrFree, PCR←Bool clear )
{
    if (ptrFree) {
        void * result = (void *)GC←malloc←atomic(size);
        if (clear && result != 0) bzero(result, size);
        return(result);
    } else {
        return((void *)GC←malloc(size));
    }
}

# define GC←ReallocProc GC←realloc

# define GC←FreeProc GC←free

typedef struct {
  PCR←ERes (*ed←proc)(void *p, size←t size, PCR←Any data);
  bool ed←pointerfree;
  PCR←ERes ed←fail←code;
  PCR←Any ed←client←data;
} enumerate←data;

void GC←enumerate←block(h, ed)
register struct hblk *h;
enumerate←data * ed;
{
    register hdr * hhdr;
    register int sz;
    word *p;
    word * lim;
    
    hhdr = HDR(h);
    sz = hhdr -> hb←sz;
    if (sz >= 0 && ed -> ed←pointerfree
    	|| sz <= 0 && !(ed -> ed←pointerfree)) return;
    if (sz < 0) sz = -sz;
    lim = (word *)(h+1) - sz;
    p = (word *)h;
    do {
        if (PCR←ERes←IsErr(ed -> ed←fail←code)) return;
        ed -> ed←fail←code =
            (*(ed -> ed←proc))(p, WORDS←TO←BYTES(sz), ed -> ed←client←data);
        p+= sz;
    } while (p <= lim);
}

struct PCR←MM←ProcsRep * GC←old←allocator = 0;

PCR←ERes GC←EnumerateProc(
    PCR←Bool ptrFree,
    PCR←ERes (*proc)(void *p, size←t size, PCR←Any data),
    PCR←Any data
)
{
    enumerate←data ed;
    
    ed.ed←proc = proc;
    ed.ed←pointerfree = ptrFree;
    ed.ed←fail←code = PCR←ERes←okay;
    ed.ed←client←data = data;
    GC←apply←to←all←blocks(GC←enumerate←block, &ed);
    if (ed.ed←fail←code != PCR←ERes←okay) {
        return(ed.ed←fail←code);
    } else {
    	/* Also enumerate objects allocated by my predecessors */
    	return((*(GC←old←allocator->mmp←enumerate))(ptrFree, proc, data));
    }
}

void GC←DummyFreeProc(void *p) {};

void GC←DummyShutdownProc(void) {};

struct PCR←MM←ProcsRep GC←Rep = {
	MY←MAGIC,
	GC←AllocProc,
	GC←ReallocProc,
	GC←DummyFreeProc,  	/* mmp←free */
	GC←FreeProc,  		/* mmp←unsafeFree */
	GC←EnumerateProc,
	GC←DummyShutdownProc	/* mmp←shutdown */
};

void GC←pcr←install()
{
    PCR←MM←Install(&GC←Rep, &GC←old←allocator);
}
# endif