12 #define USE_DL_PREFIX 1
14 #include "mono-codeman.h"
15 #include "mono-mmap.h"
16 #include "mono-counters.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>
24 #include <mono/utils/mono-os-mutex.h>
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;
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
42 #if defined(__ia64__) || defined(__x86_64__) || defined (_WIN64)
44 * We require 16 byte alignment on amd64 so the fp literals embedded in the code are
45 * properly aligned for SSE2.
52 /* if a chunk has less than this amount of free space it's considered full */
53 #define MAX_WASTAGE 32
57 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
59 #define ARCH_MAP_FLAGS 0
62 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
64 typedef struct _CodeChunck CodeChunk;
76 unsigned int flags: 8;
77 /* this number of bytes is available to resolve addresses far in memory */
78 unsigned int bsize: 24;
81 struct _MonoCodeManager {
89 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
91 #define VALLOC_FREELIST_SIZE 16
93 static mono_mutex_t valloc_mutex;
94 static GHashTable *valloc_freelists;
97 codechunk_valloc (void *preferred, guint32 size)
102 if (!valloc_freelists) {
103 mono_os_mutex_init_recursive (&valloc_mutex);
104 valloc_freelists = g_hash_table_new (NULL, NULL);
108 * Keep a small freelist of memory blocks to decrease pressure on the kernel memory subsystem to avoid #3321.
110 mono_os_mutex_lock (&valloc_mutex);
111 freelist = (GSList *) g_hash_table_lookup (valloc_freelists, GUINT_TO_POINTER (size));
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);
118 ptr = mono_valloc (preferred, size, MONO_PROT_RWX | ARCH_MAP_FLAGS, MONO_MEM_ACCOUNT_CODE);
119 if (!ptr && preferred)
120 ptr = mono_valloc (NULL, size, MONO_PROT_RWX | ARCH_MAP_FLAGS, MONO_MEM_ACCOUNT_CODE);
122 mono_os_mutex_unlock (&valloc_mutex);
127 codechunk_vfree (void *ptr, guint32 size)
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);
137 mono_vfree (ptr, size, MONO_MEM_ACCOUNT_CODE);
139 mono_os_mutex_unlock (&valloc_mutex);
143 codechunk_cleanup (void)
148 if (!valloc_freelists)
150 g_hash_table_iter_init (&iter, valloc_freelists);
151 while (g_hash_table_iter_next (&iter, &key, &value)) {
152 GSList *freelist = (GSList *) value;
155 for (l = freelist; l; l = l->next) {
156 mono_vfree (l->data, GPOINTER_TO_UINT (key), MONO_MEM_ACCOUNT_CODE);
158 g_slist_free (freelist);
160 g_hash_table_destroy (valloc_freelists);
164 mono_code_manager_init (void)
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);
172 mono_code_manager_cleanup (void)
174 codechunk_cleanup ();
178 * mono_code_manager_new:
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.
186 * Returns: the new code manager
189 mono_code_manager_new (void)
191 return (MonoCodeManager *) g_malloc0 (sizeof (MonoCodeManager));
195 * mono_code_manager_new_dynamic:
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.
201 * Returns: the new code manager
204 mono_code_manager_new_dynamic (void)
206 MonoCodeManager *cman = mono_code_manager_new ();
213 free_chunklist (CodeChunk *chunk)
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)
223 #define valgrind_unregister(x)
228 mono_profiler_code_chunk_destroy ((gpointer) dead->data);
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) {
236 code_memory_used -= dead->size;
242 * mono_code_manager_destroy:
243 * @cman: a code manager
245 * Free all the memory associated with the code manager @cman.
248 mono_code_manager_destroy (MonoCodeManager *cman)
250 free_chunklist (cman->full);
251 free_chunklist (cman->current);
256 * mono_code_manager_invalidate:
257 * @cman: a code manager
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.
264 mono_code_manager_invalidate (MonoCodeManager *cman)
268 #if defined(__i386__) || defined(__x86_64__)
269 int fill_value = 0xcc; /* x86 break */
271 int fill_value = 0x2a;
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);
281 * mono_code_manager_set_read_only:
282 * @cman: a code manager
284 * Make the code manager read only, so further allocation requests cause an assert.
287 mono_code_manager_set_read_only (MonoCodeManager *cman)
289 cman->read_only = TRUE;
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
298 * Invokes the callback @func for each different chunk of memory allocated
299 * in the code manager @cman.
302 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
305 for (chunk = cman->current; chunk; chunk = chunk->next) {
306 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
309 for (chunk = cman->full; chunk; chunk = chunk->next) {
310 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
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
320 #if defined(__ppc__) || defined(__powerpc__)
323 #if defined(TARGET_ARM64)
328 new_codechunk (CodeChunk *last, int dynamic, int size)
330 int minsize, flags = CODE_FLAG_MMAP;
331 int chunk_size, bsize = 0;
332 int pagesize, valloc_granule;
337 flags = CODE_FLAG_MALLOC;
340 pagesize = mono_pagesize ();
341 valloc_granule = mono_valloc_granule ();
345 flags = CODE_FLAG_MALLOC;
347 minsize = MAX (pagesize * MIN_PAGES, valloc_granule);
349 chunk_size = minsize;
351 /* Allocate MIN_ALIGN-1 more than we need so we can still */
352 /* guarantee MIN_ALIGN alignment for individual allocs */
353 /* from mono_code_manager_reserve_align. */
354 size += MIN_ALIGN - 1;
355 size &= ~(MIN_ALIGN - 1);
357 chunk_size += valloc_granule - 1;
358 chunk_size &= ~ (valloc_granule - 1);
363 /* Reserve more space since there are no other chunks we might use if this one gets full */
364 bsize = (chunk_size * 2) / BIND_ROOM;
366 bsize = chunk_size / BIND_ROOM;
367 if (bsize < MIN_BSIZE)
369 bsize += MIN_ALIGN -1;
370 bsize &= ~ (MIN_ALIGN - 1);
371 if (chunk_size - size < bsize) {
372 chunk_size = size + bsize;
374 chunk_size += valloc_granule - 1;
375 chunk_size &= ~ (valloc_granule - 1);
380 if (flags == CODE_FLAG_MALLOC) {
381 ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
385 /* Try to allocate code chunks next to each other to help the VM */
388 ptr = codechunk_valloc ((guint8*)last->data + last->size, chunk_size);
390 ptr = codechunk_valloc (NULL, chunk_size);
395 if (flags == CODE_FLAG_MALLOC) {
397 /* Make sure the thunks area is zeroed */
398 memset (ptr, 0, bsize);
402 chunk = (CodeChunk *) g_malloc (sizeof (CodeChunk));
404 if (flags == CODE_FLAG_MALLOC)
407 mono_vfree (ptr, chunk_size, MONO_MEM_ACCOUNT_CODE);
411 chunk->size = chunk_size;
412 chunk->data = (char *) ptr;
413 chunk->flags = flags;
415 chunk->bsize = bsize;
416 mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size);
418 code_memory_used += chunk_size;
419 mono_runtime_resource_check_limit (MONO_RESOURCE_JIT_CODE, code_memory_used);
420 /*printf ("code chunk at: %p\n", ptr);*/
425 * mono_code_manager_reserve:
426 * @cman: a code manager
427 * @size: size of memory to allocate
428 * @alignment: power of two alignment value
430 * Allocates at least @size bytes of memory inside the code manager @cman.
432 * Returns: the pointer to the allocated memory or #NULL on failure
435 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
437 CodeChunk *chunk, *prev;
439 guint32 align_mask = alignment - 1;
441 g_assert (!cman->read_only);
443 /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
446 g_assert (alignment <= MIN_ALIGN);
449 ++dynamic_code_alloc_count;
450 dynamic_code_bytes_count += size;
453 if (!cman->current) {
454 cman->current = new_codechunk (cman->last, cman->dynamic, size);
457 cman->last = cman->current;
460 for (chunk = cman->current; chunk; chunk = chunk->next) {
461 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
462 chunk->pos = ALIGN_INT (chunk->pos, alignment);
463 /* Align the chunk->data we add to chunk->pos */
464 /* or we can't guarantee proper alignment */
465 ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
466 chunk->pos = ((char*)ptr - chunk->data) + size;
471 * no room found, move one filled chunk to cman->full
472 * to keep cman->current from growing too much
475 for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
476 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
479 prev->next = chunk->next;
481 cman->current = chunk->next;
483 chunk->next = cman->full;
487 chunk = new_codechunk (cman->last, cman->dynamic, size);
490 chunk->next = cman->current;
491 cman->current = chunk;
492 cman->last = cman->current;
493 chunk->pos = ALIGN_INT (chunk->pos, alignment);
494 /* Align the chunk->data we add to chunk->pos */
495 /* or we can't guarantee proper alignment */
496 ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
497 chunk->pos = ((char*)ptr - chunk->data) + size;
502 * mono_code_manager_reserve:
503 * @cman: a code manager
504 * @size: size of memory to allocate
506 * Allocates at least @size bytes of memory inside the code manager @cman.
508 * Returns: the pointer to the allocated memory or #NULL on failure
511 mono_code_manager_reserve (MonoCodeManager *cman, int size)
513 return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
517 * mono_code_manager_commit:
518 * @cman: a code manager
519 * @data: the pointer returned by mono_code_manager_reserve ()
520 * @size: the size requested in the call to mono_code_manager_reserve ()
521 * @newsize: the new size to reserve
523 * If we reserved too much room for a method and we didn't allocate
524 * already from the code manager, we can get back the excess allocation
525 * for later use in the code manager.
528 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
530 g_assert (newsize <= size);
532 if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
533 cman->current->pos -= size - newsize;
538 * mono_code_manager_size:
539 * @cman: a code manager
540 * @used_size: pointer to an integer for the result
542 * This function can be used to get statistics about a code manager:
543 * the integer pointed to by @used_size will contain how much
544 * memory is actually used inside the code managed @cman.
546 * Returns: the amount of memory allocated in @cman
549 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
554 for (chunk = cman->current; chunk; chunk = chunk->next) {
558 for (chunk = cman->full; chunk; chunk = chunk->next) {