Line data Source code
1 : /* src/mm/dumpmemory.hpp - 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 :
27 : #ifndef DUMPMEMORY_HPP_
28 : #define DUMPMEMORY_HPP_ 1
29 :
30 : #include <assert.h> // for assert
31 : #include <stddef.h> // for size_t, NULL
32 : #include <stdint.h> // for uint8_t
33 : #include <cstddef> // for ptrdiff_t, size_t
34 : #include <list> // for list
35 : #include <new> // for operator new
36 : #include <vector> // for vector
37 : #include "config.h" // for ENABLE_MEMCHECK
38 : #include "mm/memory.hpp" // for MEMORY_CANARY_SIZE, etc
39 : #include "threads/thread.hpp" // for thread_get_current, etc
40 : #include "vm/os.hpp" // for os
41 :
42 : class DumpMemoryAllocation;
43 : class DumpMemoryArea;
44 : class DumpMemoryBlock;
45 :
46 : /**
47 : * All classes intended to be allocated on dump memory should extend this
48 : * base class to inherit the appropriate allocation operators.
49 : */
50 461178 : class DumpClass {
51 : public:
52 : void* operator new(size_t size);
53 : void operator delete(void* p);
54 : };
55 :
56 :
57 : /**
58 : * Thread-local dump memory structure.
59 : */
60 : class DumpMemory {
61 : private:
62 : size_t _size; ///< Size of the dump areas in this dump memory.
63 : size_t _used; ///< Used memory in this dump memory.
64 : std::list<DumpMemoryArea*> _areas; ///< Pointer to the current dump area.
65 :
66 : public:
67 : DumpMemory();
68 : ~DumpMemory();
69 :
70 : static inline DumpMemory* get_current();
71 : static inline void* allocate(size_t size);
72 :
73 : inline void add_size(size_t size) { _size += size; }
74 :
75 : inline size_t get_size() const { return _size; }
76 : inline size_t get_used() const { return _used; }
77 :
78 : inline DumpMemoryArea* get_current_area() const;
79 :
80 : static void* reallocate(void* src, size_t len1, size_t len2);
81 :
82 : void add_area(DumpMemoryArea* dma);
83 : void remove_area(DumpMemoryArea* dma);
84 : };
85 :
86 :
87 : /**
88 : * Dump memory area.
89 : */
90 : class DumpMemoryArea {
91 : private:
92 : size_t _size; ///< Size of the current memory block.
93 : size_t _used; ///< Used memory in the current memory block.
94 : std::vector<DumpMemoryBlock*> _blocks; ///< List of memory blocks in this area.
95 : #if defined(ENABLE_MEMCHECK)
96 : std::vector<DumpMemoryAllocation*> _allocs; ///< List of allocations in this area.
97 : #endif
98 :
99 : public:
100 : DumpMemoryArea(size_t size = 0);
101 : ~DumpMemoryArea();
102 :
103 2610303 : inline size_t get_size() const { return _size; }
104 1305101 : inline size_t get_used() const { return _used; }
105 :
106 : // Inline functions.
107 : inline void* allocate(size_t size);
108 : inline DumpMemoryBlock* get_current_block() const;
109 :
110 : DumpMemoryBlock* allocate_new_block(size_t size);
111 :
112 : #if defined(ENABLE_MEMCHECK)
113 : private:
114 : void check_canaries();
115 : #endif
116 : };
117 :
118 :
119 : /**
120 : * Dump memory block.
121 : */
122 : class DumpMemoryBlock {
123 : private:
124 : static const size_t DEFAULT_SIZE = 2 << 13; // 2 * 8192 bytes
125 :
126 : size_t _size; ///< Size of the current memory block.
127 : size_t _used; ///< Used memory in the current memory block.
128 : void* _block; ///< List of memory blocks in this area.
129 :
130 : public:
131 : DumpMemoryBlock(size_t size = 0);
132 : ~DumpMemoryBlock();
133 :
134 1545634 : inline size_t get_size() const { return _size; }
135 : inline size_t get_used() const { return _used; }
136 9852867 : inline size_t get_free() const { return _size - _used; }
137 :
138 : // Inline functions.
139 : inline void* allocate(size_t size);
140 : };
141 :
142 :
143 : /**
144 : * Allocator for the dump memory.
145 : */
146 : template<class T> class DumpMemoryAllocator {
147 : public:
148 : // Type definitions.
149 : typedef T value_type;
150 : typedef T* pointer;
151 : typedef const T* const_pointer;
152 : typedef T& reference;
153 : typedef const T& const_reference;
154 : typedef std::size_t size_type;
155 : typedef std::ptrdiff_t difference_type;
156 :
157 : // Rebind allocator to type U.
158 : template <class U> struct rebind {
159 : typedef DumpMemoryAllocator<U> other;
160 : };
161 :
162 : // Constructors and destructor, nothing to do because the
163 : // allocator has no state.
164 461178 : DumpMemoryAllocator() throw() {}
165 : DumpMemoryAllocator(const DumpMemoryAllocator&) throw() {}
166 4307142 : template <class U> DumpMemoryAllocator(const DumpMemoryAllocator<U>&) throw() {}
167 :
168 4557672 : ~DumpMemoryAllocator() throw() {}
169 :
170 2567950 : pointer allocate(size_type n, void* = 0) {
171 : // printf("allocate: n=%d * %d\n", n, sizeof(T));
172 2567950 : return static_cast<pointer>(DumpMemory::allocate(n * sizeof(T)));
173 : }
174 :
175 : // ** Reallocate block of storage (non-standard!)
176 : inline pointer reallocate(pointer p, size_type old_sz, size_type new_sz) {
177 : return static_cast<pointer>(DumpMemory::reallocate(p, old_sz * sizeof(T), new_sz * sizeof(T)));
178 : }
179 :
180 : // Initialize elements of allocated storage p with value value.
181 2567950 : void construct(pointer p, const T& value) {
182 : // printf("construct: p=%p, value=%p\n", (void*) p, (void*) value);
183 : // Initialize memory with placement new.
184 2567950 : new ((void*) p) T(value);
185 2567950 : }
186 :
187 : // Destroy elements of initialized storage p.
188 1739192 : void destroy(pointer p) {
189 : // printf("destroy: p=%p\n", (void*) p);
190 : // Destroy objects by calling their destructor.
191 1709334 : p->~T();
192 1739192 : }
193 :
194 1739192 : void deallocate(pointer p, size_type n) {
195 : // printf("deallocate: p=%p, n=%d\n", (void*) p, n);
196 : // We don't need to deallocate on dump memory.
197 1739192 : }
198 : };
199 :
200 :
201 : /**
202 : * Dump memory allocation, used for for ENABLE_MEMCHECK.
203 : */
204 : #if defined(ENABLE_MEMCHECK)
205 : class DumpMemoryAllocation {
206 : private:
207 : size_t _size;
208 : void* _mem;
209 :
210 : public:
211 : DumpMemoryAllocation() : _size(0), _mem(NULL) {}
212 : DumpMemoryAllocation(size_t size, void* mem) : _size(size), _mem(mem) {}
213 : ~DumpMemoryAllocation() {};
214 :
215 : inline size_t get_size() const { return _size; }
216 : inline void* get_mem() const { return _mem; }
217 : };
218 : #endif
219 :
220 :
221 : // Includes.
222 : #include "mm/memory.hpp"
223 :
224 : #include "vm/statistics.hpp"
225 :
226 : // Inline functions.
227 :
228 210648 : inline void* DumpClass::operator new(size_t size)
229 : {
230 210648 : return DumpMemory::allocate(size);
231 : }
232 :
233 0 : inline void DumpClass::operator delete(void* p)
234 : {
235 : // We don't need to deallocate on dump memory.
236 0 : }
237 :
238 13768015 : inline DumpMemory* DumpMemory::get_current()
239 : {
240 : // Get the DumpMemory object of the current thread.
241 13768015 : threadobject* t = thread_get_current();
242 13768065 : DumpMemory* dm = t->_dumpmemory;
243 13768065 : return dm;
244 : }
245 :
246 11157925 : inline DumpMemoryArea* DumpMemory::get_current_area() const
247 : {
248 11157925 : return _areas.back();
249 : }
250 :
251 11157912 : inline void* DumpMemory::allocate(size_t size)
252 : {
253 11157912 : DumpMemory* dm = get_current();
254 11157926 : DumpMemoryArea* dma = dm->get_current_area();
255 :
256 11157892 : size_t alignedsize = size;
257 :
258 : #if defined(ENABLE_MEMCHECK)
259 : alignedsize += 2 * MEMORY_CANARY_SIZE;
260 : #endif
261 :
262 : // Align the allocation size.
263 11157892 : alignedsize = MEMORY_ALIGN(alignedsize, ALIGNSIZE);
264 :
265 11157892 : void* p = dma->allocate(alignedsize);
266 :
267 : // Increase the used count of the dump memory.
268 11157961 : dm->_used += alignedsize;
269 :
270 11157961 : return p;
271 : }
272 :
273 11157897 : inline DumpMemoryBlock* DumpMemoryArea::get_current_block() const
274 : {
275 11157897 : return _blocks.empty() ? NULL : _blocks.back();
276 : }
277 :
278 11157899 : inline void* DumpMemoryArea::allocate(size_t size)
279 : {
280 11157899 : DumpMemoryBlock* dmb = get_current_block();
281 :
282 : // Check if we have a memory block or have enough memory in the
283 : // current memory block.
284 11157943 : if (dmb == NULL || size > dmb->get_free()) {
285 : // No, allocate a new one.
286 1545628 : dmb = allocate_new_block(size);
287 :
288 : // Increase the size of the memory area. We use get_size()
289 : // here because the default size is very likely to be bigger
290 : // than size.
291 1545635 : _size += dmb->get_size();
292 : }
293 :
294 11157947 : void* p = dmb->allocate(size);
295 :
296 : #if defined(ENABLE_MEMCHECK)
297 : uint8_t *pm;
298 : size_t origsize = size - 2 * MEMORY_CANARY_SIZE;
299 :
300 : // Make p point after the bottom canary.
301 :
302 : p = ((uint8_t *) p) + MEMORY_CANARY_SIZE;
303 :
304 : // Add the allocation to our list of allocations
305 :
306 : DumpMemoryAllocation* dma = new DumpMemoryAllocation(origsize, p);
307 :
308 : _allocs.push_back(dma);
309 :
310 : // Write the canaries.
311 :
312 : pm = ((uint8_t *) p) - MEMORY_CANARY_SIZE;
313 :
314 : for (int i = 0; i < MEMORY_CANARY_SIZE; ++i)
315 : pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
316 :
317 : pm = ((uint8_t *) p) + dma->get_size();
318 :
319 : for (int i = 0; i < MEMORY_CANARY_SIZE; ++i)
320 : pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
321 :
322 : // Clear the memory.
323 :
324 : (void) os::memset(p, MEMORY_CLEAR_BYTE, dma->get_size());
325 : #endif /* defined(ENABLE_MEMCHECK) */
326 :
327 : // Increase the used size of the memory area.
328 11157959 : _used += size;
329 :
330 11157959 : return p;
331 : }
332 :
333 : /**
334 : * Allocate memory in the current dump memory area.
335 : *
336 : * This function is a fast allocator suitable for scratch memory that
337 : * can be collectively freed when the current activity (eg. compiling)
338 : * is done.
339 : *
340 : * You cannot selectively free dump memory. Before you start
341 : * allocating it, you remember the current size returned by
342 : * `dumpmemory_marker`. Later, when you no longer need the memory,
343 : * call `dumpmemory_release` with the remembered size and all dump
344 : * memory allocated since the call to `dumpmemory_marker` will be
345 : * freed.
346 : *
347 : * @parm size Size of block to allocate in bytes. May be zero, in which case NULL is returned
348 : *
349 : * @return Pointer to allocated memory, or NULL iff size was zero.
350 : */
351 11157966 : void* DumpMemoryBlock::allocate(size_t size)
352 : {
353 11157966 : if (size == 0)
354 850180 : return NULL;
355 :
356 : // Sanity check.
357 10307786 : assert(size <= (_size - _used));
358 :
359 : // Calculate the memory address of the newly allocated memory.
360 10307786 : void* p = (void*) (((uint8_t*) _block) + _used);
361 :
362 : // Increase used memory block size by the allocated memory size.
363 10307786 : _used += size;
364 :
365 10307786 : return p;
366 : }
367 :
368 : // Legacy C interface.
369 :
370 : #define DNEW(type) ((type*) DumpMemory::allocate(sizeof(type)))
371 : #define DMNEW(type,num) ((type*) DumpMemory::allocate(sizeof(type) * (num)))
372 : #define DMREALLOC(ptr,type,num1,num2) ((type*) DumpMemory::reallocate((ptr), sizeof(type) * (num1), sizeof(type) * (num2)))
373 :
374 : #endif // DUMPMEMORY_HPP_
375 :
376 :
377 : /*
378 : * These are local overrides for various environment variables in Emacs.
379 : * Please do not remove this and leave it at the end of the file, where
380 : * Emacs will automagically detect them.
381 : * ---------------------------------------------------------------------
382 : * Local variables:
383 : * mode: c++
384 : * indent-tabs-mode: t
385 : * c-basic-offset: 4
386 : * tab-width: 4
387 : * End:
388 : * vim:noexpandtab:sw=4:ts=4:
389 : */
|