BSD 3 development
[unix-history] / usr / src / cmd / lisp / Talloc.c
CommitLineData
b2e344ca
JF
1# include "global.h"
2
3# define NUMWORDS TTSIZE * 128 /* max number of words in P0 space */
4# define BITQUADS TTSIZE * 2 /* length of bit map in quad words */
5
6# define ftstbit asm(" ashl $-2,r11,r3");\
7 asm(" bbcs r3,_bitmapq,$1");\
8 asm(" .byte 4");
9/* define ftstbit if( readbit(p) ) return; oksetbit; */
10# define readbit(p) ((int)bitmap[r=(int)p>>5] & (s=bitmsk[((int)p>>2)&7]))
11# define lookbit(p) (bitmap[(int)p>>5] & bitmsk[((int)p>>2) & 7])
12# define setbit(p) {bitmap[(int)p>>5] |= bitmsk[((int)p >> 2) & 7];}
13# define oksetbit {bitmap[r] |= s;}
14
15# define readchk(p) ((int)bitfre[(int)p>>5] & bitmsk[((int)p>>2)&7])
16# define setchk(p) {bitfre[(int)p>>5] |= bitmsk[((int)p >> 2) & 7];}
17
18struct heads {
19 struct heads *link;
20 char *pntr;
21} header[TTSIZE];
22
23FILE * chkport; /* garbage collection dump file */
24lispval datalim; /* end of data space */
25double bitmapq[BITQUADS]; /* the bit map--one bit per long */
26double zeroq; /* a quad word of zeros */
27char *bitmap = (char *) bitmapq; /* byte version of bit map array */
28char bitmsk[8]={1,2,4,8,16,32,64,128}; /* used by bit-marking macros */
29int *bind_lists = (int *) CNIL; /* lisp data for compiled code */
30
31char *xsbrk();
32
33
34int atmlen;
35
36struct types {
37char *next_free;
38int space_left,
39 space,
40 type,
41 type_len; /* note type_len is in units of int */
42lispval *items,
43 *pages,
44 *type_name;
45struct heads
46 *first;
47} atom_str = {(char *)CNIL,0,ATOMSPP,ATOM,5,&atom_items,&atom_pages,&atom_name,(struct heads *)CNIL},
48 strng_str = {(char *)CNIL,0,STRSPP,STRNG,1,&str_items,&str_pages,&str_name,(struct heads *)CNIL},
49 int_str = {(char *)CNIL,0,INTSPP,INT,1,&int_items,&int_pages,&int_name,(struct heads *)CNIL},
50 dtpr_str = {(char *)CNIL,0,DTPRSPP,DTPR,2,&dtpr_items,&dtpr_pages,&dtpr_name,(struct heads *)CNIL},
51 doub_str = {(char *)CNIL,0,DOUBSPP,DOUB,2,&doub_items,&doub_pages,&doub_name,(struct heads *)CNIL},
52 array_str = {(char *)CNIL,0,ARRAYSPP,ARRAY,5,&array_items,&array_pages,&array_name,(struct heads *)CNIL},
53 sdot_str = {(char *)CNIL,0,SDOTSPP,SDOT,2,&sdot_items,&sdot_pages,&sdot_name,(struct heads *)CNIL},
54 val_str = {(char *)CNIL,0,VALSPP,VALUE,1,&val_items,&val_pages,&val_name,(struct heads *)CNIL},
55 funct_str = {(char *)CNIL,0,BCDSPP,BCD,2,&funct_items,&funct_pages,&funct_name,(struct heads *)CNIL};
56
57extern int initflag; /* starts off TRUE: initially gc not allowed */
58
59int gcflag = FALSE; /* TRUE during garbage collection */
60
61int current = 0; /* number of pages currently allocated */
62
63#define NUMSPACES 9
64
65static struct types *(spaces[NUMSPACES]) =
66 {&atom_str, &strng_str, &int_str,
67 &dtpr_str, &doub_str, &array_str,
68 &sdot_str, &val_str, &funct_str};
69
70
71/** get_more_space(type_struct) *****************************************/
72/* */
73/* Allocates and structures a new page, returning 0. */
74/* If no space is available, returns 1. */
75
76get_more_space(type_struct)
77struct types *type_struct;
78{
79 int cntr;
80 char *start;
81 int *loop, *temp;
82 lispval p, plim;
83 struct heads *next;
84
85 if(initflag == FALSE)
86 /* mustn't look at plist of plima too soon */
87 {
88 while( plim=copval(plima,(lispval)CNIL), TYPE(plim)!=INT )
89 copval(plima,error("BAD PAGE LIMIT",TRUE));
90 if( plim->i <= current ) return(1); /* Can't allocate */
91 }
92
93 if( current >= TTSIZE ) return(2);
94
95 start = xsbrk( NBPG );
96
97 /* bump the page counter for this space */
98
99 ++((*(type_struct->pages))->i);
100
101 SETTYPE(start, type_struct->type); /* set type of page */
102
103 type_struct->space_left = type_struct->space;
104 next = &header[ current++ ];
105 if ((type_struct->type)==STRNG)
106 {
107 type_struct->next_free = start;
108 return(0); /* space was available */
109 }
110 next->pntr = start;
111 next->link = type_struct->first;
112 type_struct->first = next;
113 temp = loop = (int *) start;
114 for(cntr=1; cntr < type_struct->space; cntr++)
115 loop = (int *) (*loop = (int) (loop + type_struct->type_len));
116 *loop = (int) (type_struct->next_free);
117 type_struct->next_free = (char *) temp;
118
119 /* if type atom, set pnames to CNIL */
120
121 if( type_struct == &atom_str )
122 for(cntr=0, p=(lispval) temp; cntr<atom_str.space; ++cntr)
123 {
124 p->pname = (char *) CNIL;
125 p = (lispval) ((int *)p + atom_str.type_len);
126 }
127 return(0); /* space was available */
128}
129
130
131/** next_one(type_struct) ************************************************/
132/* */
133/* Allocates one new item of each kind of space, except STRNG. */
134/* If there is no space, calls gc, the garbage collector. */
135/* If there is still no space, allocates a new page using */
136/* get_more_space(type_struct) */
137
138lispval
139next_one(type_struct)
140struct types *type_struct;
141{
142
143 register char *temp;
144 snpand(1);
145
146 while(type_struct->next_free == (char *) CNIL)
147 {
148 int g;
149
150 if((type_struct->type != ATOM) && /* can't collect atoms */
151 (type_struct->type != STRNG) && /* can't collect strings */
152 (gcthresh->i <= current) && /* threshhold for gc */
153 ISNIL(copval(gcdis,CNIL)) && /* gc not disabled */
154 (NOTNIL(copval(gcload,CNIL)) || (loading->clb != tatom)) &&
155 /* not to collect during load */
156 (initflag == FALSE) && /* dont gc during init */
157 (gcflag == FALSE)) /* don't recurse gc */
158
159 {
160 /* fputs("Collecting",poport);
161 dmpport(poport);*/
162 gc(type_struct); /* collect */
163 }
164
165 if( type_struct->next_free != (char *) CNIL ) break;
166
167 if(! (g=get_more_space(type_struct))) break;
168
169 if( g==1 )
170 {
171 plimit->i = current+NUMSPACES;
172 /* allow a few more pages */
173 copval(plima,plimit); /* restore to reserved reg */
174
175 error("PAGE LIMIT EXCEEDED--EMERGENCY PAGES ALLOCATED",
176 TRUE);
177 }
178 else error("SORRY, ABSOLUTE PAGE LIMIT HAS BEEN REACHED",
179 TRUE);
180 }
181
182 temp = type_struct->next_free;
183 type_struct->next_free = * (char **)(type_struct->next_free);
184 return((lispval) temp);
185}
186
187lispval
188newint()
189{
190 ++(int_items->i);
191 return(next_one(&int_str));
192}
193
194lispval
195newdot()
196{
197 lispval temp;
198
199 ++(dtpr_items->i);
200 temp = next_one(&dtpr_str);
201 temp->car = temp->cdr = nil;
202 return(temp);
203}
204
205lispval
206newdoub()
207{
208 ++(doub_items->i);
209 return(next_one(&doub_str));
210}
211
212lispval
213newsdot()
214{
215 register lispval temp;
216 ++(dtpr_items->i);
217 temp = next_one(&sdot_str);
218 temp->car = temp->cdr = 0;
219 return(temp);
220}
221
222struct atom *newatom() {
223 struct atom *save;
224
225 ++(atom_items->i);
226 save = (struct atom *) next_one(&atom_str) ;
227 save->plist = save->fnbnd = nil;
228 save->hshlnk = (struct atom *)CNIL;
229 save->clb = CNIL;
230 save->pname = newstr();
231 return (save);
232}
233
234char *newstr() {
235 char *save;
236 int atmlen2;
237
238 ++(str_items->i);
239 atmlen = strlen(strbuf)+1;
240 if(atmlen > strng_str.space_left)
241 while(get_more_space(&strng_str))
242 error("YOU HAVE RUN OUT OF SPACE",TRUE);
243 strcpy((save = strng_str.next_free), strbuf);
244 atmlen2 = atmlen;
245 while(atmlen2 % 4) ++atmlen2; /* even up length of string */
246 strng_str.next_free += atmlen2;
247 strng_str.space_left -= atmlen2;
248 return(save);
249}
250
251char *inewstr(s) char *s;
252{
253 strbuf[STRBLEN-1] = '\0';
254 strcpyn(strbuf,s,STRBLEN-1);
255 return(newstr());
256}
257
258lispval
259newarray()
260 {
261 register lispval temp;
262 ++(array_items->i);
263 temp = next_one(&array_str);
264 temp->data = (char *)nil;
265 temp->accfun = nil;
266 temp->aux = nil;
267 temp->length = SMALL(0);
268 temp->delta = SMALL(0);
269 return(temp);
270 }
271
272lispval
273badcall()
274 { error("BAD FUNCTION DESCRIPTOR USED IN CALL",FALSE); }
275
276lispval
277newfunct()
278 {
279 register lispval temp;
280 ++(funct_items->i);
281 temp = next_one(&funct_str);
282 temp->entry = badcall;
283 temp->discipline = nil;
284 return(temp);
285 }
286
287lispval
288newval()
289 {
290 register lispval temp;
291 ++(val_items->i);
292 temp = next_one(&val_str);
293 temp->l = nil;
294 return(temp);
295 }
296
297lispval
298inewval(arg) lispval arg;
299 {
300 lispval temp;
301 ++(val_items->i);
302 temp = next_one(&val_str);
303 temp->l = arg;
304 return(temp);
305 }
306
307/** Ngc *****************************************************************/
308/* */
309/* LISP interface to gc. */
310
311lispval Ngc()
312 {
313 lispval temp;
314
315 if( ISNIL(lbot->val) ) return(gc(CNIL));
316
317 if( TYPE(lbot->val) != DTPR ) error("BAD CALL TO GC",FALSE);
318
319 chkport = poport;
320
321 if( NOTNIL(lbot->val->car) )
322 {
323 temp = eval(lbot->val->car);
324 if( TYPE(temp) == PORT ) chkport = (FILE *)*temp;
325 }
326
327 gc1(TRUE);
328
329 return(nil);
330 }
331
332/** gc(type_struct) *****************************************************/
333/* */
334/* garbage collector: Collects garbage by mark and sweep algorithm. */
335/* After this is done, calls the Nlambda, gcafter. */
336/* gc may also be called from LISP, as a lambda of no arguments. */
337
338lispval
339gc(type_struct)
340 struct types *type_struct;
341 {
342 lispval save;
343 struct {
344 long mytime;
345 long allelse[3];
346 } begin, finish;
347 extern int GCtime;
348
349 save = copval(gcport,CNIL);
350 if(GCtime)
351 times(&begin);
352
353 while( (TYPE(save) != PORT) && NOTNIL(save))
354 save = error("NEED PORT FOR GC",TRUE);
355
356 chkport = ISNIL(save) ? poport : (FILE *)*save;
357
358 gc1(NOTNIL(copval(gccheck,CNIL)) || (chkport!=poport)); /* mark&sweep */
359
360 /* Now we call gcafter--special case if gc called from LISP */
361
362 if( type_struct == (struct types *) CNIL )
363 gccall1->cdr = nil; /* make the call "(gcafter)" */
364 else
365 {
366 gccall1->cdr = gccall2;
367 gccall2->car = *(type_struct->type_name);
368 }
369 gcflag = TRUE; /* flag to indicate in garbage collector */
370 save = eval(gccall1); /* call gcafter */
371 gcflag = FALSE; /* turn off flag */
372
373 if(GCtime) {
374 times(&finish);
375 GCtime += (finish.mytime - begin.mytime);
376 }
377 return(save); /* return result of gcafter */
378 }
379
380
381
382/* gc1() **************************************************************/
383/* */
384/* Mark-and-sweep phase */
385
386gc1(chkflag) int chkflag;
387 {
388 int i, j, typep;
389 register int *start, *point;
390 struct types *s;
391 struct heads *loop;
392 struct argent *loop2;
393 int markdp();
394
395
396 /* decide whether to check LISP structure or not */
397
398
399
400
401 /* first set all bit maps to zero */
402
403 for(i=0; i<((int)datalim >> 8); ++i) bitmapq[i] = zeroq;
404
405
406 /* then mark all atoms' plists, clbs, and function bindings */
407
408 for(loop=atom_str.first; loop!=(struct heads *)CNIL; loop=loop->link)
409 for(start=(int *)(loop->pntr), i=1;
410 i <= atom_str.space;
411 start = start + atom_str.type_len, ++i)
412 {
413
414 /* unused atoms are marked with pname == CNIL */
415 /* this is done by get_more_space, as well as */
416 /* by gc (in the future) */
417
418 if(((lispval)start)->pname == (char *)CNIL) continue;
419#define MARKSUB(p) if(nil!=((lispval)start)->p)markdp(((lispval)start)->p);
420 MARKSUB(clb);
421 MARKSUB(fnbnd);
422 MARKSUB(plist);
423 }
424
425 /* next run up the name stack */
426
427 for(loop2 = np - 1; loop2 >= orgnp; --loop2) markdp((loop2->val));
428 /* from TBL 29july79 */
429 /* next mark all compiler linked data */
430 point = bind_lists;
431 while((start = point) != (int *)CNIL) {
432 while( *start != -1 )
433 markdp(*start++);
434 point = (int *)*(point-1);
435 }
436 /* end from TBL */
437
438 /* next mark all system-significant lisp data */
439
440 for(i=0; i<SIGNIF; ++i) markdp((lispsys[i]));
441
442 /* all accessible data has now been marked. */
443 /* all collectable spaces must be swept, */
444 /* and freelists constructed. */
445
446 for(i=0; i<NUMSPACES; ++i)
447 {
448 /* STRINGS do not participate. */
449 /* ATOMS dont either (currently) */
450
451 s = spaces[i];
452 typep = s->type;
453 if((typep==STRNG) || (typep==ATOM)) continue;
454
455 s->space_left = 0; /* we will count free cells */
456 (*(s->items))->i = 0; /* and compute cells used */
457
458 /* for each space, traverse list of pages. */
459
460 s->next_free = (char *) CNIL; /* reinitialize free list */
461
462 for(loop = s->first; loop != (struct heads *) CNIL; loop=loop->link)
463 {
464 /* add another page's worth to use count */
465
466 (*(s->items))->i += s->space;
467
468 /* for each page, make a list of unmarked data */
469
470 for(j=0, point=(int *)(loop->pntr);
471 j<s->space; ++j, point += s->type_len)
472 if( ! lookbit(point) )
473 {
474 /* add to free list */
475 /* update pointer to free list*/
476 /* update count of free list */
477
478 *point = (int)(s->next_free);
479 s->next_free = (char *) point;
480 ++(s->space_left);
481 }
482 }
483 (*(s->items))->i -= s->space_left; /* compute cells used */
484 }
485}
486
487/** alloc() *************************************************************/
488/* */
489/* This routine tries to allocate one more page of the space named */
490/* by the argument. If no more space is available returns 1, else 0. */
491
492lispval
493alloc(tname,npages)
494 lispval tname; int npages;
495 {
496 int ii, jj;
497
498 ii = typenum(tname);
499
500 for( jj=0; jj<npages; ++jj)
501 if(get_more_space(spaces[ii])) break;
502 return(inewint(jj));
503 }
504
505lispval
506csegment(tname,nitems)
507lispval tname; int nitems;
508 {
509 int ii, jj;
510 char *charadd;
511
512 ii = typenum(tname);
513
514 nitems = nitems*4*spaces[ii]->type_len; /* find c-length of space */
515 while( nitems%512 ) ++nitems; /* round up to right length */
516 current += nitems/512;
517 charadd = sbrk(nitems);
518 if( (int) charadd == 0 )
519 error("NOT ENOUGH SPACE FOR ARRAY",FALSE);
520 (datalim = (lispval)(charadd+nitems));
521 if((((int)datalim) >> 9) > TTSIZE) {
522 datalim = (lispval) (TTSIZE << 9);
523 badmem(53);
524 }
525 for(jj=0; jj<nitems; jj=jj+512) {
526 SETTYPE(charadd+jj, spaces[ii]->type);
527 }
528 return((lispval)charadd);
529 }
530
531int csizeof(tname) lispval tname;
532 {
533 return( spaces[typenum(tname)]->type_len * 4 );
534 }
535
536int typenum(tname) lispval tname;
537 {
538 int ii;
539
540chek: for(ii=0; ii<NUMSPACES; ++ii)
541 if(tname == *(spaces[ii]->type_name)) break;
542 if(ii == NUMSPACES)
543 {
544 tname = error("BAD TYPE NAME",TRUE);
545 goto chek;
546 }
547
548 return(ii);
549 }
550
551/** markit(p) ***********************************************************/
552/* just calls markdp */
553
554markit(p) lispval *p; { markdp(*p); }
555
556/** markdp(p) ***********************************************************/
557/* */
558/* markdp is the routine which marks each data item. If it is a */
559/* dotted pair, the car and cdr are marked also. */
560/* An iterative method is used to mark list structure, to avoid */
561/* excessive recursion. */
562
563
564markdp(p) register lispval p;
565 {
566/* register int r, s; (goes with non-asm readbit, oksetbit) */
567
568ptr_loop:
569 if((int)p <= 0) return; /* do not mark special data types or nil=0 */
570
571 switch( TYPE(p) )
572 {
573 case INT:
574 case DOUB:
575/* setbit(p);*/
576 ftstbit;
577 return;
578 case VALUE:
579 ftstbit;
580 p = p->l;
581 goto ptr_loop;
582 case DTPR:
583 ftstbit;
584 markdp(p->car);
585 p = p->cdr;
586 goto ptr_loop;
587
588 case ARRAY:
589 ftstbit; /* mark array itself */
590
591 markdp(p->accfun); /* mark access function */
592 markdp(p->aux); /* mark aux data */
593 markdp(p->length); /* mark length */
594 markdp(p->delta); /* mark delta */
595
596 {
597 register int i, l; int d;
598 register char *dataptr = p->data;
599
600 for(i=0, l=p->length->i, d=p->delta->i; i<l; ++i)
601 {
602 markdp(dataptr);
603 dataptr += d;
604 }
605 return;
606 }
607 case SDOT:
608 do {
609 ftstbit;
610 p = p->CDR;
611 } while (p!=0);
612 return;
613
614 case BCD:
615 ftstbit;
616 markdp(p->discipline);
617 return;
618 }
619 return;
620 }
621
622
623
624char *
625xsbrk()
626 {
627 static char *xx; /* pointer to next available blank page */
628 static int cycle = 0; /* number of blank pages available */
629 lispval u; /* used to compute limits of bit table */
630
631 if( (cycle--) <= 0 )
632 {
633 cycle = 15;
634 xx = sbrk(16*NBPG); /* get pages 16 at a time */
635 if( (int)xx== -1 )
636 lispend("For sbrk from lisp: no space... Goodbye!");
637 goto done;
638 }
639 xx += NBPG;
640done: if( (u = (lispval)(xx+NBPG)) > datalim ) datalim = u;
641 return(xx);
642 }
643
644char *ysbrk(pages,type) int pages, type;
645 {
646 char *xx; /* will point to block of storage */
647 int i;
648
649 xx = sbrk(pages*NBPG);
650 if((int)xx == -1)
651 error("OUT OF SPACE FOR ARRAY REQUEST",FALSE);
652
653 datalim = (lispval)(xx+pages*NBPG); /* compute bit table limit */
654
655 /* set type for pages */
656
657 for(i = 0; i < pages; ++i) {
658 SETTYPE((xx + i*NBPG),type);
659 }
660
661 return(xx); /* return pointer to block of storage */
662 }
663
664/* getatom **************************************************************/
665/* returns either an existing atom with the name specified in strbuf, or*/
666/* if the atom does not already exist, regurgitates a new one and */
667/* returns it. */
668lispval
669getatom()
670{ register lispval aptr;
671 register char *name, *endname;
672 lispval b;
673 char c;
674 register int hash;
675 snpand(4);
676
677 name = strbuf;
678 if (*name == (char)0377) return (eofa);
679 hash = 0;
680 for(name=strbuf; *name;) {
681 hash ^= *name++;
682 }
683 hash &= 0177; /* make sure no high-order bits have crept in */
684 atmlen = name - strbuf + 1;
685 aptr = (lispval) hasht[hash];
686 while (aptr != CNIL)
687 if (strcmp(strbuf,aptr->pname)==0)
688 return (aptr);
689 else
690 aptr = (lispval) aptr->hshlnk;
691 aptr = (lispval) newatom();
692 aptr->hshlnk = hasht[hash];
693 hasht[hash] = (struct atom *) aptr;
694 endname = name - 1;
695 name = strbuf;
696 if ((atmlen != 4) && (*name == 'c') && (*endname == 'r'))
697 {
698 b = newdot();
699 protect(b);
700 b->car = lambda;
701 b->cdr = newdot();
702 b = b->cdr;
703 b->car = newdot();
704 (b->car)->car = xatom;
705 while(TRUE)
706 {
707 b->cdr = newdot();
708 b= b->cdr;
709 if(++name == endname)
710 {
711 b->car= (lispval) xatom;
712 aptr->fnbnd = unprot();
713 break;
714 }
715 b->car= newdot();
716 b= b->car;
717 if((c = *name) == 'a') b->car = cara;
718 else if (c == 'd') b->car = cdra;
719 else{ unprot();
720 break;
721 }
722 }
723 }
724
725 return(aptr);
726 }
727