* src/mm/codememory.c (code_memory_mutex): Use mutex instead of java object
[cacao.git] / src / mm / dumpmemory.c
1 /* src/mm/dumpmemory.c - dump memory management
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
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.
12
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.
17
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
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <stdint.h>
29
30 #include "mm/dumpmemory.h"
31 #include "mm/memory.h"
32
33 #include "threads/thread.hpp"
34
35 #include "vm/options.h"
36 #include "vm/os.hpp"
37
38 #if defined(ENABLE_STATISTICS)
39 # include "vm/statistics.h"
40 #endif
41
42 #include "vm/vm.hpp"
43
44
45 /*******************************************************************************
46
47   This structure is used for dump memory allocation if cacao
48   runs without threads.
49
50 *******************************************************************************/
51
52 #if !defined(ENABLE_THREADS)
53 static dumpinfo_t _no_threads_dumpinfo;
54 #endif
55
56 #if defined(ENABLE_THREADS)
57 #define DUMPINFO    &((threadobject *) THREADOBJECT)->dumpinfo
58 #else
59 #define DUMPINFO    &_no_threads_dumpinfo
60 #endif
61
62
63 /* dump_check_canaries *********************************************************
64
65    Check canaries in dump memory.
66
67    IN:
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)
71
72    ERROR HANDLING:
73       If any canary has been changed, this function aborts the VM with
74           an error message.
75
76 *******************************************************************************/
77
78 #if defined(ENABLE_MEMCHECK)
79 static void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
80 {
81         dump_allocation_t *da;
82         uint8_t           *pm;
83         int                i, j;
84
85         /* iterate over all dump memory allocations above bottomsize */
86
87         da = di->allocations;
88
89         while (da && da->used >= bottomsize) {
90                 /* check canaries */
91
92                 pm = ((uint8_t *) da->mem) - MEMORY_CANARY_SIZE;
93
94                 for (i = 0; i < MEMORY_CANARY_SIZE; ++i) {
95                         if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
96                                 fprintf(stderr, "canary bytes:");
97
98                                 for (j = 0; j < MEMORY_CANARY_SIZE; ++j)
99                                         fprintf(stderr, " %02x", pm[j]);
100
101                                 fprintf(stderr,"\n");
102
103                                 vm_abort("error: dump memory bottom canary killed: "
104                                                  "%p (%d bytes allocated at %p)\n",
105                                                  pm + i, da->size, da->mem);
106                         }
107                 }
108
109                 pm = ((uint8_t *) da->mem) + da->size;
110
111                 for (i = 0; i < MEMORY_CANARY_SIZE; ++i) {
112                         if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
113                                 fprintf(stderr, "canary bytes:");
114
115                                 for (j = 0; j < MEMORY_CANARY_SIZE; ++j)
116                                         fprintf(stderr, " %02x", pm[j]);
117
118                                 fprintf(stderr, "\n");
119
120                                 vm_abort("error: dump memory top canary killed: "
121                                                  "%p (%d bytes allocated at %p)\n",
122                                                  pm + i, da->size, da->mem);
123                         }
124                 }
125
126                 da = da->next;
127         }
128 }
129 #endif /* defined(ENABLE_MEMCHECK) */
130
131
132 /* dumpmemory_alloc ************************************************************
133
134    ATTENTION: This function must only be called from dumpmemory_get!
135
136    Allocate a new dump memory block.
137
138    IN:
139       di ..... dumpinfo_t of the current thread
140       size ... required memory size
141
142 *******************************************************************************/
143
144 void dumpmemory_alloc(dumpinfo_t *di, size_t size)
145 {
146         dumpblock_t *db;
147         size_t       newblocksize;
148
149         /* Allocate a new dumpblock_t structure. */
150
151         db = memory_checked_alloc(sizeof(dumpblock_t));
152
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
155            size. */
156
157         if (size > DUMPBLOCKSIZE) {
158                 newblocksize = size;
159         }
160         else {
161                 newblocksize = DUMPBLOCKSIZE;
162         }
163
164         /* allocate dumpblock memory */
165
166         db->dumpmem = memory_checked_alloc(newblocksize);
167
168         db->size  = newblocksize;
169         db->prev  = di->block;
170         di->block = db;
171
172         /* Used dump size is previously allocated dump size, because the
173            remaining free memory of the previous dump block cannot be
174            used. */
175
176         di->used = di->allocated;
177
178         /* Increase the allocated dump size by the size of the new dump
179            block. */
180
181         di->allocated += newblocksize;
182
183 #if defined(ENABLE_STATISTICS)
184         /* The amount of globally allocated dump memory (thread save). */
185
186         if (opt_stat)
187                 globalallocateddumpsize += newblocksize;
188 #endif
189 }
190
191
192 /* dumpmemory_get **************************************************************
193
194    Allocate memory in the dump area.
195
196    IN:
197       size.........size of block to allocate, in bytes
198                                    may be zero, in which case NULL is returned
199
200    RETURN VALUE:
201       pointer to allocated memory, or
202           NULL iff `size` was zero
203
204    ERROR HANDLING:
205       XXX This function uses `memory_checked_alloc`, which *exits* if
206           no memory could be allocated.
207
208    THREADS:
209       dumpmemory_get is thread safe. Each thread has its own dump
210       memory area.
211
212    This function is a fast allocator suitable for scratch memory that
213    can be collectively freed when the current activity (eg. compiling)
214    is done.
215
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
221    freed.
222
223 *******************************************************************************/
224
225 void *dumpmemory_get(size_t size)
226 {
227 #if defined(DISABLE_DUMP)
228
229         /* use malloc memory for dump memory (for debugging only!) */
230
231         return mem_alloc(size);
232
233 #else /* !defined(DISABLE_DUMP) */
234
235         void       *p;
236         dumpinfo_t *di;
237 #if defined(ENABLE_MEMCHECK)
238         s4          origsize = size; /* needed for the canary system */
239 #endif
240
241         di = DUMPINFO;
242
243         if (size == 0)
244                 return NULL;
245
246 #if defined(ENABLE_MEMCHECK)
247         size += 2 * MEMORY_CANARY_SIZE;
248 #endif
249
250         size = MEMORY_ALIGN(size, ALIGNSIZE);
251
252         /* Check if we have enough memory in the current memory block. */
253
254         if (di->used + size > di->allocated) {
255                 /* If not, allocate a new one. */
256
257                 dumpmemory_alloc(di, size);
258         }
259
260         /* current dump block base address + the size of the current dump
261            block - the size of the unused memory = new start address  */
262
263         p = ((uint8_t *) di->block->dumpmem) + di->block->size -
264                 (di->allocated - di->used);
265
266 #if defined(ENABLE_MEMCHECK)
267         {
268                 dump_allocation_t *da = NEW(dump_allocation_t);
269                 uint8_t           *pm;
270                 int                i;
271
272                 /* add the allocation to our linked list of allocations */
273
274                 da->next = di->allocations;
275                 da->mem  = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
276                 da->size = origsize;
277                 da->used = di->used;
278
279                 di->allocations = da;
280
281                 /* write the canaries */
282
283                 pm = (uint8_t *) p;
284
285                 for (i = 0; i < MEMORY_CANARY_SIZE; ++i)
286                         pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
287
288                 pm = ((uint8_t *) da->mem) + da->size;
289
290                 for (i = 0; i < MEMORY_CANARY_SIZE; ++i)
291                         pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
292
293                 /* make m point after the bottom canary */
294
295                 p = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
296
297                 /* clear the memory */
298
299                 (void) os_memset(p, MEMORY_CLEAR_BYTE, da->size);
300         }
301 #endif /* defined(ENABLE_MEMCHECK) */
302
303         /* Increase used dump size by the allocated memory size. */
304
305         di->used += size;
306
307 #if defined(ENABLE_STATISTICS)
308         if (opt_stat)
309                 if (di->used > maxdumpsize)
310                         maxdumpsize = di->used;
311 #endif
312
313         return p;
314
315 #endif /* defined(DISABLE_DUMP) */
316 }
317
318
319 /* dumpmemory_realloc **********************************************************
320
321    Stupid realloc implementation for dump memory. Avoid, if possible.
322
323 *******************************************************************************/
324
325 void *dumpmemory_realloc(void *src, s4 len1, s4 len2)
326 {
327 #if defined(DISABLE_DUMP)
328         /* use malloc memory for dump memory (for debugging only!) */
329
330         return mem_realloc(src, len1, len2);
331 #else
332         void *dst;
333
334         dst = dumpmemory_get(len2);
335
336         (void) os_memcpy(dst, src, len1);
337
338 #if defined(ENABLE_MEMCHECK)
339         /* destroy the source */
340
341         (void) os_memset(src, MEMORY_CLEAR_BYTE, len1);
342 #endif
343
344         return dst;
345 #endif
346 }
347
348
349 /* dumpmemory_release **********************************************************
350
351    Release dump memory above the given size.
352
353    IN:
354        size........All dump memory above this mark will be freed. Usually
355                        `size` will be the return value of a `dumpmemory_marker`
356                                    call made earlier.
357
358         ERROR HANDLING:
359            XXX If the given size is invalid, this function *exits* with an
360                error message.
361                                    
362         See `dump_alloc`.
363
364 *******************************************************************************/
365
366 void dumpmemory_release(s4 size)
367 {
368 #if defined(DISABLE_DUMP)
369
370         /* use malloc memory for dump memory (for debugging only!) */
371
372         /* do nothing */
373
374 #else /* !defined(DISABLE_DUMP) */
375
376         dumpinfo_t *di;
377
378         di = DUMPINFO;
379
380         if ((size < 0) || (size > di->used))
381                 vm_abort("dump_release: Illegal dump release size: %d", size);
382
383 #if defined(ENABLE_MEMCHECK)
384         {
385                 dump_allocation_t *da, *next;
386
387                 /* check canaries */
388
389                 dump_check_canaries(di, size);
390
391                 /* iterate over all dump memory allocations about to be released */
392
393                 da = di->allocations;
394
395                 while ((da != NULL) && (da->used >= size)) {
396                         next = da->next;
397
398                         /* invalidate the freed memory */
399
400                         (void) os_memset(da->mem, MEMORY_CLEAR_BYTE, da->size);
401
402                         FREE(da, dump_allocation_t);
403
404                         da = next;
405                 }
406                 di->allocations = da;
407         }
408 #endif /* defined(ENABLE_MEMCHECK) */
409
410         /* Reset the used dump size to the size specified. */
411
412         di->used = size;
413
414         while ((di->block != NULL) && di->allocated - di->block->size >= di->used) {
415                 dumpblock_t *tmp = di->block;
416
417                 di->allocated -= tmp->size;
418                 di->block      = tmp->prev;
419
420 #if defined(ENABLE_STATISTICS)
421                 /* the amount of globally allocated dump memory (thread save) */
422
423                 if (opt_stat)
424                         globalallocateddumpsize -= tmp->size;
425 #endif
426
427                 /* Release the dump memory and the dumpinfo structure. */
428
429                 os_free(tmp->dumpmem);
430                 os_free(tmp);
431         }
432
433 #endif /* defined(DISABLE_DUMP) */
434 }
435
436
437 /* dumpmemory_marker ***********************************************************
438
439    Returns a marker of the dump memory area.  This marker is actually
440    the used size of the dump memory area.
441
442    RETURN VALUE:
443        marker of the current dump memory status
444
445 *******************************************************************************/
446
447 int32_t dumpmemory_marker(void)
448 {
449 #if defined(DISABLE_DUMP)
450         /* use malloc memory for dump memory (for debugging only!) */
451
452         return 0;
453
454 #else /* !defined(DISABLE_DUMP) */
455
456         dumpinfo_t *di;
457
458         di = DUMPINFO;
459
460         if (di == NULL)
461                 return 0;
462
463         return di->used;
464
465 #endif /* defined(DISABLE_DUMP) */
466 }
467
468
469 /*
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  * ---------------------------------------------------------------------
474  * Local variables:
475  * mode: c
476  * indent-tabs-mode: t
477  * c-basic-offset: 4
478  * tab-width: 4
479  * End:
480  * vim:noexpandtab:sw=4:ts=4:
481  */