* m4/assertion.m4: Fixed copyright header.
[cacao.git] / src / mm / memory.c
index 7b007bd98bf507d8237512a6e219234fd84d29a7..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 557 2003-11-02 22:51:59Z 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 <assert.h>
 #include <string.h>
-#include <sys/mman.h>
 #include <unistd.h>
 
-#include "global.h"
-#include "loging.h"
-#include "memory.h"
-
-
-/********* general types, variables and auxiliary functions *********/
-
-#define DUMPBLOCKSIZE  (2<<21)
-#define ALIGNSIZE           8
-
-typedef struct dumplist {
-       struct dumplist *prev;
-       char *dumpmem;
-} dumplist;
-
-
-
-long int memoryusage = 0;
+#if defined(__DARWIN__)
+/* If we compile with -ansi on darwin, <sys/types.h> is not
+   included. So let's do it here. */
+# include <sys/types.h>
+#endif
 
-long int dumpsize = 0;
-long int dumpspace = 0;
-dumplist *topdumpblock = NULL;
+#include "vm/types.h"
 
-long int maxmemusage = 0;
-long int maxdumpsize = 0;
+#include "arch.h"
 
-#define TRACECALLARGS
+#include "mm/memory.h"
 
-#ifdef TRACECALLARGS
-static char *nomallocmem = NULL;
-static char *nomalloctop;
-static char *nomallocptr;
+#include "native/native.h"
 
+#include "threads/lock-common.h"
+#include "threads/threads-common.h"
 
-static void *lit_checked_alloc (int length)
-{
-       void *m;
+#include "toolbox/logging.h"
 
-       if (!nomallocmem) {
-               nomallocmem = malloc(16777216); 
-               nomalloctop = nomallocmem + 16777216;
-               nomallocptr = nomallocmem;
-       }
-
-       nomallocptr = (void*) ALIGN ((long) nomallocptr, ALIGNSIZE);
-       
-       m = nomallocptr;
-       nomallocptr += length;
-       if (nomallocptr > nomalloctop) panic ("Out of memory");
-       return m;
-}
+#include "vm/exceptions.h"
+#include "vm/global.h"
+#include "vm/stringlocal.h"
+#include "vm/vm.h"
 
-#else
-
-static void *lit_checked_alloc (int length)
-{
-       void *m = malloc(length);
-       if (!m) panic ("Out of memory");
-       return m;
-}
+#include "vmcore/options.h"
 
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
 #endif
 
+#include "vmcore/system.h"
 
-static void *checked_alloc (int length)
-{
-       void *m = malloc(length);
-       if (!m) panic ("Out of memory");
-       return m;
-}
 
+/* memory_mprotect *************************************************************
 
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+   Convenience function for mprotect.  This function also does error
+   checking.
 
+*******************************************************************************/
 
-void *mem_mmap(int length)
+void memory_mprotect(void *addr, size_t len, int prot)
 {
-       void *retptr;
-
-       length = (ALIGN(length,ALIGNSIZE));
-       if (length > mmapcodesize) {
-               mmapcodesize = 0x10000;
-               if (length > mmapcodesize)
-                       mmapcodesize = length;
-               mmapcodesize = (ALIGN(mmapcodesize, getpagesize()));
-               mmapcodeptr = mmap (NULL, (size_t) mmapcodesize,
-                                                       PROT_READ | PROT_WRITE | PROT_EXEC,
-                                                       MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0);
-               if (mmapcodeptr == (void*) -1)
-                       panic ("Out of memory");
-       }
-       retptr = mmapcodeptr;
-       mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
-       mmapcodesize -= length;
-       return retptr;
+       if (system_mprotect(addr, len, prot) != 0)
+               vm_abort("memory_mprotect: system_mprotect failed: %s",
+                                strerror(errno));
 }
 
 
-#ifdef DEBUG
-
-/************ Memory manager, safe version **************/
-
+/* memory_checked_alloc ********************************************************
 
-typedef struct memblock {
-       struct memblock *prev,*next;
-       int length;
-} memblock;
+   Allocated zeroed-out memory and does an OOM check.
 
-#define BLOCKOFFSET    (ALIGN(sizeof(memblock),ALIGNSIZE))
+   ERROR HANDLING:
+      XXX If no memory could be allocated, this function justs *exists*.
 
-struct memblock *firstmemblock;
+*******************************************************************************/
 
-
-
-void *mem_alloc(int length)
+void *memory_checked_alloc(size_t size)
 {
-       memblock *mb;
-
-       if (length==0) return NULL;
-       mb = checked_alloc (length + BLOCKOFFSET);
+       /* always allocate memory zeroed out */
 
-       mb -> prev = NULL;
-       mb -> next = firstmemblock;     
-       mb -> length = length;
+       void *p = calloc(size, 1);
 
-       if (firstmemblock) firstmemblock -> prev = mb;
-       firstmemblock = mb;
+       if (p == NULL)
+               vm_abort("memory_checked_alloc: calloc failed: out of memory");
 
-       memoryusage += length;
-       if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-
-       return ((char*) mb) + BLOCKOFFSET;
+       return p;
 }
 
 
