1: #include "../h/rt.h" 2: #include "../h/gc.h" 3: #ifdef VAX 4: #define MAIN 5: #endif VAX 6: #ifdef PORT 7: #define MAIN 8: #endif PORT 9: #ifdef MAIN 10: /* 11: * hneed - insure that at least bytes of space are left in the heap. 12: * The amount of space needed is transmitted to the collector via 13: * the global variable heapneed. 14: */ 15: 16: hneed(bytes) 17: unsigned bytes; 18: { 19: heapneed = bytes; 20: if (bytes > maxheap - hpfree) 21: gcollect(0); 22: } 23: 24: /* 25: * sneed - insure that at least chars of space are left in the string 26: * space. The amount of space needed is transmitted to the collector 27: * via the global variable strneed. 28: */ 29: 30: sneed(chars) 31: unsigned chars; 32: { 33: strneed = chars; 34: if (chars > estrings - sfree) 35: gcollect(0); 36: } 37: 38: /* 39: * esneed - insure that there is a free co-expression stack. esfree 40: * points to the linked list of free stacks. 41: */ 42: 43: esneed() 44: { 45: if (esfree == NULL) 46: gcollect(1); 47: } 48: 49: /* 50: * escollect - collect the expression stack space. This is done after 51: * the marking phase of garbage collection and the stacks that are 52: * reachable have pointers to data blocks, rather than T_ESTACK, 53: * in their type field. 54: */ 55: 56: escollect() 57: { 58: register int *ep; 59: register struct b_estack *sp; 60: 61: /* 62: * Reset the type for &main. 63: */ 64: BLKLOC(k_main)->estack.type = T_ESTACK; 65: 66: /* 67: * Reset the free list pointer. 68: */ 69: esfree = NULL; 70: 71: /* 72: * The co-expression stacks start at stacks and lie contiguously. 73: * ep is pointed at the low word of each stack and sp is pointed 74: * at the b_estack block contained in the space for the stack. 75: * (Note that the last word of the b_estack block is the last word 76: * of the space for the co-expression stack. 77: */ 78: for (ep = stacks; ep < estacks; ep += stksize) { 79: sp = (struct b_estack *) (ep + (stksize - sizeof(struct b_estack)/WORDSIZE)); 80: if (blktype(sp) == T_ESTACK) { 81: /* 82: * This co-expression was not marked, so it can be collected. 83: * The stacks are linked through the first word of the stack 84: * space with esfree pointing to the last-collected stack. 85: */ 86: *ep = (int) esfree; 87: esfree = ep; 88: } 89: else 90: /* 91: * The co-expression was marked, so just reset the type field. 92: */ 93: blktype(sp) = T_ESTACK; 94: } 95: } 96: 97: /* 98: * collect - do a garbage collection. esneed indicates if a co-expression 99: * stack is needed. 100: */ 101: 102: collect(esneed) 103: int esneed; 104: { 105: register int extra; 106: register char *newend; 107: register struct descrip *dp; 108: char *sptr; 109: extern char *brk(); 110: 111: /* 112: * Reset the string qualifier free list pointer. 113: */ 114: sqfree = sqlist; 115: 116: /* 117: * Mark the stacks for &main and the current co-expression. 118: */ 119: mark(&k_main); 120: mark(¤t); 121: /* 122: * Mark &subject and the cached s2 and s3 strings for map(). 123: */ 124: mark(&k_subject); 125: mark(&maps2); 126: mark(&maps3); 127: /* 128: * Mark the tended descriptors and the global and static variables. 129: */ 130: for (dp = tended; dp < etended; dp++) 131: mark(dp); 132: for (dp = globals; dp < eglobals; dp++) 133: mark(dp); 134: for (dp = statics; dp < estatics; dp++) 135: mark(dp); 136: 137: /* 138: * Collect available co-expression stacks. 139: */ 140: escollect(); 141: if (esneed && esfree == NULL) { 142: /* 143: * A co-expression stack is needed, but none are available. The 144: * new stack at the end of the stack space and is made available 145: * by pointing esfree at it. *estacks is zeroed to terminate the 146: * (now one element) co-expression free list. 147: */ 148: esfree = estacks; 149: *estacks = 0; 150: /* 151: * Move back the end of the expression space by the size of a 152: * stack and indicate stksize words of memory are needed. 153: */ 154: estacks += stksize; 155: extra = stksize*WORDSIZE; 156: newend = (char *) sqlist + extra; 157: /* 158: * This next calculation determines if there is space for the new 159: * stack, but it's not clear what all's going on here. 160: */ 161: if (newend < (char *)sqlist || newend > (char *)0x7fffffff || 162: (newend > (char *)esqlist && ((int) brk(newend) == -1))) 163: runerr(305, NULL); 164: } 165: else 166: /* 167: * Another co-expression stack is not needed. 168: */ 169: extra = 0; 170: 171: /* 172: * Collect the string space, indicating that it must be moved back 173: * extra bytes. 174: */ 175: scollect(extra); 176: /* 177: * sptr is post-gc value for strings. Move back pointers for estrings 178: * and sqlist according to value of extra. 179: */ 180: sptr = strings + extra; 181: estrings += extra; 182: sqlist = sqlist + extra; 183: if (sqlist > esqlist) 184: esqlist = sqlist; 185: 186: /* 187: * Calculate a value for extra space. The value is (the larger of 188: * (twice the string space needed) or (the number of words currently 189: * in the string space)) plus the unallocated string space. 190: */ 191: extra = (MAX(2*strneed, (estrings-(char *)estacks)/4) - 192: (estrings - extra - sfree) + (GRANSIZE-1)) & ~(GRANSIZE-1); 193: 194: while (extra > 0) { 195: /* 196: * Try to get extra more bytes of storage. If it can't be gotten, 197: * decrease the value by GRANSIZE and try again. If it's gotten, 198: * move back estrings and sqlist. 199: */ 200: newend = (char *)sqlist + extra; 201: if (newend >= (char *)sqlist && 202: (newend <= (char *)esqlist || ((int) brk(newend) != -1))) { 203: estrings += extra; 204: sqlist = (struct descrip **) newend; 205: break; 206: } 207: extra -= GRANSIZE; 208: } 209: 210: /* 211: * Adjust the pointers in the heap. Note that hpbase is the old base 212: * of the heap and estrings will be the post-gc base of the heap. 213: */ 214: adjust(hpbase,estrings); 215: /* 216: * Compact the heap. 217: */ 218: compact(hpbase); 219: /* 220: * Calculate a value for extra space. The value is (the larger of 221: * (twice the heap space needed) or (the number of words currently 222: * in the heap space)) plus the unallocated heap space. 223: */ 224: extra = (MAX(2*heapneed, (maxheap-hpbase)/4) + 225: hpfree - maxheap + (GRANSIZE-1)) & ~(GRANSIZE-1); 226: while (extra > 0) { 227: /* 228: * Try to get extra more bytes of storage. If it can't be gotten, 229: * decrease the value by GRANSIZE and try again. If it's gotten, 230: * move back sqlist. 231: */ 232: newend = (char *)sqlist + extra; 233: if (newend >= (char *)sqlist && 234: (newend <= (char *)esqlist || ((int) brk(newend) != -1))) { 235: sqlist = (struct descrip **) newend; 236: break; 237: } 238: extra -= GRANSIZE; 239: } 240: if (sqlist > esqlist) 241: esqlist = sqlist; 242: 243: if (estrings != hpbase) { 244: /* 245: * estrings is not equal to hpbase and this indicates that the 246: * co-expression and/or string space was expanded and thus 247: * the heap must be moved. There is an assumption here that the 248: * heap always moves up in memory, i.e., the co-expression and 249: * string spaces never shrink. With this assumption in hand, 250: * the heap must be moved before the string space lest the string 251: * space overwrite heap data. The assumption is valid, but beware 252: * if shrinking regions are ever implemented. 253: */ 254: mvc((unsigned)(hpfree - hpbase), hpbase, estrings); 255: hpfree += estrings - hpbase; 256: hpbase = estrings; 257: } 258: if (sptr != strings) { 259: /* 260: * sptr is not equal to strings and this indicates that the 261: * co-expression space was expanded and thus the string space 262: * must be moved up in memory. 263: */ 264: mvc((unsigned)(sfree - strings), strings, sptr); 265: sfree += sptr - strings; 266: strings = sptr; 267: } 268: 269: /* 270: * Expand the heap. 271: */ 272: maxheap = (char *)sqlist; 273: return; 274: } 275: /* 276: * mark - mark each accessible block in the heap and build back-list of 277: * descriptors pointing to that block. (Phase I of garbage collection.) 278: */ 279: 280: mark(cdesc) 281: struct descrip *cdesc; 282: { 283: register struct descrip *ndesc; 284: register char *endblock, *block; 285: static int type; 286: static int fdesc; 287: 288: if (QUAL(*cdesc)) 289: /* 290: * The descriptor is for a string, so pass the buck to marksq. 291: */ 292: marksq(cdesc); 293: else if (isptr(cdesc)) { 294: /* 295: * The descriptor is a pointer to a block or a variable. Point 296: * block at the block referenced by the descriptor. 297: */ 298: block = (char *) BLKLOC(*cdesc); 299: if (VAR(*cdesc) && !TVAR(*cdesc)) 300: /* 301: * The descriptor is a variable; point block at the start of the 302: * block containing the descriptor that cdesc points to. For 303: * example, descriptors of this sort are created by subscripting 304: * lists. 305: */ 306: block = (char *) ((int *) block - OFFSET(*cdesc)); 307: 308: if (block >= hpbase && block < hpfree) { 309: /* 310: * The block is the heap (blocks outside the heap are ignored); 311: * get the type of the block. 312: */ 313: type = blktype(block); 314: if (type <= MAXTYPE) 315: /* 316: * type is a valid type, indicating that this block hasn't 317: * been marked. Point endblock at the byte past the end 318: * of the block. 319: */ 320: endblock = block + getsize(block); 321: /* 322: * Add cdesc to the back-chain for the block and point the 323: * block (via the type field) at cdesc. 324: */ 325: BLKLOC(*cdesc) = (union block *) type; 326: blktype(block) = (int) cdesc; 327: if ((type <= MAXTYPE) && ((fdesc = firstd[(int)type]) > 0)) 328: /* 329: * The block has not been marked, and it does contain descriptors. 330: * Mark each descriptor. 331: */ 332: for (ndesc = (struct descrip *) (block + fdesc); 333: (char *) ndesc < endblock; ndesc++) 334: mark(ndesc); 335: } 336: if (!VAR(*cdesc) && TYPE(*cdesc) == T_ESTACK && 337: blktype(block) <= MAXTYPE) { 338: /* 339: * cdesc points to a co-expression block that hasn't been marked. 340: * Point the block at cdesc. Sweep the co-expression's stack 341: * and mark the blocks for the activating co-expression and 342: * the co-expression's refresh block. 343: */ 344: blktype(block) = (int) cdesc; 345: sweep(((struct b_estack *)block)->boundary); 346: mark(&((struct b_estack *)block)->activator); 347: mark(&((struct b_estack *)block)->freshblk); 348: } 349: } 350: } 351: 352: /* 353: * adjust - adjust pointers into heap, beginning with block oblk and 354: * basing the "new" heap at nblk. (Phase II of garbage collection.) 355: */ 356: 357: adjust(oblk,nblk) 358: char *oblk, *nblk; 359: { 360: register struct descrip *nxtptr, *tptr; 361: 362: /* 363: * Loop through to end of allocated heap space moving oblk to each 364: * block in turn, using the size of a block to find the next block. 365: */ 366: while (oblk < hpfree) { 367: if ((int) (nxtptr = (struct descrip *) blktype(oblk)) > MAXTYPE) { 368: /* 369: * The type field of oblk is a back-pointer. Work along the chain 370: * of back pointers, changing each block location from oblk 371: * to nblk. 372: */ 373: while ((unsigned)nxtptr > MAXTYPE) { 374: tptr = nxtptr; 375: nxtptr = (struct descrip *) BLKLOC(*nxtptr); 376: if (VAR(*tptr) && !TVAR(*tptr)) 377: BLKLOC(*tptr) = (union block *) ((int *) nblk + OFFSET(*tptr)); 378: else 379: BLKLOC(*tptr) = (union block *) nblk; 380: } 381: blktype(oblk) = (unsigned)nxtptr | MARK; 382: nblk += getsize(oblk); 383: } 384: oblk += getsize(oblk); 385: } 386: } 387: 388: /* 389: * compact - compact good blocks in heap. (Phase III of garbage collection.) 390: */ 391: 392: compact(oblk) 393: char *oblk; 394: { 395: register char *nblk; 396: register int size; 397: 398: /* 399: * Start at oblk, which happens to be hpbase. 400: */ 401: nblk = oblk; 402: /* 403: * Loop through to end of allocated heap space moving oblk to each 404: * block in turn, using the size of a block to find the next block. 405: * If a block has been marked, it is copied to the location pointed 406: * at by nblk and nblk is pointed past the end of the block, which 407: * is the location to place the next good block at. Good blocks 408: * are un-marked. 409: */ 410: while (oblk < hpfree) { 411: size = getsize(oblk); 412: if (blktype(oblk) & MARK) { 413: blktype(oblk) &= ~MARK; 414: if (oblk != nblk) 415: mvc((unsigned)size,oblk,nblk); 416: nblk += size; 417: } 418: oblk += size; 419: } 420: /* 421: * nblk is the location of the next free block, so now that compaction 422: * is complete, point hpfree at that location. 423: */ 424: hpfree = nblk; 425: } 426: 427: /* 428: * marksq - mark a string qualifier. Strings outside the string space 429: * are ignored. 430: */ 431: 432: marksq(d) 433: struct descrip *d; 434: { 435: extern char *brk(); 436: 437: if (STRLOC(*d) >= strings && STRLOC(*d) < estrings) { 438: /* 439: * The string is in the string space, add it to the string qualifier 440: * list. But before adding it, expand the string qualifier list 441: * if necessary. 442: */ 443: if (sqfree >= esqlist) { 444: esqlist += SQLINC; 445: if ((int) brk(esqlist) == -1) 446: runerr(303, NULL); 447: } 448: *sqfree++ = d; 449: } 450: } 451: 452: /* 453: * scollect - collect the string space. sqlist is a list of pointers to 454: * descriptors for all the reachable strings in the string space. For 455: * ease of description, it is referred to as if it were composed of 456: * descriptors rather than pointers to them. 457: */ 458: 459: scollect(extra) 460: int extra; 461: { 462: register char *s, *d; 463: register struct descrip **p; 464: char *e; 465: extern int sqcmp(); 466: 467: if (sqfree <= sqlist) { 468: /* 469: * There are no accessible strings, thus there are none to collect 470: * and the whole string space is free. 471: */ 472: sfree = strings; 473: return; 474: } 475: /* 476: * Sort the sqlist in ascending order of string locations. 477: */ 478: qsort(sqlist, sqfree-sqlist, sizeof(struct descrip *), sqcmp); 479: /* 480: * The string qualifiers are now ordered by starting location. 481: * The algorithm used is described in detail in one of the references 482: * cited in the "tour", but briefly... 483: * 484: * The string region can be thought of as being made up of clumps, 485: * where a clump is a contiguous area of strings that are referenced. 486: * For example, imagine sqlist looks like: 487: * 488: * [2,400] 489: * [3,400] 490: * [10,400] 491: * [12,415] 492: * [4,420] 493: * [3,430] 494: * [1,430] 495: * 496: * There are three clumps: The first starts at location 400 and extends 497: * to 409. The second starts at 415 and extends to 426. The third 498: * starts at 430 and extends to 432. Note that there are gaps, i.e. 499: * garbage, at 410-414 and 427-429. 500: * 501: * After collection, sqlist will look like: 502: * 503: * [2,400] 504: * [3,400] 505: * [10,400] 506: * [12,410] 507: * [4,415] 508: * [3,422] 509: * [1,422] 510: * 511: * Note how the gaps have been closed by moving the strings downward 512: * in memory. 513: * 514: * The method used is to look at each qualifier in sqlist in turn 515: * and determine which ones lie in clumps and the extent of each 516: * clump. The qualifiers referencing strings in each clump are 517: * relocated and then the clump is moved down (compacted). 518: * 519: * d points to the next free location to compact into. s is the 520: * start of the current clump and e is the end. 521: */ 522: d = strings; 523: s = e = STRLOC(**sqlist); 524: /* 525: * Loop through qualifiers for accessible strings. 526: */ 527: for (p = sqlist; p < sqfree; p++) { 528: if (STRLOC(**p) > e) { 529: /* 530: * p is a qualifier for a string in the next clump; the last 531: * clump is moved and s and e are set for the next clump. 532: */ 533: while (s < e) 534: *d++ = *s++; 535: s = e = STRLOC(**p); 536: } 537: if (STRLOC(**p)+STRLEN(**p) > e) 538: /* 539: * p is a qualifier for a string in this clump, extend the clump. 540: */ 541: e = STRLOC(**p) + STRLEN(**p); 542: /* 543: * Relocate the string qualifier. 544: */ 545: STRLOC(**p) += d - s + extra; 546: } 547: /* 548: * Move the last clump. 549: */ 550: while (s < e) 551: *d++ = *s++; 552: sfree = d; 553: } 554: 555: /* 556: * sqcmp - compare the location fields of two string qualifiers for qsort. 557: */ 558: 559: sqcmp(q1,q2) 560: struct descrip **q1, **q2; 561: { 562: return (STRLOC(**q1) - STRLOC(**q2)); 563: } 564: 565: /* 566: * mvc - move n bytes from src to dst. 567: */ 568: 569: mvc(n, s, d) 570: unsigned n; 571: register char *s, *d; 572: { 573: register int words; 574: register int *srcw, *dstw; 575: int bytes; 576: 577: words = n / sizeof(int); 578: bytes = n % sizeof(int); 579: 580: srcw = (int *)s; 581: dstw = (int *)d; 582: 583: if (d < s) { 584: /* 585: * The move is from higher memory to lower memory. (It so happens 586: * that leftover bytes are not moved.) 587: */ 588: while (--words >= 0) 589: *(dstw)++ = *(srcw)++; 590: while (--bytes >= 0) 591: *d++ = *s++; 592: } 593: else if (d > s) { 594: /* 595: * The move is from lower memory to higher memory. 596: */ 597: s += n; 598: d += n; 599: while (--bytes >= 0) 600: *--d = *--s; 601: srcw = (int *)s; 602: dstw = (int *)d; 603: while (--words >= 0) 604: *--dstw = *--srcw; 605: } 606: } 607: 608: #endif MAIN 609: #ifdef PDP11 610: /* 611: * hneed(bytes) - insure at least 'bytes' space left in heap. 612: */ 613: 614: hneed(bytes) 615: unsigned bytes; 616: { 617: heapneed = bytes; 618: if (bytes > maxheap - hpfree) 619: gcollect(0); 620: } 621: 622: /* 623: * sneed(chars) - insure at least 'chars' bytes left in string space. 624: */ 625: 626: sneed(chars) 627: unsigned chars; 628: { 629: strneed = chars; 630: if (chars > estrings - sfree) 631: gcollect(0); 632: } 633: 634: /* 635: * esneed() - insure stack space free list is not empty. 636: */ 637: 638: esneed() 639: { 640: if (esfree == NULL) 641: gcollect(1); 642: } 643: 644: /* 645: * escollect() - collect the expression stack space after marking. 646: */ 647: 648: escollect() 649: { 650: register int *ep; 651: register struct b_estack *sp; 652: register struct descrip *nxtptr, *tptr; 653: 654: BLKLOC(k_main)->estack.type = T_ESTACK; /* must reset */ 655: 656: esfree = NULL; 657: for (ep = stacks; ep < estacks; ep += stksize) { 658: sp = ep + (stksize - sizeof(struct b_estack)/2); 659: if (blktype(sp) == T_ESTACK) { /* add to free list */ 660: *ep = esfree; 661: esfree = ep; 662: } 663: else /* adjust type field */ 664: blktype(sp) = T_ESTACK; 665: } 666: } 667: 668: /* 669: * collect - call the heap garbage collector. 670: */ 671: 672: collect(esneed) 673: int esneed; 674: { 675: register int extra; 676: register char *newend; 677: register struct descrip *dp; 678: char *sptr; 679: extern char *brk(); 680: 681: sqfree = sqlist; /* initialize string qualifier list */ 682: 683: mark(&k_main); /* mark main stack */ 684: mark(¤t); /* mark current stack */ 685: mark(&k_subject); /* mark tended descriptors */ 686: mark(&maps2); 687: mark(&maps3); 688: for (dp = tended; dp < etended; dp++) 689: mark(dp); 690: for (dp = globals; dp < eglobals; dp++) 691: mark(dp); 692: for (dp = statics; dp < estatics; dp++) 693: mark(dp); 694: 695: escollect(); /* collect available expression stacks */ 696: if (esneed && esfree == NULL) { 697: esfree = estacks; /* need to make room for another stack */ 698: *estacks = 0; 699: estacks += stksize; 700: extra = stksize*sizeof(int); /* string and heap ptrs are chars */ 701: newend = sqlist + extra; 702: if (newend < (char *)sqlist || newend > (char *)0177700 || 703: (newend > (char *)esqlist && brk(newend) == -1)) 704: runerr(305, NULL); 705: } 706: else 707: extra = 0; 708: 709: scollect(extra); /* collect string space */ 710: sptr = strings + extra; /* remember new location of string space */ 711: estrings += extra; 712: (char *)sqlist += extra; 713: if (sqlist > esqlist) 714: esqlist = sqlist; 715: 716: extra = (MAX(2*strneed, (estrings-estacks)/4) - 717: (estrings - extra - sfree) + 63) & ~077; 718: while (extra > 0) { /* need breathing room? */ 719: newend = (char *)sqlist + extra; 720: if (newend >= (char *)sqlist && newend <= (char *)0177700 && 721: (newend <= (char *)esqlist || brk(newend) != -1)) { 722: estrings += extra; 723: sqlist = newend; 724: break; 725: } 726: extra -= 64; 727: } 728: adjust(hpbase,estrings); /* adjust pointers into heap */ 729: compact(hpbase); /* compact heap */ 730: extra = (MAX(2*heapneed, (maxheap-hpbase)/4) + 731: hpfree - maxheap + 63) & ~077; 732: while (extra > 0) { /* need breathing room? */ 733: newend = (char *)sqlist + extra; 734: if (newend >= (char *)sqlist && newend <= (char *)0177700 && 735: (newend <= (char *)esqlist || brk(newend) != -1)) { 736: sqlist = newend; 737: break; 738: } 739: extra -= 64; 740: } 741: if (sqlist > esqlist) 742: esqlist = sqlist; 743: if (estrings != hpbase) { /* move heap */ 744: mvc((unsigned)(hpfree - hpbase), hpbase, estrings); 745: hpfree += estrings - hpbase; 746: hpbase = estrings; 747: } 748: if (sptr != strings) { /* move string space */ 749: mvc((unsigned)(sfree - strings), strings, sptr); 750: sfree += sptr - strings; 751: strings = sptr; 752: } 753: maxheap = (char *)sqlist; /* expand heap */ 754: 755: return; 756: } 757: 758: /* 759: * mark - mark each accessible block in the heap and build back-list of 760: * descriptors pointing to that block. (Phase I of garbage collection) 761: */ 762: 763: mark(cdesc) 764: struct descrip *cdesc; /* current descriptor */ 765: { 766: register struct descrip *ndesc; 767: register char *endblock, *block; 768: static char *type; 769: static int fdesc; 770: 771: if (QUAL(*cdesc)) /* if descriptor is a string qualifier, */ 772: marksq(cdesc); /* mark it for scollect */ 773: else if (isptr(cdesc)) { /* ok, descriptor is a pointer */ 774: block = BLKLOC(*cdesc); /* get pointer to top of block */ 775: if (VAR(*cdesc) && !TVAR(*cdesc)) /* if variable, need offset */ 776: block = (int *)block - OFFSET(*cdesc); 777: 778: if (block >= hpbase && block < hpfree) { /* insure it points to heap */ 779: type = blktype(block); /* save type and end of block */ 780: if (type <= MAXTYPE) 781: endblock = block + getsize(block); 782: BLKLOC(*cdesc) = type; /* add descriptor to back chain */ 783: blktype(block) = cdesc; 784: /* sweep descriptors in block */ 785: if ((type <= MAXTYPE) && ((fdesc = firstd[(int)type]) > 0)) 786: for (ndesc = block + fdesc; ndesc < endblock; ndesc++) 787: mark(ndesc); 788: } 789: if (!VAR(*cdesc) && TYPE(*cdesc) == T_ESTACK && 790: (char *)blktype(block) <= MAXTYPE) { 791: blktype(block) = cdesc; /* note block as visited */ 792: sweep(((struct b_estack *)block)->boundary); 793: mark(&((struct b_estack *)block)->activator); 794: mark(&((struct b_estack *)block)->freshblk); 795: } 796: } 797: } 798: 799: /* 800: * adjust - adjust pointers into heap, beginning with heapblock 'oblk'. 801: * (Phase II of garbage collection) 802: */ 803: 804: adjust(oblk,nblk) 805: char *oblk, *nblk; 806: { 807: register struct descrip *nxtptr, *tptr; 808: 809: while (oblk < hpfree) { /* linear sweep through heap */ 810: if ((nxtptr = blktype(oblk)) > MAXTYPE) { 811: while ((unsigned)nxtptr > MAXTYPE) { 812: tptr = nxtptr; 813: nxtptr = BLKLOC(*nxtptr); 814: if (VAR(*tptr) && !TVAR(*tptr)) 815: BLKLOC(*tptr) = (int *)nblk + OFFSET(*tptr); 816: else 817: BLKLOC(*tptr) = nblk; 818: } 819: blktype(oblk) = (unsigned)nxtptr | MARK; 820: nblk += getsize(oblk); 821: } 822: oblk += getsize(oblk); 823: } 824: } 825: 826: /* 827: * compact - compact good blocks in heap, beginning with block 'oblk'. 828: * (Phase III of garbage collection) 829: */ 830: 831: compact(oblk) 832: char *oblk; 833: { 834: register char *nblk; 835: register int size; 836: 837: nblk = oblk; /* linear sweep through heap */ 838: while (oblk < hpfree) { 839: size = getsize(oblk); 840: if (blktype(oblk) & MARK) { /* move good block */ 841: blktype(oblk) &= ~MARK; /* turn off mark */ 842: if (oblk != nblk) 843: mvc((unsigned)size,oblk,nblk); 844: nblk += size; 845: } 846: oblk += size; 847: } 848: hpfree = nblk; /* reset free space pointer */ 849: } 850: 851: /* 852: * marksq - mark a string qualifier. If it points into the 853: * string space, put a pointer to it in the string qualifier 854: * list. 855: */ 856: 857: marksq(d) 858: struct descrip *d; 859: { 860: extern char *brk(); 861: 862: if (STRLOC(*d) >= strings && STRLOC(*d) < estrings) { 863: if (sqfree >= esqlist) { 864: esqlist += SQLINC; 865: if ((int)brk(esqlist) == -1) 866: runerr(303, NULL); 867: } 868: *sqfree++ = d; 869: } 870: } 871: 872: /* 873: * scollect - collect the string space. 874: * A list of string qualifiers points to all valid strings. 875: */ 876: 877: scollect(extra) 878: int extra; 879: { 880: register char *s, *d; 881: register struct descrip **p; 882: char *e; 883: extern int sqcmp(); 884: 885: if (sqfree <= sqlist) { 886: sfree = strings; 887: return; 888: } 889: qsort(sqlist, sqfree-sqlist, sizeof(struct descrip *), sqcmp); 890: d = strings; 891: s = e = STRLOC(**sqlist); 892: for (p = sqlist; p < sqfree; p++) { 893: if (STRLOC(**p) > e) { /* outside last clump */ 894: while (s < e) /* move the clump */ 895: *d++ = *s++; 896: s = e = STRLOC(**p); /* start a new clump */ 897: } 898: if (STRLOC(**p)+STRLEN(**p) > e) /* extend the clump */ 899: e = STRLOC(**p) + STRLEN(**p); 900: STRLOC(**p) += d - s + extra; /* relocate the string qualifier */ 901: } 902: while (s < e) /* move the last clump */ 903: *d++ = *s++; 904: sfree = d; 905: } 906: 907: /* 908: * sqcmp - compare the location fields of two string qualifiers for qsort. 909: */ 910: 911: sqcmp(q1,q2) 912: struct descrip **q1, **q2; 913: { 914: return (STRLOC(**q1) - STRLOC(**q2)); 915: } 916: 917: /* 918: * mvc - move n bytes from src to dst. 919: * src and dst must be at word boundaries. 920: */ 921: 922: mvc(n, s, d) 923: unsigned n; 924: register char *s, *d; 925: { 926: register int words; 927: int bytes; 928: 929: words = n / sizeof(int); 930: bytes = n % sizeof(int); 931: 932: if (d < s) { /* move back */ 933: while (--words >= 0) 934: *((int *)d)++ = *((int *)s)++; 935: while (--bytes >= 0) 936: *d++ = *s++; 937: } 938: else if (d > s) { /* move forward */ 939: s += n; 940: d += n; 941: while (--bytes >= 0) 942: *--d = *--s; 943: while (--words >= 0) 944: *--(int *)d = *--(int *)s; 945: } 946: } 947: #endif PDP11