-/* toolbox/memory.c -
+/* src/mm/memory.c - memory management
- 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, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-
- Contact: cacao@complang.tuwien.ac.at
-
- Authors: Reinhard Grafl
-
- $Id: memory.c 1621 2004-11-30 13:06:55Z twisti $
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
*/
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#if defined(__DARWIN__)
-/* If we compile with -ansi on darwin, <sys/types.h> is not included. So */
-/* let's do it here. */
+/* 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 "vm/types.h"
+
+#include "arch.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) && defined(NATIVE_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/stringlocal.h"
+#include "vm/vm.h"
-/********* general types, variables and auxiliary functions *********/
-
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+#include "vmcore/options.h"
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
-/*******************************************************************************
+#include "vmcore/system.h"
- This structure is used for dump memory allocation if cacao runs without
- threads.
-*******************************************************************************/
+/* memory_mprotect *************************************************************
-#if !defined(USE_THREADS)
-static dumpinfo nothreads_dumpinfo;
-#endif
+ Convenience function for mprotect. This function also does error
+ checking.
+*******************************************************************************/
-void *mem_mmap(s4 size)
+void memory_mprotect(void *addr, size_t len, int prot)
{
- void *m;
+ if (system_mprotect(addr, len, prot) != 0)
+ vm_abort("memory_mprotect: system_mprotect failed: %s",
+ strerror(errno));
+}
- size = ALIGN(size, ALIGNSIZE);
-
- 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
- 0,
-#endif
- -1,
- (off_t) 0);
- if (mmapcodeptr == MAP_FAILED)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
- }
+/* memory_checked_alloc ********************************************************
- m = mmapcodeptr;
- mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
- mmapcodesize -= size;
+ Allocated zeroed-out memory and does an OOM check.
- return m;
-}
+ ERROR HANDLING:
+ XXX If no memory could be allocated, this function justs *exists*.
+*******************************************************************************/
-static void *checked_alloc(s4 size)
+void *memory_checked_alloc(size_t size)
{
/* always allocate memory zeroed out */
- void *m = calloc(size, 1);
- if (!m)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
+ void *p = calloc(size, 1);
- return m;
+ if (p == NULL)
+ vm_abort("memory_checked_alloc: calloc failed: out of memory");
+
+ return p;
}
void *mem_alloc(s4 size)
{
+ void *m;
+
if (size == 0)
return NULL;
+#if defined(ENABLE_STATISTICS)
if (opt_stat) {
memoryusage += size;
if (memoryusage > maxmemusage)
maxmemusage = memoryusage;
}
-
- return checked_alloc(size);
+#endif
+
+ 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 *dst;
- if (!src) {
+ /* prevent compiler warnings */
+
+ dst = NULL;
+
+ if (src == NULL)
if (len1 != 0)
- panic("reallocating memoryblock with address NULL, length != 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)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
+ 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;
}
if (!m) {
if (size == 0)
return;
- panic("returned memoryblock with address NULL, length != 0");
+
+ log_text("returned memoryblock with address NULL, length != 0");
+ assert(0);
}
+#if defined(ENABLE_STATISTICS)
if (opt_stat)
memoryusage -= size;
+#endif
+
+#if defined(ENABLE_MEMCHECK)
+ /* destroy the contents */
+ memset(m, MEMORY_CLEAR_BYTE, size);
+#endif
free(m);
}
-void *dump_alloc(s4 size)
-{
- void *m;
- dumpinfo *di;
-
- /* If no threads are used, the dumpinfo structure is a static structure */
- /* defined at the top of this file. */
-#if defined(USE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
+/* memory_thread ***************************************************************
- if (size == 0)
- return NULL;
+ Prints regularly memory statistics.
- size = ALIGN(size, ALIGNSIZE);
+*******************************************************************************/
- if (di->useddumpsize + size > di->allocateddumpsize) {
- dumpblock *newdumpblock;
- s4 newdumpblocksize;
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+ int32_t seconds;
- /* allocate a new dumplist structure */
- newdumpblock = checked_alloc(sizeof(dumpblock));
+ /* If both arguments are specified, use the value of
+ ProfileMemoryUsage. */
- /* 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;
+ if (opt_ProfileGCMemoryUsage)
+ seconds = opt_ProfileGCMemoryUsage;
- } else {
- newdumpblocksize = DUMPBLOCKSIZE;
- }
+ if (opt_ProfileMemoryUsage)
+ seconds = opt_ProfileMemoryUsage;
- /* allocate dumpblock memory */
- /*printf("new dumpblock: %d\n", newdumpblocksize);*/
- newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
+ while (true) {
+ /* sleep thread */
- newdumpblock->prev = di->currentdumpblock;
- newdumpblock->size = newdumpblocksize;
- di->currentdumpblock = newdumpblock;
+ threads_sleep(seconds * 1000, 0);
- /* 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;
+# if defined(ENABLE_STATISTICS)
+ /* Print current date and time (only when we print to the
+ stdout). */
- /* increase the allocated dump size by the size of the new dump block */
- di->allocateddumpsize += newdumpblocksize;
+ if (!opt_ProfileMemoryUsageGNUPlot)
+ statistics_print_date();
- /* the amount of globally allocated dump memory (thread save) */
- if (opt_stat)
- globalallocateddumpsize += newdumpblocksize;
- }
+ /* print memory usage */
- /* 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);
+ if (opt_ProfileMemoryUsage)
+ statistics_print_memory_usage();
- /* increase used dump size by the allocated memory size */
- di->useddumpsize += size;
+ /* print GC memory usage */
- if (opt_stat) {
- if (di->useddumpsize > maxdumpsize) {
- maxdumpsize = di->useddumpsize;
- }
+ if (opt_ProfileGCMemoryUsage)
+ statistics_print_gc_memory_usage();
+# endif
}
-
- return m;
-}
-
-
-void *dump_realloc(void *src, s4 len1, s4 len2)
-{
- void *dst = dump_alloc(len2);
-
- memcpy(dst, src, len1);
-
- return dst;
}
-
-
-void dump_release(s4 size)
-{
- dumpinfo *di;
-
- /* If no threads are used, the dumpinfo structure is a static structure */
- /* defined at the top of this file. */
-#if defined(USE_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;
+/* memory_start_thread *********************************************************
- while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
- dumpblock *tmp = di->currentdumpblock;
+ Starts the memory profiling thread.
-#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_THREADS) && !defined(NDEBUG)
+bool memory_start_thread(void)
+{
+ utf *name;
- /* the amount of globally allocated dump memory (thread save) */
- if (opt_stat)
- globalallocateddumpsize -= tmp->size;
+ name = utf_new_char("Memory Profiler");
- /* release the dump memory and the dumpinfo structure */
- free(tmp->dumpmem);
- free(tmp);
- }
-}
+ /* start the memory profiling thread */
+ if (!threads_thread_start_internal(name, memory_thread))
+ return false;
-s4 dump_size()
-{
- dumpinfo *di;
-
- /* If no threads are used, the dumpinfo structure is a static structure */
- /* defined at the top of this file. */
-#if defined(USE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
+ /* everything's ok */
- if (!di)
- return 0;
-
- return di->useddumpsize;
+ return true;
}
+#endif
/*
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/