X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fmm%2Fmemory.c;h=0774aee016228547abfe7b8d919478d22a72dc4a;hb=cce34f898a508bde05c54be7f19c0fbfeb2dc0a2;hp=c3a46253ac03cd4894058308511c088af6788d5a;hpb=724b31e6654e11e849cdc6297b2fbb746230eb62;p=cacao.git diff --git a/src/mm/memory.c b/src/mm/memory.c index c3a46253a..0774aee01 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,31 +20,17 @@ 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 5807 2006-10-20 00:37:37Z ajordan $ - */ #include "config.h" #include -#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 @@ -55,75 +39,37 @@ #include "arch.h" #include "mm/memory.h" -#include "native/native.h" - -#if defined(ENABLE_THREADS) -# include "threads/native/lock.h" -# include "threads/native/threads.h" -#else -# include "threads/none/lock.h" -#endif - -#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.h" - -/******************************************************************************* +#include "native/native.hpp" - 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 +#include "threads/lock.hpp" +#include "threads/thread.hpp" +#include "toolbox/logging.h" -/* global code memory variables ***********************************************/ +#include "vm/global.h" +#include "vm/string.hpp" +#include "vm/vm.hpp" -#define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */ +#include "vm/options.h" +#include "vm/os.hpp" -#if defined(ENABLE_THREADS) -static java_objectheader *lock_code_memory = NULL; +#if defined(ENABLE_STATISTICS) +# include "vm/statistics.h" #endif -static void *code_memory = NULL; -static int code_memory_size = 0; -static int pagesize = 0; -/* 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(ENABLE_THREADS) - 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; + if (os_mprotect(addr, len, prot) != 0) + vm_abort_errno("memory_mprotect: os_mprotect failed"); } @@ -136,124 +82,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); + void *p = os_calloc(size, 1); if (p == NULL) - exceptions_throw_outofmemory_exit(); + vm_abort("memory_checked_alloc: calloc failed: out of memory"); return p; } -/* memory_cnew ***************************************************************** - - Allocates memory from the heap via mmap and make the memory read-, - write-, and executeable. - -*******************************************************************************/ - -void *memory_cnew(s4 size) +void *mem_alloc(int32_t size) { - void *p; - - LOCK_MONITOR_ENTER(lock_code_memory); - - size = 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 = ALIGN(code_memory_size, pagesize); + void *m; -#if defined(ENABLE_STATISTICS) - if (opt_stat) { - codememusage += code_memory_size; - - if (codememusage > maxcodememusage) - maxcodememusage = codememusage; - } -#endif - - /* allocate the memory */ - -#if defined(MAP_ANONYMOUS) || defined(MAP_ANON) - p = mmap(NULL, - (size_t) code_memory_size, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | -# if defined(MAP_ANONYMOUS) - MAP_ANONYMOUS, -# elif defined(MAP_ANON) - MAP_ANON, -# else - 0, -# endif - -1, - (off_t) 0); - -# if defined(MAP_FAILED) - if (p == MAP_FAILED) -# else - if (p == (void *) -1) -# endif - vm_abort("mmap failed: %s", strerror(errno)); - -#else - /* This works a least on IRIX. */ - - p = memory_checked_alloc(code_memory_size); -#endif - - /* 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) -{ if (size == 0) return NULL; @@ -266,36 +111,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) + os_memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2); +#endif + dst = realloc(src, len2); if (dst == NULL) - exceptions_throw_outofmemory_exit(); + vm_abort("mem_realloc: realloc failed: out of memory"); + +#if defined(ENABLE_MEMCHECK) + if (len2 > len1) + os_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) @@ -310,242 +174,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_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) - return NULL; - - size = 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); - - /* 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 */ + os_memset(m, MEMORY_CLEAR_BYTE, size); #endif - return m; - -#endif /* defined(DISABLE_DUMP) */ + os_free(m); } -/* dump_realloc **************************************************************** +/* memory_thread *************************************************************** - Stupid realloc implementation for dump memory. Avoid, if possible. + Prints regularly memory statistics. *******************************************************************************/ -void *dump_realloc(void *src, s4 len1, s4 len2) +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +static void memory_thread(void) { -#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 -} + int32_t seconds; + /* Prevent compiler warning. */ -/* dump_release **************************************************************** + seconds = 1; - Release dump memory above the given size. + /* If both arguments are specified, use the value of + ProfileMemoryUsage. */ - 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. + if (opt_ProfileGCMemoryUsage) + seconds = opt_ProfileGCMemoryUsage; - ERROR HANDLING: - XXX If the given size is invalid, this function *exits* with an - error message. - - See `dump_alloc`. + if (opt_ProfileMemoryUsage) + seconds = opt_ProfileMemoryUsage; -*******************************************************************************/ + while (true) { + /* sleep thread */ -void dump_release(s4 size) -{ -#if defined(DISABLE_DUMP) + threads_sleep(seconds * 1000, 0); - /* use malloc memory for dump memory (for debugging only!) */ +# if defined(ENABLE_STATISTICS) + /* Print current date and time (only when we print to the + stdout). */ - /* do nothing */ + if (!opt_ProfileMemoryUsageGNUPlot) + statistics_print_date(); -#else /* !defined(DISABLE_DUMP) */ + /* print memory usage */ - dumpinfo_t *di; + if (opt_ProfileMemoryUsage) + statistics_print_memory_usage(); - /* If no threads are used, the dumpinfo structure is a static structure */ - /* defined at the top of this file. */ + /* print GC memory usage */ - di = DUMPINFO; - - if ((size < 0) || (size > di->useddumpsize)) - vm_abort("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_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); + 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_t *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 == NULL) - return 0; - - return di->useddumpsize; + /* everything's ok */ -#endif /* defined(DISABLE_DUMP) */ + return true; } +#endif /*