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