/* src/mm/memory.c -
- 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 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
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
+ Contact: cacao@cacaojvm.org
Authors: Reinhard Grafl
Changes: Christian Thalinger
- $Id: memory.c 2463 2005-05-12 23:54:07Z twisti $
+ $Id: memory.c 4357 2006-01-22 23:33:38Z twisti $
*/
+#include <assert.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
#if defined(__DARWIN__)
/* If we compile with -ansi on darwin, <sys/types.h> is not included. So */
# include <sys/types.h>
#endif
-#include <sys/mman.h>
-#include <unistd.h>
-
#include "config.h"
+#include "vm/types.h"
+
+#include "arch.h"
+
#include "mm/memory.h"
#include "native/native.h"
#include "vm/stringlocal.h"
-/********* general types, variables and auxiliary functions *********/
+/*******************************************************************************
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+ This structure is used for dump memory allocation if cacao
+ runswithout threads.
+*******************************************************************************/
+
+#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
+static dumpinfo _no_threads_dumpinfo;
+#endif
+
+#if defined(USE_THREADS) && defined(NATIVE_THREADS)
+#define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
+#else
+#define DUMPINFO &_no_threads_dumpinfo
+#endif
-/*******************************************************************************
- This structure is used for dump memory allocation if cacao runs without
- threads.
+/* global code memory variables ***********************************************/
+
+#define DEFAULT_CODEMEM_SIZE 128 * 1024 /* defaulting to 128kB */
+
+#if defined(USE_THREADS)
+static java_objectheader *codememlock = NULL;
+#endif
+static int codememsize = 0;
+static void *codememptr = NULL;
+
+
+/* memory_init *****************************************************************
+
+ Initialize the memory subsystem.
*******************************************************************************/
-#if !defined(USE_THREADS) || (defined(USE_THREADS) && !defined(NATIVE_THREADS))
-static dumpinfo nothreads_dumpinfo;
+bool memory_init(void)
+{
+#if defined(USE_THREADS)
+ codememlock = NEW(java_objectheader);
+
+# if defined(NATIVE_THREADS)
+ initObjectLock(codememlock);
+# endif
#endif
+ /* everything's ok */
+
+ return true;
+}
+
+
+/* memory_checked_alloc ********************************************************
-void *mem_mmap(s4 size)
+ Allocated zeroed-out memory and does an OOM check.
+
+*******************************************************************************/
+
+static void *memory_checked_alloc(s4 size)
{
- void *m;
+ /* always allocate memory zeroed out */
+
+ void *p = calloc(size, 1);
+
+ if (!p)
+ exceptions_throw_outofmemory_exit();
+
+ return p;
+}
+
+
+/* memory_cnew *****************************************************************
+
+ Allocates memory from the heap, aligns it to architecutres PAGESIZE
+ and make the memory read-, write-, and executeable.
+
+*******************************************************************************/
+
+void *memory_cnew(s4 size)
+{
+ void *p;
+ int pagesize;
+
+#if defined(USE_THREADS)
+ builtin_monitorenter(codememlock);
+#endif
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,
+ /* check if enough memory is available */
+
+ if (size > codememsize) {
+ /* set default code size */
+
+ codememsize = DEFAULT_CODEMEM_SIZE;
+
+ /* do we need more? */
+
+ if (size > codememsize)
+ codememsize = size;
+
+ /* get the pagesize of this architecture */
+
+ pagesize = getpagesize();
+
+ /* allocate normal heap memory */
+
+ if ((p = memory_checked_alloc(codememsize + pagesize - 1)) == NULL)
+ return NULL;
+
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat) {
+ codememusage += codememsize + pagesize - 1;
+
+ if (codememusage > maxcodememusage)
+ maxcodememusage = codememusage;
+ }
#endif
- -1,
- (off_t) 0);
- if (mmapcodeptr == MAP_FAILED)
+ /* align the memory allocated to a multiple of PAGESIZE,
+ mprotect requires this */
+
+ p = (void *) (((ptrint) p + pagesize - 1) & ~(pagesize - 1));
+
+ /* make the memory read-, write-, and executeable */
+
+ if (mprotect(p, codememsize, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
- }
+ strerror(errno));
- m = mmapcodeptr;
- mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
- mmapcodesize -= size;
+ /* set global code memory pointer */
- return m;
-}
+ codememptr = p;
+ }
+ /* get a memory chunk of the allocated memory */
-static void *checked_alloc(s4 size)
-{
- /* always allocate memory zeroed out */
- void *m = calloc(size, 1);
+ p = codememptr;
+ codememptr = (void *) ((ptrint) codememptr + size);
+ codememsize -= size;
- if (!m)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
+#if defined(USE_THREADS)
+ builtin_monitorexit(codememlock);
+#endif
- return m;
+ return p;
}
if (size == 0)
return NULL;
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
if (opt_stat) {
memoryusage += size;
}
#endif
- return checked_alloc(size);
+ return memory_checked_alloc(size);
}
void *dst;
if (!src) {
- if (len1 != 0)
- panic("reallocating memoryblock with address NULL, length != 0");
+ if (len1 != 0) {
+ log_text("reallocating memoryblock with address NULL, length != 0");
+ assert(0);
+ }
}
-#if defined(STATISTICS)
+#if defined(ENABLE_STATISTICS)
if (opt_stat)
memoryusage = (memoryusage - len1) + len2;
#endif
dst = realloc(src, len2);
if (!dst)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
+ exceptions_throw_outofmemory_exit();
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(STATISTICS)
+#if defined(ENABLE_STATISTICS)
if (opt_stat)
memoryusage -= size;
#endif
}
+/* dump_alloc ******************************************************************
+
+ XXX
+
+*******************************************************************************/
+
void *dump_alloc(s4 size)
{
- void *m;
+#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
+
+ di = DUMPINFO;
if (size == 0)
return NULL;
if (di->useddumpsize + size > di->allocateddumpsize) {
dumpblock *newdumpblock;
- s4 newdumpblocksize;
+ s4 newdumpblocksize;
/* allocate a new dumplist structure */
- newdumpblock = checked_alloc(sizeof(dumpblock));
+
+ newdumpblock = memory_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;
}
/* allocate dumpblock memory */
- /*printf("new dumpblock: %d\n", newdumpblocksize);*/
- newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
+
+ newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
newdumpblock->prev = di->currentdumpblock;
newdumpblock->size = newdumpblocksize;
/* 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;
/* 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 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);
- /* increase used dump size by the allocated memory size */
+ /* increase used dump size by the allocated memory size */
+
di->useddumpsize += size;
-#if defined(STATISTICS)
- if (opt_stat) {
- if (di->useddumpsize > maxdumpsize) {
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ if (di->useddumpsize > maxdumpsize)
maxdumpsize = di->useddumpsize;
- }
- }
#endif
return m;
-}
+#endif /* defined(DISABLE_DUMP) */
+}
+
+
+/* dump_realloc ****************************************************************
+ XXX
+
+*******************************************************************************/
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);
return dst;
+#endif
}
+/* dump_release ****************************************************************
+
+ XXX
+
+*******************************************************************************/
+
void dump_release(s4 size)
{
+#if defined(DISABLE_DUMP)
+ /* use malloc memory for dump memory (for debugging only!) */
+
+ /* 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
+
+ di = DUMPINFO;
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 */
+ /* reset the used dump size to the size specified */
+
di->useddumpsize = size;
while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
di->allocateddumpsize -= tmp->size;
di->currentdumpblock = tmp->prev;
-#if defined(STATISTICS)
- /* the amount of globally allocated dump memory (thread save) */
+#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 */
+ /* release the dump memory and the dumpinfo structure */
+
free(tmp->dumpmem);
free(tmp);
}
+#endif /* defined(DISABLE_DUMP) */
}
-s4 dump_size()
+/* dump_size *******************************************************************
+
+ XXX
+
+*******************************************************************************/
+
+s4 dump_size(void)
{
+#if defined(DISABLE_DUMP)
+ /* use malloc memory for dump memory (for debugging only!) */
+
+ return 0;
+#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
+
+ di = DUMPINFO;
if (!di)
return 0;
return di->useddumpsize;
+#endif /* defined(DISABLE_DUMP) */
}