1 /* src/mm/dumpmemory.c - dump memory management
3 Copyright (C) 1996-2005, 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "mm/dumpmemory.h"
31 #include "mm/memory.h"
33 #include "threads/threads-common.h"
35 #include "vmcore/options.h"
37 #if defined(ENABLE_STATISTICS)
38 # include "vmcore/statistics.h"
41 #include "vmcore/system.h"
46 /*******************************************************************************
48 This structure is used for dump memory allocation if cacao
51 *******************************************************************************/
53 #if !defined(ENABLE_THREADS)
54 static dumpinfo_t _no_threads_dumpinfo;
57 #if defined(ENABLE_THREADS)
58 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
60 #define DUMPINFO &_no_threads_dumpinfo
64 /* dump_check_canaries *********************************************************
66 Check canaries in dump memory.
69 di...........dumpinfo_t * of the dump area to check
70 bottomsize...dump size down to which the dump area should be checked
71 (specify 0 to check the whole dump area)
74 If any canary has been changed, this function aborts the VM with
77 *******************************************************************************/
79 #if defined(ENABLE_MEMCHECK)
80 static void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
82 dump_allocation_t *da;
86 /* iterate over all dump memory allocations above bottomsize */
90 while (da && da->used >= bottomsize) {
93 pm = ((uint8_t *) da->mem) - MEMORY_CANARY_SIZE;
95 for (i = 0; i < MEMORY_CANARY_SIZE; ++i) {
96 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
97 fprintf(stderr, "canary bytes:");
99 for (j = 0; j < MEMORY_CANARY_SIZE; ++j)
100 fprintf(stderr, " %02x", pm[j]);
102 fprintf(stderr,"\n");
104 vm_abort("error: dump memory bottom canary killed: "
105 "%p (%d bytes allocated at %p)\n",
106 pm + i, da->size, da->mem);
110 pm = ((uint8_t *) da->mem) + da->size;
112 for (i = 0; i < MEMORY_CANARY_SIZE; ++i) {
113 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
114 fprintf(stderr, "canary bytes:");
116 for (j = 0; j < MEMORY_CANARY_SIZE; ++j)
117 fprintf(stderr, " %02x", pm[j]);
119 fprintf(stderr, "\n");
121 vm_abort("error: dump memory top canary killed: "
122 "%p (%d bytes allocated at %p)\n",
123 pm + i, da->size, da->mem);
130 #endif /* defined(ENABLE_MEMCHECK) */
133 /* dumpmemory_alloc ************************************************************
135 ATTENTION: This function must only be called from dumpmemory_get!
137 Allocate a new dump memory block.
140 di ..... dumpinfo_t of the current thread
141 size ... required memory size
143 *******************************************************************************/
145 void dumpmemory_alloc(dumpinfo_t *di, size_t size)
150 /* Allocate a new dumpblock_t structure. */
152 db = memory_checked_alloc(sizeof(dumpblock_t));
154 /* If requested size is greater than the default, make the new
155 dump block as big as the size requested. Else use the default
158 if (size > DUMPBLOCKSIZE) {
162 newblocksize = DUMPBLOCKSIZE;
165 /* allocate dumpblock memory */
167 db->dumpmem = memory_checked_alloc(newblocksize);
169 db->size = newblocksize;
170 db->prev = di->block;
173 /* Used dump size is previously allocated dump size, because the
174 remaining free memory of the previous dump block cannot be
177 di->used = di->allocated;
179 /* Increase the allocated dump size by the size of the new dump
182 di->allocated += newblocksize;
184 #if defined(ENABLE_STATISTICS)
185 /* The amount of globally allocated dump memory (thread save). */
188 globalallocateddumpsize += newblocksize;
193 /* dumpmemory_get **************************************************************
195 Allocate memory in the dump area.
198 size.........size of block to allocate, in bytes
199 may be zero, in which case NULL is returned
202 pointer to allocated memory, or
203 NULL iff `size` was zero
206 XXX This function uses `memory_checked_alloc`, which *exits* if
207 no memory could be allocated.
210 dumpmemory_get is thread safe. Each thread has its own dump
213 This function is a fast allocator suitable for scratch memory that
214 can be collectively freed when the current activity (eg. compiling)
217 You cannot selectively free dump memory. Before you start
218 allocating it, you remember the current size returned by
219 `dumpmemory_marker`. Later, when you no longer need the memory,
220 call `dumpmemory_release` with the remembered size and all dump
221 memory allocated since the call to `dumpmemory_marker` will be
224 *******************************************************************************/
226 void *dumpmemory_get(size_t size)
228 #if defined(DISABLE_DUMP)
230 /* use malloc memory for dump memory (for debugging only!) */
232 return mem_alloc(size);
234 #else /* !defined(DISABLE_DUMP) */
238 #if defined(ENABLE_MEMCHECK)
239 s4 origsize = size; /* needed for the canary system */
247 #if defined(ENABLE_MEMCHECK)
248 size += 2 * MEMORY_CANARY_SIZE;
251 size = MEMORY_ALIGN(size, ALIGNSIZE);
253 /* Check if we have enough memory in the current memory block. */
255 if (di->used + size > di->allocated) {
256 /* If not, allocate a new one. */
258 dumpmemory_alloc(di, size);
261 /* current dump block base address + the size of the current dump
262 block - the size of the unused memory = new start address */
264 p = ((uint8_t *) di->block->dumpmem) + di->block->size -
265 (di->allocated - di->used);
267 #if defined(ENABLE_MEMCHECK)
269 dump_allocation_t *da = NEW(dump_allocation_t);
273 /* add the allocation to our linked list of allocations */
275 da->next = di->allocations;
276 da->mem = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
280 di->allocations = da;
282 /* write the canaries */
286 for (i = 0; i < MEMORY_CANARY_SIZE; ++i)
287 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
289 pm = ((uint8_t *) da->mem) + da->size;
291 for (i = 0; i < MEMORY_CANARY_SIZE; ++i)
292 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
294 /* make m point after the bottom canary */
296 p = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
298 /* clear the memory */
300 (void) system_memset(p, MEMORY_CLEAR_BYTE, da->size);
302 #endif /* defined(ENABLE_MEMCHECK) */
304 /* Increase used dump size by the allocated memory size. */
308 #if defined(ENABLE_STATISTICS)
310 if (di->used > maxdumpsize)
311 maxdumpsize = di->used;
316 #endif /* defined(DISABLE_DUMP) */
320 /* dumpmemory_realloc **********************************************************
322 Stupid realloc implementation for dump memory. Avoid, if possible.
324 *******************************************************************************/
326 void *dumpmemory_realloc(void *src, s4 len1, s4 len2)
328 #if defined(DISABLE_DUMP)
329 /* use malloc memory for dump memory (for debugging only!) */
331 return mem_realloc(src, len1, len2);
335 dst = dumpmemory_get(len2);
337 (void) system_memcpy(dst, src, len1);
339 #if defined(ENABLE_MEMCHECK)
340 /* destroy the source */
342 (void) system_memset(src, MEMORY_CLEAR_BYTE, len1);
350 /* dumpmemory_release **********************************************************
352 Release dump memory above the given size.
355 size........All dump memory above this mark will be freed. Usually
356 `size` will be the return value of a `dumpmemory_marker`
360 XXX If the given size is invalid, this function *exits* with an
365 *******************************************************************************/
367 void dumpmemory_release(s4 size)
369 #if defined(DISABLE_DUMP)
371 /* use malloc memory for dump memory (for debugging only!) */
375 #else /* !defined(DISABLE_DUMP) */
381 if ((size < 0) || (size > di->used))
382 vm_abort("dump_release: Illegal dump release size: %d", size);
384 #if defined(ENABLE_MEMCHECK)
386 dump_allocation_t *da, *next;
390 dump_check_canaries(di, size);
392 /* iterate over all dump memory allocations about to be released */
394 da = di->allocations;
396 while ((da != NULL) && (da->used >= size)) {
399 /* invalidate the freed memory */
401 (void) system_memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
403 FREE(da, dump_allocation_t);
407 di->allocations = da;
409 #endif /* defined(ENABLE_MEMCHECK) */
411 /* Reset the used dump size to the size specified. */
415 while ((di->block != NULL) && di->allocated - di->block->size >= di->used) {
416 dumpblock_t *tmp = di->block;
418 di->allocated -= tmp->size;
419 di->block = tmp->prev;
421 #if defined(ENABLE_STATISTICS)
422 /* the amount of globally allocated dump memory (thread save) */
425 globalallocateddumpsize -= tmp->size;
428 /* Release the dump memory and the dumpinfo structure. */
430 system_free(tmp->dumpmem);
434 #endif /* defined(DISABLE_DUMP) */
438 /* dumpmemory_marker ***********************************************************
440 Returns a marker of the dump memory area. This marker is actually
441 the used size of the dump memory area.
444 marker of the current dump memory status
446 *******************************************************************************/
448 int32_t dumpmemory_marker(void)
450 #if defined(DISABLE_DUMP)
451 /* use malloc memory for dump memory (for debugging only!) */
455 #else /* !defined(DISABLE_DUMP) */
466 #endif /* defined(DISABLE_DUMP) */
471 * These are local overrides for various environment variables in Emacs.
472 * Please do not remove this and leave it at the end of the file, where
473 * Emacs will automagically detect them.
474 * ---------------------------------------------------------------------
477 * indent-tabs-mode: t
481 * vim:noexpandtab:sw=4:ts=4: