/* xldmem - xlisp dynamic memory management routines */
/* Copyright (c) 1989, by David Michael Betz. */
/* You may give out copies of this software; for conditions see the file */
/* COPYING included with this distribution. */
#include "xlisp.h"
typedef LVAL (*subrfun)(V);
static LVAL finalize_registered, finalize_pending;
static VOID check_finalize(V);
static VOID do_finalize(V);
static VOID check_weak_boxes(V);
#ifdef NEWGC
/* gc tuning parameters */
/**** these should probably be in special variables */
#define ALLOC_THRESHOLD_INCREMENT 0x20000L
#define GC_EXPAND_FRAC 0.2
#define FULL_GC_FRAC 0.85
static double gc_expand_frac = GC_EXPAND_FRAC;
static double full_gc_frac = FULL_GC_FRAC;
/* position offsets for doubly linked list heads in segment */
#define IMMEDIATE_OFFSET 0
#define ALLOCATED_OFFSET 1
#define IMMEDIATE_TENURED_OFFSET 2
#define ALLOCATED_TENURED_OFFSET 3
#define IMMEDIATE_TO_NEW_OFFSET 4
#define ALLOCATED_TO_NEW_OFFSET 5
#define NUM_OFFSETS 6
#define TENURED_OFFSET(n) (type_info[(int)ntype(n)].tenured_offset)
#define TO_NEW_OFFSET(n) (type_info[(int)ntype(n)].to_new_offset)
/* limits for segment size - max is 2^15 - 5 for 16-bit shorts */
#define MIN_ANODES 1
#define MAX_ANODES ((1 << 15) - NUM_OFFSETS - 1)
/* macro to compute the size of a segment */
#define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node))
#ifdef TIMES
static unsigned long gctime; /* calcuate time in garbage collector */
#endif
/* macros to convert between size in bytes and vector size */
#define btow_size(n) (((unsigned)(n)+(sizeof(LVAL)-1))/(unsigned)sizeof(LVAL))
#define wtob_size(n) (((long) (n)) * sizeof(LVAL))
/* variables local to xldmem.c and xlimage.c */
SEGMENT *segs,*lastseg,*fixseg,*charseg,*lastpermseg;
int anodes,nsegs;
/* local variables */
static long minor_gccalls;
static long nperm,ntenured,alloc_threshold,threshold_crossing_gccount;
static SEGMENT *curseg;
static LVAL curbase, curtop;
/* structure for holding information about types */
struct {
int has_children, allocated;
int tenured_offset, to_new_offset;
} type_info[NUMTYPES];
/* macros using the structure */
#define node_has_children(node) (type_info[(int)ntype(node)].has_children)
#define type_is_allocated(type) (type_info[(int)type].allocated)
#define node_is_allocated(node) (type_info[(int)ntype(node)].allocated)
/* macros to check/set whether a node is in new or old space */
static int old_code = 0;
#define is_old_node(x) (ngcflag1(x)==old_code)
#define is_new_node(x) (ngcflag1(x)!=old_code)
#define set_old_node(x) (old_code ? setngcflag1(x) : unsetngcflag1(x))
#define set_new_node(x) (old_code ? unsetngcflag1(x) : setngcflag1(x))
/* macros to check/set whether a node is in the to new list */
#define is_to_new_node(x) (ngcflag2(x))
#define set_to_new_node(x) (setngcflag2(x))
#define unset_to_new_node(x) (unsetngcflag2(x))
/* macros to access and set the offsets of a node */
#define NEXT_NODE_OFFSET(x) ((x)->n_gc.n_gc_offsets.forward)
#define SET_NEXT_NODE_OFFSET(x,p) ((x)->n_gc.n_gc_offsets.forward = (p))
#define LAST_NODE_OFFSET(x) ((x)->n_gc.n_gc_offsets.backward)
#define SET_LAST_NODE_OFFSET(x,p) ((x)->n_gc.n_gc_offsets.backward = (p))
#define NODE_BASE_OFFSET(x) ((x)->n_base_offset)
#define SET_NODE_BASE_OFFSET(x,p) ((x)->n_base_offset = (p))
/* macros to access and set the forwarding pointer of a node */
#define NEXT_NODE_PTR(x) ((x)->n_gc.n_next)
#define SET_NEXT_NODE_PTR(x,p) ((x)->n_gc.n_next = (p))
/* macros to access and set the base (first node in seg.) pointer of a node */
#define NODE_BASE(x) ((x) - NODE_BASE_OFFSET(x))
#define SET_NODE_BASE(x, p) SET_NODE_BASE_OFFSET(x,(x) - (p))
/* macros to access and set linked list pointers */
#define NEXT_NODE(x) (NODE_BASE(x) + NEXT_NODE_OFFSET(x))
#define SET_NEXT_NODE(x,p) SET_NEXT_NODE_OFFSET(x,(p)-NODE_BASE(x))
#define LAST_NODE(x) (NODE_BASE(x) + LAST_NODE_OFFSET(x))
#define SET_LAST_NODE(x,p) SET_LAST_NODE_OFFSET(x,(p)-NODE_BASE(x))
/* macro to unlink a node from its current linked list */
#define UNLINK_NODE(x) {\
register LVAL __x, base; \
register short lnox, nnox; \
__x = (x); base = NODE_BASE(__x); \
lnox = LAST_NODE_OFFSET(__x); nnox = NEXT_NODE_OFFSET(__x); \
SET_NEXT_NODE_OFFSET(base + lnox,nnox); \
SET_LAST_NODE_OFFSET(base + nnox,lnox); \
}
/* macro to link a node x after a node p in a linked list in the same seg. */
#define LINK_NODE(x,p) {\
register LVAL __x, __p; \
register short ox, op, nnop; \
__x = (x); __p = (p); \
nnop = NEXT_NODE_OFFSET(__p); \
ox = NODE_BASE_OFFSET(__x); op = NODE_BASE_OFFSET(__p);\
SET_NEXT_NODE_OFFSET(__p,ox); \
SET_LAST_NODE_OFFSET(__x,op); \
SET_NEXT_NODE_OFFSET(__x,nnop); \
SET_LAST_NODE_OFFSET(NODE_BASE(__x) + nnop,ox); \
}
/* macro to link a node to the base with ffset b */
#define LINK_NODE_TO_BASE(x,b) LINK_NODE(x,NODE_BASE(x)+(b))
/* macro to move a node from one linked list to another in its segment */
#define MOVE_NODE(x,p) { UNLINK_NODE(x); LINK_NODE(x,p); }
/* macro to move a node to the list with base offset b */
#define MOVE_NODE_TO_BASE(x,b) MOVE_NODE(x,NODE_BASE(x)+(b))
/* macro to move all the nodes in a list except the base to another list */
#define MOVE_LIST(a,b) {\
register LVAL nna, lna, nnb; \
nna = NEXT_NODE(a); lna = LAST_NODE(a); nnb = NEXT_NODE(b); \
if (a != nna) { \
SET_NEXT_NODE(a,a); \
SET_LAST_NODE(a,a); \
SET_NEXT_NODE(b,nna); \
SET_LAST_NODE(nna,b); \
SET_NEXT_NODE(lna,nnb); \
SET_LAST_NODE(nnb,lna); \
} \
}
/* macro to find the next free node; also advances the pointer */
#define NEXT_FREE_NODE() \
(curtop = curbase + NEXT_NODE_OFFSET(curtop), \
(curtop == curbase) ? NIL : curtop)
/* macro to handle creating references from old to new space */
/* This assumes NIL is marked as 'old' and 'to_new' */
#define check_old_to_new(x,y) { \
if (is_old_node(x) && is_new_node(y)) { \
if (! is_to_new_node(x)) { \
MOVE_NODE_TO_BASE(x, TO_NEW_OFFSET(x)); \
set_to_new_node(x); \
} \
} \
}
/* forward declarations */
LOCAL LVAL newnode P1H(int);
LOCAL LVAL allocvector P2H(int, unsigned);
LOCAL int addseg(V);
LOCAL VOID stats(V);
LOCAL VOID check_alloc_threshold P1H(long);
LOCAL VOID adjust_alloc_threshold(V);
LOCAL VOID expand_node_space(V);
LOCAL VOID morevmem P1H(int);
LOCAL VOID ggc P1H(int);
LOCAL VOID clean_free_allocated_node P1H(LVAL);
LOCAL char *IViewNewAData P4H(int, int, long *, int);
/* xlminit - initialize the dynamic memory module */
VOID xlminit(V)
{
LVAL p;
int i;
/* initialize our internal variables */
segs = lastseg = curseg = lastpermseg = NULL;
nnodes = nfree = total = gccalls = minor_gccalls = nperm = ntenured = 0L;
alloc_threshold = ALLOC_THRESHOLD_INCREMENT;
threshold_crossing_gccount = 0L;
nsegs = 0;
anodes = NNODES;
gctime = 0L;
for (i = 0; i < NUMTYPES; i++) {
type_info[i].has_children = FALSE;
type_info[i].allocated = TRUE;
}
type_info[FREE].allocated = FALSE;
type_info[SUBR].allocated = FALSE;
type_info[FSUBR].allocated = FALSE;
type_info[CONS].allocated = FALSE;
type_info[CONS].has_children = TRUE;
type_info[SYMBOL].has_children = TRUE;
type_info[FIXNUM].allocated = FALSE;
type_info[FLONUM].allocated = FALSE;
#ifdef BIGNUMS
type_info[RATIO].allocated = FALSE;
type_info[RATIO].has_children = TRUE;
#endif
type_info[OBJECT].has_children = TRUE;
type_info[VECTOR].has_children = TRUE;
type_info[CLOSURE].has_children = TRUE;
type_info[CHAR].allocated = FALSE;
type_info[USTREAM].allocated = FALSE;
type_info[USTREAM].has_children = TRUE;
type_info[COMPLEX].allocated = FALSE;
type_info[COMPLEX].has_children = TRUE;
type_info[RNDSTATE].allocated = FALSE;
type_info[RNDSTATE].has_children = TRUE;
type_info[NATPTR].allocated = FALSE;
type_info[NATPTR].has_children = TRUE;
type_info[WEAKBOX].allocated = FALSE;
type_info[WEAKBOX].has_children = FALSE;
type_info[DARRAY].allocated = FALSE;
type_info[DARRAY].has_children = TRUE;
type_info[STRUCT].has_children = TRUE;
#ifdef BYTECODE
type_info[BCCLOSURE].allocated = FALSE;
type_info[BCCLOSURE].has_children = TRUE;
type_info[CPSNODE].has_children = TRUE;
type_info[BCODE].has_children = TRUE;
#endif /*BYTECODE */
#ifdef PACKAGES
type_info[PACKAGE].has_children = TRUE;
#endif /* PACKAGES */
for (i = 0; i < NUMTYPES; i++) {
if (type_info[i].allocated) {
type_info[i].tenured_offset = ALLOCATED_TENURED_OFFSET;
type_info[i].to_new_offset = ALLOCATED_TO_NEW_OFFSET;
}
else {
type_info[i].tenured_offset = IMMEDIATE_TENURED_OFFSET;
type_info[i].to_new_offset = IMMEDIATE_TO_NEW_OFFSET;
}
}
/* allocate the fixnum segment */
if ((fixseg = newsegment(SFIXSIZE)) == NULL)
xlfatal("insufficient memory");
/* initialize the fixnum segment */
p = &fixseg->sg_nodes[0] + NUM_OFFSETS;
for (i = SFIXMIN; i <= SFIXMAX; ++i) {
setntype(p, FIXNUM);
p->n_fixnum = i;
set_old_node(p);
++p;
nperm++;
}
/* allocate the character segment */
if ((charseg = newsegment(CHARSIZE)) == NULL)
xlfatal("insufficient memory");
/* initialize the character segment */
p = &charseg->sg_nodes[0] + NUM_OFFSETS;
for (i = CHARMIN; i <= CHARMAX; ++i) {
setntype(p, CHAR);
p->n_chcode = i;
set_old_node(p);
++p;
nperm++;
}
/* set pointer to last permanent segment */
lastpermseg = lastseg;
/* allocate an initial segment */
if (! addseg())
xlfatal("insufficient memory");
curseg = lastpermseg->sg_next;
curtop = curbase = &curseg->sg_nodes[0];
/* initialize structures that are marked by the collector */
obarray = NULL;
xlenv = xlfenv = xldenv = NIL;
s_gcflag = s_gchook = NULL;
/* allocate the evaluation stack */
if ((xlstkbase = (LVAL **)malloc(EDEPTH * sizeof(LVAL *))) == NULL)
xlfatal("insufficient memory");
xlstack = xlstktop = xlstkbase + EDEPTH;
/* allocate the argument stack */
if ((xlargstkbase = (LVAL *)malloc(ADEPTH * sizeof(LVAL))) == NULL)
xlfatal("insufficient memory");
xlargstktop = xlargstkbase + ADEPTH;
xlfp = xlsp = xlargstkbase;
*xlsp++ = NIL;
#ifdef MULVALS
/* allocate the result array */
if ((xlresults = (LVAL *)malloc(MULVALLIMIT * sizeof(LVAL))) == NULL)
xlfatal("insufficient memory");
for (i = 0; i < MULVALLIMIT; i++)
xlresults[i] = NIL;
#endif /* MULVALS */
/* we have to make a NIL symbol before continuing */
/**** this is a real hack */
p = xlmakesym("NIL");
MEMCPY(NIL, p, sizeof(struct node)); /* we point to this! */
defconstant(NIL, NIL);
set_old_node(NIL);
set_to_new_node(NIL);
setfunction(NIL, NIL);
setntype(p, FREE); /* don't collect "garbage" */
finalize_registered = NIL;
finalize_pending = NIL;
}
/* The next three functions are function versions of rplaca, rplacd and */
/* setelement that check for creating references from old to new space. */
/**** all other files need to be checked carefully to see where the */
/**** macro versions Rplaca, Rplacd and Setelement can be used safely */
LVAL rplaca P2C(LVAL, x, LVAL, y) { check_old_to_new(x,y); return Rplaca(x,y); }
LVAL rplacd P2C(LVAL, x, LVAL, y) { check_old_to_new(x,y); return Rplacd(x,y); }
LVAL setelement P3C(LVAL, x, int, i, LVAL, v)
{
check_old_to_new(x,v);
return Setelement(x,i,v);
}
/* cons - construct a new cons node */
LVAL cons P2C(LVAL, x, LVAL, y)
{
LVAL nnode;
/* get a free node */
if ((nnode = NEXT_FREE_NODE()) == NIL) {
curtop = LAST_NODE(curtop); /* back up the curtop pointer */
xlstkcheck(2);
xlprotect(x);
xlprotect(y);
nnode = newnode(CONS);
xlpopn(2);
}
else {
setntype(nnode, CONS);
unset_to_new_node(nnode);
nfree--;
}
/* initialize the new node */
Rplaca(nnode,x);
Rplacd(nnode,y);
/* return the new node */
return (nnode);
}
/* cvstring - convert a string to a string node */
LVAL cvstring P1C(char *, str)
{
LVAL val;
val = newstring(STRLEN(str));
STRCPY(getstring(val),str);
return (val);
}
/* newstring - allocate and initialize a new string */
LVAL newstring P1C(unsigned, size)
{
LVAL val;
val = allocvector(STRING,btow_size(size+1));
val->n_strlen = size;
return (val);
}
#ifdef BIGNUMS
/* newbignum - allocate a new bignum */
LVAL newbignum P1C(unsigned, size)
{
/* size of the sign field not included in n_vsize */
BIGNUMDATA *x;
LVAL val;
xlsave1(val);
val = allocvector(BIGNUM,btow_size((size+1)*sizeof(BIGNUMDATA)));
val->n_bsize = size;
x = getbignumarray(val);
size++;
while (size--) *x++ = 0; /* set value to zero */
xlpop();
return val;
}
#endif
/* cvsymbol - convert a string to a symbol */
LVAL cvsymbol P1C(char *, pname)
{
LVAL val;
xlsave1(val);
val = allocvector(SYMBOL,SYMSIZE);
setvalue(val,s_unbound);
setfunction(val,s_unbound);
setpname(val,cvstring(pname));
setsnormal(val); /* L. Tierney */
xlpop();
return (val);
}
/* cvsubr - convert a function to a subr or fsubr */
LVAL cvsubr P3C(subrfun, fcn, int, type, int, offset)
{
LVAL val;
val = newnode(type);
val->n_subr = fcn;
val->n_offset = offset;
return (val);
}
/* cvfile - convert a file pointer to a stream */
LVAL cvfile P2C(FILEP, fp, int, iomode)
{
LVAL val;
val = newnode(STREAM);
setfile(val,fp);
setsavech(val,'\0');
val->n_sflags = iomode;
val->n_cpos = 0;
return (val);
}
/* cvfixnum - convert an integer to a fixnum node */
LVAL cvfixnum P1C(FIXTYPE, n)
{
LVAL val;
if (n >= SFIXMIN && n <= SFIXMAX)
return (&fixseg->sg_nodes[(int)n-SFIXMIN+NUM_OFFSETS]);
if ((val = NEXT_FREE_NODE()) == NIL) {
curtop = LAST_NODE(curtop); /* back up the curtop pointer */
val = newnode(FIXNUM);
}
else {
setntype(val, FIXNUM);
nfree--;
}
val->n_fixnum = n;
return (val);
}
/* cvflonum - convert a floating point number to a flonum node */
LVAL cvflonum P1C(FLOTYPE, n)
{
LVAL val;
if ((val = NEXT_FREE_NODE()) == NIL) {
curtop = LAST_NODE(curtop); /* back up the curtop pointer */
val = newnode(FLONUM);
}
else {
setntype(val, FLONUM);
nfree--;
}
val->n_flonum = n;
return (val);
}
/* cvchar - convert an integer to a character node */
LVAL cvchar P1C(int, n)
{
if (n >= CHARMIN && n <= CHARMAX)
return (&charseg->sg_nodes[n-CHARMIN+NUM_OFFSETS]);
xlerror("character code out of range",cvfixnum((FIXTYPE)n));
return (NIL); /* never executed but gets rid of warning message */
}
#ifdef BIGNUMS
/* cvbratio - convert a pair of bignums into a ratio node */
LVAL cvbratio P2C(LVAL, num, LVAL, denom)
{
FIXTYPE nu, d;
int fixtyped;
LVAL n,m,r;
if (cvtbigfixnum(num, &nu) && cvtbigfixnum(denom, &d))
return cvratio(nu,d);
xlstkcheck(5);
xlprotect(num);
xlprotect(denom);
xlsave(n);
xlsave(m);
xlsave(r);
if (zeropbignum(num)) { /* zero is fixnum zero */
xlpopn(5);
return cvfixnum((FIXTYPE) 0);
}
if (getbignumsign(denom)) { /* denominator must be positive */
denom = copybignum(denom, 0);
num = copybignum(num,!getbignumsign(num)); /* final sign */
}
n = copybignum(num, 0); /* abs of numerator */
m = denom;
for (;;) { /* get gcd */
divbignum(m, n, &r); /* use remainder only */
if (zeropbignum(r)) break;
m = n;
n = r;
}
if ((!cvtbigfixnum(n, &d)) || d != 1) { /* can reduce */
denom = divbignum(denom, n, &r);
num = divbignum(num, n, &r);
}
if ((fixtyped = cvtbigfixnum(denom, &d)) != 0 && d == 1) {
/* reduced to an integer */
xlpopn(5);
if (cvtbigfixnum(num, &nu)) return cvfixnum(nu);
return num;
}
/* got value to return */
r = newnode(RATIO);
r->n_cdr = r->n_car = NIL; /* in case of garbage collect */
r->n_cdr = (fixtyped ? cvfixnum(d) : denom);
r->n_car = (cvtbigfixnum(num, &nu) ? cvfixnum(nu) : num);
xlpopn(5);
return (r);
}
/* cvratio - convert an integer pair to a ratio node */
LVAL cvratio P2C(FIXTYPE, num, FIXTYPE, denom)
{
LVAL val;
unsigned long n, m, r, nu, de;
int sign;
if (num == 0) return cvfixnum((FIXTYPE) 0); /* zero is int zero */
if (denom < 0) { /* denominator must be positive */
if (denom == -1 && num == MINFIX) {
xlsave1(val);
val = cvtulongbignum((unsigned long)MAXFIX+1, FALSE);
xlpop();
return val;
}
denom = -denom;
sign = num >= 0;
}
else
sign = num < 0;
if (num < 0) num = -num;
n = nu = (unsigned long)(long)num;
m = de = (unsigned long)(long)denom; /* reduce the ratio: compute GCD */
for (;;) {
if ((r = m % n) == 0) break;
m = n;
n = r;
}
if (n != 1) {
de /= n;
nu /= n;
}
if (de == 1)
return cvfixnum(sign ? -(long)nu : (long)nu); /* reduced to integer */
xlsave1(val);
val = newnode(RATIO);
val->n_cdr = val->n_car = NIL; /* in case of garbage collect */
if ((nu == (unsigned long)MAXFIX+1 && sign==0))
val->n_car = cvtulongbignum(nu, sign);
else
val->n_car = cvfixnum(sign ? -(long)nu : (long)nu);
if (de == (unsigned long)MAXFIX+1)
val->n_cdr = cvtulongbignum(de, FALSE);
else
val->n_cdr = cvfixnum(de);
xlpop();
return (val);
}
#endif
/* newustream - create a new unnamed stream */
LVAL newustream(V)
{
LVAL val;
val = newnode(USTREAM);
sethead(val,NIL);
settail(val,NIL);
return (val);
}
/* newobject - allocate and initialize a new object */
LVAL newobject P2C(LVAL, cls, int, size)
{
LVAL val;
val = allocvector(OBJECT,size+1);
setelement(val,0,cls);
return (val);
}
/* newclosure - allocate and initialize a new closure */
LVAL newclosure P4C(LVAL, name, LVAL, type, LVAL, env, LVAL, fenv)
{
LVAL val;
val = allocvector(CLOSURE,CLOSIZE);
setname(val,name);
settype(val,type);
setenvi(val,env);
setfenv(val,fenv);
return (val);
}
/* newstruct - allocate and initialize a new structure node */
LVAL newstruct P2C(LVAL, type, int, size)
{
LVAL val;
val = allocvector(STRUCT,size+1);
setelement(val,0,type);
return (val);
}
#ifdef BYTECODE
/* newcpsnode - allocate and initialize a new CPS node for compiler */
LVAL newcpsnode P1C(LVAL, type)
{
LVAL val;
val = allocvector(CPSNODE,CPSNODESIZE);
setcpstype(val,type);
return (val);
}
/* newbcode - allocate and initialize a new byte code vector */
LVAL newbcode P5C(LVAL, code, LVAL, jtab, LVAL, lits, LVAL, idx, LVAL, env)
{
LVAL val;
val = allocvector(BCODE,BCODESIZE);
setbccode(val, code);
setbcjtab(val, jtab);
setbclits(val, lits);
setbcidx(val, idx);
setbcenv(val, env);
return (val);
}
#endif /* BYTECODE */
#ifdef PACKAGES
/* newpackage - allocate and initialize a new package */
LVAL newpackage(V)
{
LVAL val;
xlsave1(val);
val = allocvector(PACKAGE,PACKSIZE);
setintsyms(val, newvector(HSIZE));
setextsyms(val, newvector(HSIZE));
xlpop();
return (val);
}
#endif /* PACKAGES */
/* newvector - allocate and initialize a new vector node */
LVAL newvector P1C(unsigned, size)
{
return(allocvector(VECTOR,size));
}
/* allocvector - allocate and initialize a new vector node */
LOCAL LVAL allocvector P2C(int, type, unsigned, size)
{
LVAL vect, *p;
int i;
unsigned long bsize; /* changed to unsigned long - L. Tierney */
xlsave1(vect);
vect = newnode(type);
vect->n_vsize = 0;
if (size != 0) {
bsize = wtob_size(size);
check_alloc_threshold(bsize);
if ((vect->n_vdata = (LVAL *)VALLOC(size)) == NULL) {
ggc(FALSE);
if ((vect->n_vdata = (LVAL *)VALLOC(size)) == NULL) {
ggc(TRUE);
if ((vect->n_vdata = (LVAL *)VALLOC(size)) == NULL)
xlabort("insufficient vector space");
}
}
vect->n_vsize = size;
total += bsize;
}
/* set all the elements to NIL, except for STRINGs and TVECs */
if (type != STRING && type != TVEC)
for (i = 0, p = vect->n_vdata; i < size; i++)
*p++ = NIL;
xlpop();
return (vect);
}
#ifdef XLISP_STAT
/* Added for internal allocated storage - L. Tierney */
#include "xlstat.h"
LOCAL char *IViewNewAData P4C(int, n, int, m, long *, size, int, reloc)
{
char *addr;
addr = (reloc) ? StRCalloc(n, m): StCalloc(n, m);
*size = (reloc) ? StRSize(addr) : ((long) m) * ((long) n);
return(addr);
}
/* newadata(n, m, reloc) - convert a string to a string node */
LVAL newadata P3C(int, n, int, m, int, reloc)
{
LVAL val;
long size;
/*if (reloc) xlfail("relocatable allocated data not supported");*/
size = ((long) m) * ((long) n);
check_alloc_threshold(size);
xlsave1(val);
val = newnode(ADATA);
setadreloc(val, reloc);
/**** check what happens when asked for zero length */
if ((val->n_adaddr = IViewNewAData(n, m, &size, reloc)) == NULL) {
ggc(FALSE);
if ((val->n_adaddr = IViewNewAData(n, m, &size, reloc)) == NULL) {
ggc(TRUE);
if ((val->n_adaddr = IViewNewAData(n, m, &size, reloc)) == NULL)
xlabort("insufficient memory");
}
}
val->n_adsize = size;
total += size;
xlpop();
return (val);
}
VOID reallocaddata P3C(LVAL, val, int, n, int, m)
{
char *addr;
check_alloc_threshold(((long) n) * ((long) m)); /**** overestimate */
if (! adatap(val) || ! getadreloc(val)) xlfail("not relocatable");
addr = StRRealloc(getadaddr(val), n, m);
if (addr == NULL) xlabort("allocation failed");
val->n_adaddr = addr;
total -= getadsize(val);
val->n_adsize = StRSize(addr);
total += getadsize(val);
}
VOID freeadata P1C(LVAL, val)
{
if (! adatap(val)) xlfail("not a data object");
if (getadreloc(val)) StRFree(getadaddr(val));
else StFree(getadaddr(val));
val->n_adaddr = NULL;
total -= getadsize(val);
val->n_adsize = 0;
adjust_alloc_threshold();
}
/* Added for internal allocated storage - L. Tierney */
#endif /* XLISP_STAT */
#ifdef DODO
/* find_free_node - search all segments for the first free node, NIL if none */
LOCAL LVAL find_free_node(V)
{
LVAL val;
val = NEXT_FREE_NODE();
while (val == NIL && curseg != NULL) {
curseg = curseg->sg_next;
if (curseg != NULL) {
curtop = curbase = &curseg->sg_nodes[0];
val = NEXT_FREE_NODE();
}
}
return(val);
}
#else
/* macro version */
#define FIND_FREE_NODE(val) { \
val = NEXT_FREE_NODE(); \
while (val == NIL && curseg != NULL) { \
curseg = curseg->sg_next; \
if (curseg != NULL) { \
curtop = curbase = &curseg->sg_nodes[0]; \
val = NEXT_FREE_NODE(); \
} \
} \
}
#endif /* DODO */
/**** should interrupts be disabled here? */
/* newnode - allocate a new node */
LOCAL LVAL newnode P1C(int, type)
{
register LVAL nnode;
#ifdef DODO
if ((nnode = find_free_node()) == NIL) {
ggc(FALSE);
if (nnodes - nfree > nnodes * full_gc_frac) {
ggc(TRUE);
expand_node_space();
}
if ((nnode = find_free_node()) == NIL)
xlabort("insufficient node space");
}
#else
FIND_FREE_NODE(nnode);
if (nnode == NIL) {
ggc(FALSE);
if (nnodes - nfree > nnodes * full_gc_frac) {
ggc(TRUE);
expand_node_space();
}
FIND_FREE_NODE(nnode);
if (nnode == NIL)
xlabort("insufficient node space");
}
#endif /* DODO */
nfree--;
/* move allocated node from immediate list to allocated list */
if (type_is_allocated(type)) {
nnode->n_vdata = NULL;
curtop = LAST_NODE(nnode); /* back up the curtop pointer */
MOVE_NODE_TO_BASE(nnode, ALLOCATED_OFFSET);
}
/* initialize the new node */
setntype(nnode, type);
unset_to_new_node(nnode);
/* return the new node */
return (nnode);
}
/* macro to move a node to the tenured list -- node is already marked as old */
#define TENURE_NODE(n) { LINK_NODE_TO_BASE(n,TENURED_OFFSET(n)); ntenured++; }
/* macro to either tenure a node or place it on the forwarded list */
#ifdef NULLPTRDEBUG
static int hit_null_pointer;
#define forward_node(n) \
{\
register LVAL tmp = (n); \
if (tmp == NULL) { \
hit_null_pointer = TRUE; \
} \
else { \
if (is_new_node(tmp)) {\
UNLINK_NODE(tmp); \
if (node_has_children(tmp)) { \
SET_NEXT_NODE_PTR(tmp, forwarded_nodes); \
forwarded_nodes = tmp; \
} \
else { \
TENURE_NODE(tmp); \
} \
set_old_node(tmp); \
} \
} \
}
#else
#define forward_node(n) \
{\
register LVAL tmp = (n); \
if (is_new_node(tmp)) {\
UNLINK_NODE(tmp); \
if (node_has_children(tmp)) { \
SET_NEXT_NODE_PTR(tmp, forwarded_nodes); \
forwarded_nodes = tmp; \
} \
else { \
TENURE_NODE(tmp); \
} \
set_old_node(tmp); \
}\
}
#endif /* NULLPTRDEBUG */
/* macro to forward all children of a node -- node type must have children */
#ifdef BYTECODE
#define CASE_BCCLOSURE case BCCLOSURE:
#else
#define CASE_BCCLOSURE
#endif
#ifdef BIGNUMS
#define CASE_RATIO case RATIO:
#else
#define CASE_RATIO
#endif
#define forward_children(node) \
{ \
register LVAL temp; \
register int i, n; \
temp = (node); \
switch (ntype(temp)) { \
case CONS: \
case USTREAM: \
case COMPLEX: \
case RNDSTATE: \
CASE_RATIO \
CASE_BCCLOSURE \
case DARRAY: \
forward_node(car(temp)); \
forward_node(cdr(temp)); \
break; \
case NATPTR: \
forward_node(cdr(temp)); \
break; \
default: \
for (i = 0, n = getsize(temp); --n >= 0; ++i) \
forward_node(getelement(temp,i)); \
break; \
} \
}
/* clean_free_allocated_node - do finalization for free allocated node */
LOCAL VOID clean_free_allocated_node P1C(LVAL, tmp)
{
switch (ntype(tmp)) {
case FREE: /**** I'm not sure I need this case */
break;
case STRING:
case TVEC:
if (getstring(tmp) != NULL) {
long size = btow_size(getslength(tmp) + 1);
total -= size * sizeof(LVAL);
VRELEASE(getstring(tmp), size);
}
break;
#ifdef BIGNUMS
case BIGNUM:
if (getbignumarray(tmp) != NULL) {
long size = btow_size((1+(long)getbignumsize(tmp))*sizeof(BIGNUMDATA));
total -= size * sizeof(LVAL);
VRELEASE(getstring(tmp), size);
}
break;
#endif
#ifdef XLISP_STAT
case ADATA:
if (getadaddr(tmp) != NULL) {
total -= getadsize(tmp);
if (getadreloc(tmp)) StRFree(getadaddr(tmp));
else StFree(getadaddr(tmp));
}
break;
#endif /* XLISP_STAT */
case STREAM:
if (getfile(tmp) != CLOSED
&& getfile(tmp) != STDIN
&& getfile(tmp) != STDOUT
&& getfile(tmp) != CONSOLE)/* taa fix - dont close stdio */
OSCLOSE(getfile(tmp));
break;
default:
if (tmp->n_vsize) {
VRELEASE((ALLOCTYPE *) tmp->n_vdata, tmp->n_vsize);
total -= wtob_size(tmp->n_vsize);
}
break;
}
setntype(tmp, FREE);
}
/* gc - garbage collect (only called here and in xlimage.c) */
VOID gc(V) { ggc(TRUE); }
/* ggc - generational garbage collector */
LOCAL VOID ggc P1C(int, full_gc)
{
register LVAL **p, *ap, tmp, forwarded_nodes;
char buf[STRMAX+1];
LVAL *newfp, fun;
register SEGMENT *sg;
#ifdef TIMES
unsigned long gccount = run_tick_count();
#endif
/**** make sure interrupts are turned off */
#ifdef STSZ
#if (GCSTMARGIN>0)
if (STACKREPORT(fun)<GCSTMARGIN) { /* Do not try gc with less */
dbgputstr("Insufficient stack left for GC ");
if (batchmode) xlfatal("uncaught error");
xltoplevel(TRUE);
}
#endif
#endif
set_gc_cursor(TRUE); /* L. Tierney */
/* print the start of the gc message */
if (s_gcflag != NULL && getvalue(s_gcflag) != NIL) {
/* print message on a fresh line */
xlfreshline(getvalue(s_debugio));
sprintf(buf,"[ gc: total %ld, ",nnodes);
dbgputstr(buf); /* TAA MOD -- was std output */
}
#ifdef NULLPTRDEBUG
hit_null_pointer = FALSE;
#endif /* NULLPTRDEBUG */
/* reset the current segment pointers */
curseg = lastpermseg->sg_next;
curtop = curbase = &curseg->sg_nodes[0];
/* make tenured space into new space for a full gc */
if (full_gc) {
/* change the old node code */
old_code = (old_code == 1) ? 0 : 1;
/* mark NIL and the fixed segments as old */
set_old_node(NIL);
set_to_new_node(NIL);
for (sg = segs; sg != NULL; sg = sg->sg_next) {
int n;
for (tmp = &sg->sg_nodes[0], n = sg->sg_size; --n >= 0; tmp++)
set_old_node(tmp);
if (sg == lastpermseg) break;
}
for (sg = lastpermseg->sg_next; sg != NULL; sg = sg->sg_next) {
register LVAL base;
int n;
/**** mark the list heads as old -- probably not necessary */
for (tmp = &sg->sg_nodes[0], n = NUM_OFFSETS; --n >= 0; tmp++)
set_old_node(tmp);
/* mark the nodes in the immediate and allocated lists as new; */
base = &sg->sg_nodes[0] + IMMEDIATE_OFFSET;
for (tmp = NEXT_NODE(base); tmp != base; tmp = NEXT_NODE(tmp))
set_new_node(tmp);
base = &sg->sg_nodes[0] + ALLOCATED_OFFSET;
for (tmp = NEXT_NODE(base); tmp != base; tmp = NEXT_NODE(tmp))
set_new_node(tmp);
/* move the tenured and to new lists to the new lists */
base = &sg->sg_nodes[0];
MOVE_LIST(base + IMMEDIATE_TENURED_OFFSET, base + IMMEDIATE_OFFSET);
MOVE_LIST(base + IMMEDIATE_TO_NEW_OFFSET, base + IMMEDIATE_OFFSET);
MOVE_LIST(base + ALLOCATED_TENURED_OFFSET, base + ALLOCATED_OFFSET);
MOVE_LIST(base + ALLOCATED_TO_NEW_OFFSET, base + ALLOCATED_OFFSET);
}
ntenured = 0;
}
/* reset the forwarded node list */
forwarded_nodes = NIL;
/* forward the children of NIL */
forward_children(NIL);
/* forward the unbound marker */
if (s_unbound != NIL)
forward_node(s_unbound);
/* forward the obarray and the current environment */
if (obarray != NULL)
forward_node(obarray);
forward_node(xlenv);
forward_node(xlfenv);
forward_node(xldenv);
/* forward the evaluation stack */
for (p = xlstack; p < xlstktop; ++p)
forward_node(**p);
/* forward the argument stack */
for (ap = xlargstkbase; ap < xlsp; ++ap)
forward_node(*ap);
#ifdef MULVALS
/* forward the result array */
{
int i;
for (i = 0; i < xlnumresults; i++)
forward_node(xlresults[i]);
}
#endif /* MULVALS */
/* forward the children of tenured nodes pointing to new ones */
for (sg = lastpermseg->sg_next; sg != NULL; sg = sg->sg_next) {
register LVAL base;
base = &sg->sg_nodes[0] + IMMEDIATE_TO_NEW_OFFSET;
for (tmp = NEXT_NODE(base); tmp != base; tmp = NEXT_NODE(tmp))
forward_children(tmp);
base = &sg->sg_nodes[0] + ALLOCATED_TO_NEW_OFFSET;
for (tmp = NEXT_NODE(base); tmp != base; tmp = NEXT_NODE(tmp))
forward_children(tmp);
}
/* forward the children of forwarded nodes */
while ((tmp = forwarded_nodes) != NIL) {
forwarded_nodes = NEXT_NODE_PTR(tmp);
forward_children(tmp);
TENURE_NODE(tmp);
unset_to_new_node(tmp);
}
check_finalize();
if (finalize_registered != NIL || finalize_pending != NIL) {
forward_node(finalize_registered);
forward_node(finalize_pending);
while ((tmp = forwarded_nodes) != NIL) {
forwarded_nodes = NEXT_NODE_PTR(tmp);
forward_children(tmp);
TENURE_NODE(tmp);
unset_to_new_node(tmp);
}
}
check_weak_boxes();
/* clean out free allocated nodes */
for (sg = lastpermseg->sg_next; sg != NULL; sg = sg->sg_next) {
register LVAL ibase, abase;
ibase = &sg->sg_nodes[0];
abase = ibase + ALLOCATED_OFFSET;
for (tmp = NEXT_NODE(abase); tmp != abase; tmp = NEXT_NODE(tmp)) {
clean_free_allocated_node(tmp);
}
MOVE_LIST(abase, ibase);
}
/* adjust the threshold for allocations to trigger a gc */
adjust_alloc_threshold();
/* update the statistics */
nfree = nnodes - nperm - ntenured;
++gccalls;
if (! full_gc) minor_gccalls++;
#ifdef NULLPTRDEBUG
if (hit_null_pointer)
xlfail("GC hit a null pointer -- probably time to bail out");
#endif /* NULLPTRDEBUG */
/**** move gc cursor thing to before hook? */
if (! null(finalize_pending))
do_finalize();
/* call the *gc-hook* if necessary */
if (s_gchook != NULL && ((fun = getvalue(s_gchook)) != NIL) ) {
/* rebind hook function to NIL TAA MOD */
tmp = xldenv;
xldbind(s_gchook,NIL);
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(fun);
pusharg(cvfixnum((FIXTYPE)2));
pusharg(cvfixnum((FIXTYPE)nnodes));
pusharg(cvfixnum((FIXTYPE)nfree));
xlfp = newfp;
xlapply(2);
/* unbind the symbol TAA MOD */
xlunbind(tmp);
}
/* print the end of the gc message */
if (s_gcflag != NULL && getvalue(s_gcflag) != NIL) {
sprintf(buf,"%ld free ]\n",nfree);
dbgputstr(buf); /* TAA MOD -- was std output */
}
set_gc_cursor(FALSE); /* L. Tierney */
#ifdef TIMES
gctime += run_tick_count() - gccount;
#endif
}
/* addseg - add a segment to the available memory */
LOCAL int addseg(V)
{
SEGMENT *newseg;
/* allocate the new segment */
if (anodes == 0 || (newseg = newsegment(anodes)) == NULL)
return (FALSE);
adjust_alloc_threshold();
nfree += (long)anodes;
/* return successfully */
return (TRUE);
}
/* newsegment - create a new segment (only called here and in xlimage.c) */
SEGMENT *newsegment P1C(int, n)
{
SEGMENT *newseg;
LVAL p, base;
int m;
#ifdef MACINTOSH /* L. Tierney */
maximum_memory();
#endif /* MACINTOSH */
n += NUM_OFFSETS;
/* allocate the new segment */
if ((newseg = (SEGMENT *)CALLOC(1,segsize(n))) == NULL)
return (NULL);
/* initialize the new segment */
newseg->sg_size = n;
newseg->sg_next = NULL;
if (segs != NULL)
lastseg->sg_next = newseg;
else
segs = newseg;
lastseg = newseg;
/* initialize the list header nodes */
base = &newseg->sg_nodes[0];
for (p = base, m = NUM_OFFSETS; --m >= 0; ++p) {
set_old_node(p);
SET_NODE_BASE(p, base);
SET_NEXT_NODE(p, p);
SET_LAST_NODE(p, p);
}
/* add each new node to the segment's immediate free list */
for (p = base + NUM_OFFSETS, m = n - NUM_OFFSETS; --m >= 0; ++p) {
setntype(p, FREE);
set_new_node(p);
unset_to_new_node(p);
SET_NODE_BASE(p, base);
LINK_NODE(p, base);
}
/* update the statistics */
total += (long)segsize(n);
nnodes += (long)n;
++nsegs;
/* return the new segment */
return (newseg);
}
/* stats - print memory statistics */
LOCAL VOID stats(V)
{
long major_gccalls = gccalls - minor_gccalls;
sprintf(buf,"Nodes: %ld\n",nnodes); stdputstr(buf);
sprintf(buf,"Free nodes: %ld\n",nfree); stdputstr(buf);
sprintf(buf,"Segments: %d\n",nsegs); stdputstr(buf);
sprintf(buf,"Allocate: %d\n",anodes); stdputstr(buf);
sprintf(buf,"Total: %ld\n",total); stdputstr(buf);
sprintf(buf,"Major Collections: %ld\n",major_gccalls); stdputstr(buf);
sprintf(buf,"Minor Collections: %ld\n",minor_gccalls); stdputstr(buf);
/**** drop after debugging is done */
sprintf(buf,"Threshold crosses: %ld\n", threshold_crossing_gccount);
stdputstr(buf);
#ifdef TIMES
sprintf(buf,"Time (sec): %ld\n",gctime/ticks_per_second());
stdputstr(buf);
#endif
}
/* xgc - xlisp function to force garbage collection */
LVAL xgc(V)
{
/* make sure there aren't any arguments */
xllastarg();
/* garbage collect */
gc();
/* return nil */
return (NIL);
}
/* xexpand - xlisp function to force memory expansion */
LVAL xexpand(V)
{
LVAL num;
FIXTYPE n,i;
/* get the new number to allocate */
if (moreargs()) {
num = xlgafixnum();
n = getfixnum(num);
/* make sure there aren't any more arguments */
xllastarg();
}
else
n = 1;
/* allocate more segments */
for (i = 0; i < n; i++)
if (!addseg())
break;
/* return the number of segments added */
return (cvfixnum((FIXTYPE)i));
}
/* xalloc - xlisp function to set the number of nodes to allocate */
LVAL xalloc(V)
{
FIXTYPE n; /* TAA MOD -- prevent overflow */
int oldn;
#ifdef DEBUG
/**** drop after debugging is done */
if (symbolp(peekarg(0))) {
LVAL arg;
if (xlgetkeyarg(xlenter(":GC-EXPAND-FRACTION"), &arg)) {
if (floatp(arg)) {
gc_expand_frac = getflonum(arg);
return(arg);
}
}
if (xlgetkeyarg(xlenter(":FULL-GC-FRACTION"), &arg)) {
if (floatp(arg)) {
full_gc_frac = getflonum(arg);
return(arg);
}
}
return(NIL);
}
#endif /* DEBUG */
/* get the new number to allocate */
n = getfixnum(xlgafixnum());
/* make sure there aren't any more arguments */
if (xlargc > 1) xltoomany(); /* but one more is OK, TAA MOD */
/* set the new number of nodes to allocate */
if (n > MAX_ANODES || n < MIN_ANODES)
xlfail("alloc out of range");
oldn = anodes;
anodes = (int)n;
/* return the old number */
return (cvfixnum((FIXTYPE)oldn));
}
/* xmem - xlisp function to print memory statistics */
LVAL xmem(V)
{
/* allow one argument for compatiblity with common lisp */
if (xlargc > 1) xltoomany(); /* TAA Mod */
/* print the statistics */
stats();
/* return nil */
return (NIL);
}
#ifdef SAVERESTORE
/* xsave - save the memory image */
LVAL xsave(V)
{
char *name;
/* get the file name */
name = getstring(xlgetfname());
xllastarg();
/* save the memory image */
return (xlisave(name) ? s_true : NIL);
}
/* xrestore - restore a saved memory image */
LVAL xrestore(V)
{
#ifdef XLISP_STAT
xlfail("restore not available");
return(NIL); /* never returns */
#else
extern XL_JMP_BUF top_level;
char *name;
/* get the file name */
name = getstring(xlgetfname());
xllastarg();
/* restore the saved memory image */
if (!xlirestore(name))
return (NIL);
/* return directly to the top level */
dbgputstr("[ returning to the top level ]\n"); /* TAA MOD --was std out*/
XL_LONGJMP(top_level,1);
return (NIL); /* never executed, but avoids warning message */
#endif /* XLISP_STAT */
}
VOID sweep_free_nodes(V)
{
SEGMENT *sg;
LVAL p;
int n;
/**** use free list = immediate list */
for (sg = segs->sg_next; sg != NULL; sg = sg->sg_next) {
p = &sg->sg_nodes[0] + NUM_OFFSETS;
for (n = sg->sg_size - NUM_OFFSETS; --n >= 0; ++p)
if (! is_old_node(p))
setntype(p, FREE);
}
}
VOID initialize_node P1C(LVAL, node)
{
/* set gc flags */
set_old_node(node); /*** new??? */
unset_to_new_node(node);
/* move allocated node from immediate list to allocated list */
if (node_is_allocated(node))
MOVE_NODE_TO_BASE(node, ALLOCATED_OFFSET);
}
#endif /* SAVERESTORE */
/* From XLISP-STAT, Copyright (c) 1988 Luke Tierney */
LVAL newicomplex P2C(FIXTYPE, real, FIXTYPE, imag)
{
LVAL val, r, i;
if (imag == 0) val = cvfixnum(real);
else {
xlstkcheck(2);
xlsave(r);
xlsave(i);
r = cvfixnum(real);
i = cvfixnum(imag);
val = cons(r, i);
setntype(val, COMPLEX);
xlpopn(2);
}
return(val);
}
LVAL newdcomplex P2C(double, real, double, imag)
{
LVAL val, r, i;
xlstkcheck(2);
xlsave(r);
xlsave(i);
r = cvflonum((FLOTYPE) real);
i = cvflonum((FLOTYPE) imag);
val = cons(r, i);
setntype(val, COMPLEX);
xlpopn(2);
return(val);
}
#ifdef BIGNUMS
/* newcomplex - allocate and initialize a new object */
LVAL newcomplex P2C(LVAL, real, LVAL, imag)
{
LVAL val;
xlstkcheck(2);
xlprotect(real);
xlprotect(imag);
if (! rationalp(real) || ! rationalp(imag)) {
if (! floatp(real)) real = cvflonum(makefloat(real));
if (! floatp(imag)) imag = cvflonum(makefloat(imag));
}
if (fixp(imag) && getfixnum(imag) == 0)
val = real;
else {
val = newnode(COMPLEX);
getreal(val) = real;
getimag(val) = imag;
}
xlpopn(2);
return(val);
}
#else
/* newcomplex - allocate and initialize a new object */
LVAL newcomplex P2C(LVAL, real, LVAL, imag)
{
if (fixp(real) && fixp(imag))
return(newicomplex(getfixnum(real), getfixnum(imag)));
else
return(newdcomplex(makefloat(real), makefloat(imag)));
}
#endif
#else
/* node flags */
#define MARK 0x40
#define LEFT 0x80
#define node_marked(n) ((ntype(n) & MARK))
#define unmark_node(n) (ntype(n) &= ~MARK)
#define mark_node(n) (ntype(n) |= MARK)
#define mark_and_type(n) (mark_node(n) & TYPEFIELD)
#define unmarked_array_node(n) ((ntype(n) & (ARRAY|MARK)) == ARRAY)
#define came_from_left(n) (ntype(n) & LEFT)
#define set_left(n) (ntype(n) |= LEFT)
#define unset_left(n) (ntype(n) &= ~LEFT)
#define is_array_type(x) (((x) & ARRAY) != 0)
#define gcntype(n) (ntype(n)&TYPEFIELD)
/* expansion parameters */
#define ALLOC_THRESHOLD_INCREMENT 0x20000L
#define GC_EXPAND_FRAC 0.2
/* macro to compute the size of a segment */
#define segsize(n) (sizeof(SEGMENT)+((n)-1)*sizeof(struct node))
#ifdef TIMES
static unsigned long gctime; /* calcuate time in garbage collector */
#endif
/* macros to convert between size in bytes and vector size */
#define btow_size(n) (((unsigned)(n)+(sizeof(LVAL)-1))/(unsigned)sizeof(LVAL))
#define wtob_size(n) (((long) (n)) * sizeof(LVAL))
/* variables local to xldmem.c and xlimage.c */
SEGMENT *segs,*lastseg,*fixseg,*charseg;
int anodes,nsegs;
LVAL fnodes = NIL;
/* local variables */
static long alloc_threshold,threshold_crossing_gccount;
static double gc_expand_frac = GC_EXPAND_FRAC;
/* forward declarations */
#ifdef JMAC
LOCAL LVAL Newnode P1H(int);
#else
LOCAL LVAL newnode P1H(int);
#endif
LOCAL LVAL allocvector P2H(int, unsigned);
LOCAL VOID mark P1H(LVAL);
LOCAL VOID sweep(V);
LOCAL int addseg(V);
LOCAL VOID stats(V);
LOCAL VOID check_alloc_threshold P1H(long);
LOCAL VOID adjust_alloc_threshold(V);
LOCAL VOID expand_node_space(V);
LOCAL VOID morevmem P1H(int);
LOCAL char *IViewNewAData P4H(int, int, long *, int);
#ifdef JMAC
LVAL _nnode = NIL;
FIXTYPE _tfixed = 0;
int _tint = 0;
#define newnode(type) (((_nnode = fnodes) != NIL) ? \
((fnodes = cdr(_nnode)), \
nfree--, \
(_nnode->n_type = type), \
rplacd(_nnode,NIL), \
_nnode) \
: Newnode(type))
#endif
/* $putpatch.c$: "MODULE_XLDMEM_C_GLOBALS" */
/* xlminit - initialize the dynamic memory module */
VOID xlminit(V)
{
LVAL p;
int i;
/* initialize our internal variables */
segs = lastseg = NULL;
nnodes = nfree = total = gccalls = 0L;
alloc_threshold = ALLOC_THRESHOLD_INCREMENT;
threshold_crossing_gccount = 0L;
nsegs = 0;
anodes = NNODES;
gctime = 0L;
fnodes = NIL;
/* allocate the fixnum segment */
if ((fixseg = newsegment(SFIXSIZE)) == NULL)
xlfatal("insufficient memory");
/* initialize the fixnum segment */
p = &fixseg->sg_nodes[0];
for (i = SFIXMIN; i <= SFIXMAX; ++i) {
setntype(p, FIXNUM);
p->n_fixnum = i;
++p;
}
/* allocate the character segment */
if ((charseg = newsegment(CHARSIZE)) == NULL)
xlfatal("insufficient memory");
/* initialize the character segment */
p = &charseg->sg_nodes[0];
for (i = CHARMIN; i <= CHARMAX; ++i) {
setntype(p, CHAR);
p->n_chcode = i;
++p;
}
/* initialize structures that are marked by the collector */
obarray = NULL;
xlenv = xlfenv = xldenv = NIL;
s_gcflag = s_gchook = NULL;
/* $putpatch.c$: "MODULE_XLDMEM_C_XLMINIT" */
/* allocate the evaluation stack */
if ((xlstkbase = (LVAL **)malloc(EDEPTH * sizeof(LVAL *))) == NULL)
xlfatal("insufficient memory");
xlstack = xlstktop = xlstkbase + EDEPTH;
/* allocate the argument stack */
if ((xlargstkbase = (LVAL *)malloc(ADEPTH * sizeof(LVAL))) == NULL)
xlfatal("insufficient memory");
xlargstktop = xlargstkbase + ADEPTH;
xlfp = xlsp = xlargstkbase;
*xlsp++ = NIL;
#ifdef MULVALS
/* allocate the result array */
if ((xlresults = (LVAL *)malloc(MULVALLIMIT * sizeof(LVAL))) == NULL)
xlfatal("insufficient memory");
for (i = 0; i < MULVALLIMIT; i++)
xlresults[i] = NIL;
xlnumresults = 0;
#endif /* MULVALS */
/* we have to make a NIL symbol before continuing */
p = xlmakesym("NIL");
MEMCPY(NIL, p, sizeof(struct node)); /* we point to this! */
defconstant(NIL, NIL);
setfunction(NIL, NIL);
setntype(p, FREE); /* don't collect "garbage" */
finalize_registered = NIL;
finalize_pending = NIL;
}
/* cons - construct a new cons node */
LVAL cons P2C(LVAL, x, LVAL, y)
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
xlstkcheck(2);
xlprotect(x);
xlprotect(y);
nnode = newnode(CONS);
xlpopn(2);
}
else {
fnodes = cdr(fnodes);
setntype(nnode, CONS);
nfree--;
}
/* initialize the new node */
rplaca(nnode,x);
rplacd(nnode,y);
/* return the new node */
return (nnode);
}
/* cvstring - convert a string to a string node */
LVAL cvstring P1C(char *, str)
{
LVAL val;
val = newstring(STRLEN(str));
STRCPY(getstring(val),str);
return (val);
}
/* newstring - allocate and initialize a new string */
LVAL newstring P1C(unsigned, size)
{
LVAL val;
val = allocvector(STRING,btow_size(size+1));
val->n_strlen = size;
return (val);
}
#ifdef BIGNUMS
/* newbignum - allocate a new bignum */
LVAL newbignum P1C(unsigned, size)
{
/* size of the sign field not included in n_vsize */
BIGNUMDATA *x;
LVAL val;
xlsave1(val);
val = allocvector(BIGNUM,btow_size((size+1)*sizeof(BIGNUMDATA)));
val->n_bsize = size;
x = getbignumarray(val);
size++;
while (size--) *x++ = 0; /* set value to zero */
xlpop();
return val;
}
#endif
/* cvsymbol - convert a string to a symbol */
LVAL cvsymbol P1C(char *, pname)
{
LVAL val;
xlsave1(val);
val = allocvector(SYMBOL,SYMSIZE);
setvalue(val,s_unbound);
setfunction(val,s_unbound);
setpname(val,cvstring(pname));
setsnormal(val); /* L. Tierney */
xlpop();
return (val);
}
/* cvsubr - convert a function to a subr or fsubr */
LVAL cvsubr P3C(subrfun, fcn, int, type, int, offset)
{
LVAL val;
val = newnode(type);
val->n_subr = fcn;
val->n_offset = offset;
return (val);
}
/* cvfile - convert a file pointer to a stream */
LVAL cvfile P2C(FILEP, fp, int, iomode)
{
LVAL val;
val = newnode(STREAM);
setfile(val,fp);
setsavech(val,'\0');
val->n_sflags = iomode;
val->n_cpos = 0;
return (val);
}
#ifdef JMAC
/* cvfixnum - convert an integer to a fixnum node */
LVAL Cvfixnum P1C(FIXTYPE, n)
{
LVAL val;
val = newnode(FIXNUM);
val->n_fixnum = n;
return (val);
}
#else
/* cvfixnum - convert an integer to a fixnum node */
LVAL cvfixnum P1C(FIXTYPE, n)
{
LVAL val;
if (n >= SFIXMIN && n <= SFIXMAX)
return (&fixseg->sg_nodes[(int)n-SFIXMIN]);
if ((val = fnodes) == NIL) {
val = newnode(FIXNUM);
}
else {
fnodes = cdr(fnodes);
setntype(val, FIXNUM);
nfree--;
}
val->n_fixnum = n;
return (val);
}
#endif
/* cvflonum - convert a floating point number to a flonum node */
LVAL cvflonum P1C(FLOTYPE, n)
{
LVAL val;
if ((val = fnodes) == NIL) {
val = newnode(FLONUM);
}
else {
fnodes = cdr(fnodes);
setntype(val, FLONUM);
nfree--;
}
val->n_flonum = n;
return (val);
}
/* cvchar - convert an integer to a character node */
#ifdef JMAC
LVAL Cvchar P1C(int, n)
{
xlerror("character code out of range",cvfixnum((FIXTYPE)n));
return(NIL); /* never executed */
}
#else
LVAL cvchar P1C(int, n)
{
if (n >= CHARMIN && n <= CHARMAX)
return (&charseg->sg_nodes[n-CHARMIN]);
xlerror("character code out of range",cvfixnum((FIXTYPE)n));
return NIL; /* never executed but gets rid of warning message */
}
#endif
#ifdef BIGNUMS
/* cvbratio - convert a pair of bignums into a ratio node */
LVAL cvbratio P2C(LVAL, num, LVAL, denom)
{
FIXTYPE nu, d;
int fixtyped;
LVAL n,m,r;
if (cvtbigfixnum(num, &nu) && cvtbigfixnum(denom, &d))
return cvratio(nu,d);
xlstkcheck(5);
xlprotect(num);
xlprotect(denom);
xlsave(n);
xlsave(m);
xlsave(r);
if (zeropbignum(num)) { /* zero is fixnum zero */
xlpopn(5);
return cvfixnum((FIXTYPE) 0);
}
if (getbignumsign(denom)) { /* denominator must be positive */
denom = copybignum(denom, 0);
num = copybignum(num,!getbignumsign(num)); /* final sign */
}
n = copybignum(num, 0); /* abs of numerator */
m = denom;
for (;;) { /* get gcd */
divbignum(m, n, &r); /* use remainder only */
if (zeropbignum(r)) break;
m = n;
n = r;
}
if ((!cvtbigfixnum(n, &d)) || d != 1) { /* can reduce */
denom = divbignum(denom, n, &r);
num = divbignum(num, n, &r);
}
if ((fixtyped = cvtbigfixnum(denom, &d)) != 0 && d == 1) {
/* reduced to an integer */
xlpopn(5);
if (cvtbigfixnum(num, &nu)) return cvfixnum(nu);
return num;
}
/* got value to return */
r = newnode(RATIO);
r->n_cdr = r->n_car = NIL; /* in case of garbage collect */
r->n_cdr = (fixtyped ? cvfixnum(d) : denom);
r->n_car = (cvtbigfixnum(num, &nu) ? cvfixnum(nu) : num);
xlpopn(5);
return (r);
}
/* cvratio - convert an integer pair to a ratio node */
LVAL cvratio P2C(FIXTYPE, num, FIXTYPE, denom)
{
LVAL val;
unsigned long n, m, r, nu, de;
int sign;
if (num == 0) return cvfixnum((FIXTYPE) 0); /* zero is int zero */
if (denom < 0) { /* denominator must be positive */
if (denom == -1 && num == MINFIX) {
xlsave1(val);
val = cvtulongbignum((unsigned long)MAXFIX+1, FALSE);
xlpop();
return val;
}
denom = -denom;
sign = num >= 0;
}
else
sign = num < 0;
if (num < 0) num = -num;
n = nu = (unsigned long)(long)num;
m = de = (unsigned long)(long)denom; /* reduce the ratio: compute GCD */
for (;;) {
if ((r = m % n) == 0) break;
m = n;
n = r;
}
if (n != 1) {
de /= n;
nu /= n;
}
if (de == 1)
return cvfixnum(sign ? -(long)nu : (long)nu); /* reduced to integer */
xlsave1(val);
val = newnode(RATIO);
val->n_cdr = val->n_car = NIL; /* in case of garbage collect */
if ((nu == (unsigned long)MAXFIX+1 && sign==0))
val->n_car = cvtulongbignum(nu, sign);
else
val->n_car = cvfixnum(sign ? -(long)nu : (long)nu);
if (de == (unsigned long)MAXFIX+1)
val->n_cdr = cvtulongbignum(de, FALSE);
else
val->n_cdr = cvfixnum(de);
xlpop();
return (val);
}
#endif
/* newustream - create a new unnamed stream */
LVAL newustream(V)
{
LVAL val;
val = newnode(USTREAM);
sethead(val,NIL);
settail(val,NIL);
return (val);
}
/* newobject - allocate and initialize a new object */
LVAL newobject P2C(LVAL, cls, int, size)
{
LVAL val;
val = allocvector(OBJECT,size+1);
setelement(val,0,cls);
return (val);
}
/* newclosure - allocate and initialize a new closure */
LVAL newclosure P4C(LVAL, name, LVAL, type, LVAL, env, LVAL, fenv)
{
LVAL val;
val = allocvector(CLOSURE,CLOSIZE);
setname(val,name);
settype(val,type);
setenvi(val,env);
setfenv(val,fenv);
return (val);
}
/* newstruct - allocate and initialize a new structure node */
LVAL newstruct P2C(LVAL, type, int, size)
{
LVAL val;
val = allocvector(STRUCT,size+1);
setelement(val,0,type);
return (val);
}
#ifdef BYTECODE
/* newcpsnode - allocate and initialize a new CPS node for compiler */
LVAL newcpsnode P1C(LVAL, type)
{
LVAL val;
val = allocvector(CPSNODE,CPSNODESIZE);
setcpstype(val,type);
return (val);
}
/* newbcode - allocate and initialize a new byte code vector */
LVAL newbcode P5C(LVAL, code, LVAL, jtab, LVAL, lits, LVAL, idx, LVAL, env)
{
LVAL val;
val = allocvector(BCODE,BCODESIZE);
setbccode(val, code);
setbcjtab(val, jtab);
setbclits(val, lits);
setbcidx(val, idx);
setbcenv(val, env);
return (val);
}
#endif /* BYTECODE */
#ifdef PACKAGES
/* newpackage - allocate and initialize a new package */
LVAL newpackage(V)
{
LVAL val;
xlsave1(val);
val = allocvector(PACKAGE,PACKSIZE);
setintsyms(val, newvector(HSIZE));
setextsyms(val, newvector(HSIZE));
xlpop();
return (val);
}
#endif /* PACKAGES */
/* newvector - allocate and initialize a new vector node */
LVAL newvector P1C(unsigned, size)
{
return(allocvector(VECTOR,size));
}
/* allocvector - allocate and initialize a new vector node */
LOCAL LVAL allocvector P2C(int, type, unsigned, size)
{
LVAL vect, *p;
int i;
unsigned long bsize; /* changed to unsigned long - L. Tierney */
xlsave1(vect);
vect = newnode(type);
vect->n_vsize = 0;
if (size != 0) {
bsize = wtob_size(size);
check_alloc_threshold(bsize);
if ((vect->n_vdata = (LVAL *)VALLOC(size)) == NULL) {
gc();
if ((vect->n_vdata = (LVAL *)VALLOC(size)) == NULL)
xlabort("insufficient vector space");
}
vect->n_vsize = size;
total += bsize;
}
/* set all the elements to NIL, except for STRINGs and TVECs */
if (type != STRING && type != TVEC)
for (i = 0, p = vect->n_vdata; i < size; i++)
*p++ = NIL;
xlpop();
return (vect);
}
#ifdef XLISP_STAT
/* Added for internal allocated storage - L. Tierney */
#include "xlstat.h"
LOCAL char *IViewNewAData P4C(int, n, int, m, long *, size, int, reloc)
{
char *addr;
addr = (reloc) ? StRCalloc(n, m): StCalloc(n, m);
*size = (reloc) ? StRSize(addr) : ((long) m) * ((long) n);
return(addr);
}
/* newadata(n, m, reloc) - convert a string to a string node */
LVAL newadata P3C(int, n, int, m, int, reloc)
{
LVAL val;
long size;
/*if (reloc) xlfail("relocatable allocated data not supported");*/
size = ((long) m) * ((long) n);
check_alloc_threshold(size);
xlsave1(val);
val = newnode(ADATA);
setadreloc(val, reloc);
/**** check what happens when asked for zero length */
if ((val->n_adaddr = IViewNewAData(n, m, &size, reloc)) == NULL) {
gc();
if ((val->n_adaddr = IViewNewAData(n, m, &size, reloc)) == NULL)
xlabort("insufficient memory");
}
val->n_adsize = size;
total += size;
xlpop();
return (val);
}
VOID reallocaddata P3C(LVAL, val, int, n, int, m)
{
char *addr;
check_alloc_threshold(((long) n) * ((long) m)); /**** overestimate */
if (! adatap(val) || ! getadreloc(val)) xlfail("not relocatable");
addr = StRRealloc(getadaddr(val), n, m);
if (addr == NULL) xlabort("allocation failed");
val->n_adaddr = addr;
total -= getadsize(val);
val->n_adsize = StRSize(addr);
total += getadsize(val);
}
VOID freeadata P1C(LVAL, val)
{
if (! adatap(val)) xlfail("not a data object");
if (getadreloc(val)) StRFree(getadaddr(val));
else StFree(getadaddr(val));
val->n_adaddr = NULL;
total -= getadsize(val);
val->n_adsize = 0;
adjust_alloc_threshold();
}
/* Added for internal allocated storage - L. Tierney */
#endif /* XLISP_STAT */
/* newnode - allocate a new node */
#ifdef JMAC
LOCAL LVAL Newnode P1C(int, type)
{
LVAL nnode;
/* get a free node */
gc();
expand_node_space();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
/* unlink the node from the free list */
fnodes = cdr(nnode);
nfree -= 1L;
/* initialize the new node */
nnode->n_type = type;
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
#else
LOCAL LVAL newnode P1C(int, type)
{
LVAL nnode;
/* get a free node */
if ((nnode = fnodes) == NIL) {
gc();
expand_node_space();
if ((nnode = fnodes) == NIL)
xlabort("insufficient node space");
}
/* unlink the node from the free list */
fnodes = cdr(nnode);
nfree -= 1L;
/* initialize the new node */
setntype(nnode, type);
rplacd(nnode,NIL);
/* return the new node */
return (nnode);
}
#endif
/* gc - garbage collect (only called here and in xlimage.c) */
VOID gc(V)
{
LVAL **p,*ap,tmp;
FRAMEP newfp;
LVAL fun;
#ifdef TIMES
unsigned long gccount = run_tick_count();
#endif
#ifdef STSZ
#if (GCSTMARGIN>0)
if (STACKREPORT(fun)<GCSTMARGIN) { /* Do not try gc with less */
dbgputstr("Insufficient stack left for GC ");
if (batchmode) xlfatal("uncaught error");
xltoplevel(TRUE);
}
#endif
#endif
set_gc_cursor(TRUE); /* L. Tierney */
/* print the start of the gc message */
if (s_gcflag != NULL && getvalue(s_gcflag) != NIL) {
/* print message on a fresh line */
xlfreshline(getvalue(s_debugio));
sprintf(buf,"[ gc: total %ld, ",nnodes);
dbgputstr(buf); /* TAA MOD -- was std output */
}
/* $putpatch.c$: "MODULE_XLDMEM_C_GC" */
/* mark the obarray, the argument list and the current environment */
if (obarray != NULL)
mark(obarray);
if (xlenv != NIL)
mark(xlenv);
if (xlfenv != NIL)
mark(xlfenv);
if (xldenv != NIL)
mark(xldenv);
mark(NIL);
mark(s_unbound); /* TAA Mod 1/92 */
/* mark the evaluation stack */
for (p = xlstack; p < xlstktop; ++p)
if ((tmp = **p) != NIL)
mark(tmp);
/* mark the argument stack */
for (ap = xlargstkbase; ap < xlsp; ++ap)
if ((tmp = *ap) != NIL)
mark(tmp);
#ifdef MULVALS
/* mark the results */
{
int i;
for (i = 0; i < xlnumresults; i++)
if ((tmp = xlresults[i]) != NIL)
mark(tmp);
}
#endif /* MULVALS */
/* sweep memory collecting all unmarked nodes */
sweep();
unmark_node(NIL);
adjust_alloc_threshold();
/* count the gc call */
++gccalls;
/* call the *gc-hook* if necessary */
if (s_gchook != NULL && ((fun = getvalue(s_gchook)) != NIL) ) {
/* rebind hook function to NIL TAA MOD */
tmp = xldenv;
xldbind(s_gchook,NIL);
newfp = xlsp;
pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
pusharg(fun);
pusharg(cvfixnum((FIXTYPE)2));
pusharg(cvfixnum((FIXTYPE)nnodes));
pusharg(cvfixnum((FIXTYPE)nfree));
xlfp = newfp;
xlapply(2);
/* unbind the symbol TAA MOD */
xlunbind(tmp);
}
/* print the end of the gc message */
if (s_gcflag != NULL && getvalue(s_gcflag) != NIL) {
sprintf(buf,"%ld free ]\n",nfree);
dbgputstr(buf); /* TAA MOD -- was std output */
}
set_gc_cursor(FALSE); /* L. Tierney */
#ifdef TIMES
gctime += run_tick_count() - gccount;
#endif
}
/* mark - mark all accessible nodes */
LOCAL VOID mark P1C(LVAL, ptr)
{
register LVAL this,prev,tmp;
int type,i,n;
#ifdef STSZ /* can't recover from here */
#if (GCSTMARGIN>0)
if (STACKREPORT(n) < GCMARGLO)
xlfatal("Insufficient stack during GC");
#endif
#endif
/* initialize */
prev = NIL;
this = ptr;
/* mark this list */
for (;;) {
/* descend as far as we can */
while (! node_marked(this)) {
type = mark_and_type(this);
/* check cons type nodes */
if (type >= CONS && type < ARRAY) {
if ((tmp = car(this)) != NIL) {
set_left(this);
rplaca(this,prev);
}
else if ((tmp = cdr(this)) != NIL)
rplacd(this,prev);
else /* both sides nil */
break;
prev = this; /* step down the branch */
this = tmp;
}
/* $putpatch.c$: "MODULE_XLDMEM_C_MARK" */
else if (is_array_type(type)) {
for (i = 0, n = getsize(this); i < n; i++)
if ((tmp = getelement(this,i)) != NIL)
mark(tmp);
break;
}
else if (type == NATPTR) {
mark(cdr(this));
break;
}
else
break;
}
/* backup to a point where we can continue descending */
for (;;) {
/* make sure there is a previous node */
if (prev != NIL) {
if (came_from_left(prev)) { /* came from left side */
unset_left(prev);
tmp = car(prev);
rplaca(prev,this);
if ((this = cdr(prev)) != NIL) {
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;
}
}
}
/* sweep - sweep all unmarked nodes and add them to the free list */
LOCAL VOID sweep(V)
{
SEGMENT *seg;
LVAL p;
int n;
/* empty the free list */
fnodes = NIL;
nfree = 0L;
/* add all unmarked nodes */
for (seg = segs; seg != NULL; seg = seg->sg_next) {
if (seg == fixseg || seg == charseg) {
/* remove marks from segments */
p = &seg->sg_nodes[0];
for (n = seg->sg_size; --n >= 0;)
unmark_node(p++);
continue;
}
p = &seg->sg_nodes[0];
for (n = seg->sg_size; --n >= 0; p++)
if (node_marked(p))
unmark_node(p);
else {
switch (gcntype(p)) {
case STRING:
case TVEC:
if (getstring(p) != NULL) {
long size = btow_size(getslength(p) + 1);
total -= size * sizeof(LVAL);
VRELEASE(getstring(p), size);
}
break;
#ifdef BIGNUMS
case BIGNUM:
if (getbignumarray(p) != NULL) {
long size = btow_size((1+(long)getbignumsize(p))
*sizeof(BIGNUMDATA));
total -= size * sizeof(LVAL);
VRELEASE(getstring(p), size);
}
break;
#endif
#ifdef XLISP_STAT
case ADATA:
if (getadaddr(p) != NULL) {
total -= getadsize(p);
if (getadreloc(p)) StRFree(getadaddr(p));
else StFree(getadaddr(p));
}
break;
#endif /* XLISP_STAT */
case STREAM:
if (getfile(p) != CLOSED
&& getfile(p) != STDIN
&& getfile(p) != STDOUT
&& getfile(p) != CONSOLE)/* taa fix - dont close stdio */
OSCLOSE(getfile(p));
break;
/* $putpatch.c$: "MODULE_XLDMEM_C_SWEEP" */
case SYMBOL:
case OBJECT:
case VECTOR:
case CLOSURE:
case STRUCT:
#ifdef BYTECODE
case CPSNODE:
case BCODE:
#endif /*BYTECODE */
#ifdef PACKAGES
case PACKAGE:
#endif /* PACKAGES */
if (p->n_vsize) {
total -= wtob_size(p->n_vsize);
VRELEASE((char *) p->n_vdata, p->n_vsize);
}
break;
}
setntype(p, FREE);
rplaca(p,NIL);
rplacd(p,fnodes);
fnodes = p;
nfree++;
}
}
}
/* addseg - add a segment to the available memory */
LOCAL int addseg(V)
{
SEGMENT *newseg;
LVAL p;
int n;
/* allocate the new segment */
if (anodes == 0 || (newseg = newsegment(anodes)) == NULL)
return (FALSE);
adjust_alloc_threshold();
/* add each new node to the free list */
p = &newseg->sg_nodes[0];
for (n = anodes; --n >= 0; ++p) {
rplacd(p,fnodes);
fnodes = p;
}
nfree += (long)anodes;
/* return successfully */
return (TRUE);
}
/* newsegment - create a new segment (only called here and in xlimage.c) */
SEGMENT *newsegment P1C(int, n)
{
SEGMENT *newseg;
#ifdef MACINTOSH /* L. Tierney */
maximum_memory();
#endif /* MACINTOSH */
/* allocate the new segment */
if ((newseg = (SEGMENT *)CALLOC(1,segsize(n))) == NULL)
return (NULL);
/* initialize the new segment */
newseg->sg_size = n;
newseg->sg_next = NULL;
if (segs != NULL)
lastseg->sg_next = newseg;
else
segs = newseg;
lastseg = newseg;
/* update the statistics */
total += (long)segsize(n);
nnodes += (long)n;
++nsegs;
/* return the new segment */
return (newseg);
}
/* stats - print memory statistics */
LOCAL VOID stats(V)
{
sprintf(buf,"Nodes: %ld\n",nnodes); stdputstr(buf);
sprintf(buf,"Free nodes: %ld\n",nfree); stdputstr(buf);
sprintf(buf,"Segments: %d\n",nsegs); stdputstr(buf);
sprintf(buf,"Allocate: %d\n",anodes); stdputstr(buf);
sprintf(buf,"Total: %ld\n",total); stdputstr(buf);
sprintf(buf,"Collections: %ld\n",gccalls); stdputstr(buf);
/**** drop after debugging is done */
sprintf(buf,"Threshold crosses: %ld\n", threshold_crossing_gccount);
stdputstr(buf);
#ifdef TIMES
sprintf(buf,"Time (sec): %ld\n",gctime/ticks_per_second());
stdputstr(buf);
#endif
}
/* xgc - xlisp function to force garbage collection */
LVAL xgc(V)
{
/* make sure there aren't any arguments */
xllastarg();
/* garbage collect */
gc();
/* return nil */
return (NIL);
}
/* xexpand - xlisp function to force memory expansion */
LVAL xexpand(V)
{
LVAL num;
FIXTYPE n,i;
/* get the new number to allocate */
if (moreargs()) {
num = xlgafixnum();
n = getfixnum(num);
/* make sure there aren't any more arguments */
xllastarg();
}
else
n = 1;
/* allocate more segments */
for (i = 0; i < n; i++)
if (!addseg())
break;
/* return the number of segments added */
return (cvfixnum((FIXTYPE)i));
}
/* xalloc - xlisp function to set the number of nodes to allocate */
LVAL xalloc(V)
{
FIXTYPE n; /* TAA MOD -- prevent overflow */
int oldn;
#ifdef DEBUG
/**** drop after debugging is done */
if (symbolp(peekarg(0))) {
LVAL arg;
if (xlgetkeyarg(xlenter(":GC-EXPAND-FRACTION"), &arg)) {
if (floatp(arg)) {
gc_expand_frac = getflonum(arg);
return(arg);
}
}
return(NIL);
}
#endif /* DEBUG */
/* get the new number to allocate */
n = getfixnum(xlgafixnum());
/* make sure there aren't any more arguments */
if (xlargc > 1) xltoomany(); /* but one more is OK, TAA MOD */
#ifdef DODO
/**** put something like this in after debugging */
/**** also need to be able to expand up to some level, */
/**** adjust expansion parameters */
/* Place limits on argument by clipping to reasonable values TAA MOD */
if (n > ((long)MAXSLEN - sizeof(SEGMENT))/sizeof(struct node))
n = ((long)MAXSLEN - sizeof(SEGMENT))/sizeof(struct node);
else if (n < 1000)
n = 1000; /* arbitrary */
#endif /* DODO */
/* set the new number of nodes to allocate */
oldn = anodes;
anodes = (int)n;
/* return the old number */
return (cvfixnum((FIXTYPE)oldn));
}
/* xmem - xlisp function to print memory statistics */
LVAL xmem(V)
{
/* allow one argument for compatiblity with common lisp */
if (xlargc > 1) xltoomany(); /* TAA Mod */
/* print the statistics */
stats();
/* return nil */
return (NIL);
}
#ifdef SAVERESTORE
/* xsave - save the memory image */
LVAL xsave(V)
{
char *name;
/* get the file name */
name = getstring(xlgetfname());
xllastarg();
/* save the memory image */
return (xlisave(name) ? s_true : NIL);
}
/* xrestore - restore a saved memory image */
LVAL xrestore(V)
{
#ifdef XLISP_STAT
xlfail("restore not available");
return(NIL); /* never returns */
#else
char *name;
/* get the file name */
name = getstring(xlgetfname());
xllastarg();
/* restore the saved memory image */
if (!xlirestore(name))
return (NIL);
/* return directly to the top level */
dbgputstr("[ returning to the top level ]\n"); /* TAA MOD --was std out*/
XL_LONGJMP(top_level,1);
return (NIL); /* never executed, but avoids warning message */
#endif /* XLISP_STAT */
}
#endif /* SAVERESTORE */
/* From XLISP-STAT, Copyright (c) 1988 Luke Tierney */
LVAL newicomplex P2C(FIXTYPE, real, FIXTYPE, imag)
{
LVAL val, r, i;
if (imag == 0) val = cvfixnum(real);
else {
xlstkcheck(2);
xlsave(r);
xlsave(i);
r = cvfixnum(real);
i = cvfixnum(imag);
val = cons(r, i);
setntype(val, COMPLEX);
xlpopn(2);
}
return(val);
}
LVAL newdcomplex P2C(double, real, double, imag)
{
LVAL val, r, i;
xlstkcheck(2);
xlsave(r);
xlsave(i);
r = cvflonum((FLOTYPE) real);
i = cvflonum((FLOTYPE) imag);
val = cons(r, i);
setntype(val, COMPLEX);
xlpopn(2);
return(val);
}
#ifdef BIGNUMS
/* newcomplex - allocate and initialize a new object */
LVAL newcomplex P2C(LVAL, real, LVAL, imag)
{
LVAL val;
xlstkcheck(2);
xlprotect(real);
xlprotect(imag);
if (! rationalp(real) || ! rationalp(imag)) {
if (! floatp(real)) real = cvflonum(makefloat(real));
if (! floatp(imag)) imag = cvflonum(makefloat(imag));
}
if (fixp(imag) && getfixnum(imag) == 0)
val = real;
else {
val = newnode(COMPLEX);
getreal(val) = real;
getimag(val) = imag;
}
xlpopn(2);
return(val);
}
#else
/* newcomplex - allocate and initialize a new object */
LVAL newcomplex P2C(LVAL, real, LVAL, imag)
{
if (fixp(real) && fixp(imag))
return(newicomplex(getfixnum(real), getfixnum(imag)));
else
return(newdcomplex(makefloat(real), makefloat(imag)));
}
#endif
#endif /* NEWGC */
#ifdef TIMES
/* gc_tick_count - total number of ticks spent in gc */
unsigned long gc_tick_count(V) { return(gctime); }
#endif
/* check_alloc_threshold - do gc if alloc would push total over threshold */
LOCAL VOID check_alloc_threshold P1C(long, size)
{
if (alloc_threshold < total + size) {
long tmp;
static int bumped = 0;
#ifdef NEWGC
tmp = (total + size + ALLOC_THRESHOLD_INCREMENT - 1);
tmp /= ALLOC_THRESHOLD_INCREMENT;
tmp *= ALLOC_THRESHOLD_INCREMENT;
alloc_threshold = tmp;
ggc(FALSE);
bumped++;
if (bumped > 4 || alloc_threshold < total + size) {
tmp = (total + size + ALLOC_THRESHOLD_INCREMENT - 1);
tmp /= ALLOC_THRESHOLD_INCREMENT;
tmp *= ALLOC_THRESHOLD_INCREMENT;
alloc_threshold = tmp;
ggc(TRUE);
bumped = 0;
}
#else
tmp = (total + size + ALLOC_THRESHOLD_INCREMENT - 1);
tmp /= ALLOC_THRESHOLD_INCREMENT;
tmp *= ALLOC_THRESHOLD_INCREMENT;
alloc_threshold = tmp;
gc();
#endif /* NEWGC */
threshold_crossing_gccount++;
}
}
/* adjust_alloc_threshold - adjust threshold up or down based on total */
LOCAL VOID adjust_alloc_threshold(V)
{
long n, m;
n = (total + ALLOC_THRESHOLD_INCREMENT - 1) / ALLOC_THRESHOLD_INCREMENT;
m = alloc_threshold / ALLOC_THRESHOLD_INCREMENT;
if (n > m) alloc_threshold = n * ALLOC_THRESHOLD_INCREMENT;
else if (m > n + 2) alloc_threshold = (n + 2) * ALLOC_THRESHOLD_INCREMENT;
}
/* expand_node_space allocate new nodes if necessary */
LOCAL VOID expand_node_space(V)
{
long needed;
/* find the number of additional nodes needed */
needed = (long) (gc_expand_frac * (nnodes - nfree)) + 1;
/* allocate additional segments if necessary */
if (anodes > 0)
while (needed > nfree)
if (! addseg())
break;
}
/**** This scheme assumes sizeof(void *) <= 8 */
/**** For the MS Windoes version, malloc should be tuned properly */
/**** Should be integrated properly with GC; use know sizes for symbol, etc. */
#define PAGEUNITS 9
#define MEMUNITS 10
static ALLOCTYPE *memarray[MEMUNITS] = { NULL };
/* morevmem - allocate another page of storage to nunits */
LOCAL VOID morevmem P1C(int, nunits)
{
ALLOCTYPE *p;
unsigned long nbytes, nalloc;
int n;
nalloc = (8 << ((nunits < PAGEUNITS) ? PAGEUNITS : nunits));
n = (nunits < PAGEUNITS) ? (1 << (PAGEUNITS - nunits)) : 1;
nbytes = (8 << nunits);
p = malloc(nalloc);
if (p == NULL) xlabort("insufficient vector space");
if (p != NULL) {
while (n-- > 0) {
*((char **) p) = memarray[nunits];
memarray[nunits] = p;
p = ((char *) p) + nbytes;
}
}
}
/* VALLOC - allocate space for a vector */
ALLOCTYPE *VALLOC P1C(unsigned long, size)
{
ALLOCTYPE *p;
unsigned long nbytes;
int nunits;
if (size > MAXVECLEN) xlfail("allocation too large"); /**** check this */
/* find number of bytes, rounded to next multiple of 8 */
nbytes = (size * sizeof(LVAL) + 7) & ~7;
/* find memory unit -- max(0, ceiling(log2(nbytes)) - 3) */
if (nbytes == 0) nunits = 0;
else {
register unsigned long shiftr = (nbytes - 1) >> 2;
nunits = 0;
while (shiftr >>= 1) nunits++;
}
if (nbytes == 0)
p = NULL;
else if (nunits < MEMUNITS) {
char **pt;
if (memarray[nunits] == NULL) morevmem(nunits);
pt = (char **) memarray[nunits];
if (pt != NULL) memarray[nunits] = pt[0];
p = (char *) pt;
}
else p = malloc(size * sizeof(LVAL));
if (p == NULL) xlabort("insufficient vector space");
MEMSET((char *) p, 0, wtob_size(size));
return(p);
}
/* VRELEASE - release space for a vector */
VOID VRELEASE P2C(ALLOCTYPE *, p, unsigned long, size)
{
unsigned long nbytes;
int nunits;
if (p != NULL) {
/* find number of bytes, rounded to next multiple of 8 */
nbytes = (size * sizeof(LVAL) + 7) & ~7;
/* find memory unit -- max(0, ceiling(log2(nbytes)) - 3) */
if (nbytes == 0) nunits = 0;
else {
register unsigned long shiftr = (nbytes - 1) >> 2;
nunits = 0;
while (shiftr >>= 1) nunits++;
}
if (nunits < MEMUNITS) {
*((char **) p) = memarray[nunits];
memarray[nunits] = p;
}
else free(p);
}
}
LVAL newtvec P2C(int, n, int, m)
{
unsigned size;
LVAL val;
size = n * m;
val = allocvector(TVEC,btow_size(size+1));
val->n_strlen = size;
return (val);
}
LVAL newrndstate P2C(LVAL, gen, LVAL, data)
{
LVAL val;
val = cons(gen, data);
setntype(val, RNDSTATE);
return(val);
}
#ifdef BYTECODE
LVAL newbcclosure P2C(LVAL, type, LVAL, code)
{
LVAL val;
val = cons(type, code);
setntype(val, BCCLOSURE);
return(val);
}
#endif /* BYTECODE */
static VOID check_finalize(V)
{
LVAL last = NIL, next = finalize_registered, head, tail;
while (consp(next)) {
if (is_new_node(car(car(next)))) {
head = next;
tail = cdr(next);
if (null(last))
finalize_registered = tail;
else
Rplacd(last, tail);
next = tail;
Rplacd(head, finalize_pending);
finalize_pending = head;
}
else {
last = next;
next = cdr(next);
}
}
}
static VOID do_finalize(V)
{
CONTEXT cntxt;
LVAL next;
xlsave1(next);
xlbegin(&cntxt,CF_UNWIND|CF_ERROR,NIL);
XL_SETJMP(cntxt.c_jmpbuf);
while (consp(finalize_pending)) {
next = finalize_pending;
finalize_pending = cdr(next);
xlapp1(cdr(car(next)), car(car(next)));
}
xlend(&cntxt);
xlpop();
}
static void check_weak_boxes()
{
LVAL last = NIL, next = xlweakboxes;
while (ntype(next) == WEAKBOX) {
if (is_new_node(next)) {
/* delete box from weak box list */
LVAL tail = cdr(next);
if (null(last))
xlweakboxes = tail;
else
Rplacd(last, tail);
next = tail;
}
else {
if (is_new_node(car(next)))
Rplaca(next, NIL);
last = next;
next = cdr(next);
}
}
}
LVAL xregfinal(V)
{
LVAL arg, fun;
arg = xlgetarg();
fun = xlgetarg();
xllastarg();
finalize_registered = cons(cons(arg, fun), finalize_registered);
return NIL;
}
LVAL xmkweakbox(V)
{
LVAL val = xlgetarg();
LVAL box = consa(val);
xllastarg();
ntype(box) = WEAKBOX;
Rplacd(box, xlweakboxes);
xlweakboxes = box;
return box;
}
#define weakboxp(x) (ntype(x) == WEAKBOX)
#define xlgaweakbox() (testarg(typearg(weakboxp)))
LVAL xweakboxval(V)
{
LVAL box = xlgaweakbox();
xllastarg();
return car(box);
}
LVAL newnatptr P2C(ALLOCTYPE *, p, LVAL, v)
{
LVAL val;
xlprot1(v);
val = newnode(NATPTR);
car(val) = (LVAL) p;
cdr(val) = v;
xlpop();
return val;
}
syntax highlighted by Code2HTML, v. 0.9.1