in mono/mono/mini:
[mono.git] / mono / metadata / mempool.c
1 /*
2  * mempool.c: efficient memory allocation
3  *
4  * MonoMemPool is for fast allocation of memory. We free
5  * all memory when the pool is destroyed.
6  *
7  * Author:
8  *   Dietmar Maurer (dietmar@ximian.com)
9  *
10  * (C) 2001 Ximian, Inc.
11  */
12
13 #include <config.h>
14 #include <glib.h>
15 #include <string.h>
16
17 #include "mempool.h"
18
19 /*
20  * MonoMemPool is for fast allocation of memory. We free
21  * all memory when the pool is destroyed.
22  */
23
24 #define MEM_ALIGN 8
25
26 #define MONO_MEMPOOL_PAGESIZE 8192
27
28 #ifndef G_LIKELY
29 #define G_LIKELY(a) (a)
30 #define G_UNLIKELY(a) (a)
31 #endif
32
33 struct _MonoMemPool {
34         MonoMemPool *next;
35         gint rest;
36         guint8 *pos, *end;
37         guint32 size;
38         union {
39                 double pad; /* to assure proper alignment */
40                 guint32 allocated;
41         } d;
42 };
43
44 /**
45  * mono_mempool_new:
46  *
47  * Returns: a new memory pool.
48  */
49 MonoMemPool *
50 mono_mempool_new ()
51 {
52         MonoMemPool *pool = g_malloc (MONO_MEMPOOL_PAGESIZE);
53
54         pool->next = NULL;
55         pool->pos = (guint8*)pool + sizeof (MonoMemPool);
56         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
57         pool->d.allocated = pool->size = MONO_MEMPOOL_PAGESIZE;
58         return pool;
59 }
60
61 /**
62  * mono_mempool_destroy:
63  * @pool: the memory pool to destroy
64  *
65  * Free all memory associated with this pool.
66  */
67 void
68 mono_mempool_destroy (MonoMemPool *pool)
69 {
70         MonoMemPool *p, *n;
71
72         p = pool;
73         while (p) {
74                 n = p->next;
75                 g_free (p);
76                 p = n;
77         }
78 }
79
80 /**
81  * mono_mempool_invalidate:
82  * @pool: the memory pool to invalidate
83  *
84  * Fill the memory associated with this pool to 0x2a (42). Useful for debugging.
85  */
86 void
87 mono_mempool_invalidate (MonoMemPool *pool)
88 {
89         MonoMemPool *p, *n;
90
91         p = pool;
92         while (p) {
93                 n = p->next;
94                 memset (p, 42, p->size);
95                 p = n;
96         }
97 }
98
99 void
100 mono_mempool_empty (MonoMemPool *pool)
101 {
102         pool->pos = (guint8*)pool + sizeof (MonoMemPool);
103         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
104 }
105
106 /**
107  * mono_mempool_stats:
108  * @pool: the momory pool we need stats for
109  *
110  * Print a few stats about the mempool
111  */
112 void
113 mono_mempool_stats (MonoMemPool *pool)
114 {
115         MonoMemPool *p;
116         int count = 0;
117         guint32 still_free = 0;
118
119         p = pool;
120         while (p) {
121                 still_free += p->end - p->pos;
122                 p = p->next;
123                 count++;
124         }
125         if (pool) {
126                 g_print ("Mempool %p stats:\n", pool);
127                 g_print ("Total mem allocated: %d\n", pool->d.allocated);
128                 g_print ("Num chunks: %d\n", count);
129                 g_print ("Free memory: %d\n", still_free);
130         }
131 }
132
133 #ifdef TRACE_ALLOCATIONS
134 #include <execinfo.h>
135 #include "metadata/appdomain.h"
136 #include "metadata/metadata-internals.h"
137
138 static void
139 mono_backtrace (int limit)
140 {
141         void *array[limit];
142         char **names;
143         int i;
144         backtrace (array, limit);
145         names = backtrace_symbols (array, limit);
146         for (i = 1; i < limit; ++i) {
147                 g_print ("\t%s\n", names [i]);
148         }
149         g_free (names);
150 }
151
152 #endif
153
154 /**
155  * mono_mempool_alloc:
156  * @pool: the momory pool to destroy
157  * @size: size of the momory block
158  *
159  * Allocates a new block of memory in @pool.
160  *
161  * Returns: the address of a newly allocated memory block.
162  */
163 gpointer
164 mono_mempool_alloc (MonoMemPool *pool, guint size)
165 {
166         gpointer rval;
167         
168         size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
169
170         rval = pool->pos;
171         pool->pos = (guint8*)rval + size;
172
173 #ifdef TRACE_ALLOCATIONS
174         if (pool == mono_get_corlib ()->mempool) {
175                 g_print ("Allocating %d bytes\n", size);
176                 mono_backtrace (7);
177         }
178 #endif
179         if (G_UNLIKELY (pool->pos >= pool->end)) {
180                 pool->pos -= size;
181                 if (size >= 4096) {
182                         MonoMemPool *np = g_malloc (sizeof (MonoMemPool) + size);
183                         np->next = pool->next;
184                         pool->next = np;
185                         np->pos = (guint8*)np + sizeof (MonoMemPool);
186                         np->size = sizeof (MonoMemPool) + size;
187                         np->end = np->pos + np->size - sizeof (MonoMemPool);
188                         pool->d.allocated += sizeof (MonoMemPool) + size;
189                         return (guint8*)np + sizeof (MonoMemPool);
190                 } else {
191                         MonoMemPool *np = g_malloc (MONO_MEMPOOL_PAGESIZE);
192                         np->next = pool->next;
193                         pool->next = np;
194                         pool->pos = (guint8*)np + sizeof (MonoMemPool);
195                         np->pos = (guint8*)np + sizeof (MonoMemPool);
196                         np->size = MONO_MEMPOOL_PAGESIZE;
197                         np->end = np->pos;
198                         pool->end = pool->pos + MONO_MEMPOOL_PAGESIZE - sizeof (MonoMemPool);
199                         pool->d.allocated += MONO_MEMPOOL_PAGESIZE;
200
201                         rval = pool->pos;
202                         pool->pos += size;
203                 }
204         }
205
206         return rval;
207 }
208
209 /**
210  * mono_mempool_alloc0:
211  *
212  * same as mono_mempool_alloc, but fills memory with zero.
213  */
214 gpointer
215 mono_mempool_alloc0 (MonoMemPool *pool, guint size)
216 {
217         gpointer rval;
218         
219         size = (size + MEM_ALIGN - 1) & ~(MEM_ALIGN - 1);
220
221         rval = pool->pos;
222         pool->pos = (guint8*)rval + size;
223
224         if (G_UNLIKELY (pool->pos >= pool->end)) {
225                 rval = mono_mempool_alloc (pool, size);
226         }
227
228         memset (rval, 0, size);
229         return rval;
230 }
231
232 /**
233  * mono_mempool_contains_addr:
234  *
235  *  Determines whenever ADDR is inside the memory used by the mempool.
236  */
237 gboolean
238 mono_mempool_contains_addr (MonoMemPool *pool,
239                                                         gpointer addr)
240 {
241         MonoMemPool *p;
242
243         p = pool;
244         while (p) {
245                 if (addr > (gpointer)p && addr <= (gpointer)((guint8*)p + p->size))
246                         return TRUE;
247                 p = p->next;
248         }
249
250         return FALSE;
251 }
252
253 /**
254  * mono_mempool_strdup:
255  *
256  * Same as strdup, but allocates memory from the mempool.
257  * Returns: a pointer to the newly allocated string data inside the mempool.
258  */
259 char*
260 mono_mempool_strdup (MonoMemPool *pool,
261                                          const char *s)
262 {
263         int l;
264         char *res;
265
266         if (s == NULL)
267                 return NULL;
268
269         l = strlen (s);
270         res = mono_mempool_alloc (pool, l + 1);
271         memcpy (res, s, l + 1);
272
273         return res;
274 }
275
276 /**
277  * mono_mempool_get_allocated:
278  *
279  * Return the amount of memory allocated for this mempool.
280  */
281 guint32
282 mono_mempool_get_allocated (MonoMemPool *pool)
283 {
284         return pool->d.allocated;
285 }