-void *lit_mem_alloc(int length)
+void *mem_alloc(s4 size)
 {
-       memblock *mb;
-
-       if (length==0) return NULL;
-       mb = lit_checked_alloc (length + BLOCKOFFSET);
-
-       mb -> prev = NULL;
-       mb -> next = firstmemblock;     
-       mb -> length = length;
-
-       if (firstmemblock) firstmemblock -> prev = mb;
-       firstmemblock = mb;
-
-       memoryusage += length;
-       if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-
-       return ((char*) mb) + BLOCKOFFSET;
-}
+       void *m;
 
+       if (size == 0)
+               return NULL;
 
-void mem_free(void *m, int length)
-{
-       memblock *mb;
-       if (!m) {
-               if (length==0) return;
-               panic ("returned memoryblock with address NULL, length != 0");
-       }
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat) {
+               memoryusage += size;
 
-       mb = (memblock*) (((char*) m) - BLOCKOFFSET);
-       
-       if (mb->length != length) {
-               sprintf (logtext, 
-                                "Memory block of size %d has been return as size %d",
-                        mb->length, length);
-               error();
+               if (memoryusage > maxmemusage)
+                       maxmemusage = memoryusage;
        }
-               
-       if (mb->prev) mb->prev->next = mb->next;
-       else firstmemblock = mb->next;
-       if (mb->next) mb->next->prev = mb->prev;
-
-       free (mb);
-
-       memoryusage -= length;
-}
+#endif
 
+       m = memory_checked_alloc(size);
 
-void lit_mem_free(void *m, int length)
-{
-       memblock *mb;
-       if (!m) {
-               if (length==0) return;
-               panic ("returned memoryblock with address NULL, length != 0");
-       }
-
-       mb = (memblock*) (((char*) m) - BLOCKOFFSET);
-       
-       if (mb->length != length) {
-               sprintf (logtext, 
-                                "Memory block of size %d has been return as size %d",
-                        mb->length, length);
-               error();
-       }
-               
-       if (mb->prev) mb->prev->next = mb->next;
-       else firstmemblock = mb->next;
-       if (mb->next) mb->next->prev = mb->prev;
-
-#ifdef TRACECALLARGS
-#else
-       free (mb);
+#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
 
-       memoryusage -= length;
+       return m;
 }
 
 
-void *mem_realloc (void *m1, int len1, int len2)
+void *mem_realloc(void *src, s4 len1, s4 len2)
 {
-       void *m2;
-       
-       m2 = mem_alloc (len2);
-       memcpy (m2, m1, len1);
-       mem_free (m1, len1);
+       void *dst;
 
-       return m2;
-}
+       /* prevent compiler warnings */
 
+       dst = NULL;
 
+       if (src == NULL)
+               if (len1 != 0)
+                       vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
 
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               memoryusage = (memoryusage - len1) + len2;
+#endif
 
-static void mem_characterlog (unsigned char *m, int len)
-{
-#      define LINESIZE 16
-       int z,i;
-       
-       for (z=0; z<len; z+=LINESIZE) {
-               sprintf (logtext, "   ");
-                       
-               for (i=z; i<(z+LINESIZE) && i<len; i++) {
-                       sprintf (logtext+strlen(logtext), "%2x ", m[i]);
-               }
-               for (; i<(z+LINESIZE); i++) {
-                       sprintf (logtext+strlen(logtext), "   ");
-               }
-                                       
-               sprintf (logtext+strlen(logtext),"   ");
-               for (i=z; i<(z+LINESIZE) && i<len; i++) {
-                       sprintf (logtext+strlen(logtext),
-                                        "%c", (m[i]>=' ' && m[i]<=127) ? m[i] : '.');
-               }
-                       
-               dolog();
-       }
-}
-
-#else
-/******* Memory manager, fast version ******/
-
+#if defined(ENABLE_MEMCHECK)
+       if (len2 < len1)
+               memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
+#endif
 
-void *mem_alloc(int length)
-{
-       if (length==0) return NULL;
+       dst = realloc(src, len2);
 
-       memoryusage += length;
-       if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-       
-       return checked_alloc (length);
-}
+       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
 
-void *lit_mem_alloc(int length)
-{
-       if (length==0) return NULL;
-
-       memoryusage += length;
-       if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-       
-       return lit_checked_alloc (length);
+       return dst;
 }
 
 
-void mem_free(void *m, int length)
+void mem_free(void *m, s4 size)
 {
        if (!m) {
-               if (length==0) return;
-               panic ("returned memoryblock with address NULL, length != 0");
-       }
-
-       memoryusage -= length;
-
-       free (m);
-}
-
+               if (size == 0)
+                       return;
 
-void lit_mem_free(void *m, int length)
-{
-       if (!m) {
-               if (length==0) return;
-               panic ("returned memoryblock with address NULL, length != 0");
+               log_text("returned memoryblock with address NULL, length != 0");
+               assert(0);
        }
 
-       memoryusage -= length;
+#if defined(ENABLE_STATISTICS)
+       if (opt_stat)
+               memoryusage -= size;
+#endif
 
-#ifdef TRACECALLARGS
-#else
-       free (m);
+#if defined(ENABLE_MEMCHECK)
+       /* destroy the contents */
+       memset(m, MEMORY_CLEAR_BYTE, size);
 #endif
+
+       free(m);
 }
 
 
-void *mem_realloc (void *m1, int len1, int len2)
-{
-       void *m2;
+/* memory_thread ***************************************************************
 
-       if (!m1) {
-               if (len1!=0) 
-                       panic ("reallocating memoryblock with address NULL, length != 0");
-       }
-               
-       memoryusage = (memoryusage - len1) + len2;
+   Prints regularly memory statistics.
 
-       m2 = realloc (m1, len2);
-       if (!m2) panic ("Out of memory");
-       return m2;
-}
+*******************************************************************************/
 
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+       int32_t seconds;
 
-#endif
+       /* If both arguments are specified, use the value of
+          ProfileMemoryUsage. */
 
-/******* common memory manager parts ******/
+       if (opt_ProfileGCMemoryUsage)
+               seconds = opt_ProfileGCMemoryUsage;
 
-long int mem_usage()
-{
-       return memoryusage;
-}
+       if (opt_ProfileMemoryUsage)
+               seconds = opt_ProfileMemoryUsage;
 
+       while (true) {
+               /* sleep thread */
 
-void *dump_alloc(int length)
-{
-       void *m;
+               threads_sleep(seconds * 1000, 0);
 
-       if (length == 0) return NULL;
-       
-       length = ALIGN(length, ALIGNSIZE);
+# if defined(ENABLE_STATISTICS)
+               /* Print current date and time (only when we print to the
+                  stdout). */
 
-       assert(length <= DUMPBLOCKSIZE);
-       assert(length > 0);
+               if (!opt_ProfileMemoryUsageGNUPlot)
+                       statistics_print_date();
 
-       if (dumpsize + length > dumpspace) {
-               dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
+               /* print memory usage */
 
-               newdumpblock->prev = topdumpblock;
-               topdumpblock = newdumpblock;
+               if (opt_ProfileMemoryUsage)
+                       statistics_print_memory_usage();
 
-               newdumpblock->dumpmem = checked_alloc(DUMPBLOCKSIZE);
+               /* print GC memory usage */
 
-               dumpsize = dumpspace;
-               dumpspace += DUMPBLOCKSIZE;             
-       }
-       
-       m = topdumpblock->dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize);
-       dumpsize += length;
-       
-       if (dumpsize > maxdumpsize) {
-               maxdumpsize = dumpsize;
+               if (opt_ProfileGCMemoryUsage)
+                       statistics_print_gc_memory_usage();
+# endif
        }
-               
-       return m;
-}   
-
-
-void *dump_realloc(void *ptr, int len1, int len2)
-{
-       void *p2 = dump_alloc(len2);
-       memcpy(p2, ptr, len1);  
-       return p2;
 }
+#endif
 
 
-long int dump_size()
-{
-       return dumpsize;
-}
+/* memory_start_thread *********************************************************
+
+   Starts the memory profiling thread.
 
+*******************************************************************************/
 
-void dump_release(long int size)
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+bool memory_start_thread(void)
 {
-       assert(size >= 0 && size <= dumpsize);
-
-       dumpsize = size;
-       
-       while (dumpspace > dumpsize + DUMPBLOCKSIZE) {
-               dumplist *oldtop = topdumpblock;
-               
-               topdumpblock = oldtop->prev;
-               dumpspace -= DUMPBLOCKSIZE;
-               
-#ifdef TRACECALLARGS
-#else
-               free(oldtop->dumpmem);
-               free(oldtop);
-#endif
-       }               
-}
+       utf *name;
 
+       name = utf_new_char("Memory Profiler");
 
-void mem_usagelog (int givewarnings)
-{
-       if ((memoryusage!=0) && givewarnings) {
-               sprintf (logtext, "Allocated memory not returned: %d",
-                                (int)memoryusage);
-               dolog();
-
-#ifdef DEBUG
-               { 
-                       memblock *mb = firstmemblock;
-                       while (mb) {
-                               sprintf (logtext, "   Memory block size: %d", 
-                                                (int)(mb->length) );
-                               dolog();
-                               mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
-                               mb = mb->next;
-                       }
-               }
-#endif
-                       
-       }
+       /* start the memory profiling thread */
 
-       if ((dumpsize!=0) && givewarnings) {
-               sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize);
-               dolog();
-       }
+       if (!threads_thread_start_internal(name, memory_thread))
+               return false;
 
+       /* everything's ok */
 
-       sprintf(logtext, "Random/Dump - memory usage: %dK/%dK", 
-                       (int)((maxmemusage+1023)/1024), 
-                       (int)((maxdumpsize+1023)/1024) );
-       dolog();
-       
+       return true;
 }
+#endif
 
 
 /*
@@ -489,4 +273,5 @@ void mem_usagelog (int givewarnings)
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */