Annotation of researchv10dc/cmd/icon/src/iconx/rmemmgt.c, revision 1.1.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.