home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / SYSTEM / GC / ALLOC.C < prev    next >
C/C++ Source or Header  |  1994-11-21  |  20KB  |  669 lines

  1. /*
  2.  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3.  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
  4.  *
  5.  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6.  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  7.  *
  8.  * Permission is hereby granted to use or copy this program
  9.  * for any purpose,  provided the above notices are retained on all copies.
  10.  * Permission to modify the code and to distribute modified code is granted,
  11.  * provided the above notices are retained, and a notice that the code was
  12.  * modified is included with the above copyright notice.
  13.  *
  14.  */
  15. /* Boehm, November 21, 1994 4:35 pm PST */
  16.  
  17.  
  18. # include "gc_priv.h"
  19.  
  20. # include <stdio.h>
  21. # ifndef MACOS
  22. #   include <signal.h>
  23. #   include <sys/types.h>
  24. # endif
  25.  
  26. /*
  27.  * Separate free lists are maintained for different sized objects
  28.  * up to MAXOBJSZ.
  29.  * The call GC_allocobj(i,k) ensures that the freelist for
  30.  * kind k objects of size i points to a non-empty
  31.  * free list. It returns a pointer to the first entry on the free list.
  32.  * In a single-threaded world, GC_allocobj may be called to allocate
  33.  * an object of (small) size i as follows:
  34.  *
  35.  *            opp = &(GC_objfreelist[i]);
  36.  *            if (*opp == 0) GC_allocobj(i, NORMAL);
  37.  *            ptr = *opp;
  38.  *            *opp = obj_link(ptr);
  39.  *
  40.  * Note that this is very fast if the free list is non-empty; it should
  41.  * only involve the execution of 4 or 5 simple instructions.
  42.  * All composite objects on freelists are cleared, except for
  43.  * their first word.
  44.  */
  45.  
  46. /*
  47.  *  The allocator uses GC_allochblk to allocate large chunks of objects.
  48.  * These chunks all start on addresses which are multiples of
  49.  * HBLKSZ.   Each allocated chunk has an associated header,
  50.  * which can be located quickly based on the address of the chunk.
  51.  * (See headers.c for details.) 
  52.  * This makes it possible to check quickly whether an
  53.  * arbitrary address corresponds to an object administered by the
  54.  * allocator.
  55.  */
  56.  
  57. word GC_non_gc_bytes = 0;  /* Number of bytes not intended to be collected */
  58.  
  59. word GC_gc_no = 0;
  60.  
  61. int GC_incremental = 0;    /* By default, stop the world.    */
  62.  
  63. int GC_full_freq = 4;       /* Every 5th collection is a full    */
  64.                /* collection.            */
  65.  
  66. char * GC_copyright[] =
  67. {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers",
  68. "Copyright (c) 1991-1993 by Xerox Corporation.  All rights reserved.",
  69. "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
  70. " EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK."};
  71.  
  72.  
  73. /* some more variables */
  74.  
  75. extern signed_word GC_mem_found;  /* Number of reclaimed longwords    */
  76.                   /* after garbage collection          */
  77.  
  78. bool GC_dont_expand = 0;
  79.  
  80. word GC_free_space_divisor = 4;
  81.  
  82. /* Return the minimum number of words that must be allocated between    */
  83. /* collections to amortize the collection cost.                */
  84. static word min_words_allocd()
  85. {
  86.     int dummy;
  87. #   ifdef THREADS
  88.      /* We punt, for now. */
  89.      register signed_word stack_size = 10000;
  90. #   else
  91.         register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
  92. #   endif
  93.     register word total_root_size;  /* includes double stack size,    */
  94.                         /* since the stack is expensive    */
  95.                         /* to scan.                */
  96.     
  97.     if (stack_size < 0) stack_size = -stack_size;
  98.     total_root_size = 2 * stack_size + GC_root_size;
  99.     if (GC_incremental) {
  100.         return(BYTES_TO_WORDS(GC_heapsize + total_root_size)
  101.                / (2 * GC_free_space_divisor));
  102.     } else {
  103.         return(BYTES_TO_WORDS(GC_heapsize + total_root_size)
  104.                / GC_free_space_divisor);
  105.     }
  106. }
  107.  
  108. /* Return the number of words allocated, adjusted for explicit storage    */
  109. /* management, etc..  This number is used in deciding when to trigger    */
  110. /* collections.                                */
  111. word GC_adj_words_allocd()
  112. {
  113.     register signed_word result;
  114.     register signed_word expl_managed =
  115.             BYTES_TO_WORDS((long)GC_non_gc_bytes
  116.                     - (long)GC_non_gc_bytes_at_gc);
  117.     
  118.     /* Don't count what was explicitly freed, or newly allocated for    */
  119.     /* explicit management.  Note that deallocating an explicitly    */
  120.     /* managed object should not alter result, assuming the client    */
  121.     /* is playing by the rules.                        */
  122.     result = (signed_word)GC_words_allocd
  123.              - (signed_word)GC_mem_freed - expl_managed;
  124.     if (result > (signed_word)GC_words_allocd) result = GC_words_allocd;
  125.         /* probably client bug or unfortunate scheduling */
  126.     result += GC_words_wasted;
  127.          /* This doesn't reflect useful work.  But if there is lots of    */
  128.          /* new fragmentation, the same is probably true of the heap,    */
  129.          /* and the collection will be correspondingly cheaper.        */
  130.     if (result < (signed_word)(GC_words_allocd >> 3)) {
  131.         /* Always count at least 1/8 of the allocations.  We don't want    */
  132.         /* to collect too infrequently, since that would inhibit    */
  133.         /* coalescing of free storage blocks.                */
  134.         /* This also makes us partially robust against client bugs.    */
  135.         return(GC_words_allocd >> 3);
  136.     } else {
  137.         return(result);
  138.     }
  139. }
  140.  
  141.  
  142. /* Clear up a few frames worth of garbage left at the top of the stack.    */
  143. /* This is used to prevent us from accidentally treating garbade left    */
  144. /* on the stack by other parts of the collector as roots.  This     */
  145. /* differs from the code in misc.c, which actually tries to keep the    */
  146. /* stack clear of long-lived, client-generated garbage.            */
  147. void GC_clear_a_few_frames()
  148. {
  149. #   define NWORDS 64
  150.     word frames[NWORDS];
  151.     register int i;
  152.     
  153.     for (i = 0; i < NWORDS; i++) frames[i] = 0;
  154. }
  155.  
  156. /* Have we allocated enough to amortize a collection? */
  157. bool GC_should_collect()
  158. {
  159.     return(GC_adj_words_allocd() >= min_words_allocd());
  160. }
  161.  
  162. /* 
  163.  * Initiate a garbage collection if appropriate.
  164.  * Choose judiciously
  165.  * between partial, full, and stop-world collections.
  166.  * Assumes lock held, signals disabled.
  167.  */
  168. void GC_maybe_gc()
  169. {
  170.     static int n_partial_gcs = 0;
  171.     if (GC_should_collect()) {
  172.         if (!GC_incremental) {
  173.             GC_gcollect_inner();
  174.             n_partial_gcs = 0;
  175.         } else if (n_partial_gcs >= GC_full_freq) {
  176.             GC_initiate_full();
  177.             n_partial_gcs = 0;
  178.         } else {
  179.             /* We try to mark with the world stopped.    */
  180.             /* If we run out of time, this turns into    */
  181.             /* incremental marking.            */
  182.             if (GC_stopped_mark(FALSE)) {
  183. #               ifdef SAVE_CALL_CHAIN
  184.                   GC_save_callers(GC_last_stack);
  185. #               endif
  186.                 GC_finish_collection();
  187.             }
  188.             n_partial_gcs++;
  189.         }
  190.     }
  191. }
  192.  
  193. /*
  194.  * Stop the world garbage collection.  Assumes lock held, signals disabled.
  195.  */
  196. void GC_gcollect_inner()
  197. {
  198. #   ifdef PRINTSTATS
  199.     GC_printf2(
  200.        "Initiating full world-stop collection %lu after %ld allocd bytes\n",
  201.        (unsigned long) GC_gc_no+1,
  202.        (long)WORDS_TO_BYTES(GC_words_allocd));
  203. #   endif
  204.     GC_promote_black_lists();
  205.     /* GC_reclaim_or_delete_all();  -- not needed: no intervening allocation */
  206.     GC_clear_marks();
  207. #   ifdef SAVE_CALL_CHAIN
  208.         GC_save_callers(GC_last_stack);
  209. #   endif
  210.     (void) GC_stopped_mark(TRUE);
  211.     GC_finish_collection();
  212. }
  213.  
  214. /*
  215.  * Perform n units of garbage collection work.  A unit is intended to touch
  216.  * roughly a GC_RATE pages.  Every once in a while, we do more than that.
  217.  */
  218. # define GC_RATE 8
  219.  
  220. int GC_deficit = 0;    /* The number of extra calls to GC_mark_some    */
  221.             /* that we have made.                */
  222.             /* Negative values are equivalent to 0.        */
  223. extern bool GC_collection_in_progress();
  224.  
  225. void GC_collect_a_little_inner(n)
  226. int n;
  227. {
  228.     register int i;
  229.     
  230.     if (GC_collection_in_progress()) {
  231.         for (i = GC_deficit; i < GC_RATE*n; i++) {
  232.             if (GC_mark_some()) {
  233.                 /* Need to finish a collection */
  234. #             ifdef SAVE_CALL_CHAIN
  235.                 GC_save_callers(GC_last_stack);
  236. #             endif
  237.         (void) GC_stopped_mark(TRUE);
  238.                 GC_finish_collection();
  239.                 break;
  240.             }
  241.         }
  242.         if (GC_deficit > 0) GC_deficit -= GC_RATE*n;
  243.     } else {
  244.         GC_maybe_gc();
  245.     }
  246. }
  247.  
  248. int GC_collect_a_little(NO_PARAMS)
  249. {
  250.     int result;
  251.     DCL_LOCK_STATE;
  252.  
  253.     DISABLE_SIGNALS();
  254.     LOCK();
  255.     GC_collect_a_little_inner(1);
  256.     result = (int)GC_collection_in_progress();
  257.     UNLOCK();
  258.     ENABLE_SIGNALS();
  259.     return(result);
  260. }
  261.  
  262. /*
  263.  * Assumes lock is held, signals are disabled.
  264.  * We stop the world.
  265.  * If final is TRUE, then we finish the collection, no matter how long
  266.  * it takes.
  267.  * Otherwise we may fail and return FALSE if this takes too long.
  268.  * Increment GC_gc_no if we succeed.
  269.  */
  270. bool GC_stopped_mark(final)
  271. bool final;
  272. {
  273.     CLOCK_TYPE start_time;
  274.     CLOCK_TYPE current_time;
  275.     unsigned long time_diff;
  276.     register int i;
  277.     
  278.     GET_TIME(start_time);
  279.     STOP_WORLD();
  280. #   ifdef PRINTSTATS
  281.     GC_printf1("--> Marking for collection %lu ",
  282.                (unsigned long) GC_gc_no + 1);
  283.     GC_printf2("after %lu allocd bytes + %lu wasted bytes\n",
  284.               (unsigned long) WORDS_TO_BYTES(GC_words_allocd),
  285.               (unsigned long) WORDS_TO_BYTES(GC_words_wasted));
  286. #   endif
  287.  
  288.     /* Mark from all roots.  */
  289.         /* Minimize junk left in my registers and on the stack */
  290.             GC_clear_a_few_frames();
  291.             GC_noop(0,0,0,0,0,0);
  292.     GC_initiate_partial();
  293.     for(i = 0;;i++) {
  294.         if (GC_mark_some()) break;
  295.         if (final) continue;
  296.         if ((i & 3) == 0) {
  297.             GET_TIME(current_time);
  298.             time_diff = MS_TIME_DIFF(current_time,start_time);
  299.             if (time_diff >= TIME_LIMIT) {
  300.                 START_WORLD();
  301. #               ifdef PRINTSTATS
  302.                 GC_printf0("Abandoning stopped marking after ");
  303.             GC_printf2("%lu iterations and %lu msecs\n",
  304.                    (unsigned long)i,
  305.                        (unsigned long)time_diff);
  306. #            endif
  307.             GC_deficit = i;  /* Give the mutator a chance. */
  308.                 return(FALSE);
  309.             }
  310.         }
  311.     }
  312.     
  313.     GC_gc_no++;
  314. #   ifdef PRINTSTATS
  315.       GC_printf2("Collection %lu reclaimed %ld bytes",
  316.           (unsigned long) GC_gc_no - 1,
  317.              (long)WORDS_TO_BYTES(GC_mem_found));
  318.       GC_printf1(" ---> heapsize = %lu bytes\n",
  319.                   (unsigned long) GC_heapsize);
  320.       /* Printf arguments may be pushed in funny places.  Clear the    */
  321.       /* space.                                */
  322.       GC_printf0("");
  323. #   endif      
  324.  
  325.     /* Check all debugged objects for consistency */
  326.         if (GC_debugging_started) {
  327.             (*GC_check_heap)();
  328.         }
  329.     
  330. #   ifdef PRINTTIMES
  331.     GET_TIME(current_time);
  332.     GC_printf1("World-stopped marking took %lu msecs\n",
  333.                MS_TIME_DIFF(current_time,start_time));
  334. #   endif
  335.     START_WORLD();
  336.     return(TRUE);
  337. }
  338.  
  339.  
  340. /* Finish up a collection.  Assumes lock is held, signals are disabled,    */
  341. /* but the world is otherwise running.                    */
  342. void GC_finish_collection()
  343. {
  344. #   ifdef PRINTTIMES
  345.     CLOCK_TYPE start_time;
  346.     CLOCK_TYPE finalize_time;
  347.     CLOCK_TYPE done_time;
  348.     
  349.     GET_TIME(start_time);
  350.     finalize_time = start_time;
  351. #   endif
  352.  
  353. #   ifdef GATHERSTATS
  354.         GC_mem_found = 0;
  355. #   endif
  356. #   ifdef FIND_LEAK
  357.       /* Mark all objects on the free list.  All objects should be */
  358.       /* marked when we're done.                   */
  359.     {
  360.       register word size;        /* current object size        */
  361.       register ptr_t p;    /* pointer to current object    */
  362.       register struct hblk * h;    /* pointer to block containing *p */
  363.       register hdr * hhdr;
  364.       register int word_no;           /* "index" of *p in *q          */
  365.       int kind;
  366.  
  367.       for (kind = 0; kind < GC_n_kinds; kind++) {
  368.         for (size = 1; size <= MAXOBJSZ; size++) {
  369.           for (p= GC_obj_kinds[kind].ok_freelist[size];
  370.                p != 0; p=obj_link(p)){
  371.         h = HBLKPTR(p);
  372.         hhdr = HDR(h);
  373.         word_no = (((word *)p) - ((word *)h));
  374.         set_mark_bit_from_hdr(hhdr, word_no);
  375.           }
  376.         }
  377.       }
  378.     }
  379.       /* Check that everything is marked */
  380.     GC_start_reclaim(TRUE);
  381. #   else
  382.  
  383.       GC_finalize();
  384. #     ifdef STUBBORN_ALLOC
  385.         GC_clean_changing_list();
  386. #     endif
  387.  
  388. #     ifdef PRINTTIMES
  389.     GET_TIME(finalize_time);
  390. #     endif
  391.  
  392.       /* Clear free list mark bits, in case they got accidentally marked   */
  393.       /* Note: HBLKPTR(p) == pointer to head of block containing *p        */
  394.       /* Also subtract memory remaining from GC_mem_found count.           */
  395.       /* Note that composite objects on free list are cleared.             */
  396.       /* Thus accidentally marking a free list is not a problem;  only     */
  397.       /* objects on the list itself will be marked, and that's fixed here. */
  398.       {
  399.     register word size;        /* current object size        */
  400.     register ptr_t p;    /* pointer to current object    */
  401.     register struct hblk * h;    /* pointer to block containing *p */
  402.     register hdr * hhdr;
  403.     register int word_no;           /* "index" of *p in *q          */
  404.     int kind;
  405.  
  406.     for (kind = 0; kind < GC_n_kinds; kind++) {
  407.       for (size = 1; size <= MAXOBJSZ; size++) {
  408.         for (p= GC_obj_kinds[kind].ok_freelist[size];
  409.              p != 0; p=obj_link(p)){
  410.         h = HBLKPTR(p);
  411.         hhdr = HDR(h);
  412.         word_no = (((word *)p) - ((word *)h));
  413.         clear_mark_bit_from_hdr(hhdr, word_no);
  414. #        ifdef GATHERSTATS
  415.             GC_mem_found -= size;
  416. #        endif
  417.         }
  418.       }
  419.     }
  420.       }
  421.  
  422.  
  423. #     ifdef PRINTSTATS
  424.     GC_printf1("Bytes recovered before sweep - f.l. count = %ld\n",
  425.               (long)WORDS_TO_BYTES(GC_mem_found));
  426. #     endif
  427.  
  428.     /* Reconstruct free lists to contain everything not marked */
  429.       GC_start_reclaim(FALSE);
  430.     
  431. #   endif /* !FIND_LEAK */
  432.  
  433. #   ifdef PRINTSTATS
  434.     GC_printf2(
  435.           "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
  436.               (long)WORDS_TO_BYTES(GC_mem_found),
  437.               (unsigned long)GC_heapsize);
  438.     GC_printf2("%lu (atomic) + %lu (composite) collectable bytes in use\n",
  439.                (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
  440.                (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
  441. #   endif
  442.  
  443.     /* Reset or increment counters for next cycle */
  444.       GC_words_allocd_before_gc += GC_words_allocd;
  445.       GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
  446.       GC_words_allocd = 0;
  447.       GC_words_wasted = 0;
  448.       GC_mem_freed = 0;
  449.       
  450. #   ifdef PRINTTIMES
  451.     GET_TIME(done_time);
  452.     GC_printf2("Finalize + initiate sweep took %lu + %lu msecs\n",
  453.                MS_TIME_DIFF(finalize_time,start_time),
  454.                MS_TIME_DIFF(done_time,finalize_time));
  455. #   endif
  456. }
  457.  
  458. /* Externally callable routine to invoke full, stop-world collection */
  459. void GC_gcollect(NO_PARAMS)
  460. {
  461.     DCL_LOCK_STATE;
  462.     
  463.     GC_invoke_finalizers();
  464.     DISABLE_SIGNALS();
  465.     LOCK();
  466.     if (!GC_is_initialized) GC_init_inner();
  467.     /* Minimize junk left in my registers */
  468.       GC_noop(0,0,0,0,0,0);
  469.     GC_gcollect_inner();
  470.     UNLOCK();
  471.     ENABLE_SIGNALS();
  472.     GC_invoke_finalizers();
  473. }
  474.  
  475. word GC_n_heap_sects = 0;    /* Number of sections currently in heap. */
  476.  
  477. /*
  478.  * Use the chunk of memory starting at p of syze bytes as part of the heap.
  479.  * Assumes p is HBLKSIZE aligned, and bytes is a multiple of HBLKSIZE.
  480.  */
  481. void GC_add_to_heap(p, bytes)
  482. struct hblk *p;
  483. word bytes;
  484. {
  485.     word words;
  486.     
  487.     if (GC_n_heap_sects >= MAX_HEAP_SECTS) {
  488.         ABORT("Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS");
  489.     }
  490.     if (!GC_install_header(p)) {
  491.         /* This is extremely unlikely. Can't add it.  This will        */
  492.         /* almost certainly result in a    0 return from the allocator,    */
  493.         /* which is entirely appropriate.                */
  494.         return;
  495.     }
  496.     GC_heap_sects[GC_n_heap_sects].hs_start = (ptr_t)p;
  497.     GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes;
  498.     GC_n_heap_sects++;
  499.     words = BYTES_TO_WORDS(bytes - HDR_BYTES);
  500.     HDR(p) -> hb_sz = words;
  501.     GC_freehblk(p);
  502.     GC_heapsize += bytes;
  503.     if ((ptr_t)p <= GC_least_plausible_heap_addr
  504.         || GC_least_plausible_heap_addr == 0) {
  505.         GC_least_plausible_heap_addr = (ptr_t)p - sizeof(word);
  506.             /* Making it a little smaller than necessary prevents    */
  507.             /* us from getting a false hit from the variable    */
  508.             /* itself.  There's some unintentional reflection    */
  509.             /* here.                        */
  510.     }
  511.     if ((ptr_t)p + bytes >= GC_greatest_plausible_heap_addr) {
  512.         GC_greatest_plausible_heap_addr = (ptr_t)p + bytes;
  513.     }
  514. }
  515.  
  516. ptr_t GC_least_plausible_heap_addr = (ptr_t)ONES;
  517. ptr_t GC_greatest_plausible_heap_addr = 0;
  518.  
  519. ptr_t GC_max(x,y)
  520. ptr_t x, y;
  521. {
  522.     return(x > y? x : y);
  523. }
  524.  
  525. ptr_t GC_min(x,y)
  526. ptr_t x, y;
  527. {
  528.     return(x < y? x : y);
  529. }
  530.  
  531. /*
  532.  * this explicitly increases the size of the heap.  It is used
  533.  * internally, but may also be invoked from GC_expand_hp by the user.
  534.  * The argument is in units of HBLKSIZE.
  535.  * Tiny values of n are rounded up.
  536.  * Returns FALSE on failure.
  537.  */
  538. bool GC_expand_hp_inner(n)
  539. word n;
  540. {
  541.     word bytes;
  542.     struct hblk * space;
  543.     word expansion_slop;    /* Number of bytes by which we expect the */
  544.                     /* heap to expand soon.              */
  545.  
  546.     if (n < MINHINCR) n = MINHINCR;
  547.     bytes = n * HBLKSIZE;
  548.     space = GET_MEM(bytes);
  549.     if( space == 0 ) {
  550.     return(FALSE);
  551.     }
  552. #   ifdef PRINTSTATS
  553.     GC_printf2("Increasing heap size by %lu after %lu allocated bytes\n",
  554.                (unsigned long)bytes,
  555.                (unsigned long)WORDS_TO_BYTES(GC_words_allocd));
  556. #     ifdef UNDEFINED
  557.       GC_printf1("Root size = %lu\n", GC_root_size);
  558.       GC_print_block_list(); GC_print_hblkfreelist();
  559.       GC_printf0("\n");
  560. #    endif
  561. #   endif
  562.     expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd());
  563.     if (5 * HBLKSIZE * MAXHINCR > expansion_slop) {
  564.         expansion_slop = 5 * HBLKSIZE * MAXHINCR;
  565.     }
  566.     if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
  567.         || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
  568.         /* Assume the heap is growing up */
  569.         GC_greatest_plausible_heap_addr =
  570.             GC_max(GC_greatest_plausible_heap_addr,
  571.                    (ptr_t)space + bytes + expansion_slop);
  572.     } else {
  573.         /* Heap is growing down */
  574.         GC_least_plausible_heap_addr =
  575.             GC_min(GC_least_plausible_heap_addr,
  576.                    (ptr_t)space - expansion_slop);
  577.     }
  578.     GC_prev_heap_addr = GC_last_heap_addr;
  579.     GC_last_heap_addr = (ptr_t)space;
  580.     GC_add_to_heap(space, bytes);
  581.     return(TRUE);
  582. }
  583.  
  584. /* Really returns a bool, but it's externally visible, so that's clumsy. */
  585. /* Arguments is in bytes.                        */
  586. int GC_expand_hp(bytes)
  587. size_t bytes;
  588. {
  589.     int result;
  590.     DCL_LOCK_STATE;
  591.     
  592.     DISABLE_SIGNALS();
  593.     LOCK();
  594.     if (!GC_is_initialized) GC_init_inner();
  595.     result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
  596.     UNLOCK();
  597.     ENABLE_SIGNALS();
  598.     return(result);
  599. }
  600.  
  601. bool GC_collect_or_expand(needed_blocks)
  602. word needed_blocks;
  603. {
  604.     static int count = 0;  /* How many failures? */
  605.     
  606.     if (!GC_incremental && !GC_dont_gc && GC_should_collect()) {
  607. #     ifdef SAVE_CALL_CHAIN
  608.         GC_save_callers(GC_last_stack);
  609. #     endif
  610.       GC_gcollect_inner();
  611.     } else {
  612.       word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
  613.                      + needed_blocks;
  614.       
  615.       if (blocks_to_get > MAXHINCR) {
  616.           if (needed_blocks > MAXHINCR) {
  617.               blocks_to_get = needed_blocks;
  618.           } else {
  619.               blocks_to_get = MAXHINCR;
  620.           }
  621.       }
  622.       if (!GC_expand_hp_inner(blocks_to_get)
  623.         && !GC_expand_hp_inner(needed_blocks)) {
  624.           if (count++ < 10) {
  625.               WARN("Out of Memory!  Trying to continue ...\n");
  626.         GC_gcollect_inner();
  627.     } else {
  628.         WARN("Out of Memory!  Returning NIL!\n");
  629.         return(FALSE);
  630.     }
  631.       } else if (count) {
  632.           WARN("Memory available again! Continue ...\n");
  633.           count = 0;
  634.       }
  635.     }
  636.     return(TRUE);
  637. }
  638.  
  639. /*
  640.  * Make sure the object free list for sz is not empty.
  641.  * Return a pointer to the first object on the free list.
  642.  * The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
  643.  * Assumes we hold the allocator lock and signals are disabled.
  644.  *
  645.  */
  646. ptr_t GC_allocobj(sz, kind)
  647. word sz;
  648. int kind;
  649. {
  650.     register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
  651.     
  652.     if (sz == 0) return(0);
  653.  
  654.     while (*flh == 0) {
  655.       /* Do our share of marking work */
  656.         if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner(1);
  657.       /* Sweep blocks for objects of this size */
  658.           GC_continue_reclaim(sz, kind);
  659.       if (*flh == 0) {
  660.         GC_new_hblk(sz, kind);
  661.       }
  662.       if (*flh == 0) {
  663.         if (!GC_collect_or_expand((word)1)) return(0);
  664.       }
  665.     }
  666.     
  667.     return(*flh);
  668. }
  669.