Index: trunk/src/kmk/Makefile.am
===================================================================
--- trunk/src/kmk/Makefile.am	(revision 1862)
+++ trunk/src/kmk/Makefile.am	(revision 1863)
@@ -108,4 +108,5 @@
 	-DCONFIG_WITH_LOCAL_VARIABLES \
 	-DCONFIG_WITH_2ND_TARGET_EXPANSION \
+	-DCONFIG_WITH_ALLOC_CACHES \
 	\
 	-DKMK \
Index: trunk/src/kmk/Makefile.kmk
===================================================================
--- trunk/src/kmk/Makefile.kmk	(revision 1862)
+++ trunk/src/kmk/Makefile.kmk	(revision 1863)
@@ -139,4 +139,5 @@
 	CONFIG_WITH_LOCAL_VARIABLES \
 	CONFIG_WITH_2ND_TARGET_EXPANSION \
+	CONFIG_WITH_ALLOC_CACHES \
 	\
 	KMK \
Index: trunk/src/kmk/default.c
===================================================================
--- trunk/src/kmk/default.c	(revision 1862)
+++ trunk/src/kmk/default.c	(revision 1863)
@@ -555,6 +555,10 @@
       char *p = default_suffixes;
       suffix_file->deps = (struct dep *)
+#ifndef CONFIG_WITH_ALLOC_CACHES
 	multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1),
 		    sizeof (struct dep));
+#else
+        multi_glob (parse_file_seq (&p, '\0', &dep_cache, 1), &dep_cache);
+#endif
       define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0);
     }
Index: trunk/src/kmk/dep.h
===================================================================
--- trunk/src/kmk/dep.h	(revision 1862)
+++ trunk/src/kmk/dep.h	(revision 1863)
@@ -59,9 +59,18 @@
 
 
+
+#ifndef CONFIG_WITH_ALLOC_CACHES
 struct nameseq *multi_glob (struct nameseq *chain, unsigned int size);
+#else
+struct nameseq *multi_glob (struct nameseq *chain, struct alloccache *cache);
+#endif
 #ifdef VMS
 struct nameseq *parse_file_seq ();
 #else
+# ifndef CONFIG_WITH_ALLOC_CACHES
 struct nameseq *parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip);
+# else
+struct nameseq *parse_file_seq (char **stringp, int stopchar, struct alloccache *cache, int strip);
+# endif
 #endif
 char *tilde_expand (const char *name);
Index: trunk/src/kmk/file.c
===================================================================
--- trunk/src/kmk/file.c	(revision 1862)
+++ trunk/src/kmk/file.c	(revision 1863)
@@ -524,7 +524,12 @@
 parse_prereqs (char *p)
 {
+#ifndef CONFIG_WITH_ALLOC_CACHES
   struct dep *new = (struct dep *)
     multi_glob (parse_file_seq (&p, '|', sizeof (struct dep), 1),
                 sizeof (struct dep));
+#else
+  struct dep *new = (struct dep *)
+    multi_glob (parse_file_seq (&p, '|', &dep_cache, 1), &dep_cache);
+#endif
 
   if (*p)
@@ -535,8 +540,12 @@
 
       ++p;
+#ifndef CONFIG_WITH_ALLOC_CACHES
       ood = (struct dep *)
         multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1),
                     sizeof (struct dep));
-
+#else
+      ood = (struct dep *)
+        multi_glob (parse_file_seq (&p, '\0', &dep_cache, 1), &dep_cache);
+#endif
       if (! new)
         new = ood;
Index: trunk/src/kmk/function.c
===================================================================
--- trunk/src/kmk/function.c	(revision 1862)
+++ trunk/src/kmk/function.c	(revision 1863)
@@ -514,4 +514,5 @@
   unsigned int idx;
 
+#ifndef CONFIG_WITH_ALLOC_CACHES
   chain = multi_glob (parse_file_seq
 		      (&line, '\0', sizeof (struct nameseq),
@@ -521,4 +522,13 @@
 		       0),
 		      sizeof (struct nameseq));
+#else
+  chain = multi_glob (parse_file_seq
+                      (&line, '\0', &nameseq_cache,
+                       /* We do not want parse_file_seq to strip `./'s.
+                          That would break examples like:
+                          $(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)).  */
+                       0),
+                      &nameseq_cache);
+#endif
 
   if (result == 0)
@@ -535,5 +545,9 @@
 
       struct nameseq *next = chain->next;
+#ifndef CONFIG_WITH_ALLOC_CACHES
       free (chain);
