X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fmm%2Fmemory.c;h=9c3034491c051994ef2c9aeaf20061b81fb5308d;hb=9f859ad50d3d5d98c185d40b86b2179bc4dc9aeb;hp=db8bf3e6cff6e1ab8b1c09ef82ca4d600f93e511;hpb=cef2af7d13f56d7ad1c418e1ad053d3a1dace957;p=cacao.git diff --git a/src/mm/memory.c b/src/mm/memory.c index db8bf3e6c..9c3034491 100644 --- a/src/mm/memory.c +++ b/src/mm/memory.c @@ -1,6 +1,6 @@ -/* src/mm/memory.c - +/* src/mm/memory.c - memory management - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, + Copyright (C) 1996-2005, 2006, 2007 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 @@ -22,18 +22,11 @@ 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 4957 2006-05-26 11:48:10Z edwin $ - */ +#include "config.h" + #include #include #include @@ -43,29 +36,43 @@ #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(ENABLE_THREADS) -# include "threads/native/threads.h" -#endif +#include "threads/lock-common.h" +#include "threads/threads-common.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.h" + +#include "vmcore/options.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif + + +/* constants for ENABLE_MEMCHECK **********************************************/ + +#if defined(ENABLE_MEMCHECK) +#define MEMORY_CANARY_SIZE 16 +#define MEMORY_CANARY_FIRST_BYTE 0xca +#define MEMORY_CLEAR_BYTE 0xa5 +#endif /* defined(ENABLE_MEMCHECK) */ /******************************************************************************* @@ -76,7 +83,7 @@ *******************************************************************************/ #if !defined(ENABLE_THREADS) -static dumpinfo _no_threads_dumpinfo; +static dumpinfo_t _no_threads_dumpinfo; #endif #if defined(ENABLE_THREADS) @@ -88,13 +95,14 @@ static dumpinfo _no_threads_dumpinfo; /* global code memory variables ***********************************************/ -#define DEFAULT_CODEMEM_SIZE 128 * 1024 /* defaulting to 128kB */ +#define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */ #if defined(ENABLE_THREADS) -static java_objectheader *codememlock = NULL; +static java_object_t *lock_code_memory = NULL; #endif -static int codememsize = 0; -static void *codememptr = NULL; +static void *code_memory = NULL; +static int code_memory_size = 0; +static int pagesize = 0; /* memory_init ***************************************************************** @@ -106,17 +114,64 @@ static void *codememptr = NULL; bool memory_init(void) { #if defined(ENABLE_THREADS) - codememlock = NEW(java_objectheader); + /* create lock for code memory */ + + lock_code_memory = NEW(java_object_t); - lock_init_object_lock(codememlock); + lock_init_object_lock(lock_code_memory); #endif + /* get the pagesize of this architecture */ + + pagesize = getpagesize(); + /* everything's ok */ return true; } +/* memory_mmap_anon ************************************************************ + + Maps anonymous memory, even on systems not defining + MAP_ANON(YMOUS). + +*******************************************************************************/ + +void *memory_mmap_anon(void *addr, size_t len, int prot, int flags) +{ + void *p; + +#if defined(MAP_ANON) || defined(MAP_ANONYMOUS) + p = mmap(addr, len, prot, +# if defined(MAP_ANON) + MAP_ANON | flags, +# else + MAP_ANONYMOUS | flags, +# endif + -1, 0); +#else + int fd; + + fd = open("/dev/zero", O_RDONLY, 0); + + if (fd == -1) + vm_abort("memory_mmap_anon: open failed: %s", strerror(errno)); + + p = mmap(addr, len, prot, flags, fd, 0); +#endif + +#if defined(MAP_FAILED) + if (p == MAP_FAILED) +#else + if (p == (void *) -1) +#endif + vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno)); + + return p; +} + + /* memory_checked_alloc ******************************************************** Allocated zeroed-out memory and does an OOM check. @@ -132,8 +187,8 @@ static void *memory_checked_alloc(s4 size) 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; } @@ -141,84 +196,87 @@ static void *memory_checked_alloc(s4 size) /* memory_cnew ***************************************************************** - Allocates memory from the heap, aligns it to architecutres PAGESIZE - and make the memory read-, write-, and executeable. + Allocates memory from the heap via mmap and make the memory read-, + write-, and executeable. *******************************************************************************/ void *memory_cnew(s4 size) { void *p; - int pagesize; -#if defined(ENABLE_THREADS) - builtin_monitorenter(codememlock); -#endif + LOCK_MONITOR_ENTER(lock_code_memory); - size = ALIGN(size, ALIGNSIZE); + size = MEMORY_ALIGN(size, ALIGNSIZE); /* check if enough memory is available */ - if (size > codememsize) { + if (size > code_memory_size) { /* set default code size */ - codememsize = DEFAULT_CODEMEM_SIZE; + code_memory_size = DEFAULT_CODE_MEMORY_SIZE; /* do we need more? */ - if (size > codememsize) - codememsize = size; + if (size > code_memory_size) + code_memory_size = size; - /* get the pagesize of this architecture */ + /* align the size of the memory to be allocated */ - pagesize = getpagesize(); - - /* allocate normal heap memory */ - - if ((p = memory_checked_alloc(codememsize + pagesize - 1)) == NULL) - return NULL; + code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize); #if defined(ENABLE_STATISTICS) if (opt_stat) { - codememusage += codememsize + pagesize - 1; + codememusage += code_memory_size; 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)); + /* allocate the memory */ - /* 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)); + p = memory_mmap_anon(NULL, code_memory_size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE); /* set global code memory pointer */ - codememptr = p; + code_memory = p; } /* get a memory chunk of the allocated memory */ - p = codememptr; - codememptr = (void *) ((ptrint) codememptr + size); - codememsize -= size; + p = code_memory; -#if defined(ENABLE_THREADS) - builtin_monitorexit(codememlock); -#endif + 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) { + void *m; + if (size == 0) return NULL; @@ -231,7 +289,15 @@ 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; } @@ -239,22 +305,33 @@ void *mem_realloc(void *src, s4 len1, s4 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; } @@ -275,10 +352,145 @@ void mem_free(void *m, s4 size) memoryusage -= size; #endif +#if defined(ENABLE_MEMCHECK) + /* destroy the contents */ + memset(m, MEMORY_CLEAR_BYTE, size); +#endif + free(m); } +/* memory_thread *************************************************************** + + Prints regularly memory statistics. + +*******************************************************************************/ + +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +static void memory_thread(void) +{ + int32_t seconds; + + /* If both arguments are specified, use the value of + ProfileMemoryUsage. */ + + if (opt_ProfileGCMemoryUsage) + seconds = opt_ProfileGCMemoryUsage; + + if (opt_ProfileMemoryUsage) + seconds = opt_ProfileMemoryUsage; + + while (true) { + /* sleep thread */ + + threads_sleep(seconds * 1000, 0); + +# if defined(ENABLE_STATISTICS) + /* Print current date and time (only when we print to the + stdout). */ + + if (!opt_ProfileMemoryUsageGNUPlot) + statistics_print_date(); + + /* print memory usage */ + + if (opt_ProfileMemoryUsage) + statistics_print_memory_usage(); + + /* print GC memory usage */ + + if (opt_ProfileGCMemoryUsage) + statistics_print_gc_memory_usage(); +# endif + } +} +#endif + + +/* memory_start_thread ********************************************************* + + Starts the memory profiling thread. + +*******************************************************************************/ + +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +bool memory_start_thread(void) +{ + utf *name; + + name = utf_new_char("Memory Profiler"); + + /* start the memory profiling thread */ + + if (!threads_thread_start_internal(name, memory_thread)) + return false; + + /* everything's ok */ + + return true; +} +#endif + + +/* dump_check_canaries ********************************************************* + + Check canaries in dump memory. + + IN: + di...........dumpinfo_t * of the dump area to check + bottomsize...dump size down to which the dump area should be checked + (specify 0 to check the whole dump area) + + ERROR HANDLING: + If any canary has been changed, this function aborts the VM with + an error message. + +*******************************************************************************/ + +#if defined(ENABLE_MEMCHECK) +void dump_check_canaries(dumpinfo_t *di, s4 bottomsize) +{ + dump_allocation_t *da; + u1 *pm; + s4 i, j; + + /* iterate over all dump memory allocations above bottomsize */ + + da = di->allocations; + while (da && da->useddumpsize >= bottomsize) { + /* check canaries */ + + pm = da->mem - MEMORY_CANARY_SIZE; + for (i=0; isize, da->mem); + } + + pm = da->mem + da->size; + for (i=0; isize, da->mem); + } + + da = da->next; + } +} +#endif /* defined(ENABLE_MEMCHECK) */ + + /* dump_alloc ****************************************************************** Allocate memory in the dump area. @@ -318,8 +530,11 @@ void *dump_alloc(s4 size) #else /* !defined(DISABLE_DUMP) */ - void *m; - dumpinfo *di; + void *m; + dumpinfo_t *di; +#if defined(ENABLE_MEMCHECK) + s4 origsize = size; /* needed for the canary system */ +#endif /* If no threads are used, the dumpinfo structure is a static structure */ /* defined at the top of this file. */ @@ -329,15 +544,19 @@ void *dump_alloc(s4 size) if (size == 0) return NULL; - size = ALIGN(size, ALIGNSIZE); +#if defined(ENABLE_MEMCHECK) + size += 2*MEMORY_CANARY_SIZE; +#endif + + size = MEMORY_ALIGN(size, ALIGNSIZE); if (di->useddumpsize + size > di->allocateddumpsize) { - dumpblock *newdumpblock; + dumpblock_t *newdumpblock; s4 newdumpblocksize; /* allocate a new dumplist structure */ - newdumpblock = memory_checked_alloc(sizeof(dumpblock)); + 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. */ @@ -380,6 +599,40 @@ void *dump_alloc(s4 size) m = di->currentdumpblock->dumpmem + di->currentdumpblock->size - (di->allocateddumpsize - di->useddumpsize); +#if defined(ENABLE_MEMCHECK) + { + dump_allocation_t *da = NEW(dump_allocation_t); + s4 i; + u1 *pm; + + /* add the allocation to our linked list of allocations */ + + da->next = di->allocations; + da->mem = (u1*) m + MEMORY_CANARY_SIZE; + da->size = origsize; + da->useddumpsize = di->useddumpsize; + + di->allocations = da; + + /* write the canaries */ + + pm = (u1*)m; + for (i=0; imem + da->size; + for (i=0; isize); + } +#endif /* defined(ENABLE_MEMCHECK) */ + /* increase used dump size by the allocated memory size */ di->useddumpsize += size; @@ -413,6 +666,11 @@ void *dump_realloc(void *src, s4 len1, s4 len2) memcpy(dst, src, len1); +#if defined(ENABLE_MEMCHECK) + /* destroy the source */ + memset(src, MEMORY_CLEAR_BYTE, len1); +#endif + return dst; #endif } @@ -445,23 +703,48 @@ void dump_release(s4 size) #else /* !defined(DISABLE_DUMP) */ - dumpinfo *di; + 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 || size > di->useddumpsize) - throw_cacao_exception_exit(string_java_lang_InternalError, - "Illegal dump release size %d", size); + if ((size < 0) || (size > di->useddumpsize)) + vm_abort("Illegal dump release size: %d", size); + +#if defined(ENABLE_MEMCHECK) + { + dump_allocation_t *da, *next; + + /* check canaries */ + + dump_check_canaries(di, size); + + /* iterate over all dump memory allocations about to be released */ + + da = di->allocations; + while (da && da->useddumpsize >= size) { + next = da->next; + + /* invalidate the freed memory */ + + memset(da->mem, MEMORY_CLEAR_BYTE, da->size); + + FREE(da, dump_allocation_t); + + da = next; + } + di->allocations = da; + } +#endif /* defined(ENABLE_MEMCHECK) */ /* 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; + dumpblock_t *tmp = di->currentdumpblock; di->allocateddumpsize -= tmp->size; di->currentdumpblock = tmp->prev; @@ -498,14 +781,14 @@ s4 dump_size(void) #else /* !defined(DISABLE_DUMP) */ - dumpinfo *di; + 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 (!di) + if (di == NULL) return 0; return di->useddumpsize;