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