+#else
+      alloccache_free (&nameseq_cache, chain);
+#endif
       chain = next;
 
Index: trunk/src/kmk/implicit.c
===================================================================
--- trunk/src/kmk/implicit.c	(revision 1862)
+++ trunk/src/kmk/implicit.c	(revision 1863)
@@ -66,4 +66,8 @@
 
 
+#ifdef CONFIG_WITH_ALLOC_CACHES
+struct alloccache idep_cache;
+#endif
+
 /* Struct idep captures information about implicit prerequisites
    that come from implicit rules. */
@@ -86,5 +90,9 @@
     {
       n = p->next;
+#ifndef CONFIG_WITH_ALLOC_CACHES
       free (p);
+#else
+      alloccache_free (&idep_cache, p);
+#endif
     }
 }
@@ -254,4 +262,9 @@
 
   PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */
+
+#ifdef CONFIG_WITH_ALLOC_CACHES
+  if (!idep_cache.size)
+    alloccache_init (&idep_cache, sizeof(struct idep), "dep", NULL, NULL);
+#endif
 
 #ifndef	NO_ARCHIVES
@@ -583,4 +596,5 @@
                         ;
 
+#ifndef CONFIG_WITH_ALLOC_CACHES
                       *id_ptr = (struct idep *)
                         multi_glob (
@@ -589,4 +603,12 @@
                                           sizeof (struct idep),
                                           1), sizeof (struct idep));
+#else
+                      *id_ptr = (struct idep *)
+                        multi_glob (
+                          parse_file_seq (&p2,
+                                          order_only ? '\0' : '|',
+                                          &idep_cache, 1),
+                          &idep_cache);
+#endif
 
                       /* @@ It would be nice to teach parse_file_seq or
Index: trunk/src/kmk/incdep.c
===================================================================
--- trunk/src/kmk/incdep.c	(revision 1862)
+++ trunk/src/kmk/incdep.c	(revision 1863)
@@ -145,11 +145,8 @@
   char *file_end;
 
-  int is_worker;
+  int worker_tid;
 #ifdef PARSE_IN_WORKER
   unsigned int err_line_no;
   const char *err_msg;
-
-  struct dep *dep_start;            /* start of the current dep block. */
-  struct dep *dep_end;              /* end of the current dep block. */
 
   struct incdep_variable_in_set *recorded_variables_in_set_head;
@@ -207,11 +204,20 @@
 static struct incdep * volatile incdep_tail_done;
 
+
 /* The handles to the worker threads. */
 #ifdef HAVE_PTHREAD
 static pthread_t incdep_threads[1];
+static struct alloccache incdep_dep_caches[1];
+static struct alloccache incdep_nameseq_caches[1];
+
 #elif defined (WINDOWS32)
 static HANDLE incdep_threads[2];
+static struct alloccache incdep_dep_caches[2];
+static struct alloccache incdep_nameseq_caches[2];
+
 #elif defined (__OS2__)
 static TID incdep_threads[2];
+static struct alloccache incdep_dep_caches[2];
+static struct alloccache incdep_nameseq_caches[2];
 #endif
 static unsigned incdep_num_threads;
@@ -242,5 +248,5 @@
 
 #ifdef __APPLE__
-  if (cur && cur->is_worker)
+  if (cur && cur->worker_tid != -1)
     {
       ptr = malloc_zone_malloc (incdep_zone, size);
@@ -258,4 +264,5 @@
 }
 
+#if 0
 /* memset(malloc(sz),'\0',sz) wrapper. */
 static void *
@@ -265,5 +272,5 @@
 
 #ifdef __APPLE__
-  if (cur && cur->is_worker)
+  if (cur && cur->worker_tid != -1)
     ptr = malloc_zone_calloc (incdep_zone, size, 1);
   else
@@ -278,4 +285,5 @@
   return ptr;
 }
+#endif /* unused */
 
 /* free wrapper */
@@ -289,16 +297,39 @@
 }
 
