2005-07-20 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  *   Zoltan Varga (vargaz@gmail.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include "config.h"
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #ifndef PLATFORM_WIN32
17 #include <sys/mman.h>
18 #else
19 #include <winsock2.h>
20 #include <windows.h>
21 #endif
22
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <limits.h>    /* for PAGESIZE */
26 #ifndef PAGESIZE
27 #define PAGESIZE 4096
28 #endif
29
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/debug-helpers.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/metadata-internals.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/utils/mono-logger.h>
40 #include "mono/utils/mono-compiler.h"
41
42 #include "mini.h"
43
44 #ifndef DISABLE_AOT
45
46 #ifdef PLATFORM_WIN32
47 #define SHARED_EXT ".dll"
48 #elif defined(__ppc__) && defined(__MACH__)
49 #define SHARED_EXT ".dylib"
50 #else
51 #define SHARED_EXT ".so"
52 #endif
53
54 #if defined(sparc) || defined(__ppc__)
55 #define AS_STRING_DIRECTIVE ".asciz"
56 #else
57 /* GNU as */
58 #define AS_STRING_DIRECTIVE ".string"
59 #endif
60
61 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
62
63 typedef struct MonoAotModule {
64         char *aot_name;
65         /* Optimization flags used to compile the module */
66         guint32 opts;
67         /* Pointer to the Global Offset Table */
68         gpointer *got;
69         guint32 got_size;
70         char **icall_table;
71         MonoAssemblyName *image_names;
72         char **image_guids;
73         MonoImage **image_table;
74         gboolean out_of_date;
75         guint8 *code;
76         guint8 *code_end;
77         guint32 *code_offsets;
78         guint8 *method_infos;
79         guint32 *method_info_offsets;
80         guint8 *ex_infos;
81         guint32 *ex_info_offsets;
82         guint8 *class_infos;
83         guint32 *class_info_offsets;
84         guint32 *methods_loaded;
85 } MonoAotModule;
86
87 typedef struct MonoAotOptions {
88         char *outfile;
89         gboolean save_temps;
90         gboolean write_symbols;
91 } MonoAotOptions;
92
93 typedef struct MonoAotCompile {
94         MonoImage *image;
95         MonoCompile **cfgs;
96         FILE *fp;
97         GHashTable *icall_hash;
98         GHashTable *icall_to_got_offset_hash;
99         GPtrArray *icall_table;
100         GHashTable *image_hash;
101         GPtrArray *image_table;
102         guint32 got_offset;
103         guint32 *method_got_offsets;
104         MonoAotOptions aot_opts;
105         guint32 nmethods;
106         guint32 opts;
107         int ccount, mcount, lmfcount, abscount, wrappercount, ocount;
108 } MonoAotCompile;
109
110 static GHashTable *aot_modules;
111
112 static CRITICAL_SECTION aot_mutex;
113
114 /*
115  * Disabling this will make a copy of the loaded code and use the copy instead 
116  * of the original. This will place the caller and the callee close to each 
117  * other in memory, possibly improving cache behavior. Since the original
118  * code is in copy-on-write memory, this will not increase the memory usage
119  * of the runtime.
120  */
121 #ifdef MONO_ARCH_HAVE_PIC_AOT
122 static gboolean use_loaded_code = TRUE;
123 #else
124 static gboolean use_loaded_code = FALSE;
125 #endif
126
127 /*
128  * Whenever to AOT compile loaded assemblies on demand and store them in
129  * a cache under $HOME/.mono/aot-cache.
130  */
131 static gboolean use_aot_cache = FALSE;
132
133 /* For debugging */
134 static gint32 mono_last_aot_method = -1;
135
136 static MonoJitInfo*
137 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8 *ex_info);
138
139 static gboolean 
140 is_got_patch (MonoJumpInfoType patch_type)
141 {
142 #ifdef __x86_64__
143         return TRUE;
144 #elif defined(__i386__)
145         return TRUE;
146 #else
147         return FALSE;
148 #endif
149 }
150
151 /*****************************************************/
152 /*                 AOT RUNTIME                       */
153 /*****************************************************/
154
155 static MonoImage *
156 load_image (MonoAotModule *module, int index)
157 {
158         MonoAssembly *assembly;
159         MonoImageOpenStatus status;
160
161         if (module->image_table [index])
162                 return module->image_table [index];
163         if (module->out_of_date)
164                 return NULL;
165
166         assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
167         if (!assembly) {
168                 module->out_of_date = TRUE;
169                 return NULL;
170         }
171
172         if (strcmp (assembly->image->guid, module->image_guids [index])) {
173                 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);
174                 module->out_of_date = TRUE;
175                 return NULL;
176         }
177
178         module->image_table [index] = assembly->image;
179         return assembly->image;
180 }
181
182
183 static inline gint32
184 decode_value (guint8 *ptr, guint8 **rptr)
185 {
186         guint8 b = *ptr;
187         gint32 len;
188         
189         if ((b & 0x80) == 0){
190                 len = b;
191                 ++ptr;
192         } else if ((b & 0x40) == 0){
193                 len = ((b & 0x3f) << 8 | ptr [1]);
194                 ptr += 2;
195         } else if (b != 0xff) {
196                 len = ((b & 0x1f) << 24) |
197                         (ptr [1] << 16) |
198                         (ptr [2] << 8) |
199                         ptr [3];
200                 ptr += 4;
201         }
202         else {
203                 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
204                 ptr += 5;
205         }
206         if (rptr)
207                 *rptr = ptr;
208
209         //printf ("DECODE: %d.\n", len);
210         return len;
211 }
212
213 static MonoClass*
214 decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
215 {
216         MonoImage *image;
217         MonoClass *klass;
218         guint32 token, rank, image_index;
219
220         image_index = decode_value (buf, &buf);
221         image = load_image (module, image_index);
222         if (!image)
223                 return NULL;
224         token = decode_value (buf, &buf);
225         if (mono_metadata_token_code (token) == 0) {
226                 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
227         } else {
228                 token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
229                 rank = decode_value (buf, &buf);
230                 klass = mono_class_get (image, token);
231                 g_assert (klass);
232                 klass = mono_array_class_get (klass, rank);
233         }
234         g_assert (klass);
235         mono_class_init (klass);
236
237         *endbuf = buf;
238         return klass;
239 }
240
241 static MonoClassField*
242 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
243 {
244         MonoClass *klass = decode_klass_info (module, buf, &buf);
245         guint32 token;
246
247         if (!klass)
248                 return NULL;
249
250         token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf);
251
252         *endbuf = buf;
253
254         return mono_class_get_field (klass, token);
255 }
256
257 static inline MonoImage*
258 decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **endbuf)
259 {
260         guint32 image_index, value;
261         MonoImage *image;
262
263         value = decode_value (buf, &buf);
264         *endbuf = buf;
265         image_index = value >> 24;
266         *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
267
268         image = load_image (module, image_index);
269         if (!image)
270                 return NULL;
271         else
272                 return image;
273 }
274
275 G_GNUC_UNUSED
276 static void
277 make_writable (guint8* addr, guint32 len)
278 {
279 #ifndef PLATFORM_WIN32
280         guint8 *page_start;
281         int pages, err;
282
283         page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
284         pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
285         err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
286         g_assert (err == 0);
287 #else
288         {
289                 DWORD oldp;
290                 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
291         }
292 #endif
293 }
294
295 static void
296 create_cache_structure (void)
297 {
298         const char *home;
299         char *tmp;
300         int err;
301
302         home = g_get_home_dir ();
303         if (!home)
304                 return;
305
306         tmp = g_build_filename (home, ".mono", NULL);
307         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
308                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
309 #ifdef PLATFORM_WIN32
310                 err = mkdir (tmp);
311 #else
312                 err = mkdir (tmp, 0777);
313 #endif
314                 if (err) {
315                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
316                         g_free (tmp);
317                         return;
318                 }
319         }
320         g_free (tmp);
321         tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
322         if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
323                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
324 #ifdef PLATFORM_WIN32
325                 err = mkdir (tmp);
326 #else
327                 err = mkdir (tmp, 0777);
328 #endif
329                 if (err) {
330                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
331                         g_free (tmp);
332                         return;
333                 }
334         }
335         g_free (tmp);
336 }
337
338 /*
339  * load_aot_module_from_cache:
340  *
341  *  Experimental code to AOT compile loaded assemblies on demand. 
342  *
343  * FIXME: 
344  * - Add environment variable MONO_AOT_CACHE_OPTIONS
345  * - Add options for controlling the cache size
346  * - Handle full cache by deleting old assemblies lru style
347  * - Add options for excluding assemblies during development
348  * - Maybe add a threshold after an assembly is AOT compiled
349  * - invoking a new mono process is a security risk
350  */
351 static GModule*
352 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
353 {
354         char *fname, *cmd, *tmp2;
355         const char *home;
356         GModule *module;
357         gboolean res;
358         gchar *out, *err;
359
360         *aot_name = NULL;
361
362         if (assembly->image->dynamic)
363                 return NULL;
364
365         create_cache_structure ();
366
367         home = g_get_home_dir ();
368
369         tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
370         fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
371         *aot_name = fname;
372         g_free (tmp2);
373
374         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
375         module = g_module_open (fname, G_MODULE_BIND_LAZY);     
376
377         if (!module) {
378                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
379
380                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
381
382                 /* FIXME: security */
383                 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
384
385                 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
386                 g_free (cmd);
387                 if (!res) {
388                         mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
389                         return NULL;
390                 }
391
392                 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
393
394                 module = g_module_open (fname, G_MODULE_BIND_LAZY);     
395         }
396
397         return module;
398 }
399
400 static void
401 load_aot_module (MonoAssembly *assembly, gpointer user_data)
402 {
403         char *aot_name;
404         MonoAotModule *info;
405         gboolean usable = TRUE;
406         char *saved_guid = NULL;
407         char *aot_version = NULL;
408         char *opt_flags = NULL;
409
410 #ifdef MONO_ARCH_HAVE_PIC_AOT
411         gpointer *got_addr = NULL;
412         gpointer *got = NULL;
413         guint32 *got_size_ptr = NULL;
414 #endif
415
416         if (mono_compile_aot)
417                 return;
418                                                         
419         if (use_aot_cache)
420                 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
421         else {
422                 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
423
424                 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
425
426                 if (!assembly->aot_module) {
427                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
428                 }
429         }
430
431         if (!assembly->aot_module) {
432                 g_free (aot_name);
433                 return;
434         }
435
436         g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
437         g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
438         g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
439
440         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
441                 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);
442                 usable = FALSE;
443         }
444         else {
445                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
446                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
447                         usable = FALSE;
448                 }
449         }
450
451         if (!usable) {
452                 g_free (aot_name);
453                 g_module_close (assembly->aot_module);
454                 assembly->aot_module = NULL;
455                 return;
456         }
457
458 #ifdef MONO_ARCH_HAVE_PIC_AOT
459         g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
460         g_assert (got_addr);
461         got = (gpointer*)*got_addr;
462         g_assert (got);
463         g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
464         g_assert (got_size_ptr);
465 #endif
466
467         info = g_new0 (MonoAotModule, 1);
468         info->aot_name = aot_name;
469 #ifdef MONO_ARCH_HAVE_PIC_AOT
470         info->got = got;
471         info->got_size = *got_size_ptr;
472 #endif
473         sscanf (opt_flags, "%d", &info->opts);
474
475         /* Read image table */
476         {
477                 guint32 table_len, i;
478                 char *table = NULL;
479
480                 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
481                 g_assert (table);
482
483                 table_len = *(guint32*)table;
484                 table += sizeof (guint32);
485                 info->image_table = g_new0 (MonoImage*, table_len);
486                 info->image_names = g_new0 (MonoAssemblyName, table_len);
487                 info->image_guids = g_new0 (char*, table_len);
488                 for (i = 0; i < table_len; ++i) {
489                         MonoAssemblyName *aname = &(info->image_names [i]);
490
491                         aname->name = g_strdup (table);
492                         table += strlen (table) + 1;
493                         info->image_guids [i] = g_strdup (table);
494                         table += strlen (table) + 1;
495                         if (table [0] != 0)
496                                 aname->culture = g_strdup (table);
497                         table += strlen (table) + 1;
498                         memcpy (aname->public_key_token, table, strlen (table) + 1);
499                         table += strlen (table) + 1;                    
500
501                         table = ALIGN_PTR_TO (table, 8);
502                         aname->flags = *(guint32*)table;
503                         table += 4;
504                         aname->major = *(guint32*)table;
505                         table += 4;
506                         aname->minor = *(guint32*)table;
507                         table += 4;
508                         aname->build = *(guint32*)table;
509                         table += 4;
510                         aname->revision = *(guint32*)table;
511                         table += 4;
512                 }
513         }
514
515         /* Read icall table */
516         {
517                 guint32 table_len, i;
518                 char *table = NULL;
519
520                 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
521                 g_assert (table);
522
523                 table_len = *(guint32*)table;
524                 table += sizeof (guint32);
525                 info->icall_table = g_new0 (char*, table_len);
526                 for (i = 0; i < table_len; ++i) {
527                         info->icall_table [i] = table;
528                         table += strlen (table) + 1;
529                 }
530         }
531
532         /* Read method and method_info tables */
533         g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
534         g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
535         g_module_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end);
536         g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
537         g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
538         g_module_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets);
539         g_module_symbol (assembly->aot_module, "ex_infos", (gpointer*)&info->ex_infos);
540         g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos);
541         g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
542
543         EnterCriticalSection (&aot_mutex);
544         g_hash_table_insert (aot_modules, assembly, info);
545         LeaveCriticalSection (&aot_mutex);
546
547         mono_jit_info_add_aot_module (assembly->image, info->code, info->code_end);
548
549         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
550 }
551
552 void
553 mono_aot_init (void)
554 {
555         InitializeCriticalSection (&aot_mutex);
556         aot_modules = g_hash_table_new (NULL, NULL);
557
558         mono_install_assembly_load_hook (load_aot_module, NULL);
559
560         if (getenv ("MONO_LASTAOT"))
561                 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
562         if (getenv ("MONO_AOT_CACHE"))
563                 use_aot_cache = TRUE;
564 }
565
566 static gboolean
567 decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guint8 *buf, guint8 **endbuf)
568 {
569         guint32 flags;
570
571         info->vtable_size = decode_value (buf, &buf);
572         flags = decode_value (buf, &buf);
573         info->ghcimpl = (flags >> 0) & 0x1;
574         info->has_finalize = (flags >> 1) & 0x1;
575         info->has_cctor = (flags >> 2) & 0x1;
576         if (info->has_cctor) {
577                 MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf);
578                 if (!cctor_image)
579                         return FALSE;
580         }
581         if (info->has_finalize) {
582                 info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf);
583                 if (!info->finalize_image)
584                         return FALSE;
585         }
586
587         *endbuf = buf;
588
589         return TRUE;
590 }       
591
592 gboolean
593 mono_aot_init_vtable (MonoVTable *vtable)
594 {
595         int i;
596         MonoAotModule *aot_module;
597         MonoClass *klass = vtable->klass;
598         guint8 *info, *p;
599         MonoCachedClassInfo class_info;
600         gboolean err;
601
602         if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
603                 return FALSE;
604
605         EnterCriticalSection (&aot_mutex);
606
607         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
608         if (!aot_module) {
609                 LeaveCriticalSection (&aot_mutex);
610                 return FALSE;
611         }
612
613         info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
614         p = info;
615
616         err = decode_cached_class_info (aot_module, &class_info, p, &p);
617         if (!err) {
618                 LeaveCriticalSection (&aot_mutex);
619                 return FALSE;
620         }
621
622         //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
623         for (i = 0; i < class_info.vtable_size; ++i) {
624                 guint32 image_index, token, value;
625                 MonoImage *image;
626 #ifndef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
627                 MonoMethod *m;
628 #endif
629
630                 vtable->vtable [i] = 0;
631
632                 value = decode_value (p, &p);
633                 if (!value)
634                         continue;
635
636                 image_index = value >> 24;
637                 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
638
639                 image = load_image (aot_module, image_index);
640                 if (!image) {
641                         LeaveCriticalSection (&aot_mutex);
642                         return FALSE;
643                 }
644
645 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
646                 vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
647 #else
648                 m = mono_get_method (image, token, NULL);
649                 g_assert (m);
650
651                 //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
652                 vtable->vtable [i] = mono_create_jit_trampoline (m);
653 #endif
654         }
655
656         LeaveCriticalSection (&aot_mutex);
657
658         return TRUE;
659 }
660
661 gboolean
662 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
663 {
664         MonoAotModule *aot_module;
665         guint8 *p;
666         gboolean err;
667
668         if (klass->rank || !klass->image->assembly->aot_module)
669                 return FALSE;
670
671         EnterCriticalSection (&aot_mutex);
672
673         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
674         if (!aot_module) {
675                 LeaveCriticalSection (&aot_mutex);
676                 return FALSE;
677         }
678
679         p = (guint8*)&aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
680
681         err = decode_cached_class_info (aot_module, res, p, &p);
682         if (!err) {
683                 LeaveCriticalSection (&aot_mutex);
684                 return FALSE;
685         }
686
687         LeaveCriticalSection (&aot_mutex);
688
689         return TRUE;
690 }
691
692 static MonoJitInfo*
693 decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain, 
694                                                          MonoMethod *method, guint8* ex_info, guint8 *code)
695 {
696         int i, buf_len;
697         MonoJitInfo *jinfo;
698         guint code_len, used_int_regs;
699         guint8 *p;
700         MonoMethodHeader *header;
701
702         header = mono_method_get_header (method);
703
704         /* Load the method info from the AOT file */
705
706         p = ex_info;
707         code_len = decode_value (p, &p);
708         used_int_regs = decode_value (p, &p);
709
710         /* Exception table */
711         if (header->num_clauses) {
712                 jinfo = 
713                         mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
714                 jinfo->num_clauses = header->num_clauses;
715
716                 for (i = 0; i < header->num_clauses; ++i) {
717                         MonoExceptionClause *ec = &header->clauses [i];                         
718                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
719
720                         ei->flags = ec->flags;
721                         ei->exvar_offset = decode_value (p, &p);
722
723                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
724                                 ei->data.filter = code + decode_value (p, &p);
725                         else
726                                 ei->data.catch_class = ec->data.catch_class;
727
728                         ei->try_start = code + decode_value (p, &p);
729                         ei->try_end = code + decode_value (p, &p);
730                         ei->handler_start = code + decode_value (p, &p);
731                 }
732         }
733         else
734                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
735
736         jinfo->code_size = code_len;
737         jinfo->used_regs = used_int_regs;
738         jinfo->method = method;
739         jinfo->code_start = code;
740 #ifdef MONO_ARCH_HAVE_PIC_AOT
741         jinfo->domain_neutral = 0;
742 #else
743         jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
744 #endif
745
746         /* Load debug info */
747         buf_len = decode_value (p, &p);
748         mono_debug_add_aot_method (domain, method, code, p, buf_len);
749         
750         return jinfo;
751 }
752
753 MonoJitInfo *
754 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
755 {
756         MonoAssembly *ass = image->assembly;
757         GModule *module = ass->aot_module;
758         int pos, pos2, orig_pos, left, right, len, offset, offset1, offset2;
759         guint32 token;
760         MonoAotModule *aot_module;
761         MonoMethod *method;
762         MonoJitInfo *jinfo;
763         guint8 *code, *ex_info;
764
765         if (!module)
766                 return NULL;
767
768         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
769
770         if (domain != mono_get_root_domain ())
771                 /* FIXME: */
772                 return NULL;
773
774         /* Binary search inside the code_offsets table to find the method */
775
776         len = image->tables [MONO_TABLE_METHOD].rows;
777         left = 0;
778         right = len;
779         offset = (guint8*)addr - aot_module->code;
780
781         if (len == 0)
782                 return NULL;
783
784         while (TRUE) {
785                 pos = (left + right) / 2;
786                 orig_pos = pos;
787
788                 while ((pos < len) && (aot_module->code_offsets [pos] == 0xffffffff))
789                         pos ++;
790                 if (pos >= len) {
791                         right = orig_pos;
792                         continue;
793                 }                       
794                 offset1 = aot_module->code_offsets [pos];
795
796                 /* Find the end of the method by searching for the next valid entry */
797                 pos2 = pos + 1;
798                 while ((pos2 < len) && (aot_module->code_offsets [pos2] == 0xffffffff))
799                         pos2 ++;
800                 if (pos2 >= len)
801                         offset2 = 0xfffffff;
802                 else
803                         offset2 = aot_module->code_offsets [pos2];
804
805                 if (offset < offset1)
806                         right = orig_pos;
807                 else if (offset >= offset2)
808                         left = pos + 1;
809                 else
810                         break;
811         }
812
813         token = mono_metadata_make_token (MONO_TABLE_METHOD, pos + 1);
814         method = mono_get_method (image, token, NULL);
815
816         /* FIXME: */
817         g_assert (method);
818
819         //printf ("F: %s\n", mono_method_full_name (method, TRUE));
820
821         code = &aot_module->code [aot_module->code_offsets [pos]];
822         ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [pos]];
823
824         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
825
826         g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
827         g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
828
829         /* Add it to the normal JitInfo tables */
830         mono_jit_info_table_add (domain, jinfo);
831         
832         return jinfo;
833 }
834
835 static MonoJumpInfo*
836 load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches, 
837                                  guint32 got_index, guint32 **got_slots, 
838                                  guint8 *buf, guint8 **endbuf)
839 {
840         MonoJumpInfo *patches;
841         MonoJumpInfo *patch_info;
842         MonoImage *image;
843         gpointer *table;
844         int i, pindex;
845         guint32 last_offset;
846         guint8 *p;
847
848         p = buf;
849
850         /* First load the type + offset table */
851         last_offset = 0;
852         patches = mono_mempool_alloc (mp, sizeof (MonoJumpInfo) * n_patches);
853
854         for (pindex = 0; pindex < n_patches; ++pindex) {                
855                 MonoJumpInfo *ji = &patches [pindex];
856
857 #if defined(MONO_ARCH_HAVE_PIC_AOT)
858                 ji->type = *p;
859                 p ++;
860 #else
861                 guint8 b1, b2;
862
863                 b1 = *(guint8*)p;
864                 b2 = *((guint8*)p + 1);
865                 p += 2;
866
867                 ji->type = b1 >> 2;
868
869                 if (((b1 & (1 + 2)) == 3) && (b2 == 255))
870                         ji->ip.i = decode_value (p, &p);
871                 else
872                         ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
873
874                 ji->ip.i += last_offset;
875                 last_offset = ji->ip.i;
876 #endif
877                 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
878                 ji->next = patch_info;
879                 patch_info = ji;
880         }
881
882         *got_slots = g_malloc (sizeof (guint32) * n_patches);
883         memset (*got_slots, 0xff, sizeof (guint32) * n_patches);
884
885         /* Then load the other data */
886         for (pindex = 0; pindex < n_patches; ++pindex) {
887                 MonoJumpInfo *ji = &patches [pindex];
888
889                 switch (ji->type) {
890                 case MONO_PATCH_INFO_CLASS:
891                 case MONO_PATCH_INFO_IID:
892                 case MONO_PATCH_INFO_VTABLE:
893                 case MONO_PATCH_INFO_CLASS_INIT:
894                         ji->data.klass = decode_klass_info (aot_module, p, &p);
895                         if (!ji->data.klass)
896                                 goto cleanup;
897                         break;
898                 case MONO_PATCH_INFO_IMAGE:
899                         ji->data.image = load_image (aot_module, decode_value (p, &p));
900                         if (!ji->data.image)
901                                 goto cleanup;
902                         break;
903                 case MONO_PATCH_INFO_METHOD:
904                 case MONO_PATCH_INFO_METHODCONST:
905                 case MONO_PATCH_INFO_METHOD_JUMP: {
906                         guint32 image_index, token, value;
907
908                         value = decode_value (p, &p);
909                         image_index = value >> 24;
910                         token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
911
912                         image = load_image (aot_module, image_index);
913                         if (!image)
914                                 goto cleanup;
915
916 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
917                         if (ji->type == MONO_PATCH_INFO_METHOD) {
918                                 ji->data.target = mono_create_jit_trampoline_from_token (image, token);
919                                 ji->type = MONO_PATCH_INFO_ABS;
920                         }
921                         else {
922                                 ji->data.method = mono_get_method (image, token, NULL);
923                                 g_assert (ji->data.method);
924                                 mono_class_init (ji->data.method->klass);
925                         }
926 #else
927                         ji->data.method = mono_get_method (image, token, NULL);
928                         g_assert (ji->data.method);
929                         mono_class_init (ji->data.method->klass);
930 #endif
931
932                         break;
933                 }
934                 case MONO_PATCH_INFO_WRAPPER: {
935                         guint32 wrapper_type;
936
937                         wrapper_type = decode_value (p, &p);
938
939                         switch (wrapper_type) {
940                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
941                                 guint32 image_index, token, value;
942
943                                 value = decode_value (p, &p);
944                                 image_index = value >> 24;
945                                 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
946
947                                 image = load_image (aot_module, image_index);
948                                 if (!image)
949                                         goto cleanup;
950                                 ji->data.method = mono_get_method (image, token, NULL);
951                                 g_assert (ji->data.method);
952                                 mono_class_init (ji->data.method->klass);
953
954                                 ji->type = MONO_PATCH_INFO_METHOD;
955                                 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
956                                 break;
957                         }
958                         case MONO_WRAPPER_PROXY_ISINST: {
959                                 MonoClass *klass = decode_klass_info (aot_module, p, &p);
960                                 if (!klass)
961                                         goto cleanup;
962                                 ji->type = MONO_PATCH_INFO_METHOD;
963                                 ji->data.method = mono_marshal_get_proxy_cancast (klass);
964                                 break;
965                         }
966                         case MONO_WRAPPER_LDFLD:
967                         case MONO_WRAPPER_STFLD:
968                         case MONO_WRAPPER_LDFLD_REMOTE:
969                         case MONO_WRAPPER_STFLD_REMOTE:
970                         case MONO_WRAPPER_ISINST: {
971                                 MonoClass *klass = decode_klass_info (aot_module, p, &p);
972                                 if (!klass)
973                                         goto cleanup;
974                                 ji->type = MONO_PATCH_INFO_METHOD;
975                                 if (wrapper_type == MONO_WRAPPER_LDFLD)
976                                         ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
977                                 else if (wrapper_type == MONO_WRAPPER_STFLD)
978                                         ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
979                                 else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
980                                         ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
981                                 else
982                                         ji->data.method = mono_marshal_get_isinst (klass);
983                                 break;
984                         }
985                         case MONO_WRAPPER_STELEMREF:
986                                 ji->type = MONO_PATCH_INFO_METHOD;
987                                 ji->data.method = mono_marshal_get_stelemref ();
988                                 break;
989                         default:
990                                 g_assert_not_reached ();
991                         }
992                         break;
993                 }
994                 case MONO_PATCH_INFO_FIELD:
995                 case MONO_PATCH_INFO_SFLDA:
996                         ji->data.field = decode_field_info (aot_module, p, &p);
997                         if (!ji->data.field)
998                                 goto cleanup;
999                         break;
1000                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1001                         guint32 icall_index = decode_value (p, &p);
1002
1003                         ji->data.name = aot_module->icall_table [icall_index];
1004                         g_assert (ji->data.name);
1005
1006 #if MONO_ARCH_HAVE_PIC_AOT
1007                         /* GOT entries for icalls are at the start of the got */
1008                         (*got_slots) [pindex] = icall_index;
1009 #endif
1010                         break;
1011                 }
1012                 case MONO_PATCH_INFO_SWITCH:
1013                         ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
1014                         ji->data.table->table_size = decode_value (p, &p);
1015                         table = g_new (gpointer, ji->data.table->table_size);
1016                         ji->data.table->table = (MonoBasicBlock**)table;
1017                         for (i = 0; i < ji->data.table->table_size; i++)
1018                                 table [i] = (gpointer)(gssize)decode_value (p, &p);
1019                         break;
1020                 case MONO_PATCH_INFO_R4: {
1021                         guint32 val;
1022
1023                         ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
1024                         val = decode_value (p, &p);
1025                         *(float*)ji->data.target = *(float*)&val;
1026                         break;
1027                 }
1028                 case MONO_PATCH_INFO_R8: {
1029                         guint32 val [2];
1030
1031                         ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
1032
1033                         val [0] = decode_value (p, &p);
1034                         val [1] = decode_value (p, &p);
1035                         *(double*)ji->data.target = *(double*)val;
1036                         break;
1037                 }
1038                 case MONO_PATCH_INFO_LDSTR:
1039                         image = load_image (aot_module, decode_value (p, &p));
1040                         if (!image)
1041                                 goto cleanup;
1042                         ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
1043                         break;
1044                 case MONO_PATCH_INFO_DECLSEC:
1045                 case MONO_PATCH_INFO_LDTOKEN:
1046                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1047                         image = load_image (aot_module, decode_value (p, &p));
1048                         if (!image)
1049                                 goto cleanup;
1050                         ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
1051                         break;
1052                 case MONO_PATCH_INFO_EXC_NAME:
1053                         ji->data.klass = decode_klass_info (aot_module, p, &p);
1054                         if (!ji->data.klass)
1055                                 goto cleanup;
1056                         ji->data.name = ji->data.klass->name;
1057                         break;
1058                 case MONO_PATCH_INFO_METHOD_REL:
1059                         ji->data.offset = decode_value (p, &p);
1060                         break;
1061                 default:
1062                         g_warning ("unhandled type %d", ji->type);
1063                         g_assert_not_reached ();
1064                 }
1065
1066 #if MONO_ARCH_HAVE_PIC_AOT
1067                 if ((*got_slots) [pindex] == 0xffffffff)
1068                         (*got_slots) [pindex] = got_index ++;
1069 #endif
1070         }
1071
1072         *endbuf = p;
1073         return patches;
1074
1075  cleanup:
1076         g_free (*got_slots);
1077         *got_slots = NULL;
1078
1079         return NULL;
1080 }
1081  
1082 static MonoJitInfo *
1083 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
1084 {
1085         MonoClass *klass = method->klass;
1086         MonoAssembly *ass = klass->image->assembly;
1087         GModule *module = ass->aot_module;
1088         guint8 *code, *info, *ex_info;
1089         MonoAotModule *aot_module;
1090
1091         if (!module)
1092                 return NULL;
1093
1094         if (!method->token)
1095                 return NULL;
1096
1097         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1098                 return NULL;
1099
1100         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1101                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1102                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1103                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1104                 return NULL;
1105         
1106         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1107
1108         g_assert (klass->inited);
1109
1110         if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
1111                 /* Non shared AOT code can't be used in other appdomains */
1112                 return NULL;
1113
1114         if (aot_module->out_of_date)
1115                 return NULL;
1116
1117         if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
1118                 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1119                         char *full_name = mono_method_full_name (method, TRUE);
1120                         mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
1121                         g_free (full_name);
1122                 }
1123                 return NULL;
1124         }
1125
1126         code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
1127         info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
1128         ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]];
1129
1130         if (mono_last_aot_method != -1) {
1131                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1132                                 return NULL;
1133                 else
1134                         if (mono_jit_stats.methods_aot == mono_last_aot_method)
1135                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
1136         }
1137
1138         return mono_aot_load_method (domain, aot_module, method, code, info, ex_info);
1139 }
1140
1141 static MonoJitInfo*
1142 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8* ex_info)
1143 {
1144         MonoClass *klass = method->klass;
1145         MonoJumpInfo *patch_info = NULL;
1146         MonoJitInfo *jinfo;
1147         MonoMemPool *mp;
1148         int i, pindex, got_index, n_patches, used_strings;
1149         gboolean non_got_patches, keep_patches = TRUE;
1150         guint8 *p;
1151
1152         jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
1153
1154         p = info;
1155         decode_klass_info (aot_module, p, &p);
1156
1157         if (!use_loaded_code) {
1158                 guint8 *code2;
1159                 code2 = mono_code_manager_reserve (domain->code_mp, jinfo->code_size);
1160                 memcpy (code2, code, jinfo->code_size);
1161                 mono_arch_flush_icache (code2, jinfo->code_size);
1162                 code = code2;
1163         }
1164
1165         if (aot_module->opts & MONO_OPT_SHARED)
1166                 used_strings = decode_value (p, &p);
1167         else
1168                 used_strings = 0;
1169
1170         for (i = 0; i < used_strings; i++) {
1171                 guint token = decode_value (p, &p);
1172                 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
1173         }
1174
1175         if (aot_module->opts & MONO_OPT_SHARED) 
1176                 keep_patches = FALSE;
1177
1178 #ifdef MONO_ARCH_HAVE_PIC_AOT
1179         got_index = decode_value (p, &p);
1180         keep_patches = FALSE;
1181 #endif
1182
1183         n_patches = decode_value (p, &p);
1184
1185         if (n_patches) {
1186                 MonoJumpInfo *patches;
1187                 guint32 *got_slots;
1188
1189                 if (keep_patches)
1190                         mp = domain->mp;
1191                 else
1192                         mp = mono_mempool_new ();
1193
1194                 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1195                 if (patches == NULL)
1196                         goto cleanup;
1197
1198 #if MONO_ARCH_HAVE_PIC_AOT
1199                 /* Do this outside the lock to avoid deadlocks */
1200                 LeaveCriticalSection (&aot_mutex);
1201                 non_got_patches = FALSE;
1202                 for (pindex = 0; pindex < n_patches; ++pindex) {
1203                         MonoJumpInfo *ji = &patches [pindex];
1204
1205                         if (is_got_patch (ji->type)) {
1206                                 if (!aot_module->got [got_slots [pindex]])
1207                                         aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
1208                                 ji->type = MONO_PATCH_INFO_NONE;
1209                         }
1210                         else
1211                                 non_got_patches = TRUE;
1212                 }
1213                 if (non_got_patches) {
1214                         mono_arch_flush_icache (code, jinfo->code_size);
1215                         make_writable (code, jinfo->code_size);
1216                         mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1217                 }
1218                 EnterCriticalSection (&aot_mutex);
1219 #else
1220                 if (use_loaded_code)
1221                         /* disable write protection */
1222                         make_writable (code, jinfo->code_size);
1223
1224                 /* Do this outside the lock to avoid deadlocks */
1225                 LeaveCriticalSection (&aot_mutex);
1226                 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1227                 EnterCriticalSection (&aot_mutex);
1228 #endif
1229                 g_free (got_slots);
1230
1231                 if (!keep_patches)
1232                         mono_mempool_destroy (mp);
1233         }
1234
1235         mono_jit_stats.methods_aot++;
1236
1237         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1238                 char *full_name = mono_method_full_name (method, TRUE);
1239                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + jinfo->code_size, info);
1240                 g_free (full_name);
1241         }
1242
1243         return jinfo;
1244
1245  cleanup:
1246         /* FIXME: The space in domain->mp is wasted */  
1247         if (aot_module->opts & MONO_OPT_SHARED)
1248                 /* No need to cache patches */
1249                 mono_mempool_destroy (mp);
1250
1251         return NULL;
1252 }
1253
1254 MonoJitInfo*
1255 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1256 {
1257         MonoJitInfo *info;
1258
1259         EnterCriticalSection (&aot_mutex);
1260         info = mono_aot_get_method_inner (domain, method);
1261         LeaveCriticalSection (&aot_mutex);
1262
1263         /* Do this outside the lock */
1264         if (info) {
1265                 mono_jit_info_table_add (domain, info);
1266                 return info;
1267         }
1268         else
1269                 return NULL;
1270 }
1271
1272 static gpointer
1273 mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guint32 token, MonoClass **klass)
1274 {
1275         MonoAssembly *ass = image->assembly;
1276         MonoMemPool *mp;
1277         int i, method_index, pindex, got_index, n_patches, used_strings;
1278         gboolean keep_patches = TRUE;
1279         guint8 *p;
1280         GModule *module = ass->aot_module;
1281         guint8 *code = NULL;
1282         guint8 *info;
1283         MonoAotModule *aot_module;
1284
1285         *klass = NULL;
1286
1287         if (!module)
1288                 return NULL;
1289
1290         if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1291                 return NULL;
1292
1293         aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1294
1295         if (domain != mono_get_root_domain ())
1296                 return NULL;
1297
1298         if (aot_module->out_of_date)
1299                 return NULL;
1300
1301         if (aot_module->code_offsets [mono_metadata_token_index (token) - 1] == 0xffffffff) {
1302                 return NULL;
1303         }
1304
1305         method_index = mono_metadata_token_index (token) - 1;
1306         code = &aot_module->code [aot_module->code_offsets [method_index]];
1307         info = &aot_module->method_infos [aot_module->method_info_offsets [method_index]];
1308
1309         if (mono_last_aot_method != -1) {
1310                 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1311                                 return NULL;
1312                 else
1313                         if (mono_jit_stats.methods_aot == mono_last_aot_method) {
1314                                 MonoMethod *method = mono_get_method (image, token, NULL);
1315                                 printf ("LAST AOT METHOD: %s.%s.%s.\n", method->klass->name_space, method->klass->name, method->name);
1316                         }
1317         }
1318
1319         if (!aot_module->methods_loaded)
1320                 aot_module->methods_loaded = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 1);
1321
1322         if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
1323                 return code;
1324         else
1325                 aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
1326
1327         p = info;
1328         *klass = decode_klass_info (aot_module, p, &p);
1329
1330         if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1331                 MonoMethod *method = mono_get_method (image, token, NULL);
1332                 char *full_name = mono_method_full_name (method, TRUE);
1333                 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p %p\n", full_name, code, info);
1334                 g_free (full_name);
1335         }
1336
1337         if (aot_module->opts & MONO_OPT_SHARED)
1338                 used_strings = decode_value (p, &p);
1339         else
1340                 used_strings = 0;
1341
1342         for (i = 0; i < used_strings; i++) {
1343                 guint string_token = decode_value (p, &p);
1344                 mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (string_token));
1345         }
1346
1347         if (aot_module->opts & MONO_OPT_SHARED) 
1348                 keep_patches = FALSE;
1349
1350         got_index = decode_value (p, &p);
1351         keep_patches = FALSE;
1352
1353         n_patches = decode_value (p, &p);
1354
1355         if (n_patches) {
1356                 MonoJumpInfo *patches;
1357                 guint32 *got_slots;
1358
1359                 if (keep_patches)
1360                         mp = domain->mp;
1361                 else
1362                         mp = mono_mempool_new ();
1363
1364                 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1365                 if (patches == NULL)
1366                         goto cleanup;
1367
1368                 /* Do this outside the lock to avoid deadlocks */
1369                 LeaveCriticalSection (&aot_mutex);
1370
1371                 for (pindex = 0; pindex < n_patches; ++pindex) {
1372                         MonoJumpInfo *ji = &patches [pindex];
1373
1374                         if (is_got_patch (ji->type)) {
1375                                 if (!aot_module->got [got_slots [pindex]])
1376                                         aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (NULL, domain, code, ji, TRUE);
1377                                 ji->type = MONO_PATCH_INFO_NONE;
1378                         }
1379                 }
1380
1381                 EnterCriticalSection (&aot_mutex);
1382
1383                 g_free (got_slots);
1384
1385                 if (!keep_patches)
1386                         mono_mempool_destroy (mp);
1387         }
1388
1389         mono_jit_stats.methods_aot++;
1390
1391         return code;
1392
1393  cleanup:
1394         /* FIXME: The space in domain->mp is wasted */  
1395         if (aot_module->opts & MONO_OPT_SHARED)
1396                 /* No need to cache patches */
1397                 mono_mempool_destroy (mp);
1398
1399         return NULL;
1400 }
1401
1402 /**
1403  * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
1404  * method.
1405  */
1406 gpointer
1407 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1408 {
1409         gpointer res;   
1410         MonoClass *klass;
1411
1412         EnterCriticalSection (&aot_mutex);
1413         res = mono_aot_get_method_from_token_inner (domain, image, token, &klass);
1414         LeaveCriticalSection (&aot_mutex);
1415
1416         if (klass)
1417                 mono_runtime_class_init (mono_class_vtable (domain, klass));
1418
1419         return res;
1420 }
1421
1422 typedef struct {
1423         guint8 *addr;
1424         gboolean res;
1425 } IsGotEntryUserData;
1426
1427 static void
1428 check_is_got_entry (gpointer key, gpointer value, gpointer user_data)
1429 {
1430         IsGotEntryUserData *data = (IsGotEntryUserData*)user_data;
1431         MonoAotModule *aot_module = (MonoAotModule*)value;
1432
1433         if (aot_module->got && (data->addr >= (guint8*)(aot_module->got)) && (data->addr < (guint8*)(aot_module->got + aot_module->got_size)))
1434                 data->res = TRUE;
1435 }
1436
1437 gboolean
1438 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
1439 {
1440         IsGotEntryUserData user_data;
1441
1442         if (!aot_modules)
1443                 return FALSE;
1444
1445         user_data.addr = addr;
1446         user_data.res = FALSE;
1447         EnterCriticalSection (&aot_mutex);
1448         g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data);
1449         LeaveCriticalSection (&aot_mutex);
1450         
1451         return user_data.res;
1452 }
1453
1454 /*****************************************************/
1455 /*                 AOT COMPILER                      */
1456 /*****************************************************/
1457
1458 static void
1459 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1460 {
1461 #if defined(sparc)
1462         /* For solaris as, GNU as should accept the same */
1463         fprintf (fp, ".section \"%s\"\n", section_name);
1464 #elif defined(__ppc__) && defined(__MACH__)
1465         /* This needs to be made more precise on mach. */
1466         fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1467 #else
1468         fprintf (fp, "%s %d\n", section_name, subsection_index);
1469 #endif
1470 }
1471
1472 static void
1473 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1474 {
1475         const char *stype;
1476
1477         if (func)
1478                 stype = "function";
1479         else
1480                 stype = "object";
1481
1482 #if defined(sparc)
1483         fprintf (fp, "\t.type %s,#%s\n", name, stype);
1484 #elif defined(PLATFORM_WIN32)
1485
1486 #elif !(defined(__ppc__) && defined(__MACH__))
1487         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1488 #elif defined(__x86_64__) || defined(__i386__)
1489         fprintf (fp, "\t.type %s,@%s\n", name, stype);
1490 #endif
1491 }
1492
1493 static void
1494 emit_global (FILE *fp, const char *name, gboolean func)
1495 {
1496 #if  (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1497     // mach-o always uses a '_' prefix.
1498         fprintf (fp, "\t.globl _%s\n", name);
1499 #else
1500         fprintf (fp, "\t.globl %s\n", name);
1501 #endif
1502
1503         emit_symbol_type (fp, name, func);
1504 }
1505
1506 static void
1507 emit_label (FILE *fp, const char *name)
1508 {
1509 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1510     // mach-o always uses a '_' prefix.
1511         fprintf (fp, "_%s:\n", name);
1512 #else
1513         fprintf (fp, "%s:\n", name);
1514 #endif
1515
1516 #if defined(PLATFORM_WIN32)
1517         /* Emit a normal label too */
1518         fprintf (fp, "%s:\n", name);
1519 #endif
1520 }
1521
1522 static void
1523 emit_string_symbol (FILE *fp, const char *name, const char *value)
1524 {
1525         emit_section_change (fp, ".text", 1);
1526         emit_global(fp, name, FALSE);
1527         emit_label(fp, name);
1528         fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1529 }
1530
1531 #if defined(__ppc__) && defined(__MACH__)
1532 static int
1533 ilog2(register int value)
1534 {
1535     int count = -1;
1536     while (value & ~0xf) count += 4, value >>= 4;
1537     while (value) count++, value >>= 1;
1538     return count;
1539 }
1540 #endif
1541
1542 static void 
1543 emit_alignment(FILE *fp, int size)
1544 {
1545 #if defined(__ppc__) && defined(__MACH__)
1546         // the mach-o assembler specifies alignments as powers of 2.
1547         fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1548 #elif defined(__powerpc__)
1549         /* ignore on linux/ppc */
1550 #else
1551         fprintf (fp, "\t.align %d\n", size);
1552 #endif
1553 }
1554
1555 G_GNUC_UNUSED static void
1556 emit_pointer (FILE *fp, const char *target)
1557 {
1558         emit_alignment (fp, sizeof (gpointer));
1559 #if defined(__x86_64__)
1560         fprintf (fp, "\t.quad %s\n", target);
1561 #elif defined(sparc) && SIZEOF_VOID_P == 8
1562         fprintf (fp, "\t.xword %s\n", target);
1563 #else
1564         fprintf (fp, "\t.long %s\n", target);
1565 #endif
1566 }
1567
1568 static guint32
1569 mono_get_field_token (MonoClassField *field) 
1570 {
1571         MonoClass *klass = field->parent;
1572         int i;
1573
1574         for (i = 0; i < klass->field.count; ++i) {
1575                 if (field == &klass->fields [i])
1576                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1577         }
1578
1579         g_assert_not_reached ();
1580         return 0;
1581 }
1582
1583 static inline void
1584 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
1585 {
1586         guint8 *p = buf;
1587
1588         //printf ("ENCODE: %d 0x%x.\n", value, value);
1589
1590         /* 
1591          * Same encoding as the one used in the metadata, extended to handle values
1592          * greater than 0x1fffffff.
1593          */
1594         if ((value >= 0) && (value <= 127))
1595                 *p++ = value;
1596         else if ((value >= 0) && (value <= 16383)) {
1597                 p [0] = 0x80 | (value >> 8);
1598                 p [1] = value & 0xff;
1599                 p += 2;
1600         } else if ((value >= 0) && (value <= 0x1fffffff)) {
1601                 p [0] = (value >> 24) | 0xc0;
1602                 p [1] = (value >> 16) & 0xff;
1603                 p [2] = (value >> 8) & 0xff;
1604                 p [3] = value & 0xff;
1605                 p += 4;
1606         }
1607         else {
1608                 p [0] = 0xff;
1609                 p [1] = (value >> 24) & 0xff;
1610                 p [2] = (value >> 16) & 0xff;
1611                 p [3] = (value >> 8) & 0xff;
1612                 p [4] = value & 0xff;
1613                 p += 5;
1614         }
1615         if (endbuf)
1616                 *endbuf = p;
1617 }
1618
1619 static guint32
1620 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1621 {
1622         guint32 index;
1623
1624         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1625         if (index)
1626                 return index - 1;
1627         else {
1628                 index = g_hash_table_size (cfg->image_hash);
1629                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1630                 g_ptr_array_add (cfg->image_table, image);
1631                 return index;
1632         }
1633 }
1634
1635 static void
1636 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
1637 {
1638         encode_value (get_image_index (cfg, klass->image), buf, &buf);
1639         if (!klass->type_token) {
1640                 /* Array class */
1641                 g_assert (klass->rank > 0);
1642                 g_assert (klass->element_class->type_token);
1643                 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1644                 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1645                 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1646                 encode_value (klass->rank, buf, &buf);
1647         }
1648         else {
1649                 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1650                 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1651         }
1652         *endbuf = buf;
1653 }
1654
1655 static void
1656 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
1657 {
1658         guint32 token = mono_get_field_token (field);
1659
1660         encode_klass_info (cfg, field->parent, buf, &buf);
1661         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1662         encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1663         *endbuf = buf;
1664 }
1665
1666 static void
1667 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
1668 {
1669         guint32 image_index = get_image_index (acfg, method->klass->image);
1670         guint32 token = method->token;
1671         g_assert (image_index < 256);
1672         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1673
1674         encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
1675         *endbuf = buf;
1676 }
1677
1678 static gint
1679 compare_patches (gconstpointer a, gconstpointer b)
1680 {
1681         int i, j;
1682
1683         i = (*(MonoJumpInfo**)a)->ip.i;
1684         j = (*(MonoJumpInfo**)b)->ip.i;
1685
1686         if (i < j)
1687                 return -1;
1688         else
1689                 if (i > j)
1690                         return 1;
1691         else
1692                 return 0;
1693 }
1694
1695 static guint32
1696 get_got_slot (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
1697 {
1698         guint32 res;
1699
1700         switch (patch_info->type) {
1701         case MONO_PATCH_INFO_INTERNAL_METHOD:
1702                 res = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_to_got_offset_hash, patch_info->data.name));
1703                 break;
1704         default:
1705                 res = acfg->got_offset;
1706                 acfg->got_offset ++;
1707                 break;
1708         }
1709
1710         return res;
1711 }
1712
1713 static void
1714 collect_icalls (MonoAotCompile *acfg)
1715 {
1716         int mindex, index;
1717         MonoJumpInfo *patch_info;
1718
1719         for (mindex = 0; mindex < acfg->nmethods; ++mindex) {
1720                 MonoCompile *cfg;
1721
1722                 cfg = acfg->cfgs [mindex];
1723                 if (!cfg)
1724                         continue;
1725
1726                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1727                         switch (patch_info->type) {
1728                         case MONO_PATCH_INFO_INTERNAL_METHOD:
1729                                 index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1730                                 if (!index) {
1731                                         index = g_hash_table_size (acfg->icall_hash) + 1;
1732                                         g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1733                                                                                  GUINT_TO_POINTER (index));
1734                                         g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1735
1736                                         /* Allocate a GOT slot */
1737                                         g_hash_table_insert (acfg->icall_to_got_offset_hash, (gpointer)patch_info->data.name, GUINT_TO_POINTER (acfg->got_offset));
1738                                         acfg->got_offset ++;
1739                                 }
1740                                 break;
1741                         default:
1742                                 break;
1743                         }
1744                 }
1745         }
1746 }
1747
1748 static void
1749 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1750 {
1751         MonoMethod *method;
1752         FILE *tmpfp;
1753         int i, j, pindex, byte_index;
1754         guint8 *code;
1755         char *symbol;
1756         int func_alignment = 16;
1757         GPtrArray *patches;
1758         MonoJumpInfo *patch_info;
1759         MonoMethodHeader *header;
1760 #ifdef MONO_ARCH_HAVE_PIC_AOT
1761         gboolean skip;
1762         guint32 got_slot;
1763 #endif
1764
1765         tmpfp = acfg->fp;
1766         method = cfg->method;
1767         code = cfg->native_code;
1768         header = mono_method_get_header (method);
1769
1770         /* Make the labels local */
1771         symbol = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1772
1773         emit_alignment(tmpfp, func_alignment);
1774         emit_label(tmpfp, symbol);
1775         if (acfg->aot_opts.write_symbols)
1776                 emit_global (tmpfp, symbol, TRUE);
1777
1778         if (cfg->verbose_level > 0)
1779                 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
1780
1781         /* Sort relocations */
1782         patches = g_ptr_array_new ();
1783         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1784                 g_ptr_array_add (patches, patch_info);
1785         g_ptr_array_sort (patches, compare_patches);
1786
1787 #ifdef MONO_ARCH_HAVE_PIC_AOT
1788         acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1789         byte_index = 0;
1790         for (i = 0; i < cfg->code_len; i++) {
1791                 patch_info = NULL;
1792                 for (pindex = 0; pindex < patches->len; ++pindex) {
1793                         patch_info = g_ptr_array_index (patches, pindex);
1794                         if (patch_info->ip.i == i)
1795                                 break;
1796                 }
1797
1798                 skip = FALSE;
1799                 if (patch_info && (pindex < patches->len)) {
1800                         switch (patch_info->type) {
1801                         case MONO_PATCH_INFO_LABEL:
1802                         case MONO_PATCH_INFO_BB:
1803                         case MONO_PATCH_INFO_NONE:
1804                                 break;
1805                         case MONO_PATCH_INFO_GOT_OFFSET: {
1806                                 guint32 offset = mono_arch_get_patch_offset (code + i);
1807                                 fprintf (tmpfp, "\n.byte ");
1808                                 for (j = 0; j < offset; ++j)
1809                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1810                                 fprintf (tmpfp, "\n.int got - . + %d", offset);
1811
1812                                 i += offset + 4 - 1;
1813                                 skip = TRUE;
1814                                 break;
1815                         }
1816                         default:
1817                                 if (!is_got_patch (patch_info->type))
1818                                         break;
1819
1820                                 got_slot = get_got_slot (acfg, patch_info);
1821                                 fprintf (tmpfp, "\n.byte ");
1822                                 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1823                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1824 #ifdef __x86_64__
1825                                 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
1826 #elif defined(__i386__)
1827                                 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((got_slot * sizeof (gpointer))));
1828 #endif
1829
1830                                 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1831                                 skip = TRUE;
1832                         }
1833                 }
1834
1835                 if (!skip) {
1836                         if (byte_index == 0)
1837                                 fprintf (tmpfp, "\n.byte ");
1838                         fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
1839                         byte_index = (byte_index + 1) % 32;
1840                 }
1841                 else
1842                         byte_index = 0;
1843         }
1844 #else
1845         for (i = 0; i < cfg->code_len; i++) {
1846                 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1847         }
1848 #endif
1849         fprintf (tmpfp, "\n");
1850 }
1851
1852 static void
1853 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
1854 {
1855         MonoMethod *method;
1856         GList *l;
1857         FILE *tmpfp;
1858         int i, j, pindex, buf_size, n_patches;
1859         guint8 *code;
1860         char *symbol;
1861         GPtrArray *patches;
1862         MonoJumpInfo *patch_info;
1863         MonoMethodHeader *header;
1864         guint32 last_offset;
1865         guint8 *p, *buf;
1866 #ifdef MONO_ARCH_HAVE_PIC_AOT
1867         guint32 first_got_offset;
1868 #endif
1869
1870         tmpfp = acfg->fp;
1871         method = cfg->method;
1872         code = cfg->native_code;
1873         header = mono_method_get_header (method);
1874
1875         /* Make the labels local */
1876         symbol = g_strdup_printf (".Lm_%x_p", mono_metadata_token_index (method->token));
1877
1878         /* Sort relocations */
1879         patches = g_ptr_array_new ();
1880         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1881                 g_ptr_array_add (patches, patch_info);
1882         g_ptr_array_sort (patches, compare_patches);
1883
1884 #ifdef MONO_ARCH_HAVE_PIC_AOT
1885         first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
1886 #endif
1887
1888         /**********************/
1889         /* Encode method info */
1890         /**********************/
1891
1892         buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
1893         p = buf = g_malloc (buf_size);
1894
1895         encode_klass_info (acfg, method->klass, p, &p);
1896
1897         /* String table */
1898         if (cfg->opt & MONO_OPT_SHARED) {
1899                 encode_value (g_list_length (cfg->ldstr_list), p, &p);
1900                 for (l = cfg->ldstr_list; l; l = l->next) {
1901                         encode_value ((long)l->data, p, &p);
1902                 }
1903         }
1904         else
1905                 /* Used only in shared mode */
1906                 g_assert (!cfg->ldstr_list);
1907
1908 #ifdef MONO_ARCH_HAVE_PIC_AOT
1909         encode_value (first_got_offset, p, &p);
1910 #endif
1911
1912         n_patches = 0;
1913         for (pindex = 0; pindex < patches->len; ++pindex) {
1914                 patch_info = g_ptr_array_index (patches, pindex);
1915                 
1916                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1917                         (patch_info->type == MONO_PATCH_INFO_BB) ||
1918                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1919                         (patch_info->type == MONO_PATCH_INFO_NONE))
1920                         /* Nothing to do */
1921                         continue;
1922
1923                 n_patches ++;
1924         }
1925
1926         encode_value (n_patches, p, &p);
1927
1928         /* First emit the type+position table */
1929         last_offset = 0;
1930         j = 0;
1931         for (pindex = 0; pindex < patches->len; ++pindex) {
1932                 guint32 offset;
1933                 patch_info = g_ptr_array_index (patches, pindex);
1934                 
1935                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1936                         (patch_info->type == MONO_PATCH_INFO_BB) ||
1937                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1938                         (patch_info->type == MONO_PATCH_INFO_NONE))
1939                         /* Nothing to do */
1940                         continue;
1941
1942                 j ++;
1943                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1944                 offset = patch_info->ip.i - last_offset;
1945                 last_offset = patch_info->ip.i;
1946
1947 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1948                 /* Only the type is needed */
1949                 *p = patch_info->type;
1950                 p++;
1951 #else
1952                 /* Encode type+position compactly */
1953                 g_assert (patch_info->type < 64);
1954                 if (offset < 1024 - 1) {
1955                         *p = (patch_info->type << 2) + (offset >> 8);
1956                         p++;
1957                         *p = offset & ((1 << 8) - 1);
1958                         p ++;
1959                 }
1960                 else {
1961                         *p = (patch_info->type << 2) + 3;
1962                         p ++;
1963                         *p = 255;
1964                         p ++;
1965                         encode_value (offset, p, &p);
1966                 }
1967 #endif
1968         }
1969
1970         /* Then emit the other info */
1971         for (pindex = 0; pindex < patches->len; ++pindex) {
1972                 patch_info = g_ptr_array_index (patches, pindex);
1973
1974                 switch (patch_info->type) {
1975                 case MONO_PATCH_INFO_LABEL:
1976                 case MONO_PATCH_INFO_BB:
1977                 case MONO_PATCH_INFO_GOT_OFFSET:
1978                 case MONO_PATCH_INFO_NONE:
1979                         break;
1980                 case MONO_PATCH_INFO_IMAGE:
1981                         encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
1982                         break;
1983                 case MONO_PATCH_INFO_METHOD_REL:
1984                         encode_value ((gint)patch_info->data.offset, p, &p);
1985                         break;
1986                 case MONO_PATCH_INFO_SWITCH: {
1987                         gpointer *table = (gpointer *)patch_info->data.table->table;
1988                         int k;
1989
1990                         encode_value (patch_info->data.table->table_size, p, &p);
1991                         for (k = 0; k < patch_info->data.table->table_size; k++)
1992                                 encode_value ((int)(gssize)table [k], p, &p);
1993                         break;
1994                 }
1995                 case MONO_PATCH_INFO_METHODCONST:
1996                 case MONO_PATCH_INFO_METHOD:
1997                 case MONO_PATCH_INFO_METHOD_JUMP:
1998                         encode_method_ref (acfg, patch_info->data.method, p, &p);
1999                         break;
2000                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
2001                         guint32 icall_index;
2002
2003                         icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
2004                         g_assert (icall_index);
2005                         encode_value (icall_index - 1, p, &p);
2006                         break;
2007                 }
2008                 case MONO_PATCH_INFO_LDSTR: {
2009                         guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
2010                         guint32 token = patch_info->data.token->token;
2011                         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
2012                         /* 
2013                          * An optimization would be to emit shared code for ldstr 
2014                          * statements followed by a throw.
2015                          */
2016                         encode_value (image_index, p, &p);
2017                         encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
2018                         break;
2019                 }
2020                 case MONO_PATCH_INFO_DECLSEC:
2021                 case MONO_PATCH_INFO_LDTOKEN:
2022                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2023                         encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
2024                         encode_value (patch_info->data.token->token, p, &p);
2025                         break;
2026                 case MONO_PATCH_INFO_EXC_NAME: {
2027                         MonoClass *ex_class;
2028
2029                         ex_class =
2030                                 mono_class_from_name (mono_defaults.exception_class->image,
2031                                                                           "System", patch_info->data.target);
2032                         g_assert (ex_class);
2033                         encode_klass_info (acfg, ex_class, p, &p);
2034                         break;
2035                 }
2036                 case MONO_PATCH_INFO_R4:
2037                         encode_value (*((guint32 *)patch_info->data.target), p, &p);
2038                         break;
2039                 case MONO_PATCH_INFO_R8:
2040                         encode_value (*((guint32 *)patch_info->data.target), p, &p);
2041                         encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
2042                         break;
2043                 case MONO_PATCH_INFO_VTABLE:
2044                 case MONO_PATCH_INFO_CLASS_INIT:
2045                 case MONO_PATCH_INFO_CLASS:
2046                 case MONO_PATCH_INFO_IID:
2047                         encode_klass_info (acfg, patch_info->data.klass, p, &p);
2048                         break;
2049                 case MONO_PATCH_INFO_FIELD:
2050                 case MONO_PATCH_INFO_SFLDA:
2051                         encode_field_info (acfg, patch_info->data.field, p, &p);
2052                         break;
2053                 case MONO_PATCH_INFO_WRAPPER: {
2054                         encode_value (patch_info->data.method->wrapper_type, p, &p);
2055
2056                         switch (patch_info->data.method->wrapper_type) {
2057                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
2058                                 MonoMethod *m;
2059                                 guint32 image_index;
2060                                 guint32 token;
2061
2062                                 m = mono_marshal_method_from_wrapper (patch_info->data.method);
2063                                 image_index = get_image_index (acfg, m->klass->image);
2064                                 token = m->token;
2065                                 g_assert (image_index < 256);
2066                                 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
2067
2068                                 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
2069                                 break;
2070                         }
2071                         case MONO_WRAPPER_PROXY_ISINST:
2072                         case MONO_WRAPPER_LDFLD:
2073                         case MONO_WRAPPER_STFLD:
2074                         case MONO_WRAPPER_LDFLD_REMOTE:
2075                         case MONO_WRAPPER_STFLD_REMOTE:
2076                         case MONO_WRAPPER_ISINST: {
2077                                 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
2078                                 encode_klass_info (acfg, proxy_class, p, &p);
2079                                 break;
2080                         }
2081                         case MONO_WRAPPER_STELEMREF:
2082                                 break;
2083                         default:
2084                                 g_assert_not_reached ();
2085                         }
2086                         break;
2087                 }
2088                 default:
2089                         g_warning ("unable to handle jump info %d", patch_info->type);
2090                         g_assert_not_reached ();
2091                 }
2092         }
2093
2094         /* Emit method info */
2095
2096         emit_label (tmpfp, symbol);
2097
2098         g_assert (p - buf < buf_size);
2099         for (i = 0; i < p - buf; ++i) {
2100                 if ((i % 32) == 0)
2101                         fprintf (tmpfp, "\n.byte ");
2102                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2103         }
2104         fprintf (tmpfp, "\n");
2105         g_free (buf);
2106
2107         g_free (symbol);
2108 }
2109
2110 static void
2111 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
2112 {
2113         MonoMethod *method;
2114         FILE *tmpfp;
2115         int i, k, buf_size;
2116         guint32 debug_info_size;
2117         guint8 *code;
2118         char *symbol;
2119         MonoMethodHeader *header;
2120         guint8 *p, *buf, *debug_info;
2121
2122         tmpfp = acfg->fp;
2123         method = cfg->method;
2124         code = cfg->native_code;
2125         header = mono_method_get_header (method);
2126
2127         /* Make the labels local */
2128         symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
2129
2130         buf_size = header->num_clauses * 256 + 128;
2131         p = buf = g_malloc (buf_size);
2132
2133         encode_value (cfg->code_len, p, &p);
2134         encode_value (cfg->used_int_regs, p, &p);
2135
2136         /* Exception table */
2137         if (header->num_clauses) {
2138                 MonoJitInfo *jinfo = cfg->jit_info;
2139
2140                 for (k = 0; k < header->num_clauses; ++k) {
2141                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
2142
2143                         encode_value (ei->exvar_offset, p, &p);
2144
2145                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
2146                                 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
2147
2148                         encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
2149                         encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
2150                         encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
2151                 }
2152         }
2153
2154         mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
2155
2156         encode_value (debug_info_size, p, &p);
2157         if (debug_info_size) {
2158                 memcpy (p, debug_info, debug_info_size);
2159                 p += debug_info_size;
2160                 g_free (debug_info);
2161         }
2162
2163         /* Emit info */
2164
2165         emit_label (tmpfp, symbol);
2166
2167         g_assert (p - buf < buf_size);
2168         for (i = 0; i < p - buf; ++i) {
2169                 if ((i % 32) == 0)
2170                         fprintf (tmpfp, "\n.byte ");
2171                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2172         }
2173         fprintf (tmpfp, "\n");
2174         g_free (buf);
2175
2176         g_free (symbol);
2177 }
2178
2179 static void
2180 emit_klass_info (MonoAotCompile *acfg, guint32 token)
2181 {
2182         MonoClass *klass = mono_class_get (acfg->image, token);
2183         guint8 *p, *buf;
2184         int i, buf_size;
2185         char *label;
2186         FILE *tmpfp = acfg->fp;
2187
2188         buf_size = 10240;
2189         p = buf = g_malloc (buf_size);
2190
2191         g_assert (klass);
2192
2193         mono_class_init (klass);
2194
2195         /* 
2196          * Emit all the information which is required for creating vtables so
2197          * the runtime does not need to create the MonoMethod structures which
2198          * take up a lot of space.
2199          */
2200
2201         if (1) {//!MONO_CLASS_IS_INTERFACE (klass)) {
2202                 encode_value (klass->vtable_size, p, &p);
2203                 encode_value ((klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
2204                 if (klass->has_cctor)
2205                         encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
2206                 if (klass->has_finalize)
2207                         encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
2208
2209                 for (i = 0; i < klass->vtable_size; ++i) {
2210                         MonoMethod *cm = klass->vtable [i];
2211
2212                         if (cm)
2213                                 encode_method_ref (acfg, cm, p, &p);
2214                         else
2215                                 encode_value (0, p, &p);
2216                 }
2217         }
2218
2219         /* Emit the info */
2220         label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
2221         emit_label (tmpfp, label);
2222
2223         g_assert (p - buf < buf_size);
2224         for (i = 0; i < p - buf; ++i) {
2225                 if ((i % 32) == 0)
2226                         fprintf (tmpfp, "\n.byte ");
2227                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2228         }
2229         fprintf (tmpfp, "\n");
2230         g_free (buf);
2231 }
2232
2233 static gboolean
2234 str_begins_with (const char *str1, const char *str2)
2235 {
2236         int len = strlen (str2);
2237         return strncmp (str1, str2, len) == 0;
2238 }
2239
2240 static void
2241 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
2242 {
2243         gchar **args, **ptr;
2244
2245         memset (opts, 0, sizeof (*opts));
2246
2247         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
2248         for (ptr = args; ptr && *ptr; ptr ++) {
2249                 const char *arg = *ptr;
2250
2251                 if (str_begins_with (arg, "outfile=")) {
2252                         opts->outfile = g_strdup (arg + strlen ("outfile="));
2253                 } else if (str_begins_with (arg, "save-temps")) {
2254                         opts->save_temps = TRUE;
2255                 } else if (str_begins_with (arg, "write-symbols")) {
2256                         opts->write_symbols = TRUE;
2257                 } else {
2258                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
2259                         exit (1);
2260                 }
2261         }
2262 }
2263
2264 static void
2265 compile_method (MonoAotCompile *acfg, int index)
2266 {
2267         MonoCompile *cfg;
2268         MonoMethod *method;
2269         MonoJumpInfo *patch_info;
2270         gboolean skip;
2271         guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
2272         
2273         method = mono_get_method (acfg->image, token, NULL);
2274                 
2275         /* fixme: maybe we can also precompile wrapper methods */
2276         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2277                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2278                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2279                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
2280                 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
2281                 return;
2282         }
2283
2284         acfg->mcount++;
2285
2286         /* fixme: we need to patch the IP for the LMF in that case */
2287         if (method->save_lmf) {
2288                 //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
2289                 acfg->lmfcount++;
2290                 return;
2291         }
2292
2293         /*
2294          * Since these methods are the only ones which are compiled with
2295          * AOT support, and they are not used by runtime startup/shutdown code,
2296          * the runtime will not see AOT methods during AOT compilation,so it
2297          * does not need to support them by creating a fake GOT etc.
2298          */
2299         cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
2300         g_assert (cfg);
2301
2302         if (cfg->disable_aot) {
2303                 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
2304                 acfg->ocount++;
2305                 mono_destroy_compile (cfg);
2306                 return;
2307         }
2308
2309         skip = FALSE;
2310         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2311                 if (patch_info->type == MONO_PATCH_INFO_ABS) {
2312                         /* unable to handle this */
2313                         //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
2314                         skip = TRUE;    
2315                         break;
2316                 }
2317         }
2318
2319         if (skip) {
2320                 acfg->abscount++;
2321                 mono_destroy_compile (cfg);
2322                 return;
2323         }
2324
2325         /* some wrappers are very common */
2326         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2327                 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
2328                         switch (patch_info->data.method->wrapper_type) {
2329                         case MONO_WRAPPER_PROXY_ISINST:
2330                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2331                         }
2332                 }
2333
2334                 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
2335                         switch (patch_info->data.method->wrapper_type) {
2336                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2337                         case MONO_WRAPPER_STFLD:
2338                         case MONO_WRAPPER_LDFLD:
2339                         case MONO_WRAPPER_LDFLD_REMOTE:
2340                         case MONO_WRAPPER_STFLD_REMOTE:
2341                         case MONO_WRAPPER_STELEMREF:
2342                         case MONO_WRAPPER_ISINST:
2343                         case MONO_WRAPPER_PROXY_ISINST:
2344                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2345                                 break;
2346                         }
2347                 }
2348         }
2349
2350         skip = FALSE;
2351         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2352                 switch (patch_info->type) {
2353                 case MONO_PATCH_INFO_METHOD:
2354                 case MONO_PATCH_INFO_METHODCONST:
2355                         if (patch_info->data.method->wrapper_type) {
2356                                 /* unable to handle this */
2357                                 //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));
2358                                 skip = TRUE;
2359                                 break;
2360                         }
2361                         if (!patch_info->data.method->token)
2362                                 /*
2363                                  * The method is part of a constructed type like Int[,].Set (). It doesn't
2364                                  * have a token, and we can't make one, since the parent type is part of
2365                                  * assembly which contains the element type, and not the assembly which
2366                                  * referenced this type.
2367                                  */
2368                                 skip = TRUE;
2369                         break;
2370                 case MONO_PATCH_INFO_VTABLE:
2371                 case MONO_PATCH_INFO_CLASS_INIT:
2372                 case MONO_PATCH_INFO_CLASS:
2373                 case MONO_PATCH_INFO_IID:
2374                         if (!patch_info->data.klass->type_token)
2375                                 if (!patch_info->data.klass->element_class->type_token)
2376                                         skip = TRUE;
2377                         break;
2378                 default:
2379                         break;
2380                 }
2381         }
2382
2383         if (skip) {
2384                 acfg->wrappercount++;
2385                 mono_destroy_compile (cfg);
2386                 return;
2387         }
2388
2389         //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
2390
2391         acfg->cfgs [index] = cfg;
2392
2393         acfg->ccount++;
2394 }
2395
2396 int
2397 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
2398 {
2399         MonoImage *image = ass->image;
2400         char *com, *tmpfname, *opts_str, *symbol;
2401         FILE *tmpfp;
2402         int i;
2403         MonoAotCompile *acfg;
2404         MonoCompile **cfgs;
2405         char *outfile_name, *tmp_outfile_name;
2406
2407         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
2408
2409         acfg = g_new0 (MonoAotCompile, 1);
2410         acfg->icall_hash = g_hash_table_new (NULL, NULL);
2411         acfg->icall_to_got_offset_hash = g_hash_table_new (NULL, NULL);
2412         acfg->icall_table = g_ptr_array_new ();
2413         acfg->image_hash = g_hash_table_new (NULL, NULL);
2414         acfg->image_table = g_ptr_array_new ();
2415         acfg->image = image;
2416         acfg->opts = opts;
2417
2418         mono_aot_parse_options (aot_options, &acfg->aot_opts);
2419
2420         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
2421         tmpfp = fdopen (i, "w+");
2422         acfg->fp = tmpfp;
2423         g_assert (tmpfp);
2424
2425         emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
2426
2427         emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
2428
2429         opts_str = g_strdup_printf ("%d", opts);
2430         emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
2431         g_free (opts_str);
2432
2433         cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
2434         acfg->cfgs = cfgs;
2435         acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
2436         acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
2437
2438         /* Compile methods */
2439         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
2440                 compile_method (acfg, i);
2441
2442         collect_icalls (acfg);
2443
2444         /* Emit code */
2445         symbol = g_strdup_printf ("methods");
2446         emit_section_change (tmpfp, ".text", 0);
2447         emit_global (tmpfp, symbol, TRUE);
2448         emit_alignment (tmpfp, 8);
2449         emit_label (tmpfp, symbol);
2450
2451         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2452                 if (cfgs [i])
2453                         emit_method_code (acfg, cfgs [i]);
2454         }
2455
2456         symbol = g_strdup_printf ("methods_end");
2457         emit_section_change (tmpfp, ".text", 0);
2458         emit_global (tmpfp, symbol, FALSE);
2459         emit_alignment (tmpfp, 8);
2460         emit_label (tmpfp, symbol);
2461
2462         /* Emit method info */
2463         symbol = g_strdup_printf ("method_infos");
2464         emit_section_change (tmpfp, ".text", 1);
2465         emit_global (tmpfp, symbol, FALSE);
2466         emit_alignment (tmpfp, 8);
2467         emit_label (tmpfp, symbol);
2468
2469         /* To reduce size of generate assembly */
2470         symbol = g_strdup_printf ("mi");
2471         emit_label (tmpfp, symbol);
2472
2473         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2474                 if (cfgs [i])
2475                         emit_method_info (acfg, cfgs [i]);
2476         }
2477
2478         /* Emit exception info */
2479         symbol = g_strdup_printf ("ex_infos");
2480         emit_section_change (tmpfp, ".text", 1);
2481         emit_global (tmpfp, symbol, FALSE);
2482         emit_alignment (tmpfp, 8);
2483         emit_label (tmpfp, symbol);
2484
2485         /* To reduce size of generate assembly */
2486         symbol = g_strdup_printf ("ex");
2487         emit_label (tmpfp, symbol);
2488
2489         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2490                 if (cfgs [i])
2491                         emit_exception_debug_info (acfg, cfgs [i]);
2492         }
2493
2494         /* Emit class info */
2495         symbol = g_strdup_printf ("class_infos");
2496         emit_section_change (tmpfp, ".text", 1);
2497         emit_global (tmpfp, symbol, FALSE);
2498         emit_alignment (tmpfp, 8);
2499         emit_label (tmpfp, symbol);
2500
2501         for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
2502                 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
2503
2504         symbol = g_strdup_printf ("class_info_offsets");
2505         emit_section_change (tmpfp, ".text", 1);
2506         emit_global (tmpfp, symbol, FALSE);
2507         emit_alignment (tmpfp, 8);
2508         emit_label(tmpfp, symbol);
2509
2510         for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
2511                 const char *sep;
2512                 if ((i % 32) == 0) {
2513                         fprintf (tmpfp, "\n.long ");
2514                         sep = "";
2515                 }
2516                 else
2517                         sep = ",";
2518
2519                 symbol = g_strdup_printf (".LK_I_%x", i);
2520                 fprintf (tmpfp, "%s%s - class_infos", sep, symbol);
2521         }
2522         fprintf (tmpfp, "\n");
2523
2524         /*
2525          * The icall and image tables are small but referenced in a lot of places.
2526          * So we emit them at once, and reference their elements by an index.
2527          */
2528
2529         /* Emit icall table */
2530
2531         symbol = g_strdup_printf ("mono_icall_table");
2532         emit_section_change (tmpfp, ".text", 1);
2533         emit_global(tmpfp, symbol, FALSE);
2534         emit_alignment(tmpfp, 8);
2535         emit_label(tmpfp, symbol);
2536         fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
2537         for (i = 0; i < acfg->icall_table->len; i++)
2538                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
2539
2540         /* Emit image table */
2541
2542         symbol = g_strdup_printf ("mono_image_table");
2543         emit_section_change (tmpfp, ".text", 1);
2544         emit_global(tmpfp, symbol, FALSE);
2545         emit_alignment(tmpfp, 8);
2546         emit_label(tmpfp, symbol);
2547         fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
2548         for (i = 0; i < acfg->image_table->len; i++) {
2549                 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
2550                 MonoAssemblyName *aname = &image->assembly->aname;
2551
2552                 /* FIXME: Support multi-module assemblies */
2553                 g_assert (image->assembly->image == image);
2554
2555                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
2556                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
2557                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
2558                 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
2559
2560                 emit_alignment (tmpfp, 8);
2561                 fprintf (tmpfp, ".long %d\n", aname->flags);
2562                 fprintf (tmpfp, ".long %d\n", aname->major);
2563                 fprintf (tmpfp, ".long %d\n", aname->minor);
2564                 fprintf (tmpfp, ".long %d\n", aname->build);
2565                 fprintf (tmpfp, ".long %d\n", aname->revision);
2566         }
2567
2568 #ifdef MONO_ARCH_HAVE_PIC_AOT
2569         /* Emit GOT */
2570
2571         /* Don't make GOT global so accesses to it don't need relocations */
2572         symbol = g_strdup_printf ("got");
2573         emit_section_change (tmpfp, ".bss", 1);
2574         emit_alignment (tmpfp, 8);
2575         emit_label(tmpfp, symbol);
2576         if (acfg->got_offset > 0)
2577                 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2578
2579         printf ("GOT SIZE: %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2580
2581         symbol = g_strdup_printf ("got_addr");
2582         emit_section_change (tmpfp, ".data", 1);
2583         emit_global (tmpfp, symbol, FALSE);
2584         emit_alignment (tmpfp, 8);
2585         emit_label(tmpfp, symbol);
2586         emit_pointer (tmpfp, "got");
2587
2588         symbol = g_strdup_printf ("got_size");
2589         emit_section_change (tmpfp, ".data", 1);
2590         emit_global (tmpfp, symbol, FALSE);
2591         emit_alignment (tmpfp, 8);
2592         emit_label(tmpfp, symbol);
2593         fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2594 #endif
2595
2596         symbol = g_strdup_printf ("method_offsets");
2597         emit_section_change (tmpfp, ".text", 1);
2598         emit_global (tmpfp, symbol, FALSE);
2599         emit_alignment (tmpfp, 8);
2600         emit_label(tmpfp, symbol);
2601
2602         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2603                 const char *sep;
2604                 if ((i % 32) == 0) {
2605                         fprintf (tmpfp, "\n.long ");
2606                         sep = "";
2607                 }
2608                 else
2609                         sep = ",";
2610                 if (cfgs [i]) {
2611                         symbol = g_strdup_printf (".Lm_%x", i + 1);
2612                         fprintf (tmpfp, "%s%s-methods", sep, symbol);
2613                 }
2614                 else
2615                         fprintf (tmpfp, "%s0xffffffff", sep);
2616         }
2617         fprintf (tmpfp, "\n");
2618
2619         symbol = g_strdup_printf ("method_info_offsets");
2620         emit_section_change (tmpfp, ".text", 1);
2621         emit_global (tmpfp, symbol, FALSE);
2622         emit_alignment (tmpfp, 8);
2623         emit_label(tmpfp, symbol);
2624
2625         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2626                 const char *sep;
2627                 if ((i % 32) == 0) {
2628                         fprintf (tmpfp, "\n.long ");
2629                         sep = "";
2630                 }
2631                 else
2632                         sep = ",";
2633                 if (cfgs [i]) {
2634                         symbol = g_strdup_printf (".Lm_%x_p", i + 1);
2635                         fprintf (tmpfp, "%s%s - mi", sep, symbol);
2636                 }
2637                 else
2638                         fprintf (tmpfp, "%s0", sep);
2639         }
2640         fprintf (tmpfp, "\n");
2641
2642         symbol = g_strdup_printf ("ex_info_offsets");
2643         emit_section_change (tmpfp, ".text", 1);
2644         emit_global (tmpfp, symbol, FALSE);
2645         emit_alignment (tmpfp, 8);
2646         emit_label(tmpfp, symbol);
2647
2648         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2649                 const char *sep;
2650                 if ((i % 32) == 0) {
2651                         fprintf (tmpfp, "\n.long ");
2652                         sep = "";
2653                 }
2654                 else
2655                         sep = ",";
2656                 if (cfgs [i]) {
2657                         symbol = g_strdup_printf (".Le_%x_p", i + 1);
2658                         fprintf (tmpfp, "%s%s - ex", sep, symbol);
2659                 }
2660                 else
2661                         fprintf (tmpfp, "%s0", sep);
2662         }
2663         fprintf (tmpfp, "\n");
2664
2665         fclose (tmpfp);
2666
2667 #if defined(__x86_64__)
2668         com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
2669 #elif defined(sparc) && SIZEOF_VOID_P == 8
2670         com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
2671 #else
2672         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
2673         
2674 #endif
2675         printf ("Executing the native assembler: %s\n", com);
2676         if (system (com) != 0) {
2677                 g_free (com);
2678                 return 1;
2679         }
2680
2681         g_free (com);
2682
2683         if (acfg->aot_opts.outfile)
2684                 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
2685         else
2686                 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
2687
2688         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
2689
2690 #if defined(sparc)
2691         com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
2692 #elif defined(__ppc__) && defined(__MACH__)
2693         com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
2694 #elif defined(PLATFORM_WIN32)
2695         com = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, tmpfname);
2696 #else
2697         com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
2698 #endif
2699         printf ("Executing the native linker: %s\n", com);
2700         if (system (com) != 0) {
2701                 g_free (tmp_outfile_name);
2702                 g_free (outfile_name);
2703                 g_free (com);
2704                 return 1;
2705         }
2706
2707         g_free (com);
2708         com = g_strdup_printf ("%s.o", tmpfname);
2709         unlink (com);
2710         g_free (com);
2711         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
2712         printf ("Stripping the binary: %s\n", com);
2713         system (com);
2714         g_free (com);*/
2715
2716         rename (tmp_outfile_name, outfile_name);
2717
2718         g_free (tmp_outfile_name);
2719         g_free (outfile_name);
2720
2721         printf ("Compiled %d out of %d methods (%d%%)\n", acfg->ccount, acfg->mcount, acfg->mcount ? (acfg->ccount*100)/acfg->mcount : 100);
2722         printf ("%d methods contain absolute addresses (%d%%)\n", acfg->abscount, acfg->mcount ? (acfg->abscount*100)/acfg->mcount : 100);
2723         printf ("%d methods contain wrapper references (%d%%)\n", acfg->wrappercount, acfg->mcount ? (acfg->wrappercount*100)/acfg->mcount : 100);
2724         printf ("%d methods contain lmf pointers (%d%%)\n", acfg->lmfcount, acfg->mcount ? (acfg->lmfcount*100)/acfg->mcount : 100);
2725         printf ("%d methods have other problems (%d%%)\n", acfg->ocount, acfg->mcount ? (acfg->ocount*100)/acfg->mcount : 100);
2726         if (acfg->aot_opts.save_temps)
2727                 printf ("Retained input file.\n");
2728         else
2729                 unlink (tmpfname);
2730
2731         return 0;
2732 }
2733
2734 #else
2735 /* AOT disabled */
2736
2737 void
2738 mono_aot_init (void)
2739 {
2740 }
2741
2742 MonoJitInfo*
2743 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
2744 {
2745         return NULL;
2746 }
2747
2748 gboolean
2749 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2750 {
2751         return FALSE;
2752 }
2753
2754 int
2755 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
2756 {
2757         return 0;
2758 }
2759 #endif