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