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