-/* src/mm/memory.c -
+/* src/mm/memory.c - memory management
- 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
+ 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
-
- Changes: Christian Thalinger
-
- $Id: memory.c 3067 2005-07-19 14:11:42Z twisti $
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
*/
+#include "config.h"
+
#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#include <stdint.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 "config.h"
-#include "arch.h"
+#include "vm/types.h"
-#if USE_CODEMMAP
-# include <sys/mman.h>
-# include <unistd.h>
-#endif
+#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 "native/native.hpp"
+
+#include "threads/lock.hpp"
+#include "threads/thread.hpp"
#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/global.h"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
-/********* general types, variables and auxiliary functions *********/
+#include "vm/options.h"
+#include "vm/os.hpp"
-#if USE_CODEMMAP
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
#endif
-/*******************************************************************************
+/* memory_mprotect *************************************************************
- This structure is used for dump memory allocation if cacao runs without
- threads.
+ Convenience function for mprotect. This function also does error
+ checking.
*******************************************************************************/
-#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
-static dumpinfo nothreads_dumpinfo;
-#endif
-
-
-#if USE_CODEMMAP
-void *mem_mmap(s4 size)
+void memory_mprotect(void *addr, size_t len, int prot)
{
- void *m;
+ if (os_mprotect(addr, len, prot) != 0)
+ vm_abort_errno("memory_mprotect: os_mprotect failed");
+}
- 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;
-}
-#endif
+ 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 = os_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 *mem_alloc(int32_t size)
{
+ void *m;
+
if (size == 0)
return NULL;
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
if (opt_stat) {
memoryusage += size;
}
#endif
- return 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(STATISTICS)
+#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)
- 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)
+ 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)
assert(0);
}
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
if (opt_stat)
memoryusage -= size;
#endif
- free(m);
-}
-
-
-/* dump_alloc ******************************************************************
-
- XXX
-
-*******************************************************************************/
-
-void *dump_alloc(s4 size)
-{
-#if defined(DISABLE_DUMP)
- /* use malloc memory for dump memory (for debugging only!) */
-
- return mem_alloc(size);
-#else
- 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) && defined(NATIVE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
-
- 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 = 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 = 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(STATISTICS)
- /* the amount of globally allocated dump memory (thread save) */
-
- if (opt_stat)
- globalallocateddumpsize += newdumpblocksize;
+#if defined(ENABLE_MEMCHECK)
+ /* destroy the contents */
+ os_memset(m, MEMORY_CLEAR_BYTE, size);
#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(STATISTICS)
- if (opt_stat)
- if (di->useddumpsize > maxdumpsize)
- maxdumpsize = di->useddumpsize;
-#endif
-
- return m;
-#endif /* defined(DISABLE_DUMP) */
+ os_free(m);
}
-/* dump_realloc ****************************************************************
+/* memory_thread ***************************************************************
- XXX
+ 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!) */
+ int32_t seconds;
- return mem_realloc(src, len1, len2);
-#else
- void *dst = dump_alloc(len2);
+ /* Prevent compiler warning. */
- memcpy(dst, src, len1);
+ seconds = 1;
- return dst;
-#endif
-}
+ /* If both arguments are specified, use the value of
+ ProfileMemoryUsage. */
+ if (opt_ProfileGCMemoryUsage)
+ seconds = opt_ProfileGCMemoryUsage;
-/* dump_release ****************************************************************
+ if (opt_ProfileMemoryUsage)
+ seconds = opt_ProfileMemoryUsage;
- XXX
+ while (true) {
+ /* sleep thread */
-*******************************************************************************/
-
-void dump_release(s4 size)
-{
-#if defined(DISABLE_DUMP)
- /* use malloc memory for dump memory (for debugging only!) */
+ threads_sleep(seconds * 1000, 0);
- /* do nothing */
-#else
- 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) && defined(NATIVE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
+# if defined(ENABLE_STATISTICS)
+ /* Print current date and time (only when we print to the
+ stdout). */
- if (size < 0 || size > di->useddumpsize)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Illegal dump release size %d", size);
+ if (!opt_ProfileMemoryUsageGNUPlot)
+ statistics_print_date();
- /* reset the used dump size to the size specified */
+ /* print memory usage */
- di->useddumpsize = size;
+ if (opt_ProfileMemoryUsage)
+ statistics_print_memory_usage();
- while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
- dumpblock *tmp = di->currentdumpblock;
+ /* print GC memory usage */
-#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(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 *********************************************************
- XXX
+ 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!) */
+ utf *name;
- return 0;
-#else
- dumpinfo *di;
+ name = utf_new_char("Memory Profiler");
- /* If no threads are used, the dumpinfo structure is a static structure */
- /* defined at the top of this file. */
+ /* start the memory profiling thread */
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
+ if (!threads_thread_start_internal(name, memory_thread))
+ return false;
- if (!di)
- return 0;
+ /* everything's ok */
- return di->useddumpsize;
-#endif /* defined(DISABLE_DUMP) */
+ return true;
}
+#endif
/*
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/