Line data Source code
1 : /* src/mm/dumpmemory.cpp - dump memory management
2 :
3 : Copyright (C) 1996-2013
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 : #include "mm/dumpmemory.hpp"
27 : #include <stdio.h> // for fprintf, stderr
28 : #include "config.h" // for ENABLE_MEMCHECK, etc
29 : #include "mm/memory.hpp" // for MEMORY_CANARY_SIZE, etc
30 : #include "vm/os.hpp" // for os
31 : #include "vm/vm.hpp" // for vm_abort
32 : #include "vm/options.hpp"
33 :
34 : STAT_DECLARE_GROUP(max_mem_stat)
35 : STAT_DECLARE_GROUP(not_freed_mem_stat)
36 : STAT_REGISTER_GROUP_VAR(int,maxdumpsize,0,"maxdumpsize","max. dump memory",max_mem_stat)
37 : STAT_REGISTER_GROUP_VAR(int,globalallocateddumpsize,0,"globalallocateddumpsize","dump memory not freed",not_freed_mem_stat)
38 :
39 : /*******************************************************************************
40 :
41 : This structure is used for dump memory allocation if cacao
42 : runs without threads.
43 :
44 : *******************************************************************************/
45 :
46 : /**
47 : * Allocate a new thread-local dump memory structure.
48 : */
49 793 : DumpMemory::DumpMemory() : _size(0), _used(0)
50 : {
51 793 : }
52 :
53 :
54 : /**
55 : * Stupid realloc implementation for dump memory. Avoid, if possible.
56 : */
57 174 : void* DumpMemory::reallocate(void* src, size_t len1, size_t len2)
58 : {
59 174 : void* dst = allocate(len2);
60 :
61 174 : (void) os::memcpy(dst, src, len1);
62 :
63 : #if defined(ENABLE_MEMCHECK)
64 : // Destroy the source.
65 : (void) os::memset(src, MEMORY_CLEAR_BYTE, len1);
66 : #endif
67 :
68 174 : return dst;
69 : }
70 :
71 :
72 : /**
73 : * Add the given dump area to the area list.
74 : *
75 : * @param dm Pointer to dump area.
76 : */
77 1310592 : void DumpMemory::add_area(DumpMemoryArea* dma)
78 : {
79 1310592 : _areas.push_back(dma);
80 :
81 : // Increase the size count of the dump memory.
82 1310579 : _size += dma->get_size();
83 :
84 : STATISTICS(maxdumpsize.max(_size));
85 1310585 : }
86 :
87 :
88 : /**
89 : * Remove the given dump area from the area list.
90 : *
91 : * @param dm Pointer to dump area.
92 : */
93 1310459 : void DumpMemory::remove_area(DumpMemoryArea* dma)
94 : {
95 : // Sanity check.
96 1310459 : assert(_areas.back() == dma);
97 :
98 : // Remove the last area from the list. The check above guarantees
99 : // we are removing the correct area.
100 1310465 : _areas.pop_back();
101 :
102 : // Decrease the size and used count.
103 1310461 : _size -= dma->get_size();
104 1310461 : _used -= dma->get_used();
105 1310460 : }
106 :
107 :
108 : /**
109 : * Allocate a new dump memory area.
110 : *
111 : * @ param size Required memory size.
112 : */
113 1310558 : DumpMemoryArea::DumpMemoryArea(size_t size) : _size(0), _used(0)
114 : {
115 : // Get the DumpMemory object of the current thread.
116 1310585 : DumpMemory* dm = DumpMemory::get_current();
117 :
118 : // Add this area to the areas list.
119 1310587 : dm->add_area(this);
120 0 : }
121 :
122 :
123 : /**
124 : * Release all dump memory blocks in the current dump area.
125 : */
126 1310436 : DumpMemoryArea::~DumpMemoryArea()
127 : {
128 : // Get the DumpMemory object of the current thread.
129 1310436 : DumpMemory* dm = DumpMemory::get_current();
130 :
131 : #if defined(ENABLE_MEMCHECK)
132 : // Check canaries.
133 :
134 : check_canaries();
135 :
136 : // Iterate over all dump memory allocations about to be released.
137 :
138 : for (std::vector<DumpMemoryAllocation*>::iterator it = _allocs.begin(); it != _allocs.end(); it++) {
139 : DumpMemoryAllocation* dma = *it;
140 :
141 : // Invalidate the freed memory.
142 : (void) os::memset(dma->get_mem(), MEMORY_CLEAR_BYTE, dma->get_size());
143 :
144 : // Call the destructor of the current allocation.
145 : delete dma;
146 : }
147 : #endif /* defined(ENABLE_MEMCHECK) */
148 :
149 : // Free all memory blocks.
150 2861305 : for (std::vector<DumpMemoryBlock*>::iterator it = _blocks.begin(); it != _blocks.end(); it++) {
151 : // Call the destructor of the current block.
152 1550847 : delete *it;
153 : }
154 :
155 : // Remove this area for the area list.
156 1310462 : dm->remove_area(this);
157 0 : }
158 :
159 :
160 : /**
161 : * Allocate a dump memory block for the current dump memory area.
162 : *
163 : * @param size Required memory size.
164 : *
165 : * @return Pointer to the newly allocated block.
166 : */
167 1550997 : DumpMemoryBlock* DumpMemoryArea::allocate_new_block(size_t size)
168 : {
169 1550997 : DumpMemoryBlock* dmb = new DumpMemoryBlock(size);
170 1550993 : _blocks.push_back(dmb);
171 :
172 : #if defined(ENABLE_STATISTICS)
173 : DumpMemory* dm = DumpMemory::get_current();
174 : dm->add_size(dmb->get_size());
175 :
176 : STATISTICS(maxdumpsize.max(dm->get_size()));
177 : #endif
178 :
179 1550997 : return dmb;
180 : }
181 :
182 :
183 : /**
184 : * Checks canaries in this dump memory area. If any canary has been changed,
185 : * this function aborts the VM with an error message.
186 : */
187 : #if defined(ENABLE_MEMCHECK)
188 : void DumpMemoryArea::check_canaries()
189 : {
190 : uint8_t* pm;
191 :
192 : // Iterate over all dump memory allocations.
193 :
194 : for (std::vector<DumpMemoryAllocation*>::iterator it = _allocs.begin(); it != _allocs.end(); it++) {
195 : DumpMemoryAllocation* dma = *it;
196 :
197 : // Check canaries.
198 :
199 : pm = ((uint8_t *) dma->get_mem()) - MEMORY_CANARY_SIZE;
200 :
201 : for (int i = 0; i < MEMORY_CANARY_SIZE; ++i) {
202 : if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
203 : fprintf(stderr, "canary bytes:");
204 :
205 : for (int j = 0; j < MEMORY_CANARY_SIZE; ++j)
206 : fprintf(stderr, " %02x", pm[j]);
207 :
208 : fprintf(stderr,"\n");
209 :
210 : vm_abort("error: dump memory bottom canary killed: "
211 : "%p (%d bytes allocated at %p)\n",
212 : pm + i, dma->get_size(), dma->get_mem());
213 : }
214 : }
215 :
216 : pm = ((uint8_t *) dma->get_mem()) + dma->get_size();
217 :
218 : for (int i = 0; i < MEMORY_CANARY_SIZE; ++i) {
219 : if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
220 : fprintf(stderr, "canary bytes:");
221 :
222 : for (int j = 0; j < MEMORY_CANARY_SIZE; ++j)
223 : fprintf(stderr, " %02x", pm[j]);
224 :
225 : fprintf(stderr, "\n");
226 :
227 : vm_abort("error: dump memory top canary killed: "
228 : "%p (%d bytes allocated at %p)\n",
229 : pm + i, dma->get_size(), dma->get_mem());
230 : }
231 : }
232 : }
233 : }
234 : #endif /* defined(ENABLE_MEMCHECK) */
235 :
236 :
237 : /**
238 : * Allocate a memory block for the current dump memory block.
239 : *
240 : * @param size Required memory size.
241 : */
242 1550999 : DumpMemoryBlock::DumpMemoryBlock(size_t size) : _size(0), _used(0), _block(0)
243 : {
244 : // If requested size is greater than the default, make the new
245 : // memory block as big as the requested size. Otherwise use the
246 : // default size.
247 1550999 : _size = (size > DEFAULT_SIZE) ? size : DEFAULT_SIZE;
248 :
249 : // Allocate a memory block.
250 1550999 : _block = memory_checked_alloc(_size);
251 :
252 : // The amount of globally allocated dump memory (thread safe).
253 : STATISTICS(globalallocateddumpsize += _size);
254 1550993 : }
255 :
256 :
257 : /**
258 : * Release the memory block for the dump memory block.
259 : *
260 : * @param size Required memory size.
261 : */
262 1550844 : DumpMemoryBlock::~DumpMemoryBlock()
263 : {
264 : // Release the memory block.
265 1550844 : mem_free(_block, /* XXX */ 1);
266 :
267 : // The amount of globally allocated dump memory (thread safe).
268 : STATISTICS(globalallocateddumpsize -= _size);
269 1550856 : }
270 :
271 : /*
272 : * These are local overrides for various environment variables in Emacs.
273 : * Please do not remove this and leave it at the end of the file, where
274 : * Emacs will automagically detect them.
275 : * ---------------------------------------------------------------------
276 : * Local variables:
277 : * mode: c++
278 : * indent-tabs-mode: t
279 : * c-basic-offset: 4
280 : * tab-width: 4
281 : * End:
282 : * vim:noexpandtab:sw=4:ts=4:
283 : */
|