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 7394 2007-02-23 22:47:06Z michi $
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/threads-common.h"
56 # include "threads/native/lock.h"
57 # include "threads/native/threads.h"
59 # include "threads/none/lock.h"
62 #include "toolbox/logging.h"
63 #include "vm/exceptions.h"
64 #include "vm/global.h"
65 #include "vm/stringlocal.h"
67 #include "vmcore/options.h"
69 #if defined(ENABLE_STATISTICS)
70 # include "vmcore/statistics.h"
74 /*******************************************************************************
76 This structure is used for dump memory allocation if cacao
79 *******************************************************************************/
81 #if !defined(ENABLE_THREADS)
82 static dumpinfo_t _no_threads_dumpinfo;
85 #if defined(ENABLE_THREADS)
86 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
88 #define DUMPINFO &_no_threads_dumpinfo
92 /* global code memory variables ***********************************************/
94 #define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
96 #if defined(ENABLE_THREADS)
97 static java_objectheader *lock_code_memory = NULL;
99 static void *code_memory = NULL;
100 static int code_memory_size = 0;
101 static int pagesize = 0;
104 /* global variables ***********************************************************/
106 #if defined(ENABLE_THREADS)
107 static threadobject *thread_memory;
111 /* memory_init *****************************************************************
113 Initialize the memory subsystem.
115 *******************************************************************************/
117 bool memory_init(void)
119 #if defined(ENABLE_THREADS)
120 /* create lock for code memory */
122 lock_code_memory = NEW(java_objectheader);
124 lock_init_object_lock(lock_code_memory);
127 /* get the pagesize of this architecture */
129 pagesize = getpagesize();
131 /* everything's ok */
137 /* memory_mmap_anon ************************************************************
139 Maps anonymous memory, even on systems not defining
142 *******************************************************************************/
144 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
148 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
149 p = mmap(addr, len, prot,
150 # if defined(MAP_ANON)
153 MAP_ANONYMOUS | flags,
159 fd = open("/dev/zero", O_RDONLY, 0);
162 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
164 p = mmap(addr, len, prot, flags, fd, 0);
167 #if defined(MAP_FAILED)
170 if (p == (void *) -1)
172 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
178 /* memory_checked_alloc ********************************************************
180 Allocated zeroed-out memory and does an OOM check.
183 XXX If no memory could be allocated, this function justs *exists*.
185 *******************************************************************************/
187 static void *memory_checked_alloc(s4 size)
189 /* always allocate memory zeroed out */
191 void *p = calloc(size, 1);
194 vm_abort("memory_checked_alloc: calloc failed: out of memory");
200 /* memory_cnew *****************************************************************
202 Allocates memory from the heap via mmap and make the memory read-,
203 write-, and executeable.
205 *******************************************************************************/
207 void *memory_cnew(s4 size)
211 LOCK_MONITOR_ENTER(lock_code_memory);
213 size = MEMORY_ALIGN(size, ALIGNSIZE);
215 /* check if enough memory is available */
217 if (size > code_memory_size) {
218 /* set default code size */
220 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
222 /* do we need more? */
224 if (size > code_memory_size)
225 code_memory_size = size;
227 /* align the size of the memory to be allocated */
229 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
231 #if defined(ENABLE_STATISTICS)
233 codememusage += code_memory_size;
235 if (codememusage > maxcodememusage)
236 maxcodememusage = codememusage;
240 /* allocate the memory */
242 p = memory_mmap_anon(NULL, code_memory_size,
243 PROT_READ | PROT_WRITE | PROT_EXEC,
246 /* set global code memory pointer */
251 /* get a memory chunk of the allocated memory */
255 code_memory = (void *) ((ptrint) code_memory + size);
256 code_memory_size -= size;
258 LOCK_MONITOR_EXIT(lock_code_memory);
264 /* memory_cfree ****************************************************************
266 Frees the code memory pointed to.
268 ATTENTION: This function currently does NOTHING! Because we don't
269 have a memory management for code memory.
271 *******************************************************************************/
273 void memory_cfree(void *p, s4 size)
279 void *mem_alloc(s4 size)
286 #if defined(ENABLE_STATISTICS)
290 if (memoryusage > maxmemusage)
291 maxmemusage = memoryusage;
295 m = memory_checked_alloc(size);
297 #if defined(ENABLE_MEMCHECK)
298 /* XXX we would like to poison the memory, but callers rely on */
299 /* the zeroing. This should change sooner or later. */
300 /* memset(m, MEMORY_CLEAR_BYTE, size); */
307 void *mem_realloc(void *src, s4 len1, s4 len2)
311 /* prevent compiler warnings */
317 vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
319 #if defined(ENABLE_STATISTICS)
321 memoryusage = (memoryusage - len1) + len2;
324 #if defined(ENABLE_MEMCHECK)
326 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
329 dst = realloc(src, len2);
332 vm_abort("mem_realloc: realloc failed: out of memory");
334 #if defined(ENABLE_MEMCHECK)
336 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
343 void mem_free(void *m, s4 size)
349 log_text("returned memoryblock with address NULL, length != 0");
353 #if defined(ENABLE_STATISTICS)
358 #if defined(ENABLE_MEMCHECK)
359 /* destroy the contents */
360 memset(m, MEMORY_CLEAR_BYTE, size);
367 /* memory_thread ***************************************************************
369 Prints regularly memory statistics.
371 *******************************************************************************/
373 #if defined(ENABLE_THREADS) && !defined(NDEBUG)
374 static void memory_thread(void)
377 /* sleep thread for 2 seconds */
379 threads_sleep(2 * 1000, 0);
381 # if defined(ENABLE_STATISTICS)
382 /* print memory usage */
384 statistics_print_memory_usage();
386 /* print GC memory usage */
388 statistics_print_gc_memory_usage();
395 /* memory_start_thread *********************************************************
397 Starts the memory profiling thread.
399 *******************************************************************************/
401 #if defined(ENABLE_THREADS) && !defined(NDEBUG)
402 bool memory_start_thread(void)
406 name = utf_new_char("Memory Profiler");
408 thread_memory = threads_create_thread(name);
410 if (thread_memory == NULL)
413 /* actually start the memory profiling thread */
415 threads_start_thread(thread_memory, memory_thread);
417 /* everything's ok */
424 /* dump_check_canaries *********************************************************
426 Check canaries in dump memory.
429 di...........dumpinfo_t * of the dump area to check
430 bottomsize...dump size down to which the dump area should be checked
431 (specify 0 to check the whole dump area)
434 If any canary has been changed, this function aborts the VM with
437 *******************************************************************************/
439 #if defined(ENABLE_MEMCHECK)
440 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
442 dump_allocation_t *da;
446 /* iterate over all dump memory allocations above bottomsize */
448 da = di->allocations;
449 while (da && da->useddumpsize >= bottomsize) {
452 pm = da->mem - MEMORY_CANARY_SIZE;
453 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
454 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
455 fprintf(stderr, "canary bytes:");
456 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
457 fprintf(stderr, " %02x", pm[j]);
458 fprintf(stderr,"\n");
459 vm_abort("error: dump memory bottom canary killed: "
460 "%p (%d bytes allocated at %p)\n",
461 pm + i, da->size, da->mem);
464 pm = da->mem + da->size;
465 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
466 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
467 fprintf(stderr, "canary bytes:");
468 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
469 fprintf(stderr, " %02x", pm[j]);
470 fprintf(stderr,"\n");
471 vm_abort("error: dump memory top canary killed: "
472 "%p (%d bytes allocated at %p)\n",
473 pm + i, da->size, da->mem);
479 #endif /* defined(ENABLE_MEMCHECK) */
482 /* dump_alloc ******************************************************************
484 Allocate memory in the dump area.
487 size.........size of block to allocate, in bytes
488 may be zero, in which case NULL is returned
491 pointer to allocated memory, or
492 NULL iff `size` was zero
495 XXX This function uses `memory_checked_alloc`, which *exits* if no
496 memory could be allocated.
499 dump_alloc is thread safe. Each thread has its own dump memory area.
501 dump_alloc is a fast allocator suitable for scratch memory that can be
502 collectively freed when the current activity (eg. compiling) is done.
504 You cannot selectively free dump memory. Before you start allocating it,
505 you remember the current size returned by `dump_size`. Later, when you no
506 longer need the memory, call `dump_release` with the remembered size and
507 all dump memory allocated since the call to `dump_size` will be freed.
509 *******************************************************************************/
511 void *dump_alloc(s4 size)
513 #if defined(DISABLE_DUMP)
515 /* use malloc memory for dump memory (for debugging only!) */
517 return mem_alloc(size);
519 #else /* !defined(DISABLE_DUMP) */
523 #if defined(ENABLE_MEMCHECK)
524 s4 origsize = size; /* needed for the canary system */
527 /* If no threads are used, the dumpinfo structure is a static structure */
528 /* defined at the top of this file. */
535 #if defined(ENABLE_MEMCHECK)
536 size += 2*MEMORY_CANARY_SIZE;
539 size = MEMORY_ALIGN(size, ALIGNSIZE);
541 if (di->useddumpsize + size > di->allocateddumpsize) {
542 dumpblock_t *newdumpblock;
545 /* allocate a new dumplist structure */
547 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
549 /* If requested size is greater than the default, make the new dump */
550 /* block as big as the size requested. Else use the default size. */
552 if (size > DUMPBLOCKSIZE) {
553 newdumpblocksize = size;
556 newdumpblocksize = DUMPBLOCKSIZE;
559 /* allocate dumpblock memory */
561 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
563 newdumpblock->prev = di->currentdumpblock;
564 newdumpblock->size = newdumpblocksize;
565 di->currentdumpblock = newdumpblock;
567 /* Used dump size is previously allocated dump size, because the */
568 /* remaining free memory of the previous dump block cannot be used. */
570 di->useddumpsize = di->allocateddumpsize;
572 /* increase the allocated dump size by the size of the new dump block */
574 di->allocateddumpsize += newdumpblocksize;
576 #if defined(ENABLE_STATISTICS)
577 /* the amount of globally allocated dump memory (thread save) */
580 globalallocateddumpsize += newdumpblocksize;
584 /* current dump block base address + the size of the current dump block - */
585 /* the size of the unused memory = new start address */
587 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
588 (di->allocateddumpsize - di->useddumpsize);
590 #if defined(ENABLE_MEMCHECK)
592 dump_allocation_t *da = NEW(dump_allocation_t);
596 /* add the allocation to our linked list of allocations */
598 da->next = di->allocations;
599 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
601 da->useddumpsize = di->useddumpsize;
603 di->allocations = da;
605 /* write the canaries */
608 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
609 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
610 pm = da->mem + da->size;
611 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
612 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
614 /* make m point after the bottom canary */
616 m = (u1*)m + MEMORY_CANARY_SIZE;
618 /* clear the memory */
620 memset(m, MEMORY_CLEAR_BYTE, da->size);
622 #endif /* defined(ENABLE_MEMCHECK) */
624 /* increase used dump size by the allocated memory size */
626 di->useddumpsize += size;
628 #if defined(ENABLE_STATISTICS)
630 if (di->useddumpsize > maxdumpsize)
631 maxdumpsize = di->useddumpsize;
636 #endif /* defined(DISABLE_DUMP) */
640 /* dump_realloc ****************************************************************
642 Stupid realloc implementation for dump memory. Avoid, if possible.
644 *******************************************************************************/
646 void *dump_realloc(void *src, s4 len1, s4 len2)
648 #if defined(DISABLE_DUMP)
649 /* use malloc memory for dump memory (for debugging only!) */
651 return mem_realloc(src, len1, len2);
653 void *dst = dump_alloc(len2);
655 memcpy(dst, src, len1);
657 #if defined(ENABLE_MEMCHECK)
658 /* destroy the source */
659 memset(src, MEMORY_CLEAR_BYTE, len1);
667 /* dump_release ****************************************************************
669 Release dump memory above the given size.
672 size........All dump memory above this mark will be freed. Usually
673 `size` will be the return value of a `dump_size` call
677 XXX If the given size is invalid, this function *exits* with an
682 *******************************************************************************/
684 void dump_release(s4 size)
686 #if defined(DISABLE_DUMP)
688 /* use malloc memory for dump memory (for debugging only!) */
692 #else /* !defined(DISABLE_DUMP) */
696 /* If no threads are used, the dumpinfo structure is a static structure */
697 /* defined at the top of this file. */
701 if ((size < 0) || (size > di->useddumpsize))
702 vm_abort("Illegal dump release size: %d", size);
704 #if defined(ENABLE_MEMCHECK)
706 dump_allocation_t *da, *next;
710 dump_check_canaries(di, size);
712 /* iterate over all dump memory allocations about to be released */
714 da = di->allocations;
715 while (da && da->useddumpsize >= size) {
718 /* invalidate the freed memory */
720 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
722 FREE(da, dump_allocation_t);
726 di->allocations = da;
728 #endif /* defined(ENABLE_MEMCHECK) */
730 /* reset the used dump size to the size specified */
732 di->useddumpsize = size;
734 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
735 dumpblock_t *tmp = di->currentdumpblock;
737 di->allocateddumpsize -= tmp->size;
738 di->currentdumpblock = tmp->prev;
740 #if defined(ENABLE_STATISTICS)
741 /* the amount of globally allocated dump memory (thread save) */
744 globalallocateddumpsize -= tmp->size;
747 /* release the dump memory and the dumpinfo structure */
753 #endif /* defined(DISABLE_DUMP) */
757 /* dump_size *******************************************************************
759 Return the current size of the dump memory area. See `dump_alloc`.
761 *******************************************************************************/
765 #if defined(DISABLE_DUMP)
766 /* use malloc memory for dump memory (for debugging only!) */
770 #else /* !defined(DISABLE_DUMP) */
774 /* If no threads are used, the dumpinfo structure is a static structure */
775 /* defined at the top of this file. */
782 return di->useddumpsize;
784 #endif /* defined(DISABLE_DUMP) */
789 * These are local overrides for various environment variables in Emacs.
790 * Please do not remove this and leave it at the end of the file, where
791 * Emacs will automagically detect them.
792 * ---------------------------------------------------------------------
795 * indent-tabs-mode: t
799 * vim:noexpandtab:sw=4:ts=4: