Merge pull request #2994 from ludovic-henry/remove-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 "mono-counters.h"
17 #include "dlmalloc.h"
18 #include <mono/io-layer/io-layer.h>
19 #include <mono/metadata/profiler-private.h>
20 #ifdef HAVE_VALGRIND_MEMCHECK_H
21 #include <valgrind/memcheck.h>
22 #endif
23
24 #include <mono/utils/mono-os-mutex.h>
25
26
27 static uintptr_t code_memory_used = 0;
28 static size_t dynamic_code_alloc_count;
29 static size_t dynamic_code_bytes_count;
30 static size_t dynamic_code_frees_count;
31
32 /*
33  * AMD64 processors maintain icache coherency only for pages which are 
34  * marked executable. Also, windows DEP requires us to obtain executable memory from
35  * malloc when using dynamic code managers. The system malloc can't do this so we use a 
36  * slighly modified version of Doug Lea's Malloc package for this purpose:
37  * http://g.oswego.edu/dl/html/malloc.html
38  */
39
40 #define MIN_PAGES 16
41
42 #if defined(__ia64__) || defined(__x86_64__) || defined (_WIN64)
43 /*
44  * We require 16 byte alignment on amd64 so the fp literals embedded in the code are 
45  * properly aligned for SSE2.
46  */
47 #define MIN_ALIGN 16
48 #else
49 #define MIN_ALIGN 8
50 #endif
51
52 /* if a chunk has less than this amount of free space it's considered full */
53 #define MAX_WASTAGE 32
54 #define MIN_BSIZE 32
55
56 #ifdef __x86_64__
57 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
58 #else
59 #define ARCH_MAP_FLAGS 0
60 #endif
61
62 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
63
64 typedef struct _CodeChunck CodeChunk;
65
66 enum {
67         CODE_FLAG_MMAP,
68         CODE_FLAG_MALLOC
69 };
70
71 struct _CodeChunck {
72         char *data;
73         int pos;
74         int size;
75         CodeChunk *next;
76         unsigned int flags: 8;
77         /* this number of bytes is available to resolve addresses far in memory */
78         unsigned int bsize: 24;
79 };
80
81 struct _MonoCodeManager {
82         int dynamic;
83         int read_only;
84         CodeChunk *current;
85         CodeChunk *full;
86         CodeChunk *last;
87 };
88
89 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
90
91 #define VALLOC_FREELIST_SIZE 16
92
93 static mono_mutex_t valloc_mutex;
94 static GHashTable *valloc_freelists;
95
96 static void*
97 codechunk_valloc (void *preferred, guint32 size)
98 {
99         void *ptr;
100         GSList *freelist;
101
102         if (!valloc_freelists) {
103                 mono_os_mutex_init_recursive (&valloc_mutex);
104                 valloc_freelists = g_hash_table_new (NULL, NULL);
105         }
106
107         /*
108          * Keep a small freelist of memory blocks to decrease pressure on the kernel memory subsystem to avoid #3321.
109          */
110         mono_os_mutex_lock (&valloc_mutex);
111         freelist = (GSList *) g_hash_table_lookup (valloc_freelists, GUINT_TO_POINTER (size));
112         if (freelist) {
113                 ptr = freelist->data;
114                 memset (ptr, 0, size);
115                 freelist = g_slist_delete_link (freelist, freelist);
116                 g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist);
117         } else {
118                 ptr = mono_valloc (preferred, size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
119                 if (!ptr && preferred)
120                         ptr = mono_valloc (NULL, size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
121         }
122         mono_os_mutex_unlock (&valloc_mutex);
123         return ptr;
124 }
125
126 static void
127 codechunk_vfree (void *ptr, guint32 size)
128 {
129         GSList *freelist;
130
131         mono_os_mutex_lock (&valloc_mutex);
132         freelist = (GSList *) g_hash_table_lookup (valloc_freelists, GUINT_TO_POINTER (size));
133         if (!freelist || g_slist_length (freelist) < VALLOC_FREELIST_SIZE) {
134                 freelist = g_slist_prepend (freelist, ptr);
135                 g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist);
136         } else {
137                 mono_vfree (ptr, size);
138         }
139         mono_os_mutex_unlock (&valloc_mutex);
140 }               
141
142 static void
143 codechunk_cleanup (void)
144 {
145         GHashTableIter iter;
146         gpointer key, value;
147
148         if (!valloc_freelists)
149                 return;
150         g_hash_table_iter_init (&iter, valloc_freelists);
151         while (g_hash_table_iter_next (&iter, &key, &value)) {
152                 GSList *freelist = (GSList *) value;
153                 GSList *l;
154
155                 for (l = freelist; l; l = l->next) {
156                         mono_vfree (l->data, GPOINTER_TO_UINT (key));
157                 }
158                 g_slist_free (freelist);
159         }
160         g_hash_table_destroy (valloc_freelists);
161 }
162
163 void
164 mono_code_manager_init (void)
165 {
166         mono_counters_register ("Dynamic code allocs", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_alloc_count);
167         mono_counters_register ("Dynamic code bytes", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_bytes_count);
168         mono_counters_register ("Dynamic code frees", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_frees_count);
169 }
170
171 void
172 mono_code_manager_cleanup (void)
173 {
174         codechunk_cleanup ();
175 }
176
177 /**
178  * mono_code_manager_new:
179  *
180  * Creates a new code manager. A code manager can be used to allocate memory
181  * suitable for storing native code that can be later executed.
182  * A code manager allocates memory from the operating system in large chunks
183  * (typically 64KB in size) so that many methods can be allocated inside them
184  * close together, improving cache locality.
185  *
186  * Returns: the new code manager
187  */
188 MonoCodeManager* 
189 mono_code_manager_new (void)
190 {
191         return (MonoCodeManager *) g_malloc0 (sizeof (MonoCodeManager));
192 }
193
194 /**
195  * mono_code_manager_new_dynamic:
196  *
197  * Creates a new code manager suitable for holding native code that can be
198  * used for single or small methods that need to be deallocated independently
199  * of other native code.
200  *
201  * Returns: the new code manager
202  */
203 MonoCodeManager* 
204 mono_code_manager_new_dynamic (void)
205 {
206         MonoCodeManager *cman = mono_code_manager_new ();
207         cman->dynamic = 1;
208         return cman;
209 }
210
211
212 static void
213 free_chunklist (CodeChunk *chunk)
214 {
215         CodeChunk *dead;
216         
217 #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP)
218         int valgrind_unregister = 0;
219         if (RUNNING_ON_VALGRIND)
220                 valgrind_unregister = 1;
221 #define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0) 
222 #else
223 #define valgrind_unregister(x)
224 #endif
225
226         for (; chunk; ) {
227                 dead = chunk;
228                 mono_profiler_code_chunk_destroy ((gpointer) dead->data);
229                 chunk = chunk->next;
230                 if (dead->flags == CODE_FLAG_MMAP) {
231                         codechunk_vfree (dead->data, dead->size);
232                         /* valgrind_unregister(dead->data); */
233                 } else if (dead->flags == CODE_FLAG_MALLOC) {
234                         dlfree (dead->data);
235                 }
236                 code_memory_used -= dead->size;
237                 free (dead);
238         }
239 }
240
241 /**
242  * mono_code_manager_destroy:
243  * @cman: a code manager
244  *
245  * Free all the memory associated with the code manager @cman.
246  */
247 void
248 mono_code_manager_destroy (MonoCodeManager *cman)
249 {
250         free_chunklist (cman->full);
251         free_chunklist (cman->current);
252         free (cman);
253 }
254
255 /**
256  * mono_code_manager_invalidate:
257  * @cman: a code manager
258  *
259  * Fill all the memory with an invalid native code value
260  * so that any attempt to execute code allocated in the code
261  * manager @cman will fail. This is used for debugging purposes.
262  */
263 void             
264 mono_code_manager_invalidate (MonoCodeManager *cman)
265 {
266         CodeChunk *chunk;
267
268 #if defined(__i386__) || defined(__x86_64__)
269         int fill_value = 0xcc; /* x86 break */
270 #else
271         int fill_value = 0x2a;
272 #endif
273
274         for (chunk = cman->current; chunk; chunk = chunk->next)
275                 memset (chunk->data, fill_value, chunk->size);
276         for (chunk = cman->full; chunk; chunk = chunk->next)
277                 memset (chunk->data, fill_value, chunk->size);
278 }
279
280 /**
281  * mono_code_manager_set_read_only:
282  * @cman: a code manager
283  *
284  * Make the code manager read only, so further allocation requests cause an assert.
285  */
286 void             
287 mono_code_manager_set_read_only (MonoCodeManager *cman)
288 {
289         cman->read_only = TRUE;
290 }
291
292 /**
293  * mono_code_manager_foreach:
294  * @cman: a code manager
295  * @func: a callback function pointer
296  * @user_data: additional data to pass to @func
297  *
298  * Invokes the callback @func for each different chunk of memory allocated
299  * in the code manager @cman.
300  */
301 void
302 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
303 {
304         CodeChunk *chunk;
305         for (chunk = cman->current; chunk; chunk = chunk->next) {
306                 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
307                         return;
308         }
309         for (chunk = cman->full; chunk; chunk = chunk->next) {
310                 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
311                         return;
312         }
313 }
314
315 /* BIND_ROOM is the divisor for the chunck of code size dedicated
316  * to binding branches (branches not reachable with the immediate displacement)
317  * bind_size = size/BIND_ROOM;
318  * we should reduce it and make MIN_PAGES bigger for such systems
319  */
320 #if defined(__ppc__) || defined(__powerpc__)
321 #define BIND_ROOM 4
322 #endif
323 #if defined(TARGET_ARM64)
324 #define BIND_ROOM 4
325 #endif
326
327 static CodeChunk*
328 new_codechunk (CodeChunk *last, int dynamic, int size)
329 {
330         int minsize, flags = CODE_FLAG_MMAP;
331         int chunk_size, bsize = 0;
332         int pagesize;
333         CodeChunk *chunk;
334         void *ptr;
335
336 #ifdef FORCE_MALLOC
337         flags = CODE_FLAG_MALLOC;
338 #endif
339
340         pagesize = mono_pagesize ();
341
342         if (dynamic) {
343                 chunk_size = size;
344                 flags = CODE_FLAG_MALLOC;
345         } else {
346                 minsize = pagesize * MIN_PAGES;
347                 if (size < minsize)
348                         chunk_size = minsize;
349                 else {
350                         /* Allocate MIN_ALIGN-1 more than we need so we can still */
351                         /* guarantee MIN_ALIGN alignment for individual allocs    */
352                         /* from mono_code_manager_reserve_align.                  */
353                         size += MIN_ALIGN - 1;
354                         size &= ~(MIN_ALIGN - 1);
355                         chunk_size = size;
356                         chunk_size += pagesize - 1;
357                         chunk_size &= ~ (pagesize - 1);
358                 }
359         }
360 #ifdef BIND_ROOM
361         if (dynamic)
362                 /* Reserve more space since there are no other chunks we might use if this one gets full */
363                 bsize = (chunk_size * 2) / BIND_ROOM;
364         else
365                 bsize = chunk_size / BIND_ROOM;
366         if (bsize < MIN_BSIZE)
367                 bsize = MIN_BSIZE;
368         bsize += MIN_ALIGN -1;
369         bsize &= ~ (MIN_ALIGN - 1);
370         if (chunk_size - size < bsize) {
371                 chunk_size = size + bsize;
372                 if (!dynamic) {
373                         chunk_size += pagesize - 1;
374                         chunk_size &= ~ (pagesize - 1);
375                 }
376         }
377 #endif
378
379         if (flags == CODE_FLAG_MALLOC) {
380                 ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
381                 if (!ptr)
382                         return NULL;
383         } else {
384                 /* Try to allocate code chunks next to each other to help the VM */
385                 ptr = NULL;
386                 if (last)
387                         ptr = codechunk_valloc ((guint8*)last->data + last->size, chunk_size);
388                 if (!ptr)
389                         ptr = codechunk_valloc (NULL, chunk_size);
390                 if (!ptr)
391                         return NULL;
392         }
393
394         if (flags == CODE_FLAG_MALLOC) {
395 #ifdef BIND_ROOM
396                 /* Make sure the thunks area is zeroed */
397                 memset (ptr, 0, bsize);
398 #endif
399         }
400
401         chunk = (CodeChunk *) malloc (sizeof (CodeChunk));
402         if (!chunk) {
403                 if (flags == CODE_FLAG_MALLOC)
404                         dlfree (ptr);
405                 else
406                         mono_vfree (ptr, chunk_size);
407                 return NULL;
408         }
409         chunk->next = NULL;
410         chunk->size = chunk_size;
411         chunk->data = (char *) ptr;
412         chunk->flags = flags;
413         chunk->pos = bsize;
414         chunk->bsize = bsize;
415         mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size);
416
417         code_memory_used += chunk_size;
418         mono_runtime_resource_check_limit (MONO_RESOURCE_JIT_CODE, code_memory_used);
419         /*printf ("code chunk at: %p\n", ptr);*/
420         return chunk;
421 }
422
423 /**
424  * mono_code_manager_reserve:
425  * @cman: a code manager
426  * @size: size of memory to allocate
427  * @alignment: power of two alignment value
428  *
429  * Allocates at least @size bytes of memory inside the code manager @cman.
430  *
431  * Returns: the pointer to the allocated memory or #NULL on failure
432  */
433 void*
434 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
435 {
436         CodeChunk *chunk, *prev;
437         void *ptr;
438         guint32 align_mask = alignment - 1;
439
440         g_assert (!cman->read_only);
441
442         /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
443          * handle this before
444          */
445         g_assert (alignment <= MIN_ALIGN);
446
447         if (cman->dynamic) {
448                 ++dynamic_code_alloc_count;
449                 dynamic_code_bytes_count += size;
450         }
451
452         if (!cman->current) {
453                 cman->current = new_codechunk (cman->last, cman->dynamic, size);
454                 if (!cman->current)
455                         return NULL;
456                 cman->last = cman->current;
457         }
458
459         for (chunk = cman->current; chunk; chunk = chunk->next) {
460                 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
461                         chunk->pos = ALIGN_INT (chunk->pos, alignment);
462                         /* Align the chunk->data we add to chunk->pos */
463                         /* or we can't guarantee proper alignment     */
464                         ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
465                         chunk->pos = ((char*)ptr - chunk->data) + size;
466                         return ptr;
467                 }
468         }
469         /* 
470          * no room found, move one filled chunk to cman->full 
471          * to keep cman->current from growing too much
472          */
473         prev = NULL;
474         for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
475                 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
476                         continue;
477                 if (prev) {
478                         prev->next = chunk->next;
479                 } else {
480                         cman->current = chunk->next;
481                 }
482                 chunk->next = cman->full;
483                 cman->full = chunk;
484                 break;
485         }
486         chunk = new_codechunk (cman->last, cman->dynamic, size);
487         if (!chunk)
488                 return NULL;
489         chunk->next = cman->current;
490         cman->current = chunk;
491         cman->last = cman->current;
492         chunk->pos = ALIGN_INT (chunk->pos, alignment);
493         /* Align the chunk->data we add to chunk->pos */
494         /* or we can't guarantee proper alignment     */
495         ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
496         chunk->pos = ((char*)ptr - chunk->data) + size;
497         return ptr;
498 }
499
500 /**
501  * mono_code_manager_reserve:
502  * @cman: a code manager
503  * @size: size of memory to allocate
504  *
505  * Allocates at least @size bytes of memory inside the code manager @cman.
506  *
507  * Returns: the pointer to the allocated memory or #NULL on failure
508  */
509 void*
510 mono_code_manager_reserve (MonoCodeManager *cman, int size)
511 {
512         return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
513 }
514
515 /**
516  * mono_code_manager_commit:
517  * @cman: a code manager
518  * @data: the pointer returned by mono_code_manager_reserve ()
519  * @size: the size requested in the call to mono_code_manager_reserve ()
520  * @newsize: the new size to reserve
521  *
522  * If we reserved too much room for a method and we didn't allocate
523  * already from the code manager, we can get back the excess allocation
524  * for later use in the code manager.
525  */
526 void
527 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
528 {
529         g_assert (newsize <= size);
530
531         if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
532                 cman->current->pos -= size - newsize;
533         }
534 }
535
536 /**
537  * mono_code_manager_size:
538  * @cman: a code manager
539  * @used_size: pointer to an integer for the result
540  *
541  * This function can be used to get statistics about a code manager:
542  * the integer pointed to by @used_size will contain how much
543  * memory is actually used inside the code managed @cman.
544  *
545  * Returns: the amount of memory allocated in @cman
546  */
547 int
548 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
549 {
550         CodeChunk *chunk;
551         guint32 size = 0;
552         guint32 used = 0;
553         for (chunk = cman->current; chunk; chunk = chunk->next) {
554                 size += chunk->size;
555                 used += chunk->pos;
556         }
557         for (chunk = cman->full; chunk; chunk = chunk->next) {
558                 size += chunk->size;
559                 used += chunk->pos;
560         }
561         if (used_size)
562                 *used_size = used;
563         return size;
564 }