home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / sml_nj / 93src.lha / src / runtime / gc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-09  |  17.4 KB  |  623 lines

  1. /* gc.c
  2.  *
  3.  * COPYRIGHT (c) 1989 by AT&T Bell Laboratories.
  4.  */
  5.  
  6. #include "tags.h"
  7. #include "ml_state.h"
  8. #include "eventchk.h"
  9.  
  10. /** This stuff used to be in "descriptor.h."  It should probably be merged with
  11.  ** the definitions in "ml_types.h."
  12.  **/
  13. #define is_ptr(x)    (((int)(x)&0x3) == 0)
  14. #define mask_tags    (power_tags-1)
  15. #define get_len(x)    (*(int *)(x)>>width_tags)
  16. #define get_lenz(x)    ((((*(int*)(x)) & mask_tags) == TAG_special) ? 1 : get_len(x))
  17. #define get_strlen(x)    (((*(int *)(x)>>width_tags)+3) >> 2)
  18. #define get_realarraylenw(x)    (get_len(x) << 1)  /* word len */
  19. #define get_realarraylenb(x)    (get_len(x) << 3)  /* byte len */
  20. #define tag_from_desc(d)    ((d) & mask_tags)
  21. #define get_tag(x)        tag_from_desc(*(int *)(x))
  22.  
  23. /* return true if "m" points to the descriptor word of a code string. */
  24. #define isCodeString(m)        \
  25.     (((get_len(m) & 1) == 0) && ((*((m)+2)) == MAKE_DESC(1,TAG_backptr)))
  26.  
  27. /* Given a 6-bit tag, return true if is the tag of an object that cannot
  28.  * contain pointers.
  29.  */
  30. static char hasNoPtrs[16] = {
  31.     0, 1, 1, 0,     /* pair, reald, emb_reald, unused */
  32.     0, 1, 0, 0,    /* special, backptr, unused, forwarded */
  33.     0, 0, 1, 1,    /* record, array, string, emb_string */
  34.     1, 1, 0, 0    /* bytearray, realdarray, unused, unused */
  35.     };
  36. #define ContainsNoPtrs(x)    (hasNoPtrs[((x)>>2)&0xF])
  37.  
  38. /*** NOTE: the following comment is wrong with respect to the new taggin scheme,
  39.  *** but I'm not going to bother to fix it, since the GCs days are numbered.
  40.  ***/
  41. /* registers:
  42.  inside arenas: allocation is on word boundaries and in units a multiple
  43.     of a word (4 bytes) so words with odd contents are not pointers.
  44.     Conversely, if a word is pointed to by a pointer p (i.e., the word
  45.     is p[0], then p[-1] contains a descriptor of the record the word is in:
  46.     struct {
  47.         unsigned int flg:width_tags;    least sig bits
  48.         int len:32-width_tags;
  49.     } mem;
  50.     flag is even:  look in previous word for descriptor
  51.     flag is odd: this is the descriptor.
  52.     len gives the number of 4-byte words. (not incl. descriptor)
  53.     For any record in a collectable area, len>0
  54.     when the gc isn't running:
  55.                flag=1    record containing pointers & integers
  56.                flag=5    record containing no pointers
  57.                flag=7    look in p[-len-1] for descriptor
  58.     when gc is running, descriptor in the TO space:
  59.             as above, but flag=3 not possible
  60.     when the gc is running, descriptor in the FROM space:
  61.                flag=1    unmoved record containing pointers & integers
  62.                flag=3    record has already been moved, in which case,
  63.                  p[0] is the forwarding pointer.
  64.                flag=5    unmoved record containing no pointers
  65.                flag=7    look in p[-len-1] for descriptor
  66.  
  67.     In a record containing pointers & integers,
  68.       any even number is a pointer, any odd number is not a pointer.
  69.  
  70.     There are occasional pointers to places outside the GC arena;
  71.      these get copied intact.
  72.  
  73.     Format of linked list of stored-into ref cells:
  74.       p[0] = pointer to a ref or array cell that's been stored into.
  75.       p[1] = index within object of modified slot
  76.       p[2] = next object on list (1 for nil)
  77.  
  78.     We only need to flush the I-cache if we move a piece of code.
  79.     Code is always in a string object with the following layout:
  80.  
  81.                        +------------------+
  82.     obj descriptor |  len:TAG_string  |
  83.                        +------------------+
  84.     ptr to object ---->|  register mask   |<--+
  85.                        +------------------+   |
  86.                |  backptr   o---------+
  87.                +------------------+
  88.                        |    code...       |
  89.  
  90.     The length of the string is guaranteed to be an even # of words
  91.     by the code generator.  Also, the backptr is guaranteed to have
  92.     the same value (offset 1, TAG_backptr).  So, if we encounter
  93.     an object that has these attributes and is forwarded, only then
  94.     must we flush the I-cache.
  95.  
  96. */
  97.  
  98. int ** (*gmore)();
  99. static int **to_ptr, **to_lim, **to_lim0;
  100. static int **lowest, **highest;
  101. static int repair;
  102. static int any_weak;
  103. static int *should_flush;
  104.  
  105. extern int store_preserve, preserving;
  106.  
  107. /*static
  108. xgc(refloc)
  109. register int *refloc;*/
  110. #define xgc(refloc)\
  111. {register int *m = *((int**)(refloc));\
  112.   /* if refloc is not a pointer,\
  113.          or is not in the allocated area, just leave it alone */\
  114.  if(is_ptr(m) && (m >= (int*)lowest && m < (int*)highest))\
  115.  { m--;\
  116.    for(;;)\
  117.       {\
  118.     switch(get_tag(m)) {\
  119.     case TAG_backptr:\
  120.         m -= get_len(m);\
  121.         continue;\
  122.     case TAG_emb_string:\
  123.     case TAG_emb_reald:\
  124.         m--; continue;\
  125.     case TAG_string:\
  126.             if (isCodeString(m))\
  127.           *should_flush = 1;\
  128.         /* fall through */\
  129.     case TAG_bytearray:\
  130.         {register int **i=(int**)m, **j=to_ptr, len1 = get_strlen(m)+1;\
  131.          if (j+len1 > to_lim) do {if (repair) \
  132.                         {repair=0; to_lim=to_lim0;} \
  133.                       else to_lim=gmore();}\
  134.                       while (j+len1 > to_lim);\
  135.          do {*j++ = *i++;} while (--len1 > 0);\
  136.              if (repair)  \
  137.            {if (to_ptr+5 < to_lim) \
  138.             {* -- to_lim = ((int**)m)[1]; \
  139.              * -- to_lim = m+1; \
  140.             } \
  141.             else {repair=0; to_lim=to_lim0;} \
  142.            } \
  143.          ((int**)m)[1]= 1+(int*)to_ptr;\
  144.          to_ptr = j;\
  145.         }\
  146.         (*m) = TAG_forwarded;\
  147.         *(int*)(refloc) += ((int*)m)[1] - ((int)(m+1));\
  148.         break;\
  149.     case TAG_reald: {\
  150.         register int **j=to_ptr; \
  151.         if (j+3 > to_lim) \
  152.             do { \
  153.             if (repair) {repair=0; to_lim=to_lim0;} else to_lim=gmore(); \
  154.             } while (j+3 > to_lim); \
  155.         *j++ = ((int **)m)[0]; \
  156.         *j++ = ((int **)m)[1]; \
  157.         *j++ = ((int **)m)[2]; \
  158.         m[0] = TAG_forwarded; \
  159.         m[1] = (int)(to_ptr+1);\
  160.         to_ptr = j; \
  161.         *(int*)(refloc) += ((int*)m)[1] - ((int)(m+1));\
  162.         break; \
  163.         }\
  164.     case TAG_realdarray: {\
  165.         register int **i=(int**)m, **j=to_ptr, len1 = get_realarraylenw(m)+1;\
  166.         if (j+len1 > to_lim) do {if (repair) \
  167.                         {repair=0; to_lim=to_lim0;} \
  168.                       else to_lim=gmore();}\
  169.                       while (j+len1 > to_lim);\
  170.         do {*j++ = *i++;} while (--len1 > 0);\
  171.             if (repair) { \
  172.             if (to_ptr+5 < to_lim) {\
  173.                 * -- to_lim = ((int**)m)[1]; \
  174.                 * -- to_lim = m+1; \
  175.             } \
  176.             else {repair=0; to_lim=to_lim0;} \
  177.         } \
  178.         ((int**)m)[1]= 1+(int*)to_ptr;\
  179.         to_ptr = j;\
  180.         (*m) = TAG_forwarded;\
  181.         *(int*)(refloc) += ((int*)m)[1] - ((int)(m+1));\
  182.         } break;\
  183.     case TAG_array:\
  184.       if (preserving)        \
  185.         {*to_ptr++ = (int*)MAKE_DESC(3, TAG_record);        \
  186.              *to_ptr++ = m+1;    \
  187.          *to_ptr++ = (int*)-1;    \
  188.          *to_ptr++ = (int*)store_preserve;    \
  189.          store_preserve = (int) (to_ptr-3);    \
  190.         }    \
  191.     case TAG_pair:\
  192.     case TAG_record:\
  193.         {register int **i=(int**)m, **j=to_ptr, len1 = get_len(m)+1;\
  194.          if (j+len1 > to_lim) do {if (repair) \
  195.                         {repair=0; to_lim=to_lim0;} \
  196.                       else to_lim=gmore();}\
  197.                       while (j+len1 > to_lim);\
  198.          do {*j++ = *i++;} while (--len1 > 0);\
  199.              if (repair)  \
  200.            {if (to_ptr+5 < to_lim) \
  201.             {* -- to_lim = ((int**)m)[1]; \
  202.              * -- to_lim = m+1; \
  203.             } \
  204.             else {repair=0; to_lim=to_lim0;} \
  205.            } \
  206.          ((int**)m)[1]= 1+(int*)to_ptr;\
  207.          to_ptr = j;\
  208.         }\
  209.         (*m) = TAG_forwarded;\
  210.         /* fall through */\
  211.     case TAG_forwarded:\
  212.         *(int*)(refloc) += ((int*)m)[1] - ((int)(m+1));\
  213.         break;\
  214.     case TAG_special:\
  215.         {register int **i=(int**)m, **j=to_ptr, len1 = 2;\
  216.          if (j+len1 > to_lim) do {if (repair) \
  217.                         {repair=0; to_lim=to_lim0;} \
  218.                       else to_lim=gmore();}\
  219.                       while (j+len1 > to_lim);\
  220.          do {*j++ = *i++;} while (--len1 > 0);\
  221.              if (repair)  \
  222.            {if (to_ptr+5 < to_lim) \
  223.             {* -- to_lim = ((int**)m)[1]; \
  224.              * -- to_lim = m+1; \
  225.             } \
  226.             else {repair=0; to_lim=to_lim0;} \
  227.            } \
  228.          ((int**)m)[1]= 1+(int*)to_ptr;\
  229.          to_ptr = j;\
  230.             }\
  231.         (*m) = TAG_forwarded;\
  232.            *(int*)(refloc) += ((int*)m)[1] - ((int)(m+1));\
  233.                 break;\
  234.     default: /* function pointers */\
  235.         m--; continue;\
  236.      }\
  237.      break;\
  238.     }\
  239.    }\
  240.    MAYBE_EVENTCHK();\
  241. }
  242.  
  243. gc(MLState,
  244.    from_low,        /* lowest address in space to be collected from */
  245.    from_high,        /* higher than any ... */
  246.    to_low,        /* lowest address in space to copy into */
  247.    to_high,        /* limit address to copy into */
  248.    to_done,        /* to-space is already copied into up to here */
  249.    to_where,        /* (by-ref) just past highest address copied into */
  250.    misc_roots,        /* vector (0-terminated) of ptrs to possible root words */
  251.    store_lists,        /* vector of head of linked list of store-pointers */
  252.    shouldFlush,     /* flag to indicate whether a code string was moved */
  253.    get_more,        /* procedure to call to increase to_lim */
  254.    first_root       /* (optional) address of interesting root to trace;
  255.                if present, then to_done must equal to_low */
  256. )
  257.   MLState_ptr MLState;
  258.   int **from_low, **from_high, ***misc_roots,
  259.       **to_low, **to_high, **to_done,
  260.       ***to_where, ***store_lists;
  261.   int *shouldFlush;
  262.   int *first_root;
  263.   int ** (*get_more)();
  264. {
  265. #ifdef HEAP_TRACE
  266.     target = 0;
  267. #endif
  268.     any_weak = 0;
  269.     gmore=get_more;
  270.     to_ptr = to_done;
  271.     to_lim0 = to_lim = to_high;
  272.     lowest=from_low;
  273.     highest=from_high;
  274.     should_flush = shouldFlush;
  275.     
  276.         repair=0;
  277.         if (first_root)
  278.       {register int x;
  279.            int **blast_begin = to_low;
  280.        repair=1;
  281.        xgc(first_root);
  282.        x = (int) to_done;
  283.            while (x<(int)to_ptr)
  284.         {register int p = x+4;
  285.          {register int tag = get_tag((int *)(x));
  286.           if (ContainsNoPtrs(tag)) {
  287.         if (tag == TAG_reald) x += 12;
  288.         else if (tag == TAG_realdarray) x += (get_realarraylenb(x) + 4);
  289.         else x += ((get_strlen(x) << 2) + 4);
  290.         continue;
  291.           }
  292.           x += get_lenz(x) * 4 + 4;
  293.          }
  294.          do{xgc(p); p+=4;} while (p<x);
  295.         }
  296.        blast_write(MLState, blast_begin, x, *first_root);
  297.        if (repair)
  298.         {while(to_lim<to_lim0)
  299.           {int *loc = *to_lim++;
  300.            int *old = *to_lim++;
  301.            loc[-1] = ((int*)(loc[0]))[-1];
  302.            loc[0] = (int)old;
  303.           }
  304.          return 0;
  305.         }
  306.       }
  307.  
  308.  
  309.     /* do the refs */
  310. #ifdef GCDEBUG
  311.         chatting("\nto_ptr at %x...  ",to_ptr);
  312.         chatting("beginning refs... ");
  313. #endif
  314.      {register int ***store_list;
  315.       register int **px;
  316. #ifdef GCDEBUG
  317.      int count=0;
  318. #endif
  319.      for (store_list=store_lists; *store_list; store_list++) {
  320.        for(px= (*store_list); ((int)px)!=1; px= (int**) (px[2]))
  321.         {register int **r;
  322. #ifdef GCDEBUG
  323.          count++;
  324. #endif
  325.          r = (int**)(px[0])+(((int)(px[1]))>>1);
  326.          if (r>=from_low && r < from_high) continue;
  327.           if (preserving)
  328.         {*to_ptr++ = (int*)MAKE_DESC(3, TAG_record);
  329.              *to_ptr++ = px[0];
  330.          *to_ptr++ = px[1];
  331.          *to_ptr++ = (int*)store_preserve;
  332.          store_preserve = (int) (to_ptr-3);
  333.         }
  334.          xgc(r);
  335.         }
  336.      }
  337. #ifdef GCDEBUG
  338.     chatting("(%d refs)\n",count);
  339. #endif
  340.     }
  341.  
  342.     /* do misc. roots */
  343. #ifdef GCDEBUG
  344.         chatting("to_ptr at %x...  ",to_ptr);
  345.         chatting("beginning misc roots\n");
  346. #endif
  347.     { register int ***p;
  348.       for(p=misc_roots; *p; p++) xgc(*p);
  349.     }
  350.  
  351.     /* finish the new space */
  352. #ifdef GCDEBUG
  353.         chatting("to_ptr at %x...  ",to_ptr);
  354.         chatting("finishing new space\n");
  355. #endif
  356.     {register int x = (int)to_low;
  357.          while (x < (int)to_ptr)
  358.         {register int p = x+4;
  359.          {register int descr = *(int *)(x);
  360.           register int tag = tag_from_desc(descr);
  361.           if (ContainsNoPtrs(tag)) {
  362.         if (tag == TAG_reald) x += 12;
  363.         else if (tag == TAG_realdarray) x += (get_realarraylenb(x) + 4);
  364.         else x += ((get_strlen(x) << 2) + 4);
  365.         continue;
  366.           }
  367.           x += get_lenz(x) * 4 + 4;
  368. #ifdef HEAP_TRACE
  369.           if (descr == tag_suspension + 4*power_tags)
  370.           target=p;
  371. #endif
  372.           if (descr == DESC_weak)
  373.                   {any_weak=1; continue;}
  374.          }
  375.              do{xgc(p); p+=4;} while (p<x);
  376.         }
  377.     }
  378. #ifdef GCDEBUG
  379.         chatting("to_ptr at %x...  ",to_ptr);
  380. #endif
  381.         if (any_weak)
  382.     {register int x = (int)to_low;
  383. #ifdef GCDEBUG
  384.      chatting("doing weak pointers\n");
  385. #endif
  386.          while (x<(int)to_ptr)
  387.         {int *p = ((int*)x)+1;
  388.          int descr = *(int *)(x);
  389.          int tag = tag_from_desc(descr);
  390.          if (ContainsNoPtrs(tag)) {
  391.         if (tag == TAG_reald) x += 12;
  392.         else if (tag == TAG_realdarray) x += (get_realarraylenb(x) + 4);
  393.         else x += ((get_strlen(x) << 2) + 4);
  394.         continue;
  395.          }
  396.          x += get_lenz(x) * 4 + 4;
  397.          if (descr == DESC_weak)
  398.                  {int *m = ((int*)*p)-1;
  399.                   if (is_ptr(m) && m >= (int*)from_low && m <= (int*)from_high)
  400.                       for(;;)
  401.                         {switch(get_tag(m))
  402.                           {case TAG_string: case TAG_bytearray:
  403.                            case TAG_array: case TAG_record:
  404.                case TAG_reald: case TAG_realdarray:
  405.                            case TAG_special: case TAG_pair:
  406.                                      *p = 1; 
  407.                      p[-1] = DESC_null_weak;
  408.                      break;
  409.                            case TAG_forwarded:
  410.                                      *p += m[1] - (int) (m+1);
  411.                      break;
  412.                            case TAG_backptr: m -= get_len(m); 
  413.                                     continue;
  414.                            case TAG_emb_reald: case TAG_emb_string: 
  415.                default:
  416.                     m--; 
  417.                                     continue;
  418.               }
  419.                          break;
  420.             }
  421.          }
  422.         }
  423.     }
  424. #ifdef GCDEBUG
  425.         chatting("to_ptr at %x...  ",to_ptr);
  426.         chatting("gc done\n");
  427. #endif
  428. #ifdef HEAP_TRACE
  429.         if (target) trace(to_low,target,target+4);
  430. #endif
  431.         *to_where = to_ptr;
  432.         return 1;
  433. }
  434.  
  435. blockmove(from,to,words) register int * from, *to; register int words;
  436. {
  437.  if (!words) return;
  438.  if (from<to && from+words >to)
  439.     {from+=words; to+=words;    
  440.      do {*--to = *--from;} while (--words > 0);
  441.     }
  442.  else do {*to++ = *from++;} while (--words > 0);
  443. }
  444.  
  445. moveback
  446.   (from_low,        /* lowest address in space to be collected from */
  447.    from_high,        /* higher than any ... */
  448.    to_low,        /* lowest address in space to copy into */
  449.    misc_roots        /* vector (0-terminated) of ptrs to possible root words */
  450. )
  451.   int *from_low, *from_high, **misc_roots,
  452.       *to_low;
  453. {    register int *x, offset = sizeof(int)*(to_low-from_low);
  454.  
  455. #define INRANGE(x)  (((int)(x) >= (int)from_low) &&  \
  456.              ((int)(x) < (int)from_high) )
  457. #define ADJUST1(x)   (INRANGE(x)?(x)+=offset:0)
  458. #define ADJUST(x) (is_ptr(x)?ADJUST1(x):0)
  459.  
  460.     /* do misc. roots */
  461. #ifdef GCDEBUG
  462.     chatting("misc roots... ");
  463. #endif
  464.     { register int **p;
  465.       for(p=misc_roots; *p; p++) ADJUST(**p);
  466.     }
  467.  
  468.     /* finish the new space */
  469. #ifdef GCDEBUG
  470.     chatting("finishing... ");
  471. #endif
  472.     x=from_low;
  473.     while (x<from_high) {
  474.         int tag = get_tag(x);
  475.         if (ContainsNoPtrs(tag)) {
  476.         if (tag == TAG_reald) x += 3;
  477.         else if (tag == TAG_realdarray) x += (get_realarraylenw(x) + 1);
  478.         else x += (get_strlen(x) + 1);
  479.         }
  480.         else {register int i = get_lenz(x);
  481.         ++x;
  482.         do {ADJUST(*x); x++;} while (--i > 0);
  483.         }
  484.     }
  485.     blockmove(from_low,to_low,from_high-from_low);
  486. #ifdef GCDEBUG
  487.     chatting("done\n");
  488. #endif
  489. }
  490.  
  491. relocate (start, end, stuff)
  492.     int start, end;
  493.     int *stuff;
  494. {
  495.     int *x = stuff, *done = stuff + (end-start)/4;
  496.     int adjust = ((int)stuff) - start;
  497.  
  498.     while (x < done) {
  499.     int tag = get_tag(x);
  500.     if (ContainsNoPtrs(tag)) {
  501.         if (tag == TAG_reald) x += 3;
  502.         else if (tag == TAG_realdarray) x += (get_realarraylenw(x) + 1);
  503.         else x += (get_strlen(x) + 1);
  504.     }
  505.     else {
  506.         register int i = get_lenz(x);
  507.         ++x;
  508.         do {
  509.         if (is_ptr(*x) && *x >= start && *x < end)
  510.             *x += adjust;
  511.         x++;
  512.         } while (--i > 0);
  513.     }
  514.     }
  515. }
  516.  
  517. #ifdef HEAP_TRACE
  518. /* this is from the old "trace.c" */
  519.  
  520. trace(to_low, target_lo, target_hi) int *to_low, *target_lo, *target_hi;
  521. {int *x=to_low;
  522.  chatting("tracing %8x\n", target_lo);
  523.   while(x<target_lo)
  524.    {int *p= x+1, *x0= x;
  525.     int tag = get_tag(x);
  526.     if (ContainsNoPtrs(tag)) {
  527.     if (tag == TAG_reald) x += 3;
  528.     else if (tag == TAG_realdarray) x += (get_realarraylenw(x) + 1);
  529.     else x += (get_strlen(x) +1);
  530.     }
  531.     else 
  532.       {x += get_lenz(x)+1;
  533.        do if (is_ptr(*p) && *p >= (int)target_lo && *p < (int)target_hi)
  534.             {trace(to_low,x0,x);
  535.          printrec(x0);
  536.          return;
  537.         }
  538.          while (++p < x);
  539.       }
  540.    }
  541. }
  542.  
  543. printrec(x) int *x;
  544. {int len = get_len(x), i;
  545.     chatting("\nAddress %8x:    tag=%8x\n",x+1,*x);
  546.     for(i=0;i<len;i++)
  547.      chatting("[%2x] %8x\n",i,x[i+1]);
  548. }
  549.  
  550. #endif TRACE_HEAP
  551.  
  552.  
  553. #ifdef GCMON
  554.  
  555. static int boundaries[1000];
  556. static int boundtimes[1000];
  557. static int bounddead[1000];
  558. static int boundlim=0;
  559. static int lasttime=0;
  560.  
  561. static struct {
  562.     int live, dead;
  563. } hist[32];
  564. static int histd[32];
  565. static int histl[32];
  566.  
  567. static int scan(lo,hi,age) int lo,hi,age;
  568. {register int x = lo, deadcount;
  569.  while (x<hi)
  570.     {register int dead=0, size, log;
  571.      register int descr = *(int *)(x), fp = *(int*)(x+4);
  572.       if (descr==TAG_forwarded)
  573.      descr = *(int*)(fp-4);
  574.       else dead=1;
  575.       if (contains_no_ptrs(descr)) 
  576.            size = ((descr>>width_tags)+7)&~3;
  577.         else size = (((descr&mask_tags)==tag_suspension)?1:
  578.                (descr>>width_tags)) * 4 + 4;
  579.       if (!age) age = (hi-x)>>2;
  580.        {log=0;
  581.         while (age) {log++; age>>=1;}
  582.         if (dead) {hist[log].dead+= size>>2; deadcount+=size>>2;}
  583.         else hist[log].live+= size>>2;
  584.        }
  585.       x+=size;
  586.     }
  587.  return deadcount;
  588. }
  589.  
  590. gcmonMinor(fromlo,fromhi,tolo,tohi)
  591.      int fromlo,fromhi,tolo,tohi;
  592. {
  593.  bounddead[boundlim]= scan(fromlo,fromhi,0);
  594.  boundtimes[boundlim] = lasttime;
  595.  boundaries[boundlim++] = tohi;
  596.  lasttime+=(fromhi-fromlo)>>2;
  597. }
  598.  
  599. gcmonMajor(fromlo,fromhi,tolo,tohi) int fromlo, fromhi, tolo,tohi;
  600. {int b=fromlo, i; int log,age; int dead=0;
  601.  for(i=0;i<boundlim-1;i++)
  602.   {age=lasttime-boundtimes[i];
  603.    dead+=bounddead[i]+scan(b,boundaries[i],age);
  604.    log=0;
  605.    while (age) {log++; age>>=1;}
  606.    hist[log].dead+= bounddead[i];
  607.    b=boundaries[i];}
  608.  boundlim=1;
  609.  boundaries[0]=fromlo+tohi-tolo;
  610.  boundtimes[0]=0;
  611.  bounddead[0]=dead+bounddead[boundlim-1];
  612. }
  613.  
  614. dumpMon()
  615. {char buf[100]; int i;
  616.  for (i=0; i<32; i++) {
  617.    chatting("%3d %10d %10d %5.2f%%\n",
  618.       i, hist[i].live, hist[i].dead);
  619.  }
  620. }
  621.  
  622. #endif GCMON
  623.