|
|
1.1 root 1: /*
2: * File: rmemmgt.c
3: * Contents: allocation routines, block description arrays, dump routines,
4: * garbage collaction, sweep, malloc/free
5: */
6:
7: #include "../h/rt.h"
8: #include "gc.h"
9:
10: #ifdef IconAlloc
11: /*
12: * If IconAlloc is defined the system allocation routines are not overloaded.
13: * The names are changed so that Icon's allocation routines are independently
14: * used. This works as long as no other system calls cause the break value
15: * to change.
16: */
17: #define malloc mem_alloc
18: #define free mem_free
19: #define realloc mem_realloc
20: #define calloc mem_calloc
21: #endif IconAlloc
22:
23: #ifdef RunStats
24: #ifndef VMS
25: #include <sys/types.h>
26: #include <sys/times.h>
27: #else VMS
28: #include <types.h>
29: #include <types.h>
30: struct tms {
31: time_t tms_utime; /* user time */
32: time_t tms_stime; /* system time */
33: time_t tms_cutime; /* user time, children */
34: time_t tms_cstime; /* system time, children */
35: };
36: #endif VMS
37: #endif RunStats
38:
39: /*
40: * Note: function calls beginning with "MM" are just empty macros
41: * unless MEMMON is defined.
42: */
43:
44: /*
45: * allocate - returns pointer to nbytes of free storage in block region.
46: */
47:
48: static union block *allocate(nbytes)
49: word nbytes;
50: {
51: register uword fspace, *sloc;
52:
53: Inc(al_n_total);
54: IncSum(al_bc_btotal,nbytes);
55: /*
56: * See if there is enough room in the block region.
57: */
58: fspace = maxblk - blkfree;
59: if (fspace < nbytes)
60: syserr("block allocation botch");
61:
62: /*
63: * If monitoring, show the allocation.
64: */
65: MMAlc(nbytes);
66:
67: /*
68: * Decrement the free space in the block region by the number of bytes allocated
69: * and return the address of the first byte of the allocated block.
70: */
71: sloc = (uword *) blkfree;
72: blkneed -= nbytes;
73: blkfree = blkfree + nbytes;
74: return (union block *) (sloc);
75: }
76:
77: /*
78: * alclint - allocate a long integer block in the block region.
79: */
80:
81: struct b_int *alclint(val)
82: long val;
83: {
84: register struct b_int *blk;
85: extern union block *allocate();
86:
87: MMType(T_Longint);
88: blk = (struct b_int *)allocate((word)sizeof(struct b_int));
89: blk->title = T_Longint;
90: blk->intval = val;
91: return blk;
92: }
93:
94: /*
95: * alcreal - allocate a real value in the block region.
96: */
97:
98: struct b_real *alcreal(val)
99: double val;
100: {
101: register struct b_real *blk;
102: extern union block *allocate();
103:
104: Inc(al_n_real);
105: MMType(T_Real);
106: blk = (struct b_real *) allocate((word)sizeof(struct b_real));
107: blk->title = T_Real;
108: #ifdef Double
109: /* access real values one word at a time */
110: { int *rp, *rq;
111: rp = (word *) &(blk->realval);
112: rq = (word *) &val;
113: *rp++ = *rq++;
114: *rp = *rq;
115: }
116: #else Double
117: blk->realval = val;
118: #endif Double
119: return blk;
120: }
121:
122: /*
123: * alccset - allocate a cset in the block region.
124: */
125:
126: /* >alccset */
127: struct b_cset *alccset(size)
128: int size;
129: {
130: register struct b_cset *blk;
131: register i;
132: extern union block *allocate();
133:
134: Inc(al_n_cset);
135: MMType(T_Cset);
136: blk = (struct b_cset *) allocate((word)sizeof(struct b_cset));
137: blk->title = T_Cset;
138: blk->size = size;
139: /*
140: * Zero the bit array.
141: */
142: for (i = 0; i < CsetSize; i++)
143: blk->bits[i] = 0;
144: return blk;
145: }
146: /* <alccset */
147:
148:
149: /*
150: * alcfile - allocate a file block in the block region.
151: */
152:
153: struct b_file *alcfile(fd, status, name)
154: FILE *fd;
155: int status;
156: struct descrip *name;
157: {
158: register struct b_file *blk;
159: extern union block *allocate();
160:
161: Inc(al_n_file);
162: MMType(T_File);
163: blk = (struct b_file *) allocate((word)sizeof(struct b_file));
164: blk->title = T_File;
165: blk->fd = fd;
166: blk->status = status;
167: blk->fname = *name;
168: return blk;
169: }
170:
171: /*
172: * alcrecd - allocate record with nflds fields in the block region.
173: */
174:
175: struct b_record *alcrecd(nflds, recptr)
176: int nflds;
177: struct descrip *recptr;
178: {
179: register struct b_record *blk;
180: register i, size;
181: extern union block *allocate();
182:
183: Inc(al_n_recd);
184: MMType(T_Record);
185: size = Vsizeof(struct b_record) + nflds*sizeof(struct descrip);
186: blk = (struct b_record *) allocate((word)size);
187: blk->title = T_Record;
188: blk->blksize = size;
189: blk->recdesc.dword = D_Proc;
190: BlkLoc(blk->recdesc) = (union block *)recptr;
191: /*
192: * Assign &null to each field in the record.
193: */
194: for (i = 0; i < nflds; i++)
195: blk->fields[i] = nulldesc;
196: return blk;
197: }
198:
199: /*
200: * alclist - allocate a list header block in the block region.
201: */
202:
203: struct b_list *alclist(size)
204: word size;
205: {
206: register struct b_list *blk;
207: extern union block *allocate();
208:
209: Inc(al_n_list);
210: MMType(T_List);
211: blk = (struct b_list *) allocate((word)sizeof(struct b_list));
212: blk->title = T_List;
213: blk->size = size;
214: blk->listhead = nulldesc;
215: return blk;
216: }
217:
218: /*
219: * alclstb - allocate a list element block in the block region.
220: */
221:
222: struct b_lelem *alclstb(nelem, first, nused)
223: word nelem, first, nused;
224: {
225: register struct b_lelem *blk;
226: register word i, size;
227: extern union block *allocate();
228:
229: Inc(al_n_lstb);
230: MMType(T_Lelem);
231: #ifdef MaxListSize
232: if (nelem >= MaxListSize)
233: runerr(205, NULL);
234: #endif MaxListSize
235: size = Vsizeof(struct b_lelem)+nelem*sizeof(struct descrip);
236: blk = (struct b_lelem *) allocate(size);
237: blk->title = T_Lelem;
238: blk->blksize = size;
239: blk->nelem = nelem;
240: blk->first = first;
241: blk->nused = nused;
242: blk->listprev = nulldesc;
243: blk->listnext = nulldesc;
244: /*
245: * Set all elements to &null.
246: */
247: for (i = 0; i < nelem; i++)
248: blk->lslots[i] = nulldesc;
249: return blk;
250: }
251:
252: /*
253: * alctable - allocate a table header block in the block region.
254: */
255:
256: struct b_table *alctable(def)
257: struct descrip *def;
258: {
259: register int i;
260: register struct b_table *blk;
261: extern union block *allocate();
262:
263: Inc(al_n_table);
264: MMType(T_Table);
265: blk = (struct b_table *) allocate((word)sizeof(struct b_table));
266: blk->title = T_Table;
267: blk->size = 0;
268: blk->defvalue = *def;
269: /*
270: * Zero out the buckets.
271: */
272: for (i = 0; i < TSlots; i++)
273: blk->buckets[i] = nulldesc;
274: return blk;
275: }
276:
277: /*
278: * alctelem - allocate a table element block in the block region.
279: */
280:
281: struct b_telem *alctelem()
282: {
283: register struct b_telem *blk;
284: extern union block *allocate();
285:
286: Inc(al_n_telem);
287: MMType(T_Telem);
288: blk = (struct b_telem *) allocate((word)sizeof(struct b_telem));
289: blk->title = T_Telem;
290: blk->hashnum = 0;
291: blk->clink = nulldesc;
292: blk->tref = nulldesc;
293: blk->tval = nulldesc;
294: return blk;
295: }
296:
297: /*
298: * alcset - allocate a set header block.
299: */
300:
301: struct b_set *alcset()
302: {
303: register int i;
304: register struct b_set *blk;
305: extern union block *allocate();
306:
307: MMType(T_Set);
308: blk = (struct b_set *) allocate((word)sizeof(struct b_set));
309: blk->title = T_Set;
310: blk->size = 0;
311: /*
312: * Zero out the buckets.
313: */
314: for (i = 0; i < SSlots; i++)
315: blk->sbucks[i] = nulldesc;
316: return blk;
317: }
318:
319: /*
320: * alcselem - allocate a set element block.
321: */
322:
323: struct b_selem *alcselem(mbr,hn)
324: word hn;
325: struct descrip *mbr;
326:
327: { register struct b_selem *blk;
328: extern union block *allocate();
329:
330: MMType(T_Selem);
331: blk = (struct b_selem *) allocate((word)sizeof(struct b_selem));
332: blk->title = T_Selem;
333: blk->clink = nulldesc;
334: blk->setmem = *mbr;
335: blk->hashnum = hn;
336: return blk;
337: }
338:
339: /*
340: * alcsubs - allocate a substring trapped variable in the block region.
341: */
342:
343: struct b_tvsubs *alcsubs(len, pos, var)
344: word len, pos;
345: struct descrip *var;
346: {
347: register struct b_tvsubs *blk;
348: extern union block *allocate();
349:
350: Inc(al_n_subs);
351: MMType(T_Tvsubs);
352: blk = (struct b_tvsubs *) allocate((word)sizeof(struct b_tvsubs));
353: blk->title = T_Tvsubs;
354: blk->sslen = len;
355: blk->sspos = pos;
356: blk->ssvar = *var;
357: return blk;
358: }
359:
360: /*
361: * alctvtbl - allocate a table element trapped variable block in the block region.
362: */
363:
364: struct b_tvtbl *alctvtbl(tbl, ref, hashnum)
365: register struct descrip *tbl, *ref;
366: word hashnum;
367: {
368: register struct b_tvtbl *blk;
369: extern union block *allocate();
370:
371: Inc(al_n_tvtbl);
372: MMType(T_Tvtbl);
373: blk = (struct b_tvtbl *) allocate((word)sizeof(struct b_tvtbl));
374: blk->title = T_Tvtbl;
375: blk->hashnum = hashnum;
376: blk->clink = *tbl;
377: blk->tref = *ref;
378: blk->tval = nulldesc;
379: return blk;
380: }
381:
382: /*
383: * alcstr - allocate a string in the string space.
384: */
385:
386: /* >alcstr */
387: char *alcstr(s, slen)
388: register char *s;
389: register word slen;
390: {
391: register char *d;
392: char *ofree;
393:
394: Inc(al_n_str);
395: IncSum(al_bc_stotal,slen);
396: MMStr(slen);
397: /*
398: * See if there is enough room in the string space.
399: */
400: if (strfree + slen > strend)
401: syserr("string allocation botch");
402: strneed -= slen;
403:
404: /*
405: * Copy the string into the string space, saving a pointer to its
406: * beginning. Note that s may be null, in which case the space
407: * is still to be allocated but nothing is to be copied into it.
408: */
409: ofree = d = strfree;
410: if (s != NULL) {
411: while (slen-- > 0)
412: *d++ = *s++;
413: }
414: else
415: d += slen;
416: strfree = d;
417: return ofree;
418: }
419: /* <alcstr */
420:
421: /*
422: * alcstk - allocate a co-expression stack block.
423: */
424:
425: struct b_coexpr *alcstk()
426: {
427: struct b_coexpr *ep;
428: char *malloc();
429:
430: Inc(al_n_estk);
431: ep = (struct b_coexpr *)malloc(stksize);
432: ep->title = T_Coexpr;
433: return ep;
434: }
435:
436: /*
437: * alceblk - allocate a co-expression block.
438: */
439:
440: struct b_refresh *alceblk(entryx, na, nl)
441: word *entryx;
442: int na, nl;
443: {
444: int size;
445: struct b_refresh *blk;
446: extern union block *allocate();
447:
448: Inc(al_n_eblk);
449: MMType(T_Refresh);
450: size = Vsizeof(struct b_refresh) + (na + nl) * sizeof(struct descrip);
451: blk = (struct b_refresh *) allocate((word)size);
452: blk->title = T_Refresh;
453: blk->blksize = size;
454: blk->ep = entryx;
455: blk->numlocals = nl;
456: return blk;
457: }
458:
459:
460: /*
461: * Allocated block size table (sizes given in bytes). A size of -1 is used
462: * for types that have no blocks; a size of 0 indicates that the
463: * second word of the block contains the size; a value greater than
464: * 0 is used for types with constant sized blocks.
465: */
466:
467: int bsizes[] = {
468: -1, /* 0, not used */
469: -1, /* 1, not used */
470: sizeof(struct b_int), /* T_Longint (2), long integer type */
471: sizeof(struct b_real), /* T_Real (3), real number */
472: sizeof(struct b_cset), /* T_Cset (4), cset */
473: sizeof(struct b_file), /* T_File (5), file block */
474: 0, /* T_Proc (6), procedure block */
475: sizeof(struct b_list), /* T_List (7), list header block */
476: sizeof(struct b_table), /* T_Table (8), table header block */
477: 0, /* T_Record (9), record block */
478: sizeof(struct b_telem), /* T_Telem (10), table element block */
479: 0, /* T_Lelem (11), list element block */
480: sizeof(struct b_tvsubs), /* T_Tvsubs (12), substring trapped variable */
481: -1, /* T_Tvkywd (13), keyword trapped variable */
482: sizeof(struct b_tvtbl), /* T_Tvtbl (14), table element trapped variable */
483: sizeof(struct b_set), /* T_Set (15), set header block */
484: sizeof(struct b_selem), /* T_Selem (16), set element block */
485: 0, /* T_Refresh (17), expression block */
486: -1, /* T_Coexpr (18), expression stack header */
487: };
488:
489: /*
490: * Table of offsets (in bytes) to first descriptor in blocks. -1 is for
491: * types not allocated, 0 for blocks with no descriptors.
492: */
493: int firstd[] = {
494: -1, /* 0, not used */
495: -1, /* 1, not used */
496: 0, /* T_Longint (2), long integer type */
497: 0, /* T_Real (3), real number */
498: 0, /* T_Cset (4), cset */
499: 3*WordSize, /* T_File (5), file block */
500: 8*WordSize, /* T_Proc (6), procedure block */
501: 2*WordSize, /* T_List (7), list header block */
502: 2*WordSize, /* T_Table (8), table header block */
503: 2*WordSize, /* T_Record (9), record block */
504: 2*WordSize, /* T_Telem (10), table element block */
505: 5*WordSize, /* T_Lelem (11), list element block */
506: 3*WordSize, /* T_Tvsubs (12), substring trapped variable */
507: -1, /* T_Tvkywd (13), keyword trapped variable */
508: 2*WordSize, /* T_Tvtbl (14), table element trapped variable */
509: 2*WordSize, /* T_Set (15), set header block */
510: 2*WordSize, /* T_Selem (16), set element block */
511: (4+Vwsizeof(struct pf_marker))*WordSize,
512: /* T_Refresh (17), expression block */
513: -1, /* T_Coexpr (18), expression stack header */
514: };
515:
516: /*
517: * Table of block names used by debugging functions.
518: */
519: char *blkname[] = {
520: "illegal", /* T_Null (0), not block */
521: "illegal", /* T_Integer (1), not block */
522: "long integer", /* T_Longint (2) */
523: "real number", /* T_Real (3) */
524: "cset", /* T_Cset (4) */
525: "file", /* T_File (5) */
526: "procedure", /* T_Proc (6) */
527: "list", /* T_List (7) */
528: "table", /* T_Table (8) */
529: "record", /* T_Record (9) */
530: "table element", /* T_Telem (10) */
531: "list element", /* T_Lelem (11) */
532: "substring trapped variable", /* T_Tvsubs (12) */
533: "keyword trapped variable", /* T_Tvkywd (13) */
534: "table element trapped variable", /* T_Tvtbl (14) */
535: "set", /* T_Set (15) */
536: "set elememt", /* T_Selem (16) */
537: "refresh", /* T_Refresh (17) */
538: "co-expression", /* T_Coexpr (18) */
539: };
540:
541:
542: /*
543: * descr - dump a descriptor. Used only for debugging.
544: */
545:
546: descr(dp)
547: struct descrip *dp;
548: {
549: int i;
550:
551: fprintf(stderr,"%08lx: ",(long)dp);
552: if (Qual(*dp))
553: fprintf(stderr,"%15s","qualifier");
554: else if (Var(*dp) && !Tvar(*dp))
555: fprintf(stderr,"%15s","variable");
556: else {
557: i = Type(*dp);
558: switch (i) {
559: case T_Null:
560: fprintf(stderr,"%15s","null");
561: break;
562: case T_Integer:
563: fprintf(stderr,"%15s","integer");
564: break;
565: default:
566: fprintf(stderr,"%15s",blkname[i]);
567: }
568: }
569: fprintf(stderr," %08lx %08lx\n",(long)dp->dword,(long)dp->vword.integr);
570: }
571:
572: /*
573: * blkdump - dump the allocated block region. Used only for debugging.
574: */
575:
576: blkdump()
577: {
578: register char *blk;
579: register word type, size, fdesc;
580: register struct descrip *ndesc;
581:
582: fprintf(stderr,"\nDump of allocated block region. base:%08lx free:%08lx max:%08lx\n",
583: (long)blkbase,(long)blkfree,(long)maxblk);
584: fprintf(stderr," loc type size contents\n");
585:
586: for (blk = blkbase; blk < blkfree; blk += BlkSize(blk)) {
587: type = BlkType(blk);
588: size = BlkSize(blk);
589: fprintf(stderr," %08lx %15s %4ld\n",(long)blk,blkname[type],(long)size);
590: if ((fdesc = firstd[type]) > 0)
591: for (ndesc = (struct descrip *) (blk + fdesc);
592: ndesc < (struct descrip *) (blk + size);ndesc++) {
593: fprintf(stderr," ");
594: descr(ndesc);
595: }
596: fprintf(stderr,"\n");
597: }
598: fprintf(stderr,"end of block region.\n");
599: }
600:
601:
602: /*
603: * blkreq - insure that at least bytes of space are left in the block region.
604: * The amount of space needed is transmitted to the collector via
605: * the global variable blkneed.
606: */
607:
608: blkreq(bytes)
609: uword bytes;
610: {
611: blkneed = bytes;
612: if (bytes > maxblk - blkfree) {
613: Inc(gc_n_blk);
614: collect();
615: }
616: }
617:
618: /*
619: * strreq - insure that at least n of space are left in the string
620: * space. The amount of space needed is transmitted to the collector
621: * via the global variable strneed.
622: */
623:
624: /* >strreq */
625: strreq(n)
626: uword n;
627: {
628: strneed = n; /* save in case of collection */
629: if (n > strend - strfree) {
630: Inc(gc_n_string);
631: collect();
632: }
633: }
634: /* <strreq */
635:
636: /*
637: * cofree - collect co-expression blocks. This is done after
638: * the marking phase of garbage collection and the stacks that are
639: * reachable have pointers to data blocks, rather than T_Coexpr,
640: * in their type field.
641: */
642:
643: /* >cofree */
644: cofree()
645: {
646: register struct b_coexpr **ep, *xep;
647:
648: /*
649: * Reset the type for &main.
650: */
651: BlkLoc(k_main)->coexpr.title = T_Coexpr;
652:
653: /*
654: * The co-expression blocks are linked together through their
655: * nextstk fields, with stklist pointing to the head of the list.
656: * The list is traversed and each stack that was not marked
657: * is freed.
658: */
659: ep = &stklist;
660: while (*ep != NULL) {
661: if (BlkType(*ep) == T_Coexpr) {
662: xep = *ep;
663: *ep = (*ep)->nextstk;
664: free((char *)xep);
665: }
666: else {
667: BlkType(*ep) = T_Coexpr;
668: ep = &(*ep)->nextstk;
669: }
670: }
671: }
672: /* <cofree */
673:
674: /*
675: * collect - do a garbage collection.
676: * the static region is needed.
677: */
678:
679: collect()
680: {
681: register word extra;
682: register char *newend;
683: register struct descrip *dp;
684: char *strptr;
685: struct b_coexpr *cp;
686: #ifndef MSDOS
687: extern char *brk();
688: #endif MSDOS
689: extern char *sbrk();
690: #ifdef RunStats
691: struct tms tmbuf;
692:
693: times(&tmbuf);
694: gc_t_start = tmbuf.tms_utime + tmbuf.tms_stime;
695: Inc(gc_n_total);
696: #endif RunStats
697: MMBGC();
698:
699: /*
700: * Sync the values (used by sweep) in the coexpr block for ¤t
701: * with the current values.
702: */
703: cp = (struct b_coexpr *)BlkLoc(current);
704: cp->es_pfp = pfp;
705: cp->es_gfp = gfp;
706: cp->es_efp = efp;
707: cp->es_sp = sp;
708:
709: /*
710: * Reset the string qualifier free list pointer.
711: */
712: qualfree = quallist;
713:
714: /*
715: * Mark the stacks for &main and the current co-expression.
716: */
717: markblock(&k_main);
718: markblock(¤t);
719: /*
720: * Mark &subject and the cached s2 and s3 strings for map.
721: */
722: postqual(&k_subject);
723: if (Qual(maps2)) /* caution: the cached arguments of */
724: postqual(&maps2); /* map may not be strings. */
725: else if (Pointer(maps2))
726: markblock(&maps2);
727: if (Qual(maps3))
728: postqual(&maps3);
729: else if (Pointer(maps3))
730: markblock(&maps3);
731: /*
732: * Mark the tended descriptors and the global and static variables.
733: */
734: for (dp = &tended[1]; dp <= &tended[ntended]; dp++)
735: /* >locate */
736: if (Qual(*dp))
737: postqual(dp);
738: else if (Pointer(*dp))
739: markblock(dp);
740: /* <locate */
741: for (dp = globals; dp < eglobals; dp++)
742: if (Qual(*dp))
743: postqual(dp);
744: else if (Pointer(*dp))
745: markblock(dp);
746: for (dp = statics; dp < estatics; dp++)
747: if (Qual(*dp))
748: postqual(dp);
749: else if (Pointer(*dp))
750: markblock(dp);
751:
752: /*
753: * Collect available co-expression stacks.
754: */
755: cofree();
756: if (statneed) {
757: /*
758: * The static region needs to be expanded. Make sure the end has not
759: * been changed by someone else.
760: */
761: if (currend != sbrk(0))
762: runerr(304, NULL);
763: extra = statneed;
764: newend = (char *) quallist + extra;
765: /*
766: * This next calculation determines if there is space for the requested
767: * static region expansion. The checks involving quallist and newend
768: * appear to only be required on machines where the above addition
769: * of extra might overflow.
770: */
771:
772: if (newend < (char *)quallist || newend > (char *)0x7fffffff ||
773: (newend > (char *)equallist && ((word) brk(newend) == (word)-1)))
774: runerr(303, NULL);
775: statend += statneed;
776: statneed = 0;
777: currend = sbrk(0);
778: }
779: else
780: /*
781: * Expansion of the static memory region is not required.
782: */
783: extra = 0;
784:
785: /*
786: * Collect the string space, indicating that it must be moved back
787: * extra bytes.
788: */
789: scollect(extra);
790: /*
791: * strptr is post-gc value for strings. Move back pointers for strend
792: * and quallist according to value of extra.
793: */
794: strptr = strbase + extra;
795: strend += extra;
796: quallist = (struct descrip **)((char *)quallist + extra);
797: if (quallist > equallist)
798: equallist = quallist;
799:
800: /*
801: * Calculate a value for extra space. The value is (the larger of
802: * (twice the string space needed) or (the number of words currently
803: * in the string space)) plus the unallocated string space.
804: */
805: extra = (Max(2*strneed, (strend-(char *)statend)/4) -
806: (strend - extra - strfree) + (GranSize-1)) & ~(GranSize-1);
807:
808: while (extra > 0) {
809: /*
810: * Try to get extra more bytes of storage. If it can't be gotten,
811: * decrease the value by GranSize and try again. If it's gotten,
812: * move back strend and quallist. First make sure that someone
813: * has not moved the end of the region.
814: */
815: if (currend != sbrk(0))
816: runerr(304, NULL);
817: newend = (char *)quallist + extra;
818: if (newend >= (char *)quallist &&
819: (newend <= (char *)equallist || ((int) brk(newend) != -1))) {
820: strend += extra;
821: quallist = (struct descrip **) newend;
822: currend = sbrk(0);
823: break;
824: }
825: extra -= GranSize;
826: }
827:
828: /*
829: * Adjust the pointers in the block region. Note that blkbase is the old base
830: * of the block region and strend will be the post-gc base of the block region.
831: */
832: adjust(blkbase,strend);
833: /*
834: * Compact the block region.
835: */
836: compact(blkbase);
837: /*
838: * Calculate a value for extra space. The value is (the larger of
839: * (twice the block region space needed) or (the number of words currently
840: * in the block region space)) plus the unallocated block space.
841: */
842: extra = (Max(2*blkneed, (maxblk-blkbase)/4) +
843: blkfree - maxblk + (GranSize-1)) & ~(GranSize-1);
844: while (extra > 0) {
845: /*
846: * Try to get extra more bytes of storage. If it can't be gotten,
847: * decrease the value by GranSize and try again. If it's gotten,
848: * move back quallist. First make sure the end has not been changed.
849: */
850: if (currend != sbrk(0))
851: runerr(304, NULL);
852: newend = (char *)quallist + extra;
853: if (newend >= (char *)quallist &&
854: (newend <= (char *)equallist || ((int) brk(newend) != -1))) {
855: quallist = (struct descrip **) newend;
856: currend = sbrk(0);
857: break;
858: }
859: extra -= GranSize;
860: }
861: if (quallist > equallist)
862: equallist = quallist;
863:
864: if (strend != blkbase) {
865: /*
866: * strend is not equal to blkbase and this indicates that the
867: * static region or string region was expanded and thus
868: * the block region must be moved. There is an assumption here that the
869: * block region always moves up in memory, i.e., the static and
870: * string regions never shrink. With this assumption in hand,
871: * the block region must be moved before the string space lest the string
872: * space overwrite block data. The assumption is valid, but beware
873: * if shrinking regions are ever implemented.
874: */
875: mvc((uword)(blkfree - blkbase), blkbase, strend);
876: blkfree += strend - blkbase;
877: blkbase = strend;
878: }
879: if (strptr != strbase) {
880: /*
881: * strptr is not equal to strbase and this indicates that the
882: * co-expression space was expanded and thus the string space
883: * must be moved up in memory.
884: */
885: mvc((uword)(strfree - strbase), strbase, strptr);
886: strfree += strptr - strbase;
887: strbase = strptr;
888: }
889:
890: /*
891: * Expand the block region.
892: */
893: maxblk = (char *)quallist;
894: #ifdef RunStats
895: times(&tmbuf);
896: gc_t_last =
897: 1000*(((tmbuf.tms_utime + tmbuf.tms_stime)-gc_t_start)/(double)Hz);
898: IncSum(gc_t_total,gc_t_last);
899: #endif RunStats
900: MMEGC();
901: return;
902: }
903: /*
904: * markblock- mark each accessible block in the block region and build back-list of
905: * descriptors pointing to that block. (Phase I of garbage collection.)
906: */
907:
908: /* >markblock */
909: markblock(dp)
910: struct descrip *dp;
911: {
912: register struct descrip *dp1;
913: register char *endblock, *block;
914: static word type, fdesc, off;
915:
916: /*
917: * Get the block to which dp points.
918: */
919:
920: block = (char *) BlkLoc(*dp);
921: if (block >= blkbase && block < blkfree) { /* check range */
922: if (Var(*dp) && !Tvar(*dp)) {
923:
924: /*
925: * The descriptor is a variable; point block to the head of the
926: * block containing the descriptor to which dp points.
927: */
928: off = Offset(*dp);
929: if (off == 0)
930: return;
931: else
932: block = (char *) ((word *) block - off);
933: }
934:
935: type = BlkType(block);
936: if ((uword)type <= MaxType) {
937:
938: /*
939: * The type is valid, which indicates that this block has not
940: * been marked. Point endblock to the byte past the end
941: * of the block.
942: */
943: endblock = block + BlkSize(block);
944: MMMark(block,type);
945: }
946:
947: /*
948: * Add dp to the back-chain for the block and point the
949: * block (via the type field) to dp.
950: */
951: BlkLoc(*dp) = (union block *) type;
952: BlkType(block) = (word)dp;
953: if (((unsigned)type <= MaxType) && ((fdesc = firstd[type]) > 0))
954:
955: /*
956: * The block has not been marked, and it does contain
957: * descriptors. Mark each descriptor.
958: */
959: for (dp1 = (struct descrip *) (block + fdesc);
960: (char *) dp1 < endblock; dp1++) {
961: if (Qual(*dp1))
962: postqual(dp1);
963: else if (Pointer(*dp1))
964: markblock(dp1);
965: }
966: }
967: else if (dp->dword == D_Coexpr &&
968: (unsigned)BlkType(block) <= MaxType) {
969:
970: /*
971: * dp points to a co-expression block that has not been
972: * marked. Point the block to dp. Sweep the interpreter
973: * stack in the block and mark the block for the
974: * activating co-expression and the refresh block.
975: */
976: BlkType(block) = (word)dp;
977: sweep((struct b_coexpr *)block);
978: markblock(&((struct b_coexpr *)block)->activator);
979: markblock(&((struct b_coexpr *)block)->freshblk);
980: }
981: }
982: /* <markblock */
983:
984: /*
985: * adjust - adjust pointers into the block region, beginning with block oblk and
986: * basing the "new" block region at nblk. (Phase II of garbage collection.)
987: */
988:
989: /* >adjust */
990: adjust(source,dest)
991: char *source, *dest;
992: {
993: register struct descrip *nxtptr, *tptr;
994:
995: /*
996: * Loop through to the end of allocated block region, moving source
997: * to each block in turn and using the size of a block to find the
998: * next block.
999: */
1000: while (source < blkfree) {
1001: if ((uword) (nxtptr = (struct descrip *)BlkType(source)) > MaxType) {
1002:
1003: /*
1004: * The type field of source is a back-pointer. Traverse the
1005: * chain of back pointers, changing each block location from
1006: * source to dest.
1007: */
1008: while ((uword)nxtptr > MaxType) {
1009: tptr = nxtptr;
1010: nxtptr = (struct descrip *)BlkLoc(*nxtptr);
1011: if (Var(*tptr) && !Tvar(*tptr))
1012: BlkLoc(*tptr) = (union block *)((word *)dest + Offset(*tptr));
1013: else
1014: BlkLoc(*tptr) = (union block *)dest;
1015: }
1016: BlkType(source) = (uword)nxtptr | F_Mark;
1017: dest += BlkSize(source);
1018: }
1019: source += BlkSize(source);
1020: }
1021: }
1022: /* <adjust */
1023:
1024: /*
1025: * compact - compact good blocks in the block region. (Phase III of garbage collection.)
1026: */
1027:
1028: /* >compact */
1029: compact(source)
1030: char *source;
1031: {
1032: register char *dest;
1033: register word size;
1034:
1035: /*
1036: * Start dest at source.
1037: */
1038: dest = source;
1039:
1040: /*
1041: * Loop through to end of allocated block space moving source to
1042: * each block in turn, using the size of a block to find the next
1043: * block. If a block has been marked, it is copied to the
1044: * location pointed to by dest and dest is pointed past the end
1045: * of the block, which is the location to place the next saved
1046: * block. Marks are removed from the saved blocks.
1047: */
1048: while (source < blkfree) {
1049: size = BlkSize(source);
1050: if (BlkType(source) & F_Mark) {
1051: BlkType(source) &= ~F_Mark;
1052: if (source != dest)
1053: mvc((uword)size,source,dest);
1054: dest += size;
1055: }
1056: source += size;
1057: }
1058:
1059: /*
1060: * dest is the location of the next free block. Now that compaction
1061: * is complete, point blkfree to that location.
1062: */
1063: blkfree = dest;
1064: }
1065: /* <compact */
1066:
1067: /*
1068: * postqual - mark a string qualifier. Strings outside the string space
1069: * are ignored.
1070: */
1071:
1072: /* >postqual */
1073: postqual(dp)
1074: struct descrip *dp;
1075: {
1076: #ifndef MSDOS
1077: extern char *brk();
1078: #endif MSDOS
1079: extern char *sbrk();
1080:
1081: if (StrLoc(*dp) >= strbase && StrLoc(*dp) < strend) {
1082: /*
1083: * The string is in the string space. Add it to the string qualifier
1084: * list. But before adding it, expand the string qualifier list
1085: * if necessary.
1086: */
1087: if (qualfree >= equallist) {
1088: equallist += Sqlinc;
1089: if (currend != sbrk(0)) /* make sure region has not changed */
1090: runerr(304, NULL);
1091: if ((int) brk(equallist) == -1) /* make sure region can be expanded */
1092: runerr(303, NULL);
1093: currend = sbrk(0);
1094: }
1095: *qualfree++ = dp;
1096: }
1097: }
1098: /* <postqual */
1099:
1100: /*
1101: * scollect - collect the string space. quallist is a list of pointers to
1102: * descriptors for all the reachable strings in the string space. For
1103: * ease of description, it is referred to as if it were composed of
1104: * descriptors rather than pointers to them.
1105: */
1106:
1107: /* >scollect */
1108: scollect(extra)
1109: word extra;
1110: {
1111: register char *source, *dest;
1112: register struct descrip **qptr;
1113: char *cend;
1114: extern int qlcmp();
1115:
1116: if (qualfree <= quallist) {
1117: /*
1118: * There are no accessible strings. Thus, there are none to
1119: * collect and the whole string space is free.
1120: */
1121: strfree = strbase;
1122: return;
1123: }
1124: /*
1125: * Sort the pointers on quallist in ascending order of string locations.
1126: */
1127: qsort(quallist, qualfree-quallist, sizeof(struct descrip *), qlcmp);
1128: /*
1129: * The string qualifiers are now ordered by starting location.
1130: */
1131: dest = strbase;
1132: source = cend = StrLoc(**quallist);
1133:
1134: /*
1135: * Loop through qualifiers for accessible strings.
1136: */
1137: for (qptr = quallist; qptr < qualfree; qptr++) {
1138: if (StrLoc(**qptr) > cend) {
1139:
1140: /*
1141: * qptr points to a qualifier for a string in the next clump;
1142: * the last clump is moved and source and cend are set for
1143: * the next clump.
1144: */
1145: MMSMark(source,cend - source);
1146: while (source < cend)
1147: *dest++ = *source++;
1148: source = cend = StrLoc(**qptr);
1149: }
1150: if (StrLoc(**qptr)+StrLen(**qptr) > cend)
1151: /*
1152: * qptr is a qualifier for a string in this clump; extend the clump.
1153: */
1154: cend = StrLoc(**qptr) + StrLen(**qptr);
1155: /*
1156: * Relocate the string qualifier.
1157: */
1158: StrLoc(**qptr) += dest - source + extra;
1159: }
1160:
1161: /*
1162: * Move the last clump.
1163: */
1164: MMSMark(source,cend - source);
1165: while (source < cend)
1166: *dest++ = *source++;
1167: strfree = dest;
1168: }
1169: /* <scollect */
1170:
1171: /*
1172: * qlcmp - compare the location fields of two string qualifiers for qsort.
1173: */
1174:
1175: /* >qlcmp */
1176: qlcmp(q1,q2)
1177: struct descrip **q1, **q2;
1178: {
1179: return (int)(StrLoc(**q1) - StrLoc(**q2));
1180: }
1181: /* <qlcmp */
1182:
1183: /*
1184: * mvc - move n bytes from src to dst.
1185: */
1186:
1187: mvc(n, s, d)
1188: uword n;
1189: register char *s, *d;
1190: {
1191: register int words;
1192: register int *srcw, *dstw;
1193: int bytes;
1194:
1195: words = n / sizeof(int);
1196: bytes = n % sizeof(int);
1197:
1198: srcw = (int *)s;
1199: dstw = (int *)d;
1200:
1201: if (d < s) {
1202: /*
1203: * The move is from higher memory to lower memory. (It so happens
1204: * that leftover bytes are not moved.)
1205: */
1206: while (--words >= 0)
1207: *(dstw)++ = *(srcw)++;
1208: while (--bytes >= 0)
1209: *d++ = *s++;
1210: }
1211: else if (d > s) {
1212: /*
1213: * The move is from lower memory to higher memory.
1214: */
1215: s += n;
1216: d += n;
1217: while (--bytes >= 0)
1218: *--d = *--s;
1219: srcw = (int *)s;
1220: dstw = (int *)d;
1221: while (--words >= 0)
1222: *--dstw = *--srcw;
1223: }
1224: }
1225:
1226: /*
1227: * sweep - sweep the stack, marking all descriptors there. Method
1228: * is to start at a known point, specifically, the frame that the
1229: * fp points to, and then trace back along the stack looking for
1230: * descriptors and local variables, marking them when they are found.
1231: * The sp starts at the first frame, and then is moved down through
1232: * the stack. Procedure, generator, and expression frames are
1233: * recognized when the sp is a certain distance from the fp, gfp,
1234: * and efp respectively.
1235: *
1236: * Sweeping problems can be manifested in a variety of ways due to
1237: * the "if it can't be identified it's a descriptor" methodology.
1238: */
1239: sweep(ce)
1240: struct b_coexpr *ce;
1241: {
1242: register word *s_sp;
1243: register struct pf_marker *fp;
1244: register struct gf_marker *s_gfp;
1245: register struct ef_marker *s_efp;
1246: word nargs, type, gsize;
1247:
1248: fp = ce->es_pfp;
1249: s_gfp = ce->es_gfp;
1250: if (s_gfp != 0) {
1251: type = s_gfp->gf_gentype;
1252: if (type == G_Psusp)
1253: gsize = Wsizeof(*s_gfp);
1254: else
1255: gsize = Wsizeof(struct gf_smallmarker);
1256: }
1257: s_efp = ce->es_efp;
1258: s_sp = ce->es_sp;
1259: nargs = 0; /* Nargs counter is 0 initially. */
1260:
1261: while ((fp != 0 || nargs)) { /* Keep going until current fp is
1262: 0 and no arguments are left. */
1263: if (s_sp == (word *)fp + Vwsizeof(*pfp) - 1) {/*The sp has reached the upper
1264: boundary of a procedure frame,
1265: process the frame. */
1266: s_efp = fp->pf_efp; /* Get saved efp out of frame */
1267: s_gfp = fp->pf_gfp; /* Get save gfp */
1268: if (s_gfp != 0) {
1269: type = s_gfp->gf_gentype;
1270: if (type == G_Psusp)
1271: gsize = Wsizeof(*s_gfp);
1272: else
1273: gsize = Wsizeof(struct gf_smallmarker);
1274: }
1275: s_sp = (word *)fp - 1; /* First argument descriptor is
1276: first word above proc frame */
1277: nargs = fp->pf_nargs;
1278: fp = fp->pf_pfp;
1279: }
1280: else if (s_sp == (word *)s_gfp + gsize - 1) {
1281: /* The sp has reached the lower end
1282: of a generator frame, process
1283: the frame.*/
1284: if (type == G_Psusp)
1285: fp = s_gfp->gf_pfp;
1286: s_sp = (word *)s_gfp - 1;
1287: s_efp = s_gfp->gf_efp;
1288: s_gfp = s_gfp->gf_gfp;
1289: if (s_gfp != 0) {
1290: type = s_gfp->gf_gentype;
1291: if (type == G_Psusp)
1292: gsize = Wsizeof(*s_gfp);
1293: else
1294: gsize = Wsizeof(struct gf_smallmarker);
1295: }
1296: nargs = 1;
1297: }
1298: else if (s_sp == (word *)s_efp + Wsizeof(*s_efp) - 1) {
1299: /* The sp has reached the upper
1300: end of an expression frame,
1301: process the frame. */
1302: s_gfp = s_efp->ef_gfp; /* Restore gfp, */
1303: if (s_gfp != 0) {
1304: type = s_gfp->gf_gentype;
1305: if (type == G_Psusp)
1306: gsize = Wsizeof(*s_gfp);
1307: else
1308: gsize = Wsizeof(struct gf_smallmarker);
1309: }
1310: s_efp = s_efp->ef_efp; /* and efp from frame. */
1311: s_sp -= Wsizeof(*s_efp); /* Move down past expression frame
1312: marker. */
1313: }
1314: else { /* Assume the sp is pointing at a
1315: descriptor. */
1316: if (Qual(*((struct descrip *)(&s_sp[-1]))))
1317: postqual(&s_sp[-1]);
1318: else if (Pointer(*((struct descrip *)(&s_sp[-1]))))
1319: markblock(&s_sp[-1]);
1320: s_sp -= 2; /* Move past descriptor. */
1321: if (nargs) /* Decrement argument count if in an*/
1322: nargs--; /* argument list. */
1323: }
1324: }
1325: }
1326:
1327: typedef int ALIGN; /* pick most stringent type for alignment */
1328:
1329: union bhead { /* header of free block */
1330: struct {
1331: union bhead *ptr; /* pointer to next free block */
1332: uword bsize; /* free block size */
1333: } s;
1334: ALIGN x; /* force block alignment */
1335: };
1336:
1337: typedef union bhead HEADER;
1338: #define NALLOC 1024 /* units to request at one time */
1339:
1340:
1341: static HEADER base; /* start with empty list */
1342: static HEADER *allocp = NULL; /* last allocated block */
1343:
1344: char *malloc(nbytes)
1345: unsigned nbytes;
1346: {
1347: HEADER *moremem();
1348: register HEADER *p, *q;
1349: register word nunits;
1350: int attempts;
1351:
1352: nunits = 1 + (nbytes + sizeof(HEADER) - 1) / sizeof(HEADER);
1353: if ((q = allocp) == NULL) { /* no free list yet */
1354: base.s.ptr = allocp = q = &base;
1355: base.s.bsize = 0;
1356: }
1357:
1358: for (attempts = 2; attempts--; q = allocp) {
1359: for (p = q->s.ptr;; q = p, p = p->s.ptr) {
1360: if (p->s.bsize >= nunits) { /* block is big enough */
1361: if (p->s.bsize == nunits) /* exactly right */
1362: q->s.ptr = p->s.ptr;
1363: else { /* allocate tail end */
1364: p->s.bsize -= nunits;
1365: p += p->s.bsize;
1366: p->s.bsize = nunits;
1367: }
1368: allocp = q;
1369: return (char *)(p + 1);
1370: }
1371: if (p == allocp) { /* wrap around */
1372: moremem(nunits); /* garbage collect and expand if needed */
1373: break;
1374: }
1375: }
1376: }
1377: syserr("cannot allocate requested storage");
1378: }
1379:
1380: /*
1381: * realloc() allocates a new block of memory of a different size
1382: * that contains the contents of the current block or as much as
1383: * will fit.
1384: */
1385:
1386: char *realloc(curmem,newsiz)
1387: register char *curmem; /* the current memory pointer */
1388: register int newsiz; /* the size of the new allocation */
1389: {
1390: register char *newmem, *p; /* the new memory pointer */
1391: register int cursiz; /* the size of the current allocation */
1392: register int n;
1393:
1394: HEADER *head; /* the pointer to the current header */
1395:
1396: if ((newmem = malloc(newsiz)) != NULL) {
1397: /* get the current allocation size */
1398: head = (HEADER *) (curmem-1);
1399: cursiz = head->s.bsize;
1400: p = newmem;
1401: n = (cursiz < newsiz ? cursiz : newsiz);
1402: while (--n >= 0)
1403: *newmem++ = *curmem++;
1404:
1405: /* free the current block */
1406: free(curmem);
1407: return(p);
1408: }
1409: syserr("malloc failed in realloc");
1410: }
1411:
1412: /*
1413: * calloc() allocates memory using malloc and zeroes it.
1414: */
1415:
1416: char *calloc(ecnt,esiz)
1417: register int ecnt, esiz;
1418: {
1419: register char *mem, *p; /* the memory pointer */
1420: register int amount; /* the amount of memory needed */
1421:
1422: amount = ecnt * esiz;
1423:
1424: if ((mem = malloc(amount)) != NULL) {
1425: p = mem;
1426: while (--amount >= 0)
1427: *mem++ = 0;
1428: return p;
1429: }
1430: syserr("malloc failure in calloc");
1431: }
1432:
1433: static HEADER *moremem(nunits)
1434: uword nunits;
1435: {
1436: register char *cp;
1437: register HEADER *up;
1438: register word rnu;
1439: word n;
1440:
1441: rnu = NALLOC * ((nunits + NALLOC - 1) / NALLOC);
1442: n = rnu * sizeof(HEADER);
1443: if (statfree + n > statend) {
1444: statneed = ((n / statincr) + 1) * statincr;
1445: collect();
1446: }
1447: if (statfree < statend) { /* that is, if there is any room left */
1448: up = (HEADER *) statfree;
1449: up->s.bsize = (statend - statfree) / sizeof(HEADER);
1450: statfree = statend;
1451: free((char *) (up + 1)); /* add block to free memory */
1452: }
1453: }
1454:
1455: free(ap) /* return block pointed to by ap to free list */
1456: char *ap;
1457: {
1458: register HEADER *p, *q;
1459:
1460: p = (HEADER *)ap - 1; /* point to header */
1461: if (p->s.bsize * sizeof(HEADER) >= statneed)
1462: statneed = 0;
1463: for (q = allocp; !(p > q && p < q->s.ptr); q = q->s.ptr)
1464: if (q >= q->s.ptr && (p > q || p < q->s.ptr))
1465: break; /* at one end or the other */
1466: if (p + p->s.bsize == q->s.ptr) { /* join to upper */
1467: p->s.bsize += q->s.ptr->s.bsize;
1468: if (p->s.bsize * sizeof(HEADER) >= statneed)
1469: statneed = 0;
1470: p->s.ptr = q->s.ptr->s.ptr;
1471: }
1472: else
1473: p->s.ptr = q->s.ptr;
1474: if (q + q->s.bsize == p) { /* join to lower */
1475: q->s.bsize += p->s.bsize;
1476: if (q->s.bsize * sizeof(HEADER) >= statneed)
1477: statneed = 0;
1478: q->s.ptr = p->s.ptr;
1479: }
1480: else
1481: q->s.ptr = p;
1482: allocp = q;
1483: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.