2005-01-30 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) + (minfo->info->num_clauses * sizeof (MonoJitExceptionInfo)));
578                 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo) + (minfo->info->num_clauses * sizeof (MonoJitExceptionInfo)));
579
580                 return jinfo;
581         }
582
583         if (aot_module->out_of_date)
584                 return NULL;
585
586         if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
587                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
588                         char *full_name = mono_method_full_name (method, TRUE);
589                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
590                         g_free (full_name);
591                 }
592                 return NULL;
593         }
594
595         code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
596         info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
597
598         if (mono_last_aot_method != -1) {
599                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
600                                 return NULL;
601                 else
602                         if (mono_jit_stats.methods_aot == mono_last_aot_method)
603                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
604         }
605
606         return mono_aot_load_method (domain, aot_module, method, code, info);
607 }
608
609 static MonoJitInfo*
610 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
611 {
612         MonoClass *klass = method->klass;
613         MonoJumpInfo *patch_info = NULL;
614         guint code_len, used_int_regs, used_strings;
615         MonoAotMethod *minfo;
616         MonoJitInfo *jinfo;
617         MonoMemPool *mp;
618         GPtrArray *patches;
619         int i, pindex, got_index;
620         gboolean non_got_patches, keep_patches = TRUE;
621         gboolean has_clauses;
622         char *p;
623
624         minfo = g_new0 (MonoAotMethod, 1);
625
626         minfo->domain = domain;
627
628         p = (char*)info;
629         code_len = decode_value (p, &p);
630         used_int_regs = decode_value (p, &p);
631
632         if (!use_loaded_code) {
633                 guint8 *code2;
634                 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
635                 memcpy (code2, code, code_len);
636                 mono_arch_flush_icache (code2, code_len);
637                 code = code2;
638         }
639
640         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
641                 char *full_name = mono_method_full_name (method, TRUE);
642                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + code_len, info);
643                 g_free (full_name);
644         }
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 = 
651                         mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (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         else
672                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
673
674         if (aot_module->opts & MONO_OPT_SHARED)
675                 used_strings = decode_value (p, &p);
676         else
677                 used_strings = 0;
678
679         for (i = 0; i < used_strings; i++) {
680                 guint token = decode_value (p, &p);
681                 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
682         }
683
684         if (aot_module->opts & MONO_OPT_SHARED) 
685                 keep_patches = FALSE;
686
687 #ifdef MONO_ARCH_HAVE_PIC_AOT
688         got_index = decode_value (p, &p);
689         keep_patches = FALSE;
690 #endif
691
692         if (*p) {
693                 MonoImage *image;
694                 gpointer *table;
695                 int i;
696                 guint32 last_offset, buf_len;
697
698                 if (keep_patches)
699                         mp = domain->mp;
700                 else
701                         mp = mono_mempool_new ();
702
703                 /* First load the type + offset table */
704                 last_offset = 0;
705                 patches = g_ptr_array_new ();
706                 while (*p) {
707                         MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
708
709 #if defined(MONO_ARCH_HAVE_PIC_AOT)
710                         ji->type = *p;
711                         p ++;
712 #else
713                         guint8 b1, b2;
714
715                         b1 = *(guint8*)p;
716                         b2 = *((guint8*)p + 1);
717                         p += 2;
718
719                         ji->type = b1 >> 2;
720
721                         if (((b1 & (1 + 2)) == 3) && (b2 == 255))
722                                 ji->ip.i = decode_value (p, &p);
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
737                 /* Null terminated array */
738                 p ++;
739
740                 /* Then load the other data */
741                 for (pindex = 0; pindex < patches->len; ++pindex) {
742                         MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
743
744                         switch (ji->type) {
745                         case MONO_PATCH_INFO_CLASS:
746                         case MONO_PATCH_INFO_IID:
747                         case MONO_PATCH_INFO_VTABLE:
748                         case MONO_PATCH_INFO_CLASS_INIT:
749                                 ji->data.klass = decode_klass_info (aot_module, p, &p);
750                                 if (!ji->data.klass)
751                                         goto cleanup;
752                                 break;
753                         case MONO_PATCH_INFO_IMAGE:
754                                 ji->data.image = load_image (aot_module, decode_value (p, &p));
755                                 if (!ji->data.image)
756                                         goto cleanup;
757                                 break;
758                         case MONO_PATCH_INFO_METHOD:
759                         case MONO_PATCH_INFO_METHODCONST:
760                         case MONO_PATCH_INFO_METHOD_JUMP: {
761                                 guint32 image_index, token, value;
762
763                                 value = decode_value (p, &p);
764                                 image_index = value >> 24;
765                                 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
766
767                                 image = load_image (aot_module, image_index);
768                                 if (!image)
769                                         goto cleanup;
770                                 ji->data.method = mono_get_method (image, token, NULL);
771                                 g_assert (ji->data.method);
772                                 mono_class_init (ji->data.method->klass);
773
774                                 break;
775                         }
776                         case MONO_PATCH_INFO_WRAPPER: {
777                                 guint32 wrapper_type;
778
779                                 wrapper_type = decode_value (p, &p);
780
781                                 switch (wrapper_type) {
782                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
783                                         guint32 image_index, token, value;
784
785                                         value = decode_value (p, &p);
786                                         image_index = value >> 24;
787                                         token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
788
789                                         image = load_image (aot_module, image_index);
790                                         if (!image)
791                                                 goto cleanup;
792                                         ji->data.method = mono_get_method (image, token, NULL);
793                                         g_assert (ji->data.method);
794                                         mono_class_init (ji->data.method->klass);
795
796                                         ji->type = MONO_PATCH_INFO_METHOD;
797                                         ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
798                                         break;
799                                 }
800                                 case MONO_WRAPPER_PROXY_ISINST: {
801                                         MonoClass *klass = decode_klass_info (aot_module, p, &p);
802                                         if (!klass)
803                                                 goto cleanup;
804                                         ji->type = MONO_PATCH_INFO_METHOD;
805                                         ji->data.method = mono_marshal_get_proxy_cancast (klass);
806                                         break;
807                                 }
808                                 case MONO_WRAPPER_LDFLD:
809                                 case MONO_WRAPPER_STFLD:
810                                 case MONO_WRAPPER_ISINST: {
811                                         MonoClass *klass = decode_klass_info (aot_module, p, &p);
812                                         if (!klass)
813                                                 goto cleanup;
814                                         ji->type = MONO_PATCH_INFO_METHOD;
815                                         if (wrapper_type == MONO_WRAPPER_LDFLD)
816                                                 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
817                                         else if (wrapper_type == MONO_WRAPPER_STFLD)
818                                                 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
819                                         else
820                                                 ji->data.method = mono_marshal_get_isinst (klass);
821                                         break;
822                                 }
823                                 case MONO_WRAPPER_STELEMREF:
824                                         ji->type = MONO_PATCH_INFO_METHOD;
825                                         ji->data.method = mono_marshal_get_stelemref ();
826                                         break;
827                                 default:
828                                         g_assert_not_reached ();
829                                 }
830                                 break;
831                         }
832                         case MONO_PATCH_INFO_FIELD:
833                         case MONO_PATCH_INFO_SFLDA:
834                                 ji->data.field = decode_field_info (aot_module, p, &p);
835                                 if (!ji->data.field)
836                                         goto cleanup;
837                                 break;
838                         case MONO_PATCH_INFO_INTERNAL_METHOD:
839                                 ji->data.name = aot_module->icall_table [decode_value (p, &p)];
840                                 g_assert (ji->data.name);
841                                 //printf ("A: %s.\n", ji->data.name);
842                                 break;
843                         case MONO_PATCH_INFO_SWITCH:
844                                 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
845                                 ji->data.table->table_size = decode_value (p, &p);
846                                 table = g_new (gpointer, ji->data.table->table_size);
847                                 ji->data.table->table = (MonoBasicBlock**)table;
848                                 for (i = 0; i < ji->data.table->table_size; i++)
849                                         table [i] = (gpointer)(gssize)decode_value (p, &p);
850                                 break;
851                         case MONO_PATCH_INFO_R4:
852                                 ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
853                                 guint32 val;
854
855                                 val = decode_value (p, &p);
856                                 *(float*)ji->data.target = *(float*)&val;
857                                 break;
858                         case MONO_PATCH_INFO_R8: {
859                                 ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
860                                 guint32 val [2];
861
862                                 val [0] = decode_value (p, &p);
863                                 val [1] = decode_value (p, &p);
864                                 *(double*)ji->data.target = *(double*)val;
865                                 break;
866                         }
867                         case MONO_PATCH_INFO_LDSTR:
868                                 image = load_image (aot_module, decode_value (p, &p));
869                                 if (!image)
870                                         goto cleanup;
871                                 ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
872                                 break;
873                         case MONO_PATCH_INFO_DECLSEC:
874                         case MONO_PATCH_INFO_LDTOKEN:
875                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
876                                 image = load_image (aot_module, decode_value (p, &p));
877                                 if (!image)
878                                         goto cleanup;
879                                 ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
880                                 break;
881                         case MONO_PATCH_INFO_EXC_NAME:
882                                 ji->data.klass = decode_klass_info (aot_module, p, &p);
883                                 if (!ji->data.klass)
884                                         goto cleanup;
885                                 ji->data.name = ji->data.klass->name;
886                                 break;
887                         case MONO_PATCH_INFO_METHOD_REL:
888                                 ji->data.offset = decode_value (p, &p);
889                                 break;
890                         default:
891                                 g_warning ("unhandled type %d", ji->type);
892                                 g_assert_not_reached ();
893                         }
894                 }
895
896                 buf_len = decode_value (p, &p);
897                 mono_debug_add_aot_method (domain, method, code, p, 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
934 #endif
935                 g_ptr_array_free (patches, TRUE);
936
937                 if (!keep_patches)
938                         mono_mempool_destroy (mp);
939         }
940
941         mono_jit_stats.methods_aot++;
942
943         {
944                 jinfo->code_size = code_len;
945                 jinfo->used_regs = used_int_regs;
946                 jinfo->method = method;
947                 jinfo->code_start = code;
948 #ifdef MONO_ARCH_HAVE_PIC_AOT
949                 jinfo->domain_neutral = 0;
950 #else
951                 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
952 #endif
953
954                 minfo->info = jinfo;
955                 g_hash_table_insert (aot_module->methods, method, minfo);
956
957                 return jinfo;
958         }
959
960  cleanup:
961         g_ptr_array_free (patches, TRUE);
962
963         /* FIXME: The space in domain->mp is wasted */  
964         if (aot_module->opts & MONO_OPT_SHARED)
965                 /* No need to cache patches */
966                 mono_mempool_destroy (mp);
967
968         return NULL;
969 }
970
971 MonoJitInfo*
972 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
973 {
974         MonoJitInfo *info;
975
976         EnterCriticalSection (&aot_mutex);
977         info = mono_aot_get_method_inner (domain, method);
978         LeaveCriticalSection (&aot_mutex);
979
980         /* Do this outside the lock */
981         if (info) {
982                 mono_jit_info_table_add (domain, info);
983                 return info;
984         }
985         else
986                 return NULL;
987 }
988
989 gboolean
990 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
991 {
992         MonoJitInfo *ji;
993         MonoAssembly *ass;
994         MonoAotModule *aot_module;
995
996         ji = mono_jit_info_table_find (mono_domain_get (), code);
997         if (!ji)
998                 return FALSE;
999
1000         ass = ji->method->klass->image->assembly;
1001
1002         if (!aot_modules)
1003                 return FALSE;
1004         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1005         if (!aot_module || !aot_module->got)
1006                 return FALSE;
1007
1008         return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
1009 }
1010
1011 /*****************************************************/
1012 /*                 AOT COMPILER                      */
1013 /*****************************************************/
1014
1015 static void
1016 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1017 {
1018 #if defined(sparc)
1019         /* For solaris as, GNU as should accept the same */
1020         fprintf (fp, ".section \"%s\"\n", section_name);
1021 #elif defined(__ppc__) && defined(__MACH__)
1022         /* This needs to be made more precise on mach. */
1023         fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1024 #else
1025         fprintf (fp, "%s %d\n", section_name, subsection_index);
1026 #endif
1027 }
1028
1029 static void
1030 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1031 {
1032         const char *stype;
1033
1034         if (func)
1035                 stype = "function";
1036         else
1037                 stype = "object";
1038
1039 #if defined(sparc)
1040         fprintf (fp, "\t.type %s,#%s\n", name, stype);
1041 #elif !(defined(__ppc__) && defined(__MACH__))
1042         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1043 #elif defined(__x86_64__) || defined(__i386__)
1044         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1045 #endif
1046 }
1047
1048 static void
1049 emit_global (FILE *fp, const char *name, gboolean func)
1050 {
1051 #if defined(__ppc__) && defined(__MACH__)
1052     // mach-o always uses a '_' prefix.
1053         fprintf (fp, "\t.globl _%s\n", name);
1054 #else
1055         fprintf (fp, "\t.globl %s\n", name);
1056 #endif
1057
1058         emit_symbol_type (fp, name, func);
1059 }
1060
1061 static void
1062 emit_label (FILE *fp, const char *name)
1063 {
1064 #if defined(__ppc__) && defined(__MACH__)
1065     // mach-o always uses a '_' prefix.
1066         fprintf (fp, "_%s:\n", name);
1067 #else
1068         fprintf (fp, "%s:\n", name);
1069 #endif
1070 }
1071
1072 static void
1073 emit_string_symbol (FILE *fp, const char *name, const char *value)
1074 {
1075         emit_section_change (fp, ".text", 1);
1076         emit_global(fp, name, FALSE);
1077         emit_label(fp, name);
1078         fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1079 }
1080
1081 #if defined(__ppc__) && defined(__MACH__)
1082 static int
1083 ilog2(register int value)
1084 {
1085     int count = -1;
1086     while (value & ~0xf) count += 4, value >>= 4;
1087     while (value) count++, value >>= 1;
1088     return count;
1089 }
1090 #endif
1091
1092 static void 
1093 emit_alignment(FILE *fp, int size)
1094 {
1095 #if defined(__ppc__) && defined(__MACH__)
1096         // the mach-o assembler specifies alignments as powers of 2.
1097         fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1098 #elif defined(__powerpc__)
1099         /* ignore on linux/ppc */
1100 #else
1101         fprintf (fp, "\t.align %d\n", size);
1102 #endif
1103 }
1104
1105 G_GNUC_UNUSED static void
1106 emit_pointer (FILE *fp, const char *target)
1107 {
1108         emit_alignment (fp, sizeof (gpointer));
1109 #if defined(__x86_64__)
1110         fprintf (fp, "\t.quad %s\n", target);
1111 #elif defined(sparc) && SIZEOF_VOID_P == 8
1112         fprintf (fp, "\t.xword %s\n", target);
1113 #else
1114         fprintf (fp, "\t.long %s\n", target);
1115 #endif
1116 }
1117
1118 static guint32
1119 mono_get_field_token (MonoClassField *field) 
1120 {
1121         MonoClass *klass = field->parent;
1122         int i;
1123
1124         for (i = 0; i < klass->field.count; ++i) {
1125                 if (field == &klass->fields [i])
1126                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1127         }
1128
1129         g_assert_not_reached ();
1130         return 0;
1131 }
1132
1133 static inline void
1134 encode_value (gint32 value, char *buf, char **endbuf)
1135 {
1136         char *p = buf;
1137
1138         //printf ("ENCODE: %d 0x%x.\n", value, value);
1139
1140         /* 
1141          * Same encoding as the one used in the metadata, extended to handle values
1142          * greater than 0x1fffffff.
1143          */
1144         if ((value >= 0) && (value <= 127))
1145                 *p++ = value;
1146         else if ((value >= 0) && (value <= 16383)) {
1147                 p [0] = 0x80 | (value >> 8);
1148                 p [1] = value & 0xff;
1149                 p += 2;
1150         } else if ((value >= 0) && (value <= 0x1fffffff)) {
1151                 p [0] = (value >> 24) | 0xc0;
1152                 p [1] = (value >> 16) & 0xff;
1153                 p [2] = (value >> 8) & 0xff;
1154                 p [3] = value & 0xff;
1155                 p += 4;
1156         }
1157         else {
1158                 p [0] = 0xff;
1159                 p [1] = (value >> 24) & 0xff;
1160                 p [2] = (value >> 16) & 0xff;
1161                 p [3] = (value >> 8) & 0xff;
1162                 p [4] = value & 0xff;
1163                 p += 5;
1164         }
1165         if (endbuf)
1166                 *endbuf = p;
1167 }
1168
1169 static guint32
1170 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1171 {
1172         guint32 index;
1173
1174         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1175         if (index)
1176                 return index - 1;
1177         else {
1178                 index = g_hash_table_size (cfg->image_hash);
1179                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1180                 g_ptr_array_add (cfg->image_table, image);
1181                 return index;
1182         }
1183 }
1184
1185 static void
1186 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, char *buf, char **endbuf)
1187 {
1188         encode_value (get_image_index (cfg, klass->image), buf, &buf);
1189         if (!klass->type_token) {
1190                 /* Array class */
1191                 g_assert (klass->rank > 0);
1192                 g_assert (klass->element_class->type_token);
1193                 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1194                 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1195                 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1196                 encode_value (klass->rank, buf, &buf);
1197         }
1198         else {
1199                 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1200                 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1201         }
1202         *endbuf = buf;
1203 }
1204
1205 static void
1206 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, char *buf, char **endbuf)
1207 {
1208         guint32 token = mono_get_field_token (field);
1209
1210         encode_klass_info (cfg, field->parent, buf, &buf);
1211         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1212         encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1213         *endbuf = buf;
1214 }
1215
1216 static gint
1217 compare_patches (gconstpointer a, gconstpointer b)
1218 {
1219         int i, j;
1220
1221         i = (*(MonoJumpInfo**)a)->ip.i;
1222         j = (*(MonoJumpInfo**)b)->ip.i;
1223
1224         if (i < j)
1225                 return -1;
1226         else
1227                 if (i > j)
1228                         return 1;
1229         else
1230                 return 0;
1231 }
1232
1233 static void
1234 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1235 {
1236         MonoMethod *method;
1237         FILE *tmpfp;
1238         int i, j, pindex, byte_index;
1239         guint8 *code, *mname, *mname_p;
1240         int func_alignment = 16;
1241         GPtrArray *patches;
1242         MonoJumpInfo *patch_info;
1243         MonoMethodHeader *header;
1244 #ifdef MONO_ARCH_HAVE_PIC_AOT
1245         gboolean skip;
1246 #endif
1247
1248         tmpfp = acfg->fp;
1249         method = cfg->method;
1250         code = cfg->native_code;
1251         header = mono_method_get_header (method);
1252
1253         emit_section_change (tmpfp, ".text", 0);
1254
1255         /* Make the labels local */
1256         mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1257         mname_p = g_strdup_printf ("%s_p", mname);
1258
1259         emit_alignment(tmpfp, func_alignment);
1260         emit_label(tmpfp, mname);
1261         if (acfg->aot_opts.write_symbols)
1262                 emit_global (tmpfp, mname, TRUE);
1263
1264         if (cfg->verbose_level > 0)
1265                 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), mname);
1266
1267         /* Sort relocations */
1268         patches = g_ptr_array_new ();
1269         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1270                 g_ptr_array_add (patches, patch_info);
1271         g_ptr_array_sort (patches, compare_patches);
1272
1273 #ifdef MONO_ARCH_HAVE_PIC_AOT
1274         acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1275         byte_index = 0;
1276         for (i = 0; i < cfg->code_len; i++) {
1277                 patch_info = NULL;
1278                 for (pindex = 0; pindex < patches->len; ++pindex) {
1279                         patch_info = g_ptr_array_index (patches, pindex);
1280                         if (patch_info->ip.i == i)
1281                                 break;
1282                 }
1283
1284                 skip = FALSE;
1285                 if (patch_info && (pindex < patches->len)) {
1286                         switch (patch_info->type) {
1287                         case MONO_PATCH_INFO_LABEL:
1288                         case MONO_PATCH_INFO_BB:
1289                         case MONO_PATCH_INFO_NONE:
1290                                 break;
1291                         case MONO_PATCH_INFO_GOT_OFFSET: {
1292                                 guint32 offset = mono_arch_get_patch_offset (code + i);
1293                                 fprintf (tmpfp, "\n.byte ");
1294                                 for (j = 0; j < offset; ++j)
1295                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1296                                 fprintf (tmpfp, "\n.int got - . + %d", offset);
1297
1298                                 i += offset + 4 - 1;
1299                                 skip = TRUE;
1300                                 break;
1301                         }
1302                         default:
1303                                 if (!is_got_patch (patch_info->type))
1304                                         break;
1305
1306                                 fprintf (tmpfp, "\n.byte ");
1307                                 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1308                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1309 #ifdef __x86_64__
1310                                 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4));
1311 #elif defined(__i386__)
1312                                 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer))));
1313 #endif
1314                                 acfg->got_offset ++;
1315
1316                                 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1317                                 skip = TRUE;
1318                         }
1319                 }
1320
1321                 if (!skip) {
1322                         if (byte_index == 0)
1323                                 fprintf (tmpfp, "\n.byte ");
1324                         fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
1325                         byte_index = (byte_index + 1) % 32;
1326                 }
1327                 else
1328                         byte_index = 0;
1329         }
1330 #else
1331         for (i = 0; i < cfg->code_len; i++) {
1332                 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1333         }
1334 #endif
1335         fprintf (tmpfp, "\n");
1336 }
1337
1338 static void
1339 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
1340 {
1341         MonoMethod *method;
1342         GList *l;
1343         FILE *tmpfp;
1344         int i, j, k, pindex, buf_size;
1345         guint32 debug_info_size;
1346         guint8 *code, *mname, *mname_p;
1347         GPtrArray *patches;
1348         MonoJumpInfo *patch_info;
1349         MonoMethodHeader *header;
1350         guint32 last_offset;
1351         char *p, *buf;
1352         guint8 *debug_info;
1353 #ifdef MONO_ARCH_HAVE_PIC_AOT
1354         guint32 first_got_offset;
1355 #endif
1356
1357         tmpfp = acfg->fp;
1358         method = cfg->method;
1359         code = cfg->native_code;
1360         header = mono_method_get_header (method);
1361
1362         /* Make the labels local */
1363         mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1364         mname_p = g_strdup_printf ("%s_p", mname);
1365
1366         /* Sort relocations */
1367         patches = g_ptr_array_new ();
1368         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1369                 g_ptr_array_add (patches, patch_info);
1370         g_ptr_array_sort (patches, compare_patches);
1371
1372 #ifdef MONO_ARCH_HAVE_PIC_AOT
1373         first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
1374 #endif
1375
1376         /**********************/
1377         /* Encode method info */
1378         /**********************/
1379
1380         buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
1381         p = buf = g_malloc (buf_size);
1382
1383         encode_value (cfg->code_len, p, &p);
1384         encode_value (cfg->used_int_regs, p, &p);
1385
1386         /* Exception table */
1387         encode_value (header->num_clauses ? 1 : 0, p, &p);
1388         if (header->num_clauses) {
1389                 MonoJitInfo *jinfo = cfg->jit_info;
1390
1391                 for (k = 0; k < header->num_clauses; ++k) {
1392                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1393
1394                         encode_value (ei->exvar_offset, p, &p);
1395
1396                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1397                                 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
1398
1399                         encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
1400                         encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
1401                         encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
1402                 }
1403         }
1404
1405         /* String table */
1406         if (cfg->opt & MONO_OPT_SHARED) {
1407                 encode_value (g_list_length (cfg->ldstr_list), p, &p);
1408                 for (l = cfg->ldstr_list; l; l = l->next) {
1409                         encode_value ((long)l->data, p, &p);
1410                 }
1411         }
1412         else
1413                 /* Used only in shared mode */
1414                 g_assert (!cfg->ldstr_list);
1415
1416 #ifdef MONO_ARCH_HAVE_PIC_AOT
1417         encode_value (first_got_offset, p, &p);
1418 #endif
1419
1420         /* First emit the type+position table */
1421         last_offset = 0;
1422         j = 0;
1423         for (pindex = 0; pindex < patches->len; ++pindex) {
1424                 guint32 offset;
1425                 patch_info = g_ptr_array_index (patches, pindex);
1426                 
1427                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1428                         (patch_info->type == MONO_PATCH_INFO_BB) ||
1429                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1430                         (patch_info->type == MONO_PATCH_INFO_NONE))
1431                         /* Nothing to do */
1432                         continue;
1433
1434                 j ++;
1435                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1436                 offset = patch_info->ip.i - last_offset;
1437                 last_offset = patch_info->ip.i;
1438
1439 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1440                 /* Only the type is needed */
1441                 *p = patch_info->type;
1442                 p++;
1443 #else
1444                 /* Encode type+position compactly */
1445                 g_assert (patch_info->type < 64);
1446                 if (offset < 1024 - 1) {
1447                         *p = (patch_info->type << 2) + (offset >> 8);
1448                         p++;
1449                         *p = offset & ((1 << 8) - 1);
1450                         p ++;
1451                 }
1452                 else {
1453                         *p = (patch_info->type << 2) + 3;
1454                         p ++;
1455                         *p = 255;
1456                         p ++;
1457                         encode_value (offset, p, &p);
1458                 }
1459 #endif
1460         }
1461
1462         /*
1463          * 0 is PATCH_INFO_BB, which can't be in the file.
1464          */
1465         /* NULL terminated array */
1466         *p = 0;
1467         p ++;
1468
1469         /* Then emit the other info */
1470         for (pindex = 0; pindex < patches->len; ++pindex) {
1471                 patch_info = g_ptr_array_index (patches, pindex);
1472
1473                 switch (patch_info->type) {
1474                 case MONO_PATCH_INFO_LABEL:
1475                 case MONO_PATCH_INFO_BB:
1476                 case MONO_PATCH_INFO_GOT_OFFSET:
1477                 case MONO_PATCH_INFO_NONE:
1478                         break;
1479                 case MONO_PATCH_INFO_IMAGE:
1480                         encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
1481                         break;
1482                 case MONO_PATCH_INFO_METHOD_REL:
1483                         encode_value ((gint)patch_info->data.offset, p, &p);
1484                         break;
1485                 case MONO_PATCH_INFO_SWITCH: {
1486                         gpointer *table = (gpointer *)patch_info->data.table->table;
1487                         int k;
1488
1489                         encode_value (patch_info->data.table->table_size, p, &p);
1490                         for (k = 0; k < patch_info->data.table->table_size; k++)
1491                                 encode_value ((int)(gssize)table [k], p, &p);
1492                         break;
1493                 }
1494                 case MONO_PATCH_INFO_METHODCONST:
1495                 case MONO_PATCH_INFO_METHOD:
1496                 case MONO_PATCH_INFO_METHOD_JUMP: {
1497                         guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1498                         guint32 token = patch_info->data.method->token;
1499                         g_assert (image_index < 256);
1500                         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1501
1502                         encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
1503                         break;
1504                 }
1505                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1506                         guint32 icall_index;
1507
1508                         icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1509                         if (!icall_index) {
1510                                 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1511                                 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1512                                                                          GUINT_TO_POINTER (icall_index));
1513                                 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1514                         }
1515                         encode_value (icall_index - 1, p, &p);
1516                         break;
1517                 }
1518                 case MONO_PATCH_INFO_LDSTR: {
1519                         guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
1520                         guint32 token = patch_info->data.token->token;
1521                         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
1522                         /* 
1523                          * An optimization would be to emit shared code for ldstr 
1524                          * statements followed by a throw.
1525                          */
1526                         encode_value (image_index, p, &p);
1527                         encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
1528                         break;
1529                 }
1530                 case MONO_PATCH_INFO_DECLSEC:
1531                 case MONO_PATCH_INFO_LDTOKEN:
1532                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1533                         encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
1534                         encode_value (patch_info->data.token->token, p, &p);
1535                         break;
1536                 case MONO_PATCH_INFO_EXC_NAME: {
1537                         MonoClass *ex_class;
1538
1539                         ex_class =
1540                                 mono_class_from_name (mono_defaults.exception_class->image,
1541                                                                           "System", patch_info->data.target);
1542                         g_assert (ex_class);
1543                         encode_klass_info (acfg, ex_class, p, &p);
1544                         break;
1545                 }
1546                 case MONO_PATCH_INFO_R4:
1547                         encode_value (*((guint32 *)patch_info->data.target), p, &p);
1548                         break;
1549                 case MONO_PATCH_INFO_R8:
1550                         encode_value (*((guint32 *)patch_info->data.target), p, &p);
1551                         encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
1552                         break;
1553                 case MONO_PATCH_INFO_VTABLE:
1554                 case MONO_PATCH_INFO_CLASS_INIT:
1555                 case MONO_PATCH_INFO_CLASS:
1556                 case MONO_PATCH_INFO_IID:
1557                         encode_klass_info (acfg, patch_info->data.klass, p, &p);
1558                         break;
1559                 case MONO_PATCH_INFO_FIELD:
1560                 case MONO_PATCH_INFO_SFLDA:
1561                         encode_field_info (acfg, patch_info->data.field, p, &p);
1562                         break;
1563                 case MONO_PATCH_INFO_WRAPPER: {
1564                         encode_value (patch_info->data.method->wrapper_type, p, &p);
1565
1566                         switch (patch_info->data.method->wrapper_type) {
1567                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1568                                 MonoMethod *m;
1569                                 guint32 image_index;
1570                                 guint32 token;
1571
1572                                 m = mono_marshal_method_from_wrapper (patch_info->data.method);
1573                                 image_index = get_image_index (acfg, m->klass->image);
1574                                 token = m->token;
1575                                 g_assert (image_index < 256);
1576                                 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1577
1578                                 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
1579                                 break;
1580                         }
1581                         case MONO_WRAPPER_PROXY_ISINST:
1582                         case MONO_WRAPPER_LDFLD:
1583                         case MONO_WRAPPER_STFLD:
1584                         case MONO_WRAPPER_ISINST: {
1585                                 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1586                                 encode_klass_info (acfg, proxy_class, p, &p);
1587                                 break;
1588                         }
1589                         case MONO_WRAPPER_STELEMREF:
1590                                 break;
1591                         default:
1592                                 g_assert_not_reached ();
1593                         }
1594                         break;
1595                 }
1596                 default:
1597                         g_warning ("unable to handle jump info %d", patch_info->type);
1598                         g_assert_not_reached ();
1599                 }
1600         }
1601
1602         mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
1603
1604         encode_value (debug_info_size, p, &p);
1605         if (debug_info_size) {
1606                 memcpy (p, debug_info, debug_info_size);
1607                 p += debug_info_size;
1608                 g_free (debug_info);
1609         }
1610
1611         /* Emit method info */
1612
1613         emit_section_change (tmpfp, ".text", 1);
1614         emit_label (tmpfp, mname_p);
1615
1616         g_assert (p - buf < buf_size);
1617         for (i = 0; i < p - buf; ++i) {
1618                 if ((i % 32) == 0)
1619                         fprintf (tmpfp, "\n.byte ");
1620                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
1621         }
1622         fprintf (tmpfp, "\n");
1623         g_free (buf);
1624
1625         g_free (mname);
1626         g_free (mname_p);
1627 }
1628
1629 static gboolean
1630 str_begins_with (const char *str1, const char *str2)
1631 {
1632         int len = strlen (str2);
1633         return strncmp (str1, str2, len) == 0;
1634 }
1635
1636 static void
1637 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1638 {
1639         gchar **args, **ptr;
1640
1641         memset (opts, 0, sizeof (*opts));
1642
1643         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1644         for (ptr = args; ptr && *ptr; ptr ++) {
1645                 const char *arg = *ptr;
1646
1647                 if (str_begins_with (arg, "outfile=")) {
1648                         opts->outfile = g_strdup (arg + strlen ("outfile="));
1649                 } else if (str_begins_with (arg, "save-temps")) {
1650                         opts->save_temps = TRUE;
1651                 } else if (str_begins_with (arg, "write-symbols")) {
1652                         opts->write_symbols = TRUE;
1653                 } else {
1654                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1655                         exit (1);
1656                 }
1657         }
1658 }
1659
1660 int
1661 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1662 {
1663         MonoCompile *cfg;
1664         MonoImage *image = ass->image;
1665         MonoMethod *method;
1666         char *com, *tmpfname, *opts_str;
1667         FILE *tmpfp;
1668         int i;
1669         guint8 *symbol;
1670         int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1671         MonoAotCompile *acfg;
1672         MonoCompile **cfgs;
1673         char *outfile_name, *tmp_outfile_name;
1674
1675         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1676
1677         acfg = g_new0 (MonoAotCompile, 1);
1678         acfg->icall_hash = g_hash_table_new (NULL, NULL);
1679         acfg->icall_table = g_ptr_array_new ();
1680         acfg->image_hash = g_hash_table_new (NULL, NULL);
1681         acfg->image_table = g_ptr_array_new ();
1682
1683         mono_aot_parse_options (aot_options, &acfg->aot_opts);
1684
1685         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1686         tmpfp = fdopen (i, "w+");
1687         acfg->fp = tmpfp;
1688         g_assert (tmpfp);
1689
1690         emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1691
1692         emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1693
1694         opts_str = g_strdup_printf ("%d", opts);
1695         emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1696         g_free (opts_str);
1697
1698         symbol = g_strdup_printf ("methods");
1699         emit_section_change (tmpfp, ".text", 0);
1700         emit_global (tmpfp, symbol, FALSE);
1701         emit_alignment (tmpfp, 8);
1702         emit_label (tmpfp, symbol);
1703
1704         symbol = g_strdup_printf ("method_infos");
1705         emit_section_change (tmpfp, ".text", 1);
1706         emit_global (tmpfp, symbol, FALSE);
1707         emit_alignment (tmpfp, 8);
1708         emit_label (tmpfp, symbol);
1709
1710         cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
1711         acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
1712
1713         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1714                 MonoJumpInfo *patch_info;
1715                 gboolean skip;
1716                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1717                 method = mono_get_method (image, token, NULL);
1718                 
1719                 /* fixme: maybe we can also precompile wrapper methods */
1720                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1721                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1722                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1723                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1724                         //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1725                         continue;
1726                 }
1727
1728                 mcount++;
1729
1730                 /* fixme: we need to patch the IP for the LMF in that case */
1731                 if (method->save_lmf) {
1732                         //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
1733                         lmfcount++;
1734                         continue;
1735                 }
1736
1737                 //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
1738                 //mono_compile_method (method);
1739
1740                 /*
1741                  * Since these methods are the only ones which are compiled with
1742                  * AOT support, and they are not used by runtime startup/shutdown code,
1743                  * the runtime will not see AOT methods during AOT compilation,so it
1744                  * does not need to support them by creating a fake GOT etc.
1745                  */
1746                 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, TRUE, 0);
1747                 g_assert (cfg);
1748
1749                 if (cfg->disable_aot) {
1750                         printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1751                         ocount++;
1752                         continue;
1753                 }
1754
1755                 skip = FALSE;
1756                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1757                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
1758                                 /* unable to handle this */
1759                                 //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1760                                 skip = TRUE;    
1761                                 break;
1762                         }
1763                 }
1764
1765                 if (skip) {
1766                         abscount++;
1767                         continue;
1768                 }
1769
1770                 /* some wrappers are very common */
1771                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1772                         if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1773                                 switch (patch_info->data.method->wrapper_type) {
1774                                 case MONO_WRAPPER_PROXY_ISINST:
1775                                         patch_info->type = MONO_PATCH_INFO_WRAPPER;
1776                                 }
1777                         }
1778
1779                         if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1780                                 switch (patch_info->data.method->wrapper_type) {
1781                                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1782                                 case MONO_WRAPPER_STFLD:
1783                                 case MONO_WRAPPER_LDFLD:
1784                                 case MONO_WRAPPER_STELEMREF:
1785                                 case MONO_WRAPPER_ISINST:
1786                                 case MONO_WRAPPER_PROXY_ISINST:
1787                                         patch_info->type = MONO_PATCH_INFO_WRAPPER;
1788                                         break;
1789                                 }
1790                         }
1791                 }
1792
1793                 skip = FALSE;
1794                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1795                         switch (patch_info->type) {
1796                         case MONO_PATCH_INFO_METHOD:
1797                         case MONO_PATCH_INFO_METHODCONST:
1798                                 if (patch_info->data.method->wrapper_type) {
1799                                         /* unable to handle this */
1800                                         //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));
1801                                         skip = TRUE;
1802                                         break;
1803                                 }
1804                                 if (!patch_info->data.method->token)
1805                                         /*
1806                                          * The method is part of a constructed type like Int[,].Set (). It doesn't
1807                                          * have a token, and we can't make one, since the parent type is part of
1808                                          * assembly which contains the element type, and not the assembly which
1809                                          * referenced this type.
1810                                          */
1811                                         skip = TRUE;
1812                                 break;
1813                         case MONO_PATCH_INFO_VTABLE:
1814                         case MONO_PATCH_INFO_CLASS_INIT:
1815                         case MONO_PATCH_INFO_CLASS:
1816                         case MONO_PATCH_INFO_IID:
1817                                 if (!patch_info->data.klass->type_token)
1818                                         if (!patch_info->data.klass->element_class->type_token)
1819                                                 skip = TRUE;
1820                                 break;
1821                         default:
1822                                 break;
1823                         }
1824                 }
1825
1826                 if (skip) {
1827                         wrappercount++;
1828                         mono_destroy_compile (cfg);
1829                         continue;
1830                 }
1831
1832                 //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
1833
1834                 cfgs [i] = cfg;
1835
1836                 ccount++;
1837         }
1838
1839         /* Emit code */
1840         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1841                 if (cfgs [i])
1842                         emit_method_code (acfg, cfgs [i]);
1843         }
1844
1845         /* Emit method info */
1846         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1847                 if (cfgs [i])
1848                         emit_method_info (acfg, cfgs [i]);
1849         }
1850
1851         /*
1852          * The icall and image tables are small but referenced in a lot of places.
1853          * So we emit them at once, and reference their elements by an index.
1854          */
1855
1856         /* Emit icall table */
1857
1858         symbol = g_strdup_printf ("mono_icall_table");
1859         emit_section_change (tmpfp, ".text", 1);
1860         emit_global(tmpfp, symbol, FALSE);
1861         emit_alignment(tmpfp, 8);
1862         emit_label(tmpfp, symbol);
1863         fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1864         for (i = 0; i < acfg->icall_table->len; i++)
1865                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1866
1867         /* Emit image table */
1868
1869         symbol = g_strdup_printf ("mono_image_table");
1870         emit_section_change (tmpfp, ".text", 1);
1871         emit_global(tmpfp, symbol, FALSE);
1872         emit_alignment(tmpfp, 8);
1873         emit_label(tmpfp, symbol);
1874         fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1875         for (i = 0; i < acfg->image_table->len; i++) {
1876                 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1877                 MonoAssemblyName *aname = &image->assembly->aname;
1878
1879                 /* FIXME: Support multi-module assemblies */
1880                 g_assert (image->assembly->image == image);
1881
1882                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1883                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1884                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1885                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1886
1887                 emit_alignment (tmpfp, 8);
1888                 fprintf (tmpfp, ".long %d\n", aname->flags);
1889                 fprintf (tmpfp, ".long %d\n", aname->major);
1890                 fprintf (tmpfp, ".long %d\n", aname->minor);
1891                 fprintf (tmpfp, ".long %d\n", aname->build);
1892                 fprintf (tmpfp, ".long %d\n", aname->revision);
1893         }
1894
1895 #ifdef MONO_ARCH_HAVE_PIC_AOT
1896         /* Emit GOT */
1897
1898         /* Don't make GOT global so accesses to it don't need relocations */
1899         symbol = g_strdup_printf ("got");
1900 #ifdef __x86_64__
1901         emit_section_change (tmpfp, ".bss", 1);
1902 #else
1903         emit_section_change (tmpfp, ".data", 1);
1904 #endif
1905         emit_alignment (tmpfp, 8);
1906         emit_label(tmpfp, symbol);
1907         if (acfg->got_offset > 0)
1908                 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1909
1910         symbol = g_strdup_printf ("got_addr");
1911         emit_section_change (tmpfp, ".data", 1);
1912         emit_global (tmpfp, symbol, FALSE);
1913         emit_alignment (tmpfp, 8);
1914         emit_label(tmpfp, symbol);
1915         emit_pointer (tmpfp, "got");
1916
1917         symbol = g_strdup_printf ("got_size");
1918         emit_section_change (tmpfp, ".data", 1);
1919         emit_global (tmpfp, symbol, FALSE);
1920         emit_alignment (tmpfp, 8);
1921         emit_label(tmpfp, symbol);
1922         fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1923 #endif
1924
1925         symbol = g_strdup_printf ("method_offsets");
1926         emit_section_change (tmpfp, ".text", 1);
1927         emit_global (tmpfp, symbol, FALSE);
1928         emit_alignment (tmpfp, 8);
1929         emit_label(tmpfp, symbol);
1930
1931         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1932                 const char *sep;
1933                 if ((i % 32) == 0) {
1934                         fprintf (tmpfp, "\n.long ");
1935                         sep = "";
1936                 }
1937                 else
1938                         sep = ",";
1939                 if (cfgs [i]) {
1940                         symbol = g_strdup_printf (".Lm_%x", i + 1);
1941                         fprintf (tmpfp, "%s%s-methods", sep, symbol);
1942                 }
1943                 else
1944                         fprintf (tmpfp, "%s0xffffffff", sep);
1945         }
1946         fprintf (tmpfp, "\n");
1947
1948         symbol = g_strdup_printf ("method_info_offsets");
1949         emit_section_change (tmpfp, ".text", 1);
1950         emit_global (tmpfp, symbol, FALSE);
1951         emit_alignment (tmpfp, 8);
1952         emit_label(tmpfp, symbol);
1953
1954         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1955                 const char *sep;
1956                 if ((i % 32) == 0) {
1957                         fprintf (tmpfp, "\n.long ");
1958                         sep = "";
1959                 }
1960                 else
1961                         sep = ",";
1962                 if (cfgs [i]) {
1963                         symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1964                         fprintf (tmpfp, "%s%s - method_infos", sep, symbol);
1965                 }
1966                 else
1967                         fprintf (tmpfp, "%s0", sep);
1968         }
1969         fprintf (tmpfp, "\n");
1970
1971         fclose (tmpfp);
1972
1973 #if defined(__x86_64__)
1974         com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1975 #elif defined(sparc) && SIZEOF_VOID_P == 8
1976         com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1977 #else
1978         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1979 #endif
1980         printf ("Executing the native assembler: %s\n", com);
1981         if (system (com) != 0) {
1982                 g_free (com);
1983                 return 1;
1984         }
1985
1986         g_free (com);
1987
1988         if (acfg->aot_opts.outfile)
1989                 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
1990         else
1991                 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1992
1993         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1994
1995 #if defined(sparc)
1996         com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1997 #elif defined(__ppc__) && defined(__MACH__)
1998         com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1999 #else
2000         com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
2001 #endif
2002         printf ("Executing the native linker: %s\n", com);
2003         if (system (com) != 0) {
2004                 g_free (tmp_outfile_name);
2005                 g_free (outfile_name);
2006                 g_free (com);
2007                 return 1;
2008         }
2009
2010         g_free (com);
2011         com = g_strdup_printf ("%s.o", tmpfname);
2012         unlink (com);
2013         g_free (com);
2014         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
2015         printf ("Stripping the binary: %s\n", com);
2016         system (com);
2017         g_free (com);*/
2018
2019         rename (tmp_outfile_name, outfile_name);
2020
2021         g_free (tmp_outfile_name);
2022         g_free (outfile_name);
2023
2024         printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
2025         printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
2026         printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
2027         printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
2028         printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
2029         if (acfg->aot_opts.save_temps)
2030                 printf ("Retained input file.\n");
2031         else
2032                 unlink (tmpfname);
2033
2034         return 0;
2035 }
2036
2037 #else
2038 /* AOT disabled */
2039
2040 void
2041 mono_aot_init (void)
2042 {
2043 }
2044
2045 MonoJitInfo*
2046 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
2047 {
2048         return NULL;
2049 }
2050
2051 gboolean
2052 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2053 {
2054         return FALSE;
2055 }
2056
2057 int
2058 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
2059 {
2060         return 0;
2061 }
2062 #endif
2063