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