* m4/assertion.m4: Fixed copyright header.
[cacao.git] / src / mm / memory.c
index 0f257dd3f19cd4da1983dda4423b75421bcb1ffb..4071d6bb430149a4d0736161ef8bda2edb4a664f 100644 (file)
@@ -1,9 +1,7 @@
 /* src/mm/memory.c - memory management
 
-   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
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
 
    This file is part of CACAO.
 
@@ -22,8 +20,6 @@
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   $Id: memory.c 7813 2007-04-25 19:20:13Z twisti $
-
 */
 
 
@@ -35,7 +31,6 @@
 #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
 # include "vmcore/statistics.h"
 #endif
 
-
-/* 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.
-
-*******************************************************************************/
-
-#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_objectheader *lock_code_memory = NULL;
-#endif
-static void              *code_memory      = NULL;
-static int                code_memory_size = 0;
-static int                pagesize         = 0;
-
-
-/* global variables ***********************************************************/
-
-#if defined(ENABLE_THREADS)
-static threadobject *thread_memory;
-#endif
-
-
-/* memory_init *****************************************************************
-
-   Initialize the memory subsystem.
-
-*******************************************************************************/
-
-bool memory_init(void)
-{
-#if defined(ENABLE_THREADS)
-       /* create lock for code memory */
-
-       lock_code_memory = NEW(java_objectheader);
-
-       lock_init_object_lock(lock_code_memory);
-#endif
-
-       /* get the pagesize of this architecture */
-
-       pagesize = getpagesize();
-
-       /* everything's ok */
-
-       return true;
-}
+#include "vmcore/system.h"
 
 
-/* memory_mmap_anon ************************************************************
+/* memory_mprotect *************************************************************
 
-   Maps anonymous memory, even on systems not defining
-   MAP_ANON(YMOUS).
+   Convenience function for mprotect.  This function also does error
+   checking.
 
 *******************************************************************************/
 
-void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
+void memory_mprotect(void *addr, size_t len, int prot)
 {
-       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
-       int fd;
-
-       fd = open("/dev/zero", O_RDONLY, 0);
-
-       if (fd == -1)
-               vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
-
-       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;
+       if (system_mprotect(addr, len, prot) != 0)
+               vm_abort("memory_mprotect: system_mprotect failed: %s",
+                                strerror(errno));
 }
 
 
@@ -190,7 +89,7 @@ void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
 
 *******************************************************************************/
 
-static void *memory_checked_alloc(s4 size)
+void *memory_checked_alloc(size_t size)
 {
        /* always allocate memory zeroed out */
 
@@ -203,85 +102,6 @@ static void *memory_checked_alloc(s4 size)
 }
 
 
-/* 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;
@@ -379,19 +199,38 @@ void mem_free(void *m, s4 size)
 #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 for 2 seconds */
+               /* sleep thread */
 
-               threads_sleep(2 * 1000, 0);
+               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 */
 
-               statistics_print_memory_usage();
+               if (opt_ProfileMemoryUsage)
+                       statistics_print_memory_usage();
 
                /* print GC memory usage */
 
-               statistics_print_gc_memory_usage();
+               if (opt_ProfileGCMemoryUsage)
+                       statistics_print_gc_memory_usage();
 # endif
        }
 }
@@ -411,15 +250,11 @@ bool memory_start_thread(void)
 
        name = utf_new_char("Memory Profiler");
 
-       thread_memory = threads_thread_create_internal(name);
+       /* start the memory profiling thread */
 
-       if (thread_memory == NULL)
+       if (!threads_thread_start_internal(name, memory_thread))
                return false;
 
-       /* actually start the memory profiling thread */
-
-       threads_start_thread(thread_memory, memory_thread);
-
        /* everything's ok */
 
        return true;
@@ -427,370 +262,6 @@ bool memory_start_thread(void)
 #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)
-{
-#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.                                       */
-
-       di = DUMPINFO;
-
-       if (size == 0)
-               return NULL;
-
-#if defined(ENABLE_MEMCHECK)
-       size += 2*MEMORY_CANARY_SIZE;
-#endif
-
-       size = MEMORY_ALIGN(size, ALIGNSIZE);
-
-       if (di->useddumpsize + size > di->allocateddumpsize) {
-               dumpblock_t *newdumpblock;
-               s4         newdumpblocksize;
-
-               /* allocate a new dumplist structure */
-
-               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;
-
-               } else {
-                       newdumpblocksize = DUMPBLOCKSIZE;
-               }
-
-               /* allocate dumpblock memory */
-
-               newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
-
-               newdumpblock->prev = di->currentdumpblock;
-               newdumpblock->size = newdumpblocksize;
-               di->currentdumpblock = newdumpblock;
-
-               /* Used dump size is previously allocated dump size, because the      */
-               /* remaining free memory of the previous dump block cannot be used.   */
-
-               di->useddumpsize = di->allocateddumpsize;
-
-               /* increase the allocated dump size by the size of the new dump block */
-
-               di->allocateddumpsize += newdumpblocksize;
-
-#if defined(ENABLE_STATISTICS)
-               /* the amount of globally allocated dump memory (thread save) */
-
-               if (opt_stat)
-                       globalallocateddumpsize += newdumpblocksize;
-#endif
-       }
-
-       /* 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 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(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)
-{
-#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.                                       */
-
-       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 */
-
-       di->useddumpsize = size;
-
-       while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
-               dumpblock_t *tmp = di->currentdumpblock;
-
-               di->allocateddumpsize -= tmp->size;
-               di->currentdumpblock = tmp->prev;
-
-#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 */
-
-               free(tmp->dumpmem);
-               free(tmp);
-       }
-
-#endif /* defined(DISABLE_DUMP) */
-}
-
-
-/* dump_size *******************************************************************
-
-   Return the current size of the dump memory area. See `dump_alloc`.
-
-*******************************************************************************/
-
-s4 dump_size(void)
-{
-#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.                                       */
-
-       di = DUMPINFO;
-
-       if (di == NULL)
-               return 0;
-
-       return di->useddumpsize;
-
-#endif /* defined(DISABLE_DUMP) */
-}
-
-
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where