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
38 #if defined(__DARWIN__)
39 /* If we compile with -ansi on darwin, <sys/types.h> is not
40 included. So let's do it here. */
41 # include <sys/types.h>
48 #include "mm/memory.h"
50 #include "native/native.h"
52 #include "threads/lock-common.h"
53 #include "threads/threads-common.h"
55 #include "toolbox/logging.h"
57 #include "vm/exceptions.h"
58 #include "vm/global.h"
59 #include "vm/stringlocal.h"
62 #include "vmcore/options.h"
64 #if defined(ENABLE_STATISTICS)
65 # include "vmcore/statistics.h"
69 /*******************************************************************************
71 This structure is used for dump memory allocation if cacao
74 *******************************************************************************/
76 #if !defined(ENABLE_THREADS)
77 static dumpinfo_t _no_threads_dumpinfo;
80 #if defined(ENABLE_THREADS)
81 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
83 #define DUMPINFO &_no_threads_dumpinfo
87 /* global code memory variables ***********************************************/
89 #define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
91 #if defined(ENABLE_THREADS)
92 static java_object_t *lock_code_memory = NULL;
94 static void *code_memory = NULL;
95 static int code_memory_size = 0;
96 static int pagesize = 0;
99 /* memory_init *****************************************************************
101 Initialize the memory subsystem.
103 *******************************************************************************/
105 bool memory_init(void)
107 #if defined(ENABLE_THREADS)
108 /* create lock for code memory */
110 lock_code_memory = NEW(java_object_t);
112 lock_init_object_lock(lock_code_memory);
115 /* get the pagesize of this architecture */
117 pagesize = getpagesize();
119 /* everything's ok */
125 /* memory_mmap_anon ************************************************************
127 Maps anonymous memory, even on systems not defining
130 *******************************************************************************/
132 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
136 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
137 p = mmap(addr, len, prot,
138 # if defined(MAP_ANON)
141 MAP_ANONYMOUS | flags,
147 fd = open("/dev/zero", O_RDONLY, 0);
150 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
152 p = mmap(addr, len, prot, flags, fd, 0);
155 #if defined(MAP_FAILED)
158 if (p == (void *) -1)
160 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
166 /* memory_mprotect *************************************************************
168 Convenience function for mprotect. This function also does error
171 *******************************************************************************/
173 void memory_mprotect(void *addr, size_t len, int prot)
175 if (mprotect(addr, len, prot) != 0)
176 vm_abort("memory_mprotect: mprotect failed: %s", strerror(errno));
180 /* memory_checked_alloc ********************************************************
182 Allocated zeroed-out memory and does an OOM check.
185 XXX If no memory could be allocated, this function justs *exists*.
187 *******************************************************************************/
189 static void *memory_checked_alloc(s4 size)
191 /* always allocate memory zeroed out */
193 void *p = calloc(size, 1);
196 vm_abort("memory_checked_alloc: calloc failed: out of memory");
202 /* memory_cnew *****************************************************************
204 Allocates memory from the heap via mmap and make the memory read-,
205 write-, and executeable.
207 *******************************************************************************/
209 void *memory_cnew(s4 size)
213 LOCK_MONITOR_ENTER(lock_code_memory);
215 size = MEMORY_ALIGN(size, ALIGNSIZE);
217 /* check if enough memory is available */
219 if (size > code_memory_size) {
220 /* set default code size */
222 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
224 /* do we need more? */
226 if (size > code_memory_size)
227 code_memory_size = size;
229 /* align the size of the memory to be allocated */
231 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
233 #if defined(ENABLE_STATISTICS)
235 codememusage += code_memory_size;
237 if (codememusage > maxcodememusage)
238 maxcodememusage = codememusage;
242 /* allocate the memory */
244 p = memory_mmap_anon(NULL, code_memory_size,
245 PROT_READ | PROT_WRITE | PROT_EXEC,
248 /* set global code memory pointer */
253 /* get a memory chunk of the allocated memory */
257 code_memory = (void *) ((ptrint) code_memory + size);
258 code_memory_size -= size;
260 LOCK_MONITOR_EXIT(lock_code_memory);
266 /* memory_cfree ****************************************************************
268 Frees the code memory pointed to.
270 ATTENTION: This function currently does NOTHING! Because we don't
271 have a memory management for code memory.
273 *******************************************************************************/
275 void memory_cfree(void *p, s4 size)
281 void *mem_alloc(s4 size)
288 #if defined(ENABLE_STATISTICS)
292 if (memoryusage > maxmemusage)
293 maxmemusage = memoryusage;
297 m = memory_checked_alloc(size);
299 #if defined(ENABLE_MEMCHECK)
300 /* XXX we would like to poison the memory, but callers rely on */
301 /* the zeroing. This should change sooner or later. */
302 /* memset(m, MEMORY_CLEAR_BYTE, size); */
309 void *mem_realloc(void *src, s4 len1, s4 len2)
313 /* prevent compiler warnings */
319 vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
321 #if defined(ENABLE_STATISTICS)
323 memoryusage = (memoryusage - len1) + len2;
326 #if defined(ENABLE_MEMCHECK)
328 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
331 dst = realloc(src, len2);
334 vm_abort("mem_realloc: realloc failed: out of memory");
336 #if defined(ENABLE_MEMCHECK)
338 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
345 void mem_free(void *m, s4 size)
351 log_text("returned memoryblock with address NULL, length != 0");
355 #if defined(ENABLE_STATISTICS)
360 #if defined(ENABLE_MEMCHECK)
361 /* destroy the contents */
362 memset(m, MEMORY_CLEAR_BYTE, size);
369 /* memory_thread ***************************************************************
371 Prints regularly memory statistics.
373 *******************************************************************************/
375 #if defined(ENABLE_THREADS) && !defined(NDEBUG)
376 static void memory_thread(void)
380 /* If both arguments are specified, use the value of
381 ProfileMemoryUsage. */
383 if (opt_ProfileGCMemoryUsage)
384 seconds = opt_ProfileGCMemoryUsage;
386 if (opt_ProfileMemoryUsage)
387 seconds = opt_ProfileMemoryUsage;
392 threads_sleep(seconds * 1000, 0);
394 # if defined(ENABLE_STATISTICS)
395 /* Print current date and time (only when we print to the
398 if (!opt_ProfileMemoryUsageGNUPlot)
399 statistics_print_date();
401 /* print memory usage */
403 if (opt_ProfileMemoryUsage)
404 statistics_print_memory_usage();
406 /* print GC memory usage */
408 if (opt_ProfileGCMemoryUsage)
409 statistics_print_gc_memory_usage();
416 /* memory_start_thread *********************************************************
418 Starts the memory profiling thread.
420 *******************************************************************************/
422 #if defined(ENABLE_THREADS) && !defined(NDEBUG)
423 bool memory_start_thread(void)
427 name = utf_new_char("Memory Profiler");
429 /* start the memory profiling thread */
431 if (!threads_thread_start_internal(name, memory_thread))
434 /* everything's ok */
441 /* dump_check_canaries *********************************************************
443 Check canaries in dump memory.
446 di...........dumpinfo_t * of the dump area to check
447 bottomsize...dump size down to which the dump area should be checked
448 (specify 0 to check the whole dump area)
451 If any canary has been changed, this function aborts the VM with
454 *******************************************************************************/
456 #if defined(ENABLE_MEMCHECK)
457 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
459 dump_allocation_t *da;
463 /* iterate over all dump memory allocations above bottomsize */
465 da = di->allocations;
466 while (da && da->useddumpsize >= bottomsize) {
469 pm = da->mem - MEMORY_CANARY_SIZE;
470 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
471 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
472 fprintf(stderr, "canary bytes:");
473 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
474 fprintf(stderr, " %02x", pm[j]);
475 fprintf(stderr,"\n");
476 vm_abort("error: dump memory bottom canary killed: "
477 "%p (%d bytes allocated at %p)\n",
478 pm + i, da->size, da->mem);
481 pm = da->mem + da->size;
482 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
483 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
484 fprintf(stderr, "canary bytes:");
485 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
486 fprintf(stderr, " %02x", pm[j]);
487 fprintf(stderr,"\n");
488 vm_abort("error: dump memory top canary killed: "
489 "%p (%d bytes allocated at %p)\n",
490 pm + i, da->size, da->mem);
496 #endif /* defined(ENABLE_MEMCHECK) */
499 /* dump_alloc ******************************************************************
501 Allocate memory in the dump area.
504 size.........size of block to allocate, in bytes
505 may be zero, in which case NULL is returned
508 pointer to allocated memory, or
509 NULL iff `size` was zero
512 XXX This function uses `memory_checked_alloc`, which *exits* if no
513 memory could be allocated.
516 dump_alloc is thread safe. Each thread has its own dump memory area.
518 dump_alloc is a fast allocator suitable for scratch memory that can be
519 collectively freed when the current activity (eg. compiling) is done.
521 You cannot selectively free dump memory. Before you start allocating it,
522 you remember the current size returned by `dump_size`. Later, when you no
523 longer need the memory, call `dump_release` with the remembered size and
524 all dump memory allocated since the call to `dump_size` will be freed.
526 *******************************************************************************/
528 void *dump_alloc(s4 size)
530 #if defined(DISABLE_DUMP)
532 /* use malloc memory for dump memory (for debugging only!) */
534 return mem_alloc(size);
536 #else /* !defined(DISABLE_DUMP) */
540 #if defined(ENABLE_MEMCHECK)
541 s4 origsize = size; /* needed for the canary system */
544 /* If no threads are used, the dumpinfo structure is a static structure */
545 /* defined at the top of this file. */
552 #if defined(ENABLE_MEMCHECK)
553 size += 2*MEMORY_CANARY_SIZE;
556 size = MEMORY_ALIGN(size, ALIGNSIZE);
558 if (di->useddumpsize + size > di->allocateddumpsize) {
559 dumpblock_t *newdumpblock;
562 /* allocate a new dumplist structure */
564 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
566 /* If requested size is greater than the default, make the new dump */
567 /* block as big as the size requested. Else use the default size. */
569 if (size > DUMPBLOCKSIZE) {
570 newdumpblocksize = size;
573 newdumpblocksize = DUMPBLOCKSIZE;
576 /* allocate dumpblock memory */
578 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
580 newdumpblock->prev = di->currentdumpblock;
581 newdumpblock->size = newdumpblocksize;
582 di->currentdumpblock = newdumpblock;
584 /* Used dump size is previously allocated dump size, because the */
585 /* remaining free memory of the previous dump block cannot be used. */
587 di->useddumpsize = di->allocateddumpsize;
589 /* increase the allocated dump size by the size of the new dump block */
591 di->allocateddumpsize += newdumpblocksize;
593 #if defined(ENABLE_STATISTICS)
594 /* the amount of globally allocated dump memory (thread save) */
597 globalallocateddumpsize += newdumpblocksize;
601 /* current dump block base address + the size of the current dump block - */
602 /* the size of the unused memory = new start address */
604 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
605 (di->allocateddumpsize - di->useddumpsize);
607 #if defined(ENABLE_MEMCHECK)
609 dump_allocation_t *da = NEW(dump_allocation_t);
613 /* add the allocation to our linked list of allocations */
615 da->next = di->allocations;
616 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
618 da->useddumpsize = di->useddumpsize;
620 di->allocations = da;
622 /* write the canaries */
625 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
626 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
627 pm = da->mem + da->size;
628 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
629 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
631 /* make m point after the bottom canary */
633 m = (u1*)m + MEMORY_CANARY_SIZE;
635 /* clear the memory */
637 memset(m, MEMORY_CLEAR_BYTE, da->size);
639 #endif /* defined(ENABLE_MEMCHECK) */
641 /* increase used dump size by the allocated memory size */
643 di->useddumpsize += size;
645 #if defined(ENABLE_STATISTICS)
647 if (di->useddumpsize > maxdumpsize)
648 maxdumpsize = di->useddumpsize;
653 #endif /* defined(DISABLE_DUMP) */
657 /* dump_realloc ****************************************************************
659 Stupid realloc implementation for dump memory. Avoid, if possible.
661 *******************************************************************************/
663 void *dump_realloc(void *src, s4 len1, s4 len2)
665 #if defined(DISABLE_DUMP)
666 /* use malloc memory for dump memory (for debugging only!) */
668 return mem_realloc(src, len1, len2);
670 void *dst = dump_alloc(len2);
672 memcpy(dst, src, len1);
674 #if defined(ENABLE_MEMCHECK)
675 /* destroy the source */
676 memset(src, MEMORY_CLEAR_BYTE, len1);
684 /* dump_release ****************************************************************
686 Release dump memory above the given size.
689 size........All dump memory above this mark will be freed. Usually
690 `size` will be the return value of a `dump_size` call
694 XXX If the given size is invalid, this function *exits* with an
699 *******************************************************************************/
701 void dump_release(s4 size)
703 #if defined(DISABLE_DUMP)
705 /* use malloc memory for dump memory (for debugging only!) */
709 #else /* !defined(DISABLE_DUMP) */
713 /* If no threads are used, the dumpinfo structure is a static structure */
714 /* defined at the top of this file. */
718 if ((size < 0) || (size > di->useddumpsize))
719 vm_abort("Illegal dump release size: %d", size);
721 #if defined(ENABLE_MEMCHECK)
723 dump_allocation_t *da, *next;
727 dump_check_canaries(di, size);
729 /* iterate over all dump memory allocations about to be released */
731 da = di->allocations;
732 while (da && da->useddumpsize >= size) {
735 /* invalidate the freed memory */
737 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
739 FREE(da, dump_allocation_t);
743 di->allocations = da;
745 #endif /* defined(ENABLE_MEMCHECK) */
747 /* reset the used dump size to the size specified */
749 di->useddumpsize = size;
751 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
752 dumpblock_t *tmp = di->currentdumpblock;
754 di->allocateddumpsize -= tmp->size;
755 di->currentdumpblock = tmp->prev;
757 #if defined(ENABLE_STATISTICS)
758 /* the amount of globally allocated dump memory (thread save) */
761 globalallocateddumpsize -= tmp->size;
764 /* release the dump memory and the dumpinfo structure */
770 #endif /* defined(DISABLE_DUMP) */
774 /* dump_size *******************************************************************
776 Return the current size of the dump memory area. See `dump_alloc`.
778 *******************************************************************************/
782 #if defined(DISABLE_DUMP)
783 /* use malloc memory for dump memory (for debugging only!) */
787 #else /* !defined(DISABLE_DUMP) */
791 /* If no threads are used, the dumpinfo structure is a static structure */
792 /* defined at the top of this file. */
799 return di->useddumpsize;
801 #endif /* defined(DISABLE_DUMP) */
806 * These are local overrides for various environment variables in Emacs.
807 * Please do not remove this and leave it at the end of the file, where
808 * Emacs will automagically detect them.
809 * ---------------------------------------------------------------------
812 * indent-tabs-mode: t
816 * vim:noexpandtab:sw=4:ts=4: