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/thread.hpp"
35 #include "vm/options.h"
38 #if defined(ENABLE_STATISTICS)
39 # include "vm/statistics.h"
45 /*******************************************************************************
47 This structure is used for dump memory allocation if cacao
50 *******************************************************************************/
52 #if !defined(ENABLE_THREADS)
53 static dumpinfo_t _no_threads_dumpinfo;
56 #if defined(ENABLE_THREADS)
57 #define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo
59 #define DUMPINFO &_no_threads_dumpinfo
63 /* dump_check_canaries *********************************************************
65 Check canaries in dump memory.
68 di...........dumpinfo_t * of the dump area to check
69 bottomsize...dump size down to which the dump area should be checked
70 (specify 0 to check the whole dump area)
73 If any canary has been changed, this function aborts the VM with
76 *******************************************************************************/
78 #if defined(ENABLE_MEMCHECK)
79 static void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
81 dump_allocation_t *da;
85 /* iterate over all dump memory allocations above bottomsize */
89 while (da && da->used >= bottomsize) {
92 pm = ((uint8_t *) da->mem) - MEMORY_CANARY_SIZE;
94 for (i = 0; i < MEMORY_CANARY_SIZE; ++i) {
95 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
96 fprintf(stderr, "canary bytes:");
98 for (j = 0; j < MEMORY_CANARY_SIZE; ++j)
99 fprintf(stderr, " %02x", pm[j]);
101 fprintf(stderr,"\n");
103 vm_abort("error: dump memory bottom canary killed: "
104 "%p (%d bytes allocated at %p)\n",
105 pm + i, da->size, da->mem);
109 pm = ((uint8_t *) da->mem) + da->size;
111 for (i = 0; i < MEMORY_CANARY_SIZE; ++i) {
112 if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
113 fprintf(stderr, "canary bytes:");
115 for (j = 0; j < MEMORY_CANARY_SIZE; ++j)
116 fprintf(stderr, " %02x", pm[j]);
118 fprintf(stderr, "\n");
120 vm_abort("error: dump memory top canary killed: "
121 "%p (%d bytes allocated at %p)\n",
122 pm + i, da->size, da->mem);
129 #endif /* defined(ENABLE_MEMCHECK) */
132 /* dumpmemory_alloc ************************************************************
134 ATTENTION: This function must only be called from dumpmemory_get!
136 Allocate a new dump memory block.
139 di ..... dumpinfo_t of the current thread
140 size ... required memory size
142 *******************************************************************************/
144 void dumpmemory_alloc(dumpinfo_t *di, size_t size)
149 /* Allocate a new dumpblock_t structure. */
151 db = memory_checked_alloc(sizeof(dumpblock_t));
153 /* If requested size is greater than the default, make the new
154 dump block as big as the size requested. Else use the default
157 if (size > DUMPBLOCKSIZE) {
161 newblocksize = DUMPBLOCKSIZE;
164 /* allocate dumpblock memory */
166 db->dumpmem = memory_checked_alloc(newblocksize);
168 db->size = newblocksize;
169 db->prev = di->block;
172 /* Used dump size is previously allocated dump size, because the
173 remaining free memory of the previous dump block cannot be
176 di->used = di->allocated;
178 /* Increase the allocated dump size by the size of the new dump
181 di->allocated += newblocksize;
183 #if defined(ENABLE_STATISTICS)
184 /* The amount of globally allocated dump memory (thread save). */
187 globalallocateddumpsize += newblocksize;
192 /* dumpmemory_get **************************************************************
194 Allocate memory in the dump area.
197 size.........size of block to allocate, in bytes
198 may be zero, in which case NULL is returned
201 pointer to allocated memory, or
202 NULL iff `size` was zero
205 XXX This function uses `memory_checked_alloc`, which *exits* if
206 no memory could be allocated.
209 dumpmemory_get is thread safe. Each thread has its own dump
212 This function is a fast allocator suitable for scratch memory that
213 can be collectively freed when the current activity (eg. compiling)
216 You cannot selectively free dump memory. Before you start
217 allocating it, you remember the current size returned by
218 `dumpmemory_marker`. Later, when you no longer need the memory,
219 call `dumpmemory_release` with the remembered size and all dump
220 memory allocated since the call to `dumpmemory_marker` will be
223 *******************************************************************************/
225 void *dumpmemory_get(size_t size)
227 #if defined(DISABLE_DUMP)
229 /* use malloc memory for dump memory (for debugging only!) */
231 return mem_alloc(size);
233 #else /* !defined(DISABLE_DUMP) */
237 #if defined(ENABLE_MEMCHECK)
238 s4 origsize = size; /* needed for the canary system */
246 #if defined(ENABLE_MEMCHECK)
247 size += 2 * MEMORY_CANARY_SIZE;
250 size = MEMORY_ALIGN(size, ALIGNSIZE);
252 /* Check if we have enough memory in the current memory block. */
254 if (di->used + size > di->allocated) {
255 /* If not, allocate a new one. */
257 dumpmemory_alloc(di, size);
260 /* current dump block base address + the size of the current dump
261 block - the size of the unused memory = new start address */
263 p = ((uint8_t *) di->block->dumpmem) + di->block->size -
264 (di->allocated - di->used);
266 #if defined(ENABLE_MEMCHECK)
268 dump_allocation_t *da = NEW(dump_allocation_t);
272 /* add the allocation to our linked list of allocations */
274 da->next = di->allocations;
275 da->mem = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
279 di->allocations = da;
281 /* write the canaries */
285 for (i = 0; i < MEMORY_CANARY_SIZE; ++i)
286 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
288 pm = ((uint8_t *) da->mem) + da->size;
290 for (i = 0; i < MEMORY_CANARY_SIZE; ++i)
291 pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
293 /* make m point after the bottom canary */
295 p = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
297 /* clear the memory */
299 (void) os_memset(p, MEMORY_CLEAR_BYTE, da->size);
301 #endif /* defined(ENABLE_MEMCHECK) */
303 /* Increase used dump size by the allocated memory size. */
307 #if defined(ENABLE_STATISTICS)
309 if (di->used > maxdumpsize)
310 maxdumpsize = di->used;
315 #endif /* defined(DISABLE_DUMP) */
319 /* dumpmemory_realloc **********************************************************
321 Stupid realloc implementation for dump memory. Avoid, if possible.
323 *******************************************************************************/
325 void *dumpmemory_realloc(void *src, s4 len1, s4 len2)
327 #if defined(DISABLE_DUMP)
328 /* use malloc memory for dump memory (for debugging only!) */
330 return mem_realloc(src, len1, len2);
334 dst = dumpmemory_get(len2);
336 (void) os_memcpy(dst, src, len1);
338 #if defined(ENABLE_MEMCHECK)
339 /* destroy the source */
341 (void) os_memset(src, MEMORY_CLEAR_BYTE, len1);
349 /* dumpmemory_release **********************************************************
351 Release dump memory above the given size.
354 size........All dump memory above this mark will be freed. Usually
355 `size` will be the return value of a `dumpmemory_marker`
359 XXX If the given size is invalid, this function *exits* with an
364 *******************************************************************************/
366 void dumpmemory_release(s4 size)
368 #if defined(DISABLE_DUMP)
370 /* use malloc memory for dump memory (for debugging only!) */
374 #else /* !defined(DISABLE_DUMP) */
380 if ((size < 0) || (size > di->used))
381 vm_abort("dump_release: Illegal dump release size: %d", size);
383 #if defined(ENABLE_MEMCHECK)
385 dump_allocation_t *da, *next;
389 dump_check_canaries(di, size);
391 /* iterate over all dump memory allocations about to be released */
393 da = di->allocations;
395 while ((da != NULL) && (da->used >= size)) {
398 /* invalidate the freed memory */
400 (void) os_memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
402 FREE(da, dump_allocation_t);
406 di->allocations = da;
408 #endif /* defined(ENABLE_MEMCHECK) */
410 /* Reset the used dump size to the size specified. */
414 while ((di->block != NULL) && di->allocated - di->block->size >= di->used) {
415 dumpblock_t *tmp = di->block;
417 di->allocated -= tmp->size;
418 di->block = tmp->prev;
420 #if defined(ENABLE_STATISTICS)
421 /* the amount of globally allocated dump memory (thread save) */
424 globalallocateddumpsize -= tmp->size;
427 /* Release the dump memory and the dumpinfo structure. */
429 os_free(tmp->dumpmem);
433 #endif /* defined(DISABLE_DUMP) */
437 /* dumpmemory_marker ***********************************************************
439 Returns a marker of the dump memory area. This marker is actually
440 the used size of the dump memory area.
443 marker of the current dump memory status
445 *******************************************************************************/
447 int32_t dumpmemory_marker(void)
449 #if defined(DISABLE_DUMP)
450 /* use malloc memory for dump memory (for debugging only!) */
454 #else /* !defined(DISABLE_DUMP) */
465 #endif /* defined(DISABLE_DUMP) */
470 * These are local overrides for various environment variables in Emacs.
471 * Please do not remove this and leave it at the end of the file, where
472 * Emacs will automagically detect them.
473 * ---------------------------------------------------------------------
476 * indent-tabs-mode: t
480 * vim:noexpandtab:sw=4:ts=4: