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 7338 2007-02-13 00:17:22Z 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 /* global variables ***********************************************************/
113 #if defined(ENABLE_THREADS)
114 static threadobject *thread_memory;
118 /* memory_init *****************************************************************
120 Initialize the memory subsystem.
122 *******************************************************************************/
124 bool memory_init(void)
126 #if defined(ENABLE_THREADS)
127 /* create lock for code memory */
129 lock_code_memory = NEW(java_objectheader);
131 lock_init_object_lock(lock_code_memory);
134 /* get the pagesize of this architecture */
136 pagesize = getpagesize();
138 /* everything's ok */
144 /* memory_mmap_anon ************************************************************
146 Maps anonymous memory, even on systems not defining
149 *******************************************************************************/
151 void *memory_mmap_anon(void *addr, size_t len, int prot, int flags)
155 #if defined(MAP_ANON) || defined(MAP_ANONYMOUS)
156 p = mmap(addr, len, prot,
157 # if defined(MAP_ANON)
160 MAP_ANONYMOUS | flags,
166 fd = open("/dev/zero", O_RDONLY, 0);
169 vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
171 p = mmap(addr, len, prot, flags, fd, 0);
174 #if defined(MAP_FAILED)
177 if (p == (void *) -1)
179 vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno));
185 /* memory_checked_alloc ********************************************************
187 Allocated zeroed-out memory and does an OOM check.
190 XXX If no memory could be allocated, this function justs *exists*.
192 *******************************************************************************/
194 static void *memory_checked_alloc(s4 size)
196 /* always allocate memory zeroed out */
198 void *p = calloc(size, 1);
201 vm_abort("memory_checked_alloc: calloc failed: out of memory");
207 /* memory_cnew *****************************************************************
209 Allocates memory from the heap via mmap and make the memory read-,
210 write-, and executeable.
212 *******************************************************************************/
214 void *memory_cnew(s4 size)
218 LOCK_MONITOR_ENTER(lock_code_memory);
220 size = MEMORY_ALIGN(size, ALIGNSIZE);
222 /* check if enough memory is available */
224 if (size > code_memory_size) {
225 /* set default code size */
227 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
229 /* do we need more? */
231 if (size > code_memory_size)
232 code_memory_size = size;
234 /* align the size of the memory to be allocated */
236 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
238 #if defined(ENABLE_STATISTICS)
240 codememusage += code_memory_size;
242 if (codememusage > maxcodememusage)
243 maxcodememusage = codememusage;
247 /* allocate the memory */
249 p = memory_mmap_anon(NULL, code_memory_size,
250 PROT_READ | PROT_WRITE | PROT_EXEC,
253 /* set global code memory pointer */
258 /* get a memory chunk of the allocated memory */
262 code_memory = (void *) ((ptrint) code_memory + size);
263 code_memory_size -= size;
265 LOCK_MONITOR_EXIT(lock_code_memory);
271 /* memory_cfree ****************************************************************
273 Frees the code memory pointed to.
275 ATTENTION: This function currently does NOTHING! Because we don't
276 have a memory management for code memory.
278 *******************************************************************************/
280 void memory_cfree(void *p, s4 size)
286 void *mem_alloc(s4 size)
293 #if defined(ENABLE_STATISTICS)
297 if (memoryusage > maxmemusage)
298 maxmemusage = memoryusage;
302 m = memory_checked_alloc(size);
304 #if defined(ENABLE_MEMCHECK)
305 /* XXX we would like to poison the memory, but callers rely on */
306 /* the zeroing. This should change sooner or later. */
307 /* memset(m, MEMORY_CLEAR_BYTE, size); */
314 void *mem_realloc(void *src, s4 len1, s4 len2)
318 /* prevent compiler warnings */
324 vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0");
326 #if defined(ENABLE_STATISTICS)
328 memoryusage = (memoryusage - len1) + len2;
331 #if defined(ENABLE_MEMCHECK)
333 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
336 dst = realloc(src, len2);
339 vm_abort("mem_realloc: realloc failed: out of memory");
341 #if defined(ENABLE_MEMCHECK)
343 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
350 void mem_free(void *m, s4 size)
356 log_text("returned memoryblock with address NULL, length != 0");
360 #if defined(ENABLE_STATISTICS)
365 #if defined(ENABLE_MEMCHECK)
366 /* destroy the contents */
367 memset(m, MEMORY_CLEAR_BYTE, size);
374 /* memory_thread ***************************************************************
376 Prints regularly memory statistics.
378 *******************************************************************************/
380 #if defined(ENABLE_THREADS)
381 static void memory_thread(void)
384 /* sleep thread for 2 seconds */
386 threads_sleep(2 * 1000, 0);
388 log_println("memory_thread:");
394 /* memory_start_thread *********************************************************
396 Starts the memory profiling thread.
398 *******************************************************************************/
400 #if defined(ENABLE_THREADS)
401 bool memory_start_thread(void)
405 name = utf_new_char("Memory Profiler");
407 thread_memory = threads_create_thread(name);
409 if (thread_memory == NULL)
412 /* actually start the memory profiling thread */
414 threads_start_thread(thread_memory, memory_thread);
416 /* everything's ok */
423 /* dump_check_canaries *********************************************************
425 Check canaries in dump memory.
428 di...........dumpinfo_t * of the dump area to check
429 bottomsize...dump size down to which the dump area should be checked
430 (specify 0 to check the whole dump area)
433 If any canary has been changed, this function aborts the VM with
436 *******************************************************************************/
438 #if defined(ENABLE_MEMCHECK)
439 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
441 dump_allocation_t *da;
445 /* iterate over all dump memory allocations above bottomsize */
447 da = di->allocations;
448 while (da && da->useddumpsize >= bottomsize) {
451 pm = da->mem - MEMORY_CANARY_SIZE;
452 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
453 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
454 fprintf(stderr, "canary bytes:");
455 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
456 fprintf(stderr, " %02x", pm[j]);
457 fprintf(stderr,"\n");
458 vm_abort("error: dump memory bottom canary killed: "
459 "%p (%d bytes allocated at %p)\n",
460 pm + i, da->size, da->mem);
463 pm = da->mem + da->size;
464 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
465 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
466 fprintf(stderr, "canary bytes:");
467 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
468 fprintf(stderr, " %02x", pm[j]);
469 fprintf(stderr,"\n");
470 vm_abort("error: dump memory top canary killed: "
471 "%p (%d bytes allocated at %p)\n",
472 pm + i, da->size, da->mem);
478 #endif /* defined(ENABLE_MEMCHECK) */
481 /* dump_alloc ******************************************************************
483 Allocate memory in the dump area.
486 size.........size of block to allocate, in bytes
487 may be zero, in which case NULL is returned
490 pointer to allocated memory, or
491 NULL iff `size` was zero
494 XXX This function uses `memory_checked_alloc`, which *exits* if no
495 memory could be allocated.
498 dump_alloc is thread safe. Each thread has its own dump memory area.
500 dump_alloc is a fast allocator suitable for scratch memory that can be
501 collectively freed when the current activity (eg. compiling) is done.
503 You cannot selectively free dump memory. Before you start allocating it,
504 you remember the current size returned by `dump_size`. Later, when you no
505 longer need the memory, call `dump_release` with the remembered size and
506 all dump memory allocated since the call to `dump_size` will be freed.
508 *******************************************************************************/
510 void *dump_alloc(s4 size)
512 #if defined(DISABLE_DUMP)
514 /* use malloc memory for dump memory (for debugging only!) */
516 return mem_alloc(size);
518 #else /* !defined(DISABLE_DUMP) */
522 #if defined(ENABLE_MEMCHECK)
523 s4 origsize = size; /* needed for the canary system */
526 /* If no threads are used, the dumpinfo structure is a static structure */
527 /* defined at the top of this file. */
534 #if defined(ENABLE_MEMCHECK)
535 size += 2*MEMORY_CANARY_SIZE;
538 size = MEMORY_ALIGN(size, ALIGNSIZE);
540 if (di->useddumpsize + size > di->allocateddumpsize) {
541 dumpblock_t *newdumpblock;
544 /* allocate a new dumplist structure */
546 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
548 /* If requested size is greater than the default, make the new dump */
549 /* block as big as the size requested. Else use the default size. */
551 if (size > DUMPBLOCKSIZE) {
552 newdumpblocksize = size;
555 newdumpblocksize = DUMPBLOCKSIZE;
558 /* allocate dumpblock memory */
560 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
562 newdumpblock->prev = di->currentdumpblock;
563 newdumpblock->size = newdumpblocksize;
564 di->currentdumpblock = newdumpblock;
566 /* Used dump size is previously allocated dump size, because the */
567 /* remaining free memory of the previous dump block cannot be used. */
569 di->useddumpsize = di->allocateddumpsize;
571 /* increase the allocated dump size by the size of the new dump block */
573 di->allocateddumpsize += newdumpblocksize;
575 #if defined(ENABLE_STATISTICS)
576 /* the amount of globally allocated dump memory (thread save) */
579 globalallocateddumpsize += newdumpblocksize;
583 /* current dump block base address + the size of the current dump block - */
584 /* the size of the unused memory = new start address */
586 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
587 (di->allocateddumpsize - di->useddumpsize);
589 #if defined(ENABLE_MEMCHECK)
591 dump_allocation_t *da = NEW(dump_allocation_t);
595 /* add the allocation to our linked list of allocations */
597 da->next = di->allocations;
598 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
600 da->useddumpsize = di->useddumpsize;
602 di->allocations = da;
604 /* write the canaries */
607 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
608 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
609 pm = da->mem + da->size;
610 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
611 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
613 /* make m point after the bottom canary */
615 m = (u1*)m + MEMORY_CANARY_SIZE;
617 /* clear the memory */
619 memset(m, MEMORY_CLEAR_BYTE, da->size);
621 #endif /* defined(ENABLE_MEMCHECK) */
623 /* increase used dump size by the allocated memory size */
625 di->useddumpsize += size;
627 #if defined(ENABLE_STATISTICS)
629 if (di->useddumpsize > maxdumpsize)
630 maxdumpsize = di->useddumpsize;
635 #endif /* defined(DISABLE_DUMP) */
639 /* dump_realloc ****************************************************************
641 Stupid realloc implementation for dump memory. Avoid, if possible.
643 *******************************************************************************/
645 void *dump_realloc(void *src, s4 len1, s4 len2)
647 #if defined(DISABLE_DUMP)
648 /* use malloc memory for dump memory (for debugging only!) */
650 return mem_realloc(src, len1, len2);
652 void *dst = dump_alloc(len2);
654 memcpy(dst, src, len1);
656 #if defined(ENABLE_MEMCHECK)
657 /* destroy the source */
658 memset(src, MEMORY_CLEAR_BYTE, len1);
666 /* dump_release ****************************************************************
668 Release dump memory above the given size.
671 size........All dump memory above this mark will be freed. Usually
672 `size` will be the return value of a `dump_size` call
676 XXX If the given size is invalid, this function *exits* with an
681 *******************************************************************************/
683 void dump_release(s4 size)
685 #if defined(DISABLE_DUMP)
687 /* use malloc memory for dump memory (for debugging only!) */
691 #else /* !defined(DISABLE_DUMP) */
695 /* If no threads are used, the dumpinfo structure is a static structure */
696 /* defined at the top of this file. */
700 if ((size < 0) || (size > di->useddumpsize))
701 vm_abort("Illegal dump release size: %d", size);
703 #if defined(ENABLE_MEMCHECK)
705 dump_allocation_t *da, *next;
709 dump_check_canaries(di, size);
711 /* iterate over all dump memory allocations about to be released */
713 da = di->allocations;
714 while (da && da->useddumpsize >= size) {
717 /* invalidate the freed memory */
719 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
721 FREE(da, dump_allocation_t);
725 di->allocations = da;
727 #endif /* defined(ENABLE_MEMCHECK) */
729 /* reset the used dump size to the size specified */
731 di->useddumpsize = size;
733 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
734 dumpblock_t *tmp = di->currentdumpblock;
736 di->allocateddumpsize -= tmp->size;
737 di->currentdumpblock = tmp->prev;
739 #if defined(ENABLE_STATISTICS)
740 /* the amount of globally allocated dump memory (thread save) */
743 globalallocateddumpsize -= tmp->size;
746 /* release the dump memory and the dumpinfo structure */
752 #endif /* defined(DISABLE_DUMP) */
756 /* dump_size *******************************************************************
758 Return the current size of the dump memory area. See `dump_alloc`.
760 *******************************************************************************/
764 #if defined(DISABLE_DUMP)
765 /* use malloc memory for dump memory (for debugging only!) */
769 #else /* !defined(DISABLE_DUMP) */
773 /* If no threads are used, the dumpinfo structure is a static structure */
774 /* defined at the top of this file. */
781 return di->useddumpsize;
783 #endif /* defined(DISABLE_DUMP) */
788 * These are local overrides for various environment variables in Emacs.
789 * Please do not remove this and leave it at the end of the file, where
790 * Emacs will automagically detect them.
791 * ---------------------------------------------------------------------
794 * indent-tabs-mode: t
798 * vim:noexpandtab:sw=4:ts=4: