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