+/* alloc a nameseq structure.  */
+struct nameseq *
+incdep_alloc_nameseq (struct incdep *cur)
+{
+  struct alloccache *cache;
+  if (cur->worker_tid != -1)
+    cache = &incdep_nameseq_caches[cur->worker_tid];
+  else
+    cache = &nameseq_cache;
+  return alloccache_calloc (cache);
+}
+
 /* alloc a dep structure. These are allocated in bunches to save time. */
 struct dep *
 incdep_alloc_dep (struct incdep *cur)
 {
-  if (cur->dep_start != cur->dep_end)
-    return cur->dep_start++;
-
-  cur->dep_start = (struct dep *)incdep_xcalloc (cur, sizeof(struct dep) * 256);
-  cur->dep_end = cur->dep_start + 256;
-  return cur->dep_start++;
-}
-
+  struct alloccache *cache;
+  if (cur->worker_tid != -1)
+    cache = &incdep_dep_caches[cur->worker_tid];
+  else
+    cache = &dep_cache;
+  return alloccache_calloc (cache);
+}
+
+/* grow a cache. */
+static void *
+incdep_cache_allocator (void *thrd, unsigned int size)
+{
+  (void)thrd;
+#ifdef __APPLE__
+  return malloc_zone_malloc (incdep_zone, size);
+#else
+  return xmalloc (size);
+#endif
+}
 
 /* acquires the lock */
@@ -472,11 +503,6 @@
 /* A worker thread. */
 void
-incdep_worker (void)
-{
-#ifdef PARSE_IN_WORKER
-  struct dep *dep_start = NULL;
-  struct dep *dep_end = NULL;
-#endif
-
+incdep_worker (int thrd)
+{
   incdep_lock ();
 
@@ -500,20 +526,12 @@
 
       incdep_unlock ();
-      cur->is_worker = 1;
+      cur->worker_tid = thrd;
+
       incdep_read_file (cur, NILF);
-
 #ifdef PARSE_IN_WORKER
-      cur->dep_start = dep_start;
-      cur->dep_end = dep_end;
-
       eval_include_dep_file (cur, NILF);
-
-      dep_start = cur->dep_start;
-      cur->dep_start = NULL;
-      dep_end = cur->dep_end;
-      cur->dep_end = NULL;
-#endif
-
-      cur->is_worker = 0;
+#endif
+
+      cur->worker_tid = -1;
       incdep_lock ();
 
@@ -537,8 +555,7 @@
 #ifdef HAVE_PTHREAD
 static void *
-incdep_worker_pthread (void *ignore)
-{
-  incdep_worker ();
-  (void)ignore;
+incdep_worker_pthread (void *thrd)
+{
+  incdep_worker ((size_t)thrd);
   return NULL;
 }
@@ -546,8 +563,7 @@
 #elif defined (WINDOWS32)
 static unsigned __stdcall
-incdep_worker_windows (void *ignore)
-{
-  incdep_worker ();
-  (void)ignore;
+incdep_worker_windows (void *thrd)
+{
+  incdep_worker ((size_t)thrd);
   return 0;
 }
@@ -555,8 +571,7 @@
 #elif defined (__OS2__)
 static void
-incdep_worker_os2 (void *ignore)
-{
-  incdep_worker ();
-  (void)ignore;
+incdep_worker_os2 (void *thrd)
+{
+  incdep_worker ((size_t)thrd);
 }
 #endif
@@ -633,4 +648,9 @@
   for (i = 0; i < incdep_num_threads; i++)
     {
+      alloccache_init (&incdep_dep_caches[i], sizeof(struct dep), "incdep dep",
+                       incdep_cache_allocator, (void *)i);
+      alloccache_init (&incdep_nameseq_caches[i], sizeof(struct nameseq),
+                       "incdep nameseq", incdep_cache_allocator, (void *)i);
+
 #ifdef HAVE_PTHREAD
       rc = pthread_attr_init (&attr);
@@ -641,6 +661,6 @@
       if (rc)
         fatal (f, _("pthread_attr_setdetachstate failed: err=%d"), rc);
-      rc = pthread_create (&incdep_threads[i], &attr,
-                           incdep_worker_pthread, f);
+      rc = pthread_create(&incdep_threads[i], &attr,
+                           incdep_worker_pthread, (void *)i);
       if (rc)
         fatal (f, _("pthread_mutex_init failed: err=%d"), rc);
@@ -650,5 +670,5 @@
       tid = 0;
       hThread = _beginthreadex (NULL, 128*1024, incdep_worker_windows,
-                                NULL, 0, &tid);
+                                (void *)i, 0, &tid);
       if (hThread == 0 || hThread == ~(uintptr_t)0)
         fatal (f, _("_beginthreadex failed: err=%d"), errno);
@@ -656,5 +676,5 @@
 
 #elif defined (__OS2__)
-      tid = _beginthread (incdep_worker_os2, NULL, 128*1024, NULL);
+      tid = _beginthread (incdep_worker_os2, NULL, 128*1024, (void *)i);
       if (tid <= 0)
         fatal (f, _("_beginthread failed: err=%d"), errno);
@@ -691,5 +711,8 @@
   for (i = 0; i < incdep_num_threads; i++)
     {
-      /* later? */
+      /* more later? */
+
+      alloccache_join (&dep_cache, &incdep_dep_caches[i]);
+      alloccache_join (&nameseq_cache, &incdep_nameseq_caches[i]);
     }
   incdep_num_threads = 0;
@@ -803,5 +826,5 @@
 incdep_warn (struct incdep *cur, unsigned int line_no, const char *msg)
 {
-  if (!cur->is_worker)
+  if (cur->worker_tid == -1)
     error (NILF, "%s(%d): %s", cur->name, line_no, msg);
 #ifdef PARSE_IN_WORKER
@@ -819,5 +842,5 @@
 {
   const char *ret;
-  if (!cur->is_worker)
+  if (cur->worker_tid == -1)
     {
       /* Make sure the string is terminated before we hand it to
@@ -860,5 +883,5 @@
 {
   assert (!duplicate_value);
-  if (!cur->is_worker)
+  if (cur->worker_tid == -1)
     define_variable_in_set (name, name_length, value, value_length,
                             duplicate_value, origin, recursive, set, flocp);
@@ -898,5 +921,5 @@
                             int target_var)
 {
-  if (!cur->is_worker)
+  if (cur->worker_tid == -1)
     do_variable_definition_2 (flocp, name, value, value_length, 0, value,
                               origin, flavor, target_var);
@@ -934,5 +957,5 @@
                      const struct floc *flocp)
 {
-  if (!cur->is_worker)
+  if (cur->worker_tid == -1)
     record_files (filenames, pattern, pattern_percent, deps, cmds_started,
                   commands, commands_idx, two_colon, flocp);
@@ -1329,5 +1352,5 @@
                   break;
                 }
-              filenames = incdep_xmalloc (curdep, sizeof (struct nameseq));
+              filenames = incdep_alloc_nameseq (curdep);
               memset (filenames, 0, sizeof (*filenames));
               filenames->name = incdep_record_strcache (curdep, cur, endp - cur);
@@ -1469,10 +1492,8 @@
        memcpy (cur->name, name, name_len);
        cur->name[name_len] = '\0';
-       cur->is_worker = 0;
+       cur->worker_tid = -1;
 #ifdef PARSE_IN_WORKER
        cur->err_line_no = 0;
        cur->err_msg = NULL;
-       cur->dep_start = NULL;
-       cur->dep_end = NULL;
        cur->recorded_variables_in_set_head = NULL;
        cur->recorded_variables_in_set_tail = NULL;
@@ -1491,5 +1512,9 @@
     }
 
+#ifdef ELECTRIC_HEAP
+  if (1)
+#else
   if (op == incdep_read_it)
+#endif
     {
       /* work our way thru the files directly */
Index: trunk/src/kmk/main.c
===================================================================
--- trunk/src/kmk/main.c	(revision 1862)
+++ trunk/src/kmk/main.c	(revision 1863)
@@ -644,4 +644,18 @@
 #endif
 
+#ifdef CONFIG_WITH_ALLOC_CACHES
+struct alloccache dep_cache;
+struct alloccache nameseq_cache;
+struct alloccache variable_cache;
+
+static void
+initialize_global_alloc_caches (void)
+{
+  alloccache_init (&dep_cache,      sizeof (struct dep),      "dep",      NULL, NULL);
+  alloccache_init (&nameseq_cache,  sizeof (struct nameseq),  "nameseq",  NULL, NULL);
+  alloccache_init (&variable_cache, sizeof (struct variable), "variable", NULL, NULL);
+}
+#endif
+
 static void
 initialize_global_hash_tables (void)
@@ -1271,5 +1285,5 @@
 #ifndef ELECTRIC_HEAP /* Drop this because it prevent JIT debugging. */
   SetUnhandledExceptionFilter(handle_runtime_exceptions);
-#endif /* !ELECTRICT_HEAP */
+#endif /* !ELECTRIC_HEAP */
 
   /* start off assuming we have no shell */
@@ -1468,4 +1482,7 @@
   user_access ();
 
+#ifdef CONFIG_WITH_ALLOC_CACHES
+  initialize_global_alloc_caches ();
+#endif
   initialize_global_hash_tables ();
 
@@ -2674,7 +2691,13 @@
                     char *p = *default_goal_name;
 
+#ifndef CONFIG_WITH_ALLOC_CACHES
                     ns = multi_glob (
                       parse_file_seq (&p, '\0', sizeof (struct nameseq), 1),
                       sizeof (struct nameseq));
+#else
+                    ns = multi_glob (
+                      parse_file_seq (&p, '\0', &nameseq_cache, 1),
+                      &nameseq_cache);
+#endif
 
                     /* .DEFAULT_GOAL should contain one target. */
@@ -3604,4 +3627,7 @@
   print_vpath_data_base ();
   strcache_print_stats ("#");
+#ifdef CONFIG_WITH_ALLOC_CACHES
+  alloccache_print_all ();
+#endif
 
   when = time ((time_t *) 0);
Index: trunk/src/kmk/make.h
===================================================================
--- trunk/src/kmk/make.h	(revision 1862)
+++ trunk/src/kmk/make.h	(revision 1863)
@@ -496,4 +496,86 @@
 
 char *strip_whitespace (const char **begpp, const char **endpp);
+
+#ifdef CONFIG_WITH_ALLOC_CACHES
+/* alloccache (misc.c) */
+
+struct alloccache_free_ent
+{
+  struct alloccache_free_ent *next;
+};
+
+struct alloccache
+{
+  char *free_start;
+  char *free_end;
+  struct alloccache_free_ent *free_head;
+  unsigned int size;
+  unsigned int alloc_count;
+  unsigned int total_count;
+  const char *name;
+  struct alloccache *next;
+  void *grow_arg;
+  void *(*grow_alloc)(void *grow_arg, unsigned int size);
+};
+
+void alloccache_init (struct alloccache *cache, unsigned int size, const char *name,
+                      void *(*grow_alloc)(void *grow_arg, unsigned int size), void *grow_arg);
+void alloccache_join (struct alloccache *cache, struct alloccache *eat);
+void alloccache_print (struct alloccache *cache);
+void alloccache_print_all (void);
+struct alloccache_free_ent *alloccache_alloc_grow (struct alloccache *cache);
+
+/* Allocate an item. */
+MY_INLINE void *
+alloccache_alloc (struct alloccache *cache)
+{
+  struct alloccache_free_ent *f = cache->free_head;
+  if (f)
+    cache->free_head = f->next;
+  else if (cache->free_start != cache->free_end)
+    {
+      f = (struct alloccache_free_ent *)cache->free_start;
+      cache->free_start += cache->size;
+    }
+  else
+    f = alloccache_alloc_grow (cache);
+  cache->alloc_count++;
+  return f;
+}
+
+/* Allocate a cleared item. */
+MY_INLINE void *
+alloccache_calloc (struct alloccache *cache)
+{
+  void *item = alloccache_alloc (cache);
+  memset (item, '\0', cache->size);
+  return item;
+}
+
+/* Free an item. */
+MY_INLINE void
+alloccache_free (struct alloccache *cache, void *item)
+{
+  struct alloccache_free_ent *f = (struct alloccache_free_ent *)item;
+#if 0 /*ndef NDEBUG*/
+  struct alloccache_free_ent *c;
+  unsigned int i = 0;
+  for (c = cache->free_head; c != NULL; c = c->next, i++)
+    MY_ASSERT_MSG (c != f && i < 0x10000000,
+                   ("i=%u total_count=%u\n", i, cache->total_count));
+#endif
+
+  f->next = cache->free_head;
+  cache->free_head = f;
+  cache->alloc_count--;
+}
+
+/* the alloc caches */
+extern struct alloccache dep_cache;
+extern struct alloccache nameseq_cache;
+extern struct alloccache variable_cache;
+
+#endif /* CONFIG_WITH_ALLOC_CACHES */
+
 
 /* String caching  */
Index: trunk/src/kmk/misc.c
===================================================================
--- trunk/src/kmk/misc.c	(revision 1862)
+++ trunk/src/kmk/misc.c	(revision 1863)
@@ -709,38 +709,4 @@
 
 
-#ifdef KMK
-/* Cache free struct dep to save time in free during snap_deps.
-   free is esp. slow on darwin for some reason. */
-static struct dep *free_deps = NULL;
-static struct dep *free_deps_start = NULL;
-static struct dep *free_deps_end = NULL;
-
-static struct dep *
-alloc_dep_int (void)
-{
-  struct dep *d = free_deps;
-  if (MY_PREDICT_TRUE(d))
-    free_deps = d->next;
-  else if (free_deps_start != free_deps_end)
-    d = free_deps_start++;
-  else
-    {
-      /* allocate another chunk block. */
-      free_deps_start = xmalloc (sizeof (struct dep) * 256);
-      free_deps_end = free_deps_start + 256;
-      d = free_deps_start++;
-    }
-  return d;
-}
-
-static void
-free_dep_int (struct dep *d)
-{
-  d->next = free_deps;
-  free_deps = d;
-}
-#endif /* KMK */
-
-
 /* Allocate a new `struct dep' with all fields initialized to 0.   */
 
@@ -748,11 +714,11 @@
 alloc_dep ()
 {
-#ifndef KMK
+#ifndef CONFIG_WITH_ALLOC_CACHES
   struct dep *d = xmalloc (sizeof (struct dep));
-#else
-  struct dep *d = alloc_dep_int ();
-#endif
   memset (d, '\0', sizeof (struct dep));
   return d;
+#else
+  return (struct dep *) alloccache_calloc (&dep_cache);
+#endif
 }
 
@@ -763,8 +729,8 @@
 free_dep (struct dep *d)
 {
-#ifndef KMK
+#ifndef CONFIG_WITH_ALLOC_CACHES
   free (d);
 #else
-  free_dep_int (d);
+  alloccache_free (&dep_cache, d);
 #endif
 }
@@ -781,8 +747,8 @@
   while (d != 0)
     {
-#ifndef KMK
+#ifndef CONFIG_WITH_ALLOC_CACHES
       struct dep *c = xmalloc (sizeof (struct dep));
 #else
-      struct dep *c = alloc_dep_int ();
+      struct dep *c = (struct dep *) alloccache_alloc (&dep_cache);
 #endif
       memcpy (c, d, sizeof (struct dep));
@@ -809,8 +775,8 @@
       struct dep *df = d;
       d = d->next;
-#ifndef KMK
+#ifndef CONFIG_WITH_ALLOC_CACHES
       free_dep (df);
 #else
-      free_dep_int (df);
+      alloccache_free (&dep_cache, df);
 #endif
     }
@@ -827,5 +793,9 @@
       struct nameseq *t = ns;
       ns = ns->next;
+#ifndef CONFIG_WITH_ALLOC_CACHES
       free (t);
+#else
+      alloccache_free (&nameseq_cache, t);
+#endif
     }
 }
@@ -1191,2 +1161,141 @@
 #endif
 
+
+#ifdef CONFIG_WITH_ALLOC_CACHES
+
+/* Default allocator. */
+static void *
+alloccache_default_grow_alloc(void *ignore, unsigned int size)
+{
+  return xmalloc (size);
+}
+
+/* Worker for growing the cache. */
+struct alloccache_free_ent *
+alloccache_alloc_grow (struct alloccache *cache)
+{
+  void *item;
+  unsigned int items = (64*1024 - 32) / cache->size;
+  cache->free_start  = cache->grow_alloc (cache->grow_arg, items * cache->size);
+  cache->free_end    = cache->free_start + items * cache->size;
+  cache->total_count+= items;
+
+#ifndef NDEBUG /* skip the first item so the heap can detect free(). */
+  cache->total_count--;
+  cache->free_start += cache->size;
+#endif
+
+  item = cache->free_start;
+  cache->free_start += cache->size;
+  /* caller counts */
+  return (struct alloccache_free_ent *)item;
+}
+
+/* List of alloc caches, for printing. */
+static struct alloccache *alloccache_head = NULL;
+
+/* Initializes an alloc cache */
+void
+alloccache_init (struct alloccache *cache, unsigned int size, const char *name,
+                 void *(*grow_alloc)(void *grow_arg, unsigned int size), void *grow_arg)
+{
+  /* ensure aligned and min sizeof (struct alloccache_free_ent). */
+  if (size & (sizeof (void *) - 1))
+    size += sizeof (void *) - (size & (sizeof (void *) - 1));
+
+  cache->free_start  = NULL;
+  cache->free_end    = NULL;
+  cache->free_head   = NULL;
+  cache->size        = size;
+  cache->alloc_count = 0;
+  cache->total_count = 0;
+  cache->name        = name;
+  cache->grow_arg    = grow_arg;
+  cache->grow_alloc  = grow_alloc ? grow_alloc : alloccache_default_grow_alloc;
+
+  cache->next        = alloccache_head;
+  alloccache_head    = cache;
+}
+
+/* Joins to caches, unlinking the 2nd one. */
+void
+alloccache_join (struct alloccache *cache, struct alloccache *eat)
+{
+  assert (cache->size == eat->size);
+
+#if 0 /* probably a waste of time */ /* FIXME: Optimize joining, avoid all list walking. */
+  /* add the free list... */
+  if (eat->free_head)
+    {
+     if (!cache->free_head)
+       cache->free_head = eat->free_head;
+     else if (eat->total_count - eat->alloc_count < cache->total_count - cache->alloc_count)
+       {
+         struct alloccache_free_ent *last = eat->free_head;
+         while (last->next)
+           last = last->next;
+         last->next = cache->free_head;
+         cache->free_head = eat->free_head;
+       }
+     else
+       {
+         struct alloccache_free_ent *last = cache->free_head;
+         while (last->next)
+           last = last->next;
+         last->next = eat->free_head;
+       }
+    }
+
+  /* ... and the free space. */
+  while (eat->free_start != eat->free_end)
+    {
+      struct alloccache_free_ent *f = (struct alloccache_free_ent *)eat->free_start;
+      eat->free_start += eat->size;
+      f->next = cache->free_head;
+      cache->free_head = f;
+    }
+
+  /* and statistics */
+  cache->alloc_count += eat->alloc_count;
+  cache->total_count += eat->total_count;
+#else
+  /* and statistics */
+  cache->alloc_count += eat->alloc_count;
+  cache->total_count += eat->alloc_count;
+#endif
+
+  /* unlink and disable the eat cache */
+  if (alloccache_head == eat)
+    alloccache_head = eat->next;
+  else
+    {
+      struct alloccache *cur = alloccache_head;
+      while (cur->next != eat)
+        cur = cur->next;
+      assert (cur && cur->next == eat);
+      cur->next = eat->next;
+    }
+
+  eat->size = 0;
+  eat->free_end = eat->free_start = NULL;
+  eat->free_head = NULL;
+}
+
+/* Print one alloc cache. */
+void
+alloccache_print (struct alloccache *cache)
+{
+  printf (_("\n# Alloc Cache: %s item size: %u  alloc: %d  total: %u\n"),
+          cache->name, cache->size, (int)cache->alloc_count, cache->total_count);
+}
+
+/* Print all alloc caches. */
+void
+alloccache_print_all (void)
+{
+  struct alloccache *cur;
+  for (cur = alloccache_head; cur; cur = cur->next)
+    alloccache_print (cur);
+}
+
+#endif /* CONFIG_WITH_ALLOC_CACHES */
Index: trunk/src/kmk/read.c
===================================================================
--- trunk/src/kmk/read.c	(revision 1862)
+++ trunk/src/kmk/read.c	(revision 1863)
@@ -1017,8 +1017,13 @@
 	  /* Parse the list of file names.  */
 	  p2 = p;
+#ifndef CONFIG_WITH_ALLOC_CACHES
 	  files = multi_glob (parse_file_seq (&p2, '\0',
 					      sizeof (struct nameseq),
 					      1),
 			      sizeof (struct nameseq));
+#else
+          files = multi_glob (parse_file_seq (&p2, '\0', &nameseq_cache, 1),
+                              &nameseq_cache);
+#endif
 	  free (p);
 
@@ -1038,5 +1043,9 @@
               int r;
 
+#ifndef CONFIG_WITH_ALLOC_CACHES
 	      free (files);
+#else
+	      alloccache_free (&nameseq_cache, files);
+#endif
 	      files = next;
 
@@ -1251,8 +1260,13 @@
            looking for targets.  */
         *colonp = '\0';
+#ifndef CONFIG_WITH_ALLOC_CACHES
         filenames = multi_glob (parse_file_seq (&p2, '\0',
                                                 sizeof (struct nameseq),
                                                 1),
                                 sizeof (struct nameseq));
+#else
+        filenames = multi_glob (parse_file_seq (&p2, '\0', &nameseq_cache, 1),
+                                &nameseq_cache);
+#endif
         *p2 = ':';
 
@@ -1406,5 +1420,9 @@
           {
             struct nameseq *target;
+#ifndef CONFIG_WITH_ALLOC_CACHES
             target = parse_file_seq (&p2, ':', sizeof (struct nameseq), 1);
+#else
+            target = parse_file_seq (&p2, ':', &nameseq_cache, 1);
+#endif
             ++p2;
             if (target == 0)
@@ -1416,5 +1434,9 @@
             if (pattern_percent == 0)
               fatal (fstart, _("target pattern contains no `%%' (target `%s')"), target->name); /* bird */
+#ifndef CONFIG_WITH_ALLOC_CACHES
             free (target);
+#else
+            alloccache_free (&nameseq_cache, target);
+#endif
           }
         else
@@ -2424,5 +2446,9 @@
 
       nextf = filenames->next;
+#ifndef CONFIG_WITH_ALLOC_CACHES
       free (filenames);
+#else
+      alloccache_free (&nameseq_cache, filenames);
+#endif
 
       /* Check for special targets.  Do it here instead of, say, snap_deps()
@@ -2959,6 +2985,11 @@
    If STRIP is nonzero, strip `./'s off the beginning.  */
 
+#ifndef CONFIG_WITH_ALLOC_CACHES
 struct nameseq *
 parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
+#else
+struct nameseq *
+parse_file_seq (char **stringp, int stopchar, struct alloccache *cache, int strip)
+#endif
 {
   struct nameseq *new = 0;
@@ -3079,11 +3110,8 @@
 
       /* Add it to the front of the chain.  */
-#if !defined(KMK) || !defined(NO_ARCHIVES)
+#ifndef CONFIG_WITH_ALLOC_CACHES
       new1 = xmalloc (size);
 #else
-      if (sizeof (struct dep) == size) /* use the cache */
-        new1 = (struct nameseq *)alloc_dep ();
-      else
-        new1 = xmalloc (size);
+      new1 = (struct nameseq *)alloccache_alloc (cache);
 #endif
       new1->name = name;
@@ -3138,5 +3166,9 @@
 		   Edit it out of the chain and free its storage.  */
 		lastn->next = n->next;
+#ifndef CONFIG_WITH_ALLOC_CACHES
 		free (n);
+#else
+                alloccache_free (cache, n);
+#endif
 		/* LASTN->next is the new stopping elt for the loop below.  */
 		n = lastn->next;
@@ -3158,5 +3190,9 @@
 		lastn = new1;
 		new1 = new1->next;
+#ifndef CONFIG_WITH_ALLOC_CACHES
 		free (lastn);
+#else
+                alloccache_free (cache, lastn);
+#endif
 	      }
 	    else
@@ -3794,6 +3830,11 @@
    that have room for additional info.  */
 
+#ifndef CONFIG_WITH_ALLOC_CACHES
 struct nameseq *
 multi_glob (struct nameseq *chain, unsigned int size)
+#else
+struct nameseq *
+multi_glob (struct nameseq *chain, struct alloccache *cache)
+#endif
 {
   void dir_setup_glob (glob_t *);
@@ -3896,11 +3937,10 @@
 #endif /* !NO_ARCHIVES */
 		  {
-#if !defined(KMK) && !defined(NO_ARCHIVES)
+#ifndef CONFIG_WITH_ALLOC_CACHES
 		    struct nameseq *elt = xmalloc (size);
-#else
-		    struct nameseq *elt = size == sizeof(struct dep)
-                                        ? (void *)alloc_dep() : xmalloc (size);
-#endif
                     memset (elt, '\0', size);
+#else
+		    struct nameseq *elt = alloccache_calloc (cache);
+#endif
 		    elt->name = strcache_add (gl.gl_pathv[i]);
 		    elt->next = new;
@@ -3912,11 +3952,8 @@
 #endif
 	    globfree (&gl);
-#if !defined(KMK) && !defined(NO_ARCHIVES)
+#ifndef CONFIG_WITH_ALLOC_CACHES
 	    free (old);
 #else
-	    if (size == sizeof(struct dep))
-	      free_dep ((struct dep *)old);
-	    else
-	      free (old);
+            alloccache_free (cache, old);
 #endif
 	    break;
Index: trunk/src/kmk/rule.c
===================================================================
--- trunk/src/kmk/rule.c	(revision 1862)
+++ trunk/src/kmk/rule.c	(revision 1863)
@@ -380,7 +380,13 @@
 
   ptr = p->dep;
+#ifndef CONFIG_WITH_ALLOC_CACHES
   r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0',
                                                        sizeof (struct dep), 1),
 				       sizeof (struct dep));
+#else
+  r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0',
+						       &dep_cache, 1),
+				       &dep_cache);
+#endif
 
   if (new_pattern_rule (r, 0))
Index: trunk/src/kmk/variable.c
===================================================================
--- trunk/src/kmk/variable.c	(revision 1862)
+++ trunk/src/kmk/variable.c	(revision 1863)
@@ -429,5 +429,7 @@
 variable_hash_cmp_2_inlined (const char *xs, const char *ys, unsigned int length)
 {
+#ifndef ELECTRIC_HEAP
   assert ( !((size_t)ys & 3) );
+#endif
   if (!((size_t)xs & 3))
     {
