X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fmm%2Fmemory.c;h=80951ee5e6e34f13bf88ea66b40586786d2385c9;hb=2f22fef9e8f80103c54b2bd06492340a4447a2af;hp=5f91f00ccdfe55d42df9295e0f5ba0399b4ce573;hpb=ede14e08771a169786f1351ebc3d92f56dccef10;p=cacao.git diff --git a/src/mm/memory.c b/src/mm/memory.c index 5f91f00cc..80951ee5e 100644 --- a/src/mm/memory.c +++ b/src/mm/memory.c @@ -1,9 +1,7 @@ -/* src/mm/memory.c - +/* src/mm/memory.c - memory management - 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 + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO This file is part of CACAO. @@ -22,104 +20,63 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Reinhard Grafl - - Changes: Christian Thalinger - Edwin Steiner - - $Id: memory.c 4798 2006-04-20 19:18:43Z edwin $ - */ +#include "config.h" + #include #include #include #include #include #include -#include #if defined(__DARWIN__) -/* If we compile with -ansi on darwin, is not included. So */ -/* let's do it here. */ +/* If we compile with -ansi on darwin, is not + included. So let's do it here. */ # include #endif -#include "config.h" #include "vm/types.h" #include "arch.h" #include "mm/memory.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 "threads/lock-common.h" +#include "threads/thread.h" #include "toolbox/logging.h" + #include "vm/exceptions.h" #include "vm/global.h" -#include "vm/options.h" -#include "vm/statistics.h" #include "vm/stringlocal.h" +#include "vm/vm.hpp" +#include "vmcore/options.h" -/******************************************************************************* - - This structure is used for dump memory allocation if cacao - runs without 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 +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" #endif - -/* 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; +#include "vmcore/system.h" -/* memory_init ***************************************************************** +/* memory_mprotect ************************************************************* - Initialize the memory subsystem. + Convenience function for mprotect. This function also does error + checking. *******************************************************************************/ -bool memory_init(void) +void memory_mprotect(void *addr, size_t len, int prot) { -#if defined(USE_THREADS) - codememlock = NEW(java_objectheader); - -# if defined(NATIVE_THREADS) - initObjectLock(codememlock); -# endif -#endif /* defined(USE_THREADS) */ - - /* everything's ok */ - - return true; + if (system_mprotect(addr, len, prot) != 0) + vm_abort("memory_mprotect: system_mprotect failed: %s", + strerror(errno)); } @@ -132,99 +89,23 @@ bool memory_init(void) *******************************************************************************/ -static void *memory_checked_alloc(s4 size) +void *memory_checked_alloc(size_t size) { /* always allocate memory zeroed out */ void *p = calloc(size, 1); - if (!p) - exceptions_throw_outofmemory_exit(); + if (p == NULL) + vm_abort("memory_checked_alloc: calloc failed: out of memory"); 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 *mem_alloc(int32_t size) { - void *p; - int pagesize; - -#if defined(USE_THREADS) - builtin_monitorenter(codememlock); -#endif - - size = ALIGN(size, ALIGNSIZE); - - /* 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; + void *m; - /* 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 - - /* 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, - strerror(errno)); - - /* set global code memory pointer */ - - codememptr = p; - } - - /* get a memory chunk of the allocated memory */ - - p = codememptr; - codememptr = (void *) ((ptrint) codememptr + size); - codememsize -= size; - -#if defined(USE_THREADS) - builtin_monitorexit(codememlock); -#endif - - return p; -} - - -void *mem_alloc(s4 size) -{ if (size == 0) return NULL; @@ -237,36 +118,55 @@ void *mem_alloc(s4 size) } #endif - return memory_checked_alloc(size); + m = memory_checked_alloc(size); + +#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 + + return m; } -void *mem_realloc(void *src, s4 len1, s4 len2) +void *mem_realloc(void *src, int32_t len1, int32_t len2) { void *dst; - if (!src) { - if (len1 != 0) { - log_text("reallocating memoryblock with address NULL, length != 0"); - assert(0); - } - } + /* 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 +#if defined(ENABLE_MEMCHECK) + if (len2 < len1) + memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2); +#endif + dst = realloc(src, len2); - if (!dst) - exceptions_throw_outofmemory_exit(); + 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 return dst; } -void mem_free(void *m, s4 size) +void mem_free(void *m, int32_t size) { if (!m) { if (size == 0) @@ -281,254 +181,89 @@ void mem_free(void *m, s4 size) memoryusage -= size; #endif - free(m); -} - - -/* 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 *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) - return NULL; - - size = ALIGN(size, ALIGNSIZE); - - if (di->useddumpsize + size > di->allocateddumpsize) { - dumpblock *newdumpblock; - s4 newdumpblocksize; - - /* allocate a new dumplist structure */ - - 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; - - } 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); - - /* 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; +#if defined(ENABLE_MEMCHECK) + /* destroy the contents */ + memset(m, MEMORY_CLEAR_BYTE, size); #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); - - return dst; -#endif + free(m); } -/* dump_release **************************************************************** - - Release dump memory above the given size. +/* memory_thread *************************************************************** - 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`. + Prints regularly memory statistics. *******************************************************************************/ -void dump_release(s4 size) +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +static void memory_thread(void) { -#if defined(DISABLE_DUMP) - - /* use malloc memory for dump memory (for debugging only!) */ + int32_t seconds; - /* do nothing */ + /* Prevent compiler warning. */ -#else /* !defined(DISABLE_DUMP) */ + seconds = 1; - dumpinfo *di; + /* If both arguments are specified, use the value of + ProfileMemoryUsage. */ - /* If no threads are used, the dumpinfo structure is a static structure */ - /* defined at the top of this file. */ + if (opt_ProfileGCMemoryUsage) + seconds = opt_ProfileGCMemoryUsage; - di = DUMPINFO; + if (opt_ProfileMemoryUsage) + seconds = opt_ProfileMemoryUsage; - if (size < 0 || size > di->useddumpsize) - throw_cacao_exception_exit(string_java_lang_InternalError, - "Illegal dump release size %d", size); + while (true) { + /* sleep thread */ - /* reset the used dump size to the size specified */ + threads_sleep(seconds * 1000, 0); - di->useddumpsize = size; +# if defined(ENABLE_STATISTICS) + /* Print current date and time (only when we print to the + stdout). */ - while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) { - dumpblock *tmp = di->currentdumpblock; + if (!opt_ProfileMemoryUsageGNUPlot) + statistics_print_date(); -#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 - * memory. - */ - if (!oldtop->prev) break; -#endif -#endif - - di->allocateddumpsize -= tmp->size; - di->currentdumpblock = tmp->prev; - -#if defined(ENABLE_STATISTICS) - /* the amount of globally allocated dump memory (thread save) */ + /* print memory usage */ - if (opt_stat) - globalallocateddumpsize -= tmp->size; -#endif + if (opt_ProfileMemoryUsage) + statistics_print_memory_usage(); - /* release the dump memory and the dumpinfo structure */ + /* print GC memory usage */ - free(tmp->dumpmem); - free(tmp); + if (opt_ProfileGCMemoryUsage) + statistics_print_gc_memory_usage(); +# endif } - -#endif /* defined(DISABLE_DUMP) */ } +#endif -/* dump_size ******************************************************************* +/* memory_start_thread ********************************************************* - Return the current size of the dump memory area. See `dump_alloc`. + Starts the memory profiling thread. *******************************************************************************/ -s4 dump_size(void) +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +bool memory_start_thread(void) { -#if defined(DISABLE_DUMP) - /* use malloc memory for dump memory (for debugging only!) */ - - return 0; + utf *name; -#else /* !defined(DISABLE_DUMP) */ + name = utf_new_char("Memory Profiler"); - dumpinfo *di; + /* start the memory profiling thread */ - /* If no threads are used, the dumpinfo structure is a static structure */ - /* defined at the top of this file. */ + if (!threads_thread_start_internal(name, memory_thread)) + return false; - di = DUMPINFO; - - if (!di) - return 0; - - return di->useddumpsize; + /* everything's ok */ -#endif /* defined(DISABLE_DUMP) */ + return true; } +#endif /*