Annotation of researchv10dc/cmd/icon/src/iconx/rmemmgt.c, revision 1.1

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 &current
        !           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(&current);
        !           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:    }

unix.superglobalmegacorp.com

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