3 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 Contact: cacao@cacaojvm.org
27 Authors: Reinhard Grafl
31 $Id: memory.c 7205 2007-01-11 22:36:29Z twisti $
46 #if defined(__DARWIN__)
47 /* If we compile with -ansi on darwin, <sys/types.h> is not
48 included. So let's do it here. */
49 # include <sys/types.h>
56 #include "mm/memory.h"
57 #include "native/native.h"
59 #if defined(ENABLE_THREADS)
60 # include "threads/native/lock.h"
61 # include "threads/native/threads.h"
63 # include "threads/none/lock.h"
66 #include "toolbox/logging.h"
67 #include "vm/exceptions.h"
68 #include "vm/global.h"
69 #include "vm/options.h"
70 #include "vm/statistics.h"
71 #include "vm/stringlocal.h"
75 /* constants for ENABLE_MEMCHECK **********************************************/
77 #if defined(ENABLE_MEMCHECK)
78 #define MEMORY_CANARY_SIZE 16
79 #define MEMORY_CANARY_FIRST_BYTE 0xca
80 #define MEMORY_CLEAR_BYTE 0xa5
81 #endif /* defined(ENABLE_MEMCHECK) */
84 /*******************************************************************************
86 This structure is used for dump memory allocation if cacao
89 *******************************************************************************/
91 #if !defined(ENABLE_THREADS)
92 static dumpinfo_t _no_threads_dumpinfo;
95 #if defined(ENABLE_THREADS)
96 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
98 #define DUMPINFO &_no_threads_dumpinfo
102 /* global code memory variables ***********************************************/
104 #define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
106 #if defined(ENABLE_THREADS)
107 static java_objectheader *lock_code_memory = NULL;
109 static void *code_memory = NULL;
110 static int code_memory_size = 0;
111 static int pagesize = 0;
114 /* memory_init *****************************************************************
116 Initialize the memory subsystem.
118 *******************************************************************************/
120 bool memory_init(void)
122 #if defined(ENABLE_THREADS)
123 lock_code_memory = NEW(java_objectheader);
125 lock_init_object_lock(lock_code_memory);
128 /* get the pagesize of this architecture */
130 pagesize = getpagesize();
132 /* everything's ok */
138 /* memory_mmap_anon ************************************************************
140 Maps anonymous memory, even on systems not defining
143 *******************************************************************************/
145 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
149 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
150 p = mmap(addr, len, prot,
151 # if defined(MAP_ANON)
154 MAP_ANONYMOUS | flags,
160 fd = open("/dev/zero", O_RDONLY, 0);
163 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
165 p = mmap(addr, len, prot, flags, fd, 0);
168 #if defined(MAP_FAILED)
171 if (p == (void *) -1)
173 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
179 /* memory_checked_alloc ********************************************************
181 Allocated zeroed-out memory and does an OOM check.
184 XXX If no memory could be allocated, this function justs *exists*.
186 *******************************************************************************/
188 static void *memory_checked_alloc(s4 size)
190 /* always allocate memory zeroed out */
192 void *p = calloc(size, 1);
195 vm_abort("memory_checked_alloc: calloc failed: out of memory");
201 /* memory_cnew *****************************************************************
203 Allocates memory from the heap via mmap and make the memory read-,
204 write-, and executeable.
206 *******************************************************************************/
208 void *memory_cnew(s4 size)
212 LOCK_MONITOR_ENTER(lock_code_memory);
214 size = MEMORY_ALIGN(size, ALIGNSIZE);
216 /* check if enough memory is available */
218 if (size > code_memory_size) {
219 /* set default code size */
221 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
223 /* do we need more? */
225 if (size > code_memory_size)
226 code_memory_size = size;
228 /* align the size of the memory to be allocated */
230 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
232 #if defined(ENABLE_STATISTICS)
234 codememusage += code_memory_size;
236 if (codememusage > maxcodememusage)
237 maxcodememusage = codememusage;
241 /* allocate the memory */
243 p = memory_mmap_anon(NULL, code_memory_size,
244 PROT_READ | PROT_WRITE | PROT_EXEC,
247 /* set global code memory pointer */
252 /* get a memory chunk of the allocated memory */
256 code_memory = (void *) ((ptrint) code_memory + size);
257 code_memory_size -= size;
259 LOCK_MONITOR_EXIT(lock_code_memory);
265 /* memory_cfree ****************************************************************
267 Frees the code memory pointed to.
269 ATTENTION: This function currently does NOTHING! Because we don't
270 have a memory management for code memory.
272 *******************************************************************************/
274 void memory_cfree(void *p, s4 size)
280 void *mem_alloc(s4 size)
287 #if defined(ENABLE_STATISTICS)
291 if (memoryusage > maxmemusage)
292 maxmemusage = memoryusage;
296 m = memory_checked_alloc(size);
298 #if defined(ENABLE_MEMCHECK)
299 /* XXX we would like to poison the memory, but callers rely on */
300 /* the zeroing. This should change sooner or later. */
301 /* memset(m, MEMORY_CLEAR_BYTE, size); */
308 void *mem_realloc(void *src, s4 len1, s4 len2)
312 /* prevent compiler warnings */
318 vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
320 #if defined(ENABLE_STATISTICS)
322 memoryusage = (memoryusage - len1) + len2;
325 #if defined(ENABLE_MEMCHECK)
327 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
330 dst = realloc(src, len2);
333 vm_abort("mem_realloc: realloc failed: out of memory");
335 #if defined(ENABLE_MEMCHECK)
337 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
344 void mem_free(void *m, s4 size)
350 log_text("returned memoryblock with address NULL, length != 0");
354 #if defined(ENABLE_STATISTICS)
359 #if defined(ENABLE_MEMCHECK)
360 /* destroy the contents */
361 memset(m, MEMORY_CLEAR_BYTE, size);
368 /* dump_check_canaries *********************************************************
370 Check canaries in dump memory.
373 di...........dumpinfo_t * of the dump area to check
374 bottomsize...dump size down to which the dump area should be checked
375 (specify 0 to check the whole dump area)
378 If any canary has been changed, this function aborts the VM with
381 *******************************************************************************/
383 #if defined(ENABLE_MEMCHECK)
384 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
386 dump_allocation_t *da;
390 /* iterate over all dump memory allocations above bottomsize */
392 da = di->allocations;
393 while (da && da->useddumpsize >= bottomsize) {
396 pm = da->mem - MEMORY_CANARY_SIZE;
397 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
398 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
399 fprintf(stderr, "canary bytes:");
400 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
401 fprintf(stderr, " %02x", pm[j]);
402 fprintf(stderr,"\n");
403 vm_abort("error: dump memory bottom canary killed: "
404 "%p (%d bytes allocated at %p)\n",
405 pm + i, da->size, da->mem);
408 pm = da->mem + da->size;
409 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
410 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
411 fprintf(stderr, "canary bytes:");
412 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
413 fprintf(stderr, " %02x", pm[j]);
414 fprintf(stderr,"\n");
415 vm_abort("error: dump memory top canary killed: "
416 "%p (%d bytes allocated at %p)\n",
417 pm + i, da->size, da->mem);
423 #endif /* defined(ENABLE_MEMCHECK) */
426 /* dump_alloc ******************************************************************
428 Allocate memory in the dump area.
431 size.........size of block to allocate, in bytes
432 may be zero, in which case NULL is returned
435 pointer to allocated memory, or
436 NULL iff `size` was zero
439 XXX This function uses `memory_checked_alloc`, which *exits* if no
440 memory could be allocated.
443 dump_alloc is thread safe. Each thread has its own dump memory area.
445 dump_alloc is a fast allocator suitable for scratch memory that can be
446 collectively freed when the current activity (eg. compiling) is done.
448 You cannot selectively free dump memory. Before you start allocating it,
449 you remember the current size returned by `dump_size`. Later, when you no
450 longer need the memory, call `dump_release` with the remembered size and
451 all dump memory allocated since the call to `dump_size` will be freed.
453 *******************************************************************************/
455 void *dump_alloc(s4 size)
457 #if defined(DISABLE_DUMP)
459 /* use malloc memory for dump memory (for debugging only!) */
461 return mem_alloc(size);
463 #else /* !defined(DISABLE_DUMP) */
467 #if defined(ENABLE_MEMCHECK)
468 s4 origsize = size; /* needed for the canary system */
471 /* If no threads are used, the dumpinfo structure is a static structure */
472 /* defined at the top of this file. */
479 #if defined(ENABLE_MEMCHECK)
480 size += 2*MEMORY_CANARY_SIZE;
483 size = MEMORY_ALIGN(size, ALIGNSIZE);
485 if (di->useddumpsize + size > di->allocateddumpsize) {
486 dumpblock_t *newdumpblock;
489 /* allocate a new dumplist structure */
491 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
493 /* If requested size is greater than the default, make the new dump */
494 /* block as big as the size requested. Else use the default size. */
496 if (size > DUMPBLOCKSIZE) {
497 newdumpblocksize = size;
500 newdumpblocksize = DUMPBLOCKSIZE;
503 /* allocate dumpblock memory */
505 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
507 newdumpblock->prev = di->currentdumpblock;
508 newdumpblock->size = newdumpblocksize;
509 di->currentdumpblock = newdumpblock;
511 /* Used dump size is previously allocated dump size, because the */
512 /* remaining free memory of the previous dump block cannot be used. */
514 di->useddumpsize = di->allocateddumpsize;
516 /* increase the allocated dump size by the size of the new dump block */
518 di->allocateddumpsize += newdumpblocksize;
520 #if defined(ENABLE_STATISTICS)
521 /* the amount of globally allocated dump memory (thread save) */
524 globalallocateddumpsize += newdumpblocksize;
528 /* current dump block base address + the size of the current dump block - */
529 /* the size of the unused memory = new start address */
531 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
532 (di->allocateddumpsize - di->useddumpsize);
534 #if defined(ENABLE_MEMCHECK)
536 dump_allocation_t *da = NEW(dump_allocation_t);
540 /* add the allocation to our linked list of allocations */
542 da->next = di->allocations;
543 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
545 da->useddumpsize = di->useddumpsize;
547 di->allocations = da;
549 /* write the canaries */
552 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
553 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
554 pm = da->mem + da->size;
555 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
556 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
558 /* make m point after the bottom canary */
560 m = (u1*)m + MEMORY_CANARY_SIZE;
562 /* clear the memory */
564 memset(m, MEMORY_CLEAR_BYTE, da->size);
566 #endif /* defined(ENABLE_MEMCHECK) */
568 /* increase used dump size by the allocated memory size */
570 di->useddumpsize += size;
572 #if defined(ENABLE_STATISTICS)
574 if (di->useddumpsize > maxdumpsize)
575 maxdumpsize = di->useddumpsize;
580 #endif /* defined(DISABLE_DUMP) */
584 /* dump_realloc ****************************************************************
586 Stupid realloc implementation for dump memory. Avoid, if possible.
588 *******************************************************************************/
590 void *dump_realloc(void *src, s4 len1, s4 len2)
592 #if defined(DISABLE_DUMP)
593 /* use malloc memory for dump memory (for debugging only!) */
595 return mem_realloc(src, len1, len2);
597 void *dst = dump_alloc(len2);
599 memcpy(dst, src, len1);
601 #if defined(ENABLE_MEMCHECK)
602 /* destroy the source */
603 memset(src, MEMORY_CLEAR_BYTE, len1);
611 /* dump_release ****************************************************************
613 Release dump memory above the given size.
616 size........All dump memory above this mark will be freed. Usually
617 `size` will be the return value of a `dump_size` call
621 XXX If the given size is invalid, this function *exits* with an
626 *******************************************************************************/
628 void dump_release(s4 size)
630 #if defined(DISABLE_DUMP)
632 /* use malloc memory for dump memory (for debugging only!) */
636 #else /* !defined(DISABLE_DUMP) */
640 /* If no threads are used, the dumpinfo structure is a static structure */
641 /* defined at the top of this file. */
645 if ((size < 0) || (size > di->useddumpsize))
646 vm_abort("Illegal dump release size: %d", size);
648 #if defined(ENABLE_MEMCHECK)
650 dump_allocation_t *da, *next;
654 dump_check_canaries(di, size);
656 /* iterate over all dump memory allocations about to be released */
658 da = di->allocations;
659 while (da && da->useddumpsize >= size) {
662 /* invalidate the freed memory */
664 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
666 FREE(da, dump_allocation_t);
670 di->allocations = da;
672 #endif /* defined(ENABLE_MEMCHECK) */
674 /* reset the used dump size to the size specified */
676 di->useddumpsize = size;
678 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
679 dumpblock_t *tmp = di->currentdumpblock;
681 di->allocateddumpsize -= tmp->size;
682 di->currentdumpblock = tmp->prev;
684 #if defined(ENABLE_STATISTICS)
685 /* the amount of globally allocated dump memory (thread save) */
688 globalallocateddumpsize -= tmp->size;
691 /* release the dump memory and the dumpinfo structure */
697 #endif /* defined(DISABLE_DUMP) */
701 /* dump_size *******************************************************************
703 Return the current size of the dump memory area. See `dump_alloc`.
705 *******************************************************************************/
709 #if defined(DISABLE_DUMP)
710 /* use malloc memory for dump memory (for debugging only!) */
714 #else /* !defined(DISABLE_DUMP) */
718 /* If no threads are used, the dumpinfo structure is a static structure */
719 /* defined at the top of this file. */
726 return di->useddumpsize;
728 #endif /* defined(DISABLE_DUMP) */
733 * These are local overrides for various environment variables in Emacs.
734 * Please do not remove this and leave it at the end of the file, where
735 * Emacs will automagically detect them.
736 * ---------------------------------------------------------------------
739 * indent-tabs-mode: t
743 * vim:noexpandtab:sw=4:ts=4: