The new allocator and a new bitmap management subsystem.
authorphil <none@none>
Tue, 3 Nov 1998 11:29:37 +0000 (11:29 +0000)
committerphil <none@none>
Tue, 3 Nov 1998 11:29:37 +0000 (11:29 +0000)
mm/allocator.c [new file with mode: 0644]
mm/allocator.h [new file with mode: 0644]
mm/bitmap2.c [new file with mode: 0644]
mm/bitmap2.h [new file with mode: 0644]
mm/mm.h [new file with mode: 0644]

diff --git a/mm/allocator.c b/mm/allocator.c
new file mode 100644 (file)
index 0000000..975674c
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * cacao/mm/allocator.c
+ *
+ * Copyright (c) 1998 A. Krall, R. Grafl, M. Gschwind, M. Probst, Ph. Tomsich
+ * See file COPYRIGHT for information on usage and disclaimer of warranties
+ *
+ * Authors: Philipp Tomsich     EMAIL: cacao@complang.tuwien.ac.at
+ *
+ * $Id: allocator.c 34 1998-11-03 11:29:37Z phil $
+ */
+
+/* 
+   NOTES: 
+
+   Locality preservation has not been added... yet
+*/
+
+#include "allocator.h"
+
+static FREE_EXACT*  __freelist_exact[1 << EXACT];
+static FREE_EXACT** freelist_exact = &__freelist_exact[-1];
+static FREE_LARGE*  freelist_large[LARGE << SUBBIT];
+
+#if SMALL_TABLES
+static unsigned char  highest[256];
+#else
+#      if EXACT_TOP_BIT < 8
+#       if (ADDRESS == 64)
+static unsigned char  highest_0[2048];
+#       else
+static unsigned char  highest_0[1024];
+#       endif
+
+static unsigned char* highest_8  = &highest_0[256];
+static unsigned char* highest_16 = &highest_0[512];
+static unsigned char* highest_24 = &highest_0[768];
+#       if (ADDRESS == 64)
+static unsigned char* highest_32 = &highest_0[1024];
+static unsigned char* highest_40 = &highest_0[1280];
+static unsigned char* highest_48 = &highest_0[1538];
+static unsigned char* highest_56 = &highest_0[1792];
+#       endif
+#      else
+#       if (ADDRESS == 64)
+static unsigned char  highest_8[1792];
+#       else
+static unsigned char  highest_8[768];
+#       endif
+
+static unsigned char* highest_16 = &highest_8[256];
+static unsigned char* highest_24 = &highest_8[512];
+#       if (ADDRESS == 64)
+static unsigned char* highest_32 = &highest_8[768];
+static unsigned char* highest_40 = &highest_8[1280];
+static unsigned char* highest_48 = &highest_8[1538];
+static unsigned char* highest_56 = &highest_8[1792];
+#       endif
+#      endif
+#endif
+
+static
+unsigned char 
+find_highest(SIZE bits){
+#if MSB_TO_LSB_SEARCH
+       /* optimize for large allocation sizes */
+#      if SMALL_TABLES
+#              if ADDRESS == 64
+                       if (bits & 0xff00000000000000ULL)
+                               return 56 + highest[bits >> 56 & 0xff];
+                       if (bits & 0xff000000000000ULL)
+                               return 48 + highest[bits >> 48 & 0xff];
+                       if (bits & 0xff0000000000ULL)
+                               return 40 + highest[bits >> 40 & 0xff];
+                       if (bits & 0xff00000000ULL)
+                               return 32 + highest[bits >> 32 & 0xff];
+#              endif
+
+                       if (bits & 0xff000000)
+                               return 24 + highest[bits >> 24 & 0xff];
+                       if (bits & 0xff0000)
+                               return 16 + highest[bits >> 16 & 0xff];
+                       if (bits & 0xff00)
+                               return 8 + highest[bits >> 8 & 0xff];
+
+#      if EXACT_TOP_BIT < 8
+                       return highest[bits & 0xff];
+#              endif
+#      else
+#              if ADDRESS == 64
+                       if (bits & 0xff00000000000000ULL)
+                               return highest_56[bits >> 56 & 0xff];
+                       if (bits & 0xff000000000000ULL)
+                               return highest_48[bits >> 48 & 0xff];
+                       if (bits & 0xff0000000000ULL)
+                               return highest_40[bits >> 40 & 0xff];
+                       if (bits & 0xff00000000ULL)
+                               return highest_32[bits >> 32 & 0xff];
+#              endif
+
+                       if (bits & 0xff000000)
+                               return highest_24[bits >> 24 & 0xff];
+                       if (bits & 0xff0000)
+                               return highest_16[bits >> 16 & 0xff];
+                       if (bits & 0xff00)
+                               return highest_8[bits >> 8 & 0xff];
+
+#      if EXACT_TOP_BIT < 8
+                       return highest_0[bits & 0xff];
+#              endif                   
+#      endif
+
+#else
+       /* optimize for small allocation sizes */
+
+#      if SMALL_TABLES
+#      if EXACT_TOP_BIT < 8
+                       if (!(bits & ~0xffULL))
+                               return highest[bits & 0xff];
+#              endif
+
+                       if (!(bits & ~0xffffULL))
+                               return 8 + highest[bits >> 8 & 0xff];
+
+                       if (!(bits & ~0xffffffULL))
+                               return 16 + highest[bits >> 16 & 0xff];
+
+#              if      ADDRESS == 32
+                       return 24 + highest[bits >> 24 & 0xff];
+#              else
+                       if (!(bits & ~0xffffffffULL))
+                               return 24 + highest[bits >> 24 & 0xff];
+
+                       if (!(bits & ~0xffffffffffULL))
+                               return 32 + highest[bits >> 32 & 0xff];
+
+                       if (!(bits & ~0xffffffffffffULL))
+                               return 40 + highest[bits >> 40 & 0xff];
+
+                       if (!(bits & ~0xffffffffffffffULL))
+                               return 48 + highest[bits >> 48 & 0xff];
+
+                       return 56 + highest[bits >> 56 & 0xff];
+#              endif
+#      else
+#      if EXACT_TOP_BIT < 8
+                       if (!(bits & ~0xffULL))
+                               return highest_0[bits & 0xff];
+#              endif
+
+                       if (!(bits & ~0xffffULL))
+                               return highest_8[bits >> 8 & 0xff];
+
+                       if (!(bits & ~0xffffffULL))
+                               return highest_16[bits >> 16 & 0xff];
+
+#              if      ADDRESS == 32
+                       return highest_24[bits >> 24 & 0xff];
+#              else
+                       if (!(bits & ~0xffffffffULL))
+                               return highest_24[bits >> 24 & 0xff];
+
+                       if (!(bits & ~0xffffffffffULL))
+                               return highest_32[bits >> 32 & 0xff];
+
+                       if (!(bits & ~0xffffffffffffULL))
+                               return highest_40[bits >> 40 & 0xff];
+
+                       if (!(bits & ~0xffffffffffffffULL))
+                               return highest_48[bits >> 48 & 0xff];
+
+                       return highest_56[bits >> 56 & 0xff];
+#              endif
+#      endif
+#endif
+
+};
+
+static 
+void 
+init_table()
+{
+  static unsigned char r[10] = { 1, 1, 2, 4, 8, 16, 32, 64, 128 };
+  int i, j, k, m;
+  
+  i = 0;
+  j = 0;
+  k = 0;
+  m = 0;
+
+  for (k = 0; k < 10; ++k) {
+         for (m = 0; m < r[k]; ++m) {
+#if SMALL_TABLES
+                 highest[i]  = j - (EXACT + ALIGN) - 1;
+#else
+#      if (EXACT_TOP_BIT < 8)
+                 highest_0 [i]  = j - 8 - (EXACT + ALIGN) - 1;
+#      endif
+                 highest_8 [i]  = j + 8 - (EXACT + ALIGN) - 1;
+                 highest_16 [i] =  8 + highest_8 [i];
+                 highest_24 [i] = 16 + highest_8 [i];                  
+#   if (ADDRESS == 64)
+                 highest_32 [i] = 24 + highest_8 [i];
+                 highest_40 [i] = 32 + highest_8 [i];
+                 highest_48 [i] = 40 + highest_8 [i];
+                 highest_56 [i] = 48 + highest_8 [i];
+#   endif
+#endif
+      
+                 ++i;
+         }
+         
+         ++j;
+  }
+}
+
+#define PRESERVE_LOCALITY 0
+
+#if FASTER_FAIL
+static SIZE    allocator_largest_free = 0;
+#endif
+
+#if PRESERVE_LOCALITY
+static void* allocator_last_splitoff = 0;
+static SIZE  allocator_last_splitoff_size = 0;
+#endif
+
+void
+allocator_reset()
+{
+       int i;
+
+#if FASTER_FAIL
+       allocator_largest_free = 0;
+#endif
+
+#if PRESERVE_LOCALITY
+       allocator_last_splitoff = 0;
+       allocator_last_splitoff_size = 0;
+#endif
+
+  for (i = 1; i <= (1 << EXACT); ++i)
+         freelist_exact[i] = 0;
+  
+  for (i = 0; i < (LARGE << SUBBIT); ++i)
+         freelist_large[i] = 0;
+}
+
+
+#include <stdio.h>
+
+
+#if COUNT_ALLOCATIONS
+static unsigned long long      allocator_allocations = 0;
+
+void
+allocator_display_count()
+{
+       fprintf(stderr, "total allocations: %d\n", allocator_allocations);
+}
+#endif
+
+
+void 
+allocator_init()
+{
+       fprintf(stderr, 
+                       "allocator_init: $Id: allocator.c 34 1998-11-03 11:29:37Z phil $\n\n");
+       
+       fprintf(stderr, "\t%d bit addresses\n", ADDRESS);
+       fprintf(stderr, "\t%d bit alignment\n", ALIGN);
+       fprintf(stderr, "\t%d exact bits\n", EXACT );
+       fprintf(stderr, "\t%d large bits\n", LARGE );
+       fprintf(stderr, "\t%d subbin bits\n", SUBBIT );
+       fprintf(stderr, "\tusing %s tables\n", 
+                       SMALL_TABLES ? "small (256 byte)" : "large (2048 byte)");
+       fprintf(stderr, "\tusing %s highest-bit search strategy\n",
+                       MSB_TO_LSB_SEARCH ? "MSB-to-LSB" : "LSB-to-MSB");
+       
+       fprintf(stderr, 
+                       "\tusing %d bytes for exact bins, %d bytes for sorted bins\n\n",
+                       (1 << EXACT) << ALIGN,
+                       (LARGE << SUBBIT) << ALIGN);
+       
+       init_table();           /* set up the highest-table */
+       allocator_reset();      /* clear the freelists & internal variables */
+}
+
+int
+size_to_bin(SIZE  size)
+{
+#if PRINTF
+       printf ("size: %d ", size);
+#endif
+  
+#if EXACT > 0
+       if (size > ((1 << EXACT) << ALIGN)) {
+#endif
+               // unsigned char        shift = shift_table_32[highbit];
+               // int          bin = offset_table_32[highbit] + ( (size >> shift) & mask );
+#if SUBBIT != 0
+               unsigned char   highbit = find_highest(size);
+               unsigned char   shift = highbit + (EXACT + ALIGN - SUBBIT);
+               static int      mask = (1 << SUBBIT) - 1;
+               int                             bin = (highbit << SUBBIT) + ( (size >> shift) & mask );
+
+               // printf("shift: %d, %d; %d; large bin: %d\n", shift, (size >> shift) & mask, highbit,  bin);
+#else
+               int                             bin = find_highest(size);
+#endif
+
+#if PRINTF
+               printf("==> large bin: %d\n",  bin);
+#endif
+    
+               return bin;
+#if EXACT > 0
+       } else {
+#if PRINTF
+               printf("==> exact bin: %d\n", (int)((size >> ALIGN) - 1));
+#endif
+    
+               return (size >> ALIGN);
+       }
+#endif
+}
+
+#include <assert.h>
+
+
+#define OLDEST_FIRST   1
+
+
+
+/* FIXME: 
+   Should we enforce an additional "lowest address first" - ordering
+   for the freelist-entries ??? Right now, I'm using oldest-first for 
+   the large bins and newest-first for the exact bins...
+
+   Sorting by the address may reduce heap fragmentation by reducing the
+   heap growth-rate... */
+
+void
+allocator_free(void* chunk, SIZE size)
+{
+       assert(chunk && size);
+
+#if FASTER_FAIL
+       if (size > allocator_largest_free)
+               allocator_largest_free = size;
+#endif
+
+       if (size > ((1 << EXACT) << ALIGN)) {
+               int                     bin = size_to_bin(size);
+               FREE_LARGE*             curr = freelist_large[bin];
+
+               ((FREE_LARGE*)chunk)->size = size;
+
+               if (!freelist_large[bin] || (freelist_large[bin]->size > size)) {
+                       /* prepend */
+                       ((FREE_LARGE*)chunk)->next = freelist_large[bin];
+                       freelist_large[bin] = (FREE_LARGE*)chunk;
+                       return;
+               }
+
+               while ((curr->next) && (curr->next->size <= size)) {
+                       curr = curr->next;
+               };
+
+               /* insert or append */
+               ((FREE_LARGE*)chunk)->next = curr->next;
+               curr->next=(FREE_LARGE*)chunk;
+       } else {
+               int bin = size >> ALIGN;
+
+#if OLDEST_FIRST
+               if (!freelist_exact[bin]) {
+#endif
+                       /* simply prepend */
+                       ((FREE_EXACT*)chunk)->next = freelist_exact[bin];
+                       freelist_exact[bin] = (FREE_EXACT*)chunk;
+#if OLDEST_FIRST
+               } else {
+                       FREE_EXACT*  curr = (FREE_EXACT*)freelist_exact[bin];
+                       while (curr->next && (curr < (FREE_EXACT*)chunk))
+                               curr = curr->next;
+
+                       /* insert */
+                       ((FREE_EXACT*)chunk)->next = curr->next;
+                       curr->next = (FREE_EXACT*)chunk;                        
+               }
+#endif
+       }
+
+       return;
+}
+
+void*
+allocator_alloc(SIZE size)
+{
+       void*   result = NULL;
+       int     maxbin;
+       int             bin;
+
+#if COUNT_ALLOCATIONS
+       allocator_allocations++;
+#endif
+
+#if FASTER_FAIL
+       if (size > allocator_largest_free)
+               return NULL;
+#endif
+
+#if PRESERVE_LOCALITY
+       allocator_last_splitoff = 0;
+       allocator_last_splitoff_size = 0;
+#endif
+
+       if (size <= ((1 << EXACT) << ALIGN)) {
+               /* search the exact bins */
+               bin = size >> ALIGN;
+               maxbin = 1 << EXACT;
+
+               while (bin <= maxbin) {
+                       if (freelist_exact[bin]) {
+                               /* unlink */
+                               result = (void*)freelist_exact[bin];
+                               freelist_exact[bin]=freelist_exact[bin]->next;
+
+                               /* split */
+                               if ((bin << ALIGN) > size)
+                                       allocator_free(result + size, (bin << ALIGN) - size);
+
+                               //                              fprintf(stderr, "found chunk in exact bin %d\n", bin);
+
+                               return result;
+                       } else
+                               ++bin;
+               }
+
+               bin = 0;
+       } else {
+               bin = size_to_bin(size);
+       }
+
+       maxbin = LARGE << SUBBIT;
+       
+       while (bin < maxbin) {
+               if (freelist_large[bin]) {
+                       FREE_LARGE*  chunk = freelist_large[bin];
+
+                       //                      fprintf(stderr, "found chunk in large bin %d\n", bin);
+
+                       if (chunk->size >= size) {
+                               /* unlink */
+                               freelist_large[bin] = chunk->next;
+
+                               /* split */
+                               if (chunk->size > size)
+                                       allocator_free((void*)chunk + size, (chunk->size - size));
+                               
+                               return (void*)chunk;
+                       }
+
+                       while (chunk->next && (chunk->next->size < size))
+                               chunk = chunk->next;
+
+                       if (chunk->next) {
+                               /* unlink */
+                               FREE_LARGE*  new_chunk = chunk->next;                           
+                               chunk->next = new_chunk->next;
+
+                               /* split */
+                               if (new_chunk->size > size)
+                                       allocator_free((void*)new_chunk + size, (new_chunk->size - size));
+                               
+                               return (void*)new_chunk;
+                       }
+               }
+               
+               ++bin;
+       }
+
+       return result;  /* NULL */
+}
+
+void
+allocator_dump()
+{
+       int i;
+
+       for (i = 1; i <= 1 << EXACT; ++i) {
+               int                     count = 0;
+               FREE_EXACT*     chunk = freelist_exact[i];
+
+               while (chunk) {
+                       chunk = chunk->next;
+                       ++count;
+               }
+
+               if (count)
+                       printf("exact bin %d (%d byte blocks): %d\n", i, i * (1 << ALIGN), count);
+       }
+       for (i = 0; i < LARGE << SUBBIT; ++i) {
+               int                     count = 0;
+               FREE_LARGE*     chunk = freelist_large[i];
+
+               if (chunk) 
+                       printf("large bin %d:\n", i);
+
+               while (chunk) {
+                       printf("\t%d bytes @ 0x%lx\n", chunk->size, chunk);
+                       chunk = chunk->next;
+                       ++count;
+               }
+       }
+
+       printf("dump complete.\n");
+}
+
+
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/mm/allocator.h b/mm/allocator.h
new file mode 100644 (file)
index 0000000..6209676
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * cacao/mm/allocator.h
+ * $Id: allocator.h 34 1998-11-03 11:29:37Z phil $
+ */
+
+#ifndef __allocator_h_
+#define __allocator_h_
+
+#ifndef YES
+#      define YES              1
+#endif
+#ifndef NO
+#      define NO           0
+#endif
+
+#define COUNT_ALLOCATIONS      NO
+
+#define FASTER_FAIL            NO
+
+#define PRINTF                         NO
+#define SMALL_TABLES           YES
+#define MSB_TO_LSB_SEARCH      NO
+
+#define ADDRESS        64
+//#define ADDRESS 32
+
+#if ADDRESS == 64
+#  define SIZE unsigned long long
+#else
+#  define SIZE unsigned long
+#endif
+
+#define ALIGN  3       /* 64bit alignment */
+//#define ALIGN        2       /* 32bit allignment */
+
+#define EXACT_TOP_BIT  8       /* usually somewhere in the range [8..10]
+                                                          the largest exact chunk is 1 << EXACT_TOP_BIT bytes large &
+                                                          there'll be 1 << (EXACT_TOP_BIT - ALIGN) exact bins 
+                                                          
+                                                          Supported values are between 0 and 16...
+                                                          ...any value less than ALIGN mean "no exact bins"...
+                                                          ...actually, there'll be a very small first bin containing
+                                                          chunks exactly allocationblock sized.
+                                  
+                                                          Setting EXACT_TOP_BIT to anything less than (SUBBIT + ALIGN)
+                                                          doesn't really make sense either, but is possible...
+                                                       */
+
+/* check EXACT_TOP_BIT early ... */
+
+#if (EXACT_TOP_BIT > 16)
+#      warning "EXACT_TOP_BIT > 16: bad idea & unsupported value; using 16"
+#   undef EXACT_TOP_BIT
+#      define EXACT_TOP_BIT 16
+#endif
+
+
+#if EXACT_TOP_BIT >= ALIGN
+# define EXACT (EXACT_TOP_BIT - ALIGN)
+#else
+# define EXACT  0
+#endif
+#define LARGE  (ADDRESS - EXACT - ALIGN)
+
+#define SUBBIT  0      /* set this to 0 to disable the additional hashing for the large bins;
+                                          otherwise, good values are in the range [3..5]; the best setting for
+                                          a particular application is highly dependent on the VM's heap-size 
+                                          and the cache sizes. Remember, the allocator will create 
+                                          (LARGE << SUBBIT) sorted bins. In the case of a 64bit machine with
+                                          256 exact bins (EXACT_TOP_BIT == 9), a SUBBIT setting of 3 will
+                                          create 64-9=55 bins consisting of 2^3=8 subbins; thus, a pointer
+                                          array with 55*8 fields will be allocated, eating up 3520 bytes. */
+
+/* check config */
+
+#if (SUBBIT < 0)
+#      warning "SUBBIT < 0: using 0."
+#      undef SUBBIT
+#      define SUBBIT   0
+#endif
+
+#if (SUBBIT > (EXACT_TOP_BIT - ALIGN))
+#  warning "SUBBIT > (EXACT_TOP_BIT - ALIGN): wasting subbins!"
+#endif
+
+#if (((LARGE << SUBBIT) << ALIGN) > (1 << 16))
+#  warning "((LARGE << SUBBIT) << ALIGN) > 64K: are you sure you want it this big??" 
+#endif
+
+typedef struct freeblock_exact {
+       struct freeblock_exact* next;
+} FREE_EXACT;
+
+typedef struct freeblock_large {
+       SIZE                                    size;
+       struct freeblock_large* next;
+} FREE_LARGE;
+
+
+void allocator_free(void* chunk, SIZE size);
+void* allocator_alloc(SIZE size);
+void allocator_init(void);
+void allocator_reset(void);
+
+#endif /* !defined(__allocator_h_) */
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
+
diff --git a/mm/bitmap2.c b/mm/bitmap2.c
new file mode 100644 (file)
index 0000000..350ce1e
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * cacao/mm/bitmap2.c
+ *
+ * Copyright (c) 1998 A. Krall, R. Grafl, M. Gschwind, M. Probst, P. Tomsich
+ * See file COPYRIGHT for information on usage and disclaimer of warranties
+ *
+ * Authors: Philipp Tomsich     EMAIL: cacao@complang.tuwien.ac.at
+ *
+ * $Id: bitmap2.c 34 1998-11-03 11:29:37Z phil $
+ */
+
+/*
+ * This file contains the new bitmap management; it's used within the garbage 
+ * collector and allocator to maintain and access the objectstart-, marker- 
+ * and reference-bitmaps.
+ *
+ * Notes:
+ * 1. For efficencies sake, the memory used for the bitmap is never accessed 
+ *    directly using a heap-offset, but through a pointer offset at bitmap 
+ *    creation; this saves all the subtractions and additions necessary to 
+ *    convert between an address on the heap and an offset into the heap.
+ *
+ * 2. I finally added a bitmap_t structure to encapsulate some state 
+ *    information. It contains everything necessary to access the bitmap, 
+ *    caches a few precomputable values and allows for freeing the bitmap.
+ *
+ * 3. There's no checks whatsoever to determine whether an address passed is 
+ *    valid or not. These were removed, in order to allow passing the offset 
+ *    address of the bitmap instead of the bitmap structure.
+ *    I.e., checking addresses to determine whether they are pointing onto 
+ *          the heap must be done before passing them to the bitmap management
+ *          functions.
+ *
+ * 4. Just added exceptions to note 3: Now we have new functions checking the 
+ *    validity of the address to aid in debugging. They are named 
+ *    bitmap_checking_{set|clear|test}bit and will cause an assertion to fail 
+ *    if the addr argument is out of range.
+ */
+
+#include <assert.h>  /* assert */
+#include <stdio.h>   /* printf, fprintf */
+#include <stdlib.h>  /* malloc, free */
+#include <string.h>  /* memset */
+#include <unistd.h>  /* exit */
+
+#include "bitmap2.h"
+
+
+#warning "bitmap2.c untested in 32-bit mode -- phil."
+
+/* FIXME: I haven't decided, whether to keep these macro definitions here or 
+ *        move them to the header file; they are implementation details, so 
+ *        they should stay here, but moving them would make the SETBIT,
+ *        TESTBIT and CLEARBIT macros available to the general public. --phil.
+ */
+
+/* FIXME: HEAPBLOCK_SIZE is an alias for POINTER_ALIGNMENT and should be 
+ *        removed. --phil. 
+ */
+
+/* Please note: All values are log2 */
+#if U8_AVAILABLE
+#    define POINTER_ALIGNMENT                          3  /* alignment of pointers onto the 
+                                                                                         heap == heapblocksize */
+#    define BITBLOCK_SIZE                              3  /* bytes/BITBLOCK */
+#else
+#    define POINTER_ALIGNMENT                          2
+#    define BITBLOCK_SIZE                              2
+#endif
+
+#define HEAPBLOCK_SIZE                         POINTER_ALIGNMENT
+#define BITS_PER_BYTE                          3  /* actually quite self-explainatory */
+#define HEAPBLOCKS_PER_BITBLOCK                (BITBLOCK_SIZE + BITS_PER_BYTE)
+
+#define ADDR_TO_BLOCK(addr)                    ((OFFSET_T)(addr) >> (HEAPBLOCKS_PER_BITBLOCK + POINTER_ALIGNMENT))
+#define ADDR_TO_OFFSET(addr)           (((OFFSET_T)(addr) & ((1 << (HEAPBLOCKS_PER_BITBLOCK + POINTER_ALIGNMENT)) - 1)) >> HEAPBLOCK_SIZE)
+#define BLOCK_TO_ADDR(block)           ((block) << (HEAPBLOCKS_PER_BITBLOCK + POINTER_ALIGNMENT))
+#define OFFSET_TO_ADDR(offset)         ((offset) << HEAPBLOCK_SIZE)
+#define CALC_BITMAP_SIZE(size)         (((size) + ((1 << (POINTER_ALIGNMENT + HEAPBLOCK_SIZE)) - 1)) >> BITS_PER_BYTE)
+
+#define CHECK_ADDR_ALIGNMENT(addr)     { assert(!((OFFSET_T)addr & ((1 << POINTER_ALIGNMENT) - 1))); }
+#define CALC_ZERO_OFFSET(zero)         (((OFFSET_T)(zero) >> (HEAPBLOCK_SIZE + BITS_PER_BYTE)))
+
+#define BIT_AT_OFFSET(offset)          ((BITBLOCK)1 << (offset))
+#define BIT_FOR_ADDR(addr)                     BIT_AT_OFFSET(ADDR_TO_OFFSET((addr)))
+
+#define SETBIT(bitmap, addr)           { bitmap[ADDR_TO_BLOCK(addr)] |=  BIT_FOR_ADDR(addr); }
+#define CLEARBIT(bitmap, addr)         { bitmap[ADDR_TO_BLOCK(addr)] &= ~BIT_FOR_ADDR(addr); }
+#define TESTBIT(bitmap, addr)          ( (bitmap[ADDR_TO_BLOCK(addr)] & BIT_FOR_ADDR(addr)) != 0 )
+
+
+/* Operations per macro (relative cost):
+ *  
+ *   Macro            | & | &= | |= | ~ | >> | << | + | dereference |
+ *   -----------------+---+----+----+---+----+----+---+-------------+
+ *   ADDR_TO_BLOCK    | 0 |  0 |  0 | 0 |  1 |  0 | 0 |           0 |
+ *   ADDR_TO_OFFSET   | 1 |  0 |  0 | 0 |  1 |  0 | 0 |           0 |
+ *   BLOCK_TO_ADDR    | 0 |  0 |  0 | 0 |  0 |  1 | 0 |           0 |
+ *   OFFSET_TO_ADDR   | 0 |  0 |  0 | 0 |  0 |  1 | 0 |           0 |
+ *   CALC_BITMAP_SIZE | 0 |  0 |  0 | 0 |  0 |  1 | 0 |           0 |
+ *   CALC_ZERO_OFFSET | 0 |  0 |  0 | 0 |  1 |  0 | 0 |           0 |
+ *   -----------------+---+----+----+---+----+----+---+-------------+
+ *   BIT_AT_OFFSET    | 0 |  0 |  0 | 0 |  0 |  1 | 0 |           0 |
+ *   BIT_FOR_ADDR     | 1 |  0 |  0 | 0 |  1 |  1 | 0 |           0 |
+ *   -----------------+---+----+----+---+----+----+---+-------------+
+ *   SETBIT           | 1 |  0 |  1 | 0 |  2 |  1 | 0 |           1 |
+ *   CLEARBIT         | 1 |  1 |  0 | 1 |  2 |  1 | 0 |           1 |
+ *   TESTBIT          | 2 |  0 |  0 | 0 |  2 |  1 | 0 |           1 |
+ */
+
+
+inline 
+void bitmap_setbit(BITBLOCK* bitmap, 
+                                  void* addr)
+{ 
+       SETBIT(bitmap, addr); 
+}
+
+inline 
+void bitmap_clearbit(BITBLOCK* bitmap, 
+                                        void* addr)
+{ 
+       CLEARBIT(bitmap, addr); 
+}
+
+inline 
+bool bitmap_testbit(BITBLOCK* bitmap, 
+                                       void* addr)
+{ 
+       return TESTBIT(bitmap, addr); 
+}
+
+inline
+static
+void bitmap_boundscheck(bitmap_t* bitmap,
+                                               void*     addr)
+{
+       /* check the lower bound */
+       assert((void*)&bitmap->bitmap[ADDR_TO_BLOCK(addr)] >= bitmap->bitmap_memory);
+       /* check the upper bound */
+       assert(&bitmap->bitmap[
+                                                  ADDR_TO_BLOCK(addr)] 
+                  <= &bitmap->bitmap[bitmap->bitmap_top_block]);
+       assert(addr < bitmap->bitmap_beyond_addr); /* a stricter way to check the upper bound */
+}
+
+inline
+void bitmap_checking_setbit(bitmap_t* bitmap,
+                                                       void*     addr)
+{
+       bitmap_boundscheck(bitmap, addr);
+       bitmap_setbit(bitmap->bitmap, addr);
+}
+
+inline
+void bitmap_checking_clearbit(bitmap_t* bitmap,
+                                                         void*   addr)
+{
+       bitmap_boundscheck(bitmap, addr);
+       bitmap_clearbit(bitmap->bitmap, addr);
+}
+
+inline
+bool bitmap_checking_testbit(bitmap_t* bitmap,
+                                                        void*    addr)
+{
+       bitmap_boundscheck(bitmap, addr);
+       return bitmap_testbit(bitmap->bitmap, addr);
+}
+
+inline 
+void bitmap_clear(bitmap_t* bitmap)    
+{
+       memset(bitmap->bitmap_memory, 0, bitmap->bytesize);
+}
+
+inline 
+bitmap_t* bitmap_allocate(void*        zero_addr, 
+                                                 OFFSET_T      size)
+{
+       bitmap_t*  bitmap;
+
+       unsigned long bytesize = CALC_BITMAP_SIZE(size);                                         /* align */
+       bitmap = (bitmap_t*)malloc(sizeof(bitmap_t));
+
+       CHECK_ADDR_ALIGNMENT(zero_addr);                        /* ensure correct alignment for zero_addr */
+
+       bitmap->bytesize = bytesize;
+       bitmap->bitmap_memory = malloc(bytesize);
+       bitmap->bitmap = bitmap->bitmap_memory - CALC_ZERO_OFFSET(zero_addr);   /* offset for fast access */
+
+       bitmap->bitmap_beyond_addr = zero_addr + size;
+       bitmap->bitmap_top_block = ADDR_TO_BLOCK(bitmap->bitmap_beyond_addr - sizeof(BITBLOCK));
+
+       if (!bitmap->bitmap_memory) {
+               /* handle error -- unable to allocate enough memory */
+               fprintf(stderr, "bitmap2.c: Failed to allocate memory for a bitmap.\n");
+               exit(-1);  /* FIXME: I should probably call some sort of cacao-wide "panic" function ?! -- phil. */
+       }
+
+       bitmap_clear(bitmap);
+       
+       return bitmap;
+}
+
+inline 
+void bitmap_release(bitmap_t* bitmap)
+{
+       if (bitmap) {
+               if (bitmap->bitmap_memory)
+                       free(bitmap->bitmap_memory);
+               free(bitmap);
+       }
+}
+
+static 
+inline 
+int offset_for_lowest(BITBLOCK i)
+{
+       /* Maintainer, don't despair! 
+        *
+        * The OFFSET_TO_ADDR adjusts an argument according to the size of heap-allocation blocks,
+        * so that the resulting value can be used as an offset to a pointer.
+        * I.e.: addr + OFFSET_TO_ADDR(i) is equivalent to addr + (sizeof(heap_block) * i)
+        *
+        * The definition of lowest just looks inefficient, everything should be expanded at
+        * compile-time, though. -- phil.
+        */
+
+       static signed char lowest[256] = { 
+               OFFSET_TO_ADDR(0),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(5),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(6),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(5),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(7),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(5),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(6),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(5),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0, 
+               OFFSET_TO_ADDR(4),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+               OFFSET_TO_ADDR(3),  0, OFFSET_TO_ADDR(1), 0, OFFSET_TO_ADDR(2), 0, OFFSET_TO_ADDR(1), 0,
+       };
+
+#if U8_AVAILABLE
+       if (i & 0xffffffffffULL)
+#endif
+               if (i & 0xffffUL)
+                       if (i & 0xffUL) 
+                               return OFFSET_TO_ADDR(0) + lowest[(unsigned char)i];
+                       else                     
+                               return OFFSET_TO_ADDR(8) + lowest[(unsigned char)(i>>8)];
+               else
+                       if (i & 0xff0000UL) 
+                               return OFFSET_TO_ADDR(16) + lowest[(unsigned char)(i>>16)];
+                       else                     
+                               return OFFSET_TO_ADDR(24) + lowest[(unsigned char)(i>>24)];
+#if U8_AVAILABLE
+       else
+               if (i & 0xffff00000000ULL)
+                       if (i & 0xff00000000ULL) 
+                               return OFFSET_TO_ADDR(32) + lowest[(unsigned char)(i>>32)];
+                       else                     
+                               return OFFSET_TO_ADDR(40) + lowest[(unsigned char)(i>>40)];
+               else
+                       if (i & 0xff000000000000ULL) 
+                               return OFFSET_TO_ADDR(48) + lowest[(unsigned char)(i>>48)];
+                       else                     
+                               return OFFSET_TO_ADDR(56) + lowest[(unsigned char)(i>>56)];
+#endif
+}
+
+inline
+void*
+bitmap_find_next_setbit(bitmap_t* bitmap, 
+                                               void*     addr)
+{
+       OFFSET_T  block = ADDR_TO_BLOCK(addr);
+       OFFSET_T  offset = ADDR_TO_OFFSET(addr);
+       BITBLOCK  pattern;
+
+       bitmap_boundscheck(bitmap, addr);
+
+       /* 1. check the current block, starting from the bit indicated by addr */
+       pattern = bitmap->bitmap[block] >> offset;
+       if (pattern)
+               return (void*)(addr + offset_for_lowest(pattern));
+
+       /* 2. iteratively check block by block until the end of the bitmap */
+       while (block < bitmap->bitmap_top_block) {
+               pattern = bitmap->bitmap[++block];
+
+               if (pattern)
+                       return (void*)(BLOCK_TO_ADDR(block) + offset_for_lowest(pattern));
+       }
+
+       /* 3. failed to find a set bit... */
+       return bitmap->bitmap_beyond_addr;
+}
+
+inline
+void*
+bitmap_find_next_combination_set_unset(bitmap_t* bitmap, 
+                                                                          bitmap_t* invertedmap, 
+                                                                          void*     addr)
+{
+       OFFSET_T  block = ADDR_TO_BLOCK(addr);
+       OFFSET_T  offset = ADDR_TO_OFFSET(addr);
+       BITBLOCK  pattern;
+
+       bitmap_boundscheck(bitmap, addr);
+
+       /* 1. check the current block, starting from the bit indicated by addr */
+       pattern = (bitmap->bitmap[block] & ~invertedmap->bitmap[block]) >> offset;
+       if (pattern)
+               return (void*)(addr + offset_for_lowest(pattern));
+
+       /* 2. iteratively check block by block until the end of the bitmap */
+       while (block < bitmap->bitmap_top_block) {
+               pattern = bitmap->bitmap[++block] & ~invertedmap->bitmap[block];
+
+               if (pattern)
+                       return (void*)(BLOCK_TO_ADDR(block) + offset_for_lowest(pattern));
+       }
+
+       /* 3. failed to find a combination... */
+       return bitmap->bitmap_beyond_addr;
+}
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/mm/bitmap2.h b/mm/bitmap2.h
new file mode 100644 (file)
index 0000000..35e4675
--- /dev/null
@@ -0,0 +1,55 @@
+/* 
+ * cacao/mm/bitmap.h
+ * $Id: bitmap2.h 34 1998-11-03 11:29:37Z phil $ 
+ */
+
+#ifndef __mm_bitmap_h_
+#define __mm_bitmap_h_
+
+#include "mm.h"
+
+#if U8_AVAILABLE
+#   define BITBLOCK            u8
+#      define OFFSET_T         u8
+#else
+#      define BITBLOCK         u4
+#      define OFFSET_T         u4
+#endif
+
+typedef struct {
+       BITBLOCK*           bitmap;                     /* accessor, usually copied */
+       unsigned long   bytesize;       /* used internally */
+       void*           bitmap_beyond_addr;
+       OFFSET_T                bitmap_top_block;
+       void*           bitmap_memory;  /* internal: the real address */
+} bitmap_t;
+
+inline void            bitmap_setbit(BITBLOCK* bitmap, void* addr);
+inline void            bitmap_clearbit(BITBLOCK* bitmap, void* addr);
+inline bool            bitmap_testbit(BITBLOCK* bitmap, void* addr);
+
+inline void            bitmap_checking_setbit(bitmap_t* bitmap, void* addr);
+inline void            bitmap_checking_clearbit(bitmap_t* bitmap, void* addr);
+inline bool            bitmap_checking_testbit(bitmap_t* bitmap, void* addr);
+
+inline void                    bitmap_clear(bitmap_t* bitmap);
+inline bitmap_t*       bitmap_allocate(void* zero_offset, OFFSET_T size);
+inline void            bitmap_release(bitmap_t* bitmap);
+
+inline void*           bitmap_find_next_setbit(bitmap_t* bitmap, void* addr);
+inline void*           bitmap_find_next_combination_set_unset(bitmap_t* bitmap, bitmap_t* invertedmap, void* addr);
+
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/mm/mm.h b/mm/mm.h
new file mode 100644 (file)
index 0000000..99c10cc
--- /dev/null
+++ b/mm/mm.h
@@ -0,0 +1,21 @@
+#ifndef __mm_h_
+#define __mm_h_
+
+#include "../sysdep/types.h"
+#include "../global.h"
+
+#endif
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */