home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / runtime / ralc.r < prev    next >
Text File  |  2001-12-05  |  18KB  |  799 lines

  1. /*
  2.  * File: ralc.r
  3.  *  Contents: allocation routines
  4.  */
  5.  
  6. /*
  7.  * Prototypes.
  8.  */
  9. static struct region *findgap    (struct region *curr, word nbytes);
  10. static struct region *newregion    (word nbytes, word stdsize);
  11.  
  12. extern word alcnum;
  13.  
  14. #ifndef MultiThread
  15. word coexp_ser = 2;    /* serial numbers for co-expressions; &main is 1 */
  16. word list_ser = 1;    /* serial numbers for lists */
  17. word set_ser = 1;    /* serial numbers for sets */
  18. word table_ser = 1;    /* serial numbers for tables */
  19. #endif                    /* MultiThread */
  20.  
  21.  
  22. /*
  23.  * AlcBlk - allocate a block.
  24.  */
  25. #begdef AlcBlk(var, struct_nm, t_code, nbytes)
  26. {
  27. #ifdef MultiThread
  28.    EVVal((word)nbytes, typech[t_code]);
  29. #endif                    /* MultiThread */
  30.  
  31.    /*
  32.     * Ensure that there is enough room in the block region.
  33.     */
  34.    if (DiffPtrs(blkend,blkfree) < nbytes && !reserve(Blocks, nbytes))
  35.       return NULL;
  36.  
  37.    /*
  38.     * If monitoring, show the allocation.
  39.     */
  40. #ifndef MultiThread
  41.    EVVal((word)nbytes, typech[t_code]);
  42. #endif
  43.  
  44.    /*
  45.     * Decrement the free space in the block region by the number of bytes
  46.     *  allocated and return the address of the first byte of the allocated
  47.     *  block.
  48.     */
  49.    blktotal += nbytes;
  50.    var = (struct struct_nm *)blkfree;
  51.    blkfree += nbytes;
  52.    var->title = t_code;
  53. }
  54. #enddef
  55.  
  56. /*
  57.  * AlcFixBlk - allocate a fixed length block.
  58.  */
  59. #define AlcFixBlk(var, struct_nm, t_code)\
  60.    AlcBlk(var, struct_nm, t_code, sizeof(struct struct_nm))
  61.  
  62. /*
  63.  * AlcVarBlk - allocate a variable-length block.
  64.  */
  65. #begdef AlcVarBlk(var, struct_nm, t_code, n_desc)
  66.    {
  67. #ifdef EventMon
  68.    uword size;
  69. #else                    /* EventMon */
  70.    register uword size;
  71. #endif                    /* EventMon */
  72.  
  73.    /*
  74.     * Variable size blocks are declared with one descriptor, thus
  75.     *  we need add in only n_desc - 1 descriptors.
  76.     */
  77.    size = sizeof(struct struct_nm) + (n_desc - 1) * sizeof(struct descrip);
  78.    AlcBlk(var, struct_nm, t_code, size)
  79.    var->blksize = size;
  80.    }
  81. #enddef
  82.  
  83. /*
  84.  * alcactiv - allocate a co-expression activation block.
  85.  */
  86.  
  87. struct astkblk *alcactiv()
  88.    {
  89.    struct astkblk *abp;
  90.  
  91.    abp = (struct astkblk *)malloc(sizeof(struct astkblk));
  92.  
  93.    /*
  94.     * If malloc failed, attempt to free some co-expression blocks and retry.
  95.     */
  96.    if (abp == NULL) {
  97.       collect(Static);
  98.       abp = (struct astkblk *)malloc(sizeof(struct astkblk));
  99.       }
  100.  
  101.    if (abp == NULL)
  102.       ReturnErrNum(305, NULL);
  103.    abp->nactivators = 0;
  104.    abp->astk_nxt = NULL;
  105.    return abp;
  106.    }
  107.  
  108. #ifdef LargeInts
  109. /*
  110.  * alcbignum - allocate an n-digit bignum in the block region
  111.  */
  112.  
  113. struct b_bignum *alcbignum(n)
  114. word n;
  115.    {
  116.    register struct b_bignum *blk;
  117.    register uword size;
  118.  
  119.    size = sizeof(struct b_bignum) + ((n - 1) * sizeof(DIGIT));
  120.    /* ensure whole number of words allocated */
  121.    size = (size + WordSize - 1) & -WordSize;
  122.    AlcBlk(blk, b_bignum, T_Lrgint, size);
  123.    blk->blksize = size;
  124.    blk->msd = blk->sign = 0;
  125.    blk->lsd = n - 1;
  126.    return blk;
  127.    }
  128. #endif                    /* LargeInts */
  129.  
  130. /*
  131.  * alccoexp - allocate a co-expression stack block.
  132.  */
  133.  
  134. #if COMPILER
  135. struct b_coexpr *alccoexp()
  136.    {
  137.    struct b_coexpr *ep;
  138.    static int serial = 2; /* main co-expression is allocated elsewhere */
  139.    ep = (struct b_coexpr *)malloc(stksize);
  140.  
  141.    /*
  142.     * If malloc failed or if there have been too many co-expression allocations
  143.     * since a collection, attempt to free some co-expression blocks and retry.
  144.     */
  145.  
  146.    if (ep == NULL || alcnum > AlcMax) {
  147.       collect(Static);
  148.       ep = (struct b_coexpr *)malloc(stksize);
  149.       }
  150.  
  151.    if (ep == NULL)
  152.       ReturnErrNum(305, NULL);
  153.  
  154.    alcnum++;                    /* increment allocation count since last g.c. */
  155.  
  156.    ep->title = T_Coexpr;
  157.    ep->size = 0;
  158.    ep->id = serial++;
  159.    ep->nextstk = stklist;
  160.    ep->es_tend = NULL;
  161.    ep->file_name = "";
  162.    ep->line_num = 0;
  163.    ep->freshblk = nulldesc;
  164.    ep->es_actstk = NULL;
  165.    ep->cstate[0] = 0;        /* zero the first two cstate words as a flag */
  166.    ep->cstate[1] = 0;
  167.    stklist = ep;
  168.    return ep;
  169.    }
  170. #else                    /* COMPILER */
  171. #ifdef MultiThread
  172. /*
  173.  * If this is a new program being loaded, an icodesize>0 gives the
  174.  * hdr.hsize and a stacksize to use; allocate
  175.  * sizeof(progstate) + icodesize + mstksize
  176.  * Otherwise (icodesize==0), allocate a normal stksize...
  177.  */
  178. struct b_coexpr *alccoexp(icodesize, stacksize)
  179. long icodesize, stacksize;
  180. #else                    /* MultiThread */
  181. struct b_coexpr *alccoexp()
  182. #endif                    /* MultiThread */
  183.  
  184.    {
  185.    struct b_coexpr *ep;
  186.  
  187. #ifdef MultiThread
  188.    if (icodesize > 0) {
  189.       ep = (struct b_coexpr *)
  190.     calloc(1, stacksize+
  191.                icodesize+
  192.                sizeof(struct progstate)+
  193.                sizeof(struct b_coexpr));
  194.       }
  195.    else
  196. #endif                    /* MultiThread */
  197.  
  198.    ep = (struct b_coexpr *)malloc(stksize);
  199.  
  200.    /*
  201.     * If malloc failed or if there have been too many co-expression allocations
  202.     * since a collection, attempt to free some co-expression blocks and retry.
  203.     */
  204.  
  205.    if (ep == NULL || alcnum > AlcMax) {
  206.  
  207.       collect(Static);
  208.  
  209. #ifdef MultiThread
  210.       if (icodesize>0) {
  211.          ep = (struct b_coexpr *)
  212.         malloc(mstksize+icodesize+sizeof(struct progstate));
  213.          }
  214.       else
  215. #endif                    /* MultiThread */
  216.  
  217.          ep = (struct b_coexpr *)malloc(stksize);
  218.       }
  219.       if (ep == NULL)
  220.          ReturnErrNum(305, NULL);
  221.  
  222.    alcnum++;        /* increment allocation count since last g.c. */
  223.  
  224.    ep->title = T_Coexpr;
  225.    ep->es_actstk = NULL;
  226.    ep->size = 0;
  227. #ifdef MultiThread
  228.    ep->es_pfp = NULL;
  229.    ep->es_gfp = NULL;
  230.    ep->es_argp = NULL;
  231.    ep->tvalloc = NULL;
  232.  
  233.    if (icodesize > 0)
  234.       ep->id = 1;
  235.    else
  236. #endif                    /* MultiThread */
  237.    ep->id = coexp_ser++;
  238.    ep->nextstk = stklist;
  239.    ep->es_tend = NULL;
  240.    ep->cstate[0] = 0;        /* zero the first two cstate words as a flag */
  241.    ep->cstate[1] = 0;
  242.  
  243. #ifdef MultiThread
  244.    /*
  245.     * Initialize program state to self for &main; curpstate for others.
  246.     */
  247.    if(icodesize>0) ep->program = (struct progstate *)(ep+1);
  248.    else ep->program = curpstate;
  249. #endif                    /* MultiThread */
  250.  
  251.    stklist = ep;
  252.    return ep;
  253.    }
  254. #endif                    /* COMPILER */
  255.  
  256. /*
  257.  * alccset - allocate a cset in the block region.
  258.  */
  259.  
  260. struct b_cset *alccset()
  261.    {
  262.    register struct b_cset *blk;
  263.    register int i;
  264.  
  265.    AlcFixBlk(blk, b_cset, T_Cset)
  266.    blk->size = -1;              /* flag size as not yet computed */
  267.  
  268.    /*
  269.     * Zero the bit array.
  270.     */
  271.    for (i = 0; i < CsetSize; i++)
  272.      blk->bits[i] = 0;
  273.    return blk;
  274.    }
  275.  
  276. /*
  277.  * alcfile - allocate a file block in the block region.
  278.  */
  279.  
  280. struct b_file *alcfile(fd, status, name)
  281. FILE *fd;
  282. int status;
  283. dptr name;
  284.    {
  285.    tended struct descrip tname = *name;
  286.    register struct b_file *blk;
  287.  
  288.    AlcFixBlk(blk, b_file, T_File)
  289.    blk->fd = fd;
  290.    blk->status = status;
  291.    blk->fname = tname;
  292.    return blk;
  293.    }
  294.  
  295. /*
  296.  * alchash - allocate a hashed structure (set or table header) in the block
  297.  *  region.
  298.  */
  299. union block *alchash(tcode)
  300. int tcode;
  301.    {
  302.    register int i;
  303.    register struct b_set *ps;
  304.    register struct b_table *pt;
  305.  
  306.    if (tcode == T_Table) {
  307.       AlcFixBlk(pt, b_table, T_Table);
  308.       ps = (struct b_set *)pt;
  309.       ps->id = table_ser++;
  310.       }
  311.    else {    /* tcode == T_Set */
  312.       AlcFixBlk(ps, b_set, T_Set);
  313.       ps->id = set_ser++;
  314.       }
  315.    ps->size = 0;
  316.    ps->mask = 0;
  317.    for (i = 0; i < HSegs; i++)
  318.       ps->hdir[i] = NULL;
  319.    return (union block *)ps;
  320.    }
  321.  
  322. /*
  323.  * alcsegment - allocate a slot block in the block region.
  324.  */
  325.  
  326. struct b_slots *alcsegment(nslots)
  327. word nslots;
  328.    {
  329.    uword size;
  330.    register struct b_slots *blk;
  331.  
  332.    size = sizeof(struct b_slots) + WordSize * (nslots - HSlots);
  333.    AlcBlk(blk, b_slots, T_Slots, size);
  334.    blk->blksize = size;
  335.    while (--nslots >= 0)
  336.       blk->hslots[nslots] = NULL;
  337.    return blk;
  338.    }
  339.  
  340. /*
  341.  * alclist - allocate a list header block in the block region.
  342.  *
  343.  *  Forces a g.c. if there's not enough room for the whole list.
  344.  */
  345.  
  346. struct b_list *alclist(size)
  347. uword size;
  348.    {
  349.    register struct b_list *blk;
  350.  
  351.    if (!reserve(Blocks, (word)(sizeof(struct b_list) + sizeof (struct b_lelem)
  352.       + (size - 1) * sizeof(struct descrip)))) return NULL;
  353.    AlcFixBlk(blk, b_list, T_List)
  354.    blk->size = size;
  355.    blk->id = list_ser++;
  356.    blk->listhead = NULL;
  357.    blk->listtail = NULL;
  358.    return blk;
  359.    }
  360.  
  361. /*
  362.  * alclstb - allocate a list element block in the block region.
  363.  */
  364.  
  365. struct b_lelem *alclstb(nslots, first, nused)
  366. uword nslots, first, nused;
  367.    {
  368.    register struct b_lelem *blk;
  369.    register word i;
  370.  
  371.    AlcVarBlk(blk, b_lelem, T_Lelem, nslots)
  372.    blk->nslots = nslots;
  373.    blk->first = first;
  374.    blk->nused = nused;
  375.    blk->listprev = NULL;
  376.    blk->listnext = NULL;
  377.    /*
  378.     * Set all elements to &null.
  379.     */
  380.    for (i = 0; i < nslots; i++)
  381.       blk->lslots[i] = nulldesc;
  382.    return blk;
  383.    }
  384.  
  385. /*
  386.  * alcreal - allocate a real value in the block region.
  387.  */
  388.  
  389. struct b_real *alcreal(val)
  390. double val;
  391.    {
  392.    register struct b_real *blk;
  393.  
  394.    AlcFixBlk(blk, b_real, T_Real)
  395.  
  396. #ifdef Double
  397. /* access real values one word at a time */
  398.    { int *rp, *rq;
  399.      rp = (int *) &(blk->realval);
  400.      rq = (int *) &val;
  401.      *rp++ = *rq++;
  402.      *rp   = *rq;
  403.    }
  404. #else                                   /* Double */
  405.    blk->realval = val;
  406. #endif                                  /* Double */
  407.  
  408.    return blk;
  409.    }
  410.  
  411. /*
  412.  * alcrecd - allocate record with nflds fields in the block region.
  413.  */
  414.  
  415. struct b_record *alcrecd(nflds, recptr)
  416. int nflds;
  417. union block *recptr;
  418.    {
  419.    tended union block *trecptr = recptr;
  420.    register struct b_record *blk;
  421.  
  422.    AlcVarBlk(blk, b_record, T_Record, nflds)
  423.    blk->recdesc = trecptr;
  424.    blk->id = (((struct b_proc *)recptr)->recid)++;
  425.    return blk;
  426.    }
  427.  
  428. /*
  429.  * alcrefresh - allocate a co-expression refresh block.
  430.  */
  431.  
  432. #if COMPILER
  433. struct b_refresh *alcrefresh(na, nl, nt, wrk_sz)
  434. int na;
  435. int nl;
  436. int nt;
  437. int wrk_sz;
  438.    {
  439.    struct b_refresh *blk;
  440.  
  441.    AlcVarBlk(blk, b_refresh, T_Refresh, na + nl)
  442.    blk->nlocals = nl;
  443.    blk->nargs = na;
  444.    blk->ntemps = nt;
  445.    blk->wrk_size = wrk_sz;
  446.    return blk;
  447.    }
  448. #else                    /* COMPILER */
  449. struct b_refresh *alcrefresh(entryx, na, nl)
  450. word *entryx;
  451. int na, nl;
  452.    {
  453.    struct b_refresh *blk;
  454.  
  455.    AlcVarBlk(blk, b_refresh, T_Refresh, na + nl);
  456.    blk->ep = entryx;
  457.    blk->numlocals = nl;
  458.    return blk;
  459.    }
  460. #endif                    /* COMPILER */
  461.  
  462. /*
  463.  * alcselem - allocate a set element block.
  464.  */
  465.  
  466. struct b_selem *alcselem(mbr,hn)
  467. uword hn;
  468. dptr mbr;
  469.  
  470.    {
  471.    tended struct descrip tmbr = *mbr;
  472.    register struct b_selem *blk;
  473.  
  474.    AlcFixBlk(blk, b_selem, T_Selem)
  475.    blk->clink = NULL;
  476.    blk->setmem = tmbr;
  477.    blk->hashnum = hn;
  478.    return blk;
  479.    }
  480.  
  481. /*
  482.  * alcstr - allocate a string in the string space.
  483.  */
  484.  
  485. char *alcstr(s, slen)
  486. register char *s;
  487. register word slen;
  488.    {
  489.    tended struct descrip ts;
  490.    register char *d;
  491.    char *ofree;
  492.  
  493. #ifdef MultiThread
  494.    StrLen(ts) = slen;
  495.    StrLoc(ts) = s;
  496. #ifdef EventMon
  497.    if (!noMTevents)
  498. #endif                    /* EventMon */
  499.       EVVal(slen, E_String);
  500.    s = StrLoc(ts);
  501. #endif                    /* MultiThread */
  502.  
  503.    /*
  504.     * Make sure there is enough room in the string space.
  505.     */
  506.    if (DiffPtrs(strend,strfree) < slen) {
  507.       StrLen(ts) = slen;
  508.       StrLoc(ts) = s;
  509.       if (!reserve(Strings, slen))
  510.          return NULL;
  511.       s = StrLoc(ts);
  512.       }
  513.  
  514.    strtotal += slen;
  515.  
  516.    /*
  517.     * Copy the string into the string space, saving a pointer to its
  518.     *  beginning.  Note that s may be null, in which case the space
  519.     *  is still to be allocated but nothing is to be copied into it.
  520.     */
  521.    ofree = d = strfree;
  522.    if (s) {
  523.       while (slen-- > 0)
  524.          *d++ = *s++;
  525.       }
  526.    else
  527.       d += slen;
  528.  
  529.    strfree = d;
  530.    return ofree;
  531.    }
  532.  
  533. /*
  534.  * alcsubs - allocate a substring trapped variable in the block region.
  535.  */
  536.  
  537. struct b_tvsubs *alcsubs(len, pos, var)
  538. word len, pos;
  539. dptr var;
  540.    {
  541.    tended struct descrip tvar = *var;
  542.    register struct b_tvsubs *blk;
  543.  
  544.    AlcFixBlk(blk, b_tvsubs, T_Tvsubs)
  545.    blk->sslen = len;
  546.    blk->sspos = pos;
  547.    blk->ssvar = tvar;
  548.    return blk;
  549.    }
  550.  
  551. /*
  552.  * alctelem - allocate a table element block in the block region.
  553.  */
  554.  
  555. struct b_telem *alctelem()
  556.    {
  557.    register struct b_telem *blk;
  558.  
  559.    AlcFixBlk(blk, b_telem, T_Telem)
  560.    blk->hashnum = 0;
  561.    blk->clink = NULL;
  562.    blk->tref = nulldesc;
  563.    return blk;
  564.    }
  565.  
  566. /*
  567.  * alctvtbl - allocate a table element trapped variable block in the block
  568.  *  region.
  569.  */
  570.  
  571. struct b_tvtbl *alctvtbl(tbl, ref, hashnum)
  572. register dptr tbl, ref;
  573. uword hashnum;
  574.    {
  575.    tended struct descrip ttbl = *tbl;
  576.    tended struct descrip tref = *ref;
  577.    register struct b_tvtbl *blk;
  578.  
  579.    AlcFixBlk(blk, b_tvtbl, T_Tvtbl)
  580.    blk->hashnum = hashnum;
  581.    blk->clink = BlkLoc(ttbl);
  582.    blk->tref = tref;
  583.    return blk;
  584.    }
  585.  
  586. /*
  587.  * deallocate - return a block to the heap.
  588.  *
  589.  *  The block must be the one that is at the very end of a block region.
  590.  */
  591. void deallocate (bp)
  592. union block *bp;
  593. {
  594.    word nbytes;
  595.    struct region *rp;
  596.  
  597.    nbytes = BlkSize(bp);
  598.    for (rp = curblock; rp; rp = rp->next)
  599.       if ((char *)bp + nbytes == rp->free)
  600.          break;
  601.    if (!rp)
  602.       for (rp = curblock->prev; rp; rp = rp->prev)
  603.      if ((char *)bp + nbytes == rp->free)
  604.             break;
  605.    if (!rp)
  606.       syserr ("deallocation botch");
  607.    rp->free = (char *)bp;
  608.    blktotal -= nbytes;
  609.    EVVal(nbytes, E_BlkDeAlc);
  610. }
  611.  
  612. /*
  613.  * reserve -- ensure space in either string or block region.
  614.  *
  615.  *   1. check for space in current region.
  616.  *   2. check for space in older regions.
  617.  *   3. check for space in newer regions.
  618.  *   4. set goal of 10% of size of newest region.
  619.  *   5. collect regions, newest to oldest, until goal met.
  620.  *   6. allocate new region at 200% the size of newest existing.
  621.  *   7. reset goal back to original request.
  622.  *   8. collect regions that were too small to bother with before.
  623.  *   9. search regions, newest to oldest.
  624.  *  10. give up and signal error.
  625.  */
  626.  
  627. char *reserve(region, nbytes)
  628. int region;
  629. word nbytes;
  630. {
  631.    struct region **pcurr, *curr, *rp;
  632.    word want, newsize;
  633.    extern int qualfail;
  634.  
  635.    if (region == Strings)
  636.       pcurr = &curstring;
  637.    else
  638.       pcurr = &curblock;
  639.    curr = *pcurr;
  640.  
  641.    /*
  642.     * Check for space available now.
  643.     */
  644.    if (DiffPtrs(curr->end, curr->free) >= nbytes)
  645.       return curr->free;        /* quick return: current region is OK */
  646.  
  647.    if ((rp = findgap(curr, nbytes)) != 0) {    /* check all regions on chain */
  648.       *pcurr = rp;            /* switch regions */
  649.       return rp->free;
  650.       }
  651.  
  652.    /*
  653.     * Set "curr" to point to newest region.
  654.     */
  655.    while (curr->next)
  656.       curr = curr->next;
  657.  
  658.    /*
  659.     * Need to collect garbage.  To reduce thrashing, set a minimum requirement
  660.     *  of 10% of the size of the newest region, and collect regions until that
  661.     *  amount of free space appears in one of them.
  662.     */
  663.    want = (curr->size / 100) * memcushion;
  664.    if (want < nbytes)
  665.       want = nbytes;
  666.  
  667.    for (rp = curr; rp; rp = rp->prev)
  668.       if (rp->size >= want) {    /* if large enough to possibly succeed */
  669.          *pcurr = rp;
  670.          collect(region);
  671.          if (DiffPtrs(rp->end,rp->free) >= want)
  672.             return rp->free;
  673.          }
  674.  
  675.    /*
  676.     * That didn't work.  Allocate a new region with a size based on the
  677.     * newest previous region.
  678.     */
  679.    newsize = (curr->size / 100) * memgrowth;
  680.    if (newsize < nbytes)
  681.       newsize = nbytes;
  682.    if (newsize < MinAbrSize)
  683.       newsize = MinAbrSize;
  684.  
  685.    if ((rp = newregion(nbytes, newsize)) != 0) {
  686.       rp->prev = curr;
  687.       rp->next = NULL;
  688.       curr->next = rp;
  689.       rp->Gnext = curr;
  690.       rp->Gprev = curr->Gprev;
  691.       if (curr->Gprev) curr->Gprev->Gnext = rp;
  692.       curr->Gprev = rp;
  693.       *pcurr = rp;
  694. #ifdef EventMon
  695.       if (!noMTevents) {
  696.          if (region == Strings) {
  697.             EVVal(rp->size, E_TenureString);
  698.             }
  699.          else {
  700.             EVVal(rp->size, E_TenureBlock);
  701.             }
  702.          }
  703. #endif                    /* EventMon */
  704.       return rp->free;
  705.       }
  706.  
  707.    /*
  708.     * Allocation failed.  Try to continue, probably thrashing all the way.
  709.     *  Collect the regions that weren't collected before and see if any
  710.     *  region has enough to satisfy the original request.
  711.     */
  712.    for (rp = curr; rp; rp = rp->prev)
  713.       if (rp->size < want) {        /* if not collected earlier */
  714.          *pcurr = rp;
  715.          collect(region);
  716.          if (DiffPtrs(rp->end,rp->free) >= want)
  717.             return rp->free;
  718.          }
  719.    if ((rp = findgap(curr, nbytes)) != 0) {
  720.       *pcurr = rp;
  721.       return rp->free;
  722.       }
  723.  
  724.    /*
  725.     * All attempts failed.
  726.     */
  727.    if (region == Blocks)
  728.       ReturnErrNum(307, 0);
  729.    else if (qualfail)
  730.       ReturnErrNum(304, 0);
  731.    else
  732.       ReturnErrNum(306, 0);
  733. }
  734.  
  735. /*
  736.  * findgap - search region chain for a region having at least nbytes available
  737.  */
  738. static struct region *findgap(curr, nbytes)
  739. struct region *curr;
  740. word nbytes;
  741.    {
  742.    struct region *rp;
  743.  
  744.    for (rp = curr; rp; rp = rp->prev)
  745.       if (DiffPtrs(rp->end, rp->free) >= nbytes)
  746.          return rp;
  747.    for (rp = curr->next; rp; rp = rp->next)
  748.       if (DiffPtrs(rp->end, rp->free) >= nbytes)
  749.          return rp;
  750.    return NULL;
  751.    }
  752.  
  753. /*
  754.  * newregion - try to malloc a new region and tenure the old one,
  755.  *  backing off if the requested size fails.
  756.  */
  757. static struct region *newregion(nbytes,stdsize)
  758. word nbytes,stdsize;
  759. {
  760.    uword minSize = MinAbrSize;
  761.    struct region *rp;
  762.  
  763. #if IntBits == 16
  764.    if ((uword)nbytes > (uword)MaxBlock)
  765.       return NULL;
  766.    if ((uword)stdsize > (uword)MaxBlock)
  767.       stdsize = (uword)MaxBlock;
  768. #endif                    /* IntBits == 16 */
  769.  
  770.    if ((uword)nbytes > minSize)
  771.       minSize = (uword)nbytes;
  772.  
  773.    rp = (struct region *)malloc(sizeof(struct region));
  774.    if (rp) {
  775.       rp->size = stdsize;
  776. #if IntBits == 16
  777.       if ((rp->size < nbytes) && (nbytes < (unsigned int)MaxBlock))
  778.          rp->size = Min(nbytes+stdsize,(unsigned int)MaxBlock);
  779. #else                    /* IntBits == 16 */
  780.       if (rp->size < nbytes)
  781.          rp->size = Max(nbytes+stdsize, nbytes);
  782. #endif                    /* IntBits == 16 */
  783.  
  784.       do {
  785.          rp->free = rp->base = (char *)AllocReg(rp->size);
  786.          if (rp->free != NULL) {
  787.             rp->end = rp->base + rp->size;
  788.             return rp;
  789.             }
  790.          else {
  791.             }
  792.          rp->size = (rp->size + nbytes)/2 - 1;
  793.          }
  794.       while (rp->size >= minSize);
  795.       free((char *)rp);
  796.       }
  797.    return NULL;
  798. }
  799.