/* src/mm/memory.c - memory management
- 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
+ Copyright (C) 1996-2005, 2006, 2007, 2008
+ CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
This file is part of CACAO.
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
- $Id: memory.c 8123 2007-06-20 23:50:55Z michi $
-
*/
#include "config.h"
#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/mman.h>
+#include <stdint.h>
#if defined(__DARWIN__)
/* If we compile with -ansi on darwin, <sys/types.h> is not
#include "mm/memory.h"
-#include "native/native.h"
+#include "native/native.hpp"
-#include "threads/lock-common.h"
-#include "threads/threads-common.h"
+#include "threads/lock.hpp"
+#include "threads/thread.hpp"
#include "toolbox/logging.h"
-#include "vm/exceptions.h"
#include "vm/global.h"
-#include "vm/stringlocal.h"
-#include "vm/vm.h"
+#include "vm/string.hpp"
+#include "vm/vm.hpp"
-#include "vmcore/options.h"
+#include "vm/options.h"
+#include "vm/os.hpp"
#if defined(ENABLE_STATISTICS)
-# include "vmcore/statistics.h"
-#endif
-
-
-/*******************************************************************************
-
- This structure is used for dump memory allocation if cacao
- runs without threads.
-
-*******************************************************************************/
-
-#if !defined(ENABLE_THREADS)
-static dumpinfo_t _no_threads_dumpinfo;
-#endif
-
-#if defined(ENABLE_THREADS)
-#define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
-#else
-#define DUMPINFO &_no_threads_dumpinfo
-#endif
-
-
-/* global code memory variables ***********************************************/
-
-#define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
-
-#if defined(ENABLE_THREADS)
-static java_objectheader *lock_code_memory = NULL;
+# include "vm/statistics.h"
#endif
-static void *code_memory = NULL;
-static int code_memory_size = 0;
-static int pagesize = 0;
-
-
-/* memory_init *****************************************************************
-
- Initialize the memory subsystem.
-
-*******************************************************************************/
-
-bool memory_init(void)
-{
-#if defined(ENABLE_THREADS)
- /* create lock for code memory */
-
- lock_code_memory = NEW(java_objectheader);
-
- lock_init_object_lock(lock_code_memory);
-#endif
-
- /* get the pagesize of this architecture */
-
- pagesize = getpagesize();
-
- /* everything's ok */
-
- return true;
-}
-/* memory_mmap_anon ************************************************************
+/* memory_mprotect *************************************************************
- Maps anonymous memory, even on systems not defining
- MAP_ANON(YMOUS).
+ Convenience function for mprotect. This function also does error
+ checking.
*******************************************************************************/
-void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
+void memory_mprotect(void *addr, size_t len, int prot)
{
- 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;
+ if (os_mprotect(addr, len, prot) != 0)
+ vm_abort_errno("memory_mprotect: os_mprotect failed");
}
*******************************************************************************/
-static void *memory_checked_alloc(s4 size)
+void *memory_checked_alloc(size_t size)
{
/* always allocate memory zeroed out */
- void *p = calloc(size, 1);
+ void *p = os_calloc(size, 1);
if (p == NULL)
vm_abort("memory_checked_alloc: calloc failed: out of memory");
}
-/* memory_cnew *****************************************************************
-
- Allocates memory from the heap via mmap and make the memory read-,
- write-, and executeable.
-
-*******************************************************************************/
-
-void *memory_cnew(s4 size)
-{
- void *p;
-
- LOCK_MONITOR_ENTER(lock_code_memory);
-
- size = MEMORY_ALIGN(size, ALIGNSIZE);
-
- /* check if enough memory is available */
-
- if (size > code_memory_size) {
- /* set default code size */
-
- code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
-
- /* do we need more? */
-
- if (size > code_memory_size)
- code_memory_size = size;
-
- /* align the size of the memory to be allocated */
-
- code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat) {
- codememusage += code_memory_size;
-
- if (codememusage > maxcodememusage)
- maxcodememusage = codememusage;
- }
-#endif
-
- /* allocate the memory */
-
- p = memory_mmap_anon(NULL, code_memory_size,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE);
-
- /* set global code memory pointer */
-
- code_memory = p;
- }
-
- /* get a memory chunk of the allocated memory */
-
- p = code_memory;
-
- 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 *mem_alloc(int32_t size)
{
void *m;
}
-void *mem_realloc(void *src, s4 len1, s4 len2)
+void *mem_realloc(void *src, int32_t len1, int32_t len2)
{
void *dst;
#if defined(ENABLE_MEMCHECK)
if (len2 < len1)
- memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
+ os_memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
#endif
dst = realloc(src, len2);
#if defined(ENABLE_MEMCHECK)
if (len2 > len1)
- memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, 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)
#if defined(ENABLE_MEMCHECK)
/* destroy the contents */
- memset(m, MEMORY_CLEAR_BYTE, size);
+ os_memset(m, MEMORY_CLEAR_BYTE, size);
#endif
- free(m);
+ os_free(m);
}
{
int32_t seconds;
+ /* Prevent compiler warning. */
+
+ seconds = 1;
+
/* If both arguments are specified, use the value of
ProfileMemoryUsage. */
#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; i<MEMORY_CANARY_SIZE; ++i)
- if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
- fprintf(stderr, "canary bytes:");
- for (j=0; j<MEMORY_CANARY_SIZE; ++j)
- fprintf(stderr, " %02x", pm[j]);
- fprintf(stderr,"\n");
- vm_abort("error: dump memory bottom canary killed: "
- "%p (%d bytes allocated at %p)\n",
- pm + i, da->size, da->mem);
- }
-
- pm = da->mem + da->size;
- for (i=0; i<MEMORY_CANARY_SIZE; ++i)
- if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
- fprintf(stderr, "canary bytes:");
- for (j=0; j<MEMORY_CANARY_SIZE; ++j)
- fprintf(stderr, " %02x", pm[j]);
- fprintf(stderr,"\n");
- vm_abort("error: dump memory top canary killed: "
- "%p (%d bytes allocated at %p)\n",
- pm + i, da->size, da->mem);
- }
-
- da = da->next;
- }
-}
-#endif /* defined(ENABLE_MEMCHECK) */
-
-
-/* dump_alloc ******************************************************************
-
- Allocate memory in the dump area.
-
- IN:
- size.........size of block to allocate, in bytes
- may be zero, in which case NULL is returned
-
- RETURN VALUE:
- pointer to allocated memory, or
- NULL iff `size` was zero
-
- ERROR HANDLING:
- XXX This function uses `memory_checked_alloc`, which *exits* if no
- memory could be allocated.
-
- THREADS:
- dump_alloc is thread safe. Each thread has its own dump memory area.
-
- dump_alloc is a fast allocator suitable for scratch memory that can be
- collectively freed when the current activity (eg. compiling) is done.
-
- You cannot selectively free dump memory. Before you start allocating it,
- you remember the current size returned by `dump_size`. Later, when you no
- longer need the memory, call `dump_release` with the remembered size and
- all dump memory allocated since the call to `dump_size` will be freed.
-
-*******************************************************************************/
-
-void *dump_alloc(s4 size)
-{
-#if defined(DISABLE_DUMP)
-
- /* use malloc memory for dump memory (for debugging only!) */
-
- return mem_alloc(size);
-
-#else /* !defined(DISABLE_DUMP) */
-
- 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. */
-
- di = DUMPINFO;
-
- if (size == 0)
- return NULL;
-
-#if defined(ENABLE_MEMCHECK)
- size += 2*MEMORY_CANARY_SIZE;
-#endif
-
- size = MEMORY_ALIGN(size, ALIGNSIZE);
-
- if (di->useddumpsize + size > di->allocateddumpsize) {
- dumpblock_t *newdumpblock;
- s4 newdumpblocksize;
-
- /* allocate a new dumplist structure */
-
- 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. */
-
- if (size > DUMPBLOCKSIZE) {
- newdumpblocksize = size;
-
- } else {
- newdumpblocksize = DUMPBLOCKSIZE;
- }
-
- /* allocate dumpblock memory */
-
- newdumpblock->dumpmem = memory_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(ENABLE_STATISTICS)
- /* the amount of globally allocated dump memory (thread save) */
-
- if (opt_stat)
- globalallocateddumpsize += newdumpblocksize;
-#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);
-
-#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; i<MEMORY_CANARY_SIZE; ++i)
- pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
- pm = da->mem + da->size;
- for (i=0; i<MEMORY_CANARY_SIZE; ++i)
- pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
-
- /* make m point after the bottom canary */
-
- m = (u1*)m + MEMORY_CANARY_SIZE;
-
- /* clear the memory */
-
- memset(m, MEMORY_CLEAR_BYTE, da->size);
- }
-#endif /* defined(ENABLE_MEMCHECK) */
-
- /* increase used dump size by the allocated memory size */
-
- di->useddumpsize += size;
-
-#if defined(ENABLE_STATISTICS)
- if (opt_stat)
- if (di->useddumpsize > maxdumpsize)
- maxdumpsize = di->useddumpsize;
-#endif
-
- return m;
-
-#endif /* defined(DISABLE_DUMP) */
-}
-
-
-/* dump_realloc ****************************************************************
-
- Stupid realloc implementation for dump memory. Avoid, if possible.
-
-*******************************************************************************/
-
-void *dump_realloc(void *src, s4 len1, s4 len2)
-{
-#if defined(DISABLE_DUMP)
- /* use malloc memory for dump memory (for debugging only!) */
-
- return mem_realloc(src, len1, len2);
-#else
- void *dst = dump_alloc(len2);
-
- memcpy(dst, src, len1);
-
-#if defined(ENABLE_MEMCHECK)
- /* destroy the source */
- memset(src, MEMORY_CLEAR_BYTE, len1);
-#endif
-
- return dst;
-#endif
-}
-
-
-/* dump_release ****************************************************************
-
- Release dump memory above the given size.
-
- IN:
- size........All dump memory above this mark will be freed. Usually
- `size` will be the return value of a `dump_size` call
- made earlier.
-
- ERROR HANDLING:
- XXX If the given size is invalid, this function *exits* with an
- error message.
-
- See `dump_alloc`.
-
-*******************************************************************************/
-
-void dump_release(s4 size)
-{
-#if defined(DISABLE_DUMP)
-
- /* use malloc memory for dump memory (for debugging only!) */
-
- /* do nothing */
-
-#else /* !defined(DISABLE_DUMP) */
-
- 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))
- 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_t *tmp = di->currentdumpblock;
-
- di->allocateddumpsize -= tmp->size;
- di->currentdumpblock = tmp->prev;
-
-#if defined(ENABLE_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);
- }
-
-#endif /* defined(DISABLE_DUMP) */
-}
-
-
-/* dump_size *******************************************************************
-
- Return the current size of the dump memory area. See `dump_alloc`.
-
-*******************************************************************************/
-
-s4 dump_size(void)
-{
-#if defined(DISABLE_DUMP)
- /* use malloc memory for dump memory (for debugging only!) */
-
- return 0;
-
-#else /* !defined(DISABLE_DUMP) */
-
- 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 == NULL)
- return 0;
-
- return di->useddumpsize;
-
-#endif /* defined(DISABLE_DUMP) */
-}
-
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where