GNU header update.
[cacao.git] / src / mm / memory.c
index 6a33e12f27d453e89a02195070f67a5d04948900..134ecdb5fd64bfa920f4f8861c2bdacd2f8e0ce2 100644 (file)
@@ -1,9 +1,9 @@
 /* toolbox/memory.c - 
 
-   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 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.
 
 
    Authors: Reinhard Grafl
 
-   $Id: memory.c 1141 2004-06-05 23:19:24Z twisti $
+   $Id: memory.c 1735 2004-12-07 14:33:27Z twisti $
 
 */
 
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <string.h>
+
+#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
+
 #include <sys/mman.h>
 #include <unistd.h>
 
-#include "global.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)
+# if defined(NATIVE_THREADS)
+#  include "threads/native/threads.h"
+# else
+#  include "threads/green/threads.h"
+# endif
+#endif
+
 #include "toolbox/logging.h"
-#include "toolbox/memory.h"
 
 
 /********* general types, variables and auxiliary functions *********/
 
-#define DUMPBLOCKSIZE  (2<<21)
-#define ALIGNSIZE           8
-
-typedef struct dumplist {
-       struct dumplist *prev;
-       char *dumpmem;
-       int size;
-} dumplist;
-
-
+static int mmapcodesize = 0;
+static void *mmapcodeptr = NULL;
 
-long int memoryusage = 0;
 
-long int dumpsize = 0;
-long int dumpspace = 0;
-dumplist *topdumpblock = NULL;
+/*******************************************************************************
 
-long int maxmemusage = 0;
-long int maxdumpsize = 0;
+    This structure is used for dump memory allocation if cacao runs without
+    threads.
 
-#define TRACECALLARGS
+*******************************************************************************/
 
-#ifdef TRACECALLARGS
-static char *nomallocmem = NULL;
-static char *nomalloctop;
-static char *nomallocptr;
+#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
+static dumpinfo nothreads_dumpinfo;
+#endif
 
 
-static void *lit_checked_alloc (int length)
+void *mem_mmap(s4 size)
 {
        void *m;
 
-       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");
+       size = ALIGN(size, ALIGNSIZE);
 
-       return m;
-}
+       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
-
-static void *lit_checked_alloc(int length)
-{
-       void *m = malloc(length);
-       if (!m) panic ("Out of memory");
-       return m;
-}
-
+                                                  0,
 #endif
+                                                  -1,
+                                                  (off_t) 0);
 
-
-static void *checked_alloc(int length)
-{
-       void *m = malloc(length);
-       if (!m) panic("Out of memory");
-       return m;
-}
-
-
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
-
-
-void *mem_mmap(int length)
-{
-       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");
+               if (mmapcodeptr == MAP_FAILED)
+                       throw_cacao_exception_exit(string_java_lang_InternalError,
+                                                                          "Out of memory");
        }
-       retptr = mmapcodeptr;
-       mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
-       mmapcodesize -= length;
-       return retptr;
-}
 
+       m = mmapcodeptr;
+       mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
+       mmapcodesize -= size;
 
-#ifdef DEBUG
-
-/************ Memory manager, safe version **************/
-
-
-typedef struct memblock {
-       struct memblock *prev, *next;
-       int length;
-} memblock;
-
-#define BLOCKOFFSET    (ALIGN(sizeof(memblock),ALIGNSIZE))
-
-struct memblock *firstmemblock;
-
-
-
-void *mem_alloc(int length)
-{
-       memblock *mb;
-
-       if (length == 0) return NULL;
-       mb = 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;
+       return m;
 }
 
 
-void *lit_mem_alloc(int length)
+static void *checked_alloc(s4 size)
 {
-       memblock *mb;
+       /* always allocate memory zeroed out */
+       void *m = calloc(size, 1);
 
-       if (length == 0) return NULL;
-       mb = lit_checked_alloc(length + BLOCKOFFSET);
+       if (!m)
+               throw_cacao_exception_exit(string_java_lang_InternalError,
+                                                                  "Out of memory");
 
-       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;
+       return m;
 }
 
 
-void mem_free(void *m, int length)
+void *mem_alloc(s4 size)
 {
-       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;
-
-       free (mb);
-
-       memoryusage -= length;
-}
+       if (size == 0)
+               return NULL;
 
+       if (opt_stat) {
+               memoryusage += 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");
+               if (memoryusage > maxmemusage)
+                       maxmemusage = memoryusage;
        }
-
-       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);
-#endif
-
-       memoryusage -= length;
+       return checked_alloc(size);
 }
 
 
-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);
-
-       return m2;
-}
-
-
+       void *dst;
 
-
-static void mem_characterlog(unsigned char *m, int len)
-{
-#      define LINESIZE 16
-       int z, i;
-       char logtext[MAXLOGTEXT];
-       
-       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] : '.');
-               }
-                       
-               log_text(logtext);
+       if (!src) {
+               if (len1 != 0)
+                       panic("reallocating memoryblock with address NULL, length != 0");
        }
-}
 
-#else
-/******* Memory manager, fast version ******/
+       if (opt_stat)
+               memoryusage = (memoryusage - len1) + len2;
 
+       dst = realloc(src, len2);
 
-void *mem_alloc(int length)
-{
-       if (length == 0) return NULL;
+       if (!dst)
+               throw_cacao_exception_exit(string_java_lang_InternalError,
+                                                                  "Out of memory");
 
-       memoryusage += length;
-       if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-       
-       return checked_alloc(length);
+       return dst;
 }
 
 
-void *lit_mem_alloc(int length)
-{
-       if (length == 0) return NULL;
-
-       memoryusage += length;
-       if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-       
-       return lit_checked_alloc(length);
-}
-
-
-void mem_free(void *m, int length)
+void mem_free(void *m, s4 size)
 {
        if (!m) {
-               if (length == 0) return;
+               if (size == 0)
+                       return;
                panic("returned memoryblock with address NULL, length != 0");
        }
 
-       memoryusage -= length;
+       if (opt_stat)
+               memoryusage -= size;
 
        free(m);
 }
 
 
-void lit_mem_free(void *m, int length)
+void *dump_alloc(s4 size)
 {
-       if (!m) {
-               if (length == 0) return;
-               panic("returned memoryblock with address NULL, length != 0");
-       }
-
-       memoryusage -= length;
+       void *m;
+       dumpinfo *di;
 
-#ifdef TRACECALLARGS
+       /* 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
-       free(m);
+       di = &nothreads_dumpinfo;
 #endif
-}
 
+       if (size == 0)
+               return NULL;
 
-void *mem_realloc (void *m1, int len1, int len2)
-{
-       void *m2;
+       size = ALIGN(size, ALIGNSIZE);
 
-       if (!m1) {
-               if (len1!=0) 
-                       panic ("reallocating memoryblock with address NULL, length != 0");
-       }
-               
-       memoryusage = (memoryusage - len1) + len2;
+       if (di->useddumpsize + size > di->allocateddumpsize) {
+               dumpblock *newdumpblock;
+               s4 newdumpblocksize;
 
-       m2 = realloc (m1, len2);
-       if (!m2) panic ("Out of memory");
-       return m2;
-}
+               /* allocate a new dumplist structure */
+               newdumpblock = 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;
 
-#endif
+               } else {
+                       newdumpblocksize = DUMPBLOCKSIZE;
+               }
 
-/******* common memory manager parts ******/
+               /* allocate dumpblock memory */
+               /*printf("new dumpblock: %d\n", newdumpblocksize);*/
+               newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
 
-long int mem_usage()
-{
-       return memoryusage;
-}
+               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.   */
+               /*printf("unused memory: %d\n", allocateddumpsize - useddumpsize);*/
+               di->useddumpsize = di->allocateddumpsize;
 
-void *dump_alloc(int length)
-{
-       void *m;
-       int blocksize = DUMPBLOCKSIZE;
+               /* increase the allocated dump size by the size of the new dump block */
+               di->allocateddumpsize += newdumpblocksize;
 
-       if (length == 0) return NULL;
-       
-       length = ALIGN(length, ALIGNSIZE);
-
-       if (length > DUMPBLOCKSIZE)
-               blocksize = length;
-       assert(length > 0);
-
-       if (dumpsize + length > dumpspace) {
-               dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
+               /* the amount of globally allocated dump memory (thread save)         */
+               if (opt_stat)
+                       globalallocateddumpsize += newdumpblocksize;
+       }
 
-               newdumpblock->prev = topdumpblock;
-               newdumpblock->size = blocksize;
-               topdumpblock = newdumpblock;
+       /* 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);
 
-               newdumpblock->dumpmem = checked_alloc(blocksize);
+       /* increase used dump size by the allocated memory size                   */
+       di->useddumpsize += size;
 
-               dumpsize = dumpspace;
-               dumpspace += blocksize;
-       }
-       
-       m = topdumpblock->dumpmem + blocksize - (dumpspace - dumpsize);
-       dumpsize += length;
-       
-       if (dumpsize > maxdumpsize) {
-               maxdumpsize = dumpsize;
+       if (opt_stat) {
+               if (di->useddumpsize > maxdumpsize) {
+                       maxdumpsize = di->useddumpsize;
+               }
        }
                
        return m;
 }   
 
 
-void *dump_realloc(void *ptr, int len1, int len2)
+void *dump_realloc(void *src, s4 len1, s4 len2)
 {
-       void *p2 = dump_alloc(len2);
-       memcpy(p2, ptr, len1);  
-       return p2;
-}
+       void *dst = dump_alloc(len2);
 
+       memcpy(dst, src, len1);
 
-long int dump_size()
-{
-       return dumpsize;
+       return dst;
 }
 
 
-void dump_release(long int size)
+void dump_release(s4 size)
 {
-       assert(size >= 0 && size <= dumpsize);
+       dumpinfo *di;
 
-       dumpsize = size;
-       
-       while (topdumpblock && (dumpspace - topdumpblock->size >= dumpsize)) {
-               dumplist *oldtop = topdumpblock;
+       /* 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);
+
+       /* 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
@@ -445,48 +301,38 @@ void dump_release(long int size)
                 */
                if (!oldtop->prev) break;
 #endif
-               
-               dumpspace -= oldtop->size;
-               topdumpblock = oldtop->prev;
-               
-#ifdef TRACECALLARGS
-#else
-               free(oldtop->dumpmem);
-               free(oldtop);
 #endif
-       }               
+
+               di->allocateddumpsize -= tmp->size;
+               di->currentdumpblock = tmp->prev;
+
+               /* the amount of globally allocated dump memory (thread save)         */
+               if (opt_stat)
+                       globalallocateddumpsize -= tmp->size;
+
+               /* release the dump memory and the dumpinfo structure                 */
+               free(tmp->dumpmem);
+               free(tmp);
+       }
 }
 
 
-void mem_usagelog (int givewarnings)
+s4 dump_size()
 {
-       if ((memoryusage!=0) && givewarnings) {
-               dolog ("Allocated memory not returned: %d",
-                                (int)memoryusage);
-
-#ifdef DEBUG
-               { 
-                       memblock *mb = firstmemblock;
-                       while (mb) {
-                               dolog ("   Memory block size: %d", 
-                                                (int)(mb->length) );
-                               mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
-                               mb = mb->next;
-                       }
-               }
-#endif
-                       
-       }
+       dumpinfo *di;
 
-       if ((dumpsize!=0) && givewarnings) {
-               dolog ("Dump memory not returned: %d",(int)dumpsize);
-       }
+       /* 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)
+               return 0;
 
-       dolog("Random/Dump - memory usage: %dK/%dK", 
-                       (int)((maxmemusage+1023)/1024), 
-                       (int)((maxdumpsize+1023)/1024) );
-       
+       return di->useddumpsize;
 }