* Updated header: Added 2006. Changed address of FSF. Changed email
[cacao.git] / src / mm / memory.c
index 7b1b5d9fa61de5d6598dabe636806af533425fbf..8c685f3d2dbdb41ceb0423e93aaac136efc16c83 100644 (file)
@@ -1,9 +1,9 @@
 /* src/mm/memory.c - 
 
-   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 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.
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
 
-   Contact: cacao@complang.tuwien.ac.at
+   Contact: cacao@cacaojvm.org
 
    Authors: Reinhard Grafl
 
    Changes: Christian Thalinger
 
-   $Id: memory.c 2463 2005-05-12 23:54:07Z twisti $
+   $Id: memory.c 4357 2006-01-22 23:33:38Z twisti $
 
 */
 
 
+#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      */
 # include <sys/types.h>
 #endif
 
-#include <sys/mman.h>
-#include <unistd.h>
-
 #include "config.h"
+#include "vm/types.h"
+
+#include "arch.h"
+
 #include "mm/memory.h"
 #include "native/native.h"
 
 #include "vm/stringlocal.h"
 
 
-/********* general types, variables and auxiliary functions *********/
+/*******************************************************************************
 
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+  This structure is used for dump memory allocation if cacao
+  runswithout threads.
 
+*******************************************************************************/
+
+#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
+static dumpinfo _no_threads_dumpinfo;
+#endif
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+#define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
+#else
+#define DUMPINFO    &_no_threads_dumpinfo
+#endif
 
-/*******************************************************************************
 
-    This structure is used for dump memory allocation if cacao runs without
-    threads.
+/* global code memory variables ***********************************************/
+
+#define DEFAULT_CODEMEM_SIZE    128 * 1024  /* defaulting to 128kB            */
+
+#if defined(USE_THREADS)
+static java_objectheader *codememlock = NULL;
+#endif
+static int                codememsize = 0;
+static void              *codememptr  = NULL;
+
+
+/* memory_init *****************************************************************
+
+   Initialize the memory subsystem.
 
 *******************************************************************************/
 
-#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
-static dumpinfo nothreads_dumpinfo;
+bool memory_init(void)
+{
+#if defined(USE_THREADS)
+       codememlock = NEW(java_objectheader);
+
+# if defined(NATIVE_THREADS)
+       initObjectLock(codememlock);
+# endif
 #endif
 
+       /* everything's ok */
+
+       return true;
+}
+
+
+/* memory_checked_alloc ********************************************************
 
-void *mem_mmap(s4 size)
+   Allocated zeroed-out memory and does an OOM check.
+
+*******************************************************************************/
+
+static void *memory_checked_alloc(s4 size)
 {
-       void *m;
+       /* always allocate memory zeroed out */
+
+       void *p = calloc(size, 1);
+
+       if (!p)
+               exceptions_throw_outofmemory_exit();
+
+       return p;
+}
+
+
+/* memory_cnew *****************************************************************
+
+   Allocates memory from the heap, aligns it to architecutres PAGESIZE
+   and make the memory read-, write-, and executeable.
+
+*******************************************************************************/
+
+void *memory_cnew(s4 size)
+{
+       void *p;
+       int   pagesize;
+
+#if defined(USE_THREADS)
+       builtin_monitorenter(codememlock);
+#endif
 
        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,
+       /* check if enough memory is available */
+
+       if (size > codememsize) {
+               /* set default code size */
+
+               codememsize = DEFAULT_CODEMEM_SIZE;
+
+               /* do we need more? */
+
+               if (size > codememsize)
+                       codememsize = size;
+
+               /* get the pagesize of this architecture */
+
+               pagesize = getpagesize();
+
+               /* allocate normal heap memory */
+
+               if ((p = memory_checked_alloc(codememsize + pagesize - 1)) == NULL)
+                       return NULL;
+
+#if defined(ENABLE_STATISTICS)
+               if (opt_stat) {
+                       codememusage += codememsize + pagesize - 1;
+
+                       if (codememusage > maxcodememusage)
+                               maxcodememusage = codememusage;
+               }
 #endif
-                                                  -1,
-                                                  (off_t) 0);
 
-               if (mmapcodeptr == MAP_FAILED)
+               /* align the memory allocated to a multiple of PAGESIZE,
+                  mprotect requires this */
+
+               p = (void *) (((ptrint) p + pagesize - 1) & ~(pagesize - 1));
+
+               /* make the memory read-, write-, and executeable */
+
+               if (mprotect(p, codememsize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
                        throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                          "Out of memory");
-       }
+                                                                          strerror(errno));
 
-       m = mmapcodeptr;
-       mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
-       mmapcodesize -= size;
+               /* set global code memory pointer */
 
-       return m;
-}
+               codememptr = p;
+       }
 
+       /* get a memory chunk of the allocated memory */
 
-static void *checked_alloc(s4 size)
-{
-       /* always allocate memory zeroed out */
-       void *m = calloc(size, 1);
+       p = codememptr;
+       codememptr = (void *) ((ptrint) codememptr + size);
+       codememsize -= size;
 
-       if (!m)
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Out of memory");
+#if defined(USE_THREADS)
+       builtin_monitorexit(codememlock);
+#endif
 
-       return m;
+       return p;
 }
 
 
@@ -142,7 +224,7 @@ void *mem_alloc(s4 size)
        if (size == 0)
                return NULL;
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat) {
                memoryusage += size;
 
@@ -151,7 +233,7 @@ void *mem_alloc(s4 size)
        }
 #endif
 
-       return checked_alloc(size);
+       return memory_checked_alloc(size);
 }
 
 
@@ -160,11 +242,13 @@ void *mem_realloc(void *src, s4 len1, s4 len2)
        void *dst;
 
        if (!src) {
-               if (len1 != 0)
-                       panic("reallocating memoryblock with address NULL, length != 0");
+               if (len1 != 0) {
+                       log_text("reallocating memoryblock with address NULL, length != 0");
+                       assert(0);
+               }
        }
 
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
        if (opt_stat)
                memoryusage = (memoryusage - len1) + len2;
 #endif
@@ -172,8 +256,7 @@ void *mem_realloc(void *src, s4 len1, s4 len2)
        dst = realloc(src, len2);
 
        if (!dst)
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                  "Out of memory");
+               exceptions_throw_outofmemory_exit();
 
        return dst;
 }
@@ -184,10 +267,12 @@ 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
@@ -196,18 +281,26 @@ void mem_free(void *m, s4 size)
 }
 
 
+/* dump_alloc ******************************************************************
+
+   XXX
+
+*******************************************************************************/
+
 void *dump_alloc(s4 size)
 {
-       void *m;
+#if defined(DISABLE_DUMP)
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       return mem_alloc(size);
+#else
+       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) && defined(NATIVE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
+
+       di = DUMPINFO;
 
        if (size == 0)
                return NULL;
@@ -216,13 +309,15 @@ void *dump_alloc(s4 size)
 
        if (di->useddumpsize + size > di->allocateddumpsize) {
                dumpblock *newdumpblock;
-               s4 newdumpblocksize;
+               s4         newdumpblocksize;
 
                /* allocate a new dumplist structure */
-               newdumpblock = checked_alloc(sizeof(dumpblock));
+
+               newdumpblock = memory_checked_alloc(sizeof(dumpblock));
 
                /* 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 +326,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 +335,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,51 +352,73 @@ 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                   */
+       /* 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 ****************************************************************
 
+   XXX
+
+*******************************************************************************/
 
 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);
 
        return dst;
+#endif
 }
 
 
+/* dump_release ****************************************************************
+
+   XXX
+
+*******************************************************************************/
+
 void dump_release(s4 size)
 {
+#if defined(DISABLE_DUMP)
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       /* do nothing */
+#else
        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) && defined(NATIVE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
+
+       di = DUMPINFO;
 
        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                         */
+       /* reset the used dump size to the size specified */
+
        di->useddumpsize = size;
 
        while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
@@ -319,35 +438,47 @@ void dump_release(s4 size)
                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 *******************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+s4 dump_size(void)
 {
+#if defined(DISABLE_DUMP)
+       /* use malloc memory for dump memory (for debugging only!) */
+
+       return 0;
+#else
        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) && defined(NATIVE_THREADS)
-       di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
-       di = &nothreads_dumpinfo;
-#endif
+
+       di = DUMPINFO;
 
        if (!di)
                return 0;
 
        return di->useddumpsize;
+#endif /* defined(DISABLE_DUMP) */
 }