/* 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 = ¬hreads_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 = ¬hreads_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
*/
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 = ¬hreads_dumpinfo;
+#endif
+ if (!di)
+ return 0;
- dolog("Random/Dump - memory usage: %dK/%dK",
- (int)((maxmemusage+1023)/1024),
- (int)((maxdumpsize+1023)/1024) );
-
+ return di->useddumpsize;
}