* Makefile.am (version.h): Fix issues when built out of tree.
[mono.git] / mono / utils / mono-codeman.c
1 #include "config.h"
2
3 #ifdef HAVE_UNISTD_H
4 #include <unistd.h>
5 #endif
6 #include <stdlib.h>
7 #include <string.h>
8 #include <assert.h>
9 #include <glib.h>
10
11 /* For dlmalloc.h */
12 #define USE_DL_PREFIX 1
13
14 #include "mono-codeman.h"
15 #include "mono-mmap.h"
16 #include "dlmalloc.h"
17 #include <mono/metadata/class-internals.h>
18 #ifdef HAVE_VALGRIND_MEMCHECK_H
19 #include <valgrind/memcheck.h>
20 #endif
21  
22 /*
23  * AMD64 processors maintain icache coherency only for pages which are 
24  * marked executable. Also, windows DEP requires us to obtain executable memory from
25  * malloc when using dynamic code managers. The system malloc can't do this so we use a 
26  * slighly modified version of Doug Lea's Malloc package for this purpose:
27  * http://g.oswego.edu/dl/html/malloc.html
28  */
29
30 #define MIN_PAGES 16
31
32 #if defined(__ia64__) || defined(__x86_64__)
33 /*
34  * We require 16 byte alignment on amd64 so the fp literals embedded in the code are 
35  * properly aligned for SSE2.
36  */
37 #define MIN_ALIGN 16
38 #else
39 #define MIN_ALIGN 8
40 #endif
41
42 /* if a chunk has less than this amount of free space it's considered full */
43 #define MAX_WASTAGE 32
44 #define MIN_BSIZE 32
45
46 #ifdef __x86_64__
47 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
48 #else
49 #define ARCH_MAP_FLAGS 0
50 #endif
51
52 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
53
54 typedef struct _CodeChunck CodeChunk;
55
56 enum {
57         CODE_FLAG_MMAP,
58         CODE_FLAG_MALLOC
59 };
60
61 struct _CodeChunck {
62         char *data;
63         int pos;
64         int size;
65         CodeChunk *next;
66         unsigned int flags: 8;
67         /* this number of bytes is available to resolve addresses far in memory */
68         unsigned int bsize: 24;
69 };
70
71 struct _MonoCodeManager {
72         int dynamic;
73         int read_only;
74         CodeChunk *current;
75         CodeChunk *full;
76 };
77
78 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
79
80 /**
81  * mono_code_manager_new:
82  *
83  * Creates a new code manager. A code manager can be used to allocate memory
84  * suitable for storing native code that can be later executed.
85  * A code manager allocates memory from the operating system in large chunks
86  * (typically 64KB in size) so that many methods can be allocated inside them
87  * close together, improving cache locality.
88  *
89  * Returns: the new code manager
90  */
91 MonoCodeManager* 
92 mono_code_manager_new (void)
93 {
94         MonoCodeManager *cman = malloc (sizeof (MonoCodeManager));
95         if (!cman)
96                 return NULL;
97         cman->current = NULL;
98         cman->full = NULL;
99         cman->dynamic = 0;
100         cman->read_only = 0;
101         return cman;
102 }
103
104 /**
105  * mono_code_manager_new_dynamic:
106  *
107  * Creates a new code manager suitable for holding native code that can be
108  * used for single or small methods that need to be deallocated independently
109  * of other native code.
110  *
111  * Returns: the new code manager
112  */
113 MonoCodeManager* 
114 mono_code_manager_new_dynamic (void)
115 {
116         MonoCodeManager *cman = mono_code_manager_new ();
117         cman->dynamic = 1;
118         return cman;
119 }
120
121
122 static void
123 free_chunklist (CodeChunk *chunk)
124 {
125         CodeChunk *dead;
126         
127 #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP)
128         int valgrind_unregister = 0;
129         if (RUNNING_ON_VALGRIND)
130                 valgrind_unregister = 1;
131 #define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0) 
132 #else
133 #define valgrind_unregister(x)
134 #endif
135
136         for (; chunk; ) {
137                 dead = chunk;
138                 chunk = chunk->next;
139                 if (dead->flags == CODE_FLAG_MMAP) {
140                         mono_vfree (dead->data, dead->size);
141                         /* valgrind_unregister(dead->data); */
142                 } else if (dead->flags == CODE_FLAG_MALLOC) {
143                         dlfree (dead->data);
144                 }
145                 free (dead);
146         }
147 }
148
149 /**
150  * mono_code_manager_destroy:
151  * @cman: a code manager
152  *
153  * Free all the memory associated with the code manager @cman.
154  */
155 void
156 mono_code_manager_destroy (MonoCodeManager *cman)
157 {
158         free_chunklist (cman->full);
159         free_chunklist (cman->current);
160         free (cman);
161 }
162
163 /**
164  * mono_code_manager_invalidate:
165  * @cman: a code manager
166  *
167  * Fill all the memory with an invalid native code value
168  * so that any attempt to execute code allocated in the code
169  * manager @cman will fail. This is used for debugging purposes.
170  */
171 void             
172 mono_code_manager_invalidate (MonoCodeManager *cman)
173 {
174         CodeChunk *chunk;
175
176 #if defined(__i386__) || defined(__x86_64__)
177         int fill_value = 0xcc; /* x86 break */
178 #else
179         int fill_value = 0x2a;
180 #endif
181
182         for (chunk = cman->current; chunk; chunk = chunk->next)
183                 memset (chunk->data, fill_value, chunk->size);
184         for (chunk = cman->full; chunk; chunk = chunk->next)
185                 memset (chunk->data, fill_value, chunk->size);
186 }
187
188 /**
189  * mono_code_manager_set_read_only:
190  * @cman: a code manager
191  *
192  * Make the code manager read only, so further allocation requests cause an assert.
193  */
194 void             
195 mono_code_manager_set_read_only (MonoCodeManager *cman)
196 {
197         cman->read_only = TRUE;
198 }
199
200 /**
201  * mono_code_manager_foreach:
202  * @cman: a code manager
203  * @func: a callback function pointer
204  * @user_data: additional data to pass to @func
205  *
206  * Invokes the callback @func for each different chunk of memory allocated
207  * in the code manager @cman.
208  */
209 void
210 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
211 {
212         CodeChunk *chunk;
213         for (chunk = cman->current; chunk; chunk = chunk->next) {
214                 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
215                         return;
216         }
217         for (chunk = cman->full; chunk; chunk = chunk->next) {
218                 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
219                         return;
220         }
221 }
222
223 /* BIND_ROOM is the divisor for the chunck of code size dedicated
224  * to binding branches (branches not reachable with the immediate displacement)
225  * bind_size = size/BIND_ROOM;
226  * we should reduce it and make MIN_PAGES bigger for such systems
227  */
228 #if defined(__ppc__) || defined(__powerpc__)
229 #define BIND_ROOM 4
230 #endif
231 #if defined(__arm__)
232 #define BIND_ROOM 8
233 #endif
234
235 static CodeChunk*
236 new_codechunk (int dynamic, int size)
237 {
238         int minsize, flags = CODE_FLAG_MMAP;
239         int chunk_size, bsize = 0;
240         int pagesize;
241         CodeChunk *chunk;
242         void *ptr;
243
244 #ifdef FORCE_MALLOC
245         flags = CODE_FLAG_MALLOC;
246 #endif
247
248         pagesize = mono_pagesize ();
249
250         if (dynamic) {
251                 chunk_size = size;
252                 flags = CODE_FLAG_MALLOC;
253         } else {
254                 minsize = pagesize * MIN_PAGES;
255                 if (size < minsize)
256                         chunk_size = minsize;
257                 else {
258                         chunk_size = size;
259                         chunk_size += pagesize - 1;
260                         chunk_size &= ~ (pagesize - 1);
261                 }
262         }
263 #ifdef BIND_ROOM
264         bsize = chunk_size / BIND_ROOM;
265         if (bsize < MIN_BSIZE)
266                 bsize = MIN_BSIZE;
267         bsize += MIN_ALIGN -1;
268         bsize &= ~ (MIN_ALIGN - 1);
269         if (chunk_size - size < bsize) {
270                 chunk_size = size + bsize;
271                 chunk_size += pagesize - 1;
272                 chunk_size &= ~ (pagesize - 1);
273         }
274 #endif
275
276         if (flags == CODE_FLAG_MALLOC) {
277                 ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
278                 if (!ptr)
279                         return NULL;
280         } else {
281                 ptr = mono_valloc (NULL, chunk_size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
282                 if (!ptr)
283                         return NULL;
284         }
285
286         if (flags == CODE_FLAG_MALLOC) {
287 #ifdef BIND_ROOM
288                 /* Make sure the thunks area is zeroed */
289                 memset (ptr, 0, bsize);
290 #endif
291         }
292
293         chunk = malloc (sizeof (CodeChunk));
294         if (!chunk) {
295                 if (flags == CODE_FLAG_MALLOC)
296                         dlfree (ptr);
297                 else
298                         mono_vfree (ptr, chunk_size);
299                 return NULL;
300         }
301         chunk->next = NULL;
302         chunk->size = chunk_size;
303         chunk->data = ptr;
304         chunk->flags = flags;
305         chunk->pos = bsize;
306         chunk->bsize = bsize;
307
308         /*printf ("code chunk at: %p\n", ptr);*/
309         return chunk;
310 }
311
312 /**
313  * mono_code_manager_reserve:
314  * @cman: a code manager
315  * @size: size of memory to allocate
316  * @alignment: power of two alignment value
317  *
318  * Allocates at least @size bytes of memory inside the code manager @cman.
319  *
320  * Returns: the pointer to the allocated memory or #NULL on failure
321  */
322 void*
323 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
324 {
325         CodeChunk *chunk, *prev;
326         void *ptr;
327
328         g_assert (!cman->read_only);
329
330         /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
331          * handle this before
332          */
333         g_assert (alignment <= MIN_ALIGN);
334
335         if (cman->dynamic) {
336                 ++mono_stats.dynamic_code_alloc_count;
337                 mono_stats.dynamic_code_bytes_count += size;
338         }
339
340         if (!cman->current) {
341                 cman->current = new_codechunk (cman->dynamic, size);
342                 if (!cman->current)
343                         return NULL;
344         }
345
346         for (chunk = cman->current; chunk; chunk = chunk->next) {
347                 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
348                         chunk->pos = ALIGN_INT (chunk->pos, alignment);
349                         ptr = chunk->data + chunk->pos;
350                         chunk->pos += size;
351                         return ptr;
352                 }
353         }
354         /* 
355          * no room found, move one filled chunk to cman->full 
356          * to keep cman->current from growing too much
357          */
358         prev = NULL;
359         for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
360                 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
361                         continue;
362                 if (prev) {
363                         prev->next = chunk->next;
364                 } else {
365                         cman->current = chunk->next;
366                 }
367                 chunk->next = cman->full;
368                 cman->full = chunk;
369                 break;
370         }
371         chunk = new_codechunk (cman->dynamic, size);
372         if (!chunk)
373                 return NULL;
374         chunk->next = cman->current;
375         cman->current = chunk;
376         chunk->pos = ALIGN_INT (chunk->pos, alignment);
377         ptr = chunk->data + chunk->pos;
378         chunk->pos += size;
379         return ptr;
380 }
381
382 /**
383  * mono_code_manager_reserve:
384  * @cman: a code manager
385  * @size: size of memory to allocate
386  *
387  * Allocates at least @size bytes of memory inside the code manager @cman.
388  *
389  * Returns: the pointer to the allocated memory or #NULL on failure
390  */
391 void*
392 mono_code_manager_reserve (MonoCodeManager *cman, int size)
393 {
394         return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
395 }
396
397 /**
398  * mono_code_manager_commit:
399  * @cman: a code manager
400  * @data: the pointer returned by mono_code_manager_reserve ()
401  * @size: the size requested in the call to mono_code_manager_reserve ()
402  * @newsize: the new size to reserve
403  *
404  * If we reserved too much room for a method and we didn't allocate
405  * already from the code manager, we can get back the excess allocation
406  * for later use in the code manager.
407  */
408 void
409 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
410 {
411         g_assert (newsize <= size);
412
413         if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
414                 cman->current->pos -= size - newsize;
415         }
416 }
417
418 /**
419  * mono_code_manager_size:
420  * @cman: a code manager
421  * @used_size: pointer to an integer for the result
422  *
423  * This function can be used to get statistics about a code manager:
424  * the integer pointed to by @used_size will contain how much
425  * memory is actually used inside the code managed @cman.
426  *
427  * Returns: the amount of memory allocated in @cman
428  */
429 int
430 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
431 {
432         CodeChunk *chunk;
433         guint32 size = 0;
434         guint32 used = 0;
435         for (chunk = cman->current; chunk; chunk = chunk->next) {
436                 size += chunk->size;
437                 used += chunk->pos;
438         }
439         for (chunk = cman->full; chunk; chunk = chunk->next) {
440                 size += chunk->size;
441                 used += chunk->pos;
442         }
443         if (used_size)
444                 *used_size = used;
445         return size;
446 }
447