3 Copyright (C) 1996-2005, 2006 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 Contact: cacao@cacaojvm.org
27 Authors: Reinhard Grafl
29 Changes: Christian Thalinger
32 $Id: memory.c 5901 2006-11-04 22:01:51Z edwin $
47 #if defined(__DARWIN__)
48 /* If we compile with -ansi on darwin, <sys/types.h> is not included. So */
49 /* let's do it here. */
50 # include <sys/types.h>
57 #include "mm/memory.h"
58 #include "native/native.h"
60 #if defined(ENABLE_THREADS)
61 # include "threads/native/lock.h"
62 # include "threads/native/threads.h"
64 # include "threads/none/lock.h"
67 #include "toolbox/logging.h"
68 #include "vm/exceptions.h"
69 #include "vm/global.h"
70 #include "vm/options.h"
71 #include "vm/statistics.h"
72 #include "vm/stringlocal.h"
76 /* constants for ENABLE_MEMCHECK **********************************************/
78 #if defined(ENABLE_MEMCHECK)
79 #define MEMORY_CANARY_SIZE 16
80 #define MEMORY_CANARY_FIRST_BYTE 0xca
81 #define MEMORY_CLEAR_BYTE 0xa5
82 #endif /* defined(ENABLE_MEMCHECK) */
85 /*******************************************************************************
87 This structure is used for dump memory allocation if cacao
90 *******************************************************************************/
92 #if !defined(ENABLE_THREADS)
93 static dumpinfo_t _no_threads_dumpinfo;
96 #if defined(ENABLE_THREADS)
97 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
99 #define DUMPINFO &_no_threads_dumpinfo
103 /* global code memory variables ***********************************************/
105 #define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */
107 #if defined(ENABLE_THREADS)
108 static java_objectheader *lock_code_memory = NULL;
110 static void *code_memory = NULL;
111 static int code_memory_size = 0;
112 static int pagesize = 0;
115 /* memory_init *****************************************************************
117 Initialize the memory subsystem.
119 *******************************************************************************/
121 bool memory_init(void)
123 #if defined(ENABLE_THREADS)
124 lock_code_memory = NEW(java_objectheader);
126 lock_init_object_lock(lock_code_memory);
129 /* get the pagesize of this architecture */
131 pagesize = getpagesize();
133 /* everything's ok */
139 /* memory_checked_alloc ********************************************************
141 Allocated zeroed-out memory and does an OOM check.
144 XXX If no memory could be allocated, this function justs *exists*.
146 *******************************************************************************/
148 static void *memory_checked_alloc(s4 size)
150 /* always allocate memory zeroed out */
152 void *p = calloc(size, 1);
155 exceptions_throw_outofmemory_exit();
161 /* memory_cnew *****************************************************************
163 Allocates memory from the heap via mmap and make the memory read-,
164 write-, and executeable.
166 *******************************************************************************/
168 void *memory_cnew(s4 size)
172 LOCK_MONITOR_ENTER(lock_code_memory);
174 size = MEMORY_ALIGN(size, ALIGNSIZE);
176 /* check if enough memory is available */
178 if (size > code_memory_size) {
179 /* set default code size */
181 code_memory_size = DEFAULT_CODE_MEMORY_SIZE;
183 /* do we need more? */
185 if (size > code_memory_size)
186 code_memory_size = size;
188 /* align the size of the memory to be allocated */
190 code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize);
192 #if defined(ENABLE_STATISTICS)
194 codememusage += code_memory_size;
196 if (codememusage > maxcodememusage)
197 maxcodememusage = codememusage;
201 /* allocate the memory */
203 #if defined(MAP_ANONYMOUS) || defined(MAP_ANON)
205 (size_t) code_memory_size,
206 PROT_READ | PROT_WRITE | PROT_EXEC,
208 # if defined(MAP_ANONYMOUS)
210 # elif defined(MAP_ANON)
218 # if defined(MAP_FAILED)
221 if (p == (void *) -1)
223 vm_abort("mmap failed: %s", strerror(errno));
226 /* This works a least on IRIX. */
228 p = memory_checked_alloc(code_memory_size);
231 /* set global code memory pointer */
236 /* get a memory chunk of the allocated memory */
240 code_memory = (void *) ((ptrint) code_memory + size);
241 code_memory_size -= size;
243 LOCK_MONITOR_EXIT(lock_code_memory);
249 /* memory_cfree ****************************************************************
251 Frees the code memory pointed to.
253 ATTENTION: This function currently does NOTHING! Because we don't
254 have a memory management for code memory.
256 *******************************************************************************/
258 void memory_cfree(void *p, s4 size)
264 void *mem_alloc(s4 size)
271 #if defined(ENABLE_STATISTICS)
275 if (memoryusage > maxmemusage)
276 maxmemusage = memoryusage;
280 m = memory_checked_alloc(size);
282 #if defined(ENABLE_MEMCHECK)
283 /* XXX we would like to poison the memory, but callers rely on */
284 /* the zeroing. This should change sooner or later. */
285 /* memset(m, MEMORY_CLEAR_BYTE, size); */
292 void *mem_realloc(void *src, s4 len1, s4 len2)
298 log_text("reallocating memoryblock with address NULL, length != 0");
303 #if defined(ENABLE_STATISTICS)
305 memoryusage = (memoryusage - len1) + len2;
308 #if defined(ENABLE_MEMCHECK)
310 memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2);
313 dst = realloc(src, len2);
316 exceptions_throw_outofmemory_exit();
318 #if defined(ENABLE_MEMCHECK)
320 memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1);
327 void mem_free(void *m, s4 size)
333 log_text("returned memoryblock with address NULL, length != 0");
337 #if defined(ENABLE_STATISTICS)
342 #if defined(ENABLE_MEMCHECK)
343 /* destroy the contents */
344 memset(m, MEMORY_CLEAR_BYTE, size);
351 /* dump_check_canaries *********************************************************
353 Check canaries in dump memory.
356 di...........dumpinfo_t * of the dump area to check
357 bottomsize...dump size down to which the dump area should be checked
358 (specify 0 to check the whole dump area)
361 If any canary has been changed, this function aborts the VM with
364 *******************************************************************************/
366 #if defined(ENABLE_MEMCHECK)
367 void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
369 dump_allocation_t *da;
373 /* iterate over all dump memory allocations above bottomsize */
375 da = di->allocations;
376 while (da && da->useddumpsize >= bottomsize) {
379 pm = da->mem - MEMORY_CANARY_SIZE;
380 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
381 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
382 fprintf(stderr, "canary bytes:");
383 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
384 fprintf(stderr, " %02x", pm[j]);
385 fprintf(stderr,"\n");
386 vm_abort("error: dump memory bottom canary killed: "
387 "%p (%d bytes allocated at %p)\n",
388 pm + i, da->size, da->mem);
391 pm = da->mem + da->size;
392 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
393 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
394 fprintf(stderr, "canary bytes:");
395 for (j=0; j<MEMORY_CANARY_SIZE; ++j)
396 fprintf(stderr, " %02x", pm[j]);
397 fprintf(stderr,"\n");
398 vm_abort("error: dump memory top canary killed: "
399 "%p (%d bytes allocated at %p)\n",
400 pm + i, da->size, da->mem);
406 #endif /* defined(ENABLE_MEMCHECK) */
409 /* dump_alloc ******************************************************************
411 Allocate memory in the dump area.
414 size.........size of block to allocate, in bytes
415 may be zero, in which case NULL is returned
418 pointer to allocated memory, or
419 NULL iff `size` was zero
422 XXX This function uses `memory_checked_alloc`, which *exits* if no
423 memory could be allocated.
426 dump_alloc is thread safe. Each thread has its own dump memory area.
428 dump_alloc is a fast allocator suitable for scratch memory that can be
429 collectively freed when the current activity (eg. compiling) is done.
431 You cannot selectively free dump memory. Before you start allocating it,
432 you remember the current size returned by `dump_size`. Later, when you no
433 longer need the memory, call `dump_release` with the remembered size and
434 all dump memory allocated since the call to `dump_size` will be freed.
436 *******************************************************************************/
438 void *dump_alloc(s4 size)
440 #if defined(DISABLE_DUMP)
442 /* use malloc memory for dump memory (for debugging only!) */
444 return mem_alloc(size);
446 #else /* !defined(DISABLE_DUMP) */
450 #if defined(ENABLE_MEMCHECK)
451 s4 origsize = size; /* needed for the canary system */
454 /* If no threads are used, the dumpinfo structure is a static structure */
455 /* defined at the top of this file. */
462 #if defined(ENABLE_MEMCHECK)
463 size += 2*MEMORY_CANARY_SIZE;
466 size = MEMORY_ALIGN(size, ALIGNSIZE);
468 if (di->useddumpsize + size > di->allocateddumpsize) {
469 dumpblock_t *newdumpblock;
472 /* allocate a new dumplist structure */
474 newdumpblock = memory_checked_alloc(sizeof(dumpblock_t));
476 /* If requested size is greater than the default, make the new dump */
477 /* block as big as the size requested. Else use the default size. */
479 if (size > DUMPBLOCKSIZE) {
480 newdumpblocksize = size;
483 newdumpblocksize = DUMPBLOCKSIZE;
486 /* allocate dumpblock memory */
488 newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
490 newdumpblock->prev = di->currentdumpblock;
491 newdumpblock->size = newdumpblocksize;
492 di->currentdumpblock = newdumpblock;
494 /* Used dump size is previously allocated dump size, because the */
495 /* remaining free memory of the previous dump block cannot be used. */
497 di->useddumpsize = di->allocateddumpsize;
499 /* increase the allocated dump size by the size of the new dump block */
501 di->allocateddumpsize += newdumpblocksize;
503 #if defined(ENABLE_STATISTICS)
504 /* the amount of globally allocated dump memory (thread save) */
507 globalallocateddumpsize += newdumpblocksize;
511 /* current dump block base address + the size of the current dump block - */
512 /* the size of the unused memory = new start address */
514 m = di->currentdumpblock->dumpmem + di->currentdumpblock->size -
515 (di->allocateddumpsize - di->useddumpsize);
517 #if defined(ENABLE_MEMCHECK)
519 dump_allocation_t *da = NEW(dump_allocation_t);
523 /* add the allocation to our linked list of allocations */
525 da->next = di->allocations;
526 da->mem = (u1*) m + MEMORY_CANARY_SIZE;
528 da->useddumpsize = di->useddumpsize;
530 di->allocations = da;
532 /* write the canaries */
535 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
536 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
537 pm = da->mem + da->size;
538 for (i=0; i<MEMORY_CANARY_SIZE; ++i)
539 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
541 /* make m point after the bottom canary */
543 m = (u1*)m + MEMORY_CANARY_SIZE;
545 /* clear the memory */
547 memset(m, MEMORY_CLEAR_BYTE, da->size);
549 #endif /* defined(ENABLE_MEMCHECK) */
551 /* increase used dump size by the allocated memory size */
553 di->useddumpsize += size;
555 #if defined(ENABLE_STATISTICS)
557 if (di->useddumpsize > maxdumpsize)
558 maxdumpsize = di->useddumpsize;
563 #endif /* defined(DISABLE_DUMP) */
567 /* dump_realloc ****************************************************************
569 Stupid realloc implementation for dump memory. Avoid, if possible.
571 *******************************************************************************/
573 void *dump_realloc(void *src, s4 len1, s4 len2)
575 #if defined(DISABLE_DUMP)
576 /* use malloc memory for dump memory (for debugging only!) */
578 return mem_realloc(src, len1, len2);
580 void *dst = dump_alloc(len2);
582 memcpy(dst, src, len1);
584 #if defined(ENABLE_MEMCHECK)
585 /* destroy the source */
586 memset(src, MEMORY_CLEAR_BYTE, len1);
594 /* dump_release ****************************************************************
596 Release dump memory above the given size.
599 size........All dump memory above this mark will be freed. Usually
600 `size` will be the return value of a `dump_size` call
604 XXX If the given size is invalid, this function *exits* with an
609 *******************************************************************************/
611 void dump_release(s4 size)
613 #if defined(DISABLE_DUMP)
615 /* use malloc memory for dump memory (for debugging only!) */
619 #else /* !defined(DISABLE_DUMP) */
623 /* If no threads are used, the dumpinfo structure is a static structure */
624 /* defined at the top of this file. */
628 if ((size < 0) || (size > di->useddumpsize))
629 vm_abort("Illegal dump release size: %d", size);
631 #if defined(ENABLE_MEMCHECK)
633 dump_allocation_t *da, *next;
637 dump_check_canaries(di, size);
639 /* iterate over all dump memory allocations about to be released */
641 da = di->allocations;
642 while (da && da->useddumpsize >= size) {
645 /* invalidate the freed memory */
647 memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
649 FREE(da, dump_allocation_t);
653 di->allocations = da;
655 #endif /* defined(ENABLE_MEMCHECK) */
657 /* reset the used dump size to the size specified */
659 di->useddumpsize = size;
661 while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
662 dumpblock_t *tmp = di->currentdumpblock;
664 di->allocateddumpsize -= tmp->size;
665 di->currentdumpblock = tmp->prev;
667 #if defined(ENABLE_STATISTICS)
668 /* the amount of globally allocated dump memory (thread save) */
671 globalallocateddumpsize -= tmp->size;
674 /* release the dump memory and the dumpinfo structure */
680 #endif /* defined(DISABLE_DUMP) */
684 /* dump_size *******************************************************************
686 Return the current size of the dump memory area. See `dump_alloc`.
688 *******************************************************************************/
692 #if defined(DISABLE_DUMP)
693 /* use malloc memory for dump memory (for debugging only!) */
697 #else /* !defined(DISABLE_DUMP) */
701 /* If no threads are used, the dumpinfo structure is a static structure */
702 /* defined at the top of this file. */
709 return di->useddumpsize;
711 #endif /* defined(DISABLE_DUMP) */
716 * These are local overrides for various environment variables in Emacs.
717 * Please do not remove this and leave it at the end of the file, where
718 * Emacs will automagically detect them.
719 * ---------------------------------------------------------------------
722 * indent-tabs-mode: t
726 * vim:noexpandtab:sw=4:ts=4: