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"
68 #include "vmcore/system.h"
71 /*******************************************************************************
73 This structure is used for dump memory allocation if cacao
76 *******************************************************************************/
78 #if !defined(ENABLE_THREADS)
79 static dumpinfo_t _no_threads_dumpinfo;
82 #if defined(ENABLE_THREADS)
83 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
85 #define DUMPINFO &_no_threads_dumpinfo
89 /* global code memory variables ***********************************************/
91 #define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
93 #if defined(ENABLE_THREADS)
94 static java_object_t *lock_code_memory = NULL;
96 static void *code_memory = NULL;
97 static int code_memory_size = 0;
98 static int pagesize = 0;
101 /* memory_init *****************************************************************
103 Initialize the memory subsystem.
105 *******************************************************************************/
107 bool memory_init(void)
109 #if defined(ENABLE_THREADS)
110 /* create lock for code memory */
112 lock_code_memory = NEW(java_object_t);
114 lock_init_object_lock(lock_code_memory);
117 /* get the pagesize of this architecture */
119 pagesize = getpagesize();
121 /* everything's ok */
127 /* memory_mmap_anon ************************************************************
129 Maps anonymous memory, even on systems not defining
132 *******************************************************************************/
134 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
138 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
139 p = mmap(addr, len, prot,
140 # if defined(MAP_ANON)
143 MAP_ANONYMOUS | flags,
149 fd = open("/dev/zero", O_RDONLY, 0);
152 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
154 p = mmap(addr, len, prot, flags, fd, 0);
157 #if defined(MAP_FAILED)
160 if (p == (void *) -1)
162 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
168 /* memory_mprotect *************************************************************
170 Convenience function for mprotect. This function also does error
173 *******************************************************************************/
175 void memory_mprotect(void *addr, size_t len, int prot)
177 if (system_mprotect(addr, len, prot) != 0)
178 vm_abort("memory_mprotect: system_mprotect failed: %s",
183 /* memory_checked_alloc ********************************************************
185 Allocated zeroed-out memory and does an OOM check.
188 XXX If no memory could be allocated, this function justs *exists*.
190 *******************************************************************************/
192 static void *memory_checked_alloc(s4 size)
194 /* always allocate memory zeroed out */
196 void *p = calloc(size, 1);
199 vm_abort("memory_checked_alloc: calloc failed: out of memory");
205 /* memory_cnew *****************************************************************
207 Allocates memory from the heap via mmap and make the memory read-,
208 write-, and executeable.
210 *******************************************************************************/
212 void *memory_cnew(s4 size)
216 LOCK_MONITOR_ENTER(lock_code_memory);
218 size = MEMORY_ALIGN(size, ALIGNSIZE);
220 /* check if enough memory is available */
222 if (size > code_memory_size) {
223 /* set default code size */
225 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
227 /* do we need more? */
229 if (size > code_memory_size)
230 code_memory_size = size;
232 /* align the size of the memory to be allocated */
234 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
236 #if defined(ENABLE_STATISTICS)
238 codememusage += code_memory_size;
240 if (codememusage > maxcodememusage)
241 maxcodememusage = codememusage;
245 /* allocate the memory */
247 p = memory_mmap_anon(NULL, code_memory_size,
248 PROT_READ | PROT_WRITE | PROT_EXEC,
251 /* set global code memory pointer */
256 /* get a memory chunk of the allocated memory */
260 code_memory = (void *) ((ptrint) code_memory + size);
261 code_memory_size -= size;
263 LOCK_MONITOR_EXIT(lock_code_memory);
269 /* memory_cfree ****************************************************************
271 Frees the code memory pointed to.
273 ATTENTION: This function currently does NOTHING! Because we don't
274 have a memory management for code memory.
276 *******************************************************************************/
278 void memory_cfree(void *p, s4 size)
284 void *mem_alloc(s4 size)
291 #if defined(ENABLE_STATISTICS)
295 if (memoryusage > maxmemusage)
296 maxmemusage = memoryusage;
300 m = memory_checked_alloc(size);
302 #if defined(ENABLE_MEMCHECK)
303 /* XXX we would like to poison the memory, but callers rely on */
304 /* the zeroing. This should change sooner or later. */
305 /* memset(m, MEMORY_CLEAR_BYTE, size); */
312 void *mem_realloc(void *src, s4 len1, s4 len2)
316 /* prevent compiler warnings */
322 vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
324 #if defined(ENABLE_STATISTICS)
326 memoryusage = (memoryusage - len1) + len2;
329 #if defined(ENABLE_MEMCHECK)
331 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
334 dst = realloc(src, len2);
337 vm_abort("mem_realloc: realloc failed: out of memory");
339 #if defined(ENABLE_MEMCHECK)
341 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
348 void mem_free(void *m, s4 size)
354 log_text("returned memoryblock with address NULL, length != 0");
358 #if defined(ENABLE_STATISTICS)
363 #if defined(ENABLE_MEMCHECK)
364 /* destroy the contents */
365 memset(m, MEMORY_CLEAR_BYTE, size);
372 /* memory_thread ***************************************************************
374 Prints regularly memory statistics.
376 *******************************************************************************/
378 #if defined(ENABLE_THREADS) && !defined(NDEBUG)
379 static void memory_thread(void)
383 /* If both arguments are specified, use the value of
384 ProfileMemoryUsage. */
386 if (opt_ProfileGCMemoryUsage)
387 seconds = opt_ProfileGCMemoryUsage;
389 if (opt_ProfileMemoryUsage)
390 seconds = opt_ProfileMemoryUsage;
395 threads_sleep(seconds * 1000, 0);
397 # if defined(ENABLE_STATISTICS)
398 /* Print current date and time (only when we print to the
401 if (!opt_ProfileMemoryUsageGNUPlot)
402 statistics_print_date();
404 /* print memory usage */
406 if (opt_ProfileMemoryUsage)
407 statistics_print_memory_usage();
409 /* print GC memory usage */
411 if (opt_ProfileGCMemoryUsage)
412 statistics_print_gc_memory_usage();
419 /* memory_start_thread *********************************************************
421 Starts the memory profiling thread.
423 *******************************************************************************/
425 #if defined(ENABLE_THREADS) && !defined(NDEBUG)
426 bool memory_start_thread(void)
430 name = utf_new_char("Memory Profiler");
432 /* start the memory profiling thread */
434 if (!threads_thread_start_internal(name, memory_thread))
437 /* everything's ok */
444 /* dump_check_canaries *********************************************************
446 Check canaries in dump memory.
449 di...........dumpinfo_t * of the dump area to check
450 bottomsize...dump size down to which the dump area should be checked
451 (specify 0 to check the whole dump area)
454 If any canary has been changed, this function aborts the VM with
457 *******************************************************************************/
459 #if defined(ENABLE_MEMCHECK)
460 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
462 dump_allocation_t *da;
466 /* iterate over all dump memory allocations above bottomsize */
468 da = di->allocations;
469 while (da && da->useddumpsize >= bottomsize) {
472 pm = da->mem - MEMORY_CANARY_SIZE;
473 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
474 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
475 fprintf(stderr, "canary bytes:");
476 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
477 fprintf(stderr, " %02x", pm[j]);
478 fprintf(stderr,"\n");
479 vm_abort("error: dump memory bottom canary killed: "
480 "%p (%d bytes allocated at %p)\n",
481 pm + i, da->size, da->mem);
484 pm = da->mem + da->size;
485 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
486 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
487 fprintf(stderr, "canary bytes:");
488 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
489 fprintf(stderr, " %02x", pm[j]);
490 fprintf(stderr,"\n");
491 vm_abort("error: dump memory top canary killed: "
492 "%p (%d bytes allocated at %p)\n",
493 pm + i, da->size, da->mem);
499 #endif /* defined(ENABLE_MEMCHECK) */
502 /* dump_alloc ******************************************************************
504 Allocate memory in the dump area.
507 size.........size of block to allocate, in bytes
508 may be zero, in which case NULL is returned
511 pointer to allocated memory, or
512 NULL iff `size` was zero
515 XXX This function uses `memory_checked_alloc`, which *exits* if no
516 memory could be allocated.
519 dump_alloc is thread safe. Each thread has its own dump memory area.
521 dump_alloc is a fast allocator suitable for scratch memory that can be
522 collectively freed when the current activity (eg. compiling) is done.
524 You cannot selectively free dump memory. Before you start allocating it,
525 you remember the current size returned by `dump_size`. Later, when you no
526 longer need the memory, call `dump_release` with the remembered size and
527 all dump memory allocated since the call to `dump_size` will be freed.
529 *******************************************************************************/
531 void *dump_alloc(s4 size)
533 #if defined(DISABLE_DUMP)
535 /* use malloc memory for dump memory (for debugging only!) */
537 return mem_alloc(size);
539 #else /* !defined(DISABLE_DUMP) */
543 #if defined(ENABLE_MEMCHECK)
544 s4 origsize = size; /* needed for the canary system */
547 /* If no threads are used, the dumpinfo structure is a static structure */
548 /* defined at the top of this file. */
555 #if defined(ENABLE_MEMCHECK)
556 size += 2*MEMORY_CANARY_SIZE;
559 size = MEMORY_ALIGN(size, ALIGNSIZE);
561 if (di->useddumpsize + size > di->allocateddumpsize) {
562 dumpblock_t *newdumpblock;
565 /* allocate a new dumplist structure */
567 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
569 /* If requested size is greater than the default, make the new dump */
570 /* block as big as the size requested. Else use the default size. */
572 if (size > DUMPBLOCKSIZE) {
573 newdumpblocksize = size;
576 newdumpblocksize = DUMPBLOCKSIZE;
579 /* allocate dumpblock memory */
581 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
583 newdumpblock->prev = di->currentdumpblock;
584 newdumpblock->size = newdumpblocksize;
585 di->currentdumpblock = newdumpblock;
587 /* Used dump size is previously allocated dump size, because the */
588 /* remaining free memory of the previous dump block cannot be used. */
590 di->useddumpsize = di->allocateddumpsize;
592 /* increase the allocated dump size by the size of the new dump block */
594 di->allocateddumpsize += newdumpblocksize;
596 #if defined(ENABLE_STATISTICS)
597 /* the amount of globally allocated dump memory (thread save) */
600 globalallocateddumpsize += newdumpblocksize;
604 /* current dump block base address + the size of the current dump block - */
605 /* the size of the unused memory = new start address */
607 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
608 (di->allocateddumpsize - di->useddumpsize);
610 #if defined(ENABLE_MEMCHECK)
612 dump_allocation_t *da = NEW(dump_allocation_t);
616 /* add the allocation to our linked list of allocations */
618 da->next = di->allocations;
619 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
621 da->useddumpsize = di->useddumpsize;
623 di->allocations = da;
625 /* write the canaries */
628 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
629 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
630 pm = da->mem + da->size;
631 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
632 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
634 /* make m point after the bottom canary */
636 m = (u1*)m + MEMORY_CANARY_SIZE;
638 /* clear the memory */
640 memset(m, MEMORY_CLEAR_BYTE, da->size);
642 #endif /* defined(ENABLE_MEMCHECK) */
644 /* increase used dump size by the allocated memory size */
646 di->useddumpsize += size;
648 #if defined(ENABLE_STATISTICS)
650 if (di->useddumpsize > maxdumpsize)
651 maxdumpsize = di->useddumpsize;
656 #endif /* defined(DISABLE_DUMP) */
660 /* dump_realloc ****************************************************************
662 Stupid realloc implementation for dump memory. Avoid, if possible.
664 *******************************************************************************/
666 void *dump_realloc(void *src, s4 len1, s4 len2)
668 #if defined(DISABLE_DUMP)
669 /* use malloc memory for dump memory (for debugging only!) */
671 return mem_realloc(src, len1, len2);
673 void *dst = dump_alloc(len2);
675 memcpy(dst, src, len1);
677 #if defined(ENABLE_MEMCHECK)
678 /* destroy the source */
679 memset(src, MEMORY_CLEAR_BYTE, len1);
687 /* dump_release ****************************************************************
689 Release dump memory above the given size.
692 size........All dump memory above this mark will be freed. Usually
693 `size` will be the return value of a `dump_size` call
697 XXX If the given size is invalid, this function *exits* with an
702 *******************************************************************************/
704 void dump_release(s4 size)
706 #if defined(DISABLE_DUMP)
708 /* use malloc memory for dump memory (for debugging only!) */
712 #else /* !defined(DISABLE_DUMP) */
716 /* If no threads are used, the dumpinfo structure is a static structure */
717 /* defined at the top of this file. */
721 if ((size < 0) || (size > di->useddumpsize))
722 vm_abort("Illegal dump release size: %d", size);
724 #if defined(ENABLE_MEMCHECK)
726 dump_allocation_t *da, *next;
730 dump_check_canaries(di, size);
732 /* iterate over all dump memory allocations about to be released */
734 da = di->allocations;
735 while (da && da->useddumpsize >= size) {
738 /* invalidate the freed memory */
740 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
742 FREE(da, dump_allocation_t);
746 di->allocations = da;
748 #endif /* defined(ENABLE_MEMCHECK) */
750 /* reset the used dump size to the size specified */
752 di->useddumpsize = size;
754 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
755 dumpblock_t *tmp = di->currentdumpblock;
757 di->allocateddumpsize -= tmp->size;
758 di->currentdumpblock = tmp->prev;
760 #if defined(ENABLE_STATISTICS)
761 /* the amount of globally allocated dump memory (thread save) */
764 globalallocateddumpsize -= tmp->size;
767 /* release the dump memory and the dumpinfo structure */
773 #endif /* defined(DISABLE_DUMP) */
777 /* dump_size *******************************************************************
779 Return the current size of the dump memory area. See `dump_alloc`.
781 *******************************************************************************/
785 #if defined(DISABLE_DUMP)
786 /* use malloc memory for dump memory (for debugging only!) */
790 #else /* !defined(DISABLE_DUMP) */
794 /* If no threads are used, the dumpinfo structure is a static structure */
795 /* defined at the top of this file. */
802 return di->useddumpsize;
804 #endif /* defined(DISABLE_DUMP) */
809 * These are local overrides for various environment variables in Emacs.
810 * Please do not remove this and leave it at the end of the file, where
811 * Emacs will automagically detect them.
812 * ---------------------------------------------------------------------
815 * indent-tabs-mode: t
819 * vim:noexpandtab:sw=4:ts=4: