Tue Sep 9 16:33:07 CEST 2003 Paolo Molaro <lupus@ximian.com>
[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/os/gc_wrapper.h>
34
35 #include "mini.h"
36
37 #ifdef PLATFORM_WIN32
38 #define SHARED_EXT ".dll"
39 #else
40 #define SHARED_EXT ".so"
41 #endif
42
43 typedef struct MonoAotMethod {
44         MonoJitInfo *info;
45         MonoJumpInfo *patch_info;
46 } MonoAotMethod;
47
48 typedef struct MonoAotModule {
49         /* Optimization flags used to compile the module */
50         guint32 opts;
51         /* Maps MonoMethods to MonoAotMethodInfos */
52         MonoGHashTable *methods;
53         char **icall_table;
54         MonoImage **image_table;
55         guint32* methods_present_table;
56 } MonoAotModule;
57
58 typedef struct MonoAotCompile {
59         FILE *fp;
60         GHashTable *ref_hash;
61         GHashTable *icall_hash;
62         GPtrArray *icall_table;
63         GHashTable *image_hash;
64         GPtrArray *image_table;
65 } MonoAotCompile;
66
67 static MonoGHashTable *aot_modules;
68
69 static CRITICAL_SECTION aot_mutex;
70
71 static MonoClass * 
72 decode_class_info (MonoAotModule *module, gpointer *data)
73 {
74         MonoImage *image;
75         MonoClass *klass;
76         
77         image = module->image_table [(guint32)data [1]];
78         g_assert (image);
79
80         if (data [0]) {
81                 return mono_class_get (image, (guint32)data [0]);
82         } else {
83                 klass = decode_class_info (module, data [3]);
84                 return mono_array_class_get (klass, (guint32)data [2]);
85         }
86
87         return NULL;
88 }
89
90 static void
91 load_aot_module (MonoAssembly *assembly, gpointer user_data)
92 {
93         char *aot_name;
94         MonoAotModule *info;
95         gboolean usable = TRUE;
96         char *saved_guid = NULL;
97         char *aot_version = NULL;
98         char *opt_flags = NULL;
99
100         if (mono_no_aot)
101                 return;
102
103         aot_name = g_strdup_printf ("%s.so", assembly->image->name);
104
105         assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
106
107         if (!assembly->aot_module)
108                 return;
109
110         g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
111         g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
112         g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
113
114         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
115                 /*printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);*/
116                 usable = FALSE;
117         }
118         else
119                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
120                         /*printf ("AOT module %s is out of date.\n", aot_name);*/
121                         usable = FALSE;
122                 }
123
124         if (!usable) {
125                 g_free (aot_name);
126                 g_module_close (assembly->aot_module);
127                 assembly->aot_module = NULL;
128                 return;
129         }
130
131         /*
132          * It seems that MonoGHashTables are in the GC heap, so structures
133          * containing them must be in the GC heap as well :(
134          */
135 #ifdef HAVE_BOEHM_GC
136         info = GC_MALLOC (sizeof (MonoAotModule));
137 #else
138         info = g_new0 (MonoAotModule, 1);
139 #endif
140         info->methods = mono_g_hash_table_new (NULL, NULL);
141         sscanf (opt_flags, "%d", &info->opts);
142
143         /* Read image table */
144         {
145                 guint32 table_len, i;
146                 char *table = NULL;
147
148                 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
149                 g_assert (table);
150
151                 table_len = *(guint32*)table;
152                 table += sizeof (guint32);
153                 info->image_table = g_new0 (MonoImage*, table_len);
154                 for (i = 0; i < table_len; ++i) {
155                         info->image_table [i] = mono_image_loaded_by_guid (table);
156                         if (!info->image_table [i]) {
157                                 /*printf ("AOT module %s is out of date.\n", aot_name);*/
158                                 g_free (info->methods);
159                                 g_free (info->image_table);
160                                 g_free (info);
161                                 g_free (aot_name);
162                                 g_module_close (assembly->aot_module);
163                                 assembly->aot_module = NULL;
164                                 return;
165                         }
166                         table += strlen (table) + 1;
167                 }
168         }
169
170         /* Read icall table */
171         {
172                 guint32 table_len, i;
173                 char *table = NULL;
174
175                 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
176                 g_assert (table);
177
178                 table_len = *(guint32*)table;
179                 table += sizeof (guint32);
180                 info->icall_table = g_new0 (char*, table_len);
181                 for (i = 0; i < table_len; ++i) {
182                         info->icall_table [i] = table;
183                         table += strlen (table) + 1;
184                 }
185         }
186
187         /* Read methods present table */
188         g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
189         g_assert (info->methods_present_table);
190
191         EnterCriticalSection (&aot_mutex);
192         mono_g_hash_table_insert (aot_modules, assembly, info);
193         LeaveCriticalSection (&aot_mutex);
194
195         /*printf ("Loaded AOT Module for %s.\n", assembly->image->name);*/
196 }
197
198 void
199 mono_aot_init (void)
200 {
201         InitializeCriticalSection (&aot_mutex);
202
203         aot_modules = mono_g_hash_table_new (NULL, NULL);
204
205         mono_install_assembly_load_hook (load_aot_module, NULL);
206 }
207  
208 static MonoJitInfo *
209 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
210 {
211         MonoClass *klass = method->klass;
212         MonoAssembly *ass = klass->image->assembly;
213         MonoJumpInfo *patch_info = NULL;
214         GModule *module = ass->aot_module;
215         char *method_label, *info_label;
216         guint8 *code = NULL;
217         gpointer *info;
218         guint code_len, used_int_regs, used_strings;
219         MonoAotModule *aot_module;
220         MonoAotMethod *minfo;
221         MonoJitInfo *jinfo;
222         MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
223         int i;
224
225         if (!module)
226                 return NULL;
227
228         if (!method->token)
229                 return NULL;
230
231         aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
232
233         g_assert (klass->inited);
234
235         minfo = mono_g_hash_table_lookup (aot_module->methods, method);
236         if (minfo) {
237                 /* Duplicate jinfo */
238                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
239                 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
240                 if (jinfo->clauses) {
241                         jinfo->clauses = 
242                                 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
243                         memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
244                 }
245
246                 /* This method was already loaded in another appdomain */
247                 if (aot_module->opts & MONO_OPT_SHARED)
248                         /* Use the same method in the new appdomain */
249                         ;
250                 else if (!minfo->patch_info)
251                         /* Use the same method in the new appdomain */
252                         ;                       
253                 else {
254                         /* Create a copy of the original method and apply relocations */
255
256                         code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
257                         memcpy (code, minfo->info->code_start, minfo->info->code_size);
258
259                         //printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
260
261                         /* Do this outside the lock to avoid deadlocks */
262                         LeaveCriticalSection (&aot_mutex);
263                         mono_arch_patch_code (method, domain, code, minfo->patch_info);
264                         EnterCriticalSection (&aot_mutex);
265
266                         /* Relocate jinfo */
267                         jinfo->code_start = code;
268                         if (jinfo->clauses) {
269                                 for (i = 0; i < header->num_clauses; ++i) {
270                                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
271                                         gint32 offset = code - (guint8*)minfo->info->code_start;
272
273                                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
274                                                 ei->data.filter = (guint8*)ei->data.filter + offset;
275                                         ei->try_start = (guint8*)ei->try_start + offset;
276                                         ei->try_end = (guint8*)ei->try_end + offset;
277                                         ei->handler_start = (guint8*)ei->handler_start + offset;
278                                 }
279                         }
280                 }
281
282                 return jinfo;
283         }
284
285         /* Do a fast check to see whenever the method exists */
286         {
287                 guint32 index = mono_metadata_token_index (method->token) - 1;
288                 guint32 w;
289                 w = aot_module->methods_present_table [index / 32];
290                 if (! (w & (1 << (index % 32)))) {
291                         //printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
292                         return NULL;
293                 }
294         }
295
296         method_label = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
297
298         if (!g_module_symbol (module, method_label, (gpointer *)&code)) {
299                 g_free (method_label);          
300
301                 return NULL;
302         }
303
304         info_label = g_strdup_printf ("%s_p", method_label);
305         if (!g_module_symbol (module, info_label, (gpointer *)&info)) {
306                 g_free (method_label);          
307                 g_free (info_label);
308
309                 return NULL;
310         }
311
312         {
313                 static int count = 0;
314
315                 count ++;
316
317                 if (getenv ("MONO_LASTAOT")) {
318                         if (count > atoi(getenv ("MONO_LASTAOT"))) {
319                                 return NULL;
320                         }
321                         else
322                                 if (count == atoi(getenv ("MONO_LASTAOT")))
323                                         printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
324                 }
325         }
326
327 #ifdef HAVE_BOEHM_GC
328         minfo = GC_MALLOC (sizeof (MonoAotMethod));
329 #else
330         minfo = g_new0 (MonoAotMethod, 1);
331 #endif
332
333         jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
334
335         code_len = GPOINTER_TO_UINT (*((gpointer **)info));
336         info++;
337         used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
338         info++;
339
340         //printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
341
342         /* Exception table */
343         if (header->num_clauses) {
344                 jinfo->clauses = 
345                         mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
346                 jinfo->num_clauses = header->num_clauses;
347
348                 jinfo->exvar_offset = GPOINTER_TO_UINT (*((gpointer**)info));
349                 info ++;
350
351                 for (i = 0; i < header->num_clauses; ++i) {
352                         MonoExceptionClause *ec = &header->clauses [i];                         
353                         MonoJitExceptionInfo *ei = &jinfo->clauses [i];
354
355                         ei->flags = ec->flags;
356                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
357                                 ei->data.filter = code + GPOINTER_TO_UINT (*((gpointer**)info));
358                         else
359                                 ei->data.token = GPOINTER_TO_UINT (*((gpointer**)info));
360                         info ++;
361                         ei->try_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
362                         info ++;
363                         ei->try_end = code + GPOINTER_TO_UINT (*((gpointer**)info));
364                         info ++;
365                         ei->handler_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
366                         info ++;
367                 }
368         }
369
370         if (aot_module->opts & MONO_OPT_SHARED) {
371                 used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
372                 info++;
373         }
374         else
375                 used_strings = 0;
376
377         for (i = 0; i < used_strings; i++) {
378                 guint token =  GPOINTER_TO_UINT (*((gpointer **)info));
379                 info++;
380                 mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
381         }
382
383         if (*info) {
384                 MonoMemPool *mp = mono_mempool_new (); 
385                 MonoImage *image;
386                 guint8 *page_start;
387                 gpointer *table;
388                 int pages;
389                 int i, err;
390                 guint32 last_offset;
391
392                 last_offset = 0;
393                 while (*info) {
394                         MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
395                         guint8 b1, b2;
396
397                         b1 = *(guint8*)info;
398                         b2 = *((guint8*)info + 1);
399
400                         info = (gpointer*)((guint8*)info + 2);
401
402                         ji->type = b1 >> 2;
403
404                         if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
405                                 ji->ip.i = GPOINTER_TO_UINT (*info);
406                                 info ++;
407                         }
408                         else
409                                 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
410
411                         ji->ip.i += last_offset;
412                         last_offset = ji->ip.i;
413                         //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
414
415                         gpointer *data = *((gpointer **)info);
416
417                         switch (ji->type) {
418                         case MONO_PATCH_INFO_CLASS:
419                                 ji->data.klass = decode_class_info (aot_module, data);
420                                 g_assert (ji->data.klass);
421                                 mono_class_init (ji->data.klass);
422                                 break;
423                         case MONO_PATCH_INFO_VTABLE:
424                                 ji->data.klass = decode_class_info (aot_module, data);
425                                 g_assert (ji->data.klass);
426                                 mono_class_init (ji->data.klass);
427                                 break;
428                         case MONO_PATCH_INFO_IMAGE:
429                                 ji->data.image = aot_module->image_table [(guint32)data];
430                                 g_assert (ji->data.image);
431                                 break;
432                         case MONO_PATCH_INFO_METHOD:
433                         case MONO_PATCH_INFO_METHODCONST: {
434                                 guint32 image_index, token;
435
436                                 image_index = (guint32)data >> 24;
437                                 token = MONO_TOKEN_METHOD_DEF | ((guint32)data & 0xffffff);
438
439                                 image = aot_module->image_table [image_index];
440                                 ji->data.method = mono_get_method (image, token, NULL);
441                                 g_assert (ji->data.method);
442                                 mono_class_init (ji->data.method->klass);
443
444                                 break;
445                         }
446                         case MONO_PATCH_INFO_FIELD:
447                         case MONO_PATCH_INFO_SFLDA:
448                                 image = aot_module->image_table [(guint32)data [1]];
449                                 g_assert (image);
450                                 ji->data.field = mono_field_from_token (image, (guint32)data [0], NULL);
451                                 mono_class_init (ji->data.field->parent);
452                                 g_assert (ji->data.field);
453                                 break;
454                         case MONO_PATCH_INFO_INTERNAL_METHOD:
455                                 ji->data.name = aot_module->icall_table [(guint32)data];
456                                 g_assert (ji->data.name);
457                                 //printf ("A: %s.\n", ji->data.name);
458                                 break;
459                         case MONO_PATCH_INFO_SWITCH:
460                                 ji->table_size = (int)data [0];
461                                 table = g_new (gpointer, ji->table_size);
462                                 ji->data.target = table;
463                                 for (i = 0; i < ji->table_size; i++) {
464                                         table [i] = data [i + 1];
465                                 }
466                                 break;
467                         case MONO_PATCH_INFO_R4:
468                         case MONO_PATCH_INFO_R8:
469                                 ji->data.target = data;
470                                 break;
471                         case MONO_PATCH_INFO_LDSTR:
472                         case MONO_PATCH_INFO_LDTOKEN:
473                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
474                                 ji->data.target = *data;
475                                 break;
476                         case MONO_PATCH_INFO_EXC_NAME:
477                                 ji->data.klass = decode_class_info (aot_module, data);
478                                 g_assert (ji->data.klass);
479                                 mono_class_init (ji->data.klass);
480                                 ji->data.name = ji->data.klass->name;
481                                 break;
482                         case MONO_PATCH_INFO_METHOD_REL:
483                                 ji->data.offset = (int)data [0];
484                                 break;
485                         default:
486                                 g_warning ("unhandled type %d", ji->type);
487                                 g_assert_not_reached ();
488                         }
489
490                         info++;
491                         ji->next = patch_info;
492                         patch_info = ji;
493                 }
494
495 #ifndef PLATFORM_WIN32
496                 /* disable write protection */
497                 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
498                 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
499                 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
500                 g_assert (err == 0);
501 #else
502                 {
503                         DWORD oldp;
504                         g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
505                 }
506 #endif
507
508                 /* Do this outside the lock to avoid deadlocks */
509                 LeaveCriticalSection (&aot_mutex);
510                 mono_arch_patch_code (method, domain, code, patch_info);
511                 EnterCriticalSection (&aot_mutex);
512
513                 if (aot_module->opts & MONO_OPT_SHARED)
514                         /* No need to cache this */
515                         mono_mempool_destroy (mp);
516                 else
517                         minfo->patch_info = patch_info;
518         }
519
520         g_free (info_label);
521         g_free (method_label);
522
523         mono_jit_stats.methods_aot++;
524
525         {
526                 jinfo->code_size = code_len;
527                 jinfo->used_regs = used_int_regs;
528                 jinfo->method = method;
529                 jinfo->code_start = code;
530                 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
531
532                 minfo->info = jinfo;
533                 mono_g_hash_table_insert (aot_module->methods, method, minfo);
534
535                 return jinfo;
536         }
537 }
538
539 gpointer
540 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
541 {
542         MonoJitInfo *info;
543
544         EnterCriticalSection (&aot_mutex);
545         info = mono_aot_get_method_inner (domain, method);
546         LeaveCriticalSection (&aot_mutex);
547
548         /* Do this outside the lock */
549         if (info) {
550                 mono_jit_info_table_add (domain, info);
551                 return info->code_start;
552         }
553         else
554                 return NULL;
555 }
556
557 #if 0
558 static void
559 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
560 {
561         int i;
562
563         fprintf (fp, ".globl %s\n", name);
564         fprintf (fp, ".text 1 \n\t.align %d\n", align);
565         fprintf (fp, "\t.type %s,@object\n", name);
566         fprintf (fp, "\t.size %s,%d\n", name, size);
567         fprintf (fp, "%s:\n", name);
568         for (i = 0; i < size; i++) { 
569                 fprintf (fp, ".byte %d\n", buf [i]);
570         }
571         
572 }
573 #endif
574
575 static void
576 write_string_symbol (FILE *fp, const char *name, const char *value)
577 {
578         fprintf (fp, ".globl %s\n", name);
579         fprintf (fp, ".text 1\n");
580         fprintf (fp, "%s:\n", name);
581         fprintf (fp, "\t.string \"%s\"\n", value);
582 }
583
584 static guint32
585 mono_get_field_token (MonoClassField *field) 
586 {
587         MonoClass *klass = field->parent;
588         int i;
589
590         for (i = 0; i < klass->field.count; ++i) {
591                 if (field == &klass->fields [i])
592                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
593         }
594
595         g_assert_not_reached ();
596         return 0;
597 }
598
599 static guint32
600 get_image_index (MonoAotCompile *cfg, MonoImage *image)
601 {
602         guint32 index;
603
604         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
605         if (index)
606                 return index - 1;
607         else {
608                 index = g_hash_table_size (cfg->image_hash);
609                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
610                 g_ptr_array_add (cfg->image_table, image);
611                 return index;
612         }
613 }
614
615 static void
616 emit_image_index (MonoAotCompile *cfg, MonoImage *image)
617 {
618         guint32 image_index;
619
620         image_index = get_image_index (cfg, image);
621
622         fprintf (cfg->fp, "\t.long %d\n", image_index);
623 }
624
625 static char *
626 cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
627 {
628         char *l1, *el = NULL;
629
630         if ((l1 = g_hash_table_lookup (cfg->ref_hash, klass))) 
631                 return l1;
632
633         if (!klass->type_token) {
634                 g_assert (klass->rank > 0);
635                 el = cond_emit_klass_label (cfg, klass->element_class);
636         }
637         
638         fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
639         l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass);
640         fprintf (cfg->fp, "%s:\n", l1);
641         fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
642         emit_image_index (cfg, klass->image);
643
644         if (el) {
645                 fprintf (cfg->fp, "\t.long %d\n", klass->rank); 
646                 fprintf (cfg->fp, "\t.long %s\n", el);
647         }
648
649         g_hash_table_insert (cfg->ref_hash, klass, l1);
650
651         return l1;
652 }
653
654 static char *
655 cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
656 {
657         MonoClassField *field = patch_info->data.field;
658         char *l1;
659         guint token;
660
661         if ((l1 = g_hash_table_lookup (cfg->ref_hash, field))) 
662                 return l1;
663
664         fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
665         token = mono_get_field_token (field);
666         l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
667         fprintf (cfg->fp, "%s:\n", l1);
668         fprintf (cfg->fp, "\t.long 0x%08x\n", token);
669         g_assert (token);
670         emit_image_index (cfg, field->parent->image);
671                 
672         g_hash_table_insert (cfg->ref_hash, field, l1);
673
674         return l1;
675 }
676
677 static gint
678 compare_patches (gconstpointer a, gconstpointer b)
679 {
680         int i, j;
681
682         i = (*(MonoJumpInfo**)a)->ip.i;
683         j = (*(MonoJumpInfo**)b)->ip.i;
684
685         if (i < j)
686                 return -1;
687         else
688                 if (i > j)
689                         return 1;
690         else
691                 return 0;
692 }
693
694 static void
695 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
696 {
697         MonoMethod *method;
698         GList *l;
699         FILE *tmpfp;
700         int i, j, k, pindex;
701         guint8 *code, *mname;
702         int func_alignment = 16;
703         GPtrArray *patches;
704         MonoJumpInfo *patch_info;
705         MonoMethodHeader *header;
706
707         tmpfp = acfg->fp;
708         method = cfg->method;
709         code = cfg->native_code;
710         header = ((MonoMethodNormal*)method)->header;
711
712         fprintf (tmpfp, ".text 0\n");
713         mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
714         fprintf (tmpfp, "\t.align %d\n", func_alignment);
715         fprintf (tmpfp, ".globl %s\n", mname);
716         fprintf (tmpfp, "\t.type %s,@function\n", mname);
717         fprintf (tmpfp, "%s:\n", mname);
718
719         for (i = 0; i < cfg->code_len; i++) 
720                 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
721
722         fprintf (tmpfp, ".text 1\n");
723
724         /* Sort relocations */
725         patches = g_ptr_array_new ();
726         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
727                 g_ptr_array_add (patches, patch_info);
728         g_ptr_array_sort (patches, compare_patches);
729
730         j = 0;
731         for (pindex = 0; pindex < patches->len; ++pindex) {
732                 patch_info = g_ptr_array_index (patches, pindex);
733                 switch (patch_info->type) {
734                 case MONO_PATCH_INFO_LABEL:
735                 case MONO_PATCH_INFO_BB:
736                         /* relative jumps are no problem, there is no need to handle then here */
737                         break;
738                 case MONO_PATCH_INFO_SWITCH: {
739                         gpointer *table = (gpointer *)patch_info->data.target;
740                         int k;
741
742                         fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
743                         fprintf (tmpfp, "%s_p_%d:\n", mname, j);
744                         fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
745                         
746                         for (k = 0; k < patch_info->table_size; k++) {
747                                 fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
748                         }
749                         j++;
750                         break;
751                 }
752                 case MONO_PATCH_INFO_INTERNAL_METHOD: {
753                         guint32 icall_index;
754
755                         icall_index = (guint32)g_hash_table_lookup (acfg->icall_hash, patch_info->data.name);
756                         if (!icall_index) {
757                                 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
758                                 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
759                                                                          GUINT_TO_POINTER (icall_index));
760                                 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
761                         }
762                         patch_info->data.name = g_strdup_printf ("%d", icall_index - 1);
763                         j++;
764                         break;
765                 }
766                 case MONO_PATCH_INFO_METHODCONST:
767                 case MONO_PATCH_INFO_METHOD: {
768                         /*
769                          * The majority of patches are for methods, so we emit
770                          * them inline instead of defining a label for them to
771                          * decrease the number of relocations.
772                          */
773                         guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
774                         guint32 token = patch_info->data.method->token;
775                         g_assert (image_index < 256);
776                         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
777
778                         patch_info->data.name = 
779                                 g_strdup_printf ("%d", (image_index << 24) + (mono_metadata_token_index (token)));
780                         j++;
781                         break;
782                 }
783                 case MONO_PATCH_INFO_FIELD:
784                         patch_info->data.name = cond_emit_field_label (acfg, patch_info);
785                         j++;
786                         break;
787                 case MONO_PATCH_INFO_CLASS:
788                         patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
789                         j++;
790                         break;
791                 case MONO_PATCH_INFO_IMAGE:
792                         patch_info->data.name = g_strdup_printf ("%d", get_image_index (acfg, patch_info->data.image));
793                         j++;
794                         break;
795                 case MONO_PATCH_INFO_EXC_NAME: {
796                         MonoClass *ex_class;
797                         
798                         ex_class =
799                                 mono_class_from_name (mono_defaults.exception_class->image,
800                                                                           "System", patch_info->data.target);
801                         g_assert (ex_class);
802                         patch_info->data.name = cond_emit_klass_label (acfg, ex_class);
803                         j++;
804                         break;
805                 }
806                 case MONO_PATCH_INFO_R4:
807                         fprintf (tmpfp, "\t.align 8\n");
808                         fprintf (tmpfp, "%s_p_%d:\n", mname, j);
809                         fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));     
810                         j++;
811                         break;
812                 case MONO_PATCH_INFO_R8:
813                         fprintf (tmpfp, "\t.align 8\n");
814                         fprintf (tmpfp, "%s_p_%d:\n", mname, j);
815                         fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
816                         fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
817                         j++;
818                         break;
819                 case MONO_PATCH_INFO_METHOD_REL:
820                         fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
821                         fprintf (tmpfp, "%s_p_%d:\n", mname, j);
822                         fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
823                         j++;
824                         break;
825                 case MONO_PATCH_INFO_VTABLE:
826                         patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
827                         j++;
828                         break;
829                 case MONO_PATCH_INFO_SFLDA:
830                         patch_info->data.name = cond_emit_field_label (acfg, patch_info);
831                         j++;
832                         break;
833                 case MONO_PATCH_INFO_LDSTR:
834                 case MONO_PATCH_INFO_LDTOKEN:
835                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
836                         fprintf (tmpfp, "\t.align 8\n");
837                         fprintf (tmpfp, "%s_p_%d:\n", mname, j);
838                         fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
839                         j++;
840                         break;
841                 default:
842                         g_warning ("unable to handle jump info %d", patch_info->type);
843                         g_assert_not_reached ();
844                 }
845         }
846
847         fprintf (tmpfp, ".globl %s_p\n", mname);
848         fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
849         fprintf (tmpfp, "%s_p:\n", mname);
850
851         fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
852         fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
853
854         /* Exception table */
855         if (header->num_clauses) {
856                 MonoJitInfo *jinfo = cfg->jit_info;
857
858                 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
859
860                 for (k = 0; k < header->num_clauses; ++k) {
861                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
862
863                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
864                                 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->data.filter - code);
865                         else
866                                 /* fixme: tokens are not global */
867                                 fprintf (tmpfp, "\t.long %d\n", ei->data.token);
868
869                         fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_start - code);
870                         fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_end - code);
871                         fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->handler_start - code);
872                 }
873         }
874
875         /* String table */
876         if (cfg->opt & MONO_OPT_SHARED) {
877                 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
878                 for (l = cfg->ldstr_list; l; l = l->next) {
879                         fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
880                 }
881         }
882         else
883                 /* Used only in shared mode */
884                 g_assert (!cfg->ldstr_list);
885
886         //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
887
888         if (j) {
889                 guint32 last_offset;
890                 last_offset = 0;
891                 j = 0;
892                 for (pindex = 0; pindex < patches->len; ++pindex) {
893                         guint32 offset;
894                         patch_info = g_ptr_array_index (patches, pindex);
895
896                         if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
897                                 (patch_info->type == MONO_PATCH_INFO_BB))
898                                 /* Nothing to do */
899                                 continue;
900
901                         //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
902                         offset = patch_info->ip.i - last_offset;
903                         last_offset = patch_info->ip.i;
904
905                         /* Encode type+position compactly */
906                         g_assert (patch_info->type < 64);
907                         if (offset < 1024 - 1) {
908                                 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
909                                 fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
910                         }
911                         else {
912                                 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
913                                 fprintf (tmpfp, "\t.byte %d\n", 255);
914                                 fprintf (tmpfp, "\t.long %d\n", offset);
915                         }
916
917                         switch (patch_info->type) {
918                         case MONO_PATCH_INFO_METHODCONST:
919                         case MONO_PATCH_INFO_METHOD:
920                         case MONO_PATCH_INFO_CLASS:
921                         case MONO_PATCH_INFO_FIELD:
922                         case MONO_PATCH_INFO_INTERNAL_METHOD:
923                         case MONO_PATCH_INFO_IMAGE:
924                         case MONO_PATCH_INFO_VTABLE:
925                         case MONO_PATCH_INFO_SFLDA:
926                         case MONO_PATCH_INFO_EXC_NAME:
927                                 fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
928                                 j++;
929                                 break;
930                         case MONO_PATCH_INFO_SWITCH:
931                         case MONO_PATCH_INFO_R4:
932                         case MONO_PATCH_INFO_R8:
933                         case MONO_PATCH_INFO_METHOD_REL:
934                         case MONO_PATCH_INFO_LDSTR:
935                         case MONO_PATCH_INFO_LDTOKEN:
936                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
937                                 fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j);
938                                 j++;
939                                 break;
940                         case MONO_PATCH_INFO_LABEL:
941                         case MONO_PATCH_INFO_BB:
942                                 break;
943                         default:
944                                 g_warning ("unable to handle jump info %d", patch_info->type);
945                                 g_assert_not_reached ();
946                         }
947
948                 }
949         }
950
951         /*
952          * 0 is PATCH_INFO_BB, which can't be in the file.
953          */
954         /* NULL terminated array */
955         fprintf (tmpfp, "\t.long 0\n");
956
957         /* fixme: save the rest of the required infos */
958
959         g_free (mname);
960 }
961
962 int
963 mono_compile_assembly (MonoAssembly *ass, guint32 opts)
964 {
965         MonoCompile *cfg;
966         MonoImage *image = ass->image;
967         MonoMethod *method;
968         char *com, *tmpfname, *opts_str;
969         FILE *tmpfp;
970         int i;
971         guint8 *symbol;
972         int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
973         GHashTable *ref_hash;
974         MonoAotCompile *acfg;
975         gboolean *emitted;
976
977         printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
978
979         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
980         tmpfp = fdopen (i, "w+");
981         g_assert (tmpfp);
982
983         ref_hash = g_hash_table_new (NULL, NULL);
984
985         acfg = g_new0 (MonoAotCompile, 1);
986         acfg->fp = tmpfp;
987         acfg->ref_hash = ref_hash;
988         acfg->icall_hash = g_hash_table_new (NULL, NULL);
989         acfg->icall_table = g_ptr_array_new ();
990         acfg->image_hash = g_hash_table_new (NULL, NULL);
991         acfg->image_table = g_ptr_array_new ();
992
993         write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
994
995         write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
996
997         opts_str = g_strdup_printf ("%d", opts);
998         write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
999         g_free (opts_str);
1000
1001         emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
1002
1003         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1004                 MonoJumpInfo *patch_info;
1005                 gboolean skip;
1006                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1007                 method = mono_get_method (image, token, NULL);
1008                 
1009                 /* fixme: maybe we can also precompile wrapper methods */
1010                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1011                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1012                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1013                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1014                         //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1015                         continue;
1016                 }
1017
1018                 mcount++;
1019
1020                 /* fixme: we need to patch the IP for the LMF in that case */
1021                 if (method->save_lmf) {
1022                         //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
1023                         lmfcount++;
1024                         continue;
1025                 }
1026
1027                 //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
1028                 //mono_compile_method (method);
1029
1030                 cfg = mini_method_compile (method, opts, mono_root_domain, 0);
1031                 g_assert (cfg);
1032
1033                 if (cfg->disable_aot) {
1034                         ocount++;
1035                         continue;
1036                 }
1037
1038                 skip = FALSE;
1039                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1040                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
1041                                 /* unable to handle this */
1042                                 //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1043                                 skip = TRUE;    
1044                                 break;
1045                         }
1046                 }
1047
1048                 if (skip) {
1049                         abscount++;
1050                         continue;
1051                 }
1052
1053                 skip = FALSE;
1054                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1055                         if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
1056                              patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
1057                             patch_info->data.method->wrapper_type) {
1058                                 /* unable to handle this */
1059                                 //printf ("Skip (wrapper call):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1060                                 skip = TRUE;    
1061                                 break;
1062                         }
1063                 }
1064
1065                 if (skip) {
1066                         wrappercount++;
1067                         continue;
1068                 }
1069
1070                 //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
1071
1072                 emitted [i] = TRUE;
1073                 emit_method (acfg, cfg);
1074
1075                 mono_destroy_compile (cfg);
1076
1077                 ccount++;
1078         }
1079
1080         /*
1081          * The icall and image tables are small but referenced in a lot of places.
1082          * So we emit them at once, and reference their elements by an index
1083          * instead of an assembly label to cut back on the number of relocations.
1084          */
1085
1086         /* Emit icall table */
1087
1088         symbol = g_strdup_printf ("mono_icall_table");
1089         fprintf (tmpfp, ".globl %s\n", symbol);
1090         fprintf (tmpfp, ".text 1 \n");
1091         fprintf (tmpfp, "\t.align 8\n");
1092         fprintf (tmpfp, "%s:\n", symbol);
1093         fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1094         for (i = 0; i < acfg->icall_table->len; i++)
1095                 fprintf (tmpfp, ".string \"%s\"\n", (char*)g_ptr_array_index (acfg->icall_table, i));
1096
1097         /* Emit image table */
1098
1099         symbol = g_strdup_printf ("mono_image_table");
1100         fprintf (tmpfp, ".globl %s\n", symbol);
1101         fprintf (tmpfp, ".text 1 \n");
1102         fprintf (tmpfp, "\t.align 8\n");
1103         fprintf (tmpfp, "%s:\n", symbol);
1104         fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1105         for (i = 0; i < acfg->image_table->len; i++)
1106                 fprintf (tmpfp, ".string \"%s\"\n", ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
1107
1108         /*
1109          * g_module_symbol takes a lot of time for failed lookups, so we emit
1110          * a table which contains one bit for each method. This bit specifies
1111          * whenever the method is emitted or not.
1112          */
1113
1114         symbol = g_strdup_printf ("mono_methods_present_table");
1115         fprintf (tmpfp, ".globl %s\n", symbol);
1116         fprintf (tmpfp, ".text 1 \n");
1117         fprintf (tmpfp, "\t.align 8\n");
1118         fprintf (tmpfp, "%s:\n", symbol);
1119         {
1120                 guint32 k, nrows;
1121                 guint32 w;
1122
1123                 nrows = image->tables [MONO_TABLE_METHOD].rows;
1124                 for (i = 0; i < nrows / 32 + 1; ++i) {
1125                         w = 0;
1126                         for (k = 0; k < 32; ++k) {
1127                                 if (emitted [(i * 32) + k])
1128                                         w += (1 << k);
1129                         }
1130                         //printf ("EMITTED [%d] = %d.\n", i, b);
1131                         fprintf (tmpfp, "\t.long %d\n", w);
1132                 }
1133         }
1134
1135         fclose (tmpfp);
1136
1137         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1138         printf ("Executing the native assembler: %s\n", com);
1139         system (com);
1140         g_free (com);
1141         com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
1142         printf ("Executing the native linker: %s\n", com);
1143         system (com);
1144         g_free (com);
1145         com = g_strdup_printf ("%s.o", tmpfname);
1146         unlink (com);
1147         g_free (com);
1148         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1149         printf ("Stripping the binary: %s\n", com);
1150         system (com);
1151         g_free (com);*/
1152
1153         printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
1154         printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
1155         printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
1156         printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
1157         printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);
1158         unlink (tmpfname);
1159
1160         return 0;
1161 }
1162
1163