BSD 4_3_Reno development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 11 Dec 1987 10:28:00 +0000 (02:28 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Fri, 11 Dec 1987 10:28:00 +0000 (02:28 -0800)
Work on file usr/src/pgrm/lisp/franz/alloc.c

Synthesized-from: CSRG/cd2/4.3reno

usr/src/pgrm/lisp/franz/alloc.c [new file with mode: 0644]

diff --git a/usr/src/pgrm/lisp/franz/alloc.c b/usr/src/pgrm/lisp/franz/alloc.c
new file mode 100644 (file)
index 0000000..74e91e5
--- /dev/null
@@ -0,0 +1,1630 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: alloc.c,v 1.13 87/12/11 17:27:45 sklower Exp $";
+#endif
+
+/*
+ *     alloc.c                         $Locker:  $
+ * storage allocator and garbage collector
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+# include "global.h"
+# include "structs.h"
+
+#include <sys/types.h>
+#include <sys/times.h>
+#ifdef METER
+#include <sys/vtimes.h>
+#endif
+# define NUMWORDS TTSIZE * 128  /*  max number of words in P0 space  */
+# define BITQUADS TTSIZE * 2   /*  length of bit map in quad words  */
+# define BITLONGS TTSIZE * 4   /*  length of bit map in long words  */
+
+# ifdef vax
+# define ftstbit       asm("   ashl    $-2,r11,r3");\
+                       asm("   bbcs    r3,_bitmapi,1f");\
+                       asm("   ret"); \
+                       asm("1:");
+
+/* setbit is a fast way of setting a bit, it is like ftstbit except it
+ * always continues on to the next instruction
+ */
+# define setbit                asm("   ashl    $-2,r11,r0"); \
+                       asm("   bbcs    r0,_bitmapi,$0");
+# endif
+
+# if m_68k
+# define ftstbit       {if(Itstbt()) return;}
+# define setbit                Itstbt()
+# endif
+
+# ifdef tahoe
+# define ftstbit       if( readbit(p) ) return; oksetbit;
+# define setbit                {bitmapi[(int)p>>7] |= bitmsk[((int)p >> 2)&31];}
+# define readbit(p)    ((int)bitmapi[r=(int)p>>7] & (s=bitmsk[((int)p>>2)&31]))
+# define oksetbit      {bitmapi[r] |= s;}
+# endif
+
+/*     Unused bit macros
+# define lookbit(p)    (bbitmap[(int)p>>5] & bitmsk[((int)p>>2) & 7])
+# define readchk(p)    ((int)bitfre[(int)p>>5] & bitmsk[((int)p>>2)&7])
+# define setchk(p)     {bitfre[(int)p>>5] |= bitmsk[((int)p >> 2) & 7];}
+*/
+
+# define roundup(x,l)  (((x - 1) | (l - 1)) + 1) 
+
+# define MARKVAL(v)    if(((int)v) >= (int)beginsweep) markdp(v);
+# define ATOLX(p)      ((((int)p)-OFFSET)>>7)
+
+/* the Vax hardware only allows 2^16-1 bytes to be accessed with one
+ * movc5 instruction.  We use the movc5 instruction to clear the 
+ * bitmaps.
+ */
+# define MAXCLEAR ((1<<16)-1)
+
+/* METER denotes something added to help meter storage allocation. */
+
+extern int *beginsweep;                        /* first sweepable data         */
+extern char purepage[];
+extern int fakettsize;
+extern int gcstrings;
+int debugin  = FALSE;                  /* temp debug flag */
+
+extern lispval datalim;                        /*  end of data space */
+int bitmapi[BITLONGS];                 /*  the bit map--one bit per long  */
+double zeroq;                          /*  a quad word of zeros  */
+char *bbitmap = (char *) bitmapi;      /*  byte version of bit map array */
+double  *qbitmap = (double *) bitmapi; /*  integer version of bit map array */
+#ifdef METER
+extern int gcstat;
+extern struct vtimes
+       premark,presweep,alldone;       /* actually struct tbuffer's */
+
+extern int mrkdpcnt;
+extern int conssame, consdiff,consnil; /* count of cells whose cdr point
+                                        * to the same page and different
+                                        * pages respectively
+                                        */
+#endif
+int bitmsk[32]={1,2,4,8,16,32,64,128,  /*  used by bit-marking macros  */
+               0x100, 0x200, 0x400, 0x800, 
+               0x1000, 0x2000, 0x4000, 0x8000, 
+               0x10000, 0x20000, 0x40000, 0x80000, 
+               0x100000, 0x200000, 0x400000, 0x800000, 
+               0x1000000, 0x2000000, 0x4000000, 0x8000000, 
+               0x10000000, 0x20000000, 0x40000000, 0x80000000}; 
+extern int  *bind_lists;               /*  lisp data for compiled code */
+
+char *xsbrk();
+char *gethspace();
+
+
+extern struct types atom_str, strng_str, int_str, dtpr_str, doub_str,
+       array_str, sdot_str, val_str, funct_str, hunk_str[], vect_str,
+       vecti_str, other_str;
+
+extern struct str_x str_current[];
+
+lispval hunk_items[7], hunk_pages[7], hunk_name[7];
+
+extern int initflag; /* starts off TRUE: initially gc not allowed */
+
+
+/* this is a table of pointers to all struct types objects
+ * the index is the type number.
+ */
+static struct types *spaces[NUMSPACES] = 
+       {&strng_str, &atom_str, &int_str,
+        &dtpr_str, &doub_str, &funct_str, 
+        (struct types *) 0,  /* port objects not allocated in this way  */
+        &array_str,
+        &other_str,  /* other objects not allocated in this way  */
+        &sdot_str,&val_str, 
+        &hunk_str[0], &hunk_str[1], &hunk_str[2],
+        &hunk_str[3], &hunk_str[4], &hunk_str[5],
+        &hunk_str[6],
+        &vect_str, &vecti_str};
+
+
+/* this is a table of pointers to collectable struct types objects
+ * the index is the type number.
+ */
+struct types *gcableptr[] = {
+#ifndef GCSTRINGS
+     (struct types *) 0,  /* strings not collectable */
+#else
+     &strng_str,
+#endif
+     &atom_str,
+     &int_str, &dtpr_str, &doub_str,
+     (struct types *) 0,  /* binary objects not collectable */
+     (struct types *) 0,  /* port objects not collectable */
+     &array_str,
+     (struct types *) 0,  /* gap in the type number sequence */
+     &sdot_str,&val_str, 
+     &hunk_str[0], &hunk_str[1], &hunk_str[2],
+     &hunk_str[3], &hunk_str[4], &hunk_str[5],
+     &hunk_str[6],
+     &vect_str, &vecti_str};
+
+
+/*
+ *   get_more_space(type_struct,purep) 
+ *                                                                     
+ *  Allocates and structures a new page, returning 0.
+ *  If no space is available, returns positive number.
+ *  If purep is TRUE, then pure space is allocated.
+ */
+get_more_space(type_struct,purep)                                 
+struct types *type_struct;
+{
+       int cntr;
+       char *start;
+       int *loop, *temp;
+       lispval p;
+       extern char holend[];
+
+       if( (int) datalim >= TTSIZE*LBPG+OFFSET ) return(2);
+
+       /*
+        * If the hole is defined, then we allocate binary objects
+        * and strings in the hole.  However we don't put strings in
+        * the hole if strings are gc'ed.
+        */
+#ifdef HOLE
+       if(   purep
+#ifndef GCSTRINGS
+          || type_struct==&strng_str
+#endif
+          || type_struct==&funct_str)
+               start = gethspace(LBPG,type_struct->type);
+       else
+#endif
+               start = xsbrk(1);               /* get new page */
+
+
+       SETTYPE(start, type_struct->type,20);  /*  set type of page  */
+
+       purepage[ATOX(start)] = (char)purep;  /* remember if page was pure*/
+
+       /* bump the page counter for this space if not pure */
+
+       if(!purep) ++((*(type_struct->pages))->i);
+
+       type_struct->space_left = type_struct->space;
+       temp = loop = (int *) start;
+       for(cntr=1; cntr < type_struct->space; cntr++)
+               loop = (int *) (*loop = (int) (loop + type_struct->type_len));
+
+       /* attach new cells to either the pure space free list  or the 
+        * standard free list
+        */
+       if(purep) {
+           *loop = (int) (type_struct->next_pure_free);
+           type_struct->next_pure_free = (char *) temp;
+       }
+       else  {
+           *loop = (int) (type_struct->next_free);
+           type_struct->next_free = (char *) temp;
+       }
+
+       /*  if type atom, set pnames to CNIL  */
+
+       if( type_struct == &atom_str )
+               for(cntr=0, p=(lispval) temp; cntr<atom_str.space; ++cntr)
+                       {
+                       p->a.pname = (char *) CNIL;
+                       p = (lispval) ((int *)p + atom_str.type_len);
+                       }
+       return(0);  /*  space was available  */
+}
+
+
+/*
+ * next_one(type_struct) 
+ *
+ *  Allocates one new item of each kind of space, except STRNG.        
+ *  If there is no space, calls gc, the garbage collector.
+ *  If there is still no space, allocates a new page using
+ *  get_more_space
+ */
+
+lispval
+next_one(type_struct)
+struct types *type_struct;
+{
+
+       register char *temp;
+
+       while(type_struct->next_free == (char *) CNIL)
+               {
+               int g;
+
+               if(
+                  (initflag == FALSE) &&       /* dont gc during init */
+#ifndef GCSTRINGS
+                  (type_struct->type != STRNG) && /* can't collect strings */
+#else
+                  gcstrings &&                 /* user (sstatus gcstrings) */
+#endif
+                  (type_struct->type != BCD) &&   /* nor function headers  */
+                  gcdis->a.clb == nil )                /* gc not disabled */
+                                       /* not to collect during load */
+
+                       {
+                       gc(type_struct);  /*  collect  */
+                       }
+
+               if( type_struct->next_free != (char *) CNIL ) break;
+
+               if(! (g=get_more_space(type_struct,FALSE))) break;
+
+               space_warn(g);
+               }
+       temp = type_struct->next_free;
+       type_struct->next_free = * (char **)(type_struct->next_free);
+       (*(type_struct->items))->i ++;
+       return((lispval) temp);
+}
+/*
+ * Warn about exhaustion of space,
+ * shared with next_pure_free().
+ */
+space_warn(g)
+{
+       if( g==1 ) {
+           plimit->i += NUMSPACES; /*  allow a few more pages  */
+           copval(plima,plimit);       /*  restore to reserved reg  */
+
+           error("PAGE LIMIT EXCEEDED--EMERGENCY PAGES ALLOCATED", TRUE);
+       } else error("SORRY, ABSOLUTE PAGE LIMIT HAS BEEN REACHED", TRUE);
+}
+
+
+/* allocate an element of a pure structure.  Pure structures will
+ * be ignored by the garbage collector.
+ */
+lispval
+next_pure_one(type_struct)
+struct types *type_struct;
+{
+
+       register char *temp;
+
+       while(type_struct->next_pure_free == (char *) CNIL)
+               {
+               int g;
+               if(! (g=get_more_space(type_struct,TRUE))) break;
+               space_warn(g);
+               }
+
+       temp = type_struct->next_pure_free;
+       type_struct->next_pure_free = * (char **)(type_struct->next_pure_free);
+       return((lispval) temp);
+}
+
+lispval
+newint()
+{
+       return(next_one(&int_str));
+}
+
+lispval
+pnewint()
+{
+       return(next_pure_one(&int_str));
+}
+
+lispval
+newdot()
+{
+       lispval temp;
+
+       temp = next_one(&dtpr_str);
+       temp->d.car = temp->d.cdr = nil;
+       return(temp);
+}
+
+lispval
+pnewdot()
+{
+       lispval temp;
+
+       temp = next_pure_one(&dtpr_str);
+       temp->d.car = temp->d.cdr = nil;
+       return(temp);
+}
+
+lispval
+newdoub()
+{
+       return(next_one(&doub_str));
+}
+
+lispval
+pnewdb()
+{
+       return(next_pure_one(&doub_str));
+}
+
+lispval
+newsdot()
+{
+       register lispval temp;
+       temp = next_one(&sdot_str);
+       temp->d.car = temp->d.cdr = 0;
+       return(temp);
+}
+
+lispval
+pnewsdot()
+{
+       register lispval temp;
+       temp = next_pure_one(&sdot_str);
+       temp->d.car = temp->d.cdr = 0;
+       return(temp);
+}
+
+struct atom *
+newatom(pure) {
+       struct atom *save; char *mypname;
+
+       mypname = newstr(pure);
+       pnameprot = ((lispval) mypname);
+       save = (struct atom *) next_one(&atom_str) ;    
+       save->plist = save->fnbnd = nil;
+       save->hshlnk = (struct atom *)CNIL;
+       save->clb = CNIL;
+       save->pname = mypname;
+       return (save);
+}
+
+char *
+newstr(purep) {
+       char *save, *strcpy();
+       int atmlen;
+       register struct str_x *p = str_current + purep;
+
+       atmlen = strlen(strbuf)+1;
+       if(atmlen > p->space_left) {
+               if(atmlen >= STRBLEN) {
+                       save = (char *)csegment(OTHER, atmlen, purep);
+                       SETTYPE(save,STRNG,40);
+                       purepage[ATOX(save)] = (char)purep;
+                       strcpy(save,strbuf);
+                       return(save);
+               }
+               p->next_free =  (char *) (purep ?
+                       next_pure_one(&strng_str) : next_one(&strng_str)) ;
+               p->space_left = LBPG;
+       }
+       strcpy((save = p->next_free), strbuf);
+       /*while(atmlen & 3) ++atmlen;   /*  even up length of string  */
+       p->next_free += atmlen;
+       p->space_left -= atmlen;
+       return(save);
+}
+
+static char * Iinewstr(s,purep) char *s;
+{
+       int len = strlen(s);
+       while(len > (endstrb - strbuf - 1)) atomtoolong(strbuf);
+       strcpy(strbuf,s);
+       return(newstr(purep));
+}
+
+
+char *inewstr(s) char *s;
+{
+       Iinewstr(s,0);
+}
+
+char *pinewstr(s) char *s;
+{
+       Iinewstr(s,1);
+}
+
+lispval
+newarray()
+       {
+       register lispval temp;
+
+       temp = next_one(&array_str);
+       temp->ar.data = (char *)nil;
+       temp->ar.accfun = nil;
+       temp->ar.aux = nil;
+       temp->ar.length = SMALL(0);
+       temp->ar.delta = SMALL(0);
+       return(temp);
+       }
+
+lispval
+newfunct()
+       {
+       register lispval temp;
+       lispval Badcall();
+       temp = next_one(&funct_str);
+       temp->bcd.start = Badcall;
+       temp->bcd.discipline = nil;
+       return(temp);
+       }
+
+lispval
+newval()
+       {
+       register lispval temp;
+       temp = next_one(&val_str);
+       temp->l = nil;
+       return(temp);
+       }
+
+lispval
+pnewval()
+       {
+       register lispval temp;
+       temp = next_pure_one(&val_str);
+       temp->l = nil;
+       return(temp);
+       }
+
+lispval
+newhunk(hunknum)
+int hunknum;
+       {
+       register lispval temp;
+
+       temp = next_one(&hunk_str[hunknum]);    /* Get a hunk */
+       return(temp);
+       }
+
+lispval
+pnewhunk(hunknum)
+int hunknum;
+       {
+       register lispval temp;
+
+       temp = next_pure_one(&hunk_str[hunknum]);       /* Get a hunk */
+       return(temp);
+       }
+
+lispval
+inewval(arg) lispval arg;
+       {
+       lispval temp;
+       temp = next_one(&val_str);
+       temp->l = arg;
+       return(temp);
+       }
+
+/*
+ * Vector allocators.
+ * a vector looks like:
+ *  longword: N = size in bytes
+ *  longword: pointer to lisp object, this is the vector property field
+ *  N consecutive bytes
+ *
+ */
+lispval getvec();
+
+lispval
+newvec(size)
+{
+    return(getvec(size,&vect_str,FALSE));
+}
+
+lispval
+pnewvec(size)
+{
+    return(getvec(size,&vect_str,TRUE));
+}
+
+lispval
+nveci(size)
+{
+    return(getvec(size,&vecti_str,FALSE));
+}
+
+lispval
+pnveci(size)
+{
+    return(getvec(size,&vecti_str,TRUE));
+}
+
+/*
+ * getvec
+ *  get a vector of size byte, from type structure typestr and
+ * get it from pure space if purep is TRUE.
+ *  vectors are stored linked through their property field.  Thus
+ * when the code here refers to v.vector[0], it is the prop field
+ * and vl.vectorl[-1] is the size field.   In other code,
+ * v.vector[-1] is the prop field, and vl.vectorl[-2] is the size.
+ */
+lispval
+getvec(size,typestr,purep)
+register struct types *typestr;
+{
+    register lispval back, current;
+    int sizewant, bytes, thissize, pages, pindex, triedgc = FALSE;
+
+    /* we have to round up to a multiple of 4 bytes to determine the
+     * size of vector we want.  The rounding up assures that the
+     * property pointers are longword aligned
+     */
+    sizewant = VecTotSize(size);
+    if(debugin) fprintf(stderr,"want vect %db\n",size);    
+ again:
+    if(purep)
+        back = (lispval) &(typestr->next_pure_free);
+    else
+        back = (lispval) &(typestr->next_free);
+    current = back->v.vector[0];
+    while(current !=  CNIL)
+    {
+       if(debugin)
+            fprintf(stderr,"next free size %db; ", current->vl.vectorl[-1]);
+       if ((thissize = VecTotSize(current->vl.vectorl[-1])) == sizewant)
+       {
+           if(debugin) fprintf(stderr,"exact match of size %d at 0x%x\n",
+                               4*thissize, &current->v.vector[1]);
+           back->v.vector[0]
+               = current->v.vector[0];/* change free pointer*/
+           current->v.vector[0] = nil; /* put nil in property */
+           /* to the user, vector begins one after property*/
+           return((lispval)&current->v.vector[1]);
+       }
+       else if (thissize >= sizewant + 3)
+       {
+           /* the reason that there is a `+ 3' instead of `+ 2'
+            * is that we don't want to leave a zero sized vector which
+            * isn't guaranteed to be followed by another vector
+            */
+           if(debugin)
+            fprintf(stderr,"breaking a %d vector into a ",
+                                       current->vl.vectorl[-1]);
+
+           current->v.vector[1+sizewant+1]
+                       = current->v.vector[0];  /* free list pointer */
+           current->vl.vectorl[1+sizewant]
+                       = VecTotToByte(thissize - sizewant - 2);/*size info */
+           back->v.vector[0] = (lispval) &(current->v.vector[1+sizewant+1]);
+           current->vl.vectorl[-1] = size;
+
+           if(debugin)fprintf(stderr," %d one and a %d one\n",
+               current->vl.vectorl[-1],current->vl.vectorl[1+sizewant]);
+           current->v.vector[0] = nil; /* put nil in property */
+           /* vector begins one after the property */
+           if(debugin) fprintf(stderr," and returning vector at 0x%x\n",
+                               &current->v.vector[1]);
+           return((lispval)(&current->v.vector[1]));
+       }
+       back =  current;
+       current =  current->v.vector[0];
+    }
+    if(!triedgc
+        && !purep
+       && (gcdis->a.clb == nil)
+       && (initflag == FALSE))
+    {
+       gc(typestr);
+       triedgc = TRUE;
+       goto again;
+    }
+    
+    /* set bytes to size needed for this vector */
+    bytes = size + 2*sizeof(long);
+    
+    /* must make sure that if the vector we are allocating doesnt
+       completely fill a page, there is room for another vector to record
+       the size left over */
+    if((bytes & (LBPG - 1)) > (LBPG - 2*sizeof(long))) bytes += LBPG;
+    bytes = roundup(bytes,LBPG);
+
+    current = csegment(typestr->type,bytes/sizeof(long),purep);
+    current->vl.vectorl[0] = bytes - 2*sizeof(long);
+    
+    if(purep) {
+        current->v.vector[1] = (lispval)(typestr->next_pure_free);
+        typestr->next_pure_free = (char *) &(current->v.vector[1]);
+       /* make them pure */
+       pages = bytes/LBPG;
+       for(pindex = ATOX(current); pages ; pages--)
+       {
+           purepage[pindex++] = TRUE;
+       }
+    } else {
+        current->v.vector[1] = (lispval)(typestr->next_free);
+        typestr->next_free = (char *) &(current->v.vector[1]);
+       if(debugin) fprintf(stderr,"grabbed %d vec pages\n",bytes/LBPG);
+    }
+    if(debugin)
+      fprintf(stderr,"creating a new vec, size %d\n",current->v.vector[0]);
+    goto again;
+}
+
+/*
+ * Ipurep :: routine to check for pureness of a data item
+ *
+ */
+lispval 
+Ipurep(element)
+lispval element;
+{
+    if(purepage[ATOX(element)]) return(tatom) ; else return(nil);
+}
+
+/* routines to return space to the free list.  These are used by the
+ * arithmetic routines which tend to create large intermediate results
+ * which are know to be garbage after the calculation is over.
+ *
+ * There are jsb callable versions of these routines in qfuncl.s
+ */
+
+/* pruneb   - prune bignum. A bignum is an sdot followed by a list of
+ *  dtprs.    The dtpr list is linked by car instead of cdr so when we
+ *  put it in the free list, we have to change the links.
+ */
+pruneb(bignum)
+lispval bignum;
+{
+       register lispval temp = bignum;
+
+       if(TYPE(temp) != SDOT) 
+           errorh(Vermisc,"value to pruneb not a sdot",nil,FALSE,0);
+
+       --(sdot_items->i);
+       temp->s.I = (int) sdot_str.next_free;
+       sdot_str.next_free = (char *) temp;
+
+       /* bignums are not terminated by nil on the dual,
+          they are terminated by (lispval) 0 */
+
+       while(temp = temp->s.CDR)
+       {
+           if(TYPE(temp) != DTPR) 
+             errorh(Vermisc,"value to pruneb not a list",
+                     nil,FALSE,0);
+           --(dtpr_items->i);
+           temp->s.I = (int) dtpr_str.next_free;
+           dtpr_str.next_free = (char *) temp;
+       }
+}
+lispval
+Badcall()
+       { error("BAD FUNCTION DESCRIPTOR USED IN CALL",FALSE); }
+
+
+
+/*
+ * Ngc 
+ *  this is the lisp function gc
+ *
+ */
+
+lispval
+Ngc()
+{
+    return(gc((struct types *)CNIL));
+}
+
+/*
+ * gc(type_struct) 
+ *
+ *  garbage collector:  Collects garbage by mark and sweep algorithm.
+ *  After this is done, calls the Nlambda, gcafter.
+ *  gc may also be called from LISP, as an  nlambda of no arguments.
+ * type_struct is the type of lisp data that ran out causing this
+ * garbage collection
+ */
+int printall = 0;
+lispval
+gc(type_struct)
+       struct types *type_struct;
+       {
+       lispval save;
+       struct tms begin, finish;
+       extern int gctime;
+
+       /* if this was called automatically when space ran out
+        * print out a message
+        */
+       if((Vgcprint->a.clb != nil)
+          && (type_struct != (struct types *) CNIL ))
+       {
+           FILE *port = okport(Vpoport->a.clb,poport);
+           fprintf(port,"gc:");
+           fflush(port);
+       }
+       
+       if(gctime) times(&begin);
+
+       gc1(); /* mark&sweep */
+
+       /* Now we call gcafter--special c ase if gc called from LISP */
+
+       if( type_struct == (struct types *) CNIL )
+               gccall1->d.cdr = nil;  /* make the call "(gcafter)" */
+       else
+               {
+               gccall1->d.cdr = gccall2;
+               gccall2->d.car = *(type_struct->type_name);
+               }
+       PUSHDOWN(gcdis,gcdis);  /*  flag to indicate in garbage collector  */
+       save = eval(gccall1);   /*  call gcafter  */
+       POP;                    /*  turn off flag  */
+
+       if(gctime) {
+               times(&finish);
+               gctime += (finish.tms_utime - begin.tms_utime);
+       }
+       return(save);   /*  return result of gcafter  */
+       }
+
+       
+
+/*  gc1()  **************************************************************/
+/*                                                                     */
+/*  Mark-and-sweep phase                                               */
+
+gc1()
+{
+       int j, k;
+       register int *start,bvalue,type_len; 
+       register struct types *s;
+       int *point,i,freecnt,itemstogo,bits,bindex,type,bytestoclear;
+       int usedcnt;
+       char *pindex;
+       struct argent *loop2;
+       struct nament *loop3;
+       struct atom *symb;
+       int markdp();
+       extern int hashtop;
+
+       pagerand(); 
+       /*  decide whether to check LISP structure or not  */
+
+
+#ifdef METER
+       vtimes(&premark,0);
+       mrkdpcnt = 0;
+       conssame = consdiff = consnil = 0;
+#endif
+
+       /*  first set all bit maps to zero  */
+
+
+#ifdef SLOCLEAR
+       {
+           int enddat;
+           enddat = (int)(datalim-OFFSET) >> 8;
+           for(bvalue=0; bvalue < (int)enddat ; ++bvalue)
+           {
+                qbitmap[bvalue] = zeroq; 
+           }
+       }
+#endif
+
+       /* try the movc5 to clear the bit maps */
+       /* the maximum number of bytes we can clear in one sweep is
+        * 2^16 (or 1<<16 in the C lingo)
+        */
+       bytestoclear = ((((int)datalim)-((int)beginsweep)) >> 9) * 16; 
+       for(start = bitmapi + ATOLX(beginsweep);
+           bytestoclear > 0;)
+           {
+               if(bytestoclear > MAXCLEAR)
+                       blzero((int)start,MAXCLEAR);
+               else
+                       blzero((int)start,bytestoclear);
+               start = (int *) (MAXCLEAR + (int) start);
+               bytestoclear -= MAXCLEAR;
+           }
+                       
+       /* mark all atoms in the oblist */
+        for( bvalue=0 ; bvalue <= hashtop-1 ; bvalue++ ) /* though oblist */
+        {
+           for( symb = hasht[bvalue] ; symb != (struct atom *) CNIL ;
+                     symb = symb-> hshlnk) {
+                 markdp((lispval)symb); 
+           }
+       }
+
+
+       /* Mark all the atoms and ints associated with the hunk
+          data types */
+          
+       for(i=0; i<7; i++) {
+               markdp(hunk_items[i]);
+               markdp(hunk_name[i]);
+               markdp(hunk_pages[i]);
+       }
+       /* next run up the name stack */
+       for(loop2 = np - 1; loop2 >=  orgnp; --loop2) MARKVAL(loop2->val);      
+
+       /* now the bindstack (vals only, atoms are marked elsewhere ) */
+       for(loop3 = bnp - 1; loop3 >= orgbnp; --loop3)MARKVAL(loop3->val);
+
+       
+       /* next mark all compiler linked data */
+       /* if the Vpurcopylits switch is non nil (lisp variable $purcopylits)
+        * then when compiled code is read in, it tables will not be linked
+        * into this table and thus will not be marked here.  That is ok
+        * though, since that data is assumed to be pure.
+        */
+        point = bind_lists;
+        while((start = point) != (int *)CNIL) {
+               while( *start != -1 )
+               {
+                       markdp((lispval)*start);
+                       start++;
+               }
+               point = (int *)*(point-1);
+        }
+
+       /* next mark all system-significant lisp data */
+
+       
+       for(i=0; i<SIGNIF; ++i) markdp((lispsys[i]));
+
+#ifdef METER
+       vtimes(&presweep,0);
+#endif
+       /* all accessible data has now been marked. */
+       /* all collectable spaces must be swept,    */
+       /* and freelists constructed.               */
+
+       /* first clear the structure elements for types
+        * we will sweep
+        */
+       
+       for(k=0 ; k <= VECTORI ; k++)
+       {
+               if( s=gcableptr[k]) {
+                   if(k==STRNG && !gcstrings) { /* don't do anything*/ }
+                   else
+                       {
+                         (*(s->items))->i = 0;
+                         s->space_left = 0;
+                         s->next_free = (char *) CNIL;
+                       }
+               }
+       }
+#if m_68k
+       fixbits(bitmapi+ATOLX(beginsweep),bitmapi+ATOLX(datalim));
+#endif
+
+
+       /* sweep up in memory looking at gcable pages */
+
+       for(start = beginsweep,  bindex = ATOLX(start), 
+                 pindex = &purepage[ATOX(start)]; 
+           start < (int *)datalim;
+           start += 128, pindex++)
+       {
+           if(!(s=gcableptr[type = TYPE(start)]) || *pindex
+#ifdef GCSTRINGS
+            || (type==STRNG && !gcstrings) 
+#endif
+               )
+           {
+               /* ignore this page but advance pointer         */
+               bindex += 4;   /* and 4 words of 32 bit bitmap words */
+               continue;
+           }
+
+           freecnt = 0;                /* number of free items found */
+           usedcnt = 0;                /* number of used items found */
+           
+           point = start;
+           /* sweep dtprs as a special case, since
+            * 1) there will (usually) be more dtpr pages than any other type
+            * 2) most dtpr pages will be empty so we can really win by special
+            *    caseing the sweeping of massive numbers of free cells
+            */
+           /* since sdot's have the same structure as dtprs, this code will
+              work for them too
+            */
+           if((type == DTPR) || (type == SDOT))
+           {
+               int *head,*lim;
+               head = (int *) s->next_free;    /* first value on free list*/
+
+               for(i=0; i < 4; i++)    /* 4 bit map words per page  */
+               {
+                   bvalue = bitmapi[bindex++]; /* 32 bits = 16 dtprs */
+                   if(bvalue == 0)     /* if all are free      */
+                   {
+                       *point = (int)head;
+                       lim = point + 32;   /* 16 dtprs = 32 ints */
+                       for(point += 2; point < lim ; point += 2)
+                       {
+                           *point = (int)(point - 2);
+                       }
+                       head = point - 2;
+                       freecnt += 16;
+                   }
+                   else for(j = 0; j < 16 ; j++)
+                   {
+                       if(!(bvalue & 1))
+                       {
+                           freecnt++;
+                           *point = (int)head;
+                           head = point;
+                       }
+#ifdef METER
+                       /* check if the page address of this cell is the
+                        * same as the address of its cdr
+                        */
+                       else if(FALSE && gcstat && (type == DTPR))
+                       {  
+                          if(((int)point & ~511) 
+                             == ((int)(*point) & ~511)) conssame++;
+                          else consdiff++;
+                          usedcnt++;
+                       }
+#endif
+                       else usedcnt++;         /* keep track of used */
+                       
+                       point += 2;
+                       bvalue = bvalue >> 2;
+                   }
+               }
+               s->next_free = (char *) head;
+           }
+           else if((type == VECTOR) || (type == VECTORI))
+           {
+               int canjoin = FALSE;
+               int *tempp;
+
+               /* check if first item on freelist ends exactly at
+                  this page
+                */
+               if(((tempp = (int *)s->next_free) != (int *)CNIL)
+                  && ((VecTotSize(((lispval)tempp)->vl.vectorl[-1])
+                                                           + 1 + tempp)
+                                       == point))
+                  canjoin = TRUE;
+                  
+               /* arbitrary sized vector sweeper */
+               /*
+                * jump past first word since that is a size fixnum
+                * and second word since that is property word
+                */
+               if(debugin)
+                 fprintf(stderr,"vector sweeping, start at 0x%x\n",
+                               point);
+               bits = 30;
+               bvalue = bitmapi[bindex++] >> 2;
+               point += 2;
+               while (TRUE) {
+                   type_len = point[VSizeOff];
+                   if(debugin) {
+                     fprintf(stderr,"point: 0x%x, type_len %d\n",
+                               point, type_len);
+                     fprintf(stderr,"bvalue: 0x%x, bits: %d, bindex: 0x%x\n",
+                               bvalue, bits, bindex);
+                   }
+                                       /* get size of vector */
+                   if(!(bvalue & 1))   /* if free */
+                   {
+                       if(debugin) fprintf(stderr,"free\n");
+                       freecnt += type_len + 2*sizeof(long);
+                       if(canjoin)
+                       {
+                           /* join by adjusting size of first vector */
+                           ((lispval)(s->next_free))->vl.vectorl[-1]
+                             +=  type_len + 2*sizeof(long); 
+                           if(debugin)
+                             fprintf(stderr,"joined size: %d\n",
+                                 ((lispval)(s->next_free))->vl.vectorl[-1]);
+                       }
+                       else {
+                           /* vectors are linked at the property word */
+                           *(point - 1) = (int)(s->next_free);
+                           s->next_free = (char *) (point - 1);
+                       }
+                       canjoin = TRUE;
+                   }
+                   else {
+                       canjoin = FALSE;
+                       usedcnt += type_len + 2*sizeof(long);
+                   }
+                   
+                   point += VecTotSize(type_len);
+                   /* we stop sweeping only when we reach a page
+                      boundary since vectors can span pages
+                    */
+                   if(((int)point & 511) == 0)
+                   {
+                       /* reset the counters, we cannot predict how
+                        * many pages we have crossed over
+                        */
+                       bindex = ATOLX(point);
+                       /* these will be inced, so we must dec */
+                       pindex = &purepage[ATOX(point)] - 1;
+                       start = point - 128;
+                       if(debugin)
+                       fprintf(stderr,
+                               "out of vector sweep when point = 0x%x\n",
+                               point);
+                       break;
+                   }
+                   /* must advance to next point and next value in bitmap.
+                    * we add VecTotSize(type_len) + 2 to get us to the 0th
+                    * entry in the next vector (beyond the size fixnum)
+                    */
+                   point += 2;         /* point to next 0th entry */
+                   if ( (bits -= (VecTotSize(type_len) + 2)) > 0)  
+                       bvalue = bvalue >> (VecTotSize(type_len) + 2);
+                   else {
+                       bits = -bits;   /* must advance to next word in map */
+                       bindex += bits / 32; /* this is tricky stuff... */
+                       bits = bits % 32;
+                       bvalue = bitmapi[bindex++] >> bits;
+                       bits = 32 - bits;
+                   }
+               }
+           }
+           else { 
+               /* general sweeper, will work for all types */
+               itemstogo = s->space;   /* number of items per page  */
+               bits = 32;                      /* number of bits per word */
+               type_len = s->type_len;
+
+               /* printf(" s %d, itemstogo %d, len %d\n",s,itemstogo,type_len);*/
+               bvalue = bitmapi[bindex++];
+
+               while(TRUE)
+               {
+                   if(!(bvalue & 1))   /* if data element is not marked */
+                   {
+                       freecnt++;
+                       *point = (int) (s->next_free) ;
+                       s->next_free = (char *) point;
+                   }
+                   else usedcnt++;
+
+                   if( --itemstogo <= 0 ) 
+                   {    if(type_len >= 64) 
+                        {
+                           bindex++;
+                           if(type_len >=128) bindex += 2;
+                        }
+                        break;
+                   }
+
+                   point += type_len;
+                   /* shift over mask by number of words in data type */
+
+                   if( (bits -= type_len) > 0)
+                   {  bvalue = bvalue >> type_len;
+                   } 
+                   else if( bits == 0 ) 
+                   {  bvalue = bitmapi[bindex++];
+                      bits = 32;
+                   }
+                   else
+                   {  bits = -bits;
+                      while( bits >= 32) { bindex++;
+                                           bits -= 32;
+                                         }
+                      bvalue = bitmapi[bindex++];
+                      bvalue = bvalue >> bits;
+                      bits = 32 - bits;;
+                   }
+           }
+       }
+
+     s->space_left += freecnt;
+     (*(s->items))->i += usedcnt;
+     }
+
+#ifdef METER
+        vtimes(&alldone,0);
+       if(gcstat) gcdump();
+#endif
+       pagenorm(); 
+}
+
+/*
+ * alloc
+ *
+ *  This routine tries to allocate one or more pages of the space named
+ *  by the first argument.   Returns the number of pages actually allocated.
+ *  
+ */
+
+lispval
+alloc(tname,npages)
+lispval tname; long npages;
+{
+       long ii, jj;
+       struct types *typeptr;
+
+       ii = typenum(tname);
+        typeptr = spaces[ii];
+       if(npages <= 0) return(inewint(npages));
+       
+       if((ATOX(datalim)) + npages > TTSIZE)
+          error("Space request would exceed maximum memory allocation",FALSE);
+       if((ii == VECTOR) || (ii == VECTORI))
+       {
+           /* allocate in one big chunk */
+           tname = csegment((int) ii,(int) npages*128,0);
+           tname->vl.vectorl[0] = (npages*512 - 2*sizeof(long));
+           tname->v.vector[1] = (lispval) typeptr->next_free;
+           typeptr->next_free = (char *) &(tname->v.vector[1]);
+           if(debugin) fprintf(stderr,"alloced %d vec pages\n",npages);
+           return(inewint(npages));
+       }
+          
+       for( jj=0; jj<npages; ++jj)
+               if(get_more_space(spaces[ii],FALSE)) break;
+       return(inewint(jj));
+}
+
+/*
+ * csegment(typecode,nitems,useholeflag)
+ *  allocate nitems of type typecode.  If useholeflag is true, then
+ * allocate in the hole if there is room.  This routine doesn't look
+ * in the free lists, it always allocates space.
+ */    
+lispval
+csegment(typecode,nitems,useholeflag)
+{
+       register int ii, jj;
+       register char *charadd;
+
+       ii = typecode;
+
+       if(ii!=OTHER) nitems *= 4*spaces[ii]->type_len;
+       nitems = roundup(nitems,512);           /*  round up to right length  */
+#ifdef HOLE
+       if(useholeflag)
+               charadd = gethspace(nitems,ii);
+       else
+#endif
+       {
+               charadd = sbrk(nitems);
+               datalim = (lispval)(charadd+nitems);
+       }
+       if( (int) charadd <= 0 )
+               error("NOT ENOUGH SPACE FOR ARRAY",FALSE);
+       /*if(ii!=OTHER)*/ (*spaces[ii]->pages)->i +=  nitems/512;
+       if(ATOX(datalim) > fakettsize) {
+               datalim = (lispval) (OFFSET + (fakettsize << 9));
+               if(fakettsize >= TTSIZE)
+               {
+                   printf("There isn't room enough to continue, goodbye\n");
+                   franzexit(1);
+               }
+               fakettsize++;
+               badmem(53);
+       }
+       for(jj=0; jj<nitems; jj=jj+512) {
+               SETTYPE(charadd+jj, ii,30);
+       }
+       ii = (int) charadd;
+       while(nitems > MAXCLEAR)
+       {
+           blzero(ii,MAXCLEAR);
+           nitems -= MAXCLEAR;
+           ii += MAXCLEAR;
+       }
+       blzero(ii,nitems);
+       return((lispval)charadd);
+}
+
+int csizeof(tname) lispval tname;
+       {
+       return( spaces[typenum(tname)]->type_len * 4 );
+       }
+
+int typenum(tname) lispval tname;
+       {
+       int ii;
+
+chek:  for(ii=0; ii<NUMSPACES; ++ii)
+               if(spaces[ii] && tname == *(spaces[ii]->type_name)) break;
+       if(ii == NUMSPACES)
+               {
+               tname = error("BAD TYPE NAME",TRUE);
+               goto chek;
+               }
+
+       return(ii);
+       
+       }
+char *
+gethspace(segsiz,type)
+{
+       extern usehole; extern char holend[]; extern char *curhbeg;
+       register char *value;
+
+       if(usehole) {   
+               curhbeg = (char *) roundup(((int)curhbeg),LBPG);
+               if((holend - curhbeg) < segsiz)
+               {       
+                       usehole = FALSE;
+                       curhbeg = holend;
+               } else {
+                       value = curhbeg;
+                       curhbeg = curhbeg + segsiz;
+                       /*printf("start %d, finish %d, size %d\n",value, curhbeg,segsiz);*/
+                       return(value);
+               }
+       }
+       value = (ysbrk(segsiz/LBPG,type));
+       datalim = (lispval)(value + segsiz);
+       return(value);
+}
+gcrebear()
+{
+#ifdef HOLE
+        register int i; register struct types *p;
+
+       /* this gets done upon rebirth */
+       str_current[1].space_left = 0;
+#ifndef GCSTRINGS
+       str_current[0].space_left = 0;  /* both kinds of strings go in hole*/
+#endif
+       funct_str.space_left = 0;
+       funct_str.next_free = (char *) CNIL;
+       /* clear pure space pointers */
+       for(i = 0; i < NUMSPACES; i++)
+       {
+           if(p=spaces[i])
+           p->next_pure_free = (char *) CNIL;
+       }
+#endif
+}
+
+/** markit(p) ***********************************************************/
+/*  just calls markdp                                                  */
+
+markit(p) lispval *p; { markdp(*p); }
+
+/*
+ * markdp(p)
+ *
+ *  markdp is the routine which marks each data item.  If it is a
+ *  dotted pair, the car and cdr are marked also.
+ *  An iterative method is used to mark list structure, to avoid
+ *  excessive recursion.
+ */
+markdp(p) register lispval p;
+       {
+#ifdef tahoe
+       register int r, s;      /* (goes with non-asm readbit, oksetbit) */
+#endif
+/*     register hsize, hcntr;                                           */
+       int hsize, hcntr;
+
+#ifdef METER
+       mrkdpcnt++;
+#endif
+ptr_loop:
+       if(((int)p) <= ((int)nil)) return;      /*  do not mark special data types or nil=0  */
+
+               
+       switch( TYPE(p) )
+               {
+               case ATOM:
+                       ftstbit;
+                       MARKVAL(p->a.clb);
+                       MARKVAL(p->a.plist);
+                       MARKVAL(p->a.fnbnd);
+#ifdef GCSTRINGS
+                       if(gcstrings) MARKVAL(((lispval)p->a.pname));
+                       return;
+
+               case STRNG:
+                       p = (lispval) (((int) p) & ~ (LBPG-1));
+                       ftstbit;
+#endif
+                       return;
+                       
+               case INT:
+               case DOUB:
+                       ftstbit;
+                       return;
+               case VALUE:
+                       ftstbit;
+                       p = p->l;
+                       goto ptr_loop;
+               case DTPR:
+                       ftstbit;
+                       MARKVAL(p->d.car);
+#ifdef METER
+                       /* if we are metering , then check if the cdr is
+                        * nil, or if the cdr is on the same page, and if
+                        * it isn't one of those, then it is on a different
+                        * page
+                        */
+                        if(gcstat)
+                        {
+                            if(p->d.cdr == nil) consnil++;
+                            else if(((int)p & ~511) 
+                                    == (((int)(p->d.cdr)) & ~511))
+                               conssame++;
+                            else consdiff++;
+                         }
+#endif
+                       p = p->d.cdr;
+                       goto ptr_loop;
+
+               case ARRAY:
+                       ftstbit;        /* mark array itself */
+
+                       MARKVAL(p->ar.accfun);  /* mark access function */
+                       MARKVAL(p->ar.aux);             /* mark aux data */
+                       MARKVAL(p->ar.length);  /* mark length */
+                       MARKVAL(p->ar.delta);   /* mark delta */
+                       if(TYPE(p->ar.aux)==DTPR && p->ar.aux->d.car==Vnogbar)
+                       {
+                           /* a non garbage collected array must have its
+                            * array space marked but the value of the array
+                            * space is not marked
+                            */
+                            int l; 
+                            int cnt,d;
+                            if(debugin) {
+                              printf("mark array holders len %d, del %d, start 0x%x\n",
+                                p->ar.length->i,p->ar.delta->i,p->ar.data);
+                                fflush(stdout);
+                           }
+                            l = p->ar.length->i; /* number of elements */
+                            d = p->ar.delta->i;  /* bytes per element  */
+                            p = (lispval) p->ar.data;/* address of first one*/
+                            if(purepage[ATOX(p)]) return;
+
+                            for((cnt = 0); cnt<l ; 
+                                     p = (lispval)(((char *) p) + d), cnt++)
+                            {
+                               setbit;
+                            }
+                       } else {
+/*                     register int i, l; int d;               */
+/*                     register char *dataptr = p->ar.data;    */
+                       int i,l,d;
+                       char *dataptr = p->ar.data;
+
+                       for(i=0, l=p->ar.length->i, d=p->ar.delta->i; i<l; ++i)
+                               {
+                               markdp((lispval)dataptr);
+                               dataptr += d;
+                               }
+                       }
+                       return;
+               case SDOT:
+                       do {
+                               ftstbit;
+                               p = p->s.CDR;
+                       } while (p!=0);
+                       return;
+
+               case BCD:
+                       ftstbit;
+                       markdp(p->bcd.discipline);
+                       return;
+
+               case HUNK2:
+               case HUNK4:
+               case HUNK8:
+               case HUNK16:
+               case HUNK32:
+               case HUNK64:
+               case HUNK128:
+                       {
+                               hsize = 2 << HUNKSIZE(p);
+                               ftstbit;
+                               for (hcntr = 0; hcntr < hsize; hcntr++)
+                                       MARKVAL(p->h.hunk[hcntr]);
+                               return;
+                       }
+                       
+               case VECTORI:
+                       ftstbit;
+                       MARKVAL(p->v.vector[-1]);       /* mark property */
+                       return;
+                       
+               case VECTOR:
+                       {
+                           register int vsize;
+                           ftstbit;
+                           vsize = VecSize(p->vl.vectorl[VSizeOff]);
+                           if(debugin)
+                              fprintf(stderr,"mark vect at %x  size %d\n",
+                                       p,vsize);
+                           while(--vsize >= -1)
+                           {
+                               MARKVAL(p->v.vector[vsize]);
+                           };
+                           return;
+                       }
+               }
+       return;
+       }
+
+
+/* xsbrk allocates space in large chunks (currently 16 pages)
+ * xsbrk(1)  returns a pointer to a page
+ * xsbrk(0)  returns a pointer to the next page we will allocate (like sbrk(0))
+ */
+
+char *
+xsbrk(n)
+       {
+       static char *xx;        /*  pointer to next available blank page  */
+       extern int xcycle;      /*  number of blank pages available  */
+       lispval u;                      /*  used to compute limits of bit table  */
+
+       if( (xcycle--) <= 0 )
+               {
+               xcycle = 15;
+               xx = sbrk(16*LBPG);     /*  get pages 16 at a time  */
+               if( (int)xx== -1 )
+                       lispend("For sbrk from lisp: no space... Goodbye!");
+               }
+       else xx += LBPG;
+
+       if(n == 0)
+       {
+           xcycle++;   /* don't allocate the page */
+           xx -= LBPG;
+           return(xx); /* just return its address */
+       }
+
+       if( (u = (lispval)(xx+LBPG))  > datalim ) datalim = u;
+       return(xx);
+       }
+
+char *ysbrk(pages,type) int pages, type;
+       {
+       char *xx;       /*  will point to block of storage  */
+       int i;
+
+       xx = sbrk(pages*LBPG);
+       if((int)xx == -1)
+               error("OUT OF SPACE FOR ARRAY REQUEST",FALSE);
+
+       datalim = (lispval)(xx+pages*LBPG);     /*  compute bit table limit  */
+
+       /*  set type for pages  */
+
+       for(i = 0; i < pages; ++i) {
+               SETTYPE((xx + i*LBPG),type,10);
+       }
+
+       return(xx);     /*  return pointer to block of storage  */
+       }
+       
+/*
+ * getatom 
+ * returns either an existing atom with the name specified in strbuf, or
+ * if the atom does not already exist, regurgitates a new one and 
+ * returns it.
+ */
+lispval
+getatom(purep)
+{   register lispval aptr;
+    register char *name, *endname;
+    register int hash;
+    lispval    b;
+    char       c;
+
+       name = strbuf;
+       if (*name == (char)0377) return (eofa);
+       hash = hashfcn(name);
+       atmlen = strlen(name) + 1;
+       aptr = (lispval) hasht[hash];
+       while (aptr != CNIL)
+           /* if (strcmp(name,aptr->a.pname)==0) */
+           if (*name==*aptr->a.pname && strcmp(name,aptr->a.pname)==0)
+               return (aptr);
+           else
+               aptr = (lispval) aptr->a.hshlnk;
+       aptr = (lispval) newatom(purep);  /*share pname of atoms on oblist*/
+       aptr->a.hshlnk = hasht[hash];
+       hasht[hash] = (struct atom *) aptr;
+       endname = name + atmlen - 2;
+       if ((atmlen != 4) && (*name == 'c') && (*endname == 'r'))
+               {
+               b = newdot();
+               protect(b);
+               b->d.car = lambda;
+               b->d.cdr = newdot();
+               b = b->d.cdr;
+               b->d.car = newdot();
+               (b->d.car)->d.car = xatom;
+               while(TRUE)
+                       {
+                       b->d.cdr = newdot();
+                       b= b->d.cdr;
+                       if(++name == endname)
+                               {
+                               b->d.car= (lispval) xatom;
+                               aptr->a.fnbnd = (--np)->val;
+                               break;
+                               }
+                       b->d.car= newdot();
+                       b= b->d.car;
+                       if((c = *name) == 'a') b->d.car = cara;
+                       else if (c == 'd') b->d.car = cdra;
+                       else{ --np;
+                          break;
+                        }
+                       }
+               }
+
+       return(aptr);
+       }
+
+/*
+ * inewatom is like getatom, except that you provide it a string
+ * to be used as the print name.  It doesn't do the automagic
+ * creation of things of the form c[ad]*r.
+ */
+lispval
+inewatom(name)
+register char *name;
+{   register struct atom *aptr;
+    register int hash;
+    extern struct types atom_str;
+    char       c;
+
+       if (*name == (char)0377) return (eofa);
+       hash = hashfcn(name);
+       aptr = hasht[hash];
+       while (aptr != (struct atom *)CNIL)
+           if (strcmp(name,aptr->pname)==0)
+               return ((lispval) aptr);
+           else
+               aptr = aptr->hshlnk;
+       aptr = (struct atom *) next_one(&atom_str) ;    
+       aptr->plist = aptr->fnbnd = nil;
+       aptr->clb = CNIL;
+       aptr->pname = name;
+       aptr->hshlnk = hasht[hash];
+       hasht[hash] = aptr;
+       return((lispval)aptr);
+}
+
+
+/* our hash function */
+
+hashfcn(symb)
+register char *symb;
+{
+       register int i;
+/*     for (i=0 ; *symb ; i += i + *symb++); return(i & (HASHTOP-1)); */
+       for (i=0 ; *symb ; i += i*2 + *symb++);
+       return(i&077777 % HASHTOP);
+}
+
+lispval
+LImemory()
+{
+    int nextadr, pagesinuse;
+    
+    printf("Memory report. max pages = %d (0x%x) = %d Bytes\n",
+               TTSIZE,TTSIZE,TTSIZE*LBPG);
+#ifdef HOLE
+        printf("This lisp has a hole:\n");
+       printf("  current hole start: %d (0x%x), end %d (0x%x)\n",
+               curhbeg, curhbeg, holend, holend);
+       printf("  hole free: %d bytes = %d pages\n\n",
+              holend-curhbeg, (holend-curhbeg)/LBPG);
+#endif 
+    nextadr = (int) xsbrk(0);  /* next space to be allocated */
+    pagesinuse = nextadr/LBPG;
+    printf("Next allocation at addr %d (0x%x) = page %d\n",
+                       nextadr, nextadr, pagesinuse);
+    printf("Free data pages: %d\n", TTSIZE-pagesinuse);
+    return(nil);
+}
+
+extern struct atom *hasht[HASHTOP];
+myhook(){}