* Mono.Posix.dll.sources: Rename Mono.Posix to Mono.Unix.
[mono.git] / mono / mini / aot.c
1 /*
2  * aot.c: mono Ahead of Time compiler
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2002 Ximian, Inc.
8  */
9
10 #include "config.h"
11 #include <sys/types.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <string.h>
15 #ifndef PLATFORM_WIN32
16 #include <sys/mman.h>
17 #else
18 #include <windows.h>
19 #endif
20
21 #include <errno.h>
22 #include <sys/stat.h>
23 #include <limits.h>    /* for PAGESIZE */
24 #ifndef PAGESIZE
25 #define PAGESIZE 4096
26 #endif
27
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/class.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/tokentype.h>
32 #include <mono/metadata/appdomain.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/metadata-internals.h>
36 #include <mono/metadata/marshal.h>
37 #include <mono/utils/mono-logger.h>
38 #include <mono/os/gc_wrapper.h>
39
40 #include "mini.h"
41
42 #ifdef PLATFORM_WIN32
43 #define SHARED_EXT ".dll"
44 #elif defined(__ppc__) && defined(__MACH__)
45 #define SHARED_EXT ".dylib"
46 #else
47 #define SHARED_EXT ".so"
48 #endif
49
50 #if defined(sparc) || defined(__ppc__)
51 #define AS_STRING_DIRECTIVE ".asciz"
52 #else
53 /* GNU as */
54 #define AS_STRING_DIRECTIVE ".string"
55 #endif
56
57 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
58
59 typedef struct MonoAotMethod {
60         MonoJitInfo *info;
61         MonoJumpInfo *patch_info;
62         MonoDomain *domain;
63 } MonoAotMethod;
64
65 typedef struct MonoAotModule {
66         /* Optimization flags used to compile the module */
67         guint32 opts;
68         /* Maps MonoMethods to MonoAotMethodInfos */
69         MonoGHashTable *methods;
70         char **icall_table;
71         MonoImage **image_table;
72         guint32* methods_present_table;
73 } MonoAotModule;
74
75 typedef struct MonoAotCompile {
76         FILE *fp;
77         GHashTable *ref_hash;
78         GHashTable *icall_hash;
79         GPtrArray *icall_table;
80         GHashTable *image_hash;
81         GPtrArray *image_table;
82 } MonoAotCompile;
83
84 typedef struct MonoAotOptions {
85         char *outfile;
86 } MonoAotOptions;
87
88 static MonoGHashTable *aot_modules;
89
90 static CRITICAL_SECTION aot_mutex;
91
92 /*
93  * Disabling this will make a copy of the loaded code and use the copy instead 
94  * of the original. This will place the caller and the callee close to each 
95  * other in memory, possibly improving cache behavior. Since the original
96  * code is in copy-on-write memory, this will not increase the memory usage
97  * of the runtime.
98  */
99 static gboolean use_loaded_code = FALSE;
100
101 /*
102  * Whenever to AOT compile loaded assemblies on demand and store them in
103  * a cache under $HOME/.mono/aot-cache.
104  */
105 static gboolean use_aot_cache = FALSE;
106
107 /* For debugging */
108 static gint32 mono_last_aot_method = -1;
109
110 static MonoJitInfo*
111 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
112
113 static MonoClass*
114 decode_klass_info (MonoAotModule *module, guint32 *info, guint32 **out_info)
115 {
116         MonoImage *image;
117         MonoClass *klass;
118         guint32 token, rank;
119
120         image = module->image_table [info [0]];
121         token = info [1];
122         info += 2;
123         if (token) {
124                 klass = mono_class_get (image, token);
125         } else {
126                 token = info [0];
127                 rank = info [1];
128                 info += 2;
129                 klass = mono_class_get (image, token);
130                 g_assert (klass);
131                 klass = mono_array_class_get (klass, rank);
132         }
133         g_assert (klass);
134         mono_class_init (klass);
135
136         *out_info = info;
137         return klass;
138 }
139
140 static MonoClassField*
141 decode_field_info (MonoAotModule *module, guint32 *info, guint32 **out_info)
142 {
143         MonoClass *klass = decode_klass_info (module, info, &info);
144         guint32 token;
145
146         token = info [0];
147         info ++;
148         *out_info = info;
149
150         return mono_class_get_field (klass, token);
151 }
152
153 static void
154 create_cache_structure (void)
155 {
156         const char *home;
157         char *tmp;
158         int err;
159
160         home = g_get_home_dir ();
161         if (!home)
162                 return;
163
164         tmp = g_build_filename (home, ".mono", NULL);
165         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
166                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
167 #ifdef PLATFORM_WIN32
168                 err = mkdir (tmp);
169 #else
170                 err = mkdir (tmp, 0777);
171 #endif
172                 if (err) {
173                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
174                         g_free (tmp);
175                         return;
176                 }
177         }
178         g_free (tmp);
179         tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
180         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
181                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
182 #ifdef PLATFORM_WIN32
183                 err = mkdir (tmp);
184 #else
185                 err = mkdir (tmp, 0777);
186 #endif
187                 if (err) {
188                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
189                         g_free (tmp);
190                         return;
191                 }
192         }
193         g_free (tmp);
194 }
195
196 /*
197  * load_aot_module_from_cache:
198  *
199  *  Experimental code to AOT compile loaded assemblies on demand. 
200  *
201  * FIXME: 
202  * - Add environment variable MONO_AOT_CACHE_OPTIONS
203  * - Add options for controlling the cache size
204  * - Handle full cache by deleting old assemblies lru style
205  * - Add options for excluding assemblies during development
206  * - Maybe add a threshold after an assembly is AOT compiled
207  * - invoking a new mono process is a security risk
208  */
209 static GModule*
210 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
211 {
212         char *fname, *cmd, *tmp2;
213         const char *home;
214         GModule *module;
215         gboolean res;
216         gchar *out, *err;
217
218         *aot_name = NULL;
219
220         if (assembly->image->dynamic)
221                 return NULL;
222
223         create_cache_structure ();
224
225         home = g_get_home_dir ();
226
227         tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
228         fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
229         *aot_name = fname;
230         g_free (tmp2);
231
232         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
233         module = g_module_open (fname, G_MODULE_BIND_LAZY);     
234
235         if (!module) {
236                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
237
238                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
239
240                 /* FIXME: security */
241                 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
242
243                 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
244                 g_free (cmd);
245                 if (!res) {
246                         mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
247                         return NULL;
248                 }
249
250                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
251
252                 module = g_module_open (fname, G_MODULE_BIND_LAZY);     
253         }
254
255         return module;
256 }
257
258 static void
259 load_aot_module (MonoAssembly *assembly, gpointer user_data)
260 {
261         char *aot_name;
262         MonoAotModule *info;
263         gboolean usable = TRUE;
264         char *saved_guid = NULL;
265         char *aot_version = NULL;
266         char *opt_flags = NULL;
267
268         if (mono_compile_aot)
269                 return;
270                                                         
271         if (use_aot_cache)
272                 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
273         else {
274                 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
275
276                 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
277
278                 if (!assembly->aot_module) {
279                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
280                 }
281         }
282
283         if (!assembly->aot_module) {
284                 g_free (aot_name);
285                 return;
286         }
287
288         g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
289         g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
290         g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
291
292         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
293                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
294                 usable = FALSE;
295         }
296         else
297                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
298                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
299                         usable = FALSE;
300                 }
301
302         if (!usable) {
303                 g_free (aot_name);
304                 g_module_close (assembly->aot_module);
305                 assembly->aot_module = NULL;
306                 return;
307         }
308
309         /*
310          * It seems that MonoGHashTables are in the GC heap, so structures
311          * containing them must be in the GC heap as well :(
312          */
313 #ifdef HAVE_BOEHM_GC
314         info = GC_MALLOC (sizeof (MonoAotModule));
315 #else
316         info = g_new0 (MonoAotModule, 1);
317 #endif
318         info->methods = mono_g_hash_table_new (NULL, NULL);
319         sscanf (opt_flags, "%d", &info->opts);
320
321         /* Read image table */
322         {
323                 guint32 table_len, i;
324                 char *table = NULL;
325
326                 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
327                 g_assert (table);
328
329                 table_len = *(guint32*)table;
330                 table += sizeof (guint32);
331                 info->image_table = g_new0 (MonoImage*, table_len);
332                 for (i = 0; i < table_len; ++i) {
333                         info->image_table [i] = mono_image_loaded_by_guid (table);
334                         if (!info->image_table [i]) {
335                                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
336                                 mono_g_hash_table_destroy (info->methods);
337                                 g_free (info->image_table);
338 #ifndef HAVE_BOEHM_GC
339                                 g_free (info);
340 #endif
341                                 g_free (aot_name);
342                                 g_module_close (assembly->aot_module);
343                                 assembly->aot_module = NULL;
344                                 return;
345                         }
346                         table += strlen (table) + 1;
347                 }
348         }
349
350         /* Read icall table */
351         {
352                 guint32 table_len, i;
353                 char *table = NULL;
354
355                 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
356                 g_assert (table);
357
358                 table_len = *(guint32*)table;
359                 table += sizeof (guint32);
360                 info->icall_table = g_new0 (char*, table_len);
361                 for (i = 0; i < table_len; ++i) {
362                         info->icall_table [i] = table;
363                         table += strlen (table) + 1;
364                 }
365         }
366
367         /* Read methods present table */
368         g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
369         g_assert (info->methods_present_table);
370
371         EnterCriticalSection (&aot_mutex);
372         mono_g_hash_table_insert (aot_modules, assembly, info);
373         LeaveCriticalSection (&aot_mutex);
374
375         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
376 }
377
378 void
379 mono_aot_init (void)
380 {
381         InitializeCriticalSection (&aot_mutex);
382
383         MONO_GC_REGISTER_ROOT (aot_modules);
384         aot_modules = mono_g_hash_table_new (NULL, NULL);
385
386         mono_install_assembly_load_hook (load_aot_module, NULL);
387
388         if (getenv ("MONO_LASTAOT"))
389                 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
390         if (getenv ("MONO_AOT_CACHE"))
391                 use_aot_cache = TRUE;
392 }
393  
394 static MonoJitInfo *
395 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
396 {
397         MonoClass *klass = method->klass;
398         MonoAssembly *ass = klass->image->assembly;
399         GModule *module = ass->aot_module;
400         char method_label [256];
401         char info_label [256];
402         guint8 *code = NULL;
403         guint8 *info;
404         MonoAotModule *aot_module;
405         MonoAotMethod *minfo;
406         MonoJitInfo *jinfo;
407         MonoMethodHeader *header;
408         int i;
409
410         if (!module)
411                 return NULL;
412
413         if (!method->token)
414                 return NULL;
415
416         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
417                 return NULL;
418
419         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
420                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
421                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
422                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
423                 return NULL;
424         
425         header = mono_method_get_header (method);
426         
427         aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
428
429         g_assert (klass->inited);
430
431         minfo = mono_g_hash_table_lookup (aot_module->methods, method);
432         /* Can't use code from non-root domains since they can be unloaded */
433         if (minfo && (minfo->domain == mono_get_root_domain ())) {
434                 /* This method was already loaded in another appdomain */
435
436                 /* Duplicate jinfo */
437                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
438                 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
439                 if (jinfo->clauses) {
440                         jinfo->clauses = 
441                                 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
442                         memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
443                 }
444
445                 if (aot_module->opts & MONO_OPT_SHARED)
446                         /* Use the same method in the new appdomain */
447                         ;
448                 else if (!minfo->patch_info)
449                         /* Use the same method in the new appdomain */
450                         ;                       
451                 else {
452                         /* Create a copy of the original method and apply relocations */
453
454                         code = mono_code_manager_reserve (domain->code_mp, minfo->info->code_size);
455                         memcpy (code, minfo->info->code_start, minfo->info->code_size);
456
457                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + minfo->info->code_size);
458
459                         /* Do this outside the lock to avoid deadlocks */
460                         LeaveCriticalSection (&aot_mutex);
461                         mono_arch_patch_code (method, domain, code, minfo->patch_info, TRUE);
462                         EnterCriticalSection (&aot_mutex);
463                         mono_arch_flush_icache (code, minfo->info->code_size);
464
465                         /* Relocate jinfo */
466                         jinfo->code_start = code;
467                         if (jinfo->clauses) {
468                                 for (i = 0; i < header->num_clauses; ++i) {
469                                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
470                                         gint32 offset = code - (guint8*)minfo->info->code_start;
471
472                                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
473                                                 ei->data.filter = (guint8*)ei->data.filter + offset;
474                                         else
475                                                 ei->data.catch_class = header->clauses [i].data.catch_class;
476                                         ei->try_start = (guint8*)ei->try_start + offset;
477                                         ei->try_end = (guint8*)ei->try_end + offset;
478                                         ei->handler_start = (guint8*)ei->handler_start + offset;
479                                 }
480                         }
481                 }
482
483                 return jinfo;
484         }
485
486         /* Do a fast check to see whenever the method exists */
487         {
488                 guint32 index = mono_metadata_token_index (method->token) - 1;
489                 guint32 w;
490                 w = aot_module->methods_present_table [index / 32];
491                 if (! (w & (1 << (index % 32)))) {
492                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
493                         return NULL;
494                 }
495         }
496
497         sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
498
499         if (!g_module_symbol (module, method_label, (gpointer *)&code))
500                 return NULL;
501
502         sprintf (info_label, "%s_p", method_label);
503
504         if (!g_module_symbol (module, info_label, (gpointer *)&info))
505                 return NULL;
506
507         if (mono_last_aot_method != -1) {
508                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
509                                 return NULL;
510                 else
511                         if (mono_jit_stats.methods_aot == mono_last_aot_method)
512                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
513         }
514
515         return mono_aot_load_method (domain, aot_module, method, code, info);
516 }
517
518 static MonoJitInfo*
519 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
520 {
521         MonoClass *klass = method->klass;
522         MonoJumpInfo *patch_info = NULL;
523         guint code_len, used_int_regs, used_strings;
524         MonoAotMethod *minfo;
525         MonoJitInfo *jinfo;
526         MonoMethodHeader *header = mono_method_get_header (method);
527         GPtrArray *patches;
528         int i, pindex;
529
530         minfo = g_new0 (MonoAotMethod, 1);
531
532         minfo->domain = domain;
533         jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
534
535         code_len = *(guint32*)info;
536         info += 4;
537         used_int_regs = *(guint32*)info;
538         info += 4;
539
540         if (!use_loaded_code) {
541                 guint8 *code2;
542                 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
543                 memcpy (code2, code, code_len);
544                 mono_arch_flush_icache (code2, code_len);
545                 code = code2;
546         }
547
548         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
549
550         /* Exception table */
551         if (header->num_clauses) {
552                 jinfo->clauses = 
553                         mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
554                 jinfo->num_clauses = header->num_clauses;
555
556                 jinfo->exvar_offset = *(guint32*)info;
557                 info += 4;
558
559                 for (i = 0; i < header->num_clauses; ++i) {
560                         MonoExceptionClause *ec = &header->clauses [i];                         
561                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
562
563                         ei->flags = ec->flags;
564                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
565                                 ei->data.filter = code + *(guint32*)info;
566                         else
567                                 ei->data.catch_class = ec->data.catch_class;
568                         info += 4;
569                         ei->try_start = code + *(guint32*)info;
570                         info += 4;
571                         ei->try_end = code + *(guint32*)info;
572                         info += 4;
573                         ei->handler_start = code + *(guint32*)info;
574                         info += 4;
575                 }
576         }
577
578         if (aot_module->opts & MONO_OPT_SHARED) {
579                 used_strings = *(guint32*)info;
580                 info += 4;
581         }
582         else
583                 used_strings = 0;
584
585         for (i = 0; i < used_strings; i++) {
586                 guint token =  *(guint32*)info;
587                 info += 4;
588                 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
589         }
590
591         if (*info) {
592                 MonoMemPool *mp;
593                 MonoImage *image;
594                 guint8 *page_start;
595                 gpointer *table;
596                 int pages;
597                 int i, err;
598                 guint32 last_offset, buf_len;
599                 guint32 *info32;
600
601                 if (aot_module->opts & MONO_OPT_SHARED)
602                         mp = mono_mempool_new ();
603                 else
604                         mp = domain->mp;
605
606                 /* First load the type + offset table */
607                 last_offset = 0;
608                 patches = g_ptr_array_new ();
609                 while (*info) {
610                         MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
611
612                         guint8 b1, b2;
613
614                         b1 = *(guint8*)info;
615                         b2 = *((guint8*)info + 1);
616                         
617                         info += 2;
618
619                         ji->type = b1 >> 2;
620
621                         if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
622                                 info = ALIGN_PTR_TO (info, 4);
623                                 ji->ip.i = *(guint32*)info;
624                                 info += 4;
625                         }
626                         else
627                                 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
628
629                         ji->ip.i += last_offset;
630                         last_offset = ji->ip.i;
631                         //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
632
633                         ji->next = patch_info;
634                         patch_info = ji;
635
636                         g_ptr_array_add (patches, ji);
637                 }
638                 info ++;
639
640                 info = ALIGN_PTR_TO (info, sizeof (gpointer));
641
642                 info32 = (guint32*)info;
643
644                 /* Then load the other data */
645                 for (pindex = 0; pindex < patches->len; ++pindex) {
646                         MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
647
648                         switch (ji->type) {
649                         case MONO_PATCH_INFO_CLASS:
650                         case MONO_PATCH_INFO_IID:
651                         case MONO_PATCH_INFO_VTABLE:
652                         case MONO_PATCH_INFO_CLASS_INIT:
653                                 ji->data.klass = decode_klass_info (aot_module, info32, &info32);
654                                 break;
655                         case MONO_PATCH_INFO_IMAGE:
656                                 ji->data.image = aot_module->image_table [info32 [0]];
657                                 g_assert (ji->data.image);
658                                 info32 ++;
659                                 break;
660                         case MONO_PATCH_INFO_METHOD:
661                         case MONO_PATCH_INFO_METHODCONST:
662                         case MONO_PATCH_INFO_METHOD_JUMP: {
663                                 guint32 image_index, token;
664
665                                 image_index = info32 [0] >> 24;
666                                 token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff);
667
668                                 image = aot_module->image_table [image_index];
669                                 ji->data.method = mono_get_method (image, token, NULL);
670                                 g_assert (ji->data.method);
671                                 mono_class_init (ji->data.method->klass);
672                                 info32 ++;
673
674                                 break;
675                         }
676                         case MONO_PATCH_INFO_WRAPPER: {
677                                 guint32 wrapper_type;
678
679                                 wrapper_type = info32 [0];
680                                 info32 ++;
681
682                                 switch (wrapper_type) {
683                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
684                                         guint32 image_index, token;
685
686                                         image_index = info32 [0] >> 24;
687                                         token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff);
688
689                                         image = aot_module->image_table [image_index];
690                                         ji->data.method = mono_get_method (image, token, NULL);
691                                         g_assert (ji->data.method);
692                                         mono_class_init (ji->data.method->klass);
693
694                                         ji->type = MONO_PATCH_INFO_METHOD;
695                                         ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
696                                         info32 ++;
697                                         break;
698                                 }
699                                 case MONO_WRAPPER_PROXY_ISINST: {
700                                         MonoClass *klass = decode_klass_info (aot_module, info32, &info32);
701
702                                         ji->type = MONO_PATCH_INFO_METHODCONST;
703                                         ji->data.method = mono_marshal_get_proxy_cancast (klass);
704                                         break;
705                                 }
706                                 case MONO_WRAPPER_LDFLD:
707                                 case MONO_WRAPPER_STFLD: {
708                                         MonoClass *klass = decode_klass_info (aot_module, info32, &info32);
709
710                                         ji->type = MONO_PATCH_INFO_METHOD;
711                                         if (wrapper_type == MONO_WRAPPER_LDFLD)
712                                                 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
713                                         else
714                                                 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
715                                         break;
716                                 }
717                                 default:
718                                         g_assert_not_reached ();
719                                 }
720                                 break;
721                         }
722                         case MONO_PATCH_INFO_FIELD:
723                         case MONO_PATCH_INFO_SFLDA:
724                                 ji->data.field = decode_field_info (aot_module, info32, &info32);
725                                 break;
726                         case MONO_PATCH_INFO_INTERNAL_METHOD:
727                                 ji->data.name = aot_module->icall_table [info32 [0]];
728                                 g_assert (ji->data.name);
729                                 info32 ++;
730                                 //printf ("A: %s.\n", ji->data.name);
731                                 break;
732                         case MONO_PATCH_INFO_SWITCH:
733                                 ji->table_size = info32 [0];
734                                 table = g_new (gpointer, ji->table_size);
735                                 ji->data.target = table;
736                                 for (i = 0; i < ji->table_size; i++) {
737                                         table [i] = (gpointer)(gssize)info32 [i + 1];
738                                 }
739                                 info32 += (ji->table_size + 1);
740                                 break;
741                         case MONO_PATCH_INFO_R4:
742                                 ji->data.target = info32;
743                                 info32 ++;
744                                 break;
745                         case MONO_PATCH_INFO_R8:
746                                 info32 = ALIGN_PTR_TO (info32, 8);
747                                 ji->data.target = info32;
748                                 info32 += 2;
749                                 break;
750                         case MONO_PATCH_INFO_LDSTR:
751                         case MONO_PATCH_INFO_LDTOKEN:
752                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
753                                 image = aot_module->image_table [info32 [0]];
754                                 ji->data.token = mono_jump_info_token_new (mp, image, info32 [1]);
755                                 info32 += 2;
756                                 break;
757                         case MONO_PATCH_INFO_EXC_NAME:
758                                 ji->data.klass = decode_klass_info (aot_module, info32, &info32);
759                                 ji->data.name = ji->data.klass->name;
760                                 break;
761                         case MONO_PATCH_INFO_METHOD_REL:
762                                 ji->data.offset = info32 [0];
763                                 info32 ++;
764                                 break;
765                         default:
766                                 g_warning ("unhandled type %d", ji->type);
767                                 g_assert_not_reached ();
768                         }
769                 }
770
771                 info = (guint8*)info32;
772
773                 g_ptr_array_free (patches, TRUE);
774
775                 buf_len = *(guint32*)info;
776                 info += 4;
777                 mono_debug_add_aot_method (domain, method, code, info, buf_len);
778
779                 if (use_loaded_code) {
780                 /* disable write protection */
781 #ifndef PLATFORM_WIN32
782                         page_start = (char *) (((gssize) (code)) & ~ (PAGESIZE - 1));
783                         pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
784                         err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
785                         g_assert (err == 0);
786 #else
787                         {
788                                 DWORD oldp;
789                                 g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
790                         }
791 #endif
792                 }
793
794                 /* Do this outside the lock to avoid deadlocks */
795                 LeaveCriticalSection (&aot_mutex);
796                 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
797                 EnterCriticalSection (&aot_mutex);
798
799                 if (aot_module->opts & MONO_OPT_SHARED)
800                         /* No need to cache patches */
801                         mono_mempool_destroy (mp);
802                 else
803                         minfo->patch_info = patch_info;
804         }
805
806         mono_jit_stats.methods_aot++;
807
808         {
809                 jinfo->code_size = code_len;
810                 jinfo->used_regs = used_int_regs;
811                 jinfo->method = method;
812                 jinfo->code_start = code;
813                 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
814
815                 minfo->info = jinfo;
816                 mono_g_hash_table_insert (aot_module->methods, method, minfo);
817
818                 return jinfo;
819         }
820 }
821
822 MonoJitInfo*
823 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
824 {
825         MonoJitInfo *info;
826
827         EnterCriticalSection (&aot_mutex);
828         info = mono_aot_get_method_inner (domain, method);
829         LeaveCriticalSection (&aot_mutex);
830
831         /* Do this outside the lock */
832         if (info) {
833                 mono_jit_info_table_add (domain, info);
834                 return info;
835         }
836         else
837                 return NULL;
838 }
839
840 static void
841 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
842 {
843 #if defined(sparc)
844         /* For solaris as, GNU as should accept the same */
845         fprintf (fp, ".section \"%s\"\n", section_name);
846 #elif defined(__ppc__) && defined(__MACH__)
847         /* This needs to be made more precise on mach. */
848         fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
849 #else
850         fprintf (fp, "%s %d\n", section_name, subsection_index);
851 #endif
852 }
853
854 static void
855 emit_global (FILE *fp, const char *name)
856 {
857 #if defined(__ppc__) && defined(__MACH__)
858     // mach-o always uses a '_' prefix.
859         fprintf (fp, ".globl _%s\n", name);
860 #else
861         fprintf (fp, ".globl %s\n", name);
862 #endif
863 }
864
865 static void
866 emit_label (FILE *fp, const char *name)
867 {
868 #if defined(__ppc__) && defined(__MACH__)
869     // mach-o always uses a '_' prefix.
870         fprintf (fp, "_%s:\n", name);
871 #else
872         fprintf (fp, "%s:\n", name);
873 #endif
874 }
875
876 #if 0
877 static void
878 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
879 {
880         int i;
881
882         emit_section_change (fp, ".text", 1);
883
884         fprintf (fp, ".globl %s\n", name);
885         fprintf (fp, "\t.align %d\n", align);
886         fprintf (fp, "\t.type %s,#object\n", name);
887         fprintf (fp, "\t.size %s,%d\n", name, size);
888         fprintf (fp, "%s:\n", name);
889         for (i = 0; i < size; i++) { 
890                 fprintf (fp, ".byte %d\n", buf [i]);
891         }
892         
893 }
894 #endif
895
896 static void
897 write_string_symbol (FILE *fp, const char *name, const char *value)
898 {
899         emit_section_change (fp, ".text", 1);
900         emit_global(fp, name);
901         emit_label(fp, name);
902         fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
903 }
904
905 static guint32
906 mono_get_field_token (MonoClassField *field) 
907 {
908         MonoClass *klass = field->parent;
909         int i;
910
911         for (i = 0; i < klass->field.count; ++i) {
912                 if (field == &klass->fields [i])
913                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
914         }
915
916         g_assert_not_reached ();
917         return 0;
918 }
919
920 static guint32
921 get_image_index (MonoAotCompile *cfg, MonoImage *image)
922 {
923         guint32 index;
924
925         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
926         if (index)
927                 return index - 1;
928         else {
929                 index = g_hash_table_size (cfg->image_hash);
930                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
931                 g_ptr_array_add (cfg->image_table, image);
932                 return index;
933         }
934 }
935
936 static void
937 emit_klass_info (MonoAotCompile *cfg, MonoClass *klass)
938 {
939         fprintf (cfg->fp, "\t.long 0x%08x\n", get_image_index (cfg, klass->image));
940         fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
941         if (!klass->type_token) {
942                 /* Array class */
943                 g_assert (klass->rank > 0);
944                 g_assert (klass->element_class->type_token);
945                 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->element_class->type_token);
946                 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->rank);
947         }
948 }
949
950 static void
951 emit_field_info (MonoAotCompile *cfg, MonoClassField *field)
952 {
953         emit_klass_info (cfg, field->parent);
954         fprintf (cfg->fp, "\t.long 0x%08x\n", mono_get_field_token (field));
955 }
956
957 #if defined(__ppc__) && defined(__MACH__)
958 static int
959 ilog2(register int value)
960 {
961     int count = -1;
962     while (value & ~0xf) count += 4, value >>= 4;
963     while (value) count++, value >>= 1;
964     return count;
965 }
966 #endif
967
968 static void 
969 emit_alignment(FILE *fp, int size)
970 {
971 #if defined(__ppc__) && defined(__MACH__)
972         // the mach-o assembler specifies alignments as powers of 2.
973         fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
974 #elif defined(__powerpc__)
975         /* ignore on linux/ppc */
976 #else
977         fprintf (fp, "\t.align %d\n", size);
978 #endif
979 }
980
981 G_GNUC_UNUSED static void
982 emit_pointer (FILE *fp, const char *target)
983 {
984         emit_alignment (fp, sizeof (gpointer));
985 #if defined(__x86_64__)
986         fprintf (fp, "\t.quad %s\n", target);
987 #elif defined(sparc) && SIZEOF_VOID_P == 8
988         fprintf (fp, "\t.xword %s\n", target);
989 #else
990         fprintf (fp, "\t.long %s\n", target);
991 #endif
992 }
993
994 static gint
995 compare_patches (gconstpointer a, gconstpointer b)
996 {
997         int i, j;
998
999         i = (*(MonoJumpInfo**)a)->ip.i;
1000         j = (*(MonoJumpInfo**)b)->ip.i;
1001
1002         if (i < j)
1003                 return -1;
1004         else
1005                 if (i > j)
1006                         return 1;
1007         else
1008                 return 0;
1009 }
1010
1011 static void
1012 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
1013 {
1014         MonoMethod *method;
1015         GList *l;
1016         FILE *tmpfp;
1017         int i, j, k, pindex;
1018         guint8 *code, *mname, *mname_p;
1019         int func_alignment = 16;
1020         GPtrArray *patches;
1021         MonoJumpInfo *patch_info;
1022         MonoMethodHeader *header;
1023         guint32 last_offset;
1024
1025         tmpfp = acfg->fp;
1026         method = cfg->method;
1027         code = cfg->native_code;
1028         header = mono_method_get_header (method);
1029
1030         emit_section_change (tmpfp, ".text", 0);
1031         mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
1032         mname_p = g_strdup_printf ("%s_p", mname);
1033         emit_alignment(tmpfp, func_alignment);
1034         emit_global(tmpfp, mname);
1035 #if defined(sparc)
1036         fprintf (tmpfp, "\t.type %s,#function\n", mname);
1037 #elif !(defined(__ppc__) && defined(__MACH__))
1038         fprintf (tmpfp, "\t.type %s,@function\n", mname);
1039 #endif
1040         emit_label(tmpfp, mname);
1041
1042         for (i = 0; i < cfg->code_len; i++) 
1043                 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
1044
1045         emit_section_change (tmpfp, ".text", 1);
1046
1047         /* Sort relocations */
1048         patches = g_ptr_array_new ();
1049         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1050                 g_ptr_array_add (patches, patch_info);
1051         g_ptr_array_sort (patches, compare_patches);
1052
1053         emit_global (tmpfp, mname_p);
1054         emit_alignment (tmpfp, sizeof (gpointer));
1055         emit_label (tmpfp, mname_p);
1056
1057         fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
1058         fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
1059
1060         /* Exception table */
1061         if (header->num_clauses) {
1062                 MonoJitInfo *jinfo = cfg->jit_info;
1063
1064                 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
1065
1066                 for (k = 0; k < header->num_clauses; ++k) {
1067                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1068
1069                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1070                                 fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->data.filter - code));
1071                         else
1072                                 /* the class is loaded from the header: optimize away later */
1073                                 fprintf (tmpfp, "\t.long %d\n", 0);
1074
1075                         fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_start - code));
1076                         fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_end - code));
1077                         fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->handler_start - code));
1078                 }
1079         }
1080
1081         /* String table */
1082         if (cfg->opt & MONO_OPT_SHARED) {
1083                 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
1084                 for (l = cfg->ldstr_list; l; l = l->next) {
1085                         fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
1086                 }
1087         }
1088         else
1089                 /* Used only in shared mode */
1090                 g_assert (!cfg->ldstr_list);
1091
1092         //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
1093
1094         /* First emit the type+position table */
1095         last_offset = 0;
1096         j = 0;
1097         for (pindex = 0; pindex < patches->len; ++pindex) {
1098                 guint32 offset;
1099                 patch_info = g_ptr_array_index (patches, pindex);
1100                 
1101                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1102                         (patch_info->type == MONO_PATCH_INFO_BB))
1103                         /* Nothing to do */
1104                         continue;
1105
1106                 j ++;
1107                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1108                 offset = patch_info->ip.i - last_offset;
1109                 last_offset = patch_info->ip.i;
1110
1111                 /* Encode type+position compactly */
1112                 g_assert (patch_info->type < 64);
1113                 if (offset < 1024 - 1) {
1114                         fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
1115                         fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
1116                 }
1117                 else {
1118                         fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
1119                         fprintf (tmpfp, "\t.byte %d\n", 255);
1120                         emit_alignment(tmpfp, 4);
1121                         fprintf (tmpfp, "\t.long %d\n", offset);
1122                 }
1123         }
1124
1125         if (j) {
1126                 /*
1127                  * 0 is PATCH_INFO_BB, which can't be in the file.
1128                  */
1129                 /* NULL terminated array */
1130                 fprintf (tmpfp, "\t.byte 0\n");
1131
1132                 emit_alignment (tmpfp, sizeof (gpointer));
1133
1134                 /* Then emit the other info */
1135                 for (pindex = 0; pindex < patches->len; ++pindex) {
1136                         patch_info = g_ptr_array_index (patches, pindex);
1137
1138                         if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1139                                 (patch_info->type == MONO_PATCH_INFO_BB))
1140                                 /* Nothing to do */
1141                                 continue;
1142
1143                         switch (patch_info->type) {
1144                         case MONO_PATCH_INFO_LABEL:
1145                         case MONO_PATCH_INFO_BB:
1146                                 break;
1147                         case MONO_PATCH_INFO_IMAGE:
1148                                 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.image));
1149                                 break;
1150                         case MONO_PATCH_INFO_METHOD_REL:
1151                                 fprintf (tmpfp, "\t.long 0x%08x\n", (gint)patch_info->data.offset);
1152                                 break;
1153                         case MONO_PATCH_INFO_SWITCH: {
1154                                 gpointer *table = (gpointer *)patch_info->data.target;
1155                                 int k;
1156
1157                                 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
1158                         
1159                                 for (k = 0; k < patch_info->table_size; k++) {
1160                                         fprintf (tmpfp, "\t.long %d\n", (int)(gssize)table [k]);
1161                                 }
1162                                 break;
1163                         }
1164                         case MONO_PATCH_INFO_METHODCONST:
1165                         case MONO_PATCH_INFO_METHOD:
1166                         case MONO_PATCH_INFO_METHOD_JUMP: {
1167                                 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1168                                 guint32 token = patch_info->data.method->token;
1169                                 g_assert (image_index < 256);
1170                                 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1171
1172                                 fprintf (tmpfp, "\t.long 0x%08x\n", (image_index << 24) + (mono_metadata_token_index (token)));
1173                                 break;
1174                         }
1175                         case MONO_PATCH_INFO_INTERNAL_METHOD: {
1176                                 guint32 icall_index;
1177
1178                                 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1179                                 if (!icall_index) {
1180                                         icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1181                                         g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1182                                                                                  GUINT_TO_POINTER (icall_index));
1183                                         g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1184                                 }
1185                                 fprintf (tmpfp, "\t.long 0x%08x\n", icall_index - 1);
1186                                 break;
1187                         }
1188                         case MONO_PATCH_INFO_LDSTR:
1189                         case MONO_PATCH_INFO_LDTOKEN:
1190                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1191                                 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
1192                                 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
1193                                 break;
1194                         case MONO_PATCH_INFO_EXC_NAME: {
1195                                 MonoClass *ex_class;
1196
1197                                 ex_class =
1198                                         mono_class_from_name (mono_defaults.exception_class->image,
1199                                                                                   "System", patch_info->data.target);
1200                                 g_assert (ex_class);
1201                                 emit_klass_info (acfg, ex_class);
1202                                 break;
1203                         }
1204                         case MONO_PATCH_INFO_R4:
1205                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));     
1206                                 break;
1207                         case MONO_PATCH_INFO_R8:
1208                                 emit_alignment (tmpfp, 8);
1209                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1210                                 fprintf (tmpfp, "\t.long 0x%08x\n", *(((guint32 *)patch_info->data.target) + 1));
1211                                 break;
1212                         case MONO_PATCH_INFO_VTABLE:
1213                         case MONO_PATCH_INFO_CLASS_INIT:
1214                         case MONO_PATCH_INFO_CLASS:
1215                         case MONO_PATCH_INFO_IID:
1216                                 emit_klass_info (acfg, patch_info->data.klass);
1217                                 break;
1218                         case MONO_PATCH_INFO_FIELD:
1219                         case MONO_PATCH_INFO_SFLDA:
1220                                 emit_field_info (acfg, patch_info->data.field);
1221                                 break;
1222                         case MONO_PATCH_INFO_WRAPPER: {
1223                                 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1224
1225                                 switch (patch_info->data.method->wrapper_type) {
1226                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1227                                         MonoMethod *m;
1228                                         guint32 image_index;
1229                                         guint32 token;
1230
1231                                         m = mono_marshal_method_from_wrapper (patch_info->data.method);
1232                                         image_index = get_image_index (acfg, m->klass->image);
1233                                         token = m->token;
1234                                         g_assert (image_index < 256);
1235                                         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1236
1237                                         fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
1238                                         break;
1239                                 }
1240                                 case MONO_WRAPPER_PROXY_ISINST:
1241                                 case MONO_WRAPPER_LDFLD:
1242                                 case MONO_WRAPPER_STFLD: {
1243                                         MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1244                                         emit_klass_info (acfg, proxy_class);
1245                                         break;
1246                                 }
1247                                 default:
1248                                         g_assert_not_reached ();
1249                                 }
1250                                 break;
1251                         }
1252                         default:
1253                                 g_warning ("unable to handle jump info %d", patch_info->type);
1254                                 g_assert_not_reached ();
1255                         }
1256                 }
1257         }
1258
1259         {
1260                 guint8 *buf;
1261                 guint32 buf_len;
1262
1263                 mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
1264
1265                 fprintf (tmpfp, "\t.long %d\n", buf_len);
1266
1267                 for (i = 0; i < buf_len; ++i)
1268                         fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
1269
1270                 if (buf_len > 0)
1271                         g_free (buf);
1272         }
1273
1274         /* fixme: save the rest of the required infos */
1275
1276         g_free (mname);
1277         g_free (mname_p);
1278 }
1279
1280 static gboolean
1281 str_begins_with (const char *str1, const char *str2)
1282 {
1283         int len = strlen (str2);
1284         return strncmp (str1, str2, len) == 0;
1285 }
1286
1287 static void
1288 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1289 {
1290         gchar **args, **ptr;
1291
1292         memset (opts, 0, sizeof (*opts));
1293
1294         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1295         for (ptr = args; ptr && *ptr; ptr ++) {
1296                 const char *arg = *ptr;
1297
1298                 if (str_begins_with (arg, "outfile=")) {
1299                         opts->outfile = g_strdup (arg + strlen ("outfile="));
1300                 }
1301                 else {
1302                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1303                         exit (1);
1304                 }
1305         }
1306 }
1307
1308 int
1309 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1310 {
1311         MonoCompile *cfg;
1312         MonoImage *image = ass->image;
1313         MonoMethod *method;
1314         char *com, *tmpfname, *opts_str;
1315         FILE *tmpfp;
1316         int i;
1317         guint8 *symbol;
1318         int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1319         GHashTable *ref_hash;
1320         MonoAotCompile *acfg;
1321         gboolean *emitted;
1322         MonoAotOptions aot_opts;
1323         char *outfile_name, *tmp_outfile_name;
1324
1325         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1326
1327         mono_aot_parse_options (aot_options, &aot_opts);
1328
1329         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1330         tmpfp = fdopen (i, "w+");
1331         g_assert (tmpfp);
1332
1333         ref_hash = g_hash_table_new (NULL, NULL);
1334
1335         acfg = g_new0 (MonoAotCompile, 1);
1336         acfg->fp = tmpfp;
1337         acfg->ref_hash = ref_hash;
1338         acfg->icall_hash = g_hash_table_new (NULL, NULL);
1339         acfg->icall_table = g_ptr_array_new ();
1340         acfg->image_hash = g_hash_table_new (NULL, NULL);
1341         acfg->image_table = g_ptr_array_new ();
1342
1343         write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1344
1345         write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1346
1347         opts_str = g_strdup_printf ("%d", opts);
1348         write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1349         g_free (opts_str);
1350
1351         emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
1352
1353         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1354                 MonoJumpInfo *patch_info;
1355                 gboolean skip;
1356                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1357                 method = mono_get_method (image, token, NULL);
1358                 
1359                 /* fixme: maybe we can also precompile wrapper methods */
1360                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1361                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1362                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1363                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1364                         //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1365                         continue;
1366                 }
1367
1368                 mcount++;
1369
1370                 /* fixme: we need to patch the IP for the LMF in that case */
1371                 if (method->save_lmf) {
1372                         //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
1373                         lmfcount++;
1374                         continue;
1375                 }
1376
1377                 //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
1378                 //mono_compile_method (method);
1379
1380                 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, 0);
1381                 g_assert (cfg);
1382
1383                 if (cfg->disable_aot) {
1384                         printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1385                         ocount++;
1386                         continue;
1387                 }
1388
1389                 skip = FALSE;
1390                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1391                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
1392                                 /* unable to handle this */
1393                                 //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1394                                 skip = TRUE;    
1395                                 break;
1396                         }
1397                 }
1398
1399                 if (skip) {
1400                         abscount++;
1401                         continue;
1402                 }
1403
1404                 /* some wrappers are very common */
1405                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1406                         if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1407                                 switch (patch_info->data.method->wrapper_type) {
1408                                 case MONO_WRAPPER_PROXY_ISINST:
1409                                         patch_info->type = MONO_PATCH_INFO_WRAPPER;
1410                                 }
1411                         }
1412
1413                         if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1414                                 switch (patch_info->data.method->wrapper_type) {
1415                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1416                                 case MONO_WRAPPER_STFLD:
1417                                 case MONO_WRAPPER_LDFLD:
1418                                         patch_info->type = MONO_PATCH_INFO_WRAPPER;
1419                                         break;
1420                                 }
1421                         }
1422                 }
1423
1424                 skip = FALSE;
1425                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1426                         if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
1427                              patch_info->type == MONO_PATCH_INFO_METHODCONST)) {
1428                                 if (patch_info->data.method->wrapper_type) {
1429                                         /* unable to handle this */
1430                                         //printf ("Skip (wrapper call):   %s %d -> %s\n", mono_method_full_name (method, TRUE), patch_info->type, mono_method_full_name (patch_info->data.method, TRUE));
1431                                         skip = TRUE;
1432                                         break;
1433                                 }
1434                                 if (!patch_info->data.method->token) {
1435                                         /*
1436                                          * The method is part of a constructed type like Int[,].Set (). It doesn't
1437                                          * have a token, and we can't make one, since the parent type is part of
1438                                          * assembly which contains the element type, and not the assembly which
1439                                          * referenced this type.
1440                                          */
1441                                         skip = TRUE;
1442                                         break;
1443                                 }
1444                         }
1445                 }
1446
1447                 if (skip) {
1448                         wrappercount++;
1449                         continue;
1450                 }
1451
1452                 //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
1453
1454                 emitted [i] = TRUE;
1455                 emit_method (acfg, cfg);
1456
1457                 mono_destroy_compile (cfg);
1458
1459                 ccount++;
1460         }
1461
1462         /*
1463          * The icall and image tables are small but referenced in a lot of places.
1464          * So we emit them at once, and reference their elements by an index
1465          * instead of an assembly label to cut back on the number of relocations.
1466          */
1467
1468         /* Emit icall table */
1469
1470         symbol = g_strdup_printf ("mono_icall_table");
1471         emit_section_change (tmpfp, ".text", 1);
1472         emit_global(tmpfp, symbol);
1473         emit_alignment(tmpfp, 8);
1474         emit_label(tmpfp, symbol);
1475         fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1476         for (i = 0; i < acfg->icall_table->len; i++)
1477                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1478
1479         /* Emit image table */
1480
1481         symbol = g_strdup_printf ("mono_image_table");
1482         emit_section_change (tmpfp, ".text", 1);
1483         emit_global(tmpfp, symbol);
1484         emit_alignment(tmpfp, 8);
1485         emit_label(tmpfp, symbol);
1486         fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1487         for (i = 0; i < acfg->image_table->len; i++)
1488                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
1489
1490         /*
1491          * g_module_symbol takes a lot of time for failed lookups, so we emit
1492          * a table which contains one bit for each method. This bit specifies
1493          * whenever the method is emitted or not.
1494          */
1495
1496         symbol = g_strdup_printf ("mono_methods_present_table");
1497         emit_section_change (tmpfp, ".text", 1);
1498         emit_global(tmpfp, symbol);
1499         emit_alignment(tmpfp, 8);
1500         emit_label(tmpfp, symbol);
1501         {
1502                 guint32 k, nrows;
1503                 guint32 w;
1504
1505                 nrows = image->tables [MONO_TABLE_METHOD].rows;
1506                 for (i = 0; i < nrows / 32 + 1; ++i) {
1507                         w = 0;
1508                         for (k = 0; k < 32; ++k) {
1509                                 if (emitted [(i * 32) + k])
1510                                         w += (1 << k);
1511                         }
1512                         //printf ("EMITTED [%d] = %d.\n", i, b);
1513                         fprintf (tmpfp, "\t.long %d\n", w);
1514                 }
1515         }
1516
1517         fclose (tmpfp);
1518
1519 #if defined(__x86_64__)
1520         com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1521 #elif defined(sparc) && SIZEOF_VOID_P == 8
1522         com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1523 #else
1524         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1525 #endif
1526         printf ("Executing the native assembler: %s\n", com);
1527         if (system (com) != 0) {
1528                 g_free (com);
1529                 return 1;
1530         }
1531
1532         g_free (com);
1533
1534         if (aot_opts.outfile)
1535                 outfile_name = g_strdup_printf ("%s", aot_opts.outfile);
1536         else
1537                 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1538
1539         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1540
1541 #if defined(sparc)
1542         com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1543 #elif defined(__ppc__) && defined(__MACH__)
1544         com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1545 #else
1546         com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1547 #endif
1548         printf ("Executing the native linker: %s\n", com);
1549         if (system (com) != 0) {
1550                 g_free (tmp_outfile_name);
1551                 g_free (outfile_name);
1552                 g_free (com);
1553                 return 1;
1554         }
1555
1556         g_free (com);
1557         com = g_strdup_printf ("%s.o", tmpfname);
1558         unlink (com);
1559         g_free (com);
1560         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1561         printf ("Stripping the binary: %s\n", com);
1562         system (com);
1563         g_free (com);*/
1564
1565         rename (tmp_outfile_name, outfile_name);
1566
1567         g_free (tmp_outfile_name);
1568         g_free (outfile_name);
1569
1570         printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
1571         printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
1572         printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
1573         printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
1574         printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
1575         //printf ("Retained input file.\n");
1576         unlink (tmpfname);
1577
1578         return 0;
1579 }
1580
1581