* Removed all Id tags.
[cacao.git] / src / mm / memory.c
index 7b1b5d9fa61de5d6598dabe636806af533425fbf..9c3034491c051994ef2c9aeaf20061b81fb5308d 100644 (file)
@@ -1,9 +1,9 @@
-/* src/mm/memory.c - 
+/* src/mm/memory.c - memory management
 
-   Copyright (C) 1996-2005 R. Grafl, A. Krall, C. Kruegel, C. Oates,
-   R. Obermaisser, M. Platter, M. Probst, S. Ring, E. Steiner,
-   C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, J. Wenninger,
-   Institut f. Computersprachen - TU Wien
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
 
    This file is part of CACAO.
 
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.
-
-   Contact: cacao@complang.tuwien.ac.at
-
-   Authors: Reinhard Grafl
-
-   Changes: Christian Thalinger
-
-   $Id: memory.c 2463 2005-05-12 23:54:07Z twisti $
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
 */
 
 
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
 
 #if defined(__DARWIN__)
-/* If we compile with -ansi on darwin, <sys/types.h> is not included. So      */
-/* let's do it here.                                                          */
+/* If we compile with -ansi on darwin, <sys/types.h> is not
+   included. So let's do it here. */
 # include <sys/types.h>
 #endif
 
-#include <sys/mman.h>
-#include <unistd.h>
+#include "vm/types.h"
+
+#include "arch.h"
 
-#include "config.h"
 #include "mm/memory.h"
+
 #include "native/native.h"
 
-#if defined(USE_THREADS)
-# if defined(NATIVE_THREADS)
-#  include "threads/native/threads.h"
-# else
-#  include "threads/green/threads.h"
-# endif
-#endif
+#include "threads/lock-common.h"
+#include "threads/threads-common.h"
 
 #include "toolbox/logging.h"
+
 #include "vm/exceptions.h"
 #include "vm/global.h"
-#include "vm/options.h"
-#include "vm/statistics.h"
 #include "vm/stringlocal.h"
+#include "vm/vm.h"
 
+#include "vmcore/options.h"
+
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
 
-/********* general types, variables and auxiliary functions *********/
 
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+/* constants for ENABLE_MEMCHECK **********************************************/
+
+#if defined(ENABLE_MEMCHECK)
+#define MEMORY_CANARY_SIZE          16
+#define MEMORY_CANARY_FIRST_BYTE    0xca
+#define MEMORY_CLEAR_BYTE           0xa5
+#endif /* defined(ENABLE_MEMCHECK) */
 
 
 /*******************************************************************************
 
-    This structure is used for dump memory allocation if cacao runs without
-    threads.
+  This structure is used for dump memory allocation if cacao
+  runs without threads.
 
 *******************************************************************************/
 
-#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
-static dumpinfo nothreads_dumpinfo;
+#if !defined(ENABLE_THREADS)
+static dumpinfo_t _no_threads_dumpinfo;
+#endif
+
+#if defined(ENABLE_THREADS)
+#define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
+#else
+#define DUMPINFO    &_no_threads_dumpinfo
+#endif
+
+
+/* global code memory variables ***********************************************/
+
+#define DEFAULT_CODE_MEMORY_SIZE    128 * 1024 /* defaulting to 128kB         */
+
+#if defined(ENABLE_THREADS)
+static java_object_t *lock_code_memory = NULL;
 #endif
+static void          *code_memory      = NULL;
+static int            code_memory_size = 0;
+static int            pagesize         = 0;
+
 
+/* memory_init *****************************************************************
 
-void *mem_mmap(s4 size)
+   Initialize the memory subsystem.
+
+*******************************************************************************/
+
+bool memory_init(void)
 {
-       void *m;
+#if defined(ENABLE_THREADS)
+       /* create lock for code memory */
 
-       size = ALIGN(size, ALIGNSIZE);
+       lock_code_memory = NEW(java_object_t);
 
-       if (size > mmapcodesize) {
-               mmapcodesize = 0x10000;
+       lock_init_object_lock(lock_code_memory);
+#endif
+
+       /* get the pagesize of this architecture */
+
+       pagesize = getpagesize();
 
-               if (size > mmapcodesize)
-                       mmapcodesize = size;
+       /* everything's ok */
+
+       return true;
+}
 
-               mmapcodesize = ALIGN(mmapcodesize, getpagesize());
-               mmapcodeptr = mmap(NULL,
-                                                  (size_t) mmapcodesize,
-                                                  PROT_READ | PROT_WRITE | PROT_EXEC,
-                                                  MAP_PRIVATE |
-#if defined(HAVE_MAP_ANONYMOUS)
-                                                  MAP_ANONYMOUS,
-#elif defined(HAVE_MAP_ANON)
-                                                  MAP_ANON,
+
+/* memory_mmap_anon ************************************************************
+
+   Maps anonymous memory, even on systems not defining
+   MAP_ANON(YMOUS).
+
+*******************************************************************************/
+
+void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
+{
+       void *p;
+
+#if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
+       p = mmap(addr, len, prot,
+# if defined(MAP_ANON)
+                        MAP_ANON | flags,
+# else
+                        MAP_ANONYMOUS | flags,
+# endif
+                        -1, 0);
 #else
-                                                  0,
-#endif
-                                                  -1,
-                                                  (off_t) 0);
+       int fd;
 
-               if (mmapcodeptr == MAP_FAILED)
-                       throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                          "Out of memory");
-       }
+       fd = open("/dev/zero", O_RDONLY, 0);
 
-       m = mmapcodeptr;
-       mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
-       mmapcodesize -= size;
+       if (fd == -1)
+               vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
 
-       return m;
+       p = mmap(addr, len, prot, flags, fd, 0);
+#endif
+
+#if defined(MAP_FAILED)
+       if (p == MAP_FAILED)
+#else
+       if (p == (void *) -1)
+#endif
+               vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
+
+       return p;
 }
 
 
-static void *checked_alloc(s4 size)
+/* memory_checked_alloc ********************************************************
+
+   Allocated zeroed-out memory and does an OOM check.
+
+   ERROR HANDLING:
+      XXX If no memory could be allocated, this function justs *exists*.
+
+*******************************************************************************/
+
+static void *memory_checked_alloc(s4 size)
 {
        /* always allocate memory zeroed out */
-       void *m = calloc(size, 1);
 
-       if (!m)
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Out of memory");
+       void *p = calloc(size, 1);
 
-       return m;
+       if (p == NULL)
+               vm_abort("memory_checked_alloc: calloc failed: out of memory");
+
+       return p;
+}
+
+
+/* memory_cnew *****************************************************************
+
+   Allocates memory from the heap via mmap and make the memory read-,
+   write-, and executeable.
+
+*******************************************************************************/
+
+void *memory_cnew(s4 size)
+{
+       void *p;
+
+       LOCK_MONITOR_ENTER(lock_code_memory);
+
+       size = MEMORY_ALIGN(size, ALIGNSIZE);
+
+       /* check if enough memory is available */
+
+       if (size > code_memory_size) {
+               /* set default code size */
+
+               code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
+
+               /* do we need more? */
+
+               if (size > code_memory_size)
+                       code_memory_size = size;
+
+               /* align the size of the memory to be allocated */
+
+               code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
+
+#if defined(ENABLE_STATISTICS)
+               if (opt_stat) {
+                       codememusage += code_memory_size;
+
+                       if (codememusage > maxcodememusage)
+                               maxcodememusage = codememusage;
+               }
+#endif
+
+               /* allocate the memory */
+
+               p = memory_mmap_anon(NULL, code_memory_size,
+                                                        PROT_READ | PROT_WRITE | PROT_EXEC,
+                                                        MAP_PRIVATE);
+
+               /* set global code memory pointer */
+
+               code_memory = p;
+       }
+
+       /* get a memory chunk of the allocated memory */
+
+       p = code_memory;
+
+       code_memory       = (void *) ((ptrint) code_memory + size);
+       code_memory_size -= size;
+
+       LOCK_MONITOR_EXIT(lock_code_memory);
+
+       return p;
+}
+
+
+/* memory_cfree ****************************************************************
+
+   Frees the code memory pointed to.
+
+   ATTENTION: This function currently does NOTHING!  Because we don't
+   have a memory management for code memory.
+
+*******************************************************************************/
+
+void memory_cfree(void *p, s4 size)
+{
+       /* do nothing */
 }
 
 
 void *mem_alloc(s4 size)
 {
+       void *m;
+
        if (size == 0)
                return NULL;
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat) {
                memoryusage += size;
 
@@ -151,7 +289,15 @@ void *mem_alloc(s4 size)
        }
 #endif
 
-       return checked_alloc(size);
+       m = memory_checked_alloc(size);
+
+#if defined(ENABLE_MEMCHECK)
+       /* XXX we would like to poison the memory, but callers rely on */
+       /* the zeroing. This should change sooner or later.            */
+       /* memset(m, MEMORY_CLEAR_BYTE, size); */
+#endif
+
+       return m;
 }
 
 
@@ -159,21 +305,33 @@ void *mem_realloc(void *src, s4 len1, s4 len2)
 {
        void *dst;
 
-       if (!src) {
+       /* prevent compiler warnings */
+
+       dst = NULL;
+
+       if (src == NULL)
                if (len1 != 0)
-                       panic("reallocating memoryblock with address NULL, length != 0");
-       }
+                       vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat)
                memoryusage = (memoryusage - len1) + len2;
 #endif
 
+#if defined(ENABLE_MEMCHECK)
+       if (len2 < len1)
+               memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
+#endif
+
        dst = realloc(src, len2);
 
-       if (!dst)
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Out of memory");
+       if (dst == NULL)
+               vm_abort("mem_realloc: realloc failed: out of memory");
+
+#if defined(ENABLE_MEMCHECK)
+       if (len2 > len1)
+               memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
+#endif
 
        return dst;
 }
@@ -184,45 +342,225 @@ void mem_free(void *m, s4 size)
        if (!m) {
                if (size == 0)
                        return;
-               panic("returned memoryblock with address NULL, length != 0");
+
+               log_text("returned memoryblock with address NULL, length != 0");
+               assert(0);
        }
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat)
                memoryusage -= size;
 #endif
 
+#if defined(ENABLE_MEMCHECK)
+       /* destroy the contents */
+       memset(m, MEMORY_CLEAR_BYTE, size);
+#endif
+
        free(m);
 }
 
 
