CACAO
dumpmemory.hpp
Go to the documentation of this file.
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 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  */
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  inline size_t get_size() const { return _size; }
104  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 
111 
112 #if defined(ENABLE_MEMCHECK)
113 private:
114  void check_canaries();
115 #endif
116 };
117 
118 
119 /**
120  * Dump memory block.
121  */
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);
133 
134  inline size_t get_size() const { return _size; }
135  inline size_t get_used() const { return _used; }
136  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 {
160  };
161 
162  // Constructors and destructor, nothing to do because the
163  // allocator has no state.
164  DumpMemoryAllocator() throw() {}
166  template <class U> DumpMemoryAllocator(const DumpMemoryAllocator<U>&) throw() {}
167 
168  ~DumpMemoryAllocator() throw() {}
169 
170  pointer allocate(size_type n, void* = 0) {
171 // printf("allocate: n=%d * %d\n", n, sizeof(T));
172  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  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  new ((void*) p) T(value);
185  }
186 
187  // Destroy elements of initialized storage p.
188  void destroy(pointer p) {
189 // printf("destroy: p=%p\n", (void*) p);
190  // Destroy objects by calling their destructor.
191  p->~T();
192  }
193 
195 // printf("deallocate: p=%p, n=%d\n", (void*) p, n);
196  // We don't need to deallocate on dump memory.
197  }
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 inline void* DumpClass::operator new(size_t size)
229 {
230  return DumpMemory::allocate(size);
231 }
232 
233 inline void DumpClass::operator delete(void* p)
234 {
235  // We don't need to deallocate on dump memory.
236 }
237 
239 {
240  // Get the DumpMemory object of the current thread.
242  DumpMemory* dm = t->_dumpmemory;
243  return dm;
244 }
245 
247 {
248  return _areas.back();
249 }
250 
251 inline void* DumpMemory::allocate(size_t size)
252 {
253  DumpMemory* dm = get_current();
254  DumpMemoryArea* dma = dm->get_current_area();
255 
256  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  alignedsize = MEMORY_ALIGN(alignedsize, ALIGNSIZE);
264 
265  void* p = dma->allocate(alignedsize);
266 
267  // Increase the used count of the dump memory.
268  dm->_used += alignedsize;
269 
270  return p;
271 }
272 
274 {
275  return _blocks.empty() ? NULL : _blocks.back();
276 }
277 
278 inline void* DumpMemoryArea::allocate(size_t size)
279 {
281 
282  // Check if we have a memory block or have enough memory in the
283  // current memory block.
284  if (dmb == NULL || size > dmb->get_free()) {
285  // No, allocate a new one.
286  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  _size += dmb->get_size();
292  }
293 
294  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  _used += size;
329 
330  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  */
352 {
353  if (size == 0)
354  return NULL;
355 
356  // Sanity check.
357  assert(size <= (_size - _used));
358 
359  // Calculate the memory address of the newly allocated memory.
360  void* p = (void*) (((uint8_t*) _block) + _used);
361 
362  // Increase used memory block size by the allocated memory size.
363  _used += size;
364 
365  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  */
pointer allocate(size_type n, void *=0)
Definition: dumpmemory.hpp:170
DumpMemoryArea(size_t size=0)
Allocate a new dump memory area.
Definition: dumpmemory.cpp:113
All classes intended to be allocated on dump memory should extend this base class to inherit the appr...
Definition: dumpmemory.hpp:50
static void * memset(void *s, int c, size_t n)
Definition: os.hpp:501
std::vector< DumpMemoryBlock * > _blocks
List of memory blocks in this area.
Definition: dumpmemory.hpp:94
DumpMemoryAllocator< U > other
Definition: dumpmemory.hpp:159
void remove_area(DumpMemoryArea *dma)
Remove the given dump area from the area list.
Definition: dumpmemory.cpp:93
void construct(pointer p, const T &value)
Definition: dumpmemory.hpp:181
std::ptrdiff_t difference_type
Definition: dumpmemory.hpp:155
Allocator for the dump memory.
Definition: dumpmemory.hpp:146
Dump memory block.
Definition: dumpmemory.hpp:122
DumpMemoryArea * get_current_area() const
Definition: dumpmemory.hpp:246
size_t get_free() const
Definition: dumpmemory.hpp:136
DumpMemoryAllocator(const DumpMemoryAllocator &)
Definition: dumpmemory.hpp:165
void deallocate(pointer p, size_type n)
Definition: dumpmemory.hpp:194
typedef void(JNICALL *jvmtiEventSingleStep)(jvmtiEnv *jvmti_env
void * allocate(size_t size)
Definition: dumpmemory.hpp:278
const T * const_pointer
Definition: dumpmemory.hpp:151
DumpMemoryBlock(size_t size=0)
Checks canaries in this dump memory area.
Definition: dumpmemory.cpp:242
pointer reallocate(pointer p, size_type old_sz, size_type new_sz)
Definition: dumpmemory.hpp:176
size_t get_used() const
Definition: dumpmemory.hpp:135
const T & const_reference
Definition: dumpmemory.hpp:153
size_t get_size() const
Definition: dumpmemory.hpp:103
size_t _used
Used memory in the current memory block.
Definition: dumpmemory.hpp:127
JNIEnv jthread jobject jclass jlong size
Definition: jvmti.h:387
size_t _size
Size of the current memory block.
Definition: dumpmemory.hpp:92
~DumpMemoryArea()
Release all dump memory blocks in the current dump area.
Definition: dumpmemory.cpp:126
size_t _size
Size of the dump areas in this dump memory.
Definition: dumpmemory.hpp:62
void destroy(pointer p)
Definition: dumpmemory.hpp:188
DumpMemoryBlock * get_current_block() const
Definition: dumpmemory.hpp:273
size_t _size
Size of the current memory block.
Definition: dumpmemory.hpp:126
Dump memory area.
Definition: dumpmemory.hpp:90
size_t get_size() const
Definition: dumpmemory.hpp:75
This file contains the statistics framework.
static void * reallocate(void *src, size_t len1, size_t len2)
Stupid realloc implementation for dump memory.
Definition: dumpmemory.cpp:57
void add_size(size_t size)
Definition: dumpmemory.hpp:73
size_t get_used() const
Definition: dumpmemory.hpp:104
MIIterator i
#define ALIGNSIZE
Definition: gc-none.cpp:50
size_t _used
Used memory in this dump memory.
Definition: dumpmemory.hpp:63
size_t _used
Used memory in the current memory block.
Definition: dumpmemory.hpp:93
~DumpMemoryBlock()
Release the memory block for the dump memory block.
Definition: dumpmemory.cpp:262
size_t get_used() const
Definition: dumpmemory.hpp:76
static threadobject * thread_get_current()
Return the threadobject for the current thread.
Definition: thread-none.hpp:56
void * _block
List of memory blocks in this area.
Definition: dumpmemory.hpp:128
DumpMemoryAllocator(const DumpMemoryAllocator< U > &)
Definition: dumpmemory.hpp:166
static void * allocate(size_t size)
Definition: dumpmemory.hpp:251
std::list< DumpMemoryArea * > _areas
Pointer to the current dump area.
Definition: dumpmemory.hpp:64
#define MEMORY_ALIGN(pos, size)
Definition: memory.hpp:37
DumpMemory()
Allocate a new thread-local dump memory structure.
Definition: dumpmemory.cpp:49
DumpMemoryBlock * allocate_new_block(size_t size)
Allocate a dump memory block for the current dump memory area.
Definition: dumpmemory.cpp:167
DumpMemory * _dumpmemory
Dump memory structure.
Definition: thread.hpp:143
Thread-local dump memory structure.
Definition: dumpmemory.hpp:60
std::size_t size_type
Definition: dumpmemory.hpp:154
size_t get_size() const
Definition: dumpmemory.hpp:134
void * allocate(size_t size)
Allocate memory in the current dump memory area.
Definition: dumpmemory.hpp:351
static const size_t DEFAULT_SIZE
Definition: dumpmemory.hpp:124
void add_area(DumpMemoryArea *dma)
Add the given dump area to the area list.
Definition: dumpmemory.cpp:77
static DumpMemory * get_current()
Definition: dumpmemory.hpp:238