Imported and merged Boehm GC 7.0
[cacao.git] / src / mm / boehm-gc / allchblk.c
index aec95dd11d559b5b4977f2caf369fe1d60ca404a..b91806f0c725f9edf603dfb083d9be67240e866b 100644 (file)
@@ -58,9 +58,7 @@ struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
 # ifdef __GNUC__
   __inline__
 # endif
-  static GC_bool GC_enough_large_bytes_left(bytes,n)
-  word bytes;
-  int n;
+  static GC_bool GC_enough_large_bytes_left(word bytes, int n)
   {
     int i;
     for (i = N_HBLK_FLS; i >= n; --i) {
@@ -82,12 +80,11 @@ struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
 #endif /* USE_MUNMAP */
 
 /* Map a number of blocks to the appropriate large block free list index. */
-int GC_hblk_fl_from_blocks(blocks_needed)
-word blocks_needed;
+int GC_hblk_fl_from_blocks(word blocks_needed)
 {
-    if (blocks_needed <= UNIQUE_THRESHOLD) return blocks_needed;
+    if (blocks_needed <= UNIQUE_THRESHOLD) return (int)blocks_needed;
     if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS;
-    return (blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
+    return (int)(blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
                                        + UNIQUE_THRESHOLD;
     
 }
@@ -108,46 +105,44 @@ void GC_print_hblkfreelist()
     word total_free = 0;
     hdr * hhdr;
     word sz;
-    int i;
+    unsigned i;
     
     for (i = 0; i <= N_HBLK_FLS; ++i) {
       h = GC_hblkfreelist[i];
 #     ifdef USE_MUNMAP
-        if (0 != h) GC_printf1("Free list %ld:\n",
-                              (unsigned long)i);
+        if (0 != h) GC_printf("Free list %ld:\n",
+                             (unsigned long)i);
 #     else
-        if (0 != h) GC_printf2("Free list %ld (Total size %ld):\n",
-                              (unsigned long)i,
-                              (unsigned long)GC_free_bytes[i]);
+        if (0 != h) GC_printf("Free list %lu (Total size %lu):\n",
+                             i, (unsigned long)GC_free_bytes[i]);
 #     endif
       while (h != 0) {
         hhdr = HDR(h);
         sz = hhdr -> hb_sz;
-       GC_printf2("\t0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
+       GC_printf("\t%p size %lu ", h, (unsigned long)sz);
        total_free += sz;
         if (GC_is_black_listed(h, HBLKSIZE) != 0) {
-             GC_printf0("start black listed\n");
+             GC_printf("start black listed\n");
         } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
-             GC_printf0("partially black listed\n");
+             GC_printf("partially black listed\n");
         } else {
-             GC_printf0("not black listed\n");
+             GC_printf("not black listed\n");
         }
         h = hhdr -> hb_next;
       }
     }
 #   ifndef USE_MUNMAP
       if (total_free != GC_large_free_bytes) {
-       GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
-                  (unsigned long) GC_large_free_bytes);
+       GC_printf("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
+                 (unsigned long) GC_large_free_bytes);
       }
 #   endif
-    GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
+    GC_printf("Total of %lu bytes on free list\n", (unsigned long)total_free);
 }
 
 /* Return the free list index on which the block described by the header */
 /* appears, or -1 if it appears nowhere.                                */
-int free_list_index_of(wanted)
-hdr * wanted;
+int free_list_index_of(hdr *wanted)
 {
     struct hblk * h;
     hdr * hhdr;
@@ -180,12 +175,12 @@ void GC_dump_regions()
            ++i;
            end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
          }
-       GC_printf2("***Section from 0x%lx to 0x%lx\n", start, end);
+       GC_printf("***Section from %p to %p\n", start, end);
        for (p = start; p < end;) {
            hhdr = HDR(p);
-           GC_printf1("\t0x%lx ", (unsigned long)p);
+           GC_printf("\t%p ", p);
            if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
-               GC_printf1("Missing header!!(%ld)\n", hhdr);
+               GC_printf("Missing header!!(%d)\n", hhdr);
                p += HBLKSIZE;
                continue;
            }
@@ -194,25 +189,25 @@ void GC_dump_regions()
                                        divHBLKSZ(hhdr -> hb_sz));
                int actual_index;
                
-               GC_printf1("\tfree block of size 0x%lx bytes",
-                          (unsigned long)(hhdr -> hb_sz));
+               GC_printf("\tfree block of size 0x%lx bytes",
+                         (unsigned long)(hhdr -> hb_sz));
                if (IS_MAPPED(hhdr)) {
-                   GC_printf0("\n");
+                   GC_printf("\n");
                } else {
-                   GC_printf0("(unmapped)\n");
+                   GC_printf("(unmapped)\n");
                }
                actual_index = free_list_index_of(hhdr);
                if (-1 == actual_index) {
-                   GC_printf1("\t\tBlock not on free list %ld!!\n",
-                               correct_index);
+                   GC_printf("\t\tBlock not on free list %d!!\n",
+                             correct_index);
                } else if (correct_index != actual_index) {
-                   GC_printf2("\t\tBlock on list %ld, should be on %ld!!\n",
-                              actual_index, correct_index);
+                   GC_printf("\t\tBlock on list %d, should be on %d!!\n",
+                             actual_index, correct_index);
                }
                p += hhdr -> hb_sz;
            } else {
-               GC_printf1("\tused for blocks of size 0x%lx bytes\n",
-                          (unsigned long)WORDS_TO_BYTES(hhdr -> hb_sz));
+               GC_printf("\tused for blocks of size 0x%lx bytes\n",
+                         (unsigned long)(hhdr -> hb_sz));
                p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
            }
        }
@@ -224,25 +219,56 @@ void GC_dump_regions()
 /* Initialize hdr for a block containing the indicated size and        */
 /* kind of objects.                                                    */
 /* Return FALSE on failure.                                            */
-static GC_bool setup_header(hhdr, sz, kind, flags)
-register hdr * hhdr;
-word sz;       /* object size in words */
-int kind;
-unsigned char flags;
+static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
+                           int kind, unsigned flags)
 {
-    register word descr;
+    word descr;
+    size_t granules;
     
-    /* Add description of valid object pointers */
-      if (!GC_add_map_entry(sz)) return(FALSE);
-      hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
-      
     /* Set size, kind and mark proc fields */
-      hhdr -> hb_sz = sz;
-      hhdr -> hb_obj_kind = kind;
-      hhdr -> hb_flags = flags;
+      hhdr -> hb_sz = byte_sz;
+      hhdr -> hb_obj_kind = (unsigned char)kind;
+      hhdr -> hb_flags = (unsigned char)flags;
+      hhdr -> hb_block = block;
       descr = GC_obj_kinds[kind].ok_descriptor;
-      if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
+      if (GC_obj_kinds[kind].ok_relocate_descr) descr += byte_sz;
       hhdr -> hb_descr = descr;
+    
+#   ifdef MARK_BIT_PER_OBJ
+     /* Set hb_inv_sz as portably as possible.                                 */
+     /* We set it to the smallest value such that sz * inv_sz > 2**32    */
+     /* This may be more precision than necessary.                     */
+      if (byte_sz > MAXOBJBYTES) {
+        hhdr -> hb_inv_sz = LARGE_INV_SZ;
+      } else {
+       word inv_sz;
+
+#       if CPP_WORDSZ == 64
+          inv_sz = ((word)1 << 32)/byte_sz;
+         if (((inv_sz*byte_sz) >> 32) == 0) ++inv_sz;
+#      else  /* 32 bit words */
+         GC_ASSERT(byte_sz >= 4);
+         inv_sz = ((unsigned)1 << 31)/byte_sz;
+         inv_sz *= 2;
+         while (inv_sz*byte_sz > byte_sz) ++inv_sz;
+#      endif
+       hhdr -> hb_inv_sz = inv_sz;
+      }
+#   else /* MARK_BIT_PER_GRANULE */
+      hhdr -> hb_large_block = (unsigned char)(byte_sz > MAXOBJBYTES);
+      granules = BYTES_TO_GRANULES(byte_sz);
+      if (EXPECT(!GC_add_map_entry(granules), FALSE)) {
+        /* Make it look like a valid block. */
+        hhdr -> hb_sz = HBLKSIZE;
+        hhdr -> hb_descr = 0;
+        hhdr -> hb_large_block = TRUE;
+        hhdr -> hb_map = 0;
+        return FALSE;
+      } else {
+        size_t index = (hhdr -> hb_large_block? 0 : granules);
+        hhdr -> hb_map = GC_obj_map[index];
+      }
+#   endif /* MARK_BIT_PER_GRANULE */
       
     /* Clear mark bits */
       GC_clear_hdr_marks(hhdr);
@@ -257,9 +283,7 @@ unsigned char flags;
  * We assume it is on the nth free list, or on the size
  * appropriate free list if n is FL_UNKNOWN.
  */
-void GC_remove_from_fl(hhdr, n)
-hdr * hhdr;
-int n;
+void GC_remove_from_fl(hdr *hhdr, int n)
 {
     int index;
 
@@ -300,8 +324,7 @@ int n;
 /*
  * Return a pointer to the free block ending just before h, if any.
  */
-struct hblk * GC_free_block_ending_at(h)
-struct hblk *h;
+struct hblk * GC_free_block_ending_at(struct hblk *h)
 {
     struct hblk * p = h - 1;
     hdr * phdr;
@@ -332,9 +355,7 @@ struct hblk *h;
  * Add hhdr to the appropriate free list.
  * We maintain individual free lists sorted by address.
  */
-void GC_add_to_fl(h, hhdr)
-struct hblk *h;
-hdr * hhdr;
+void GC_add_to_fl(struct hblk *h, hdr *hhdr)
 {
     int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
     struct hblk *second = GC_hblkfreelist[index];
@@ -357,7 +378,7 @@ hdr * hhdr;
       GET_HDR(second, second_hdr);
       second_hdr -> hb_prev = h;
     }
-    GC_invalidate_map(hhdr);
+    hhdr -> hb_flags |= FREE_BLK;
 }
 
 #ifdef USE_MUNMAP
@@ -457,11 +478,8 @@ void GC_merge_unmapped(void)
  * The header for the returned block must be set up by the caller.
  * If the return value is not 0, then hhdr is the header for it.
  */
-struct hblk * GC_get_first_part(h, hhdr, bytes, index)
-struct hblk *h;
-hdr * hhdr;
-word bytes;
-int index;
+struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
+                               size_t bytes, int index)
 {
     word total_size = hhdr -> hb_sz;
     struct hblk * rest;
@@ -473,7 +491,7 @@ int index;
     rest = (struct hblk *)((word)h + bytes);
     rest_hdr = GC_install_header(rest);
     if (0 == rest_hdr) {
-       /* This may be very bad news ... */
+       /* FIXME: This is likely to be very bad news ... */
        WARN("Header allocation failed: Dropping block.\n", 0);
        return(0);
     }
@@ -481,7 +499,7 @@ int index;
     rest_hdr -> hb_flags = 0;
 #   ifdef GC_ASSERTIONS
       /* Mark h not free, to avoid assertion about adjacent free blocks. */
-        hhdr -> hb_map = 0;
+        hhdr -> hb_flags &= ~FREE_BLK;
 #   endif
     GC_add_to_fl(rest, rest_hdr);
     return h;
@@ -499,12 +517,8 @@ int index;
  * (Hence adding it to a free list is silly.  But this path is hopefully
  * rare enough that it doesn't matter.  The code is cleaner this way.)
  */
-void GC_split_block(h, hhdr, n, nhdr, index)
-struct hblk *h;
-hdr * hhdr;
-struct hblk *n;
-hdr * nhdr;
-int index;     /* Index of free list */
+void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
+                   hdr *nhdr, int index /* Index of free list */)
 {
     word total_size = hhdr -> hb_sz;
     word h_size = (word)n - (word)h;
@@ -527,7 +541,8 @@ int index;  /* Index of free list */
       INCR_FREE_BYTES(index, -(signed_word)h_size);
       FREE_ASSERT(GC_free_bytes[index] > 0);
 #     ifdef GC_ASSERTIONS
-       nhdr -> hb_map = 0;     /* Don't fail test for consecutive      */
+       nhdr -> hb_flags &= ~FREE_BLK;
+                               /* Don't fail test for consecutive      */
                                /* free blocks in GC_add_to_fl.         */
 #     endif
 #   ifdef USE_MUNMAP
@@ -535,30 +550,31 @@ int index;        /* Index of free list */
 #   endif
     hhdr -> hb_sz = h_size;
     GC_add_to_fl(h, hhdr);
-    GC_invalidate_map(nhdr);
+    nhdr -> hb_flags |= FREE_BLK;
 }
        
-struct hblk * GC_allochblk_nth();
+struct hblk *
+GC_allochblk_nth(size_t sz/* bytes */, int kind, unsigned flags, int n);
 
 /*
  * Allocate (and return pointer to) a heap block
- *   for objects of size sz words, searching the nth free list.
+ *   for objects of size sz bytes, searching the nth free list.
  *
  * NOTE: We set obj_map field in header correctly.
  *       Caller is responsible for building an object freelist in block.
  *
- * Unlike older versions of the collectors, the client is responsible
- * for clearing the block, if necessary.
+ * The client is responsible for clearing the block, if necessary.
  */
 struct hblk *
-GC_allochblk(sz, kind, flags)
-word sz;
-int kind;
-unsigned flags;  /* IGNORE_OFF_PAGE or 0 */
+GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
 {
-    word blocks = OBJ_SZ_TO_BLOCKS(sz);
-    int start_list = GC_hblk_fl_from_blocks(blocks);
+    word blocks;
+    int start_list;
     int i;
+
+    GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
+    blocks = OBJ_SZ_TO_BLOCKS(sz);
+    start_list = GC_hblk_fl_from_blocks(blocks);
     for (i = start_list; i <= N_HBLK_FLS; ++i) {
        struct hblk * result = GC_allochblk_nth(sz, kind, flags, i);
        if (0 != result) {
@@ -569,18 +585,18 @@ unsigned flags;  /* IGNORE_OFF_PAGE or 0 */
 }
 /*
  * The same, but with search restricted to nth free list.
+ * Flags is IGNORE_OFF_PAGE or zero.
+ * Unlike the above, sz is in bytes.
  */
 struct hblk *
-GC_allochblk_nth(sz, kind, flags, n)
-word sz;
-int kind;
-unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
-int n;
+GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
 {
-    register struct hblk *hbp;
-    register hdr * hhdr;               /* Header corr. to hbp */
-    register struct hblk *thishbp;
-    register hdr * thishdr;            /* Header corr. to hbp */
+    struct hblk *hbp;
+    hdr * hhdr;                /* Header corr. to hbp */
+                       /* Initialized after loop if hbp !=0    */
+                       /* Gcc uninitialized use warning is bogus.      */
+    struct hblk *thishbp;
+    hdr * thishdr;             /* Header corr. to hbp */
     signed_word size_needed;    /* number of bytes in requested objects */
     signed_word size_avail;    /* bytes available in this block        */
 
@@ -611,8 +627,7 @@ int n;
                    /* If we are deallocating lots of memory from       */
                    /* finalizers, fail and collect sooner rather       */
                    /* than later.                                      */
-                   if (WORDS_TO_BYTES(GC_finalizer_mem_freed)
-                       > (GC_heapsize >> 4))  {
+                   if (GC_finalizer_bytes_freed > (GC_heapsize >> 4))  {
                      continue;
                    }
 #              endif /* !USE_MUNMAP */
@@ -702,14 +717,13 @@ int n;
                      struct hblk * h;
                      struct hblk * prev = hhdr -> hb_prev;
                      
-                     GC_words_wasted += BYTES_TO_WORDS(total_size);
                      GC_large_free_bytes -= total_size;
                      GC_remove_from_fl(hhdr, n);
                      for (h = hbp; h < limit; h++) {
                        if (h == hbp || 0 != (hhdr = GC_install_header(h))) {
                          (void) setup_header(
-                                 hhdr,
-                                 BYTES_TO_WORDS(HBLKSIZE),
+                                 hhdr, h,
+                                 HBLKSIZE,
                                  PTRFREE, 0); /* Cant fail */
                          if (GC_debugging_started) {
                            BZERO(h, HBLKSIZE);
@@ -747,7 +761,7 @@ int n;
        /* This leaks memory under very rare conditions. */
                
     /* Set up header */
-        if (!setup_header(hhdr, sz, kind, flags)) {
+        if (!setup_header(hhdr, hbp, sz, kind, flags)) {
             GC_remove_counts(hbp, (word)size_needed);
             return(0); /* ditto */
         }
@@ -781,8 +795,7 @@ struct hblk * GC_freehblk_ptr = 0;  /* Search position hint for GC_freehblk */
  * All mark words are assumed to be cleared.
  */
 void
-GC_freehblk(hbp)
-struct hblk *hbp;
+GC_freehblk(struct hblk *hbp)
 {
 struct hblk *next, *prev;
 hdr *hhdr, *prevhdr, *nexthdr;
@@ -800,13 +813,12 @@ signed_word size;
     
     /* Check for duplicate deallocation in the easy case */
       if (HBLK_IS_FREE(hhdr)) {
-        GC_printf1("Duplicate large block deallocation of 0x%lx\n",
-                  (unsigned long) hbp);
+        GC_printf("Duplicate large block deallocation of %p\n", hbp);
        ABORT("Duplicate large block deallocation");
       }
 
     GC_ASSERT(IS_MAPPED(hhdr));
-    GC_invalidate_map(hhdr);
+    hhdr -> hb_flags |= FREE_BLK;
     next = (struct hblk *)((word)hbp + size);
     GET_HDR(next, nexthdr);
     prev = GC_free_block_ending_at(hbp);