7028ef301abe45ba51438148decf59b168637260
[cacao.git] / src / boehm-gc / allchblk.c
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  * Copyright (c) 1998-1999 by Silicon Graphics.  All rights reserved.
5  * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
6  *
7  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
9  *
10  * Permission is hereby granted to use or copy this program
11  * for any purpose,  provided the above notices are retained on all copies.
12  * Permission to modify the code and to distribute modified code is granted,
13  * provided the above notices are retained, and a notice that the code was
14  * modified is included with the above copyright notice.
15  */
16
17 #include "config.h"
18
19 /* #define DEBUG */
20 #include <stdio.h>
21 #include "private/gc_priv.h"
22
23 GC_bool GC_use_entire_heap = 0;
24
25 /*
26  * Free heap blocks are kept on one of several free lists,
27  * depending on the size of the block.  Each free list is doubly linked.
28  * Adjacent free blocks are coalesced.
29  */
30
31  
32 # define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
33                 /* largest block we will allocate starting on a black   */
34                 /* listed block.  Must be >= HBLKSIZE.                  */
35
36
37 # define UNIQUE_THRESHOLD 32
38         /* Sizes up to this many HBLKs each have their own free list    */
39 # define HUGE_THRESHOLD 256
40         /* Sizes of at least this many heap blocks are mapped to a      */
41         /* single free list.                                            */
42 # define FL_COMPRESSION 8
43         /* In between sizes map this many distinct sizes to a single    */
44         /* bin.                                                         */
45
46 # define N_HBLK_FLS (HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION \
47                                  + UNIQUE_THRESHOLD
48
49 struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
50
51 #ifndef USE_MUNMAP
52
53   word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
54         /* Number of free bytes on each list.   */
55
56   /* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS       */
57   /* > GC_max_large_allocd_bytes?                                       */
58 # ifdef __GNUC__
59   __inline__
60 # endif
61   static GC_bool GC_enough_large_bytes_left(bytes,n)
62   word bytes;
63   int n;
64   {
65     int i;
66     for (i = N_HBLK_FLS; i >= n; --i) {
67         bytes += GC_free_bytes[i];
68         if (bytes > GC_max_large_allocd_bytes) return TRUE;
69     }
70     return FALSE;
71   }
72
73 # define INCR_FREE_BYTES(n, b) GC_free_bytes[n] += (b);
74
75 # define FREE_ASSERT(e) GC_ASSERT(e)
76
77 #else /* USE_MUNMAP */
78
79 # define INCR_FREE_BYTES(n, b)
80 # define FREE_ASSERT(e)
81
82 #endif /* USE_MUNMAP */
83
84 /* Map a number of blocks to the appropriate large block free list index. */
85 int GC_hblk_fl_from_blocks(blocks_needed)
86 word blocks_needed;
87 {
88     if (blocks_needed <= UNIQUE_THRESHOLD) return blocks_needed;
89     if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS;
90     return (blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
91                                         + UNIQUE_THRESHOLD;
92     
93 }
94
95 # define PHDR(hhdr) HDR(hhdr -> hb_prev)
96 # define NHDR(hhdr) HDR(hhdr -> hb_next)
97
98 # ifdef USE_MUNMAP
99 #   define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0)
100 # else  /* !USE_MMAP */
101 #   define IS_MAPPED(hhdr) 1
102 # endif /* USE_MUNMAP */
103
104 # if !defined(NO_DEBUGGING)
105 void GC_print_hblkfreelist()
106 {
107     struct hblk * h;
108     word total_free = 0;
109     hdr * hhdr;
110     word sz;
111     int i;
112     
113     for (i = 0; i <= N_HBLK_FLS; ++i) {
114       h = GC_hblkfreelist[i];
115 #     ifdef USE_MUNMAP
116         if (0 != h) GC_printf1("Free list %ld:\n",
117                                (unsigned long)i);
118 #     else
119         if (0 != h) GC_printf2("Free list %ld (Total size %ld):\n",
120                                (unsigned long)i,
121                                (unsigned long)GC_free_bytes[i]);
122 #     endif
123       while (h != 0) {
124         hhdr = HDR(h);
125         sz = hhdr -> hb_sz;
126         GC_printf2("\t0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
127         total_free += sz;
128         if (GC_is_black_listed(h, HBLKSIZE) != 0) {
129              GC_printf0("start black listed\n");
130         } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
131              GC_printf0("partially black listed\n");
132         } else {
133              GC_printf0("not black listed\n");
134         }
135         h = hhdr -> hb_next;
136       }
137     }
138 #   ifndef USE_MUNMAP
139       if (total_free != GC_large_free_bytes) {
140         GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
141                    (unsigned long) GC_large_free_bytes);
142       }
143 #   endif
144     GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
145 }
146
147 /* Return the free list index on which the block described by the header */
148 /* appears, or -1 if it appears nowhere.                                 */
149 int free_list_index_of(wanted)
150 hdr * wanted;
151 {
152     struct hblk * h;
153     hdr * hhdr;
154     int i;
155     
156     for (i = 0; i <= N_HBLK_FLS; ++i) {
157       h = GC_hblkfreelist[i];
158       while (h != 0) {
159         hhdr = HDR(h);
160         if (hhdr == wanted) return i;
161         h = hhdr -> hb_next;
162       }
163     }
164     return -1;
165 }
166
167 void GC_dump_regions()
168 {
169     unsigned i;
170     ptr_t start, end;
171     ptr_t p;
172     size_t bytes;
173     hdr *hhdr;
174     for (i = 0; i < GC_n_heap_sects; ++i) {
175         start = GC_heap_sects[i].hs_start;
176         bytes = GC_heap_sects[i].hs_bytes;
177         end = start + bytes;
178         /* Merge in contiguous sections.        */
179           while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) {
180             ++i;
181             end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
182           }
183         GC_printf2("***Section from 0x%lx to 0x%lx\n", start, end);
184         for (p = start; p < end;) {
185             hhdr = HDR(p);
186             GC_printf1("\t0x%lx ", (unsigned long)p);
187             if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
188                 GC_printf1("Missing header!!(%ld)\n", hhdr);
189                 p += HBLKSIZE;
190                 continue;
191             }
192             if (HBLK_IS_FREE(hhdr)) {
193                 int correct_index = GC_hblk_fl_from_blocks(
194                                         divHBLKSZ(hhdr -> hb_sz));
195                 int actual_index;
196                 
197                 GC_printf1("\tfree block of size 0x%lx bytes",
198                            (unsigned long)(hhdr -> hb_sz));
199                 if (IS_MAPPED(hhdr)) {
200                     GC_printf0("\n");
201                 } else {
202                     GC_printf0("(unmapped)\n");
203                 }
204                 actual_index = free_list_index_of(hhdr);
205                 if (-1 == actual_index) {
206                     GC_printf1("\t\tBlock not on free list %ld!!\n",
207                                 correct_index);
208                 } else if (correct_index != actual_index) {
209                     GC_printf2("\t\tBlock on list %ld, should be on %ld!!\n",
210                                actual_index, correct_index);
211                 }
212                 p += hhdr -> hb_sz;
213             } else {
214                 GC_printf1("\tused for blocks of size 0x%lx bytes\n",
215                            (unsigned long)WORDS_TO_BYTES(hhdr -> hb_sz));
216                 p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
217             }
218         }
219     }
220 }
221
222 # endif /* NO_DEBUGGING */
223
224 /* Initialize hdr for a block containing the indicated size and         */
225 /* kind of objects.                                                     */
226 /* Return FALSE on failure.                                             */
227 static GC_bool setup_header(hhdr, sz, kind, flags)
228 register hdr * hhdr;
229 word sz;        /* object size in words */
230 int kind;
231 unsigned char flags;
232 {
233     register word descr;
234     
235     /* Add description of valid object pointers */
236       if (!GC_add_map_entry(sz)) return(FALSE);
237       hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
238       
239     /* Set size, kind and mark proc fields */
240       hhdr -> hb_sz = sz;
241       hhdr -> hb_obj_kind = kind;
242       hhdr -> hb_flags = flags;
243       descr = GC_obj_kinds[kind].ok_descriptor;
244       if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
245       hhdr -> hb_descr = descr;
246       
247     /* Clear mark bits */
248       GC_clear_hdr_marks(hhdr);
249       
250     hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
251     return(TRUE);
252 }
253
254 #define FL_UNKNOWN -1
255 /*
256  * Remove hhdr from the appropriate free list.
257  * We assume it is on the nth free list, or on the size
258  * appropriate free list if n is FL_UNKNOWN.
259  */
260 void GC_remove_from_fl(hhdr, n)
261 hdr * hhdr;
262 int n;
263 {
264     int index;
265
266     GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
267 #   ifndef USE_MUNMAP
268       /* We always need index to mainatin free counts.  */
269       if (FL_UNKNOWN == n) {
270           index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
271       } else {
272           index = n;
273       }
274 #   endif
275     if (hhdr -> hb_prev == 0) {
276 #       ifdef USE_MUNMAP
277           if (FL_UNKNOWN == n) {
278             index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
279           } else {
280             index = n;
281           }
282 #       endif
283         GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr);
284         GC_hblkfreelist[index] = hhdr -> hb_next;
285     } else {
286         hdr *phdr;
287         GET_HDR(hhdr -> hb_prev, phdr);
288         phdr -> hb_next = hhdr -> hb_next;
289     }
290     FREE_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
291     INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
292     if (0 != hhdr -> hb_next) {
293         hdr * nhdr;
294         GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
295         GET_HDR(hhdr -> hb_next, nhdr);
296         nhdr -> hb_prev = hhdr -> hb_prev;
297     }
298 }
299
300 /*
301  * Return a pointer to the free block ending just before h, if any.
302  */
303 struct hblk * GC_free_block_ending_at(h)
304 struct hblk *h;
305 {
306     struct hblk * p = h - 1;
307     hdr * phdr;
308
309     GET_HDR(p, phdr);
310     while (0 != phdr && IS_FORWARDING_ADDR_OR_NIL(phdr)) {
311         p = FORWARDED_ADDR(p,phdr);
312         phdr = HDR(p);
313     }
314     if (0 != phdr) {
315         if(HBLK_IS_FREE(phdr)) {
316             return p;
317         } else {
318             return 0;
319         }
320     }
321     p = GC_prev_block(h - 1);
322     if (0 != p) {
323       phdr = HDR(p);
324       if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) {
325         return p;
326       }
327     }
328     return 0;
329 }
330
331 /*
332  * Add hhdr to the appropriate free list.
333  * We maintain individual free lists sorted by address.
334  */
335 void GC_add_to_fl(h, hhdr)
336 struct hblk *h;
337 hdr * hhdr;
338 {
339     int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
340     struct hblk *second = GC_hblkfreelist[index];
341     hdr * second_hdr;
342 #   ifdef GC_ASSERTIONS
343       struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz);
344       hdr * nexthdr = HDR(next);
345       struct hblk *prev = GC_free_block_ending_at(h);
346       hdr * prevhdr = HDR(prev);
347       GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr) || !IS_MAPPED(nexthdr));
348       GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr) || !IS_MAPPED(prevhdr));
349 #   endif
350     GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
351     GC_hblkfreelist[index] = h;
352     INCR_FREE_BYTES(index, hhdr -> hb_sz);
353     FREE_ASSERT(GC_free_bytes[index] <= GC_large_free_bytes)
354     hhdr -> hb_next = second;
355     hhdr -> hb_prev = 0;
356     if (0 != second) {
357       GET_HDR(second, second_hdr);
358       second_hdr -> hb_prev = h;
359     }
360     GC_invalidate_map(hhdr);
361 }
362
363 #ifdef USE_MUNMAP
364
365 /* Unmap blocks that haven't been recently touched.  This is the only way */
366 /* way blocks are ever unmapped.                                          */
367 void GC_unmap_old(void)
368 {
369     struct hblk * h;
370     hdr * hhdr;
371     word sz;
372     unsigned short last_rec, threshold;
373     int i;
374 #   define UNMAP_THRESHOLD 6
375     
376     for (i = 0; i <= N_HBLK_FLS; ++i) {
377       for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) {
378         hhdr = HDR(h);
379         if (!IS_MAPPED(hhdr)) continue;
380         threshold = (unsigned short)(GC_gc_no - UNMAP_THRESHOLD);
381         last_rec = hhdr -> hb_last_reclaimed;
382         if ((last_rec > GC_gc_no || last_rec < threshold)
383             && threshold < GC_gc_no /* not recently wrapped */) {
384           sz = hhdr -> hb_sz;
385           GC_unmap((ptr_t)h, sz);
386           hhdr -> hb_flags |= WAS_UNMAPPED;
387         }
388       }
389     }  
390 }
391
392 /* Merge all unmapped blocks that are adjacent to other free            */
393 /* blocks.  This may involve remapping, since all blocks are either     */
394 /* fully mapped or fully unmapped.                                      */
395 void GC_merge_unmapped(void)
396 {
397     struct hblk * h, *next;
398     hdr * hhdr, *nexthdr;
399     word size, nextsize;
400     int i;
401     
402     for (i = 0; i <= N_HBLK_FLS; ++i) {
403       h = GC_hblkfreelist[i];
404       while (h != 0) {
405         GET_HDR(h, hhdr);
406         size = hhdr->hb_sz;
407         next = (struct hblk *)((word)h + size);
408         GET_HDR(next, nexthdr);
409         /* Coalesce with successor, if possible */
410           if (0 != nexthdr && HBLK_IS_FREE(nexthdr)) {
411             nextsize = nexthdr -> hb_sz;
412             if (IS_MAPPED(hhdr)) {
413               GC_ASSERT(!IS_MAPPED(nexthdr));
414               /* make both consistent, so that we can merge */
415                 if (size > nextsize) {
416                   GC_remap((ptr_t)next, nextsize);
417                 } else {
418                   GC_unmap((ptr_t)h, size);
419                   hhdr -> hb_flags |= WAS_UNMAPPED;
420                 }
421             } else if (IS_MAPPED(nexthdr)) {
422               GC_ASSERT(!IS_MAPPED(hhdr));
423               if (size > nextsize) {
424                 GC_unmap((ptr_t)next, nextsize);
425               } else {
426                 GC_remap((ptr_t)h, size);
427                 hhdr -> hb_flags &= ~WAS_UNMAPPED;
428                 hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed;
429               }
430             } else {
431               /* Unmap any gap in the middle */
432                 GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nexthdr -> hb_sz);
433             }
434             /* If they are both unmapped, we merge, but leave unmapped. */
435             GC_remove_from_fl(hhdr, i);
436             GC_remove_from_fl(nexthdr, FL_UNKNOWN);
437             hhdr -> hb_sz += nexthdr -> hb_sz; 
438             GC_remove_header(next);
439             GC_add_to_fl(h, hhdr); 
440             /* Start over at beginning of list */
441             h = GC_hblkfreelist[i];
442           } else /* not mergable with successor */ {
443             h = hhdr -> hb_next;
444           }
445       } /* while (h != 0) ... */
446     } /* for ... */
447 }
448
449 #endif /* USE_MUNMAP */
450
451 /*
452  * Return a pointer to a block starting at h of length bytes.
453  * Memory for the block is mapped.
454  * Remove the block from its free list, and return the remainder (if any)
455  * to its appropriate free list.
456  * May fail by returning 0.
457  * The header for the returned block must be set up by the caller.
458  * If the return value is not 0, then hhdr is the header for it.
459  */
460 struct hblk * GC_get_first_part(h, hhdr, bytes, index)
461 struct hblk *h;
462 hdr * hhdr;
463 word bytes;
464 int index;
465 {
466     word total_size = hhdr -> hb_sz;
467     struct hblk * rest;
468     hdr * rest_hdr;
469
470     GC_ASSERT((total_size & (HBLKSIZE-1)) == 0);
471     GC_remove_from_fl(hhdr, index);
472     if (total_size == bytes) return h;
473     rest = (struct hblk *)((word)h + bytes);
474     rest_hdr = GC_install_header(rest);
475     if (0 == rest_hdr) {
476         /* This may be very bad news ... */
477         WARN("Header allocation failed: Dropping block.\n", 0);
478         return(0);
479     }
480     rest_hdr -> hb_sz = total_size - bytes;
481     rest_hdr -> hb_flags = 0;
482 #   ifdef GC_ASSERTIONS
483       /* Mark h not free, to avoid assertion about adjacent free blocks. */
484         hhdr -> hb_map = 0;
485 #   endif
486     GC_add_to_fl(rest, rest_hdr);
487     return h;
488 }
489
490 /*
491  * H is a free block.  N points at an address inside it.
492  * A new header for n has already been set up.  Fix up h's header
493  * to reflect the fact that it is being split, move it to the
494  * appropriate free list.
495  * N replaces h in the original free list.
496  *
497  * Nhdr is not completely filled in, since it is about to allocated.
498  * It may in fact end up on the wrong free list for its size.
499  * (Hence adding it to a free list is silly.  But this path is hopefully
500  * rare enough that it doesn't matter.  The code is cleaner this way.)
501  */
502 void GC_split_block(h, hhdr, n, nhdr, index)
503 struct hblk *h;
504 hdr * hhdr;
505 struct hblk *n;
506 hdr * nhdr;
507 int index;      /* Index of free list */
508 {
509     word total_size = hhdr -> hb_sz;
510     word h_size = (word)n - (word)h;
511     struct hblk *prev = hhdr -> hb_prev;
512     struct hblk *next = hhdr -> hb_next;
513
514     /* Replace h with n on its freelist */
515       nhdr -> hb_prev = prev;
516       nhdr -> hb_next = next;
517       nhdr -> hb_sz = total_size - h_size;
518       nhdr -> hb_flags = 0;
519       if (0 != prev) {
520         HDR(prev) -> hb_next = n;
521       } else {
522         GC_hblkfreelist[index] = n;
523       }
524       if (0 != next) {
525         HDR(next) -> hb_prev = n;
526       }
527       INCR_FREE_BYTES(index, -(signed_word)h_size);
528       FREE_ASSERT(GC_free_bytes[index] > 0);
529 #     ifdef GC_ASSERTIONS
530         nhdr -> hb_map = 0;     /* Don't fail test for consecutive      */
531                                 /* free blocks in GC_add_to_fl.         */
532 #     endif
533 #   ifdef USE_MUNMAP
534       hhdr -> hb_last_reclaimed = GC_gc_no;
535 #   endif
536     hhdr -> hb_sz = h_size;
537     GC_add_to_fl(h, hhdr);
538     GC_invalidate_map(nhdr);
539 }
540         
541 struct hblk * GC_allochblk_nth();
542
543 /*
544  * Allocate (and return pointer to) a heap block
545  *   for objects of size sz words, searching the nth free list.
546  *
547  * NOTE: We set obj_map field in header correctly.
548  *       Caller is responsible for building an object freelist in block.
549  *
550  * Unlike older versions of the collectors, the client is responsible
551  * for clearing the block, if necessary.
552  */
553 struct hblk *
554 GC_allochblk(sz, kind, flags)
555 word sz;
556 int kind;
557 unsigned flags;  /* IGNORE_OFF_PAGE or 0 */
558 {
559     word blocks = OBJ_SZ_TO_BLOCKS(sz);
560     int start_list = GC_hblk_fl_from_blocks(blocks);
561     int i;
562     for (i = start_list; i <= N_HBLK_FLS; ++i) {
563         struct hblk * result = GC_allochblk_nth(sz, kind, flags, i);
564         if (0 != result) {
565             return result;
566         }
567     }
568     return 0;
569 }
570 /*
571  * The same, but with search restricted to nth free list.
572  */
573 struct hblk *
574 GC_allochblk_nth(sz, kind, flags, n)
575 word sz;
576 int kind;
577 unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
578 int n;
579 {
580     register struct hblk *hbp;
581     register hdr * hhdr;                /* Header corr. to hbp */
582     register struct hblk *thishbp;
583     register hdr * thishdr;             /* Header corr. to hbp */
584     signed_word size_needed;    /* number of bytes in requested objects */
585     signed_word size_avail;     /* bytes available in this block        */
586
587     size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
588
589     /* search for a big enough block in free list */
590         hbp = GC_hblkfreelist[n];
591         for(; 0 != hbp; hbp = hhdr -> hb_next) {
592             GET_HDR(hbp, hhdr);
593             size_avail = hhdr->hb_sz;
594             if (size_avail < size_needed) continue;
595             if (size_avail != size_needed
596                 && !GC_use_entire_heap
597                 && !GC_dont_gc
598                 && USED_HEAP_SIZE >= GC_requested_heapsize
599                 && !TRUE_INCREMENTAL && GC_should_collect()) {
600 #               ifdef USE_MUNMAP
601                     continue;
602 #               else
603                     /* If we have enough large blocks left to cover any */
604                     /* previous request for large blocks, we go ahead   */
605                     /* and split.  Assuming a steady state, that should */
606                     /* be safe.  It means that we can use the full      */
607                     /* heap if we allocate only small objects.          */
608                     if (!GC_enough_large_bytes_left(GC_large_allocd_bytes, n)) {
609                       continue;
610                     } 
611                     /* If we are deallocating lots of memory from       */
612                     /* finalizers, fail and collect sooner rather       */
613                     /* than later.                                      */
614                     if (WORDS_TO_BYTES(GC_finalizer_mem_freed)
615                         > (GC_heapsize >> 4))  {
616                       continue;
617                     }
618 #               endif /* !USE_MUNMAP */
619             }
620             /* If the next heap block is obviously better, go on.       */
621             /* This prevents us from disassembling a single large block */
622             /* to get tiny blocks.                                      */
623             {
624               signed_word next_size;
625               
626               thishbp = hhdr -> hb_next;
627               if (thishbp != 0) {
628                 GET_HDR(thishbp, thishdr);
629                 next_size = (signed_word)(thishdr -> hb_sz);
630                 if (next_size < size_avail
631                   && next_size >= size_needed
632                   && !GC_is_black_listed(thishbp, (word)size_needed)) {
633                   continue;
634                 }
635               }
636             }
637             if ( !IS_UNCOLLECTABLE(kind) &&
638                  (kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
639               struct hblk * lasthbp = hbp;
640               ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
641               signed_word orig_avail = size_avail;
642               signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
643                                                 HBLKSIZE
644                                                 : size_needed);
645               
646               
647               while ((ptr_t)lasthbp <= search_end
648                      && (thishbp = GC_is_black_listed(lasthbp,
649                                                       (word)eff_size_needed))
650                         != 0) {
651                 lasthbp = thishbp;
652               }
653               size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
654               thishbp = lasthbp;
655               if (size_avail >= size_needed) {
656                 if (thishbp != hbp &&
657                     0 != (thishdr = GC_install_header(thishbp))) {
658                   /* Make sure it's mapped before we mangle it. */
659 #                   ifdef USE_MUNMAP
660                       if (!IS_MAPPED(hhdr)) {
661                         GC_remap((ptr_t)hbp, hhdr -> hb_sz);
662                         hhdr -> hb_flags &= ~WAS_UNMAPPED;
663                       }
664 #                   endif
665                   /* Split the block at thishbp */
666                       GC_split_block(hbp, hhdr, thishbp, thishdr, n);
667                   /* Advance to thishbp */
668                       hbp = thishbp;
669                       hhdr = thishdr;
670                       /* We must now allocate thishbp, since it may     */
671                       /* be on the wrong free list.                     */
672                 }
673               } else if (size_needed > (signed_word)BL_LIMIT
674                          && orig_avail - size_needed
675                             > (signed_word)BL_LIMIT) {
676                 /* Punt, since anything else risks unreasonable heap growth. */
677                 if (++GC_large_alloc_warn_suppressed
678                     >= GC_large_alloc_warn_interval) {
679                   WARN("Repeated allocation of very large block "
680                        "(appr. size %ld):\n"
681                        "\tMay lead to memory leak and poor performance.\n",
682                        size_needed);
683                   GC_large_alloc_warn_suppressed = 0;
684                 }
685                 size_avail = orig_avail;
686               } else if (size_avail == 0 && size_needed == HBLKSIZE
687                          && IS_MAPPED(hhdr)) {
688                 if (!GC_find_leak) {
689                   static unsigned count = 0;
690                   
691                   /* The block is completely blacklisted.  We need      */
692                   /* to drop some such blocks, since otherwise we spend */
693                   /* all our time traversing them if pointerfree        */
694                   /* blocks are unpopular.                              */
695                   /* A dropped block will be reconsidered at next GC.   */
696                   if ((++count & 3) == 0) {
697                     /* Allocate and drop the block in small chunks, to  */
698                     /* maximize the chance that we will recover some    */
699                     /* later.                                           */
700                       word total_size = hhdr -> hb_sz;
701                       struct hblk * limit = hbp + divHBLKSZ(total_size);
702                       struct hblk * h;
703                       struct hblk * prev = hhdr -> hb_prev;
704                       
705                       GC_words_wasted += BYTES_TO_WORDS(total_size);
706                       GC_large_free_bytes -= total_size;
707                       GC_remove_from_fl(hhdr, n);
708                       for (h = hbp; h < limit; h++) {
709                         if (h == hbp || 0 != (hhdr = GC_install_header(h))) {
710                           (void) setup_header(
711                                   hhdr,
712                                   BYTES_TO_WORDS(HBLKSIZE),
713                                   PTRFREE, 0); /* Cant fail */
714                           if (GC_debugging_started) {
715                             BZERO(h, HBLKSIZE);
716                           }
717                         }
718                       }
719                     /* Restore hbp to point at free block */
720                       hbp = prev;
721                       if (0 == hbp) {
722                         return GC_allochblk_nth(sz, kind, flags, n);
723                       }
724                       hhdr = HDR(hbp);
725                   }
726                 }
727               }
728             }
729             if( size_avail >= size_needed ) {
730 #               ifdef USE_MUNMAP
731                   if (!IS_MAPPED(hhdr)) {
732                     GC_remap((ptr_t)hbp, hhdr -> hb_sz);
733                     hhdr -> hb_flags &= ~WAS_UNMAPPED;
734                   }
735 #               endif
736                 /* hbp may be on the wrong freelist; the parameter n    */
737                 /* is important.                                        */
738                 hbp = GC_get_first_part(hbp, hhdr, size_needed, n);
739                 break;
740             }
741         }
742
743     if (0 == hbp) return 0;
744         
745     /* Add it to map of valid blocks */
746         if (!GC_install_counts(hbp, (word)size_needed)) return(0);
747         /* This leaks memory under very rare conditions. */
748                 
749     /* Set up header */
750         if (!setup_header(hhdr, sz, kind, flags)) {
751             GC_remove_counts(hbp, (word)size_needed);
752             return(0); /* ditto */
753         }
754
755     /* Notify virtual dirty bit implementation that we are about to write.  */
756     /* Ensure that pointerfree objects are not protected if it's avoidable. */
757         GC_remove_protection(hbp, divHBLKSZ(size_needed),
758                              (hhdr -> hb_descr == 0) /* pointer-free */);
759         
760     /* We just successfully allocated a block.  Restart count of        */
761     /* consecutive failures.                                            */
762     {
763         extern unsigned GC_fail_count;
764         
765         GC_fail_count = 0;
766     }
767
768     GC_large_free_bytes -= size_needed;
769     
770     GC_ASSERT(IS_MAPPED(hhdr));
771     return( hbp );
772 }
773  
774 struct hblk * GC_freehblk_ptr = 0;  /* Search position hint for GC_freehblk */
775
776 /*
777  * Free a heap block.
778  *
779  * Coalesce the block with its neighbors if possible.
780  *
781  * All mark words are assumed to be cleared.
782  */
783 void
784 GC_freehblk(hbp)
785 struct hblk *hbp;
786 {
787 struct hblk *next, *prev;
788 hdr *hhdr, *prevhdr, *nexthdr;
789 signed_word size;
790
791
792     GET_HDR(hbp, hhdr);
793     size = hhdr->hb_sz;
794     size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
795     GC_remove_counts(hbp, (word)size);
796     hhdr->hb_sz = size;
797 #   ifdef USE_MUNMAP
798       hhdr -> hb_last_reclaimed = GC_gc_no;
799 #   endif
800     
801     /* Check for duplicate deallocation in the easy case */
802       if (HBLK_IS_FREE(hhdr)) {
803         GC_printf1("Duplicate large block deallocation of 0x%lx\n",
804                    (unsigned long) hbp);
805         ABORT("Duplicate large block deallocation");
806       }
807
808     GC_ASSERT(IS_MAPPED(hhdr));
809     GC_invalidate_map(hhdr);
810     next = (struct hblk *)((word)hbp + size);
811     GET_HDR(next, nexthdr);
812     prev = GC_free_block_ending_at(hbp);
813     /* Coalesce with successor, if possible */
814       if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)) {
815         GC_remove_from_fl(nexthdr, FL_UNKNOWN);
816         hhdr -> hb_sz += nexthdr -> hb_sz; 
817         GC_remove_header(next);
818       }
819     /* Coalesce with predecessor, if possible. */
820       if (0 != prev) {
821         prevhdr = HDR(prev);
822         if (IS_MAPPED(prevhdr)) {
823           GC_remove_from_fl(prevhdr, FL_UNKNOWN);
824           prevhdr -> hb_sz += hhdr -> hb_sz;
825 #         ifdef USE_MUNMAP
826             prevhdr -> hb_last_reclaimed = GC_gc_no;
827 #         endif
828           GC_remove_header(hbp);
829           hbp = prev;
830           hhdr = prevhdr;
831         }
832       }
833     /* FIXME: It is not clear we really always want to do these merges  */
834     /* with -DUSE_MUNMAP, since it updates ages and hence prevents      */
835     /* unmapping.                                                       */
836
837     GC_large_free_bytes += size;
838     GC_add_to_fl(hbp, hhdr);    
839 }
840