Annotation of 43BSD/contrib/icon/rt/gc.c, revision 1.1

1.1     ! root        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(&current);
        !           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(&current);              /* 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
        !           948: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.