Check for missing Assembly.Location
[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 #if defined(__native_client_codegen__) && defined(__native_client__)
25 #include <malloc.h>
26 #include <nacl/nacl_dyncode.h>
27 #include <mono/mini/mini.h>
28 #endif
29 #include <mono/utils/mono-mutex.h>
30
31
32 static uintptr_t code_memory_used = 0;
33 static size_t dynamic_code_alloc_count;
34 static size_t dynamic_code_bytes_count;
35 static size_t dynamic_code_frees_count;
36
37 /*
38  * AMD64 processors maintain icache coherency only for pages which are 
39  * marked executable. Also, windows DEP requires us to obtain executable memory from
40  * malloc when using dynamic code managers. The system malloc can't do this so we use a 
41  * slighly modified version of Doug Lea's Malloc package for this purpose:
42  * http://g.oswego.edu/dl/html/malloc.html
43  */
44
45 #define MIN_PAGES 16
46
47 #if defined(__ia64__) || defined(__x86_64__) || defined (_WIN64)
48 /*
49  * We require 16 byte alignment on amd64 so the fp literals embedded in the code are 
50  * properly aligned for SSE2.
51  */
52 #define MIN_ALIGN 16
53 #else
54 #define MIN_ALIGN 8
55 #endif
56 #ifdef __native_client_codegen__
57 /* For Google Native Client, all targets of indirect control flow need to    */
58 /* be aligned to bundle boundary. 16 bytes on ARM, 32 bytes on x86.
59  * MIN_ALIGN was updated to force alignment for calls from
60  * tramp-<arch>.c to mono_global_codeman_reserve()     */
61 /* and mono_domain_code_reserve().                                           */
62 #undef MIN_ALIGN
63 #define MIN_ALIGN kNaClBundleSize
64
65 #endif
66
67 /* if a chunk has less than this amount of free space it's considered full */
68 #define MAX_WASTAGE 32
69 #define MIN_BSIZE 32
70
71 #ifdef __x86_64__
72 #define ARCH_MAP_FLAGS MONO_MMAP_32BIT
73 #else
74 #define ARCH_MAP_FLAGS 0
75 #endif
76
77 #define MONO_PROT_RWX (MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC)
78
79 typedef struct _CodeChunck CodeChunk;
80
81 enum {
82         CODE_FLAG_MMAP,
83         CODE_FLAG_MALLOC
84 };
85
86 struct _CodeChunck {
87         char *data;
88         int pos;
89         int size;
90         CodeChunk *next;
91         unsigned int flags: 8;
92         /* this number of bytes is available to resolve addresses far in memory */
93         unsigned int bsize: 24;
94 };
95
96 struct _MonoCodeManager {
97         int dynamic;
98         int read_only;
99         CodeChunk *current;
100         CodeChunk *full;
101         CodeChunk *last;
102 #if defined(__native_client_codegen__) && defined(__native_client__)
103         GHashTable *hash;
104 #endif
105 };
106
107 #define ALIGN_INT(val,alignment) (((val) + (alignment - 1)) & ~(alignment - 1))
108
109 #if defined(__native_client_codegen__) && defined(__native_client__)
110 /* End of text segment, set by linker. 
111  * Dynamic text starts on the next allocated page.
112  */
113 extern char etext[];
114 char *next_dynamic_code_addr = NULL;
115
116 /*
117  * This routine gets the next available bundle aligned
118  * pointer in the dynamic code section.  It does not check
119  * for the section end, this error will be caught in the
120  * service runtime.
121  */
122 void*
123 allocate_code(intptr_t increment)
124 {
125         char *addr;
126         if (increment < 0) return NULL;
127         increment = increment & kNaClBundleMask ? (increment & ~kNaClBundleMask) + kNaClBundleSize : increment;
128         addr = next_dynamic_code_addr;
129         next_dynamic_code_addr += increment;
130         return addr;
131 }
132
133 int
134 nacl_is_code_address (void *target)
135 {
136         return (char *)target < next_dynamic_code_addr;
137 }
138
139 /* Fill code buffer with arch-specific NOPs. */
140 void
141 mono_nacl_fill_code_buffer (guint8 *data, int size);
142
143 #ifndef USE_JUMP_TABLES
144 const int kMaxPatchDepth = 32;
145 __thread unsigned char **patch_source_base = NULL;
146 __thread unsigned char **patch_dest_base = NULL;
147 __thread int *patch_alloc_size = NULL;
148 __thread int patch_current_depth = -1;
149 __thread int allow_target_modification = 1;
150
151 static void
152 nacl_jit_check_init ()
153 {
154         if (patch_source_base == NULL) {
155                 patch_source_base = g_malloc (kMaxPatchDepth * sizeof(unsigned char *));
156                 patch_dest_base = g_malloc (kMaxPatchDepth * sizeof(unsigned char *));
157                 patch_alloc_size = g_malloc (kMaxPatchDepth * sizeof(int));
158         }
159 }
160 #endif
161
162 void
163 nacl_allow_target_modification (int val)
164 {
165 #ifndef USE_JUMP_TABLES
166         allow_target_modification = val;
167 #endif /* USE_JUMP_TABLES */
168 }
169
170 /* Given a patch target, modify the target such that patching will work when
171  * the code is copied to the data section.
172  */
173 void*
174 nacl_modify_patch_target (unsigned char *target)
175 {
176         /*
177          * There's no need in patch tricks for jumptables,
178          * as we always patch same jumptable.
179          */
180 #ifndef USE_JUMP_TABLES
181         /* This seems like a bit of an ugly way to do this but the advantage
182          * is we don't have to worry about all the conditions in
183          * mono_resolve_patch_target, and it can be used by all the bare uses
184          * of <arch>_patch.
185          */
186         unsigned char *sb;
187         unsigned char *db;
188
189         if (!allow_target_modification) return target;
190
191         nacl_jit_check_init ();
192         sb = patch_source_base[patch_current_depth];
193         db = patch_dest_base[patch_current_depth];
194
195         if (target >= sb && (target < sb + patch_alloc_size[patch_current_depth])) {
196                 /* Do nothing.  target is in the section being generated.
197                  * no need to modify, the disp will be the same either way.
198                  */
199         } else {
200                 int target_offset = target - db;
201                 target = sb + target_offset;
202         }
203 #endif
204         return target;
205 }
206
207 void*
208 nacl_inverse_modify_patch_target (unsigned char *target)
209 {
210         /*
211          * There's no need in patch tricks for jumptables,
212          * as we always patch same jumptable.
213          */
214 #ifndef USE_JUMP_TABLES
215         unsigned char *sb;
216         unsigned char *db;
217         int target_offset;
218
219         if (!allow_target_modification) return target;
220
221         nacl_jit_check_init ();
222         sb = patch_source_base[patch_current_depth];
223         db = patch_dest_base[patch_current_depth];
224
225         target_offset = target - sb;
226         target = db + target_offset;
227 #endif
228         return target;
229 }
230
231
232 #endif /* __native_client_codegen && __native_client__ */
233
234 #define VALLOC_FREELIST_SIZE 16
235
236 static mono_mutex_t valloc_mutex;
237 static GHashTable *valloc_freelists;
238
239 static void*
240 codechunk_valloc (void *preferred, guint32 size)
241 {
242         void *ptr;
243         GSList *freelist;
244
245         if (!valloc_freelists) {
246                 mono_mutex_init_recursive (&valloc_mutex);
247                 valloc_freelists = g_hash_table_new (NULL, NULL);
248         }
249
250         /*
251          * Keep a small freelist of memory blocks to decrease pressure on the kernel memory subsystem to avoid #3321.
252          */
253         mono_mutex_lock (&valloc_mutex);
254         freelist = g_hash_table_lookup (valloc_freelists, GUINT_TO_POINTER (size));
255         if (freelist) {
256                 ptr = freelist->data;
257                 memset (ptr, 0, size);
258                 freelist = g_slist_delete_link (freelist, freelist);
259                 g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist);
260         } else {
261                 ptr = mono_valloc (preferred, size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
262                 if (!ptr && preferred)
263                         ptr = mono_valloc (NULL, size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
264         }
265         mono_mutex_unlock (&valloc_mutex);
266         return ptr;
267 }
268
269 static void
270 codechunk_vfree (void *ptr, guint32 size)
271 {
272         GSList *freelist;
273
274         mono_mutex_lock (&valloc_mutex);
275         freelist = g_hash_table_lookup (valloc_freelists, GUINT_TO_POINTER (size));
276         if (!freelist || g_slist_length (freelist) < VALLOC_FREELIST_SIZE) {
277                 freelist = g_slist_prepend (freelist, ptr);
278                 g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist);
279         } else {
280                 mono_vfree (ptr, size);
281         }
282         mono_mutex_unlock (&valloc_mutex);
283 }               
284
285 static void
286 codechunk_cleanup (void)
287 {
288         GHashTableIter iter;
289         gpointer key, value;
290
291         if (!valloc_freelists)
292                 return;
293         g_hash_table_iter_init (&iter, valloc_freelists);
294         while (g_hash_table_iter_next (&iter, &key, &value)) {
295                 GSList *freelist = value;
296                 GSList *l;
297
298                 for (l = freelist; l; l = l->next) {
299                         mono_vfree (l->data, GPOINTER_TO_UINT (key));
300                 }
301                 g_slist_free (freelist);
302         }
303         g_hash_table_destroy (valloc_freelists);
304 }
305
306 void
307 mono_code_manager_init (void)
308 {
309         mono_counters_register ("Dynamic code allocs", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_alloc_count);
310         mono_counters_register ("Dynamic code bytes", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_bytes_count);
311         mono_counters_register ("Dynamic code frees", MONO_COUNTER_JIT | MONO_COUNTER_ULONG, &dynamic_code_frees_count);
312 }
313
314 void
315 mono_code_manager_cleanup (void)
316 {
317         codechunk_cleanup ();
318 }
319
320 /**
321  * mono_code_manager_new:
322  *
323  * Creates a new code manager. A code manager can be used to allocate memory
324  * suitable for storing native code that can be later executed.
325  * A code manager allocates memory from the operating system in large chunks
326  * (typically 64KB in size) so that many methods can be allocated inside them
327  * close together, improving cache locality.
328  *
329  * Returns: the new code manager
330  */
331 MonoCodeManager* 
332 mono_code_manager_new (void)
333 {
334         MonoCodeManager *cman = g_malloc0 (sizeof (MonoCodeManager));
335         if (!cman)
336                 return NULL;
337 #if defined(__native_client_codegen__) && defined(__native_client__)
338         if (next_dynamic_code_addr == NULL) {
339                 const guint kPageMask = 0xFFFF; /* 64K pages */
340                 next_dynamic_code_addr = (uintptr_t)(etext + kPageMask) & ~kPageMask;
341 #if defined (__GLIBC__)
342                 /* TODO: For now, just jump 64MB ahead to avoid dynamic libraries. */
343                 next_dynamic_code_addr += (uintptr_t)0x4000000;
344 #else
345                 /* Workaround bug in service runtime, unable to allocate */
346                 /* from the first page in the dynamic code section.    */
347                 next_dynamic_code_addr += (uintptr_t)0x10000;
348 #endif
349         }
350         cman->hash =  g_hash_table_new (NULL, NULL);
351 # ifndef USE_JUMP_TABLES
352         if (patch_source_base == NULL) {
353                 patch_source_base = g_malloc (kMaxPatchDepth * sizeof(unsigned char *));
354                 patch_dest_base = g_malloc (kMaxPatchDepth * sizeof(unsigned char *));
355                 patch_alloc_size = g_malloc (kMaxPatchDepth * sizeof(int));
356         }
357 # endif
358 #endif
359         return cman;
360 }
361
362 /**
363  * mono_code_manager_new_dynamic:
364  *
365  * Creates a new code manager suitable for holding native code that can be
366  * used for single or small methods that need to be deallocated independently
367  * of other native code.
368  *
369  * Returns: the new code manager
370  */
371 MonoCodeManager* 
372 mono_code_manager_new_dynamic (void)
373 {
374         MonoCodeManager *cman = mono_code_manager_new ();
375         cman->dynamic = 1;
376         return cman;
377 }
378
379
380 static void
381 free_chunklist (CodeChunk *chunk)
382 {
383         CodeChunk *dead;
384         
385 #if defined(HAVE_VALGRIND_MEMCHECK_H) && defined (VALGRIND_JIT_UNREGISTER_MAP)
386         int valgrind_unregister = 0;
387         if (RUNNING_ON_VALGRIND)
388                 valgrind_unregister = 1;
389 #define valgrind_unregister(x) do { if (valgrind_unregister) { VALGRIND_JIT_UNREGISTER_MAP(NULL,x); } } while (0) 
390 #else
391 #define valgrind_unregister(x)
392 #endif
393
394         for (; chunk; ) {
395                 dead = chunk;
396                 mono_profiler_code_chunk_destroy ((gpointer) dead->data);
397                 chunk = chunk->next;
398                 if (dead->flags == CODE_FLAG_MMAP) {
399                         codechunk_vfree (dead->data, dead->size);
400                         /* valgrind_unregister(dead->data); */
401                 } else if (dead->flags == CODE_FLAG_MALLOC) {
402                         dlfree (dead->data);
403                 }
404                 code_memory_used -= dead->size;
405                 free (dead);
406         }
407 }
408
409 /**
410  * mono_code_manager_destroy:
411  * @cman: a code manager
412  *
413  * Free all the memory associated with the code manager @cman.
414  */
415 void
416 mono_code_manager_destroy (MonoCodeManager *cman)
417 {
418         free_chunklist (cman->full);
419         free_chunklist (cman->current);
420         free (cman);
421 }
422
423 /**
424  * mono_code_manager_invalidate:
425  * @cman: a code manager
426  *
427  * Fill all the memory with an invalid native code value
428  * so that any attempt to execute code allocated in the code
429  * manager @cman will fail. This is used for debugging purposes.
430  */
431 void             
432 mono_code_manager_invalidate (MonoCodeManager *cman)
433 {
434         CodeChunk *chunk;
435
436 #if defined(__i386__) || defined(__x86_64__)
437         int fill_value = 0xcc; /* x86 break */
438 #else
439         int fill_value = 0x2a;
440 #endif
441
442         for (chunk = cman->current; chunk; chunk = chunk->next)
443                 memset (chunk->data, fill_value, chunk->size);
444         for (chunk = cman->full; chunk; chunk = chunk->next)
445                 memset (chunk->data, fill_value, chunk->size);
446 }
447
448 /**
449  * mono_code_manager_set_read_only:
450  * @cman: a code manager
451  *
452  * Make the code manager read only, so further allocation requests cause an assert.
453  */
454 void             
455 mono_code_manager_set_read_only (MonoCodeManager *cman)
456 {
457         cman->read_only = TRUE;
458 }
459
460 /**
461  * mono_code_manager_foreach:
462  * @cman: a code manager
463  * @func: a callback function pointer
464  * @user_data: additional data to pass to @func
465  *
466  * Invokes the callback @func for each different chunk of memory allocated
467  * in the code manager @cman.
468  */
469 void
470 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
471 {
472         CodeChunk *chunk;
473         for (chunk = cman->current; chunk; chunk = chunk->next) {
474                 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
475                         return;
476         }
477         for (chunk = cman->full; chunk; chunk = chunk->next) {
478                 if (func (chunk->data, chunk->size, chunk->bsize, user_data))
479                         return;
480         }
481 }
482
483 /* BIND_ROOM is the divisor for the chunck of code size dedicated
484  * to binding branches (branches not reachable with the immediate displacement)
485  * bind_size = size/BIND_ROOM;
486  * we should reduce it and make MIN_PAGES bigger for such systems
487  */
488 #if defined(__ppc__) || defined(__powerpc__)
489 #define BIND_ROOM 4
490 #endif
491 #if defined(__arm__)
492 #define BIND_ROOM 8
493 #endif
494 #if defined(TARGET_ARM64)
495 #define BIND_ROOM 8
496 #endif
497
498 static CodeChunk*
499 new_codechunk (CodeChunk *last, int dynamic, int size)
500 {
501         int minsize, flags = CODE_FLAG_MMAP;
502         int chunk_size, bsize = 0;
503         int pagesize;
504         CodeChunk *chunk;
505         void *ptr;
506
507 #ifdef FORCE_MALLOC
508         flags = CODE_FLAG_MALLOC;
509 #endif
510
511         pagesize = mono_pagesize ();
512
513         if (dynamic) {
514                 chunk_size = size;
515                 flags = CODE_FLAG_MALLOC;
516         } else {
517                 minsize = pagesize * MIN_PAGES;
518                 if (size < minsize)
519                         chunk_size = minsize;
520                 else {
521                         /* Allocate MIN_ALIGN-1 more than we need so we can still */
522                         /* guarantee MIN_ALIGN alignment for individual allocs    */
523                         /* from mono_code_manager_reserve_align.                  */
524                         size += MIN_ALIGN - 1;
525                         size &= ~(MIN_ALIGN - 1);
526                         chunk_size = size;
527                         chunk_size += pagesize - 1;
528                         chunk_size &= ~ (pagesize - 1);
529                 }
530         }
531 #ifdef BIND_ROOM
532         if (dynamic)
533                 /* Reserve more space since there are no other chunks we might use if this one gets full */
534                 bsize = (chunk_size * 2) / BIND_ROOM;
535         else
536                 bsize = chunk_size / BIND_ROOM;
537         if (bsize < MIN_BSIZE)
538                 bsize = MIN_BSIZE;
539         bsize += MIN_ALIGN -1;
540         bsize &= ~ (MIN_ALIGN - 1);
541         if (chunk_size - size < bsize) {
542                 chunk_size = size + bsize;
543                 if (!dynamic) {
544                         chunk_size += pagesize - 1;
545                         chunk_size &= ~ (pagesize - 1);
546                 }
547         }
548 #endif
549
550         if (flags == CODE_FLAG_MALLOC) {
551                 ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
552                 if (!ptr)
553                         return NULL;
554         } else {
555                 /* Try to allocate code chunks next to each other to help the VM */
556                 ptr = NULL;
557                 if (last)
558                         ptr = codechunk_valloc ((guint8*)last->data + last->size, chunk_size);
559                 if (!ptr)
560                         ptr = codechunk_valloc (NULL, chunk_size);
561                 if (!ptr)
562                         return NULL;
563         }
564
565         if (flags == CODE_FLAG_MALLOC) {
566 #ifdef BIND_ROOM
567                 /* Make sure the thunks area is zeroed */
568                 memset (ptr, 0, bsize);
569 #endif
570         }
571
572         chunk = malloc (sizeof (CodeChunk));
573         if (!chunk) {
574                 if (flags == CODE_FLAG_MALLOC)
575                         dlfree (ptr);
576                 else
577                         mono_vfree (ptr, chunk_size);
578                 return NULL;
579         }
580         chunk->next = NULL;
581         chunk->size = chunk_size;
582         chunk->data = ptr;
583         chunk->flags = flags;
584         chunk->pos = bsize;
585         chunk->bsize = bsize;
586         mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size);
587
588         code_memory_used += chunk_size;
589         mono_runtime_resource_check_limit (MONO_RESOURCE_JIT_CODE, code_memory_used);
590         /*printf ("code chunk at: %p\n", ptr);*/
591         return chunk;
592 }
593
594 /**
595  * mono_code_manager_reserve:
596  * @cman: a code manager
597  * @size: size of memory to allocate
598  * @alignment: power of two alignment value
599  *
600  * Allocates at least @size bytes of memory inside the code manager @cman.
601  *
602  * Returns: the pointer to the allocated memory or #NULL on failure
603  */
604 void*
605 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
606 {
607 #if !defined(__native_client__) || !defined(__native_client_codegen__)
608         CodeChunk *chunk, *prev;
609         void *ptr;
610         guint32 align_mask = alignment - 1;
611
612         g_assert (!cman->read_only);
613
614         /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
615          * handle this before
616          */
617         g_assert (alignment <= MIN_ALIGN);
618
619         if (cman->dynamic) {
620                 ++dynamic_code_alloc_count;
621                 dynamic_code_bytes_count += size;
622         }
623
624         if (!cman->current) {
625                 cman->current = new_codechunk (cman->last, cman->dynamic, size);
626                 if (!cman->current)
627                         return NULL;
628                 cman->last = cman->current;
629         }
630
631         for (chunk = cman->current; chunk; chunk = chunk->next) {
632                 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
633                         chunk->pos = ALIGN_INT (chunk->pos, alignment);
634                         /* Align the chunk->data we add to chunk->pos */
635                         /* or we can't guarantee proper alignment     */
636                         ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
637                         chunk->pos = ((char*)ptr - chunk->data) + size;
638                         return ptr;
639                 }
640         }
641         /* 
642          * no room found, move one filled chunk to cman->full 
643          * to keep cman->current from growing too much
644          */
645         prev = NULL;
646         for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
647                 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
648                         continue;
649                 if (prev) {
650                         prev->next = chunk->next;
651                 } else {
652                         cman->current = chunk->next;
653                 }
654                 chunk->next = cman->full;
655                 cman->full = chunk;
656                 break;
657         }
658         chunk = new_codechunk (cman->last, cman->dynamic, size);
659         if (!chunk)
660                 return NULL;
661         chunk->next = cman->current;
662         cman->current = chunk;
663         cman->last = cman->current;
664         chunk->pos = ALIGN_INT (chunk->pos, alignment);
665         /* Align the chunk->data we add to chunk->pos */
666         /* or we can't guarantee proper alignment     */
667         ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
668         chunk->pos = ((char*)ptr - chunk->data) + size;
669         return ptr;
670 #else
671         unsigned char *temp_ptr, *code_ptr;
672         /* Round up size to next bundle */
673         alignment = kNaClBundleSize;
674         size = (size + kNaClBundleSize) & (~kNaClBundleMask);
675         /* Allocate a temp buffer */
676         temp_ptr = memalign (alignment, size);
677         g_assert (((uintptr_t)temp_ptr & kNaClBundleMask) == 0);
678         /* Allocate code space from the service runtime */
679         code_ptr = allocate_code (size);
680         /* Insert pointer to code space in hash, keyed by buffer ptr */
681         g_hash_table_insert (cman->hash, temp_ptr, code_ptr);
682
683 #ifndef USE_JUMP_TABLES
684         nacl_jit_check_init ();
685
686         patch_current_depth++;
687         patch_source_base[patch_current_depth] = temp_ptr;
688         patch_dest_base[patch_current_depth] = code_ptr;
689         patch_alloc_size[patch_current_depth] = size;
690         g_assert (patch_current_depth < kMaxPatchDepth);
691 #endif
692
693         return temp_ptr;
694 #endif
695 }
696
697 /**
698  * mono_code_manager_reserve:
699  * @cman: a code manager
700  * @size: size of memory to allocate
701  *
702  * Allocates at least @size bytes of memory inside the code manager @cman.
703  *
704  * Returns: the pointer to the allocated memory or #NULL on failure
705  */
706 void*
707 mono_code_manager_reserve (MonoCodeManager *cman, int size)
708 {
709         return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
710 }
711
712 /**
713  * mono_code_manager_commit:
714  * @cman: a code manager
715  * @data: the pointer returned by mono_code_manager_reserve ()
716  * @size: the size requested in the call to mono_code_manager_reserve ()
717  * @newsize: the new size to reserve
718  *
719  * If we reserved too much room for a method and we didn't allocate
720  * already from the code manager, we can get back the excess allocation
721  * for later use in the code manager.
722  */
723 void
724 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
725 {
726 #if !defined(__native_client__) || !defined(__native_client_codegen__)
727         g_assert (newsize <= size);
728
729         if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
730                 cman->current->pos -= size - newsize;
731         }
732 #else
733         unsigned char *code;
734         int status;
735         g_assert (NACL_BUNDLE_ALIGN_UP(newsize) <= size);
736         code = g_hash_table_lookup (cman->hash, data);
737         g_assert (code != NULL);
738         mono_nacl_fill_code_buffer ((uint8_t*)data + newsize, size - newsize);
739         newsize = NACL_BUNDLE_ALIGN_UP(newsize);
740         g_assert ((GPOINTER_TO_UINT (data) & kNaClBundleMask) == 0);
741         g_assert ((newsize & kNaClBundleMask) == 0);
742         status = nacl_dyncode_create (code, data, newsize);
743         if (status != 0) {
744                 unsigned char *codep;
745                 fprintf(stderr, "Error creating Native Client dynamic code section attempted to be\n"
746                                 "emitted at %p (hex dissasembly of code follows):\n", code);
747                 for (codep = data; codep < data + newsize; codep++)
748                         fprintf(stderr, "%02x ", *codep);
749                 fprintf(stderr, "\n");
750                 g_assert_not_reached ();
751         }
752         g_hash_table_remove (cman->hash, data);
753 # ifndef USE_JUMP_TABLES
754         g_assert (data == patch_source_base[patch_current_depth]);
755         g_assert (code == patch_dest_base[patch_current_depth]);
756         patch_current_depth--;
757         g_assert (patch_current_depth >= -1);
758 # endif
759         free (data);
760 #endif
761 }
762
763 #if defined(__native_client_codegen__) && defined(__native_client__)
764 void *
765 nacl_code_manager_get_code_dest (MonoCodeManager *cman, void *data)
766 {
767         return g_hash_table_lookup (cman->hash, data);
768 }
769 #endif
770
771 /**
772  * mono_code_manager_size:
773  * @cman: a code manager
774  * @used_size: pointer to an integer for the result
775  *
776  * This function can be used to get statistics about a code manager:
777  * the integer pointed to by @used_size will contain how much
778  * memory is actually used inside the code managed @cman.
779  *
780  * Returns: the amount of memory allocated in @cman
781  */
782 int
783 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
784 {
785         CodeChunk *chunk;
786         guint32 size = 0;
787         guint32 used = 0;
788         for (chunk = cman->current; chunk; chunk = chunk->next) {
789                 size += chunk->size;
790                 used += chunk->pos;
791         }
792         for (chunk = cman->full; chunk; chunk = chunk->next) {
793                 size += chunk->size;
794                 used += chunk->pos;
795         }
796         if (used_size)
797                 *used_size = used;
798         return size;
799 }
800
801 #ifdef __native_client_codegen__
802 # if defined(TARGET_ARM)
803 /* Fill empty space with UDF instruction used as halt on ARM. */
804 void
805 mono_nacl_fill_code_buffer (guint8 *data, int size)
806 {
807         guint32* data32 = (guint32*)data;
808         int i;
809         g_assert(size % 4 == 0);
810         for (i = 0; i < size / 4; i++)
811                 data32[i] = 0xE7FEDEFF;
812 }
813 # elif (defined(TARGET_X86) || defined(TARGET_AMD64))
814 /* Fill empty space with HLT instruction */
815 void
816 mono_nacl_fill_code_buffer(guint8 *data, int size)
817 {
818         memset (data, 0xf4, size);
819 }
820 # else
821 #  error "Not ported"
822 # endif
823 #endif