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