* m4/assertion.m4: Fixed copyright header.
[cacao.git] / src / mm / memory.c
index 85ea79ea85b5c600f6b2f3470ca50e6020090125..4071d6bb430149a4d0736161ef8bda2edb4a664f 100644 (file)
@@ -1,9 +1,7 @@
-/* toolbox/memory.c - 
+/* src/mm/memory.c - memory management
 
-   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
-   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
-   P. Tomsich, J. Wenninger
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    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
-
-   $Id: memory.c 1621 2004-11-30 13:06:55Z 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>
 
 #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 "vm/exceptions.h"
-#include "vm/global.h"
-#include "vm/options.h"
-#include "vm/statistics.h"
+
 #include "native/native.h"
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-# include "threads/native/threads.h"
-#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/stringlocal.h"
+#include "vm/vm.h"
 
-/********* general types, variables and auxiliary functions *********/
-
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+#include "vmcore/options.h"
 
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
 
-/*******************************************************************************
+#include "vmcore/system.h"
 
-    This structure is used for dump memory allocation if cacao runs without
-    threads.
 
-*******************************************************************************/
+/* memory_mprotect *************************************************************
 
-#if !defined(USE_THREADS)
-static dumpinfo nothreads_dumpinfo;
-#endif
+   Convenience function for mprotect.  This function also does error
+   checking.
 
+*******************************************************************************/
 
-void *mem_mmap(s4 size)
+void memory_mprotect(void *addr, size_t len, int prot)
 {
-       void *m;
+       if (system_mprotect(addr, len, prot) != 0)
+               vm_abort("memory_mprotect: system_mprotect failed: %s",
+                                strerror(errno));
+}
 
-       size = ALIGN(size, ALIGNSIZE);
-
-       if (size > mmapcodesize) {
-               mmapcodesize = 0x10000;
-
-               if (size > mmapcodesize)
-                       mmapcodesize = size;
-
-               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,
-#else
-                                                  0,
-#endif
-                                                  -1,
-                                                  (off_t) 0);
 
-               if (mmapcodeptr == MAP_FAILED)
-                       throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                          "Out of memory");
-       }
+/* memory_checked_alloc ********************************************************
 
-       m = mmapcodeptr;
-       mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
-       mmapcodesize -= size;
+   Allocated zeroed-out memory and does an OOM check.
 
-       return m;
-}
+   ERROR HANDLING:
+      XXX If no memory could be allocated, this function justs *exists*.
 
+*******************************************************************************/
 
-static void *checked_alloc(s4 size)
+void *memory_checked_alloc(size_t 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;
 }
 
 
 void *mem_alloc(s4 size)
 {
+       void *m;
+
        if (size == 0)
                return NULL;
 
+#if defined(ENABLE_STATISTICS)
        if (opt_stat) {
                memoryusage += size;
 
                if (memoryusage > maxmemusage)
                        maxmemusage = memoryusage;
        }
-       
-       return checked_alloc(size);
+#endif
+
+       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;
 }
 
 
@@ -150,19 +134,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(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;
 }
@@ -173,163 +171,95 @@ 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(ENABLE_STATISTICS)
        if (opt_stat)
                memoryusage -= size;
+#endif
+
+#if defined(ENABLE_MEMCHECK)
+       /* destroy the contents */
+       memset(m, MEMORY_CLEAR_BYTE, size);
+#endif
 
        free(m);
 }
 
 
-void *dump_alloc(s4 size)
-{
-       void *m;
-       dumpinfo *di;
-
-       /* If no threads are used, the dumpinfo structure is a static structure   */
-       /* defined at the top of this file.                                       */
-#if defined(USE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
+/* memory_thread ***************************************************************
 
-       if (size == 0)
-               return NULL;
+   Prints regularly memory statistics.
 
-       size = ALIGN(size, ALIGNSIZE);
+*******************************************************************************/
 
-       if (di->useddumpsize + size > di->allocateddumpsize) {
-               dumpblock *newdumpblock;
-               s4 newdumpblocksize;
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+       int32_t seconds;
 
-               /* allocate a new dumplist structure */
-               newdumpblock = checked_alloc(sizeof(dumpblock));
+       /* If both arguments are specified, use the value of
+          ProfileMemoryUsage. */
 
-               /* 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;
+       if (opt_ProfileGCMemoryUsage)
+               seconds = opt_ProfileGCMemoryUsage;
 
-               } else {
-                       newdumpblocksize = DUMPBLOCKSIZE;
-               }
+       if (opt_ProfileMemoryUsage)
+               seconds = opt_ProfileMemoryUsage;
 
-               /* allocate dumpblock memory */
-               /*printf("new dumpblock: %d\n", newdumpblocksize);*/
-               newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
+       while (true) {
+               /* sleep thread */
 
-               newdumpblock->prev = di->currentdumpblock;
-               newdumpblock->size = newdumpblocksize;
-               di->currentdumpblock = newdumpblock;
+               threads_sleep(seconds * 1000, 0);
 
-               /* 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;
+# if defined(ENABLE_STATISTICS)
+               /* Print current date and time (only when we print to the
+                  stdout). */
 
-               /* increase the allocated dump size by the size of the new dump block */
-               di->allocateddumpsize += newdumpblocksize;
+               if (!opt_ProfileMemoryUsageGNUPlot)
+                       statistics_print_date();
 
-               /* the amount of globally allocated dump memory (thread save)         */
-               if (opt_stat)
-                       globalallocateddumpsize += newdumpblocksize;
-       }
+               /* print memory usage */
 
-       /* 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);
+               if (opt_ProfileMemoryUsage)
+                       statistics_print_memory_usage();
 
-       /* increase used dump size by the allocated memory size                   */
-       di->useddumpsize += size;
+               /* print GC memory usage */
 
-       if (opt_stat) {
-               if (di->useddumpsize > maxdumpsize) {
-                       maxdumpsize = di->useddumpsize;
-               }
+               if (opt_ProfileGCMemoryUsage)
+                       statistics_print_gc_memory_usage();
+# endif
        }
-               
-       return m;
-}   
-
-
-void *dump_realloc(void *src, s4 len1, s4 len2)
-{
-       void *dst = dump_alloc(len2);
-
-       memcpy(dst, src, len1);
-
-       return dst;
 }
-
-
-void dump_release(s4 size)
-{
-       dumpinfo *di;
-
-       /* If no threads are used, the dumpinfo structure is a static structure   */
-       /* defined at the top of this file.                                       */
-#if defined(USE_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);
 
-       /* reset the used dump size to the size specified                         */
-       di->useddumpsize = size;
+/* memory_start_thread *********************************************************
 
-       while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
-               dumpblock *tmp = di->currentdumpblock;
+   Starts the memory profiling thread.
 
-#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
+*******************************************************************************/
 
-               di->allocateddumpsize -= tmp->size;
-               di->currentdumpblock = tmp->prev;
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+bool memory_start_thread(void)
+{
+       utf *name;
 
-               /* the amount of globally allocated dump memory (thread save)         */
-               if (opt_stat)
-                       globalallocateddumpsize -= tmp->size;
+       name = utf_new_char("Memory Profiler");
 
-               /* release the dump memory and the dumpinfo structure                 */
-               free(tmp->dumpmem);
-               free(tmp);
-       }
-}
+       /* start the memory profiling thread */
 
+       if (!threads_thread_start_internal(name, memory_thread))
+               return false;
 
-s4 dump_size()
-{
-       dumpinfo *di;
-
-       /* If no threads are used, the dumpinfo structure is a static structure   */
-       /* defined at the top of this file.                                       */
-#if defined(USE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
+       /* everything's ok */
 
-       if (!di)
-               return 0;
-
-       return di->useddumpsize;
+       return true;
 }
+#endif
 
 
 /*
@@ -343,4 +273,5 @@ s4 dump_size()
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */