-/* 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 662 2003-11-21 18:06:25Z jowenn $
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include "global.h"
-#include "loging.h"
-#include "memory.h"
-
-
-/********* general types, variables and auxiliary functions *********/
-
-#define DUMPBLOCKSIZE (2<<21)
-#define ALIGNSIZE 8
-
-typedef struct dumplist {
- struct dumplist *prev;
- char *dumpmem;
-} dumplist;
-
-
-
-long int memoryusage = 0;
-
-long int dumpsize = 0;
-long int dumpspace = 0;
-dumplist *topdumpblock = NULL;
+#include "config.h"
-long int maxmemusage = 0;
-long int maxdumpsize = 0;
+#include <assert.h>
+#include <stdint.h>
-#define TRACECALLARGS
+#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
-#ifdef TRACECALLARGS
-static char *nomallocmem = NULL;
-static char *nomalloctop;
-static char *nomallocptr;
+#include "vm/types.h"
+#include "arch.h"
-static void *lit_checked_alloc (int length)
-{
- void *m;
+#include "mm/memory.h"
- if (!nomallocmem) {
- nomallocmem = malloc(16777216);
- nomalloctop = nomallocmem + 16777216;
- nomallocptr = nomallocmem;
- }
+#include "native/native.hpp"
- nomallocptr = (void*) ALIGN((long) nomallocptr, ALIGNSIZE);
-
- m = nomallocptr;
- nomallocptr += length;
- if (nomallocptr > nomalloctop)
- panic("Out of memory");
+#include "threads/lock.hpp"
+#include "threads/thread.hpp"
- return m;
-}
+#include "toolbox/logging.h"
-#else
+#include "vm/global.h"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
-static void *lit_checked_alloc(int length)
-{
- void *m = malloc(length);
- if (!m) panic ("Out of memory");
- return m;
-}
+#include "vm/options.h"
+#include "vm/os.hpp"
+#if defined(ENABLE_STATISTICS)
+# include "vm/statistics.h"
#endif
-static void *checked_alloc(int length)
-{
- void *m = malloc(length);
- if (!m) panic("Out of memory");
- return m;
-}
+/* memory_mprotect *************************************************************
+ Convenience function for mprotect. This function also does error
+ checking.
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+*******************************************************************************/
-
-void *mem_mmap(int length)
+void memory_mprotect(void *addr, size_t len, int prot)
{
- void *retptr;
-
- length = (ALIGN(length,ALIGNSIZE));
- if (length > mmapcodesize) {
- mmapcodesize = 0x10000;
- if (length > mmapcodesize)
- mmapcodesize = length;
- 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 == (void*) -1)
- panic ("Out of memory");
- }
- retptr = mmapcodeptr;
- mmapcodeptr = (void*) ((char*) mmapcodeptr + length);
- mmapcodesize -= length;
- return retptr;
+ if (os_mprotect(addr, len, prot) != 0)
+ vm_abort_errno("memory_mprotect: os_mprotect failed");
}
-#ifdef DEBUG
-
-/************ Memory manager, safe version **************/
-
+/* memory_checked_alloc ********************************************************
-typedef struct memblock {
- struct memblock *prev, *next;
- int length;
-} memblock;
+ Allocated zeroed-out memory and does an OOM check.
-#define BLOCKOFFSET (ALIGN(sizeof(memblock),ALIGNSIZE))
+ ERROR HANDLING:
+ XXX If no memory could be allocated, this function justs *exists*.
-struct memblock *firstmemblock;
+*******************************************************************************/
-
-
-void *mem_alloc(int length)
+void *memory_checked_alloc(size_t size)
{
- memblock *mb;
-
- if (length == 0) return NULL;
- mb = checked_alloc(length + BLOCKOFFSET);
+ /* always allocate memory zeroed out */
- mb->prev = NULL;
- mb->next = firstmemblock;
- mb->length = length;
+ void *p = os_calloc(size, 1);
- if (firstmemblock) firstmemblock->prev = mb;
- firstmemblock = mb;
+ if (p == NULL)
+ vm_abort("memory_checked_alloc: calloc failed: out of memory");
- memoryusage += length;
- if (memoryusage > maxmemusage)
- maxmemusage = memoryusage;
-
- return ((char*) mb) + BLOCKOFFSET;
+ return p;
}
-void *lit_mem_alloc(int length)
+void *mem_alloc(int32_t size)
{
- memblock *mb;
-
- if (length == 0) return NULL;
- mb = lit_checked_alloc(length + BLOCKOFFSET);
-
- mb->prev = NULL;
- mb->next = firstmemblock;
- mb->length = length;
-
- if (firstmemblock) firstmemblock -> prev = mb;
- firstmemblock = mb;
-
- memoryusage += length;
- if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-
- return ((char*) mb) + BLOCKOFFSET;
-}
+ void *m;
+ if (size == 0)
+ return NULL;
-void mem_free(void *m, int length)
-{
- memblock *mb;
- if (!m) {
- if (length == 0) return;
- panic("returned memoryblock with address NULL, length != 0");
- }
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat) {
+ memoryusage += size;
- mb = (memblock*) (((char*) m) - BLOCKOFFSET);
-
- if (mb->length != length) {
- sprintf(logtext,
- "Memory block of size %d has been return as size %d",
- mb->length, length);
- error();
+ if (memoryusage > maxmemusage)
+ maxmemusage = memoryusage;
}
-
- if (mb->prev) mb->prev->next = mb->next;
- else firstmemblock = mb->next;
- if (mb->next) mb->next->prev = mb->prev;
-
- free (mb);
-
- memoryusage -= length;
-}
+#endif
+ m = memory_checked_alloc(size);
-void lit_mem_free(void *m, int length)
-{
- memblock *mb;
- if (!m) {
- if (length==0) return;
- panic("returned memoryblock with address NULL, length != 0");
- }
-
- mb = (memblock*) (((char*) m) - BLOCKOFFSET);
-
- if (mb->length != length) {
- sprintf(logtext,
- "Memory block of size %d has been return as size %d",
- mb->length, length);
- error();
- }
-
- if (mb->prev) mb->prev->next = mb->next;
- else firstmemblock = mb->next;
- if (mb->next) mb->next->prev = mb->prev;
-
-#ifdef TRACECALLARGS
-#else
- free(mb);
+#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
- memoryusage -= length;
+ return m;
}
-void *mem_realloc(void *m1, int len1, int len2)
+void *mem_realloc(void *src, int32_t len1, int32_t len2)
{
- void *m2;
-
- m2 = mem_alloc(len2);
- memcpy(m2, m1, len1);
- mem_free(m1, len1);
+ void *dst;
- return m2;
-}
+ /* 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
-static void mem_characterlog(unsigned char *m, int len)
-{
-# define LINESIZE 16
- int z, i;
-
- for (z = 0; z < len; z += LINESIZE) {
- sprintf(logtext, " ");
-
- for (i = z; i < (z + LINESIZE) && i < len; i++) {
- sprintf(logtext + strlen(logtext), "%2x ", m[i]);
- }
- for (; i < (z + LINESIZE); i++) {
- sprintf(logtext + strlen(logtext), " ");
- }
-
- sprintf(logtext + strlen(logtext)," ");
- for (i = z; i < (z + LINESIZE) && i < len; i++) {
- sprintf(logtext+strlen(logtext),
- "%c", (m[i] >= ' ' && m[i] <= 127) ? m[i] : '.');
- }
-
- dolog();
- }
-}
-
-#else
-/******* Memory manager, fast version ******/
-
+#if defined(ENABLE_MEMCHECK)
+ if (len2 < len1)
+ os_memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
+#endif
-void *mem_alloc(int length)
-{
- if (length == 0) return NULL;
+ dst = realloc(src, len2);
- memoryusage += length;
- if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-
- return checked_alloc(length);
-}
+ 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
-void *lit_mem_alloc(int length)
-{
- if (length == 0) return NULL;
-
- memoryusage += length;
- if (memoryusage > maxmemusage) maxmemusage = memoryusage;
-
- return lit_checked_alloc(length);
+ return dst;
}
-void mem_free(void *m, int length)
+void mem_free(void *m, int32_t size)
{
if (!m) {
- if (length == 0) return;
- panic("returned memoryblock with address NULL, length != 0");
- }
-
- memoryusage -= length;
-
- free(m);
-}
-
+ if (size == 0)
+ return;
-void lit_mem_free(void *m, int length)
-{
- if (!m) {
- if (length == 0) return;
- panic("returned memoryblock with address NULL, length != 0");
+ log_text("returned memoryblock with address NULL, length != 0");
+ assert(0);
}
- memoryusage -= length;
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ memoryusage -= size;
+#endif
-#ifdef TRACECALLARGS
-#else
- free(m);
+#if defined(ENABLE_MEMCHECK)
+ /* destroy the contents */
+ os_memset(m, MEMORY_CLEAR_BYTE, size);
#endif
+
+ os_free(m);
}
-void *mem_realloc (void *m1, int len1, int len2)
-{
- void *m2;
+/* memory_thread ***************************************************************
- if (!m1) {
- if (len1!=0)
- panic ("reallocating memoryblock with address NULL, length != 0");
- }
-
- memoryusage = (memoryusage - len1) + len2;
+ Prints regularly memory statistics.
- m2 = realloc (m1, len2);
- if (!m2) panic ("Out of memory");
- return m2;
-}
+*******************************************************************************/
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+ int32_t seconds;
-#endif
+ /* Prevent compiler warning. */
-/******* common memory manager parts ******/
+ seconds = 1;
-long int mem_usage()
-{
- return memoryusage;
-}
+ /* If both arguments are specified, use the value of
+ ProfileMemoryUsage. */
+ if (opt_ProfileGCMemoryUsage)
+ seconds = opt_ProfileGCMemoryUsage;
-void *dump_alloc(int length)
-{
- void *m;
+ if (opt_ProfileMemoryUsage)
+ seconds = opt_ProfileMemoryUsage;
- if (length == 0) return NULL;
-
- length = ALIGN(length, ALIGNSIZE);
+ while (true) {
+ /* sleep thread */
- assert(length <= DUMPBLOCKSIZE);
- assert(length > 0);
+ threads_sleep(seconds * 1000, 0);
- if (dumpsize + length > dumpspace) {
- dumplist *newdumpblock = checked_alloc(sizeof(dumplist));
+# if defined(ENABLE_STATISTICS)
+ /* Print current date and time (only when we print to the
+ stdout). */
- newdumpblock->prev = topdumpblock;
- topdumpblock = newdumpblock;
+ if (!opt_ProfileMemoryUsageGNUPlot)
+ statistics_print_date();
- newdumpblock->dumpmem = checked_alloc(DUMPBLOCKSIZE);
+ /* print memory usage */
- dumpsize = dumpspace;
- dumpspace += DUMPBLOCKSIZE;
- }
-
- m = topdumpblock->dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize);
- dumpsize += length;
-
- if (dumpsize > maxdumpsize) {
- maxdumpsize = dumpsize;
- }
-
- return m;
-}
+ if (opt_ProfileMemoryUsage)
+ statistics_print_memory_usage();
+ /* print GC memory usage */
-void *dump_realloc(void *ptr, int len1, int len2)
-{
- void *p2 = dump_alloc(len2);
- memcpy(p2, ptr, len1);
- return p2;
+ if (opt_ProfileGCMemoryUsage)
+ statistics_print_gc_memory_usage();
+# endif
+ }
}
+#endif
-long int dump_size()
-{
- return dumpsize;
-}
+/* memory_start_thread *********************************************************
+
+ Starts the memory profiling thread.
+*******************************************************************************/
-void dump_release(long int size)
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+bool memory_start_thread(void)
{
- assert(size >= 0 && size <= dumpsize);
-
- dumpsize = size;
-
- while (dumpspace > dumpsize + DUMPBLOCKSIZE) {
- dumplist *oldtop = topdumpblock;
-
- topdumpblock = oldtop->prev;
- dumpspace -= DUMPBLOCKSIZE;
-
-#ifdef TRACECALLARGS
-#else
- free(oldtop->dumpmem);
- free(oldtop);
-#endif
- }
-}
+ utf *name;
+ name = utf_new_char("Memory Profiler");
-void mem_usagelog (int givewarnings)
-{
- if ((memoryusage!=0) && givewarnings) {
- sprintf (logtext, "Allocated memory not returned: %d",
- (int)memoryusage);
- dolog();
-
-#ifdef DEBUG
- {
- memblock *mb = firstmemblock;
- while (mb) {
- sprintf (logtext, " Memory block size: %d",
- (int)(mb->length) );
- dolog();
- mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length);
- mb = mb->next;
- }
- }
-#endif
-
- }
+ /* start the memory profiling thread */
- if ((dumpsize!=0) && givewarnings) {
- sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize);
- dolog();
- }
+ if (!threads_thread_start_internal(name, memory_thread))
+ return false;
+ /* everything's ok */
- sprintf(logtext, "Random/Dump - memory usage: %dK/%dK",
- (int)((maxmemusage+1023)/1024),
- (int)((maxdumpsize+1023)/1024) );
- dolog();
-
+ return true;
}
+#endif
/*
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/