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