Making sure mono_marshal_free is used instead of g_free in mono_string_builder_to_utf8
[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-os-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_os_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_os_mutex_lock (&valloc_mutex);
254         freelist = (GSList *) 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_os_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_os_mutex_lock (&valloc_mutex);
275         freelist = (GSList *) 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_os_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 = (GSList *) 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 = (MonoCodeManager *) 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(TARGET_ARM64)
492 #define BIND_ROOM 4
493 #endif
494
495 static CodeChunk*
496 new_codechunk (CodeChunk *last, int dynamic, int size)
497 {
498         int minsize, flags = CODE_FLAG_MMAP;
499         int chunk_size, bsize = 0;
500         int pagesize;
501         CodeChunk *chunk;
502         void *ptr;
503
504 #ifdef FORCE_MALLOC
505         flags = CODE_FLAG_MALLOC;
506 #endif
507
508         pagesize = mono_pagesize ();
509
510         if (dynamic) {
511                 chunk_size = size;
512                 flags = CODE_FLAG_MALLOC;
513         } else {
514                 minsize = pagesize * MIN_PAGES;
515                 if (size < minsize)
516                         chunk_size = minsize;
517                 else {
518                         /* Allocate MIN_ALIGN-1 more than we need so we can still */
519                         /* guarantee MIN_ALIGN alignment for individual allocs    */
520                         /* from mono_code_manager_reserve_align.                  */
521                         size += MIN_ALIGN - 1;
522                         size &= ~(MIN_ALIGN - 1);
523                         chunk_size = size;
524                         chunk_size += pagesize - 1;
525                         chunk_size &= ~ (pagesize - 1);
526                 }
527         }
528 #ifdef BIND_ROOM
529         if (dynamic)
530                 /* Reserve more space since there are no other chunks we might use if this one gets full */
531                 bsize = (chunk_size * 2) / BIND_ROOM;
532         else
533                 bsize = chunk_size / BIND_ROOM;
534         if (bsize < MIN_BSIZE)
535                 bsize = MIN_BSIZE;
536         bsize += MIN_ALIGN -1;
537         bsize &= ~ (MIN_ALIGN - 1);
538         if (chunk_size - size < bsize) {
539                 chunk_size = size + bsize;
540                 if (!dynamic) {
541                         chunk_size += pagesize - 1;
542                         chunk_size &= ~ (pagesize - 1);
543                 }
544         }
545 #endif
546
547         if (flags == CODE_FLAG_MALLOC) {
548                 ptr = dlmemalign (MIN_ALIGN, chunk_size + MIN_ALIGN - 1);
549                 if (!ptr)
550                         return NULL;
551         } else {
552                 /* Try to allocate code chunks next to each other to help the VM */
553                 ptr = NULL;
554                 if (last)
555                         ptr = codechunk_valloc ((guint8*)last->data + last->size, chunk_size);
556                 if (!ptr)
557                         ptr = codechunk_valloc (NULL, chunk_size);
558                 if (!ptr)
559                         return NULL;
560         }
561
562         if (flags == CODE_FLAG_MALLOC) {
563 #ifdef BIND_ROOM
564                 /* Make sure the thunks area is zeroed */
565                 memset (ptr, 0, bsize);
566 #endif
567         }
568
569         chunk = (CodeChunk *) malloc (sizeof (CodeChunk));
570         if (!chunk) {
571                 if (flags == CODE_FLAG_MALLOC)
572                         dlfree (ptr);
573                 else
574                         mono_vfree (ptr, chunk_size);
575                 return NULL;
576         }
577         chunk->next = NULL;
578         chunk->size = chunk_size;
579         chunk->data = (char *) ptr;
580         chunk->flags = flags;
581         chunk->pos = bsize;
582         chunk->bsize = bsize;
583         mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size);
584
585         code_memory_used += chunk_size;
586         mono_runtime_resource_check_limit (MONO_RESOURCE_JIT_CODE, code_memory_used);
587         /*printf ("code chunk at: %p\n", ptr);*/
588         return chunk;
589 }
590
591 /**
592  * mono_code_manager_reserve:
593  * @cman: a code manager
594  * @size: size of memory to allocate
595  * @alignment: power of two alignment value
596  *
597  * Allocates at least @size bytes of memory inside the code manager @cman.
598  *
599  * Returns: the pointer to the allocated memory or #NULL on failure
600  */
601 void*
602 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
603 {
604 #if !defined(__native_client__) || !defined(__native_client_codegen__)
605         CodeChunk *chunk, *prev;
606         void *ptr;
607         guint32 align_mask = alignment - 1;
608
609         g_assert (!cman->read_only);
610
611         /* eventually allow bigger alignments, but we need to fix the dynamic alloc code to
612          * handle this before
613          */
614         g_assert (alignment <= MIN_ALIGN);
615
616         if (cman->dynamic) {
617                 ++dynamic_code_alloc_count;
618                 dynamic_code_bytes_count += size;
619         }
620
621         if (!cman->current) {
622                 cman->current = new_codechunk (cman->last, cman->dynamic, size);
623                 if (!cman->current)
624                         return NULL;
625                 cman->last = cman->current;
626         }
627
628         for (chunk = cman->current; chunk; chunk = chunk->next) {
629                 if (ALIGN_INT (chunk->pos, alignment) + size <= chunk->size) {
630                         chunk->pos = ALIGN_INT (chunk->pos, alignment);
631                         /* Align the chunk->data we add to chunk->pos */
632                         /* or we can't guarantee proper alignment     */
633                         ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
634                         chunk->pos = ((char*)ptr - chunk->data) + size;
635                         return ptr;
636                 }
637         }
638         /* 
639          * no room found, move one filled chunk to cman->full 
640          * to keep cman->current from growing too much
641          */
642         prev = NULL;
643         for (chunk = cman->current; chunk; prev = chunk, chunk = chunk->next) {
644                 if (chunk->pos + MIN_ALIGN * 4 <= chunk->size)
645                         continue;
646                 if (prev) {
647                         prev->next = chunk->next;
648                 } else {
649                         cman->current = chunk->next;
650                 }
651                 chunk->next = cman->full;
652                 cman->full = chunk;
653                 break;
654         }
655         chunk = new_codechunk (cman->last, cman->dynamic, size);
656         if (!chunk)
657                 return NULL;
658         chunk->next = cman->current;
659         cman->current = chunk;
660         cman->last = cman->current;
661         chunk->pos = ALIGN_INT (chunk->pos, alignment);
662         /* Align the chunk->data we add to chunk->pos */
663         /* or we can't guarantee proper alignment     */
664         ptr = (void*)((((uintptr_t)chunk->data + align_mask) & ~(uintptr_t)align_mask) + chunk->pos);
665         chunk->pos = ((char*)ptr - chunk->data) + size;
666         return ptr;
667 #else
668         unsigned char *temp_ptr, *code_ptr;
669         /* Round up size to next bundle */
670         alignment = kNaClBundleSize;
671         size = (size + kNaClBundleSize) & (~kNaClBundleMask);
672         /* Allocate a temp buffer */
673         temp_ptr = memalign (alignment, size);
674         g_assert (((uintptr_t)temp_ptr & kNaClBundleMask) == 0);
675         /* Allocate code space from the service runtime */
676         code_ptr = allocate_code (size);
677         /* Insert pointer to code space in hash, keyed by buffer ptr */
678         g_hash_table_insert (cman->hash, temp_ptr, code_ptr);
679
680 #ifndef USE_JUMP_TABLES
681         nacl_jit_check_init ();
682
683         patch_current_depth++;
684         patch_source_base[patch_current_depth] = temp_ptr;
685         patch_dest_base[patch_current_depth] = code_ptr;
686         patch_alloc_size[patch_current_depth] = size;
687         g_assert (patch_current_depth < kMaxPatchDepth);
688 #endif
689
690         return temp_ptr;
691 #endif
692 }
693
694 /**
695  * mono_code_manager_reserve:
696  * @cman: a code manager
697  * @size: size of memory to allocate
698  *
699  * Allocates at least @size bytes of memory inside the code manager @cman.
700  *
701  * Returns: the pointer to the allocated memory or #NULL on failure
702  */
703 void*
704 mono_code_manager_reserve (MonoCodeManager *cman, int size)
705 {
706         return mono_code_manager_reserve_align (cman, size, MIN_ALIGN);
707 }
708
709 /**
710  * mono_code_manager_commit:
711  * @cman: a code manager
712  * @data: the pointer returned by mono_code_manager_reserve ()
713  * @size: the size requested in the call to mono_code_manager_reserve ()
714  * @newsize: the new size to reserve
715  *
716  * If we reserved too much room for a method and we didn't allocate
717  * already from the code manager, we can get back the excess allocation
718  * for later use in the code manager.
719  */
720 void
721 mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsize)
722 {
723 #if !defined(__native_client__) || !defined(__native_client_codegen__)
724         g_assert (newsize <= size);
725
726         if (cman->current && (size != newsize) && (data == cman->current->data + cman->current->pos - size)) {
727                 cman->current->pos -= size - newsize;
728         }
729 #else
730         unsigned char *code;
731         int status;
732         g_assert (NACL_BUNDLE_ALIGN_UP(newsize) <= size);
733         code = g_hash_table_lookup (cman->hash, data);
734         g_assert (code != NULL);
735         mono_nacl_fill_code_buffer ((uint8_t*)data + newsize, size - newsize);
736         newsize = NACL_BUNDLE_ALIGN_UP(newsize);
737         g_assert ((GPOINTER_TO_UINT (data) & kNaClBundleMask) == 0);
738         g_assert ((newsize & kNaClBundleMask) == 0);
739         status = nacl_dyncode_create (code, data, newsize);
740         if (status != 0) {
741                 unsigned char *codep;
742                 fprintf(stderr, "Error creating Native Client dynamic code section attempted to be\n"
743                                 "emitted at %p (hex dissasembly of code follows):\n", code);
744                 for (codep = data; codep < data + newsize; codep++)
745                         fprintf(stderr, "%02x ", *codep);
746                 fprintf(stderr, "\n");
747                 g_assert_not_reached ();
748         }
749         g_hash_table_remove (cman->hash, data);
750 # ifndef USE_JUMP_TABLES
751         g_assert (data == patch_source_base[patch_current_depth]);
752         g_assert (code == patch_dest_base[patch_current_depth]);
753         patch_current_depth--;
754         g_assert (patch_current_depth >= -1);
755 # endif
756         free (data);
757 #endif
758 }
759
760 #if defined(__native_client_codegen__) && defined(__native_client__)
761 void *
762 nacl_code_manager_get_code_dest (MonoCodeManager *cman, void *data)
763 {
764         return g_hash_table_lookup (cman->hash, data);
765 }
766 #endif
767
768 /**
769  * mono_code_manager_size:
770  * @cman: a code manager
771  * @used_size: pointer to an integer for the result
772  *
773  * This function can be used to get statistics about a code manager:
774  * the integer pointed to by @used_size will contain how much
775  * memory is actually used inside the code managed @cman.
776  *
777  * Returns: the amount of memory allocated in @cman
778  */
779 int
780 mono_code_manager_size (MonoCodeManager *cman, int *used_size)
781 {
782         CodeChunk *chunk;
783         guint32 size = 0;
784         guint32 used = 0;
785         for (chunk = cman->current; chunk; chunk = chunk->next) {
786                 size += chunk->size;
787                 used += chunk->pos;
788         }
789         for (chunk = cman->full; chunk; chunk = chunk->next) {
790                 size += chunk->size;
791                 used += chunk->pos;
792         }
793         if (used_size)
794                 *used_size = used;
795         return size;
796 }
797
798 #ifdef __native_client_codegen__
799 # if defined(TARGET_ARM)
800 /* Fill empty space with UDF instruction used as halt on ARM. */
801 void
802 mono_nacl_fill_code_buffer (guint8 *data, int size)
803 {
804         guint32* data32 = (guint32*)data;
805         int i;
806         g_assert(size % 4 == 0);
807         for (i = 0; i < size / 4; i++)
808                 data32[i] = 0xE7FEDEFF;
809 }
810 # elif (defined(TARGET_X86) || defined(TARGET_AMD64))
811 /* Fill empty space with HLT instruction */
812 void
813 mono_nacl_fill_code_buffer(guint8 *data, int size)
814 {
815         memset (data, 0xf4, size);
816 }
817 # else
818 #  error "Not ported"
819 # endif
820 #endif