diff --git a/src/Makefile.in b/src/Makefile.in
index d2f21c6f22cf21a6802ef6eed9c62280e553dc32..b3c26a3c34fa316381ab2234f668ba802eeb92b9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -164,6 +164,7 @@ CORE_OBJ= \
  pike_types.o \
  pike_embed.o \
  mapping.o \
+ block_allocator.o \
  pike_memory.o \
  module_support.o \
  pikecode.o \
@@ -1431,6 +1432,7 @@ HFILES=						\
   main.protos					\
   stralloc.protos					\
   mapping.protos					\
+  block_allocator.protos					\
   stuff.protos					\
   dynamic_buffer.protos				\
   svalue.protos					\
diff --git a/src/backend.cmod b/src/backend.cmod
index 126f3d0f74de43cb06c2a3ce1a779d2dcdc1c527..0e1a08461d69f7198ed9013d2b8b5b356fd0f7d7 100644
--- a/src/backend.cmod
+++ b/src/backend.cmod
@@ -37,6 +37,7 @@
 #include "svalue.h"
 #include "gc.h"
 #include "module_support.h"
+#include "block_allocator.h"
 
 /*
  * Things to do
@@ -132,8 +133,8 @@
 
 /* Declarations for the legacy backend interface stuff. */
 
-#include "block_alloc_h.h"
-BLOCK_ALLOC (compat_cb_box, N/A);
+static struct compat_cb_box * alloc_compat_cb_box();
+static void really_free_compat_cb_box(struct compat_cb_box * b);
 static int compat_box_dispatcher (struct fd_callback_box *box, int event);
 
 /* CALL OUT STUFF */
@@ -5116,18 +5117,29 @@ struct compat_cb_box
   int flags; /* fs event flags */
 };
 
-#include "block_alloc.h"
-
-#undef BLOCK_ALLOC_NEXT
-#define BLOCK_ALLOC_NEXT read_data
-
 #undef DMALLOC_DESCRIBE_BLOCK
 #define DMALLOC_DESCRIBE_BLOCK(X) do {					\
     fprintf (stderr, "  backend: %p, fd: %d, events: 0x%x\n",		\
 	     X->box.backend, X->box.fd, X->box.events);			\
   } while (0)
 
-BLOCK_ALLOC_FILL_PAGES (compat_cb_box, 1)
+static struct block_allocator compat_cb_allocator = BA_INIT_PAGES(sizeof(struct compat_cb_box), 1);
+
+static struct compat_cb_box * alloc_compat_cb_box() {
+    return ba_alloc(&compat_cb_allocator);
+}
+
+static void really_free_compat_cb_box(struct compat_cb_box * b) {
+    ba_free(&compat_cb_allocator, b);
+}
+
+void count_memory_in_compat_cb_boxs(size_t * n, size_t * s) {
+    ba_count_all(&compat_cb_allocator, n, s);
+}
+
+void free_all_compat_cb_box_blocks() {
+    ba_destroy(&compat_cb_allocator);
+}
 
 static int compat_box_dispatcher (struct fd_callback_box *box, int event)
 {
@@ -5404,7 +5416,6 @@ static struct callback *mem_callback;
 void init_backend(void)
 {
   IF_PD(fprintf(stderr, "BACKEND: Init compat callback boxes...\n"));
-  init_compat_cb_box_blocks();
   IF_PD(fprintf(stderr, "BACKEND: INIT...\n"));
   INIT;
   IF_PD(fprintf(stderr, "BACKEND: Creating default backend...\n"));
diff --git a/src/backend.h b/src/backend.h
index 0e442fd3ede54b4d8767712146c24f3bed2fbd8f..de8344247da8f55a014d7a9bf04d06c11edeaa1b 100644
--- a/src/backend.h
+++ b/src/backend.h
@@ -83,6 +83,7 @@ extern struct callback_list do_debug_callbacks;
 PMOD_EXPORT extern struct program *Backend_program;
 
 void count_memory_in_compat_cb_boxs(size_t *num, size_t *size);
+void free_all_compat_cb_box_blocks();
 
 PMOD_EXPORT void debug_check_fd_not_in_use (int fd);
 #if 1
diff --git a/src/post_modules/CritBit/bitvector.h b/src/bitvector.h
similarity index 99%
rename from src/post_modules/CritBit/bitvector.h
rename to src/bitvector.h
index 0f4bb7b24b97f79e38465385d4b75e619ceceac2..3e7de8c9f1f1a777396bd8bb223402c5a68d7c3e 100644
--- a/src/post_modules/CritBit/bitvector.h
+++ b/src/bitvector.h
@@ -1,7 +1,7 @@
 #ifndef BITVECTOR_H
 #define BITVECTOR_H
 
-#include "critbit_config.h"
+#include "machine.h"
 #define MOD_PRIME
 
 #include "pike_int_types.h"
diff --git a/src/block_alloc.h b/src/block_alloc.h
index 0351753ef7af92ab720b3c7aef97358c4d2aa7f4..3317f4150e5953f8c7d607103a2779e4e4229363 100644
--- a/src/block_alloc.h
+++ b/src/block_alloc.h
@@ -98,6 +98,21 @@
 			   DO_IF_DMALLOC( + sizeof(INT32)))
 #endif
 
+#define WALK_NONFREE_BLOCKS(DATA, BLOCK, FCOND, CODE)	do {		\
+    struct PIKE_CONCAT(DATA,_block) * p;				\
+    for(p=PIKE_CONCAT(DATA,_blocks);p;p=p->next) {			\
+	int n = p->used;						\
+	int i;								\
+	for (i = 0; n && i < (sizeof(p->x)/sizeof(struct DATA)); i++) {	\
+	    BLOCK = &p->x[i];						\
+	    if (FCOND) {						\
+		do CODE while(0);					\
+		--n;							\
+	    }								\
+	}								\
+    }									\
+} while(0)
+
 #define BLOCK_ALLOC(DATA,BSIZE)						\
 									\
 struct PIKE_CONCAT(DATA,_block)						\
@@ -513,19 +528,16 @@ static INLINE struct DATA *						     \
  PIKE_CONCAT3(really_low_find_,DATA,_unlocked)(void *ptr,		     \
 					       PIKE_HASH_T hval)	     \
 {									     \
-  struct DATA *p,**pp;							     \
+  struct DATA *p;							     \
   p=PIKE_CONCAT(DATA,_hash_table)[hval];                                     \
   if(!p || p->PTR_HASH_ALLOC_DATA == ptr)				     \
   {                                                                          \
     return p;                                                                \
   }                                                                          \
-  while((p=*(pp=&p->BLOCK_ALLOC_NEXT)))                                      \
+  while((p=p->BLOCK_ALLOC_NEXT))					     \
   {									     \
     if(p->PTR_HASH_ALLOC_DATA==ptr)					     \
     {									     \
-      *pp=p->BLOCK_ALLOC_NEXT;						     \
-      p->BLOCK_ALLOC_NEXT=PIKE_CONCAT(DATA,_hash_table)[hval];		     \
-      PIKE_CONCAT(DATA,_hash_table)[hval]=p;				     \
       return p;								     \
     }									     \
   }									     \
@@ -622,18 +634,22 @@ int PIKE_CONCAT3(check_,DATA,_semaphore)(void *ptr)			     \
 									     \
 void PIKE_CONCAT(move_,DATA)(struct DATA *block, void *new_ptr)		     \
 {									     \
+  struct DATA **pp, *p;							     \
   PIKE_HASH_T hval =							     \
     (PIKE_HASH_T)PTR_TO_INT(block->PTR_HASH_ALLOC_DATA);		     \
   DO_IF_RUN_UNLOCKED(mt_lock(&PIKE_CONCAT(DATA,_mutex)));		     \
   hval %= (PIKE_HASH_T)PIKE_CONCAT(DATA,_hash_table_size);		     \
-  if (!PIKE_CONCAT3(really_low_find_,DATA,_unlocked)(			     \
-	block->PTR_HASH_ALLOC_DATA, hval))				     \
-    Pike_fatal("The block to move wasn't found.\n");			     \
-  DO_IF_DEBUG(								     \
-    if (PIKE_CONCAT(DATA,_hash_table)[hval] != block)			     \
-      Pike_fatal("Expected the block to be at the top of the hash chain.\n"); \
-  );									     \
-  PIKE_CONCAT(DATA,_hash_table)[hval] = block->BLOCK_ALLOC_NEXT;	     \
+  pp=PIKE_CONCAT(DATA,_hash_table) + hval;                                   \
+  while((p = *pp))							     \
+  {									     \
+    if(p == block)							     \
+    {									     \
+      *pp = p->BLOCK_ALLOC_NEXT;					     \
+      break;								     \
+    }									     \
+    pp = &p->BLOCK_ALLOC_NEXT;						     \
+  }									     \
+  if (!p) Pike_fatal("The block to move wasn't found.\n");		     \
   block->PTR_HASH_ALLOC_DATA = new_ptr;					     \
   hval = (PIKE_HASH_T)PTR_TO_INT(new_ptr) %				     \
     (PIKE_HASH_T)PIKE_CONCAT(DATA,_hash_table_size);			     \
@@ -644,7 +660,7 @@ void PIKE_CONCAT(move_,DATA)(struct DATA *block, void *new_ptr)		     \
 									     \
 int PIKE_CONCAT(remove_,DATA)(void *ptr)				     \
 {									     \
-  struct DATA *p;							     \
+  struct DATA **pp, *p;							     \
   PIKE_HASH_T hval = (PIKE_HASH_T)PTR_TO_INT(ptr);			     \
   DO_IF_RUN_UNLOCKED(mt_lock(&PIKE_CONCAT(DATA,_mutex)));                    \
   if(!PIKE_CONCAT(DATA,_hash_table))                                         \
@@ -653,15 +669,18 @@ int PIKE_CONCAT(remove_,DATA)(void *ptr)				     \
     return 0;				                                     \
   }                                                                          \
   hval %= (PIKE_HASH_T)PIKE_CONCAT(DATA,_hash_table_size);		     \
-  if((p=PIKE_CONCAT3(really_low_find_,DATA,_unlocked)(ptr, hval)))	     \
+  pp=PIKE_CONCAT(DATA,_hash_table) + hval;                                   \
+  while((p = *pp))							     \
   {									     \
-    PIKE_CONCAT(num_,DATA)--;						     \
-    DO_IF_DEBUG( if(PIKE_CONCAT(DATA,_hash_table)[hval]!=p)                  \
-                    Pike_fatal("GAOssdf\n"); );                       	     \
-    PIKE_CONCAT(DATA,_hash_table)[hval]=p->BLOCK_ALLOC_NEXT;		     \
-    BA_UL(PIKE_CONCAT(really_free_,DATA))(p);				     \
-    DO_IF_RUN_UNLOCKED(mt_unlock(&PIKE_CONCAT(DATA,_mutex)));                \
-    return 1;								     \
+    if(p->PTR_HASH_ALLOC_DATA==ptr)					     \
+    {									     \
+      *pp = p->BLOCK_ALLOC_NEXT;					     \
+      PIKE_CONCAT(num_,DATA)--;						     \
+      BA_UL(PIKE_CONCAT(really_free_,DATA))(p);				     \
+      DO_IF_RUN_UNLOCKED(mt_unlock(&PIKE_CONCAT(DATA,_mutex)));              \
+      return 1;								     \
+    }									     \
+    pp = &p->BLOCK_ALLOC_NEXT;						     \
   }									     \
   DO_IF_RUN_UNLOCKED(mt_unlock(&PIKE_CONCAT(DATA,_mutex)));                  \
   return 0;								     \
diff --git a/src/block_allocator.c b/src/block_allocator.c
new file mode 100644
index 0000000000000000000000000000000000000000..44e3fd90e3748126a5af83297390d01001f07ad6
--- /dev/null
+++ b/src/block_allocator.c
@@ -0,0 +1,200 @@
+#include "global.h"
+#include "pike_error.h"
+#include "pike_memory.h"
+
+#include "block_allocator.h"
+#include "bitvector.h"
+
+#define BA_BLOCKN(l, p, n) ((struct ba_block_header *)(((char*)((p)+1)) + (n)*((l).block_size)))
+#define BA_LASTBLOCK(l, p) ((struct ba_block_header*)((char*)((p)+1) + (l).offset))
+#define BA_CHECK_PTR(l, p, ptr)	((size_t)((char*)(ptr) - (char*)((p)+1)) <= (l).offset)
+
+#define BA_ONE	((struct ba_block_header *)1)
+
+static INLINE void ba_dec_layout(struct ba_layout * l, int i) {
+    l->blocks >>= i;
+    l->offset += l->block_size;
+    l->offset >>= i;
+    l->offset -= l->block_size;
+}
+
+static INLINE void ba_inc_layout(struct ba_layout * l, int i) {
+    l->blocks <<= i;
+    l->offset += l->block_size;
+    l->offset <<= i;
+    l->offset -= l->block_size;
+}
+
+static INLINE void ba_double_layout(struct ba_layout * l) {
+    ba_inc_layout(l, 1);
+}
+
+static INLINE void ba_half_layout(struct ba_layout * l) {
+    ba_dec_layout(l, 1);
+}
+
+static INLINE struct ba_layout ba_get_layout(const struct block_allocator * a, int i) {
+    struct ba_layout l = a->l;
+    ba_inc_layout(&l, i);
+    return l;
+}
+
+struct ba_block_header {
+    struct ba_block_header * next;
+};
+
+static struct ba_page * ba_alloc_page(struct block_allocator * a, int i) {
+    struct ba_layout l = ba_get_layout(a, i);
+    size_t n = l.offset + l.block_size + sizeof(struct ba_page);
+    struct ba_page * p = (struct ba_page*)xalloc(n);
+    p->h.first = BA_BLOCKN(a->l, p, 0);
+    p->h.first->next = BA_ONE;
+    p->h.used = 0;
+    return p;
+}
+
+PMOD_EXPORT void ba_init(struct block_allocator * a, unsigned INT32 block_size, unsigned INT32 blocks) {
+    block_size = MAXIMUM(block_size, sizeof(struct ba_block_header));
+    blocks = round_up32(blocks);
+    a->alloc = a->last_free = 0;
+    a->size = 1;
+    a->l.block_size = block_size;
+    a->l.blocks = blocks;
+    a->l.offset = block_size * (blocks-1);
+    memset(a->pages, 0, sizeof(a->pages));
+    a->pages[0] = ba_alloc_page(a, 0);
+}
+
+PMOD_EXPORT void ba_destroy(struct block_allocator * a) {
+    int i;
+    for (i = 0; i < a->size; i++) {
+	if (a->pages[i]) {
+	    free(a->pages[i]);
+	    a->pages[i] = NULL;
+	}
+    }
+    a->size = 0;
+    a->alloc = 0;
+    a->last_free = 0;
+}
+
+PMOD_EXPORT size_t ba_count(const struct block_allocator * a) {
+    size_t c = 0;
+    unsigned int i;
+    for (i = 0; i < a->size; i++) {
+	c += a->pages[i]->h.used;
+    }
+
+    return c;
+}
+
+PMOD_EXPORT void ba_count_all(const struct block_allocator * a, size_t * num, size_t * size) {
+    size_t n = (a->l.blocks << (a->size-1)) - a->l.blocks;
+    *num = n;
+    *size = a->l.block_size * n;
+}
+
+static void ba_low_alloc(struct block_allocator * a) {
+    if (a->l.offset) {
+	unsigned int i;
+
+	for (i = 1; i <= a->size; i++) {
+	    struct ba_page * p = a->pages[a->size - i];
+
+	    if (p->h.first) {
+		a->alloc = a->size - i;
+		return;
+	    }
+	}
+	if (a->size == (sizeof(a->pages)/sizeof(a->pages[0]))) {
+	    Pike_error("Out of memory.");
+	}
+	a->pages[a->size] = ba_alloc_page(a, a->size);
+	a->alloc = a->size;
+	a->size++;
+    } else {
+	ba_init(a, a->l.block_size, a->l.blocks);
+    }
+}
+
+ATTRIBUTE((malloc))
+PMOD_EXPORT void * ba_alloc(struct block_allocator * a) {
+    struct ba_page * p = a->pages[a->alloc];
+    struct ba_block_header * ptr;
+
+    if (!p || !p->h.first) {
+	ba_low_alloc(a);
+	p = a->pages[a->alloc];
+    }
+
+    ptr = p->h.first;
+
+    p->h.used++;
+
+    if (ptr->next == BA_ONE) {
+	struct ba_layout l = ba_get_layout(a, a->alloc);
+	p->h.first = (struct ba_block_header*)((char*)ptr + a->l.block_size);
+	p->h.first->next = (struct ba_block_header*)(ptrdiff_t)!(p->h.first == BA_LASTBLOCK(l, p));
+    } else {
+	p->h.first = ptr->next;
+    }
+
+    return ptr;
+}
+
+PMOD_EXPORT void ba_free(struct block_allocator * a, void * ptr) {
+    int i = a->last_free;
+    struct ba_page * p = a->pages[i];
+    struct ba_layout l = ba_get_layout(a, i);
+
+    if (BA_CHECK_PTR(l, p, ptr)) goto found;
+
+    p = NULL;
+
+    for (i = a->size-1, l = ba_get_layout(a, i); i >= 0; i--, ba_half_layout(&l)) {
+	if (BA_CHECK_PTR(l, a->pages[i], ptr)) {
+	    a->last_free = i;
+	    p = a->pages[i];
+	    break;
+	}
+    }
+found:
+
+#ifdef PIKE_DEBUG
+    if (p) {
+#endif
+    {
+	struct ba_block_header * b = (struct ba_block_header*)ptr;
+	b->next = p->h.first;
+	p->h.first = b;
+#ifdef PIKE_DEBUG
+	if (!p->h.used) {
+	    fprintf(stderr, "freeing from empty page %p\n", p);
+	    goto ERR;
+	}
+#endif
+	if (!(--p->h.used) && i+1 == a->size) {
+	    while (i >= 0 && !(p->h.used)) {
+		free(p);
+		a->pages[i] = NULL;
+
+		p = a->pages[--i];
+	    }
+	    a->size = i+1;
+	    a->alloc = a->last_free = MAXIMUM(0, i);
+	}
+    }
+#ifdef PIKE_DEBUG
+    } else {
+	int i;
+ERR:
+	for (i = a->size-1, l = ba_get_layout(a, i); i >= 0; ba_half_layout(&l), i--) {
+	    p = a->pages[i];
+	    fprintf(stderr, "page: %p used: %u/%u last: %p p+offset: %p\n", a->pages[i],
+		    p->h.used, l.blocks,
+		    BA_BLOCKN(l, p, l.blocks-1), BA_LASTBLOCK(l, p));
+	}
+	Pike_fatal("ptr %p not in any page.\n", ptr);
+    }
+#endif
+}
diff --git a/src/block_allocator.h b/src/block_allocator.h
new file mode 100644
index 0000000000000000000000000000000000000000..9c0d27d3b8e286d28e53ddc1f6ff3c226035f661
--- /dev/null
+++ b/src/block_allocator.h
@@ -0,0 +1,60 @@
+#ifndef BLOCK_ALLOCATOR_H
+#define BLOCK_ALLOCATOR_H
+
+#include "global.h"
+#include "pike_error.h"
+#include "pike_memory.h"
+#include "pike_int_types.h"
+
+struct ba_layout {
+    unsigned INT32 offset;
+    unsigned INT32 block_size;
+    unsigned INT32 blocks;
+};
+
+#define BA_LAYOUT_INIT(block_size, blocks)  { 0, (block_size), (blocks) }
+
+struct ba_page_header {
+    struct ba_block_header * first;
+    unsigned INT32 used;
+};
+
+struct ba_page {
+    struct ba_page_header h;
+};
+
+struct block_allocator {
+    struct ba_layout l;
+    unsigned char size;
+    unsigned char last_free;
+    unsigned char alloc;
+    unsigned char __align;
+    /*
+     * This places an upper limit on the number of blocks
+     * and should be adjusted as needed.
+     *
+     * the formula is as follows:
+     *	(initial_size << 24) - initial_size
+     * for example for short pike strings this means that at most
+     * 192 GB of short pike strings with shift width 0 can be allocated.
+     */
+    struct ba_page * pages[24];
+};
+
+#define BA_INIT(block_size, blocks) {		\
+    BA_LAYOUT_INIT(block_size, blocks),		\
+    0, 0, 0, 0,					\
+    { NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,  \
+      NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,  \
+      NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL } \
+}
+
+#define BA_INIT_PAGES(block_size, pages)	BA_INIT(block_size, ((pages) * PIKE_MALLOC_PAGE_SIZE)/(block_size))
+
+PMOD_EXPORT void ba_init(struct block_allocator * a, unsigned INT32 block_size, unsigned INT32 blocks);
+ATTRIBUTE((malloc)) PMOD_EXPORT void * ba_alloc(struct block_allocator * a);
+PMOD_EXPORT void ba_free(struct block_allocator * a, void * ptr);
+PMOD_EXPORT void ba_destroy(struct block_allocator * a);
+PMOD_EXPORT size_t ba_count(const struct block_allocator * a);
+PMOD_EXPORT void ba_count_all(const struct block_allocator * a, size_t * num, size_t * size);
+#endif
diff --git a/src/builtin.cmod b/src/builtin.cmod
index 841e63f813d521f6257dcb97eb5c786852a96d97..a159721b6b7d207d09d1a161cc967cb50ce390de 100644
--- a/src/builtin.cmod
+++ b/src/builtin.cmod
@@ -28,7 +28,7 @@
 #include "fsort.h"
 #include "port.h"
 #include "gc.h"
-#include "block_alloc.h"
+#include "block_allocator.h"
 #include "pikecode.h"
 #include "opcodes.h"
 
@@ -4142,31 +4142,36 @@ PIKEFUN array __automap__(mixed fun, mixed ... tmpargs)
 
 /* Linked list stuff.
  */
-#undef INIT_BLOCK
-#define INIT_BLOCK(NODE) do {				\
-    (NODE)->next = (NODE)->prev = NULL;			\
-    (NODE)->refs = 1;					\
-    SET_SVAL((NODE)->val, T_INT, NUMBER_UNDEFINED,	\
-	     integer, 0);				\
-  } while(0) 
-
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(NODE) do {				\
-    if ((NODE)->prev) {					\
-      free_list_node((NODE)->prev);			\
-    }							\
-    if ((NODE)->next) {					\
-      free_list_node((NODE)->next);			\
-    }							\
-    free_svalue(&(NODE)->val);				\
-  } while(0)
-
-BLOCK_ALLOC_FILL_PAGES(pike_list_node, 4);
+static struct block_allocator pike_list_node_allocator = BA_INIT_PAGES(sizeof(struct pike_list_node), 4);
+
+ATTRIBUTE((malloc))
+static struct pike_list_node * alloc_pike_list_node() {
+    struct pike_list_node * node = ba_alloc(&pike_list_node_allocator);
+    node->next = node->prev = NULL;
+    node->refs = 1;
+    SET_SVAL(node->val, T_INT, NUMBER_UNDEFINED, integer, 0);
+    return node;
+}
+
+void count_memory_in_pike_list_nodes(size_t * n, size_t * s) {
+    ba_count_all(&pike_list_node_allocator, n, s);
+}
+
+void free_all_pike_list_node_blocks() {
+    ba_destroy(&pike_list_node_allocator);
+}
 
 PMOD_EXPORT void free_list_node(struct pike_list_node *node)
 {
   if (!sub_ref(node)) {
-    really_free_pike_list_node(node);
+    if (node->prev) {
+      free_list_node(node->prev);
+    }
+    if (node->next) {
+      free_list_node(node->next);
+    }
+    free_svalue(&node->val);
+    ba_free(&pike_list_node_allocator, node);
   }
 }
 
@@ -5760,7 +5765,6 @@ PIKECLASS __Backtrace_Tester__
 
 void init_builtin(void)
 {
-  init_pike_list_node_blocks();
   INIT
 }
 
@@ -5773,7 +5777,7 @@ void exit_builtin(void)
    * in this case, so that the pike_list_node's are valid at cleanup
    * time, thus avoiding "got invalid pointer" fatals at exit.
    */
-  free_all_pike_list_node_blocks();
+  ba_destroy(&pike_list_node_allocator);
 #endif
 #ifndef USE_SETENV
   if (env_allocs) free_mapping (env_allocs);
diff --git a/src/builtin_functions.h b/src/builtin_functions.h
index be92d4a2e04542163744ce68c4067360b7c6b6e3..c8658d253fd5c3f32c8d4be24eb29dbceab9754f 100644
--- a/src/builtin_functions.h
+++ b/src/builtin_functions.h
@@ -10,7 +10,6 @@
 #define TYPEP(ID,NAME,TYPE) PMOD_EXPORT void ID(INT32 args);
 
 #include "callback.h"
-#include "block_alloc_h.h"
 
 /* Weak flags for arrays, multisets and mappings. 1 is avoided for
  * compatibility reasons. */
@@ -207,7 +206,8 @@ struct pike_list_node
   struct pike_list_node *prev;
   struct svalue val;
 };
-BLOCK_ALLOC_FILL_PAGES(pike_list_node, 4);
+void count_memory_in_pike_list_nodes(size_t * n, size_t * s);
+void free_all_pike_list_node_blocks();
 PMOD_EXPORT void free_list_node(struct pike_list_node *node);
 PMOD_EXPORT void unlink_list_node(struct pike_list_node *n);
 PMOD_EXPORT void prepend_list_node(struct pike_list_node *node,
diff --git a/src/callback.c b/src/callback.c
index 7f4f720cc5f93c17b0ece4033fdcfc6ab88601ba..de977cd69a01d11427568b110ed23e33436ea3a4 100644
--- a/src/callback.c
+++ b/src/callback.c
@@ -35,7 +35,14 @@ struct callback
 #define PRE_INIT_BLOCK(X) X->free_func=(callback_func)remove_callback;
 #endif
 #endif
-BLOCK_ALLOC(callback, CALLBACK_CHUNK)
+
+#include "block_allocator.h"
+static struct block_allocator callback_allocator
+    = BA_INIT(sizeof(struct callback), CALLBACK_CHUNK);
+
+void count_memory_in_callbacks(size_t * num, size_t * size) {
+    ba_count_all(&callback_allocator, num, size);
+}
 
 
 #ifdef PIKE_DEBUG
@@ -53,7 +60,7 @@ static int is_in_free_list(struct callback * c)
     if ((bar->x <= c) && ((c - bar->x) < CALLBACK_CHUNK)) {
       struct callback *foo;
       for (foo = bar->free_callbacks; foo;
-	   foo = (void *)foo->BLOCK_ALLOC_NEXT) {
+	   foo = (void *)foo->next) {
 	if (foo == c) return 1;
       }
       return 0;
@@ -191,7 +198,7 @@ PMOD_EXPORT void low_call_callback(struct callback_list *lst, void *arg)
       l->free_func=(callback_func)remove_callback;
 #endif
 #endif
-      really_free_callback(l);
+      ba_free(&callback_allocator, l);
     }else{
       ptr=& l->next;
     }
@@ -206,7 +213,7 @@ PMOD_EXPORT struct callback *debug_add_to_callback(struct callback_list *lst,
 				       callback_func free_func)
 {
   struct callback *l;
-  l=alloc_callback();
+  l=(struct callback*)ba_alloc(&callback_allocator);
   l->call=call;
   l->arg=arg;
   l->free_func=free_func;
@@ -246,11 +253,11 @@ void free_callback_list(struct callback_list *lst)
     if(l->free_func)
       l->free_func(l, l->arg, 0);
     *ptr=l->next;
-    really_free_callback(l);
+    ba_free(&callback_allocator, l);
   }
 }
 
 void cleanup_callbacks(void)
 {
-  free_all_callback_blocks();
+  ba_destroy(&callback_allocator);
 }
diff --git a/src/callback.h b/src/callback.h
index a04f1b2e8a6ef9356460d0b53bd85eae61f824cd..34138348a358df199fd68177084a09b6132ad512 100644
--- a/src/callback.h
+++ b/src/callback.h
@@ -21,10 +21,7 @@ extern struct callback_list fork_child_callback;
 
 typedef void (*callback_func)(struct callback *, void *,void *);
 
-#include "block_alloc_h.h"
 /* Prototypes begin here */
-struct callback;
-BLOCK_ALLOC(callback, CALLBACK_CHUNK);
 PMOD_EXPORT void low_call_callback(struct callback_list *lst, void *arg);
 PMOD_EXPORT struct callback *debug_add_to_callback(struct callback_list *lst,
 						   callback_func call,
diff --git a/src/configure.in b/src/configure.in
index 24e2e689c35814984754e2176b9b7e483a1257d6..0f6c4e6aad5f35cc0dde6b6a2b62dffe8ff97560 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -2474,6 +2474,67 @@ if test "x$pike_cv_sys_have_crc_intrinsics" = "xyes" ; then
   AC_DEFINE(HAVE_CRC32_INTRINSICS,[], [True if crc32 intrinsics are available])
 fi
 
+# test for several buildins
+
+define(TEST_BUILTIN, [
+    AC_MSG_CHECKING(for $1)
+    AC_TRY_RUN([
+$3
+unsigned long lint;
+int main(int argc, char **argv) {
+	static volatile int foo = 0;
+	foo = (int)$1($2);
+	return 0;
+}
+	],
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(translit([HAS_$1], [a-z], [A-Z]), 1, [Whether $1 is available])
+    ,
+    AC_MSG_RESULT(no)
+    )
+])
+
+# GCC builtins
+TEST_BUILTIN(__builtin_clz, 23)
+TEST_BUILTIN(__builtin_clzl, 23)
+TEST_BUILTIN(__builtin_clzll, 23)
+TEST_BUILTIN(__builtin_ctz, 23)
+TEST_BUILTIN(__builtin_ctzl, 23)
+TEST_BUILTIN(__builtin_ctzll, 23)
+TEST_BUILTIN(__builtin_bswap32, 23)
+TEST_BUILTIN(__builtin_bswap64, 23)
+TEST_BUILTIN(__builtin_expect, [argc,0])
+# ICC builtins
+TEST_BUILTIN(_bswap, 23)
+TEST_BUILTIN(_bswap64, 23)
+TEST_BUILTIN(_bit_scan_reverse, 23)
+TEST_BUILTIN(_bit_scan_forward, 23)
+# Visual Studio builtins
+TEST_BUILTIN(_BitScanForward, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_BitScanForward64, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_BitScanReverse, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_BitScanReverse64, [&lint, 23], [
+    #include <intrin.h>
+])
+TEST_BUILTIN(_byteswap_ulong, 23, [
+    #include <stdlib.h>
+])
+TEST_BUILTIN(_byteswap_uint64, 23, [
+    #include <stdlib.h>
+])
+# IBM C builtins
+TEST_BUILTIN(__cntlz4, 23)
+TEST_BUILTIN(__cntlz8, 23)
+TEST_BUILTIN(__cnttz4, 23)
+TEST_BUILTIN(__cnttz8, 23)
+
+
 #############################################################################
 
 # Script to translate from POSIX paths to native paths.
diff --git a/src/constants.c b/src/constants.c
index a7663026176b9f0934e02ff0d3816fc4a3f22460..7d89182fc9c15647a7dd78325ecaf50d7a4f1d4c 100644
--- a/src/constants.c
+++ b/src/constants.c
@@ -68,11 +68,6 @@ PMOD_EXPORT void add_global_program(const char *name, struct program *p)
   low_add_constant(name, p?&s:NULL);
 }
 
-#undef INIT_BLOCK
-#define INIT_BLOCK(X) do {						\
-    DO_IF_DEBUG (DOUBLELINK (first_callable, X));			\
-  } while (0)
-
 #undef EXIT_BLOCK
 #define EXIT_BLOCK(X) do {		\
   DO_IF_DEBUG (DOUBLEUNLINK (first_callable, X)); \
@@ -82,7 +77,20 @@ PMOD_EXPORT void add_global_program(const char *name, struct program *p)
   EXIT_PIKE_MEMOBJ(X);                  \
 }while(0)
 
-BLOCK_ALLOC_FILL_PAGES(callable,2)
+#include "block_allocator.h"
+static struct block_allocator callable_allocator
+    = BA_INIT_PAGES(sizeof(struct callable), 2);
+
+void really_free_callable(struct callable * c) {
+    EXIT_BLOCK(c);
+    ba_free(&callable_allocator, c);
+}
+void count_memory_in_callables(size_t * num, size_t * size) {
+    ba_count_all(&callable_allocator, num, size);
+}
+void free_all_callable_blocks() {
+    ba_destroy(&callable_allocator);
+}
 
 int global_callable_flags=0;
 
@@ -94,7 +102,10 @@ PMOD_EXPORT struct callable *low_make_callable(c_fun fun,
 					       optimize_fun optimize,
 					       docode_fun docode)
 {
-  struct callable *f=alloc_callable();
+  struct callable *f=(struct callable*)ba_alloc(&callable_allocator);
+#ifdef PIKE_DEBUG
+  DOUBLELINK(first_callable, f);
+#endif
   INIT_PIKE_MEMOBJ(f, T_STRUCT_CALLABLE);
   f->function=fun;
   f->name=name;
@@ -213,17 +224,9 @@ PMOD_EXPORT void visit_callable (struct callable *c, int action)
 #ifdef PIKE_DEBUG
 void present_constant_profiling(void)
 {
-  struct callable_block *b;
-  size_t e;
-  for(b=callable_blocks;b;b=b->next)
-  {
-    for(e=0;e<NELEM(b->x);e++)
-    {
-      if(b->x[e].name)
-      {
-	fprintf(stderr,"%010ld @E@: %s\n",b->x[e].runs, b->x[e].name->str);
-      }
-    }
+  struct callable *c;
+  for (c = first_callable; c; c = c->next) {
+    fprintf(stderr,"%010ld @E@: %s\n",c->runs, c->name->str);
   }
 }
 #endif
diff --git a/src/constants.h b/src/constants.h
index 6c894b1a694371059e46199a02a9c9d3ec471d49..d9ffdcdbad41cf7c39ba8d8dc3c0f1a4bed7b63c 100644
--- a/src/constants.h
+++ b/src/constants.h
@@ -48,7 +48,9 @@ void low_add_efun(struct pike_string *name, struct svalue *fun);
 void low_add_constant(const char *name, struct svalue *fun);
 void add_pike_string_constant(const char *name, const char *str, int len);
 PMOD_EXPORT void add_global_program(const char *name, struct program *p);
-BLOCK_ALLOC_FILL_PAGES(callable,2);
+void really_free_callable(struct callable * c);
+void count_memory_in_callables(size_t * num, size_t * size);
+void free_all_callable_blocks();
 PMOD_EXPORT struct callable *low_make_callable(c_fun fun,
 				   struct pike_string *name,
 				   struct pike_type *type,
diff --git a/src/gc.c b/src/gc.c
index d8cc7c206749d73a4def428bb36440cf2a85268d..c2d1459eee0d7010b5b049cff3402454a11b6e2a 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -27,6 +27,7 @@ struct callback *gc_evaluator_callback=0;
 #include "pike_threadlib.h"
 #include "gc.h"
 #include "main.h"
+#include "block_allocator.h"
 
 #include <math.h>
 
@@ -420,25 +421,25 @@ static unsigned rec_frames, link_frames, free_extra_frames;
 static unsigned max_rec_frames, max_link_frames;
 static unsigned tot_max_rec_frames = 0, tot_max_link_frames = 0, tot_max_free_extra_frames = 0;
 
-#undef INIT_BLOCK
-#define INIT_BLOCK(f) do {						\
-    if (++rec_frames > max_rec_frames)					\
-      max_rec_frames = rec_frames;					\
-  } while (0)
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(f) do {						\
-    DO_IF_DEBUG ({							\
-	if (f->rf_flags & GC_FRAME_FREED)				\
-	  gc_fatal (f->data, 0, "Freeing gc_rec_frame twice.\n");	\
-	f->rf_flags |= GC_FRAME_FREED;					\
-	f->u.link_top = (struct link_frame *) (ptrdiff_t) -1;		\
-	f->prev = f->next = f->cycle_id = f->cycle_piece =		\
-	  (struct gc_rec_frame *) (ptrdiff_t) -1;			\
-      });								\
-    rec_frames--;							\
-  } while (0)
+struct block_allocator gc_rec_frame_allocator =
+    BA_INIT_PAGES(sizeof(struct gc_rec_frame), 2);
 
-BLOCK_ALLOC_FILL_PAGES (gc_rec_frame, 2)
+static void really_free_gc_rec_frame(struct gc_rec_frame * f) {
+#ifdef PIKE_DEBUG
+  if (f->rf_flags & GC_FRAME_FREED)
+    gc_fatal (f->data, 0, "Freeing gc_rec_frame twice.\n");
+  f->rf_flags |= GC_FRAME_FREED;
+  f->u.link_top = (struct link_frame *) (ptrdiff_t) -1;
+  f->prev = f->next = f->cycle_id = f->cycle_piece =
+    (struct gc_rec_frame *) (ptrdiff_t) -1;
+#endif
+  rec_frames--;
+  ba_free(&gc_rec_frame_allocator, f);
+}
+
+void count_memory_in_gc_rec_frames(size_t *num, size_t * size) {
+  ba_count_all(&gc_rec_frame_allocator, num, size);
+}
 
 /* Link and free_extra frames are approximately the same size, so let
  * them share block_alloc area. */
@@ -451,18 +452,16 @@ struct ba_mixed_frame
   } u;
 };
 
-#undef BLOCK_ALLOC_NEXT
-#define BLOCK_ALLOC_NEXT u.next
-#undef INIT_BLOCK
-#define INIT_BLOCK(f)
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(f)
+static struct block_allocator ba_mixed_frame_allocator
+    = BA_INIT_PAGES(sizeof(struct ba_mixed_frame), 2);
 
-BLOCK_ALLOC_FILL_PAGES (ba_mixed_frame, 2)
+void count_memory_in_ba_mixed_frames(size_t *num, size_t * size) {
+  ba_count_all(&ba_mixed_frame_allocator, num, size);
+}
 
 static INLINE struct link_frame *alloc_link_frame()
 {
-  struct ba_mixed_frame *f = alloc_ba_mixed_frame();
+  struct ba_mixed_frame *f = ba_alloc(&ba_mixed_frame_allocator);
   if (++link_frames > max_link_frames)
     max_link_frames = link_frames;
   return (struct link_frame *) f;
@@ -470,7 +469,7 @@ static INLINE struct link_frame *alloc_link_frame()
 
 static INLINE struct free_extra_frame *alloc_free_extra_frame()
 {
-  struct ba_mixed_frame *f = alloc_ba_mixed_frame();
+  struct ba_mixed_frame *f = ba_alloc(&ba_mixed_frame_allocator);
   free_extra_frames++;
   return (struct free_extra_frame *) f;
 }
@@ -478,13 +477,13 @@ static INLINE struct free_extra_frame *alloc_free_extra_frame()
 static INLINE void really_free_link_frame (struct link_frame *f)
 {
   link_frames--;
-  really_free_ba_mixed_frame ((struct ba_mixed_frame *) f);
+  ba_free(&ba_mixed_frame_allocator, f);
 }
 
 static INLINE void really_free_free_extra_frame (struct free_extra_frame *f)
 {
   free_extra_frames--;
-  really_free_ba_mixed_frame ((struct ba_mixed_frame *) f);
+  ba_free(&ba_mixed_frame_allocator, f);
 }
 
 /* These are only collected for the sake of gc_status. */
@@ -522,6 +521,8 @@ static void gc_cycle_pop();
   (X)->flags=(X)->refs=(X)->weak_refs=0;		\
   (X)->frame = 0;
 #endif
+#undef EXIT_BLOCK
+#define EXIT_BLOCK(f)
 
 #undef get_marker
 #define get_marker debug_get_marker
@@ -574,7 +575,7 @@ static void describe_rec_stack (struct gc_rec_frame *p1, const char *p1_name,
 				struct gc_rec_frame *p3, const char *p3_name)
 {
   struct gc_rec_frame *l, *cp;
-  size_t longest;
+  size_t longest = 0;
 
   if (p1) longest = strlen (p1_name);
   if (p2) {size_t l = strlen (p2_name); if (l > longest) longest = l;}
@@ -2039,8 +2040,8 @@ void exit_gc(void)
   if (!gc_keep_markers)
     cleanup_markers();
 
-  free_all_gc_rec_frame_blocks();
-  free_all_ba_mixed_frame_blocks();
+  ba_destroy(&gc_rec_frame_allocator);
+  ba_destroy(&ba_mixed_frame_allocator);
 
 #ifdef PIKE_DEBUG
   if (gc_is_watching) {
@@ -2347,7 +2348,7 @@ static void check_rec_stack (struct gc_rec_frame *p1, const char *p1n,
   /* This debug check is disabled during the final cleanup since this
    * is O(n^2) on the stack size, and the stack gets a lot larger then. */
   if (gc_debug && !gc_destruct_everything) {
-    struct gc_rec_frame *l, *last_cycle_id;
+    struct gc_rec_frame *l, *last_cycle_id = NULL;
     for (l = &sentinel_frame; l != stack_top;) {
       l = l->next;
       check_rec_stack_frame (l, p1, p1n, p2, p2n, file, line);
@@ -2636,7 +2637,9 @@ PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int we
 
 static struct gc_rec_frame *gc_cycle_enqueue_rec (void *data)
 {
-  struct gc_rec_frame *r = alloc_gc_rec_frame();
+  struct gc_rec_frame *r =
+    (struct gc_rec_frame*)ba_alloc(&gc_rec_frame_allocator);
+  if (++rec_frames > max_rec_frames) max_rec_frames = rec_frames;
 #ifdef PIKE_DEBUG
   if (Pike_in_gc != GC_PASS_CYCLE)
     gc_fatal(data, 0, "Use of the gc frame stack outside the cycle check pass.\n");
diff --git a/src/las.c b/src/las.c
index be3d32e22f0bc30a9738faf962c2daf27dc47cbb..2d204d16d28eb10ad289f9dc2a481d9f99a36e3f 100644
--- a/src/las.c
+++ b/src/las.c
@@ -404,13 +404,11 @@ static int check_node_type(node *n, struct pike_type *t, const char *msg)
 
 #undef PRE_INIT_BLOCK
 #define PRE_INIT_BLOCK(NODE) do {					\
-    NODE->token = USHRT_MAX;						\
+    (NODE)->token = USHRT_MAX;						\
   } while (0)
 
 BLOCK_ALLOC_FILL_PAGES(node_s, 2)
 
-#define NODES (sizeof (((struct node_s_block *) NULL)->x) / sizeof (struct node_s))
-
 #undef BLOCK_ALLOC_NEXT
 #define BLOCK_ALLOC_NEXT next
 
@@ -419,32 +417,15 @@ void free_all_nodes(void)
   if(!Pike_compiler->previous)
   {
     node *tmp;
-    struct node_s_block *tmp2;
-    size_t e=0;
 
 #ifndef PIKE_DEBUG
-    if(cumulative_parse_error)
-    {
+    if(cumulative_parse_error) {
+#else
+      size_t e=0, s=0;
+      count_memory_in_node_ss(&e, &s);
+      if(e) {
 #endif
-      
-      for(tmp2=node_s_blocks;tmp2;tmp2=tmp2->next) e+=tmp2->used;
-      if(e)
-      {
-        size_t e2=e;
-	struct node_s_block *nextblk;
-	for(tmp2=node_s_blocks;tmp2;tmp2=nextblk)
-	{
-	  int n = tmp2->used;
-	  nextblk = tmp2->next;
-	  /* We want to be able to access the token field of all
-	   * the blocks...
-	   */
-	  PIKE_MEM_RW(tmp2->x);
-	  for(e=0;n && e<NODES;e++)
-	  {
-	    if (tmp2->x[e].token != USHRT_MAX)
-	    {
-	      tmp=tmp2->x+e;
+	WALK_NONFREE_BLOCKS(node_s, tmp, tmp->token != USHRT_MAX, {
 #ifdef PIKE_DEBUG
 	      if(!cumulative_parse_error)
 	      {
@@ -475,17 +456,13 @@ void free_all_nodes(void)
 		tmp->refs = 1;
 		debug_malloc_touch(tmp->type);
 		free_node(tmp);
-		--n;
 	      }
-	    }
-	  }
-	}
+	});
 #ifdef PIKE_DEBUG
 	if(!cumulative_parse_error)
-	  Pike_fatal("Failed to free %"PRINTSIZET"d nodes when compiling!\n",e2);
-#endif
+	  Pike_fatal("Failed to free %"PRINTSIZET"d nodes when compiling!\n",e);
       }
-#ifndef PIKE_DEBUG
+#else
     }
 #endif
     free_all_node_s_blocks();
diff --git a/src/mapping.c b/src/mapping.c
index 33cb343baaae89cd52222a72b5f6389cdc3df3e8..43afd10c8e47790b1ae734a427af5438bb61d9d8 100644
--- a/src/mapping.c
+++ b/src/mapping.c
@@ -20,7 +20,7 @@
 #include "gc.h"
 #include "stralloc.h"
 #include "pike_security.h"
-#include "block_alloc.h"
+#include "block_allocator.h"
 #include "opcodes.h"
 #include "stuff.h"
 
@@ -42,39 +42,41 @@ static struct mapping *gc_mark_mapping_pos = 0;
 #define MAPPING_DATA_SIZE(HSIZE, KEYPAIRS) \
    PTR_TO_INT(MD_KEYPAIRS(0, HSIZE) + KEYPAIRS)
 
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(m)	do{						\
-DO_IF_DEBUG(								\
-  if(m->refs) {								\
-    DO_IF_DMALLOC(describe_something(m, T_MAPPING, 0,2,0, NULL));	\
-    Pike_fatal("really free mapping on mapping with %d refs.\n", m->refs); \
-  }									\
-)									\
-									\
-  FREE_PROT(m);								\
-									\
-  unlink_mapping_data(m->data);						\
-									\
-  DOUBLEUNLINK(first_mapping, m);					\
-									\
-  GC_FREE(m);                                                           \
-}while(0)
-
+static struct block_allocator mapping_allocator = BA_INIT_PAGES(sizeof(struct mapping), 2);
+void count_memory_in_mappings(size_t * num, size_t * size) {
+    struct mapping *m;
+    double datasize = 0.0;
+    ba_count_all(&mapping_allocator, num, size);
+    for(m=first_mapping;m;m=m->next) {
+	datasize+=MAPPING_DATA_SIZE(m->data->hashsize, m->data->num_keypairs) / (double) m->data->refs;
+    }
+    *size += (size_t) datasize;
+}
 
-#undef COUNT_OTHER
+void really_free_mapping(struct mapping * m) {
+#ifdef PIKE_DEBUG
+  if (m->refs) {
+# ifdef DEBUG_MALLOC
+    describe_something(m, T_MAPPING, 0,2,0, NULL);
+# endif
+    Pike_fatal("really free mapping on mapping with %d refs.\n", m->refs);
+  }
+#endif
+  FREE_PROT(m);
+  unlink_mapping_data(m->data);
+  DOUBLEUNLINK(first_mapping, m);
+  GC_FREE(m);
+  ba_free(&mapping_allocator, m);
+}
 
-#define COUNT_OTHER() do{				\
-  struct mapping *m;					\
-  double datasize = 0.0;				\
-  for(m=first_mapping;m;m=m->next)			\
-  {							\
-    datasize+=MAPPING_DATA_SIZE(m->data->hashsize, m->data->num_keypairs) / \
-      (double) m->data->refs;						\
-  }							\
-  size += (size_t) datasize;				\
-}while(0)
+ATTRIBUTE((malloc))
+static struct mapping * alloc_mapping() {
+    return ba_alloc(&mapping_allocator);
+}
 
-BLOCK_ALLOC_FILL_PAGES(mapping, 2)
+void free_all_mapping_blocks() {
+    ba_destroy(&mapping_allocator);
+}
 
 #ifndef PIKE_MAPPING_KEYPAIR_LOOP
 #define IF_ELSE_KEYPAIR_LOOP(X, Y)	Y
diff --git a/src/mapping.h b/src/mapping.h
index 207e394c45979fc793cff6c24ebb26bf4452e138..c244a1a28f09e73f861eb8872f17804d31639d4a 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -9,7 +9,6 @@
 
 #include "svalue.h"
 #include "dmalloc.h"
-#include "block_alloc_h.h"
 
 /* Compatible with PIKE_WEAK_INDICES and PIKE_WEAK_VALUES. */
 #define MAPPING_WEAK_INDICES	2
@@ -133,8 +132,8 @@ PMOD_EXPORT void really_free_mapping(struct mapping *md);
 }while(0)
 
 /* Prototypes begin here */
-BLOCK_ALLOC_FILL_PAGES(mapping, 2);
-
+void really_free_mapping(struct mapping * m);
+void count_memory_in_mappings(size_t * num, size_t * size);
 
 
 
@@ -387,6 +386,8 @@ void simple_describe_mapping(struct mapping *m);
 void debug_dump_mapping(struct mapping *m);
 int mapping_is_constant(struct mapping *m,
 			struct processing *p);
+void free_all_mapping_blocks();
+
 /* Prototypes end here */
 
 #define allocate_mapping(X) dmalloc_touch(struct mapping *,debug_allocate_mapping(X))
diff --git a/src/modules/Parser/html.c b/src/modules/Parser/html.c
index b9499428111eb2ff90191568bc6c9c558790b08e..a0d2544649c25dc67ac031d716e08fc9427ea4cc 100644
--- a/src/modules/Parser/html.c
+++ b/src/modules/Parser/html.c
@@ -88,12 +88,21 @@ struct piece
    struct piece *next;
 };
 
-#undef INIT_BLOCK
-#define INIT_BLOCK(p) p->next = NULL;
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(p) free_string (p->s);
+#include "block_allocator.h"
 
-BLOCK_ALLOC_FILL_PAGES (piece, 2);
+static struct block_allocator piece_allocator
+    = BA_INIT_PAGES(sizeof(struct piece), 2);
+
+static INLINE struct piece * alloc_piece() {
+    struct piece * p = ba_alloc(&piece_allocator);
+    p->next = NULL;
+    return p;
+}
+
+static INLINE void really_free_piece(struct piece * p) {
+    free_string(p->s);
+    ba_free(&piece_allocator, p);
+}
 
 struct out_piece
 {
@@ -101,12 +110,18 @@ struct out_piece
    struct out_piece *next;
 };
 
-#undef INIT_BLOCK
-#define INIT_BLOCK(p) p->next = NULL
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(p) free_svalue (&p->v)
+static struct block_allocator out_piece_allocator
+    = BA_INIT_PAGES(sizeof(struct out_piece), 2);
 
-BLOCK_ALLOC_FILL_PAGES (out_piece, 2);
+static INLINE struct out_piece * alloc_out_piece() {
+    struct out_piece * p = ba_alloc(&out_piece_allocator);
+    p->next = NULL;
+    return p;
+}
+static INLINE void really_free_out_piece(struct out_piece * p) {
+    free_svalue(&p->v);
+    ba_free(&out_piece_allocator, p);
+}
 
 struct feed_stack
 {
@@ -128,20 +143,21 @@ struct feed_stack
    struct location pos;
 };
 
-#undef BLOCK_ALLOC_NEXT
-#define BLOCK_ALLOC_NEXT prev
-#undef INIT_BLOCK
-#define INIT_BLOCK(p) p->local_feed = NULL;
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(p)							\
-  while (p->local_feed)							\
-  {									\
-    struct piece *f=p->local_feed;					\
-    p->local_feed=f->next;						\
-    really_free_piece (f);						\
-  }
-
-BLOCK_ALLOC (feed_stack, 1);
+static struct block_allocator feed_stack_allocator
+    = BA_INIT_PAGES(sizeof(struct feed_stack), 1);
+static INLINE struct feed_stack * alloc_feed_stack() {
+    struct feed_stack * p = ba_alloc(&feed_stack_allocator);
+    p->local_feed = NULL;
+    return p;
+}
+static INLINE void really_free_feed_stack(struct feed_stack * p) {
+    while (p->local_feed) {
+	struct piece *f=p->local_feed;
+	p->local_feed=f->next;
+	really_free_piece (f);
+    }
+    ba_free(&feed_stack_allocator, p);
+}
 
 enum types {
   TYPE_TAG,			/* empty tag callback */
@@ -5310,9 +5326,6 @@ static void html_ignore_comments(INT32 args)
 void init_parser_html(void)
 {
    size_t offset;
-   init_piece_blocks();
-   init_out_piece_blocks();
-   init_feed_stack_blocks();
 
    offset = ADD_STORAGE(struct parser_html_storage);
 
@@ -5491,9 +5504,9 @@ void init_parser_html(void)
 
 void exit_parser_html()
 {
-   free_all_piece_blocks();
-   free_all_out_piece_blocks();
-   free_all_feed_stack_blocks();
+   ba_destroy(&piece_allocator);
+   ba_destroy(&out_piece_allocator);
+   ba_destroy(&feed_stack_allocator);
    exit_calc_chars();
 }
 
diff --git a/src/modules/Parser/xml.cmod b/src/modules/Parser/xml.cmod
index cd2e07ae4b91a598b2aa8a4286af326d5d3ef27c..869d9af85aa800d9811208cc13f9b7a707d9fcf5 100644
--- a/src/modules/Parser/xml.cmod
+++ b/src/modules/Parser/xml.cmod
@@ -22,7 +22,7 @@
 #include "operators.h"
 #include "pike_error.h"
 #include "bignum.h"
-#include "block_alloc.h"
+#include "block_allocator.h"
 
 
 #define sp Pike_sp
@@ -660,15 +660,20 @@ PIKECLASS Simple
     struct pike_string *entity;
   };
 
-#undef INIT_BLOCK
-#define INIT_BLOCK(X) do {			\
-    (X)->next = NULL;				\
-    (X)->callbackinfo = NULL;			\
-    (X)->to_free = NULL;			\
-    (X)->entity = NULL;				\
-  } while(0)
+  static struct block_allocator xmlinput_allocator = BA_INIT(sizeof(struct xmlinput), 64);
 
-  BLOCK_ALLOC(xmlinput, 64)
+  static struct xmlinput * alloc_xmlinput() {
+    struct xmlinput * i = ba_alloc(&xmlinput_allocator);
+    i->next = NULL;
+    i->callbackinfo = NULL;
+    i->to_free = NULL;
+    i->entity = NULL;
+    return i;
+  }
+
+  static void really_free_xmlinput(struct xmlinput * i) {
+    ba_free(&xmlinput_allocator, i);
+  }
 
   struct xmlinput *new_string_xmlinput(struct pike_string *s)
   {
@@ -3482,7 +3487,6 @@ PIKEFUN string autoconvert(string s)
 
 void init_parser_xml(void)
 {
-  init_xmlinput_blocks();
   push_text("location");
   location_string_svalue=sp[-1];
   sp--;
@@ -3506,6 +3510,6 @@ void exit_parser_xml(void)
 {
   EXIT;
 
-  free_all_xmlinput_blocks();
+  ba_destroy(&xmlinput_allocator);
   free_svalue(&location_string_svalue);
 }
diff --git a/src/multiset.c b/src/multiset.c
index 35555b33c5b9fbc444cf2956cbb1dd3d19cd1570..4de7b3ba04253c331e64f0c00a7bbf5665b4c486 100644
--- a/src/multiset.c
+++ b/src/multiset.c
@@ -29,7 +29,7 @@
 #include "mapping.h"
 #endif
 
-#include "block_alloc.h"
+#include "block_allocator.h"
 
 /* FIXME: Optimize finds and searches on type fields? (But not when
  * objects are involved!) Well.. Although cheap I suspect it pays off
@@ -252,37 +252,43 @@ void free_multiset_data (struct multiset_data *msd);
   } while (0)
 #endif
 
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(L) do {						\
-    FREE_PROT (L);							\
-    DO_IF_DEBUG (							\
-      if (L->refs) {							\
-	DO_IF_DMALLOC(describe_something (L, T_MULTISET, 0,2,0, NULL));	\
-	Pike_fatal ("Too few refs %d to multiset.\n", L->refs);		\
-      }									\
-      if (L->node_refs) {						\
-	DO_IF_DMALLOC(describe_something (L, T_MULTISET, 0,2,0, NULL));	\
-	Pike_fatal ("Freeing multiset with %d node refs.\n", L->node_refs); \
-      }									\
-    );									\
-    if (!sub_ref (L->msd)) free_multiset_data (L->msd);			\
-    DOUBLEUNLINK (first_multiset, L);					\
-    GC_FREE (L);							\
-  } while (0)
+static struct block_allocator multiset_allocator = BA_INIT_PAGES(sizeof(struct multiset), 2);
 
-#undef COUNT_OTHER
-#define COUNT_OTHER() do {						\
-    struct multiset *l;							\
-    double datasize = 0.0;						\
-    for (l = first_multiset; l; l = l->next)				\
-      datasize += (l->msd->flags & MULTISET_INDVAL ?			\
-		   NODE_OFFSET (msnode_indval, l->msd->allocsize) :	\
-		   NODE_OFFSET (msnode_ind, l->msd->allocsize)) /	\
-	(double) l->msd->refs;						\
-    size += (size_t) datasize;						\
-  } while (0)
+PMOD_EXPORT void really_free_multiset (struct multiset *l) {
+    FREE_PROT (l);
+#ifdef PIKE_DEBUG
+    if (l->refs) {
+# if DEBUG_MALLOC
+	describe_something (l, T_MULTISET, 0,2,0, NULL);
+# endif
+	Pike_fatal ("Too few refs %d to multiset.n", l->refs);
+    }
+    if (l->node_refs) {
+# if DEBUG_MALLOC
+	describe_something (l, T_MULTISET, 0,2,0, NULL);
+# endif
+	Pike_fatal ("Freeing multiset with %d node refs.n", l->node_refs);
+    }
+#endif
+    if (!sub_ref (l->msd)) free_multiset_data (l->msd);
+    DOUBLEUNLINK (first_multiset, l);
+    GC_FREE (l);
+    ba_free(&multiset_allocator, l);
+}
 
-BLOCK_ALLOC_FILL_PAGES (multiset, 2)
+PMOD_EXPORT void count_memory_in_multisets (size_t * n, size_t * s) {
+    struct multiset *l;
+    double datasize = 0.0;
+
+    ba_count_all(&multiset_allocator, n, s);
+
+    for (l = first_multiset; l; l = l->next)
+      datasize += (l->msd->flags & MULTISET_INDVAL ?
+		   NODE_OFFSET (msnode_indval, l->msd->allocsize) :
+		   NODE_OFFSET (msnode_ind, l->msd->allocsize)) /
+	(double) l->msd->refs;
+    *s += (size_t) datasize;
+}
 
 /* Note: The returned block has no refs. */
 #ifdef PIKE_DEBUG
@@ -872,7 +878,7 @@ PMOD_EXPORT struct multiset *real_allocate_multiset (int allocsize,
 						     int flags,
 						     struct svalue *cmp_less)
 {
-  struct multiset *l = alloc_multiset();
+  struct multiset *l = ba_alloc(&multiset_allocator);
 
   /* FIXME: There's currently little use in making "inflated"
    * multisets with allocsize, since prepare_for_add shrinks them. */
@@ -1285,7 +1291,7 @@ PMOD_EXPORT struct multiset *mkmultiset_2 (struct array *indices,
     fix_free_list (new.msd, indices->size);
   }
 
-  l = alloc_multiset();
+  l = ba_alloc(&multiset_allocator);
   l->msd = new.msd;
   add_ref (new.msd);
   INIT_MULTISET (l);
@@ -3389,7 +3395,7 @@ PMOD_EXPORT struct multiset *copy_multiset (struct multiset *l)
   struct multiset_data *msd = l->msd;
   debug_malloc_touch (l);
   debug_malloc_touch (msd);
-  l = alloc_multiset();
+  l = ba_alloc(&multiset_allocator);
   INIT_MULTISET (l);
   add_ref (l->msd = msd);
   return l;
@@ -4890,13 +4896,11 @@ void init_multiset()
   dmalloc_accept_leak (&empty_indval_msd);
 #endif
 
-  init_multiset_blocks();
 }
 
 /* Pike might exit without calling this. */
 void exit_multiset()
 {
-  free_all_multiset_blocks();
 }
 
 #if defined (PIKE_DEBUG) || defined (TEST_MULTISET)
diff --git a/src/multiset.h b/src/multiset.h
index 983caf87fbd12a2cb14d8a6c0842166f6c4a2ccd..70fa1b83bfa99dcd98e99a368bf0ab883fbd94b4 100644
--- a/src/multiset.h
+++ b/src/multiset.h
@@ -17,7 +17,6 @@
 #include "svalue.h"
 #include "dmalloc.h"
 #include "rbtree.h"
-#include "block_alloc_h.h"
 
 /* Keep this defined so that code can test which multiset API is in use. */
 #define PIKE_NEW_MULTISETS
@@ -231,6 +230,7 @@ PMOD_EXPORT INT32 multiset_sizeof (struct multiset *l);
 #else
 
 PMOD_EXPORT void really_free_multiset (struct multiset *l);
+PMOD_EXPORT void count_memory_in_multisets (size_t * n, size_t * s);
 
 #define free_multiset(L) do {						\
     struct multiset *_ms_ = (L);					\
@@ -261,8 +261,6 @@ PMOD_EXPORT union msnode *debug_check_msnode (
 
 #endif
 
-BLOCK_ALLOC_FILL_PAGES (multiset, 2);
-
 /* See rbtree.h for a description of the operations.
  *
  * If cmp_less is used, it's a function pointer used as `< to compare
diff --git a/src/object.c b/src/object.c
index 0b81ff5b5d1ebe425e86ca80a4d8d45a11a36ff0..1f0c30f4a63ae5070f4798d55db1edadbd59b57e 100644
--- a/src/object.c
+++ b/src/object.c
@@ -33,6 +33,7 @@
 #include "operators.h"
 
 #include "block_alloc.h"
+#include "block_allocator.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -83,22 +84,35 @@ PMOD_EXPORT struct object *first_object;
 struct object *gc_internal_object = 0;
 static struct object *gc_mark_object_pos = 0;
 
-#undef COUNT_OTHER
-
-#define COUNT_OTHER() do{			\
-  struct object *o;                             \
-  for(o=first_object;o;o=o->next)		\
-    if(o->prog)					\
-      size+=o->prog->storage_needed;		\
-						\
-  for(o=objects_to_destruct;o;o=o->next)	\
-    if(o->prog)					\
-      size+=o->prog->storage_needed;		\
-}while(0)
-BLOCK_ALLOC_FILL_PAGES(object, 2)
-
-#undef COUNT_OTHER
-#define COUNT_OTHER()
+static struct block_allocator object_allocator = BA_INIT_PAGES(sizeof(struct object), 2);
+
+void count_memory_in_objects(size_t *_num, size_t *_size) {
+    size_t size;
+    struct object *o;
+
+    ba_count_all(&object_allocator, _num, &size);
+
+    for(o=first_object;o;o=o->next)
+	if(o->prog)
+	    size+=o->prog->storage_needed;
+    for(o=objects_to_destruct;o;o=o->next)
+	if(o->prog)
+	    size+=o->prog->storage_needed;
+    *_size = size;
+}
+
+void really_free_object(struct object * o) {
+    ba_free(&object_allocator, o);
+}
+
+ATTRIBUTE((malloc))
+struct object * alloc_object() {
+    return ba_alloc(&object_allocator);
+}
+
+void free_all_object_blocks() {
+    ba_destroy(&object_allocator);
+}
 
 PMOD_EXPORT struct object *low_clone(struct program *p)
 {
diff --git a/src/object.h b/src/object.h
index df0a26742bfc7e69f375bfa67703cab8a384cdd4..2d214113430a20586efab4d6dbe93233b4a485aa 100644
--- a/src/object.h
+++ b/src/object.h
@@ -74,8 +74,11 @@ enum object_destruct_reason {
 };
 
 #include "block_alloc_h.h"
-/* Prototypes begin here */
-BLOCK_ALLOC_FILL_PAGES(object, 2);
+
+ATTRIBUTE((malloc)) struct object * alloc_object();
+void really_free_object(struct object * o);
+void count_memory_in_objects(size_t *_num, size_t *_size);
+void free_all_object_blocks();
 PMOD_EXPORT struct object *low_clone(struct program *p);
 PMOD_EXPORT void call_c_initializers(struct object *o);
 PMOD_EXPORT void call_prog_event(struct object *o, int event);
diff --git a/src/pike_embed.c b/src/pike_embed.c
index 797fc88b70ebebb3c3c9c66570767ea6f8fd40c5..b5fd0f305bd59d70168b5e686abb41b1d9c3412f 100644
--- a/src/pike_embed.c
+++ b/src/pike_embed.c
@@ -160,27 +160,8 @@ void init_pike(char **argv, const char *file)
   
   fd_init();
   {
-    extern void init_mapping_blocks(void);
-    extern void init_callable_blocks(void);
-    extern void init_gc_rec_frame_blocks(void);
-    extern void init_ba_mixed_frame_blocks(void);
-    extern void init_pike_frame_blocks(void);
     extern void init_node_s_blocks(void);
-    extern void init_object_blocks(void);
-    extern void init_callback_blocks(void);
-
-    init_mapping_blocks();
-    init_callable_blocks();
-    init_gc_rec_frame_blocks();
-    init_ba_mixed_frame_blocks();
-    /* init_catch_context_blocks(); */
-    /* init_pike_frame_blocks(); */
     init_node_s_blocks();
-    init_object_blocks();
-#if !defined(DEBUG_MALLOC) || !defined(_REENTRANT)
-    /* This has already been done by initialize_dmalloc(). */
-    init_callback_blocks();
-#endif /* !DEBUG_MALLOC */
     init_multiset();
     init_builtin_constants();
   }
diff --git a/src/pike_memory.c b/src/pike_memory.c
index 17d84748dfbeac8aa4a40f084e395b5dd2867738..3cde906160665182a93485d80bf57ce1a943a399 100644
--- a/src/pike_memory.c
+++ b/src/pike_memory.c
@@ -2998,16 +2998,6 @@ static void initialize_dmalloc(void)
     mt_init(&debug_malloc_mutex);
 #endif
 
-    /* NOTE: th_atfork() may be a simulated function, which
-     *       utilizes callbacks. We thus need to initialize
-     *       the callback blocks before we perform the call
-     *       to th_atfork().
-     */
-    {
-      extern void init_callback_blocks(void);
-      init_callback_blocks();
-    }
-
     th_atfork(lock_da_lock, unlock_da_lock,  unlock_da_lock);
 #endif
 #ifdef DMALLOC_USING_DLOPEN
diff --git a/src/pike_types.c b/src/pike_types.c
index 67d24d33d65079c74882ef852d11d3b9d1f4a8c1..654d86a2e93a049868a00d7354f5ef29385d7047 100644
--- a/src/pike_types.c
+++ b/src/pike_types.c
@@ -27,7 +27,7 @@
 #include "cyclic.h"
 #include "gc.h"
 #include "pike_compiler.h"
-#include "block_alloc.h"
+#include "block_allocator.h"
 
 #ifdef PIKE_DEBUG
 #define PIKE_TYPE_DEBUG
@@ -277,8 +277,20 @@ static void internal_parse_type(const char **s);
  * a many argument just have a MANY node, and no FUNCTION node.
  *
  */
-#define PIKE_TYPE_CHUNK	128
-BLOCK_ALLOC(pike_type, PIKE_TYPE_CHUNK)
+static struct block_allocator type_allocator = BA_INIT(sizeof(struct pike_type), 128);
+
+PMOD_EXPORT void really_free_pike_type(struct pike_type * t) {
+    ba_free(&type_allocator, t);
+}
+
+ATTRIBUTE((malloc))
+PMOD_EXPORT struct pike_type * alloc_pike_type() {
+    return ba_alloc(&type_allocator);
+}
+
+PMOD_EXPORT void count_memory_in_pike_types(size_t *n, size_t *s) {
+    ba_count_all(&type_allocator, n, s);
+}
 
 struct pike_type **pike_type_hash = NULL;
 size_t pike_type_hash_size = 0;
@@ -316,7 +328,7 @@ void debug_free_type(struct pike_type *t)
     cdr = t->cdr;
     type = t->type;
 
-    really_free_pike_type((struct pike_type *)debug_malloc_pass(t));
+    really_free_pike_type((struct pike_type*)debug_malloc_pass(t));
 
     /* FIXME: Recursion: Should we use a stack? */
     switch(type) {
@@ -558,7 +570,7 @@ static inline struct pike_type *debug_mk_type(unsigned INT32 type,
   }
 #endif
       
-  debug_malloc_pass(t = alloc_pike_type());
+  debug_malloc_pass(t = ba_alloc(&type_allocator));
 
 #ifdef ATOMIC_SVALUE
   t->ref_type = PIKE_T_TYPE;
@@ -8564,7 +8576,6 @@ void init_types(void)
                                                (PIKE_TYPE_HASH_SIZE+1));
   MEMSET(pike_type_hash, 0, sizeof(struct pike_type *) * (PIKE_TYPE_HASH_SIZE+1));
   pike_type_hash_size = PIKE_TYPE_HASH_SIZE;
-  init_pike_type_blocks();
 
   int_type_string = CONSTTYPE(tInt);	/* MUST come before string! */
   string0_type_string = CONSTTYPE(tStr0);
@@ -8664,7 +8675,7 @@ void cleanup_pike_type_table(void)
   pike_type_hash_size = 0;
 
 #ifdef DO_PIKE_CLEANUP
-  free_all_pike_type_blocks();
+  ba_destroy(&type_allocator);
 #endif /* DO_PIKE_CLEANUP */
 }
 
diff --git a/src/pike_types.h b/src/pike_types.h
index d0e5995fc5c13a5254eda415388dc4d7c55a736e..311c1c0d060ee65a08d3de2505248230eb5d46c8 100644
--- a/src/pike_types.h
+++ b/src/pike_types.h
@@ -41,9 +41,6 @@ extern size_t pike_type_hash_size;
 #define CAR_TO_INT(TYPE) ((char *) (TYPE)->car - (char *) 0)
 #define CDR_TO_INT(TYPE) ((char *) (TYPE)->cdr - (char *) 0)
 
-#include "block_alloc_h.h"
-BLOCK_ALLOC(pike_type, n/a);
-
 /*
  * pike_type flags:
  */
@@ -210,6 +207,9 @@ void debug_push_reverse_type(unsigned int type);
 } while(0)
 
 /* Prototypes begin here */
+PMOD_EXPORT void really_free_pike_type(struct pike_type * t);
+PMOD_EXPORT ATTRIBUTE((malloc)) struct pike_type * alloc_pike_type();
+PMOD_EXPORT void count_memory_in_pike_types(size_t *n, size_t *s);
 void debug_check_type_string(struct pike_type *s);
 void init_types(void);
 ptrdiff_t pop_stack_mark(void);
diff --git a/src/post_modules/CritBit/Makefile.in b/src/post_modules/CritBit/Makefile.in
index 63b26b423838b0c0965a8ecaafee1ffef46dc610..16e70d2b8350435f856db2589e9cbb99e95bb963 100644
--- a/src/post_modules/CritBit/Makefile.in
+++ b/src/post_modules/CritBit/Makefile.in
@@ -10,7 +10,7 @@ AUTODOC_SRC_IN=$(SRCDIR)/stringtree.c $(SRCDIR)/floattree.c $(SRCDIR)/inttree.c
 OBJS=glue.o inttree.o stringtree.o floattree.o bignumtree.o
 CONFIG_HEADERS=@CONFIG_HEADERS@
 CMOD_HEADERS=redefine.H tree_header.H iterator_source.H tree_source.H prefix.H
-COMMON_HEADERS=$(SRCDIR)/tree_high.c $(SRCDIR)/tree_low.h $(SRCDIR)/tree_low.c $(SRCDIR)/critbit/critbit.h $(SRCDIR)/common.h $(SRCDIR)/critbit/value_svalue.h $(SRCDIR)/bitvector.h
+COMMON_HEADERS=$(SRCDIR)/tree_high.c $(SRCDIR)/tree_low.h $(SRCDIR)/tree_low.c $(SRCDIR)/critbit/critbit.h $(SRCDIR)/common.h $(SRCDIR)/critbit/value_svalue.h
 
 PRECOMPILER_ARGS=--api=4
 
diff --git a/src/program.c b/src/program.c
index 5c7931069e52419ed8967848ef026b398030aa8b..ff626368b17aa2cfd051bf43d0c037e84a913633 100644
--- a/src/program.c
+++ b/src/program.c
@@ -32,6 +32,7 @@
 #include "pike_types.h"
 #include "opcodes.h"
 #include "version.h"
+#include "block_allocator.h"
 #include "block_alloc.h"
 #include "pikecode.h"
 #include "pike_compiler.h"
@@ -51,20 +52,30 @@ static size_t add_xstorage(size_t size,
 			   size_t alignment,
 			   ptrdiff_t modulo_orig);
 
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(P) exit_program_struct( (P) )
+static struct block_allocator program_allocator = BA_INIT_PAGES(sizeof(struct program), 4);
 
-#undef COUNT_OTHER
-#define COUNT_OTHER() do{			\
-  struct program *p;				\
-  for(p=first_program;p;p=p->next)		\
-  {						\
-    size+=p->total_size - sizeof (struct program); \
-  }						\
-}while(0)
+ATTRIBUTE((malloc))
+struct program * alloc_program() {
+    return ba_alloc(&program_allocator);
+}
 
-BLOCK_ALLOC_FILL_PAGES(program, 4)
+void really_free_program(struct program * p) {
+    exit_program_struct(p);
+    ba_free(&program_allocator, p);
+}
 
+void count_memory_in_programs(size_t *num, size_t *_size) {
+    size_t size;
+    struct program *p;
+    ba_count_all(&program_allocator, num, &size);
+    for(p=first_program;p;p=p->next) {
+	size+=p->total_size - sizeof (struct program);
+    }
+}
+
+void free_all_program_blocks() {
+    ba_destroy(&program_allocator);
+}
 
 /* #define COMPILER_DEBUG */
 /* #define PROGRAM_BUILD_DEBUG */
@@ -7970,11 +7981,6 @@ struct supporter_marker
   int level, verified;
 };
 
-#undef EXIT_BLOCK
-#define EXIT_BLOCK(P)
-#undef COUNT_OTHER
-#define COUNT_OTHER()
-
 #undef INIT_BLOCK
 #define INIT_BLOCK(X) do { (X)->level = (X)->verified = 0; }while(0)
 PTR_HASH_ALLOC(supporter_marker, 128);
@@ -10607,7 +10613,6 @@ void init_program(void)
   struct svalue key;
   struct svalue val;
   struct svalue id;
-  init_program_blocks();
 
   MAKE_CONST_STRING(this_function_string,"this_function");
   MAKE_CONST_STRING(this_program_string,"this_program");
diff --git a/src/program.h b/src/program.h
index f2f46607ca3d5f38c21ca5525c59de753dcc17f5..1e11644b7b92bf887b00f4a9e96127381fc69018 100644
--- a/src/program.h
+++ b/src/program.h
@@ -15,7 +15,6 @@
 #include "time_stuff.h"
 #include "program_id.h"
 #include "pike_rusage.h"
-#include "block_alloc_h.h"
 
 /* Needed to support dynamic loading on NT */
 PMOD_EXPORT extern struct program_state * Pike_compiler;
@@ -691,7 +690,11 @@ PMOD_EXPORT void gc_check_zapped (void *a, TYPE_T type, const char *file, INT_TY
   }while(0)
 #endif
 
-BLOCK_ALLOC_FILL_PAGES(program, n/a);
+ATTRIBUTE((malloc))
+PMOD_EXPORT struct program * alloc_program();
+PMOD_EXPORT void really_free_program(struct program * p);
+PMOD_EXPORT void count_memory_in_programs(size_t *num, size_t *_size);
+void free_all_program_blocks();
 
 
 extern struct program *first_program;
diff --git a/src/stralloc.c b/src/stralloc.c
index f4c38130b3334db65a476e8089a1791bcf4f34b0..cf8d98e569477ff6010fa4ce156ff11bbdfba08a 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -18,6 +18,7 @@
 #include "block_alloc.h"
 #include "operators.h"
 #include "pike_float.h"
+#include "block_allocator.h"
 #include "port.h"
 
 #include <errno.h>
@@ -667,26 +668,6 @@ struct pike_string_hdr {
 
 /* Allocate some fixed string sizes with BLOCK_ALLOC. */
 
-/* Use the BLOCK_ALLOC() stuff for short strings */
-
-#undef INIT_BLOCK
-#ifdef ATOMIC_SVALUE
-#define INIT_BLOCK(NEW_STR) do {				\
-    (NEW_STR)->ref_type = T_STRING;				\
-    (NEW_STR)->refs = 0;					\
-    add_ref((NEW_STR));						\
-    (NEW_STR)->flags =						\
-      STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT;	\
-  } while(0)
-#else /* !ATOMIC_SVALUE */
-#define INIT_BLOCK(NEW_STR) do {				\
-    (NEW_STR)->refs = 0;					\
-    add_ref((NEW_STR));						\
-    (NEW_STR)->flags =						\
-      STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT;	\
-  } while(0)
-#endif
-
 #define SHORT_STRING_BLOCK	256
 #define SHORT_STRING_THRESHOLD	15 /* % 4 === -1 */
 
@@ -705,25 +686,30 @@ struct short_pike_string2 {
   p_wchar2 str[SHORT_STRING_THRESHOLD+1];
 };
 
-BLOCK_ALLOC(short_pike_string0, SHORT_STRING_BLOCK)
-BLOCK_ALLOC(short_pike_string1, SHORT_STRING_BLOCK)
-BLOCK_ALLOC(short_pike_string2, SHORT_STRING_BLOCK)
-
-#undef INIT_BLOCK
-#define INIT_BLOCK(x)
-
-#define really_free_short_pike_string(s) do { \
-     if (!s->size_shift) { \
-       really_free_short_pike_string0((struct short_pike_string0 *)s); \
-     } else if (s->size_shift == 1) { \
-       really_free_short_pike_string1((struct short_pike_string1 *)s); \
-     DO_IF_DEBUG( \
-     } else if (s->size_shift != 2) { \
-       Pike_fatal("Unsupported string shift: %d\n", s->size_shift); \
-     ) \
-     } else { \
-       really_free_short_pike_string2((struct short_pike_string2 *)s); \
-     } \
+static struct block_allocator string_allocator[] = {
+    BA_INIT(sizeof(struct short_pike_string0), SHORT_STRING_BLOCK),
+    BA_INIT(sizeof(struct short_pike_string1), SHORT_STRING_BLOCK),
+    BA_INIT(sizeof(struct short_pike_string2), SHORT_STRING_BLOCK)
+};
+
+static struct pike_string * alloc_short_pike_string(unsigned int shift) {
+    struct pike_string * s = (struct pike_string *)ba_alloc(string_allocator+shift);
+
+#ifdef ATOMIC_SVALUE
+    s->ref_type = T_STRING;
+#endif
+    s->refs = 0;
+    add_ref(s);	/* For DMALLOC */
+    s->flags = STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT;
+    return s;
+}
+
+#define really_free_short_pike_string(s) do {				\
+    DO_IF_DEBUG(							\
+     if (s->size_shift > 2)						\
+       Pike_fatal("Unsupported string shift: %d\n", s->size_shift);	\
+     )									\
+     ba_free(string_allocator + s->size_shift, s);			\
    } while(0)
 
 #define free_unlinked_pike_string(s) do { \
@@ -746,7 +732,8 @@ PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t len)
     verify_shared_strings_tables();
 #endif
   if (len <= SHORT_STRING_THRESHOLD) {
-    t=(struct pike_string *)alloc_short_pike_string0();
+    t=(struct pike_string *)ba_alloc(string_allocator);
+    t->flags = STRING_NOT_HASHED | STRING_NOT_SHARED | STRING_IS_SHORT;
   } else {
     t=(struct pike_string *)xalloc(len + 1 + sizeof(struct pike_string_hdr));
     t->flags = STRING_NOT_HASHED | STRING_NOT_SHARED;
@@ -876,17 +863,12 @@ PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int s
     verify_shared_strings_tables();
 #endif
   if (len <= SHORT_STRING_THRESHOLD) {
-    if (!shift) {
-      t = (struct pike_string *)alloc_short_pike_string0();
-    } else if (shift == 1) {
-      t = (struct pike_string *)alloc_short_pike_string1();
 #ifdef PIKE_DEBUG
-    } else if (shift != 2) {
+    if (shift > 2)
       Pike_fatal("Unsupported string shift: %d\n", shift);
 #endif /* PIKE_DEBUG */
-    } else {
-      t = (struct pike_string *)alloc_short_pike_string2();
-    }
+    t=(struct pike_string *)ba_alloc(string_allocator+shift);
+    t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT;
   } else {
     t=(struct pike_string *)xalloc(((len + 1)<<shift) +
 				   sizeof(struct pike_string_hdr));
@@ -1246,7 +1228,7 @@ PMOD_EXPORT void really_free_string(struct pike_string *s)
     if(((ptrdiff_t)s->next) & 1)
       Pike_fatal("Freeing shared string again, memory corrupt or other bug!\n");
   }
-  if ((s->size_shift < 0) || (s->size_shift > 2)) {
+  if (s->size_shift > 2) {
     Pike_fatal("Freeing string with bad shift (0x%08x); could it be a type?\n",
 	  s->size_shift);
   }
@@ -2316,9 +2298,6 @@ PMOD_EXPORT struct pike_string *string_replace(struct pike_string *str,
 /*** init/exit memory ***/
 void init_shared_string_table(void)
 {
-  init_short_pike_string0_blocks();
-  init_short_pike_string1_blocks();
-  init_short_pike_string2_blocks();
   for(hashprimes_entry=0;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);
   SET_HSIZE(hashprimes_entry);
   base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size);
@@ -2394,9 +2373,9 @@ void cleanup_shared_string_table(void)
   num_strings=0;
 
 #ifdef DO_PIKE_CLEANUP
-  free_all_short_pike_string0_blocks();
-  free_all_short_pike_string1_blocks();
-  free_all_short_pike_string2_blocks();
+  ba_destroy(string_allocator+0);
+  ba_destroy(string_allocator+1);
+  ba_destroy(string_allocator+2);
 #endif /* DO_PIKE_CLEANUP */
 }
 
@@ -2415,11 +2394,11 @@ static INLINE size_t memory_in_string (struct pike_string *s)
 void count_memory_in_short_pike_strings(size_t *num, size_t *size)
 {
   size_t num_=0, size_=0;
-  count_memory_in_short_pike_string0s(num, size);
-  count_memory_in_short_pike_string1s(&num_, &size_);
+  ba_count_all(string_allocator, num, size);
+  ba_count_all(string_allocator+1, &num_, &size_);
   *num += num_;
   *size += size_;
-  count_memory_in_short_pike_string2s(&num_, &size_);
+  ba_count_all(string_allocator+2, &num_, &size_);
   *num += num_;
   *size += size_;
 }
diff --git a/src/stralloc.h b/src/stralloc.h
index 79681fe166a1ce01d66a241f3f25ef8d74135b18..951d3f6c6dd61418f80dd30dc0308812e65cede1 100644
--- a/src/stralloc.h
+++ b/src/stralloc.h
@@ -9,7 +9,6 @@
 #include "global.h"
 
 #include "pike_macros.h"
-#include "block_alloc_h.h"
 
 #define STRINGS_ARE_SHARED
 
@@ -276,10 +275,6 @@ struct pike_string *findstring(const char *foo);
 struct short_pike_string0;
 struct short_pike_string1;
 struct short_pike_string2;
-BLOCK_ALLOC(short_pike_string0, SHORT_STRING_BLOCK);
-BLOCK_ALLOC(short_pike_string1, SHORT_STRING_BLOCK);
-BLOCK_ALLOC(short_pike_string2, SHORT_STRING_BLOCK);
-
 
 PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t len) ATTRIBUTE((malloc));
 PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int shift)  ATTRIBUTE((malloc));