1 /* src/mm/memory.c - memory management
3 Copyright (C) 1996-2005, 2006, 2007 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 $Id: memory.c 7246 2007-01-29 18:49:05Z twisti $
40 #if defined(__DARWIN__)
41 /* If we compile with -ansi on darwin, <sys/types.h> is not
42 included. So let's do it here. */
43 # include <sys/types.h>
50 #include "mm/memory.h"
51 #include "native/native.h"
53 #if defined(ENABLE_THREADS)
54 # include "threads/native/lock.h"
55 # include "threads/native/threads.h"
57 # include "threads/none/lock.h"
60 #include "toolbox/logging.h"
61 #include "vm/exceptions.h"
62 #include "vm/global.h"
63 #include "vm/stringlocal.h"
65 #include "vmcore/options.h"
67 #if defined(ENABLE_STATISTICS)
68 # include "vmcore/statistics.h"
72 /* constants for ENABLE_MEMCHECK **********************************************/
74 #if defined(ENABLE_MEMCHECK)
75 #define MEMORY_CANARY_SIZE 16
76 #define MEMORY_CANARY_FIRST_BYTE 0xca
77 #define MEMORY_CLEAR_BYTE 0xa5
78 #endif /* defined(ENABLE_MEMCHECK) */
81 /*******************************************************************************
83 This structure is used for dump memory allocation if cacao
86 *******************************************************************************/
88 #if !defined(ENABLE_THREADS)
89 static dumpinfo_t _no_threads_dumpinfo;
92 #if defined(ENABLE_THREADS)
93 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
95 #define DUMPINFO &_no_threads_dumpinfo
99 /* global code memory variables ***********************************************/
101 #define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
103 #if defined(ENABLE_THREADS)
104 static java_objectheader *lock_code_memory = NULL;
106 static void *code_memory = NULL;
107 static int code_memory_size = 0;
108 static int pagesize = 0;
111 /* memory_init *****************************************************************
113 Initialize the memory subsystem.
115 *******************************************************************************/
117 bool memory_init(void)
119 #if defined(ENABLE_THREADS)
120 lock_code_memory = NEW(java_objectheader);
122 lock_init_object_lock(lock_code_memory);
125 /* get the pagesize of this architecture */
127 pagesize = getpagesize();
129 /* everything's ok */
135 /* memory_mmap_anon ************************************************************
137 Maps anonymous memory, even on systems not defining
140 *******************************************************************************/
142 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
146 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
147 p = mmap(addr, len, prot,
148 # if defined(MAP_ANON)
151 MAP_ANONYMOUS | flags,
157 fd = open("/dev/zero", O_RDONLY, 0);
160 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
162 p = mmap(addr, len, prot, flags, fd, 0);
165 #if defined(MAP_FAILED)
168 if (p == (void *) -1)
170 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
176 /* memory_checked_alloc ********************************************************
178 Allocated zeroed-out memory and does an OOM check.
181 XXX If no memory could be allocated, this function justs *exists*.
183 *******************************************************************************/
185 static void *memory_checked_alloc(s4 size)
187 /* always allocate memory zeroed out */
189 void *p = calloc(size, 1);
192 vm_abort("memory_checked_alloc: calloc failed: out of memory");
198 /* memory_cnew *****************************************************************
200 Allocates memory from the heap via mmap and make the memory read-,
201 write-, and executeable.
203 *******************************************************************************/
205 void *memory_cnew(s4 size)
209 LOCK_MONITOR_ENTER(lock_code_memory);
211 size = MEMORY_ALIGN(size, ALIGNSIZE);
213 /* check if enough memory is available */
215 if (size > code_memory_size) {
216 /* set default code size */
218 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
220 /* do we need more? */
222 if (size > code_memory_size)
223 code_memory_size = size;
225 /* align the size of the memory to be allocated */
227 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
229 #if defined(ENABLE_STATISTICS)
231 codememusage += code_memory_size;
233 if (codememusage > maxcodememusage)
234 maxcodememusage = codememusage;
238 /* allocate the memory */
240 p = memory_mmap_anon(NULL, code_memory_size,
241 PROT_READ | PROT_WRITE | PROT_EXEC,
244 /* set global code memory pointer */
249 /* get a memory chunk of the allocated memory */
253 code_memory = (void *) ((ptrint) code_memory + size);
254 code_memory_size -= size;
256 LOCK_MONITOR_EXIT(lock_code_memory);
262 /* memory_cfree ****************************************************************
264 Frees the code memory pointed to.
266 ATTENTION: This function currently does NOTHING! Because we don't
267 have a memory management for code memory.
269 *******************************************************************************/
271 void memory_cfree(void *p, s4 size)
277 void *mem_alloc(s4 size)
284 #if defined(ENABLE_STATISTICS)
288 if (memoryusage > maxmemusage)
289 maxmemusage = memoryusage;
293 m = memory_checked_alloc(size);
295 #if defined(ENABLE_MEMCHECK)
296 /* XXX we would like to poison the memory, but callers rely on */
297 /* the zeroing. This should change sooner or later. */
298 /* memset(m, MEMORY_CLEAR_BYTE, size); */
305 void *mem_realloc(void *src, s4 len1, s4 len2)
309 /* prevent compiler warnings */
315 vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
317 #if defined(ENABLE_STATISTICS)
319 memoryusage = (memoryusage - len1) + len2;
322 #if defined(ENABLE_MEMCHECK)
324 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
327 dst = realloc(src, len2);
330 vm_abort("mem_realloc: realloc failed: out of memory");
332 #if defined(ENABLE_MEMCHECK)
334 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
341 void mem_free(void *m, s4 size)
347 log_text("returned memoryblock with address NULL, length != 0");
351 #if defined(ENABLE_STATISTICS)
356 #if defined(ENABLE_MEMCHECK)
357 /* destroy the contents */
358 memset(m, MEMORY_CLEAR_BYTE, size);
365 /* dump_check_canaries *********************************************************
367 Check canaries in dump memory.
370 di...........dumpinfo_t * of the dump area to check
371 bottomsize...dump size down to which the dump area should be checked
372 (specify 0 to check the whole dump area)
375 If any canary has been changed, this function aborts the VM with
378 *******************************************************************************/
380 #if defined(ENABLE_MEMCHECK)
381 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
383 dump_allocation_t *da;
387 /* iterate over all dump memory allocations above bottomsize */
389 da = di->allocations;
390 while (da && da->useddumpsize >= bottomsize) {
393 pm = da->mem - MEMORY_CANARY_SIZE;
394 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
395 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
396 fprintf(stderr, "canary bytes:");
397 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
398 fprintf(stderr, " %02x", pm[j]);
399 fprintf(stderr,"\n");
400 vm_abort("error: dump memory bottom canary killed: "
401 "%p (%d bytes allocated at %p)\n",
402 pm + i, da->size, da->mem);
405 pm = da->mem + da->size;
406 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
407 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
408 fprintf(stderr, "canary bytes:");
409 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
410 fprintf(stderr, " %02x", pm[j]);
411 fprintf(stderr,"\n");
412 vm_abort("error: dump memory top canary killed: "
413 "%p (%d bytes allocated at %p)\n",
414 pm + i, da->size, da->mem);
420 #endif /* defined(ENABLE_MEMCHECK) */
423 /* dump_alloc ******************************************************************
425 Allocate memory in the dump area.
428 size.........size of block to allocate, in bytes
429 may be zero, in which case NULL is returned
432 pointer to allocated memory, or
433 NULL iff `size` was zero
436 XXX This function uses `memory_checked_alloc`, which *exits* if no
437 memory could be allocated.
440 dump_alloc is thread safe. Each thread has its own dump memory area.
442 dump_alloc is a fast allocator suitable for scratch memory that can be
443 collectively freed when the current activity (eg. compiling) is done.
445 You cannot selectively free dump memory. Before you start allocating it,
446 you remember the current size returned by `dump_size`. Later, when you no
447 longer need the memory, call `dump_release` with the remembered size and
448 all dump memory allocated since the call to `dump_size` will be freed.
450 *******************************************************************************/
452 void *dump_alloc(s4 size)
454 #if defined(DISABLE_DUMP)
456 /* use malloc memory for dump memory (for debugging only!) */
458 return mem_alloc(size);
460 #else /* !defined(DISABLE_DUMP) */
464 #if defined(ENABLE_MEMCHECK)
465 s4 origsize = size; /* needed for the canary system */
468 /* If no threads are used, the dumpinfo structure is a static structure */
469 /* defined at the top of this file. */
476 #if defined(ENABLE_MEMCHECK)
477 size += 2*MEMORY_CANARY_SIZE;
480 size = MEMORY_ALIGN(size, ALIGNSIZE);
482 if (di->useddumpsize + size > di->allocateddumpsize) {
483 dumpblock_t *newdumpblock;
486 /* allocate a new dumplist structure */
488 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
490 /* If requested size is greater than the default, make the new dump */
491 /* block as big as the size requested. Else use the default size. */
493 if (size > DUMPBLOCKSIZE) {
494 newdumpblocksize = size;
497 newdumpblocksize = DUMPBLOCKSIZE;
500 /* allocate dumpblock memory */
502 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
504 newdumpblock->prev = di->currentdumpblock;
505 newdumpblock->size = newdumpblocksize;
506 di->currentdumpblock = newdumpblock;
508 /* Used dump size is previously allocated dump size, because the */
509 /* remaining free memory of the previous dump block cannot be used. */
511 di->useddumpsize = di->allocateddumpsize;
513 /* increase the allocated dump size by the size of the new dump block */
515 di->allocateddumpsize += newdumpblocksize;
517 #if defined(ENABLE_STATISTICS)
518 /* the amount of globally allocated dump memory (thread save) */
521 globalallocateddumpsize += newdumpblocksize;
525 /* current dump block base address + the size of the current dump block - */
526 /* the size of the unused memory = new start address */
528 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
529 (di->allocateddumpsize - di->useddumpsize);
531 #if defined(ENABLE_MEMCHECK)
533 dump_allocation_t *da = NEW(dump_allocation_t);
537 /* add the allocation to our linked list of allocations */
539 da->next = di->allocations;
540 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
542 da->useddumpsize = di->useddumpsize;
544 di->allocations = da;
546 /* write the canaries */
549 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
550 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
551 pm = da->mem + da->size;
552 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
553 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
555 /* make m point after the bottom canary */
557 m = (u1*)m + MEMORY_CANARY_SIZE;
559 /* clear the memory */
561 memset(m, MEMORY_CLEAR_BYTE, da->size);
563 #endif /* defined(ENABLE_MEMCHECK) */
565 /* increase used dump size by the allocated memory size */
567 di->useddumpsize += size;
569 #if defined(ENABLE_STATISTICS)
571 if (di->useddumpsize > maxdumpsize)
572 maxdumpsize = di->useddumpsize;
577 #endif /* defined(DISABLE_DUMP) */
581 /* dump_realloc ****************************************************************
583 Stupid realloc implementation for dump memory. Avoid, if possible.
585 *******************************************************************************/
587 void *dump_realloc(void *src, s4 len1, s4 len2)
589 #if defined(DISABLE_DUMP)
590 /* use malloc memory for dump memory (for debugging only!) */
592 return mem_realloc(src, len1, len2);
594 void *dst = dump_alloc(len2);
596 memcpy(dst, src, len1);
598 #if defined(ENABLE_MEMCHECK)
599 /* destroy the source */
600 memset(src, MEMORY_CLEAR_BYTE, len1);
608 /* dump_release ****************************************************************
610 Release dump memory above the given size.
613 size........All dump memory above this mark will be freed. Usually
614 `size` will be the return value of a `dump_size` call
618 XXX If the given size is invalid, this function *exits* with an
623 *******************************************************************************/
625 void dump_release(s4 size)
627 #if defined(DISABLE_DUMP)
629 /* use malloc memory for dump memory (for debugging only!) */
633 #else /* !defined(DISABLE_DUMP) */
637 /* If no threads are used, the dumpinfo structure is a static structure */
638 /* defined at the top of this file. */
642 if ((size < 0) || (size > di->useddumpsize))
643 vm_abort("Illegal dump release size: %d", size);
645 #if defined(ENABLE_MEMCHECK)
647 dump_allocation_t *da, *next;
651 dump_check_canaries(di, size);
653 /* iterate over all dump memory allocations about to be released */
655 da = di->allocations;
656 while (da && da->useddumpsize >= size) {
659 /* invalidate the freed memory */
661 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
663 FREE(da, dump_allocation_t);
667 di->allocations = da;
669 #endif /* defined(ENABLE_MEMCHECK) */
671 /* reset the used dump size to the size specified */
673 di->useddumpsize = size;
675 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
676 dumpblock_t *tmp = di->currentdumpblock;
678 di->allocateddumpsize -= tmp->size;
679 di->currentdumpblock = tmp->prev;
681 #if defined(ENABLE_STATISTICS)
682 /* the amount of globally allocated dump memory (thread save) */
685 globalallocateddumpsize -= tmp->size;
688 /* release the dump memory and the dumpinfo structure */
694 #endif /* defined(DISABLE_DUMP) */
698 /* dump_size *******************************************************************
700 Return the current size of the dump memory area. See `dump_alloc`.
702 *******************************************************************************/
706 #if defined(DISABLE_DUMP)
707 /* use malloc memory for dump memory (for debugging only!) */
711 #else /* !defined(DISABLE_DUMP) */
715 /* If no threads are used, the dumpinfo structure is a static structure */
716 /* defined at the top of this file. */
723 return di->useddumpsize;
725 #endif /* defined(DISABLE_DUMP) */
730 * These are local overrides for various environment variables in Emacs.
731 * Please do not remove this and leave it at the end of the file, where
732 * Emacs will automagically detect them.
733 * ---------------------------------------------------------------------
736 * indent-tabs-mode: t
740 * vim:noexpandtab:sw=4:ts=4: