* configure.ac: New switch for disabling -O2 (--disable-optimizations).
[cacao.git] / src / mm / dumpmemory.cpp
1 /* src/mm/dumpmemory.cpp - dump memory management
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5    Copyright (C) 2008 Theobroma Systems Ltd.
6
7    This file is part of CACAO.
8
9    This program is free software; you can redistribute it and/or
10    modify it under the terms of the GNU General Public License as
11    published by the Free Software Foundation; either version 2, or (at
12    your option) any later version.
13
14    This program is distributed in the hope that it will be useful, but
15    WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22    02110-1301, USA.
23
24 */
25
26
27 #include "config.h"
28
29 #include <stdint.h>
30
31 #include "mm/dumpmemory.hpp"
32 #include "mm/memory.hpp"
33
34 #include "threads/thread.hpp"
35
36 #include "vm/options.h"
37 #include "vm/os.hpp"
38
39 #if defined(ENABLE_STATISTICS)
40 # include "vm/statistics.h"
41 #endif
42
43 #include "vm/vm.hpp"
44
45
46 /*******************************************************************************
47
48   This structure is used for dump memory allocation if cacao
49   runs without threads.
50
51 *******************************************************************************/
52
53 #if !defined(ENABLE_THREADS)
54 static dumpinfo_t _no_threads_dumpinfo;
55 #endif
56
57
58 /**
59  * Allocate a new thread-local dump memory structure.
60  */
61 DumpMemory::DumpMemory() : _size(0), _used(0)
62 {
63 }
64
65
66 /**
67  * Stupid realloc implementation for dump memory.  Avoid, if possible.
68  */
69 void* DumpMemory::reallocate(void* src, size_t len1, size_t len2)
70 {
71         void* dst = allocate(len2);
72
73         (void) os::memcpy(dst, src, len1);
74
75 #if defined(ENABLE_MEMCHECK)
76         // Destroy the source.
77         (void) os::memset(src, MEMORY_CLEAR_BYTE, len1);
78 #endif
79
80         return dst;
81 }
82
83
84 /**
85  * Add the given dump area to the area list.
86  *
87  * @param dm Pointer to dump area.
88  */
89 void DumpMemory::add_area(DumpMemoryArea* dma)
90 {
91         _areas.push_back(dma);
92
93         // Increase the size count of the dump memory.
94         _size += dma->get_size();
95
96 #if defined(ENABLE_STATISTICS)
97         if (opt_stat) {
98                 if (_size > (size_t) maxdumpsize)
99                         maxdumpsize = _size;
100         }
101 #endif
102 }
103
104
105 /**
106  * Remove the given dump area from the area list.
107  *
108  * @param dm Pointer to dump area.
109  */
110 void DumpMemory::remove_area(DumpMemoryArea* dma)
111 {
112         // Sanity check.
113         assert(_areas.back() == dma);
114
115         // Remove the last area from the list.  The check above guarantees
116         // we are removing the correct area.
117         _areas.pop_back();
118
119         // Decrease the size and used count.
120         _size -= dma->get_size();
121         _used -= dma->get_used();
122 }
123
124
125 /**
126  * Allocate a new dump memory area.
127  *
128  * @ param size Required memory size.
129  */
130 DumpMemoryArea::DumpMemoryArea(size_t size) : _size(0), _used(0)
131 {
132         // Get the DumpMemory object of the current thread.
133         DumpMemory* dm = DumpMemory::get_current();
134
135         // Add this area to the areas list.
136         dm->add_area(this);
137 }
138
139
140 /**
141  * Release all dump memory blocks in the current dump area.
142  */
143 DumpMemoryArea::~DumpMemoryArea()
144 {
145         // Get the DumpMemory object of the current thread.
146         DumpMemory* dm = DumpMemory::get_current();
147
148 #if defined(ENABLE_MEMCHECK)
149         // Check canaries.
150
151         check_canaries();
152
153         // Iterate over all dump memory allocations about to be released.
154
155         for (std::vector<DumpMemoryAllocation*>::iterator it = _allocs.begin(); it != _allocs.end(); it++) {
156                 DumpMemoryAllocation* dma = *it;
157
158                 // Invalidate the freed memory.
159                 (void) os::memset(dma->get_mem(), MEMORY_CLEAR_BYTE, dma->get_size());
160
161                 // Call the destructor of the current allocation.
162                 delete dma;
163         }
164 #endif /* defined(ENABLE_MEMCHECK) */
165
166         // Free all memory blocks.
167         for (std::vector<DumpMemoryBlock*>::iterator it = _blocks.begin(); it != _blocks.end(); it++) {
168                 // Call the destructor of the current block.
169                 delete *it;
170         }
171
172         // Remove this area for the area list.
173         dm->remove_area(this);
174 }
175
176
177 /**
178  * Allocate a dump memory block for the current dump memory area.
179  *
180  * @param size Required memory size.
181  *
182  * @return Pointer to the newly allocated block.
183  */
184 DumpMemoryBlock* DumpMemoryArea::allocate_new_block(size_t size)
185 {
186         DumpMemoryBlock* dmb = new DumpMemoryBlock(size);
187         _blocks.push_back(dmb);
188
189 #if defined(ENABLE_STATISTICS)
190         if (opt_stat) {
191                 DumpMemory* dm = DumpMemory::get_current();
192                 dm->add_size(dmb->get_size());
193
194                 if (dm->get_size() > (size_t) maxdumpsize)
195                         maxdumpsize = dm->get_size();
196         }
197 #endif
198
199         return dmb;
200 }
201
202
203 /**
204  * Checks canaries in this dump memory area. If any canary has been changed,
205  * this function aborts the VM with an error message.
206  */
207 #if defined(ENABLE_MEMCHECK)
208 void DumpMemoryArea::check_canaries()
209 {
210         uint8_t* pm;
211
212         // Iterate over all dump memory allocations.
213
214         for (std::vector<DumpMemoryAllocation*>::iterator it = _allocs.begin(); it != _allocs.end(); it++) {
215                 DumpMemoryAllocation* dma = *it;
216
217                 // Check canaries.
218
219                 pm = ((uint8_t *) dma->get_mem()) - MEMORY_CANARY_SIZE;
220
221                 for (int i = 0; i < MEMORY_CANARY_SIZE; ++i) {
222                         if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
223                                 fprintf(stderr, "canary bytes:");
224
225                                 for (int j = 0; j < MEMORY_CANARY_SIZE; ++j)
226                                         fprintf(stderr, " %02x", pm[j]);
227
228                                 fprintf(stderr,"\n");
229
230                                 vm_abort("error: dump memory bottom canary killed: "
231                                                  "%p (%d bytes allocated at %p)\n",
232                                                  pm + i, dma->get_size(), dma->get_mem());
233                         }
234                 }
235
236                 pm = ((uint8_t *) dma->get_mem()) + dma->get_size();
237
238                 for (int i = 0; i < MEMORY_CANARY_SIZE; ++i) {
239                         if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
240                                 fprintf(stderr, "canary bytes:");
241
242                                 for (int j = 0; j < MEMORY_CANARY_SIZE; ++j)
243                                         fprintf(stderr, " %02x", pm[j]);
244
245                                 fprintf(stderr, "\n");
246
247                                 vm_abort("error: dump memory top canary killed: "
248                                                  "%p (%d bytes allocated at %p)\n",
249                                                  pm + i, dma->get_size(), dma->get_mem());
250                         }
251                 }
252         }
253 }
254 #endif /* defined(ENABLE_MEMCHECK) */
255
256
257 /**
258  * Allocate a memory block for the current dump memory block.
259  *
260  * @param size Required memory size.
261  */
262 DumpMemoryBlock::DumpMemoryBlock(size_t size) : _size(0), _used(0), _block(0)
263 {
264         // If requested size is greater than the default, make the new
265         // memory block as big as the requested size.  Otherwise use the
266         // default size.
267         _size = (size > DEFAULT_SIZE) ? size : DEFAULT_SIZE;
268
269         // Allocate a memory block.
270         _block = memory_checked_alloc(_size);
271
272 #if defined(ENABLE_STATISTICS)
273         // The amount of globally allocated dump memory (thread safe).
274         if (opt_stat)
275                 globalallocateddumpsize += _size;
276 #endif
277 }
278
279
280 /**
281  * Release the memory block for the dump memory block.
282  *
283  * @param size Required memory size.
284  */
285 DumpMemoryBlock::~DumpMemoryBlock()
286 {
287         // Release the memory block.
288         mem_free(_block, /* XXX */ 1);
289
290 #if defined(ENABLE_STATISTICS)
291         // The amount of globally allocated dump memory (thread safe).
292         if (opt_stat)
293                 globalallocateddumpsize -= _size;
294 #endif
295 }
296
297
298 // Legacy C interface.
299
300 extern "C" {
301         void* DumpMemory_allocate(size_t size) { return DumpMemory::allocate(size); }
302         void* DumpMemory_reallocate(void* src, size_t len1, size_t len2) { return DumpMemory::reallocate(src, len1, len2); }
303 }
304
305
306 /*
307  * These are local overrides for various environment variables in Emacs.
308  * Please do not remove this and leave it at the end of the file, where
309  * Emacs will automagically detect them.
310  * ---------------------------------------------------------------------
311  * Local variables:
312  * mode: c++
313  * indent-tabs-mode: t
314  * c-basic-offset: 4
315  * tab-width: 4
316  * End:
317  * vim:noexpandtab:sw=4:ts=4:
318  */