-/* 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.
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
- Contact: cacao@complang.tuwien.ac.at
+*/
- Authors: Reinhard Grafl
- $Id: memory.c 1437 2004-11-05 09:51:07Z twisti $
+#include "config.h"
-*/
+#include <assert.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. */
+# include <sys/types.h>
+#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include "exceptions.h"
-#include "global.h"
-#include "native.h"
-#include "options.h"
-#include "statistics.h"
-#include "threads/nativethread.h"
-#include "toolbox/logging.h"
-#include "toolbox/memory.h"
+#include "vm/types.h"
+#include "arch.h"
-/********* general types, variables and auxiliary functions *********/
+#include "mm/memory.h"
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+#include "native/native.h"
+#include "threads/lock-common.h"
+#include "threads/thread.hpp"
-/*******************************************************************************
+#include "toolbox/logging.h"
- This structure is used for dump memory allocation if cacao runs without
- threads.
+#include "vm/global.h"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
-*******************************************************************************/
+#include "vm/options.h"
+#include "vm/os.hpp"
-#if !defined(USE_THREADS)
-static dumpinfo nothreads_dumpinfo;
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
#endif
-void *mem_mmap(int size)
-{
- void *m;
+/* memory_mprotect *************************************************************
- size = ALIGN(size, ALIGNSIZE);
+ Convenience function for mprotect. This function also does error
+ checking.
- if (size > mmapcodesize) {
- mmapcodesize = 0x10000;
+*******************************************************************************/
- if (size > mmapcodesize)
- mmapcodesize = size;
+void memory_mprotect(void *addr, size_t len, int prot)
+{
+ if (os_mprotect(addr, len, prot) != 0)
+ vm_abort_errno("memory_mprotect: os_mprotect failed");
+}
- mmapcodesize = ALIGN(mmapcodesize, getpagesize());
- mmapcodeptr = mmap(NULL,
- (size_t) mmapcodesize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -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(int 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(int size)
+void *mem_alloc(int32_t 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 *mem_realloc(void *src, int len1, int len2)
+void *mem_realloc(void *src, int32_t len1, int32_t len2)
{
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)
+ 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, int size)
+void mem_free(void *m, int32_t size)
{
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
- free(m);
-}
-
-
-void *dump_alloc(int 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;
+#if defined(ENABLE_MEMCHECK)
+ /* destroy the contents */
+ os_memset(m, MEMORY_CLEAR_BYTE, size);
#endif
- if (size == 0)
- return NULL;
+ os_free(m);
+}
- size = ALIGN(size, ALIGNSIZE);
- if (di->useddumpsize + size > di->allocateddumpsize) {
- dumpblock *newdumpblock;
- s4 newdumpblocksize;
+/* memory_thread ***************************************************************
- /* allocate a new dumplist structure */
- newdumpblock = checked_alloc(sizeof(dumpblock));
+ Prints regularly memory statistics.
- /* 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;
- }
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+ int32_t seconds;
- /* allocate dumpblock memory */
- //printf("new dumpblock: %d\n", newdumpblocksize);
- newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
+ /* Prevent compiler warning. */
- newdumpblock->prev = di->currentdumpblock;
- newdumpblock->size = newdumpblocksize;
- di->currentdumpblock = newdumpblock;
+ seconds = 1;
- /* 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 both arguments are specified, use the value of
+ ProfileMemoryUsage. */
- /* increase the allocated dump size by the size of the new dump block */
- di->allocateddumpsize += newdumpblocksize;
+ if (opt_ProfileGCMemoryUsage)
+ seconds = opt_ProfileGCMemoryUsage;
- /* the amount of globally allocated dump memory (thread save) */
- if (opt_stat)
- globalallocateddumpsize += newdumpblocksize;
- }
+ if (opt_ProfileMemoryUsage)
+ seconds = opt_ProfileMemoryUsage;
- /* 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);
+ while (true) {
+ /* sleep thread */
- /* increase used dump size by the allocated memory size */
- di->useddumpsize += size;
+ threads_sleep(seconds * 1000, 0);
- if (opt_stat) {
- if (di->useddumpsize > maxdumpsize) {
- maxdumpsize = di->useddumpsize;
- }
- }
-
- return m;
-}
+# if defined(ENABLE_STATISTICS)
+ /* Print current date and time (only when we print to the
+ stdout). */
+ if (!opt_ProfileMemoryUsageGNUPlot)
+ statistics_print_date();
-void *dump_realloc(void *src, int len1, int len2)
-{
- void *dst = dump_alloc(len2);
-
- memcpy(dst, src, len1);
+ /* print memory usage */
- return dst;
-}
+ if (opt_ProfileMemoryUsage)
+ statistics_print_memory_usage();
+ /* print GC memory usage */
-void dump_release(int 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;
+ if (opt_ProfileGCMemoryUsage)
+ statistics_print_gc_memory_usage();
+# endif
+ }
+}
#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;
-long 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 */
- return di->useddumpsize;
+ return true;
}
+#endif
/*
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/