2004-12-27 Ben Maurer <bmaurer@ximian.com>
[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
39 #include "mini.h"
40
41 #ifndef DISABLE_AOT
42
43 #ifdef PLATFORM_WIN32
44 #define SHARED_EXT ".dll"
45 #elif defined(__ppc__) && defined(__MACH__)
46 #define SHARED_EXT ".dylib"
47 #else
48 #define SHARED_EXT ".so"
49 #endif
50
51 #if defined(sparc) || defined(__ppc__)
52 #define AS_STRING_DIRECTIVE ".asciz"
53 #else
54 /* GNU as */
55 #define AS_STRING_DIRECTIVE ".string"
56 #define AS_HAS_SUBSECTIONS 1
57 #endif
58
59 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
60
61 typedef struct MonoAotMethod {
62         MonoJitInfo *info;
63         MonoJumpInfo *patch_info;
64         MonoDomain *domain;
65 } MonoAotMethod;
66
67 typedef struct MonoAotModule {
68         char *aot_name;
69         /* Optimization flags used to compile the module */
70         guint32 opts;
71         /* Maps MonoMethods to MonoAotMethodInfos */
72         GHashTable *methods;
73         /* Pointer to the Global Offset Table */
74         gpointer *got;
75         guint32 got_size;
76         char **icall_table;
77         MonoAssemblyName *image_names;
78         char **image_guids;
79         MonoImage **image_table;
80         guint32* methods_present_table;
81         gboolean out_of_date;
82         guint8 *code;
83         guint32 *code_offsets;
84         guint8 *method_infos;
85         guint32 *method_info_offsets;
86 } MonoAotModule;
87
88 typedef struct MonoAotCompile {
89         FILE *fp;
90         GHashTable *ref_hash;
91         GHashTable *icall_hash;
92         GPtrArray *icall_table;
93         GHashTable *image_hash;
94         GPtrArray *image_table;
95         guint32 got_offset;
96 } MonoAotCompile;
97
98 typedef struct MonoAotOptions {
99         char *outfile;
100 } MonoAotOptions;
101
102 static GHashTable *aot_modules;
103
104 static CRITICAL_SECTION aot_mutex;
105
106 /*
107  * Disabling this will make a copy of the loaded code and use the copy instead 
108  * of the original. This will place the caller and the callee close to each 
109  * other in memory, possibly improving cache behavior. Since the original
110  * code is in copy-on-write memory, this will not increase the memory usage
111  * of the runtime.
112  */
113 #ifdef MONO_ARCH_HAVE_PIC_AOT
114 static gboolean use_loaded_code = TRUE;
115 #else
116 static gboolean use_loaded_code = FALSE;
117 #endif
118
119 /*
120  * Whenever to AOT compile loaded assemblies on demand and store them in
121  * a cache under $HOME/.mono/aot-cache.
122  */
123 static gboolean use_aot_cache = FALSE;
124
125 /* For debugging */
126 static gint32 mono_last_aot_method = -1;
127
128 static MonoJitInfo*
129 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
130
131 static gboolean 
132 is_got_patch (MonoJumpInfoType patch_type)
133 {
134 #ifdef __x86_64__
135         return TRUE;
136 #elif defined(__i386__)
137         return TRUE;
138 #else
139         return FALSE;
140 #endif
141 }
142
143 /*****************************************************/
144 /*                 AOT RUNTIME                       */
145 /*****************************************************/
146
147 static MonoImage *
148 load_image (MonoAotModule *module, int index)
149 {
150         MonoAssembly *assembly;
151         MonoImageOpenStatus status;
152
153         if (module->image_table [index])
154                 return module->image_table [index];
155         if (module->out_of_date)
156                 return NULL;
157
158         assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
159         if (!assembly) {
160                 module->out_of_date = TRUE;
161                 return NULL;
162         }
163
164         if (strcmp (assembly->image->guid, module->image_guids [index])) {
165                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date (Older than dependency %s).\n", module->aot_name, module->image_names [index].name);
166                 module->out_of_date = TRUE;
167                 return NULL;
168         }
169
170         module->image_table [index] = assembly->image;
171         return assembly->image;
172 }
173
174 static MonoClass*
175 decode_klass_info (MonoAotModule *module, guint32 *info, guint32 **out_info)
176 {
177         MonoImage *image;
178         MonoClass *klass;
179         guint32 token, rank;
180
181         image = load_image (module, info [0]);
182         if (!image)
183                 return NULL;
184         token = info [1];
185         info += 2;
186         if (token) {
187                 klass = mono_class_get (image, token);
188         } else {
189                 token = info [0];
190                 rank = info [1];
191                 info += 2;
192                 klass = mono_class_get (image, token);
193                 g_assert (klass);
194                 klass = mono_array_class_get (klass, rank);
195         }
196         g_assert (klass);
197         mono_class_init (klass);
198
199         *out_info = info;
200         return klass;
201 }
202
203 static MonoClassField*
204 decode_field_info (MonoAotModule *module, guint32 *info, guint32 **out_info)
205 {
206         MonoClass *klass = decode_klass_info (module, info, &info);
207         guint32 token;
208
209         if (!klass)
210                 return NULL;
211
212         token = info [0];
213         info ++;
214         *out_info = info;
215
216         return mono_class_get_field (klass, token);
217 }
218
219 G_GNUC_UNUSED
220 static void
221 make_writable (guint8* addr, guint32 len)
222 {
223 #ifndef PLATFORM_WIN32
224         guint8 *page_start;
225         int pages, err;
226
227         page_start = (char *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
228         pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
229         err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
230         g_assert (err == 0);
231 #else
232         {
233                 DWORD oldp;
234                 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
235         }
236 #endif
237 }
238
239 static void
240 create_cache_structure (void)
241 {
242         const char *home;
243         char *tmp;
244         int err;
245
246         home = g_get_home_dir ();
247         if (!home)
248                 return;
249
250         tmp = g_build_filename (home, ".mono", NULL);
251         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
252                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
253 #ifdef PLATFORM_WIN32
254                 err = mkdir (tmp);
255 #else
256                 err = mkdir (tmp, 0777);
257 #endif
258                 if (err) {
259                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
260                         g_free (tmp);
261                         return;
262                 }
263         }
264         g_free (tmp);
265         tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
266         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
267                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
268 #ifdef PLATFORM_WIN32
269                 err = mkdir (tmp);
270 #else
271                 err = mkdir (tmp, 0777);
272 #endif
273                 if (err) {
274                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
275                         g_free (tmp);
276                         return;
277                 }
278         }
279         g_free (tmp);
280 }
281
282 /*
283  * load_aot_module_from_cache:
284  *
285  *  Experimental code to AOT compile loaded assemblies on demand. 
286  *
287  * FIXME: 
288  * - Add environment variable MONO_AOT_CACHE_OPTIONS
289  * - Add options for controlling the cache size
290  * - Handle full cache by deleting old assemblies lru style
291  * - Add options for excluding assemblies during development
292  * - Maybe add a threshold after an assembly is AOT compiled
293  * - invoking a new mono process is a security risk
294  */
295 static GModule*
296 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
297 {
298         char *fname, *cmd, *tmp2;
299         const char *home;
300         GModule *module;
301         gboolean res;
302         gchar *out, *err;
303
304         *aot_name = NULL;
305
306         if (assembly->image->dynamic)
307                 return NULL;
308
309         create_cache_structure ();
310
311         home = g_get_home_dir ();
312
313         tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
314         fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
315         *aot_name = fname;
316         g_free (tmp2);
317
318         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
319         module = g_module_open (fname, G_MODULE_BIND_LAZY);     
320
321         if (!module) {
322                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
323
324                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
325
326                 /* FIXME: security */
327                 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
328
329                 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
330                 g_free (cmd);
331                 if (!res) {
332                         mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
333                         return NULL;
334                 }
335
336                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
337
338                 module = g_module_open (fname, G_MODULE_BIND_LAZY);     
339         }
340
341         return module;
342 }
343
344 static void
345 load_aot_module (MonoAssembly *assembly, gpointer user_data)
346 {
347         char *aot_name;
348         MonoAotModule *info;
349         gboolean usable = TRUE;
350         char *saved_guid = NULL;
351         char *aot_version = NULL;
352         char *opt_flags = NULL;
353
354 #ifdef MONO_ARCH_HAVE_PIC_AOT
355         gpointer *got_addr = NULL;
356         gpointer *got = NULL;
357         guint32 *got_size_ptr = NULL;
358 #endif
359
360         if (mono_compile_aot)
361                 return;
362                                                         
363         if (use_aot_cache)
364                 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
365         else {
366                 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
367
368                 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
369
370                 if (!assembly->aot_module) {
371                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
372                 }
373         }
374
375         if (!assembly->aot_module) {
376                 g_free (aot_name);
377                 return;
378         }
379
380         g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
381         g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
382         g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
383
384         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
385                 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);
386                 usable = FALSE;
387         }
388         else {
389                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
390                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
391                         usable = FALSE;
392                 }
393         }
394
395         if (!usable) {
396                 g_free (aot_name);
397                 g_module_close (assembly->aot_module);
398                 assembly->aot_module = NULL;
399                 return;
400         }
401
402 #ifdef MONO_ARCH_HAVE_PIC_AOT
403         g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
404         g_assert (got_addr);
405         got = (gpointer*)*got_addr;
406         g_assert (got);
407         g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
408         g_assert (got_size_ptr);
409 #endif
410
411         info = g_new0 (MonoAotModule, 1);
412         info->aot_name = aot_name;
413         info->methods = g_hash_table_new (NULL, NULL);
414 #ifdef MONO_ARCH_HAVE_PIC_AOT
415         info->got = got;
416         info->got_size = *got_size_ptr;
417 #endif
418         sscanf (opt_flags, "%d", &info->opts);
419
420         /* Read image table */
421         {
422                 guint32 table_len, i;
423                 char *table = NULL;
424
425                 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
426                 g_assert (table);
427
428                 table_len = *(guint32*)table;
429                 table += sizeof (guint32);
430                 info->image_table = g_new0 (MonoImage*, table_len);
431                 info->image_names = g_new0 (MonoAssemblyName, table_len);
432                 info->image_guids = g_new0 (char*, table_len);
433                 for (i = 0; i < table_len; ++i) {
434                         MonoAssemblyName *aname = &(info->image_names [i]);
435
436                         aname->name = g_strdup (table);
437                         table += strlen (table) + 1;
438                         info->image_guids [i] = g_strdup (table);
439                         table += strlen (table) + 1;
440                         if (table [0] != 0)
441                                 aname->culture = g_strdup (table);
442                         table += strlen (table) + 1;
443                         memcpy (aname->public_key_token, table, strlen (table) + 1);
444                         table += strlen (table) + 1;                    
445
446                         table = ALIGN_PTR_TO (table, 8);
447                         aname->flags = *(guint32*)table;
448                         table += 4;
449                         aname->major = *(guint32*)table;
450                         table += 4;
451                         aname->minor = *(guint32*)table;
452                         table += 4;
453                         aname->build = *(guint32*)table;
454                         table += 4;
455                         aname->revision = *(guint32*)table;
456                         table += 4;
457                 }
458         }
459
460         /* Read icall table */
461         {
462                 guint32 table_len, i;
463                 char *table = NULL;
464
465                 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
466                 g_assert (table);
467
468                 table_len = *(guint32*)table;
469                 table += sizeof (guint32);
470                 info->icall_table = g_new0 (char*, table_len);
471                 for (i = 0; i < table_len; ++i) {
472                         info->icall_table [i] = table;
473                         table += strlen (table) + 1;
474                 }
475         }
476
477         /* Read methods present table */
478         g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
479
480         /* Read method and method_info tables */
481         g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
482         g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
483         g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
484         g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
485
486         EnterCriticalSection (&aot_mutex);
487         g_hash_table_insert (aot_modules, assembly, info);
488         LeaveCriticalSection (&aot_mutex);
489
490         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
491 }
492
493 void
494 mono_aot_init (void)
495 {
496         InitializeCriticalSection (&aot_mutex);
497         aot_modules = g_hash_table_new (NULL, NULL);
498
499         mono_install_assembly_load_hook (load_aot_module, NULL);
500
501         if (getenv ("MONO_LASTAOT"))
502                 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
503         if (getenv ("MONO_AOT_CACHE"))
504                 use_aot_cache = TRUE;
505 }
506  
507 static MonoJitInfo *
508 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
509 {
510         MonoClass *klass = method->klass;
511         MonoAssembly *ass = klass->image->assembly;
512         GModule *module = ass->aot_module;
513         char method_label [256];
514         char info_label [256];
515         guint8 *code = NULL;
516         guint8 *info;
517         MonoAotModule *aot_module;
518         MonoAotMethod *minfo;
519         MonoJitInfo *jinfo;
520         MonoMethodHeader *header;
521
522         if (!module)
523                 return NULL;
524
525         if (!method->token)
526                 return NULL;
527
528         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
529                 return NULL;
530
531         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
532                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
533                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
534                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
535                 return NULL;
536         
537         header = mono_method_get_header (method);
538         
539         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
540
541         g_assert (klass->inited);
542
543         if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
544                 /* Non shared AOT code can't be used in other appdomains */
545                 return NULL;
546
547         minfo = g_hash_table_lookup (aot_module->methods, method);
548         /* Can't use code from non-root domains since they can be unloaded */
549         if (minfo && (minfo->domain == mono_get_root_domain ())) {
550                 /* This method was already loaded in another appdomain */
551
552                 /* Duplicate jinfo */
553                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
554                 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
555                 if (jinfo->clauses) {
556                         jinfo->clauses = 
557                                 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
558                         memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
559                 }
560
561                 return jinfo;
562         }
563
564         if (aot_module->out_of_date)
565                 return NULL;
566
567         if (aot_module->code) {
568                 if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
569                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
570                         return NULL;
571                 }
572
573                 code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
574                 info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
575         } else {
576                 /* Do a fast check to see whenever the method exists */
577
578                 guint32 index = mono_metadata_token_index (method->token) - 1;
579                 guint32 w;
580                 w = aot_module->methods_present_table [index / 32];
581                 if (! (w & (1 << (index % 32)))) {
582                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
583                         return NULL;
584                 }
585
586                 sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
587                 if (!g_module_symbol (module, method_label, (gpointer *)&code))
588                         return NULL;
589
590                 sprintf (info_label, "%s_p", method_label);
591
592                 if (!g_module_symbol (module, info_label, (gpointer *)&info))
593                         return NULL;
594         }
595
596         if (mono_last_aot_method != -1) {
597                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
598                                 return NULL;
599                 else
600                         if (mono_jit_stats.methods_aot == mono_last_aot_method)
601                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
602         }
603
604         return mono_aot_load_method (domain, aot_module, method, code, info);
605 }
606
607 static MonoJitInfo*
608 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
609 {
610         MonoClass *klass = method->klass;
611         MonoJumpInfo *patch_info = NULL;
612         guint code_len, used_int_regs, used_strings;
613         MonoAotMethod *minfo;
614         MonoJitInfo *jinfo;
615         MonoMethodHeader *header = mono_method_get_header (method);
616         MonoMemPool *mp;
617         GPtrArray *patches;
618         int i, pindex, got_index;
619         gboolean non_got_patches;
620
621         minfo = g_new0 (MonoAotMethod, 1);
622
623         minfo->domain = domain;
624         jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
625
626         code_len = *(guint32*)info;
627         info += 4;
628         used_int_regs = *(guint32*)info;
629         info += 4;
630
631         if (!use_loaded_code) {
632                 guint8 *code2;
633                 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
634                 memcpy (code2, code, code_len);
635                 mono_arch_flush_icache (code2, code_len);
636                 code = code2;
637         }
638
639         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);
640
641         /* Exception table */
642         if (header->num_clauses) {
643                 jinfo->clauses = 
644                         mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
645                 jinfo->num_clauses = header->num_clauses;
646
647                 jinfo->exvar_offset = *(guint32*)info;
648                 info += 4;
649
650                 for (i = 0; i < header->num_clauses; ++i) {
651                         MonoExceptionClause *ec = &header->clauses [i];                         
652                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
653
654                         ei->flags = ec->flags;
655                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
656                                 ei->data.filter = code + *(guint32*)info;
657                         else
658                                 ei->data.catch_class = ec->data.catch_class;
659                         info += 4;
660                         ei->try_start = code + *(guint32*)info;
661                         info += 4;
662                         ei->try_end = code + *(guint32*)info;
663                         info += 4;
664                         ei->handler_start = code + *(guint32*)info;
665                         info += 4;
666                 }
667         }
668
669         if (aot_module->opts & MONO_OPT_SHARED) {
670                 used_strings = *(guint32*)info;
671                 info += 4;
672         }
673         else
674                 used_strings = 0;
675
676         for (i = 0; i < used_strings; i++) {
677                 guint token =  *(guint32*)info;
678                 info += 4;
679                 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
680         }
681
682 #ifdef MONO_ARCH_HAVE_PIC_AOT
683         got_index = *(guint32*)info;
684         info += 4;
685 #endif
686
687         if (*info) {
688                 MonoImage *image;
689                 gpointer *table;
690                 int i;
691                 guint32 last_offset, buf_len;
692                 guint32 *info32;
693
694                 if (aot_module->opts & MONO_OPT_SHARED)
695                         mp = mono_mempool_new ();
696                 else
697                         mp = domain->mp;
698
699                 /* First load the type + offset table */
700                 last_offset = 0;
701                 patches = g_ptr_array_new ();
702                 while (*info) {
703                         MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
704
705 #if defined(MONO_ARCH_HAVE_PIC_AOT)
706                         ji->type = *(guint8*)info;
707                         info ++;
708 #else
709                         guint8 b1, b2;
710
711                         b1 = *(guint8*)info;
712                         b2 = *((guint8*)info + 1);
713                         
714                         info += 2;
715
716                         ji->type = b1 >> 2;
717
718                         if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
719                                 info = ALIGN_PTR_TO (info, 4);
720                                 ji->ip.i = *(guint32*)info;
721                                 info += 4;
722                         }
723                         else
724                                 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
725
726                         ji->ip.i += last_offset;
727                         last_offset = ji->ip.i;
728 #endif
729                         //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
730
731                         ji->next = patch_info;
732                         patch_info = ji;
733
734                         g_ptr_array_add (patches, ji);
735                 }
736                 info ++;
737
738                 info = ALIGN_PTR_TO (info, sizeof (gpointer));
739
740                 info32 = (guint32*)info;
741
742                 /* Then load the other data */
743                 for (pindex = 0; pindex < patches->len; ++pindex) {
744                         MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
745
746                         switch (ji->type) {
747                         case MONO_PATCH_INFO_CLASS:
748                         case MONO_PATCH_INFO_IID:
749                         case MONO_PATCH_INFO_VTABLE:
750                         case MONO_PATCH_INFO_CLASS_INIT:
751                                 ji->data.klass = decode_klass_info (aot_module, info32, &info32);
752                                 if (!ji->data.klass)
753                                         goto cleanup;
754                                 break;
755                         case MONO_PATCH_INFO_IMAGE:
756                                 ji->data.image = load_image (aot_module, info32 [0]);
757                                 if (!ji->data.image)
758                                         goto cleanup;
759                                 g_assert (ji->data.image);
760                                 info32 ++;
761                                 break;
762                         case MONO_PATCH_INFO_METHOD:
763                         case MONO_PATCH_INFO_METHODCONST:
764                         case MONO_PATCH_INFO_METHOD_JUMP: {
765                                 guint32 image_index, token;
766
767                                 image_index = info32 [0] >> 24;
768                                 token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff);
769
770                                 image = load_image (aot_module, image_index);
771                                 if (!image)
772                                         goto cleanup;
773                                 ji->data.method = mono_get_method (image, token, NULL);
774                                 g_assert (ji->data.method);
775                                 mono_class_init (ji->data.method->klass);
776                                 info32 ++;
777
778                                 break;
779                         }
780                         case MONO_PATCH_INFO_WRAPPER: {
781                                 guint32 wrapper_type;
782
783                                 wrapper_type = info32 [0];
784                                 info32 ++;
785
786                                 switch (wrapper_type) {
787                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
788                                         guint32 image_index, token;
789
790                                         image_index = info32 [0] >> 24;
791                                         token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff);
792
793                                         image = load_image (aot_module, image_index);
794                                         if (!image)
795                                                 goto cleanup;
796                                         ji->data.method = mono_get_method (image, token, NULL);
797                                         g_assert (ji->data.method);
798                                         mono_class_init (ji->data.method->klass);
799
800                                         ji->type = MONO_PATCH_INFO_METHOD;
801                                         ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
802                                         info32 ++;
803                                         break;
804                                 }
805                                 case MONO_WRAPPER_PROXY_ISINST: {
806                                         MonoClass *klass = decode_klass_info (aot_module, info32, &info32);
807                                         if (!klass)
808                                                 goto cleanup;
809                                         ji->type = MONO_PATCH_INFO_METHOD;
810                                         ji->data.method = mono_marshal_get_proxy_cancast (klass);
811                                         break;
812                                 }
813                                 case MONO_WRAPPER_LDFLD:
814                                 case MONO_WRAPPER_STFLD:
815                                 case MONO_WRAPPER_ISINST: {
816                                         MonoClass *klass = decode_klass_info (aot_module, info32, &info32);
817                                         if (!klass)
818                                                 goto cleanup;
819                                         ji->type = MONO_PATCH_INFO_METHOD;
820                                         if (wrapper_type == MONO_WRAPPER_LDFLD)
821                                                 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
822                                         else if (wrapper_type == MONO_WRAPPER_STFLD)
823                                                 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
824                                         else
825                                                 ji->data.method = mono_marshal_get_isinst (klass);
826                                         break;
827                                 }
828                                 case MONO_WRAPPER_STELEMREF:
829                                         ji->type = MONO_PATCH_INFO_METHOD;
830                                         ji->data.method = mono_marshal_get_stelemref ();
831                                         break;
832                                 default:
833                                         g_assert_not_reached ();
834                                 }
835                                 break;
836                         }
837                         case MONO_PATCH_INFO_FIELD:
838                         case MONO_PATCH_INFO_SFLDA:
839                                 ji->data.field = decode_field_info (aot_module, info32, &info32);
840                                 if (!ji->data.field)
841                                         goto cleanup;
842                                 break;
843                         case MONO_PATCH_INFO_INTERNAL_METHOD:
844                                 ji->data.name = aot_module->icall_table [info32 [0]];
845                                 g_assert (ji->data.name);
846                                 info32 ++;
847                                 //printf ("A: %s.\n", ji->data.name);
848                                 break;
849                         case MONO_PATCH_INFO_SWITCH:
850                                 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
851                                 ji->data.table->table_size = info32 [0];
852                                 table = g_new (gpointer, ji->data.table->table_size);
853                                 ji->data.table->table = (MonoBasicBlock**)table;
854                                 for (i = 0; i < ji->data.table->table_size; i++) {
855                                         table [i] = (gpointer)(gssize)info32 [i + 1];
856                                 }
857                                 info32 += (ji->data.table->table_size + 1);
858                                 break;
859                         case MONO_PATCH_INFO_R4:
860                                 ji->data.target = info32;
861                                 info32 ++;
862                                 break;
863                         case MONO_PATCH_INFO_R8:
864                                 info32 = ALIGN_PTR_TO (info32, 8);
865                                 ji->data.target = info32;
866                                 info32 += 2;
867                                 break;
868                         case MONO_PATCH_INFO_LDSTR:
869                         case MONO_PATCH_INFO_LDTOKEN:
870                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
871                                 image = load_image (aot_module, info32 [0]);
872                                 if (!image)
873                                         goto cleanup;
874                                 ji->data.token = mono_jump_info_token_new (mp, image, info32 [1]);
875                                 info32 += 2;
876                                 break;
877                         case MONO_PATCH_INFO_EXC_NAME:
878                                 ji->data.klass = decode_klass_info (aot_module, info32, &info32);
879                                 if (!ji->data.klass)
880                                         goto cleanup;
881                                 ji->data.name = ji->data.klass->name;
882                                 break;
883                         case MONO_PATCH_INFO_METHOD_REL:
884                                 ji->data.offset = info32 [0];
885                                 info32 ++;
886                                 break;
887                         default:
888                                 g_warning ("unhandled type %d", ji->type);
889                                 g_assert_not_reached ();
890                         }
891                 }
892
893                 info = (guint8*)info32;
894
895                 buf_len = *(guint32*)info;
896                 info += 4;
897                 mono_debug_add_aot_method (domain, method, code, info, buf_len);
898
899 #if MONO_ARCH_HAVE_PIC_AOT
900                 mono_arch_flush_icache (code, code_len);
901
902                 if (non_got_patches)
903                         make_writable (code, code_len);
904
905                 /* Do this outside the lock to avoid deadlocks */
906                 LeaveCriticalSection (&aot_mutex);
907                 non_got_patches = FALSE;
908                 for (pindex = 0; pindex < patches->len; ++pindex) {
909                         MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
910
911                         if (is_got_patch (ji->type)) {
912                                 aot_module->got [got_index] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
913                                 got_index ++;
914                                 ji->type = MONO_PATCH_INFO_NONE;
915                         }
916                         else
917                                 non_got_patches = TRUE;
918                 }
919                 if (non_got_patches) {
920                         make_writable (code, code_len);
921                         mono_arch_patch_code (method, domain, code, patch_info, TRUE);
922                 }
923                 EnterCriticalSection (&aot_mutex);
924 #else
925                 if (use_loaded_code)
926                         /* disable write protection */
927                         make_writable (code, code_len);
928
929                 /* Do this outside the lock to avoid deadlocks */
930                 LeaveCriticalSection (&aot_mutex);
931                 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
932                 EnterCriticalSection (&aot_mutex);
933 #endif
934
935                 g_ptr_array_free (patches, TRUE);
936
937                 if (aot_module->opts & MONO_OPT_SHARED)
938                         /* No need to cache patches */
939                         mono_mempool_destroy (mp);
940                 else
941                         minfo->patch_info = patch_info;
942         }
943
944         mono_jit_stats.methods_aot++;
945
946         {
947                 jinfo->code_size = code_len;
948                 jinfo->used_regs = used_int_regs;
949                 jinfo->method = method;
950                 jinfo->code_start = code;
951 #ifdef MONO_ARCH_HAVE_PIC_AOT
952                 jinfo->domain_neutral = 0;
953 #else
954                 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
955 #endif
956
957                 minfo->info = jinfo;
958                 g_hash_table_insert (aot_module->methods, method, minfo);
959
960                 return jinfo;
961         }
962
963  cleanup:
964         g_ptr_array_free (patches, TRUE);
965
966         /* FIXME: The space in domain->mp is wasted */  
967         if (aot_module->opts & MONO_OPT_SHARED)
968                 /* No need to cache patches */
969                 mono_mempool_destroy (mp);
970
971         return NULL;
972 }
973
974 MonoJitInfo*
975 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
976 {
977         MonoJitInfo *info;
978
979         EnterCriticalSection (&aot_mutex);
980         info = mono_aot_get_method_inner (domain, method);
981         LeaveCriticalSection (&aot_mutex);
982
983         /* Do this outside the lock */
984         if (info) {
985                 mono_jit_info_table_add (domain, info);
986                 return info;
987         }
988         else
989                 return NULL;
990 }
991
992 gboolean
993 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
994 {
995         MonoJitInfo *ji;
996         MonoAssembly *ass;
997         MonoAotModule *aot_module;
998
999         ji = mono_jit_info_table_find (mono_domain_get (), code);
1000         if (!ji)
1001                 return FALSE;
1002
1003         ass = ji->method->klass->image->assembly;
1004
1005         if (!aot_modules)
1006                 return FALSE;
1007         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1008         if (!aot_module || !aot_module->got)
1009                 return FALSE;
1010
1011         return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
1012 }
1013
1014 /*****************************************************/
1015 /*                 AOT COMPILER                      */
1016 /*****************************************************/
1017
1018 static void
1019 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1020 {
1021 #if defined(sparc)
1022         /* For solaris as, GNU as should accept the same */
1023         fprintf (fp, ".section \"%s\"\n", section_name);
1024 #elif defined(__ppc__) && defined(__MACH__)
1025         /* This needs to be made more precise on mach. */
1026         fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1027 #else
1028         fprintf (fp, "%s %d\n", section_name, subsection_index);
1029 #endif
1030 }
1031
1032 static void
1033 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1034 {
1035         const char *stype;
1036
1037         if (func)
1038                 stype = "function";
1039         else
1040                 stype = "object";
1041
1042 #if defined(sparc)
1043         fprintf (fp, "\t.type %s,#%s\n", name, stype);
1044 #elif !(defined(__ppc__) && defined(__MACH__))
1045         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1046 #elif defined(__x86_64__) || defined(__i386__)
1047         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1048 #endif
1049 }
1050
1051 static void
1052 emit_global (FILE *fp, const char *name, gboolean func)
1053 {
1054 #if defined(__ppc__) && defined(__MACH__)
1055     // mach-o always uses a '_' prefix.
1056         fprintf (fp, ".globl _%s\n", name);
1057 #else
1058         fprintf (fp, ".globl %s\n", name);
1059 #endif
1060
1061         emit_symbol_type (fp, name, func);
1062 }
1063
1064 static void
1065 emit_label (FILE *fp, const char *name)
1066 {
1067 #if defined(__ppc__) && defined(__MACH__)
1068     // mach-o always uses a '_' prefix.
1069         fprintf (fp, "_%s:\n", name);
1070 #else
1071         fprintf (fp, "%s:\n", name);
1072 #endif
1073 }
1074
1075 #if 0
1076 static void
1077 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
1078 {
1079         int i;
1080
1081         emit_section_change (fp, ".text", 1);
1082
1083         fprintf (fp, ".globl %s\n", name);
1084         fprintf (fp, "\t.align %d\n", align);
1085         fprintf (fp, "\t.type %s,#object\n", name);
1086         fprintf (fp, "\t.size %s,%d\n", name, size);
1087         fprintf (fp, "%s:\n", name);
1088         for (i = 0; i < size; i++) { 
1089                 fprintf (fp, ".byte %d\n", buf [i]);
1090         }
1091         
1092 }
1093 #endif
1094
1095 static void
1096 write_string_symbol (FILE *fp, const char *name, const char *value)
1097 {
1098         emit_section_change (fp, ".text", 1);
1099         emit_global(fp, name, FALSE);
1100         emit_label(fp, name);
1101         fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1102 }
1103
1104 static guint32
1105 mono_get_field_token (MonoClassField *field) 
1106 {
1107         MonoClass *klass = field->parent;
1108         int i;
1109
1110         for (i = 0; i < klass->field.count; ++i) {
1111                 if (field == &klass->fields [i])
1112                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1113         }
1114
1115         g_assert_not_reached ();
1116         return 0;
1117 }
1118
1119 static guint32
1120 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1121 {
1122         guint32 index;
1123
1124         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1125         if (index)
1126                 return index - 1;
1127         else {
1128                 index = g_hash_table_size (cfg->image_hash);
1129                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1130                 g_ptr_array_add (cfg->image_table, image);
1131                 return index;
1132         }
1133 }
1134
1135 static void
1136 emit_klass_info (MonoAotCompile *cfg, MonoClass *klass)
1137 {
1138         fprintf (cfg->fp, "\t.long 0x%08x\n", get_image_index (cfg, klass->image));
1139         fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
1140         if (!klass->type_token) {
1141                 /* Array class */
1142                 g_assert (klass->rank > 0);
1143                 g_assert (klass->element_class->type_token);
1144                 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->element_class->type_token);
1145                 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->rank);
1146         }
1147 }
1148
1149 static void
1150 emit_field_info (MonoAotCompile *cfg, MonoClassField *field)
1151 {
1152         emit_klass_info (cfg, field->parent);
1153         fprintf (cfg->fp, "\t.long 0x%08x\n", mono_get_field_token (field));
1154 }
1155
1156 #if defined(__ppc__) && defined(__MACH__)
1157 static int
1158 ilog2(register int value)
1159 {
1160     int count = -1;
1161     while (value & ~0xf) count += 4, value >>= 4;
1162     while (value) count++, value >>= 1;
1163     return count;
1164 }
1165 #endif
1166
1167 static void 
1168 emit_alignment(FILE *fp, int size)
1169 {
1170 #if defined(__ppc__) && defined(__MACH__)
1171         // the mach-o assembler specifies alignments as powers of 2.
1172         fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1173 #elif defined(__powerpc__)
1174         /* ignore on linux/ppc */
1175 #else
1176         fprintf (fp, "\t.align %d\n", size);
1177 #endif
1178 }
1179
1180 G_GNUC_UNUSED static void
1181 emit_pointer (FILE *fp, const char *target)
1182 {
1183         emit_alignment (fp, sizeof (gpointer));
1184 #if defined(__x86_64__)
1185         fprintf (fp, "\t.quad %s\n", target);
1186 #elif defined(sparc) && SIZEOF_VOID_P == 8
1187         fprintf (fp, "\t.xword %s\n", target);
1188 #else
1189         fprintf (fp, "\t.long %s\n", target);
1190 #endif
1191 }
1192
1193 static gint
1194 compare_patches (gconstpointer a, gconstpointer b)
1195 {
1196         int i, j;
1197
1198         i = (*(MonoJumpInfo**)a)->ip.i;
1199         j = (*(MonoJumpInfo**)b)->ip.i;
1200
1201         if (i < j)
1202                 return -1;
1203         else
1204                 if (i > j)
1205                         return 1;
1206         else
1207                 return 0;
1208 }
1209
1210 static void
1211 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
1212 {
1213         MonoMethod *method;
1214         GList *l;
1215         FILE *tmpfp;
1216         int i, j, k, pindex;
1217         guint8 *code, *mname, *mname_p;
1218         int func_alignment = 16;
1219         GPtrArray *patches;
1220         MonoJumpInfo *patch_info;
1221         MonoMethodHeader *header;
1222         guint32 last_offset;
1223 #ifdef MONO_ARCH_HAVE_PIC_AOT
1224         guint32 first_got_offset;
1225         gboolean skip;
1226 #endif
1227
1228         tmpfp = acfg->fp;
1229         method = cfg->method;
1230         code = cfg->native_code;
1231         header = mono_method_get_header (method);
1232
1233         emit_section_change (tmpfp, ".text", 0);
1234
1235 #ifdef AS_HAS_SUBSECTIONS
1236         /* Make the labels local */
1237         mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1238 #else
1239         mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
1240 #endif
1241         mname_p = g_strdup_printf ("%s_p", mname);
1242
1243         emit_alignment(tmpfp, func_alignment);
1244 #ifndef AS_HAS_SUBSECTIONS
1245         emit_global(tmpfp, mname, TRUE);
1246 #endif
1247         emit_label(tmpfp, mname);
1248
1249         if (cfg->verbose_level > 0)
1250                 g_print ("Emitted as %s\n", mname);
1251
1252         /* Sort relocations */
1253         patches = g_ptr_array_new ();
1254         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1255                 g_ptr_array_add (patches, patch_info);
1256         g_ptr_array_sort (patches, compare_patches);
1257
1258 #ifdef MONO_ARCH_HAVE_PIC_AOT
1259         first_got_offset = acfg->got_offset;
1260         for (i = 0; i < cfg->code_len; i++) {
1261                 patch_info = NULL;
1262                 for (pindex = 0; pindex < patches->len; ++pindex) {
1263                         patch_info = g_ptr_array_index (patches, pindex);
1264                         if (patch_info->ip.i == i)
1265                                 break;
1266                 }
1267
1268                 skip = FALSE;
1269                 if (patch_info && (pindex < patches->len)) {
1270                         switch (patch_info->type) {
1271                         case MONO_PATCH_INFO_LABEL:
1272                         case MONO_PATCH_INFO_BB:
1273                         case MONO_PATCH_INFO_NONE:
1274                                 break;
1275                         case MONO_PATCH_INFO_GOT_OFFSET: {
1276                                 guint32 offset = mono_arch_get_patch_offset (code + i);
1277                                 for (j = 0; j < offset; ++j)
1278                                         fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i + j]);
1279                                 fprintf (tmpfp, ".int got - . + %d\n", offset);
1280
1281                                 i += offset + 4 - 1;
1282                                 skip = TRUE;
1283                                 break;
1284                         }
1285                         default:
1286                                 if (!is_got_patch (patch_info->type))
1287                                         break;
1288
1289                                 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1290                                         fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i + j]);
1291 #ifdef __x86_64__
1292                                 fprintf (tmpfp, ".int got - . + %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4));
1293 #elif defined(__i386__)
1294                                 fprintf (tmpfp, ".int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer))));
1295 #endif
1296                                 acfg->got_offset ++;
1297
1298                                 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1299                                 skip = TRUE;
1300                         }
1301                 }
1302
1303                 if (!skip)
1304                         fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1305         }
1306 #else
1307         for (i = 0; i < cfg->code_len; i++) {
1308                 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1309         }
1310 #endif
1311
1312         emit_section_change (tmpfp, ".text", 1);
1313
1314 #ifndef AS_HAS_SUBSECTIONS
1315         emit_global (tmpfp, mname_p, FALSE);
1316 #endif
1317
1318         emit_alignment (tmpfp, 4);
1319
1320         emit_label (tmpfp, mname_p);
1321
1322         fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
1323         fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
1324
1325         /* Exception table */
1326         if (header->num_clauses) {
1327                 MonoJitInfo *jinfo = cfg->jit_info;
1328
1329                 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
1330
1331                 for (k = 0; k < header->num_clauses; ++k) {
1332                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1333
1334                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1335                                 fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->data.filter - code));
1336                         else
1337                                 /* the class is loaded from the header: optimize away later */
1338                                 fprintf (tmpfp, "\t.long %d\n", 0);
1339
1340                         fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_start - code));
1341                         fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_end - code));
1342                         fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->handler_start - code));
1343                 }
1344         }
1345
1346         /* String table */
1347         if (cfg->opt & MONO_OPT_SHARED) {
1348                 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
1349                 for (l = cfg->ldstr_list; l; l = l->next) {
1350                         fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
1351                 }
1352         }
1353         else
1354                 /* Used only in shared mode */
1355                 g_assert (!cfg->ldstr_list);
1356
1357         //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
1358
1359 #ifdef MONO_ARCH_HAVE_PIC_AOT
1360         fprintf (tmpfp, "\t.long %d\n", first_got_offset);
1361 #endif
1362
1363         /* First emit the type+position table */
1364         last_offset = 0;
1365         j = 0;
1366         for (pindex = 0; pindex < patches->len; ++pindex) {
1367                 guint32 offset;
1368                 patch_info = g_ptr_array_index (patches, pindex);
1369                 
1370                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1371                         (patch_info->type == MONO_PATCH_INFO_BB) ||
1372                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1373                         (patch_info->type == MONO_PATCH_INFO_NONE))
1374                         /* Nothing to do */
1375                         continue;
1376
1377                 j ++;
1378                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1379                 offset = patch_info->ip.i - last_offset;
1380                 last_offset = patch_info->ip.i;
1381
1382 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1383                 /* Only the type is needed */
1384                 fprintf (tmpfp, "\t.byte %d\n", patch_info->type);
1385 #else
1386                 /* Encode type+position compactly */
1387                 g_assert (patch_info->type < 64);
1388                 if (offset < 1024 - 1) {
1389                         fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
1390                         fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
1391                 }
1392                 else {
1393                         fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
1394                         fprintf (tmpfp, "\t.byte %d\n", 255);
1395                         emit_alignment(tmpfp, 4);
1396                         fprintf (tmpfp, "\t.long %d\n", offset);
1397                 }
1398 #endif
1399         }
1400
1401         if (j) {
1402                 /*
1403                  * 0 is PATCH_INFO_BB, which can't be in the file.
1404                  */
1405                 /* NULL terminated array */
1406                 fprintf (tmpfp, "\t.byte 0\n");
1407
1408                 emit_alignment (tmpfp, sizeof (gpointer));
1409
1410                 /* Then emit the other info */
1411                 for (pindex = 0; pindex < patches->len; ++pindex) {
1412                         patch_info = g_ptr_array_index (patches, pindex);
1413
1414                         switch (patch_info->type) {
1415                         case MONO_PATCH_INFO_LABEL:
1416                         case MONO_PATCH_INFO_BB:
1417                         case MONO_PATCH_INFO_GOT_OFFSET:
1418                         case MONO_PATCH_INFO_NONE:
1419                                 break;
1420                         case MONO_PATCH_INFO_IMAGE:
1421                                 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.image));
1422                                 break;
1423                         case MONO_PATCH_INFO_METHOD_REL:
1424                                 fprintf (tmpfp, "\t.long 0x%08x\n", (gint)patch_info->data.offset);
1425                                 break;
1426                         case MONO_PATCH_INFO_SWITCH: {
1427                                 gpointer *table = (gpointer *)patch_info->data.table->table;
1428                                 int k;
1429
1430                                 fprintf (tmpfp, "\t.long %d\n", patch_info->data.table->table_size);
1431                         
1432                                 for (k = 0; k < patch_info->data.table->table_size; k++) {
1433                                         fprintf (tmpfp, "\t.long %d\n", (int)(gssize)table [k]);
1434                                 }
1435                                 break;
1436                         }
1437                         case MONO_PATCH_INFO_METHODCONST:
1438                         case MONO_PATCH_INFO_METHOD:
1439                         case MONO_PATCH_INFO_METHOD_JUMP: {
1440                                 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1441                                 guint32 token = patch_info->data.method->token;
1442                                 g_assert (image_index < 256);
1443                                 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1444
1445                                 fprintf (tmpfp, "\t.long 0x%08x\n", (image_index << 24) + (mono_metadata_token_index (token)));
1446                                 break;
1447                         }
1448                         case MONO_PATCH_INFO_INTERNAL_METHOD: {
1449                                 guint32 icall_index;
1450
1451                                 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1452                                 if (!icall_index) {
1453                                         icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1454                                         g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1455                                                                                  GUINT_TO_POINTER (icall_index));
1456                                         g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1457                                 }
1458                                 fprintf (tmpfp, "\t.long 0x%08x\n", icall_index - 1);
1459                                 break;
1460                         }
1461                         case MONO_PATCH_INFO_LDSTR:
1462                         case MONO_PATCH_INFO_LDTOKEN:
1463                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1464                                 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
1465                                 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
1466                                 break;
1467                         case MONO_PATCH_INFO_EXC_NAME: {
1468                                 MonoClass *ex_class;
1469
1470                                 ex_class =
1471                                         mono_class_from_name (mono_defaults.exception_class->image,
1472                                                                                   "System", patch_info->data.target);
1473                                 g_assert (ex_class);
1474                                 emit_klass_info (acfg, ex_class);
1475                                 break;
1476                         }
1477                         case MONO_PATCH_INFO_R4:
1478                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));     
1479                                 break;
1480                         case MONO_PATCH_INFO_R8:
1481                                 emit_alignment (tmpfp, 8);
1482                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1483                                 fprintf (tmpfp, "\t.long 0x%08x\n", *(((guint32 *)patch_info->data.target) + 1));
1484                                 break;
1485                         case MONO_PATCH_INFO_VTABLE:
1486                         case MONO_PATCH_INFO_CLASS_INIT:
1487                         case MONO_PATCH_INFO_CLASS:
1488                         case MONO_PATCH_INFO_IID:
1489                                 emit_klass_info (acfg, patch_info->data.klass);
1490                                 break;
1491                         case MONO_PATCH_INFO_FIELD:
1492                         case MONO_PATCH_INFO_SFLDA:
1493                                 emit_field_info (acfg, patch_info->data.field);
1494                                 break;
1495                         case MONO_PATCH_INFO_WRAPPER: {
1496                                 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1497
1498                                 switch (patch_info->data.method->wrapper_type) {
1499                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1500                                         MonoMethod *m;
1501                                         guint32 image_index;
1502                                         guint32 token;
1503
1504                                         m = mono_marshal_method_from_wrapper (patch_info->data.method);
1505                                         image_index = get_image_index (acfg, m->klass->image);
1506                                         token = m->token;
1507                                         g_assert (image_index < 256);
1508                                         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1509
1510                                         fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
1511                                         break;
1512                                 }
1513                                 case MONO_WRAPPER_PROXY_ISINST:
1514                                 case MONO_WRAPPER_LDFLD:
1515                                 case MONO_WRAPPER_STFLD:
1516                                 case MONO_WRAPPER_ISINST: {
1517                                         MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1518                                         emit_klass_info (acfg, proxy_class);
1519                                         break;
1520                                 }
1521                                 case MONO_WRAPPER_STELEMREF:
1522                                         break;
1523                                 default:
1524                                         g_assert_not_reached ();
1525                                 }
1526                                 break;
1527                         }
1528                         default:
1529                                 g_warning ("unable to handle jump info %d", patch_info->type);
1530                                 g_assert_not_reached ();
1531                         }
1532                 }
1533         }
1534
1535         {
1536                 guint8 *buf;
1537                 guint32 buf_len;
1538
1539                 mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
1540
1541                 fprintf (tmpfp, "\t.long %d\n", buf_len);
1542
1543                 for (i = 0; i < buf_len; ++i)
1544                         fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
1545
1546                 if (buf_len > 0)
1547                         g_free (buf);
1548         }
1549
1550         /* fixme: save the rest of the required infos */
1551
1552         g_free (mname);
1553         g_free (mname_p);
1554 }
1555
1556 static gboolean
1557 str_begins_with (const char *str1, const char *str2)
1558 {
1559         int len = strlen (str2);
1560         return strncmp (str1, str2, len) == 0;
1561 }
1562
1563 static void
1564 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1565 {
1566         gchar **args, **ptr;
1567
1568         memset (opts, 0, sizeof (*opts));
1569
1570         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1571         for (ptr = args; ptr && *ptr; ptr ++) {
1572                 const char *arg = *ptr;
1573
1574                 if (str_begins_with (arg, "outfile=")) {
1575                         opts->outfile = g_strdup (arg + strlen ("outfile="));
1576                 }
1577                 else {
1578                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1579                         exit (1);
1580                 }
1581         }
1582 }
1583
1584 int
1585 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1586 {
1587         MonoCompile *cfg;
1588         MonoImage *image = ass->image;
1589         MonoMethod *method;
1590         char *com, *tmpfname, *opts_str;
1591         FILE *tmpfp;
1592         int i;
1593         guint8 *symbol;
1594         int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1595         GHashTable *ref_hash;
1596         MonoAotCompile *acfg;
1597         gboolean *emitted;
1598         MonoAotOptions aot_opts;
1599         char *outfile_name, *tmp_outfile_name;
1600
1601         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1602
1603         mono_aot_parse_options (aot_options, &aot_opts);
1604
1605         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1606         tmpfp = fdopen (i, "w+");
1607         g_assert (tmpfp);
1608
1609         ref_hash = g_hash_table_new (NULL, NULL);
1610
1611         acfg = g_new0 (MonoAotCompile, 1);
1612         acfg->fp = tmpfp;
1613         acfg->ref_hash = ref_hash;
1614         acfg->icall_hash = g_hash_table_new (NULL, NULL);
1615         acfg->icall_table = g_ptr_array_new ();
1616         acfg->image_hash = g_hash_table_new (NULL, NULL);
1617         acfg->image_table = g_ptr_array_new ();
1618
1619         write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1620
1621         write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1622
1623         opts_str = g_strdup_printf ("%d", opts);
1624         write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1625         g_free (opts_str);
1626
1627         /*
1628          *
1629          * Emit code and method infos into two gas subsections sequentially, so we
1630          * access them without defining a separate global symbol for each one.
1631          * This only works with gas.
1632          */
1633 #ifdef AS_HAS_SUBSECTIONS
1634         symbol = g_strdup_printf ("methods");
1635         emit_section_change (tmpfp, ".text", 0);
1636         emit_global (tmpfp, symbol, FALSE);
1637         emit_alignment (tmpfp, 8);
1638         emit_label (tmpfp, symbol);
1639
1640         symbol = g_strdup_printf ("method_infos");
1641         emit_section_change (tmpfp, ".text", 1);
1642         emit_global (tmpfp, symbol, FALSE);
1643         emit_alignment (tmpfp, 8);
1644         emit_label (tmpfp, symbol);
1645 #endif
1646
1647         emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows + 32);
1648
1649         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1650                 MonoJumpInfo *patch_info;
1651                 gboolean skip;
1652                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1653                 method = mono_get_method (image, token, NULL);
1654                 
1655                 /* fixme: maybe we can also precompile wrapper methods */
1656                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1657                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1658                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1659                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1660                         //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1661                         continue;
1662                 }
1663
1664                 mcount++;
1665
1666                 /* fixme: we need to patch the IP for the LMF in that case */
1667                 if (method->save_lmf) {
1668                         //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
1669                         lmfcount++;
1670                         continue;
1671                 }
1672
1673                 //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
1674                 //mono_compile_method (method);
1675
1676                 /*
1677                  * Since these methods are the only ones which are compiled with
1678                  * AOT support, and they are not used by runtime startup/shutdown code,
1679                  * the runtime will not see AOT methods during AOT compilation,so it
1680                  * does not need to support them by creating a fake GOT etc.
1681                  */
1682                 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, TRUE, 0);
1683                 g_assert (cfg);
1684
1685                 if (cfg->disable_aot) {
1686                         printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1687                         ocount++;
1688                         continue;
1689                 }
1690
1691                 skip = FALSE;
1692                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1693                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
1694                                 /* unable to handle this */
1695                                 //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1696                                 skip = TRUE;    
1697                                 break;
1698                         }
1699                 }
1700
1701                 if (skip) {
1702                         abscount++;
1703                         continue;
1704                 }
1705
1706                 /* some wrappers are very common */
1707                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1708                         if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1709                                 switch (patch_info->data.method->wrapper_type) {
1710                                 case MONO_WRAPPER_PROXY_ISINST:
1711                                         patch_info->type = MONO_PATCH_INFO_WRAPPER;
1712                                 }
1713                         }
1714
1715                         if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1716                                 switch (patch_info->data.method->wrapper_type) {
1717                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1718                                 case MONO_WRAPPER_STFLD:
1719                                 case MONO_WRAPPER_LDFLD:
1720                                 case MONO_WRAPPER_STELEMREF:
1721                                 case MONO_WRAPPER_ISINST:
1722                                 case MONO_WRAPPER_PROXY_ISINST:
1723                                         patch_info->type = MONO_PATCH_INFO_WRAPPER;
1724                                         break;
1725                                 }
1726                         }
1727                 }
1728
1729                 skip = FALSE;
1730                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1731                         switch (patch_info->type) {
1732                         case MONO_PATCH_INFO_METHOD:
1733                         case MONO_PATCH_INFO_METHODCONST:
1734                                 if (patch_info->data.method->wrapper_type) {
1735                                         /* unable to handle this */
1736                                         //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));
1737                                         skip = TRUE;
1738                                         break;
1739                                 }
1740                                 if (!patch_info->data.method->token)
1741                                         /*
1742                                          * The method is part of a constructed type like Int[,].Set (). It doesn't
1743                                          * have a token, and we can't make one, since the parent type is part of
1744                                          * assembly which contains the element type, and not the assembly which
1745                                          * referenced this type.
1746                                          */
1747                                         skip = TRUE;
1748                                 break;
1749                         case MONO_PATCH_INFO_VTABLE:
1750                         case MONO_PATCH_INFO_CLASS_INIT:
1751                         case MONO_PATCH_INFO_CLASS:
1752                         case MONO_PATCH_INFO_IID:
1753                                 if (!patch_info->data.klass->type_token)
1754                                         if (!patch_info->data.klass->element_class->type_token)
1755                                                 skip = TRUE;
1756                                 break;
1757                         default:
1758                                 break;
1759                         }
1760                 }
1761
1762                 if (skip) {
1763                         wrappercount++;
1764                         continue;
1765                 }
1766
1767                 //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
1768
1769                 emitted [i] = TRUE;
1770                 emit_method (acfg, cfg);
1771
1772                 mono_destroy_compile (cfg);
1773
1774                 ccount++;
1775         }
1776
1777         /*
1778          * The icall and image tables are small but referenced in a lot of places.
1779          * So we emit them at once, and reference their elements by an index
1780          * instead of an assembly label to cut back on the number of relocations.
1781          */
1782
1783         /* Emit icall table */
1784
1785         symbol = g_strdup_printf ("mono_icall_table");
1786         emit_section_change (tmpfp, ".text", 1);
1787         emit_global(tmpfp, symbol, FALSE);
1788         emit_alignment(tmpfp, 8);
1789         emit_label(tmpfp, symbol);
1790         fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1791         for (i = 0; i < acfg->icall_table->len; i++)
1792                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1793
1794         /* Emit image table */
1795
1796         symbol = g_strdup_printf ("mono_image_table");
1797         emit_section_change (tmpfp, ".text", 1);
1798         emit_global(tmpfp, symbol, FALSE);
1799         emit_alignment(tmpfp, 8);
1800         emit_label(tmpfp, symbol);
1801         fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1802         for (i = 0; i < acfg->image_table->len; i++) {
1803                 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1804                 MonoAssemblyName *aname = &image->assembly->aname;
1805
1806                 /* FIXME: Support multi-module assemblies */
1807                 g_assert (image->assembly->image == image);
1808
1809                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1810                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1811                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1812                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1813
1814                 emit_alignment (tmpfp, 8);
1815                 fprintf (tmpfp, ".long %d\n", aname->flags);
1816                 fprintf (tmpfp, ".long %d\n", aname->major);
1817                 fprintf (tmpfp, ".long %d\n", aname->minor);
1818                 fprintf (tmpfp, ".long %d\n", aname->build);
1819                 fprintf (tmpfp, ".long %d\n", aname->revision);
1820         }
1821
1822 #ifdef MONO_ARCH_HAVE_PIC_AOT
1823         /* Emit GOT */
1824
1825         /* Don't make GOT global so accesses to it don't need relocations */
1826         symbol = g_strdup_printf ("got");
1827 #ifdef __x86_64__
1828         emit_section_change (tmpfp, ".bss", 1);
1829 #else
1830         emit_section_change (tmpfp, ".data", 1);
1831 #endif
1832         emit_alignment (tmpfp, 8);
1833         emit_label(tmpfp, symbol);
1834         if (acfg->got_offset > 0)
1835                 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1836
1837         symbol = g_strdup_printf ("got_addr");
1838         emit_section_change (tmpfp, ".data", 1);
1839         emit_global (tmpfp, symbol, FALSE);
1840         emit_alignment (tmpfp, 8);
1841         emit_label(tmpfp, symbol);
1842         emit_pointer (tmpfp, "got");
1843
1844         symbol = g_strdup_printf ("got_size");
1845         emit_section_change (tmpfp, ".data", 1);
1846         emit_global (tmpfp, symbol, FALSE);
1847         emit_alignment (tmpfp, 8);
1848         emit_label(tmpfp, symbol);
1849         fprintf (tmpfp, ".long %d\n", acfg->got_offset * sizeof (gpointer));
1850 #endif
1851
1852 #ifdef AS_HAS_SUBSECTIONS
1853         symbol = g_strdup_printf ("method_offsets");
1854         emit_section_change (tmpfp, ".text", 1);
1855         emit_global (tmpfp, symbol, FALSE);
1856         emit_alignment (tmpfp, 8);
1857         emit_label(tmpfp, symbol);
1858
1859         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1860                 if (emitted [i]) {
1861                         symbol = g_strdup_printf (".Lm_%x", i + 1);
1862                         fprintf (tmpfp, ".long %s - methods\n", symbol);
1863                 }
1864                 else
1865                         fprintf (tmpfp, ".long 0xffffffff\n");
1866         }
1867
1868         symbol = g_strdup_printf ("method_info_offsets");
1869         emit_section_change (tmpfp, ".text", 1);
1870         emit_global (tmpfp, symbol, FALSE);
1871         emit_alignment (tmpfp, 8);
1872         emit_label(tmpfp, symbol);
1873
1874         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1875                 if (emitted [i]) {
1876                         symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1877                         fprintf (tmpfp, ".long %s - method_infos\n", symbol);
1878                 }
1879                 else
1880                         fprintf (tmpfp, ".long 0\n");
1881         }
1882 #else
1883         /*
1884          * g_module_symbol takes a lot of time for failed lookups, so we emit
1885          * a table which contains one bit for each method. This bit specifies
1886          * whenever the method is emitted or not.
1887          */
1888         symbol = g_strdup_printf ("mono_methods_present_table");
1889         emit_section_change (tmpfp, ".text", 1);
1890         emit_global (tmpfp, symbol, FALSE);
1891         emit_alignment (tmpfp, 8);
1892         emit_label (tmpfp, symbol);
1893         {
1894                 guint32 k, nrows;
1895                 guint32 w;
1896
1897                 nrows = image->tables [MONO_TABLE_METHOD].rows;
1898                 for (i = 0; i < nrows / 32 + 1; ++i) {
1899                         w = 0;
1900                         for (k = 0; k < 32; ++k) {
1901                                 if (emitted [(i * 32) + k])
1902                                         w += (1 << k);
1903                         }
1904                         //printf ("EMITTED [%d] = %d.\n", i, b);
1905                         fprintf (tmpfp, "\t.long %d\n", w);
1906                 }
1907         }
1908 #endif
1909
1910         fclose (tmpfp);
1911
1912 #if defined(__x86_64__)
1913         com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1914 #elif defined(sparc) && SIZEOF_VOID_P == 8
1915         com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1916 #else
1917         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1918 #endif
1919         printf ("Executing the native assembler: %s\n", com);
1920         if (system (com) != 0) {
1921                 g_free (com);
1922                 return 1;
1923         }
1924
1925         g_free (com);
1926
1927         if (aot_opts.outfile)
1928                 outfile_name = g_strdup_printf ("%s", aot_opts.outfile);
1929         else
1930                 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1931
1932         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1933
1934 #if defined(sparc)
1935         com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1936 #elif defined(__ppc__) && defined(__MACH__)
1937         com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1938 #else
1939         com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1940 #endif
1941         printf ("Executing the native linker: %s\n", com);
1942         if (system (com) != 0) {
1943                 g_free (tmp_outfile_name);
1944                 g_free (outfile_name);
1945                 g_free (com);
1946                 return 1;
1947         }
1948
1949         g_free (com);
1950         com = g_strdup_printf ("%s.o", tmpfname);
1951         unlink (com);
1952         g_free (com);
1953         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1954         printf ("Stripping the binary: %s\n", com);
1955         system (com);
1956         g_free (com);*/
1957
1958         rename (tmp_outfile_name, outfile_name);
1959
1960         g_free (tmp_outfile_name);
1961         g_free (outfile_name);
1962
1963         printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
1964         printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
1965         printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
1966         printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
1967         printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
1968         //printf ("Retained input file.\n");
1969         unlink (tmpfname);
1970
1971         return 0;
1972 }
1973
1974 #else
1975 /* AOT disabled */
1976
1977 void
1978 mono_aot_init (void)
1979 {
1980 }
1981
1982 MonoJitInfo*
1983 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1984 {
1985         return NULL;
1986 }
1987
1988 gboolean
1989 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
1990 {
1991         return FALSE;
1992 }
1993
1994 int
1995 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1996 {
1997         return 0;
1998 }
1999 #endif
2000