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