home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
08
/
xscheme
/
xsdmem.c
< prev
next >
Wrap
Text File
|
1991-06-04
|
17KB
|
743 lines
/* xsdmem.c - xscheme dynamic memory management routines */
/* Copyright (c) 1988, by David Michael Betz
All Rights Reserved
Permission is granted for unrestricted non-commercial use */
#include "xscheme.h"
/* virtual machine registers */
LVAL xlfun=NIL; /* current function */
LVAL xlenv=NIL; /* current environment */
LVAL xlval=NIL; /* value of most recent instruction */
LVAL *xlsp=NULL; /* value stack pointer */
/* stack limits */
LVAL *xlstkbase=NULL; /* base of value stack */
LVAL *xlstktop=NULL; /* top of value stack (actually, one beyond) */
/* variables shared with xsimage.c */
FIXTYPE total=0; /* total number of bytes of memory in use */
FIXTYPE gccalls=0; /* number of calls to the garbage collector */
/* node space */
NSEGMENT *nsegments=NULL; /* list of node segments */
NSEGMENT *nslast=NULL; /* last node segment */
int nscount=0; /* number of node segments */
FIXTYPE nnodes=0; /* total number of nodes */
FIXTYPE nfree=0; /* number of nodes in free list */
LVAL fnodes=NIL; /* list of free nodes */
/* vector (and string) space */
VSEGMENT *vsegments=NULL; /* list of vector segments */
VSEGMENT *vscurrent=NULL; /* current vector segment */
int vscount=0; /* number of vector segments */
LVAL *vfree=NULL; /* next free location in vector space */
LVAL *vtop=NULL; /* top of vector space */
/* external variables */
extern LVAL s_unbound; /* *UNBOUND* symbol */
extern LVAL obarray; /* *OBARRAY* symbol */
extern LVAL default_object; /* default object */
extern LVAL eof_object; /* eof object */
extern LVAL true; /* truth value */
/* external routines */
extern char *calloc();
/* forward declarations */
#ifdef __STDC__
static LVAL allocnode(int type);
static void findmemory(void);
static LVAL allocvector(int type,int size);
static int findvmemory(int size);
static void mark(LVAL ptr);
static void markvector(LVAL vect);
static void compact(void);
static void compact_vector(VSEGMENT *vseg);
static void sweep(void);
static void sweep_segment(NSEGMENT *nseg);
static void badobjtype(int type);
#else
static LVAL allocnode();
static LVAL allocvector();
static LVAL compact();
#endif
/* cons - construct a new cons node */
LVAL cons(x,y)
LVAL x,y;
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
check(2);
push(x);
push(y);
findmemory();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
drop(2);
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
--nfree;
/* initialize the new node */
nnode->n_type = CONS;
rplaca(nnode,x);
rplacd(nnode,y);
/* return the new node */
return (nnode);
}
/* newframe - create a new environment frame */
LVAL newframe(parent,size)
LVAL parent; int size;
{
LVAL frame;
frame = cons(newvector(size),parent);
frame->n_type = ENV;
return (frame);
}
/* cvstring - convert a string to a string node */
LVAL cvstring(str)
char *str;
{
LVAL val;
val = newstring(strlen(str)+1);
strcpy(getstring(val),str);
return (val);
}
/* cvsymbol - convert a string to a symbol */
LVAL cvsymbol(pname)
char *pname;
{
LVAL val;
val = allocvector(SYMBOL,SYMSIZE);
cpush(val);
setvalue(val,s_unbound);
setpname(val,cvstring(pname));
setplist(val,NIL);
return (pop());
}
/* cvfixnum - convert an integer to a fixnum node */
LVAL cvfixnum(n)
FIXTYPE n;
{
LVAL val;
if (n >= SFIXMIN && n <= SFIXMAX)
return (cvsfixnum(n));
val = allocnode(FIXNUM);
val->n_int = n;
return (val);
}
/* cvflonum - convert a floating point number to a flonum node */
LVAL cvflonum(n)
FLOTYPE n;
{
LVAL val;
val = allocnode(FLONUM);
val->n_flonum = n;
return (val);
}
/* cvchar - convert an integer to a character node */
LVAL cvchar(ch)
int ch;
{
LVAL val;
val = allocnode(CHAR);
val->n_chcode = ch;
return (val);
}
/* cvclosure - convert code and an environment to a closure */
LVAL cvclosure(code,env)
LVAL code,env;
{
LVAL val;
val = cons(code,env);
val->n_type = CLOSURE;
return (val);
}
/* cvpromise - convert a procedure to a promise */
LVAL cvpromise(code,env)
LVAL code,env;
{
LVAL val;
val = cons(cvclosure(code,env),NIL);
val->n_type = PROMISE;
return (val);
}
/* cvmethod - convert code and an environment to a method */
LVAL cvmethod(code,class)
LVAL code,class;
{
LVAL val;
val = cons(code,class);
val->n_type = METHOD;
return (val);
}
/* cvsubr - convert a function to a subr/xsubr */
LVAL cvsubr(type,fcn,offset)
int type; LVAL (*fcn)(); int offset;
{
LVAL val;
val = allocnode(type);
val->n_subr = fcn;
val->n_offset = offset;
return (val);
}
/* cvport - convert a file pointer to an port */
LVAL cvport(fp,flags)
FILE *fp; int flags;
{
LVAL val;
val = allocnode(PORT);
setfile(val,fp);
setsavech(val,'\0');
setpflags(val,flags);
return (val);
}
/* newvector - allocate and initialize a new vector */
LVAL newvector(size)
int size;
{
return (allocvector(VECTOR,size));
}
/* newstring - allocate and initialize a new string */
LVAL newstring(size)
int size;
{
LVAL val;
val = allocvector(STRING,btow_size(size));
val->n_vsize = size;
return (val);
}
/* newcode - create a new code object */
LVAL newcode(nlits)
int nlits;
{
return (allocvector(CODE,nlits));
}
/* newcontinuation - create a new continuation object */
LVAL newcontinuation(size)
int size;
{
return (allocvector(CONTINUATION,size));
}
/* newobject - allocate and initialize a new object */
LVAL newobject(cls,size)
LVAL cls; int size;
{
LVAL val;
val = allocvector(OBJECT,size+2); /* class, ivars */
setclass(val,cls);
return (val);
}
/* allocnode - allocate a new node */
static LVAL allocnode(type)
int type;
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
findmemory();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
--nfree;
/* initialize the new node */
nnode->n_type = type;
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
/* findmemory - garbage collect, then add more node space if necessary */
static void findmemory()
{
/* first try garbage collecting */
gc();
/* expand memory only if less than one segment is free */
if (nfree < (long)NSSIZE)
nexpand(NSSIZE);
}
/* nexpand - expand node space */
int nexpand(size)
int size;
{
NSEGMENT *newnsegment(),*newseg;
LVAL p;
int i;
/* allocate the new segment */
if ((newseg = newnsegment(size)) != NULL) {
/* add each new node to the free list */
p = &newseg->ns_data[0];
for (i = NSSIZE; --i >= 0; ++p) {
p->n_type = FREE;
p->n_flags = 0;
rplacd(p,fnodes);
fnodes = p;
}
}
return (newseg != NULL);
}
/* allocvector - allocate and initialize a new vector node */
static LVAL allocvector(type,size)
int type,size;
{
register LVAL val,*p;
register int i;
/* get a free node */
if ((val = fnodes) == NIL) {
findmemory();
if ((val = fnodes) == NIL)
xlabort("insufficient node space");
}
/* unlink the node from the free list */
fnodes = cdr(fnodes);
--nfree;
/* initialize the vector node */
val->n_type = type;
val->n_vsize = size;
val->n_vdata = NULL;
cpush(val);
/* add space for the backpointer */
++size;
/* make sure there's enough space */
if (!VCOMPARE(vfree,size,vtop)
&& !checkvmemory(size)
&& !findvmemory(size))
xlabort("insufficient vector space");
/* allocate the next available block */
p = vfree;
vfree += size;
/* store the backpointer */
*p++ = top();
val->n_vdata = p;
/* set all the elements to NIL */
for (i = size; i > 1; --i)
*p++ = NIL;
/* return the new vector */
return (pop());
}
/* findvmemory - find vector memory */
static int findvmemory(size)
int size;
{
/* try garbage collecting */
gc();
/* check to see if we found enough memory */
if (VCOMPARE(vfree,size,vtop) || checkvmemory(size))
return (TRUE);
/* expand vector space */
return (makevmemory(size));
}
/* checkvmemory - check for vector memory (used by 'xsimage.c') */
int checkvmemory(size)
int size;
{
VSEGMENT *vseg;
for (vseg = vsegments; vseg != NULL; vseg = vseg->vs_next)
if (vseg != vscurrent && VCOMPARE(vseg->vs_free,size,vseg->vs_top)) {
if (vscurrent != NULL)
vscurrent->vs_free = vfree;
vfree = vseg->vs_free;
vtop = vseg->vs_top;
vscurrent = vseg;
return (TRUE);
}
return (FALSE);
}
/* makevmemory - make vector memory (used by 'xsimage.c') */
int makevmemory(size)
int size;
{
return (vexpand(size < VSSIZE ? VSSIZE : size));
}
/* vexpand - expand vector space */
int vexpand(size)
int size;
{
VSEGMENT *newvsegment(),*vseg;
/* allocate the new segment */
if ((vseg = newvsegment(size)) != NULL) {
/* initialize the new segment and make it current */
if (vscurrent != NULL)
vscurrent->vs_free = vfree;
vfree = vseg->vs_free;
vtop = vseg->vs_top;
vscurrent = vseg;
}
return (vseg != NULL);
}
/* newnsegment - create a new node segment */
NSEGMENT *newnsegment(n)
unsigned int n;
{
NSEGMENT *newseg;
/* allocate the new segment */
if ((newseg = (NSEGMENT *)calloc(1,nsegsize(n))) == NULL)
return (NULL);
/* initialize the new segment */
newseg->ns_size = n;
newseg->ns_next = NULL;
if (nsegments)
nslast->ns_next = newseg;
else
nsegments = newseg;
nslast = newseg;
/* update the statistics */
total += (long)nsegsize(n);
nnodes += (long)n;
nfree += (long)n;
++nscount;
/* return the new segment */
return (newseg);
}
/* newvsegment - create a new vector segment */
VSEGMENT *newvsegment(n)
unsigned int n;
{
VSEGMENT *newseg;
/* allocate the new segment */
if ((newseg = (VSEGMENT *)calloc(1,vsegsize(n))) == NULL)
return (NULL);
/* initialize the new segment */
newseg->vs_free = &newseg->vs_data[0];
newseg->vs_top = newseg->vs_free + n;
newseg->vs_next = vsegments;
vsegments = newseg;
/* update the statistics */
total += (long)vsegsize(n);
++vscount;
/* return the new segment */
return (newseg);
}
/* gc - garbage collect */
void gc()
{
register LVAL *p,tmp;
/* mark the obarray and the current environment */
if (obarray && ispointer(obarray))
mark(obarray);
if (xlfun && ispointer(xlfun))
mark(xlfun);
if (xlenv && ispointer(xlenv))
mark(xlenv);
if (xlval && ispointer(xlval))
mark(xlval);
if (default_object && ispointer(default_object))
mark(default_object);
if (eof_object && ispointer(eof_object))
mark(eof_object);
if (true && ispointer(true))
mark(true);
/* mark the stack */
for (p = xlsp; p < xlstktop; ++p)
if ((tmp = *p) != NIL && ispointer(tmp))
mark(tmp);
/* compact vector space */
gc_protect(compact);
/* sweep memory collecting all unmarked nodes */
sweep();
/* count the gc call */
++gccalls;
}
/* mark - mark all accessible nodes */
static void mark(ptr)
LVAL ptr;
{
register LVAL this,prev,tmp;
/* initialize */
prev = NIL;
this = ptr;
/* mark this node */
for (;;) {
/* descend as far as we can */
while (!(this->n_flags & MARK))
/* mark this node and trace its children */
switch (this->n_type) {
case CONS: /* mark cons-like nodes */
case CLOSURE:
case METHOD:
case PROMISE:
case ENV:
this->n_flags |= MARK;
if ((tmp = car(this)) != NIL && ispointer(tmp)) {
this->n_flags |= LEFT;
rplaca(this,prev);
prev = this;
this = tmp;
}
else if ((tmp = cdr(this)) != NIL && ispointer(tmp)) {
rplacd(this,prev);
prev = this;
this = tmp;
}
break;
case SYMBOL: /* mark vector-like nodes */
case OBJECT:
case VECTOR:
case CODE:
case CONTINUATION:
this->n_flags |= MARK;
markvector(this);
break;
case FIXNUM: /* mark objects that don't contain pointers */
case FLONUM:
case STRING:
case PORT:
case SUBR:
case XSUBR:
case CSUBR:
case CHAR:
this->n_flags |= MARK;
break;
default: /* bad object type */
badobjtype(this->n_type);
break;
}
/* backup to a point where we can continue descending */
for (;;)
/* make sure there is a previous node */
if (prev) {
if (prev->n_flags & LEFT) { /* came from left side */
prev->n_flags &= ~LEFT;
tmp = car(prev);
rplaca(prev,this);
if ((this = cdr(prev)) != NIL && ispointer(this)) {
rplacd(prev,tmp);
break;
}
}
else { /* came from right side */
tmp = cdr(prev);
rplacd(prev,this);
}
this = prev; /* step back up the branch */
prev = tmp;
}
/* no previous node, must be done */
else
return;
}
}
/* markvector - mark a vector-like node */
static void markvector(vect)
LVAL vect;
{
register LVAL tmp,*p;
register int n;
if ((p = vect->n_vdata) != NULL) {
n = getsize(vect);
while (--n >= 0)
if ((tmp = *p++) != NIL && ispointer(tmp))
mark(tmp);
}
}
/* compact - compact vector space */
static void compact()
{
VSEGMENT *vseg;
/* store the current segment information */
if (vscurrent)
vscurrent->vs_free = vfree;
/* compact each vector segment */
for (vseg = vsegments; vseg != NULL; vseg = vseg->vs_next)
compact_vector(vseg);
/* make the first vector segment current */
if ((vscurrent = vsegments) != NULL) {
vfree = vscurrent->vs_free;
vtop = vscurrent->vs_top;
}
}
/* compact_vector - compact a vector segment */
static void compact_vector(vseg)
VSEGMENT *vseg;
{
register LVAL *vdata,*vnext,*vfree,vector;
register int vsize;
vdata = vnext = &vseg->vs_data[0];
vfree = vseg->vs_free;
while (vdata < vfree) {
vector = *vdata;
vsize = (vector->n_type == STRING ? btow_size(vector->n_vsize)
: vector->n_vsize) + 1;
if (vector->n_flags & MARK) {
if (vdata == vnext) {
vdata += vsize;
vnext += vsize;
}
else {
vector->n_vdata = vnext + 1;
while (--vsize >= 0)
*vnext++ = *vdata++;
}
}
else
vdata += vsize;
}
vseg->vs_free = vnext;
}
/* sweep - sweep all unmarked nodes and add them to the free list */
static void sweep()
{
NSEGMENT *nseg;
/* empty the free list */
fnodes = NIL;
nfree = 0L;
/* sweep each node segment */
for (nseg = nsegments; nseg != NULL; nseg = nseg->ns_next)
sweep_segment(nseg);
}
/* sweep_segment - sweep a node segment */
static void sweep_segment(nseg)
NSEGMENT *nseg;
{
register FIXTYPE n;
register LVAL p;
/* add all unmarked nodes */
for (p = &nseg->ns_data[0], n = nseg->ns_size; --n >= 0L; ++p)
if (!(p->n_flags & MARK)) {
switch (p->n_type) {
case PORT:
if (getfile(p))
osclose(getfile(p));
break;
}
p->n_type = FREE;
rplacd(p,fnodes);
fnodes = p;
++nfree;
}
else
p->n_flags &= ~MARK;
}
/* xlminit - initialize the dynamic memory module */
void xlminit(ssize)
unsigned int ssize;
{
unsigned int n;
/* initialize our internal variables */
gccalls = 0;
total = 0L;
/* initialize node space */
nsegments = nslast = NULL;
nscount = 0;
nnodes = nfree = 0L;
fnodes = NIL;
/* initialize vector space */
vsegments = vscurrent = NULL;
vscount = 0;
vfree = vtop = NULL;
/* allocate the value stack */
n = ssize * sizeof(LVAL);
if ((xlstkbase = (LVAL *)calloc(1,n)) == NULL)
xlfatal("insufficient memory");
total += (long)n;
/* initialize structures that are marked by the collector */
obarray = default_object = eof_object = true = NIL;
xlfun = xlenv = xlval = NIL;
/* initialize the stack */
xlsp = xlstktop = xlstkbase + ssize;
}
/* badobjtype - report a bad object type error */
static void badobjtype(type)
int type;
{
char buf[100];
sprintf(buf,"bad object type - %d",type);
xlfatal(buf);
}