+/* memory_thread ***************************************************************
+
+   Prints regularly memory statistics.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+       int32_t seconds;
+
+       /* If both arguments are specified, use the value of
+          ProfileMemoryUsage. */
+
+       if (opt_ProfileGCMemoryUsage)
+               seconds = opt_ProfileGCMemoryUsage;
+
+       if (opt_ProfileMemoryUsage)
+               seconds = opt_ProfileMemoryUsage;
+
+       while (true) {
+               /* sleep thread */
+
+               threads_sleep(seconds * 1000, 0);
+
+# if defined(ENABLE_STATISTICS)
+               /* Print current date and time (only when we print to the
+                  stdout). */
+
+               if (!opt_ProfileMemoryUsageGNUPlot)
+                       statistics_print_date();
+
+               /* print memory usage */
+
+               if (opt_ProfileMemoryUsage)
+                       statistics_print_memory_usage();
+
+               /* print GC memory usage */
+
+               if (opt_ProfileGCMemoryUsage)
+                       statistics_print_gc_memory_usage();
+# endif
+       }
+}
+#endif
+
+
+/* memory_start_thread *********************************************************
+
+   Starts the memory profiling thread.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+bool memory_start_thread(void)
+{
+       utf *name;
+
+       name = utf_new_char("Memory Profiler");
+
+       /* start the memory profiling thread */
+
+       if (!threads_thread_start_internal(name, memory_thread))
+               return false;
+
+       /* everything's ok */
+
+       return true;
+}
+#endif
+
+
+/* dump_check_canaries *********************************************************
+
+   Check canaries in dump memory.
+
+   IN:
+      di...........dumpinfo_t * of the dump area to check
+         bottomsize...dump size down to which the dump area should be checked
+                      (specify 0 to check the whole dump area)
+
+   ERROR HANDLING:
+      If any canary has been changed, this function aborts the VM with
+         an error message.
+
+*******************************************************************************/
+
+#if defined(ENABLE_MEMCHECK)
+void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
+{
+       dump_allocation_t *da;
+       u1 *pm;
+       s4 i, j;
+
+       /* iterate over all dump memory allocations above bottomsize */
+
+       da = di->allocations;
+       while (da && da->useddumpsize >= bottomsize) {
+               /* check canaries */
+
+               pm = da->mem - MEMORY_CANARY_SIZE;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
+                               fprintf(stderr, "canary bytes:");
+                               for (j=0; j<MEMORY_CANARY_SIZE; ++j)
+                                       fprintf(stderr, " %02x", pm[j]);
+                               fprintf(stderr,"\n");
+                               vm_abort("error: dump memory bottom canary killed: "
+                                                "%p (%d bytes allocated at %p)\n",
+                                               pm + i, da->size, da->mem);
+                       }
+
+               pm = da->mem + da->size;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
+                               fprintf(stderr, "canary bytes:");
+                               for (j=0; j<MEMORY_CANARY_SIZE; ++j)
+                                       fprintf(stderr, " %02x", pm[j]);
+                               fprintf(stderr,"\n");
+                               vm_abort("error: dump memory top canary killed: "
+                                                "%p (%d bytes allocated at %p)\n",
+                                               pm + i, da->size, da->mem);
+                       }
+
+               da = da->next;
+       }
+}
+#endif /* defined(ENABLE_MEMCHECK) */
+
+
+/* dump_alloc ******************************************************************
+
+   Allocate memory in the dump area.
+
+   IN:
+      size.........size of block to allocate, in bytes
+                                  may be zero, in which case NULL is returned
+
+   RETURN VALUE:
+      pointer to allocated memory, or
+         NULL iff `size` was zero
+
+   ERROR HANDLING:
+      XXX This function uses `memory_checked_alloc`, which *exits* if no 
+         memory could be allocated.
+
+   THREADS:
+      dump_alloc is thread safe. Each thread has its own dump memory area.
+
+   dump_alloc is a fast allocator suitable for scratch memory that can be
+   collectively freed when the current activity (eg. compiling) is done.
+
+   You cannot selectively free dump memory. Before you start allocating it, 
+   you remember the current size returned by `dump_size`. Later, when you no 
+   longer need the memory, call `dump_release` with the remembered size and
+   all dump memory allocated since the call to `dump_size` will be freed.
+
+*******************************************************************************/
+
 void *dump_alloc(s4 size)
 {
-       void *m;
-       dumpinfo *di;
+#if defined(DISABLE_DUMP)
+
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       return mem_alloc(size);
+
+#else /* !defined(DISABLE_DUMP) */
+
+       void       *m;
+       dumpinfo_t *di;
+#if defined(ENABLE_MEMCHECK)
+       s4          origsize = size; /* needed for the canary system */
+#endif
 
        /* If no threads are used, the dumpinfo structure is a static structure   */
        /* defined at the top of this file.                                       */
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
+
+       di = DUMPINFO;
 
        if (size == 0)
                return NULL;
 
-       size = ALIGN(size, ALIGNSIZE);
+#if defined(ENABLE_MEMCHECK)
+       size += 2*MEMORY_CANARY_SIZE;
+#endif
+
+       size = MEMORY_ALIGN(size, ALIGNSIZE);
 
        if (di->useddumpsize + size > di->allocateddumpsize) {
-               dumpblock *newdumpblock;
-               s4 newdumpblocksize;
+               dumpblock_t *newdumpblock;
+               s4         newdumpblocksize;
 
                /* allocate a new dumplist structure */
-               newdumpblock = checked_alloc(sizeof(dumpblock));
+
+               newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
 
                /* If requested size is greater than the default, make the new dump   */
                /* block as big as the size requested. Else use the default size.     */
+
                if (size > DUMPBLOCKSIZE) {
                        newdumpblocksize = size;
 
@@ -231,8 +569,8 @@ void *dump_alloc(s4 size)
                }
 
                /* allocate dumpblock memory */
-               /*printf("new dumpblock: %d\n", newdumpblocksize);*/
-               newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
+
+               newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
 
                newdumpblock->prev = di->currentdumpblock;
                newdumpblock->size = newdumpblocksize;
@@ -240,14 +578,16 @@ void *dump_alloc(s4 size)
 
                /* Used dump size is previously allocated dump size, because the      */
                /* remaining free memory of the previous dump block cannot be used.   */
-               /*printf("unused memory: %d\n", allocateddumpsize - useddumpsize);*/
+
                di->useddumpsize = di->allocateddumpsize;
 
                /* increase the allocated dump size by the size of the new dump block */
+
                di->allocateddumpsize += newdumpblocksize;
 
-#if defined(STATISTICS)
-               /* the amount of globally allocated dump memory (thread save)         */
+#if defined(ENABLE_STATISTICS)
+               /* the amount of globally allocated dump memory (thread save) */
+
                if (opt_stat)
                        globalallocateddumpsize += newdumpblocksize;
 #endif
@@ -255,99 +595,205 @@ void *dump_alloc(s4 size)
 
        /* current dump block base address + the size of the current dump block - */
        /* the size of the unused memory = new start address                      */
+
        m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
                (di->allocateddumpsize - di->useddumpsize);
 
-       /* increase used dump size by the allocated memory size                   */
+#if defined(ENABLE_MEMCHECK)
+       {
+               dump_allocation_t *da = NEW(dump_allocation_t);
+               s4 i;
+               u1 *pm;
+
+               /* add the allocation to our linked list of allocations */
+
+               da->next = di->allocations;
+               da->mem = (u1*) m + MEMORY_CANARY_SIZE;
+               da->size = origsize;
+               da->useddumpsize = di->useddumpsize;
+
+               di->allocations = da;
+
+               /* write the canaries */
+
+               pm = (u1*)m;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
+               pm = da->mem + da->size;
+               for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+                       pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
+
+               /* make m point after the bottom canary */
+
+               m = (u1*)m + MEMORY_CANARY_SIZE;
+
+               /* clear the memory */
+
+               memset(m, MEMORY_CLEAR_BYTE, da->size);
+       }
+#endif /* defined(ENABLE_MEMCHECK) */
+
+       /* increase used dump size by the allocated memory size */
+
        di->useddumpsize += size;
 
-#if defined(STATISTICS)
-       if (opt_stat) {
-               if (di->useddumpsize > maxdumpsize) {
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               if (di->useddumpsize > maxdumpsize)
                        maxdumpsize = di->useddumpsize;
-               }
-       }
 #endif
-               
+
        return m;
-}   
 
+#endif /* defined(DISABLE_DUMP) */
+}
+
+
+/* dump_realloc ****************************************************************
+
+   Stupid realloc implementation for dump memory. Avoid, if possible.
+
+*******************************************************************************/
 
 void *dump_realloc(void *src, s4 len1, s4 len2)
 {
+#if defined(DISABLE_DUMP)
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       return mem_realloc(src, len1, len2);
+#else
        void *dst = dump_alloc(len2);
 
        memcpy(dst, src, len1);
 
+#if defined(ENABLE_MEMCHECK)
+       /* destroy the source */
+       memset(src, MEMORY_CLEAR_BYTE, len1);
+#endif
+
        return dst;
+#endif
 }
 
 
+/* dump_release ****************************************************************
+
+   Release dump memory above the given size.
+
+   IN:
+       size........All dump memory above this mark will be freed. Usually
+                      `size` will be the return value of a `dump_size` call
+                                  made earlier.
+
+       ERROR HANDLING:
+          XXX If the given size is invalid, this function *exits* with an
+              error message.
+                                  
+       See `dump_alloc`.
+
+*******************************************************************************/
+
 void dump_release(s4 size)
 {
-       dumpinfo *di;
+#if defined(DISABLE_DUMP)
+
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       /* do nothing */
+
+#else /* !defined(DISABLE_DUMP) */
+
+       dumpinfo_t *di;
 
        /* If no threads are used, the dumpinfo structure is a static structure   */
        /* defined at the top of this file.                                       */
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
 
-       if (size < 0 || size > di->useddumpsize)
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Illegal dump release size %d", size);
+       di = DUMPINFO;
+
+       if ((size < 0) || (size > di->useddumpsize))
+               vm_abort("Illegal dump release size: %d", size);
+
+#if defined(ENABLE_MEMCHECK)
+       {
+               dump_allocation_t *da, *next;
+
+               /* check canaries */
+
+               dump_check_canaries(di, size);
+
+               /* iterate over all dump memory allocations about to be released */
+
+               da = di->allocations;
+               while (da && da->useddumpsize >= size) {
+                       next = da->next;
+
+                       /* invalidate the freed memory */
+
+                       memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
+
+                       FREE(da, dump_allocation_t);
+
+                       da = next;
+               }
+               di->allocations = da;
+       }
+#endif /* defined(ENABLE_MEMCHECK) */
+
+       /* reset the used dump size to the size specified */
 
-       /* reset the used dump size to the size specified                         */
        di->useddumpsize = size;
 
        while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
-               dumpblock *tmp = di->currentdumpblock;
-
-#if 0
-               /* XXX TWISTI: can someone explain this to me? */
-#ifdef TRACECALLARGS
-               /* Keep the first dumpblock if we don't free memory. Otherwise
-                * a new dumpblock is allocated each time and we run out of
-                * memory.
-                */
-               if (!oldtop->prev) break;
-#endif
-#endif
+               dumpblock_t *tmp = di->currentdumpblock;
 
                di->allocateddumpsize -= tmp->size;
                di->currentdumpblock = tmp->prev;
 
-#if defined(STATISTICS)
-               /* the amount of globally allocated dump memory (thread save)         */
+#if defined(ENABLE_STATISTICS)
+               /* the amount of globally allocated dump memory (thread save) */
+
                if (opt_stat)
                        globalallocateddumpsize -= tmp->size;
 #endif
 
-               /* release the dump memory and the dumpinfo structure                 */
+               /* release the dump memory and the dumpinfo structure */
+
                free(tmp->dumpmem);
                free(tmp);
        }
+
+#endif /* defined(DISABLE_DUMP) */
 }
 
 
-s4 dump_size()
+/* dump_size *******************************************************************
+
+   Return the current size of the dump memory area. See `dump_alloc`.
+
+*******************************************************************************/
+
+s4 dump_size(void)
 {
-       dumpinfo *di;
+#if defined(DISABLE_DUMP)
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       return 0;
+
+#else /* !defined(DISABLE_DUMP) */
+
+       dumpinfo_t *di;
 
        /* If no threads are used, the dumpinfo structure is a static structure   */
        /* defined at the top of this file.                                       */
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
 
-       if (!di)
+       di = DUMPINFO;
+
+       if (di == NULL)
                return 0;
 
        return di->useddumpsize;
+
+#endif /* defined(DISABLE_DUMP) */
 }
 
 
@@ -362,4 +808,5 @@ s4 dump_size()
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */