2006-04-26 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / aot-compiler.c
1 /*
2  * aot.c: mono Ahead of Time compiler
3  *
4  * Author:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *   Zoltan Varga (vargaz@gmail.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include "config.h"
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #ifndef PLATFORM_WIN32
17 #include <sys/mman.h>
18 #else
19 #include <winsock2.h>
20 #include <windows.h>
21 #endif
22
23 #include <errno.h>
24 #include <sys/stat.h>
25 #include <limits.h>    /* for PAGESIZE */
26 #ifndef PAGESIZE
27 #define PAGESIZE 4096
28 #endif
29
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/debug-helpers.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/metadata-internals.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/utils/mono-logger.h>
40 #include "mono/utils/mono-compiler.h"
41
42 #include "mini.h"
43
44 #ifndef DISABLE_AOT
45
46 #ifdef PLATFORM_WIN32
47 #define SHARED_EXT ".dll"
48 #elif defined(__ppc__) && defined(__MACH__)
49 #define SHARED_EXT ".dylib"
50 #else
51 #define SHARED_EXT ".so"
52 #endif
53
54 #if defined(sparc) || defined(__ppc__)
55 #define AS_STRING_DIRECTIVE ".asciz"
56 #else
57 /* GNU as */
58 #define AS_STRING_DIRECTIVE ".string"
59 #endif
60
61 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
62 #define ROUND_DOWN(VALUE,SIZE)  ((VALUE) & ~((SIZE) - 1))
63
64 typedef struct MonoAotOptions {
65         char *outfile;
66         gboolean save_temps;
67         gboolean write_symbols;
68 } MonoAotOptions;
69
70 typedef struct MonoAotCompile {
71         MonoImage *image;
72         MonoCompile **cfgs;
73         FILE *fp;
74         GHashTable *patch_to_plt_offset;
75         GHashTable *plt_offset_to_patch;
76         GHashTable *image_hash;
77         GHashTable *method_to_cfg;
78         GPtrArray *image_table;
79         GList *method_order;
80         guint32 got_offset, plt_offset;
81         guint32 *method_got_offsets;
82         MonoAotOptions aot_opts;
83         guint32 nmethods;
84         guint32 opts;
85         int ccount, mcount, lmfcount, abscount, wrappercount, ocount;
86         int code_size, info_size, ex_info_size, got_size, class_info_size;
87 } MonoAotCompile;
88
89 static gboolean 
90 is_got_patch (MonoJumpInfoType patch_type)
91 {
92 #ifdef __x86_64__
93         return TRUE;
94 #elif defined(__i386__)
95         return TRUE;
96 #else
97         return FALSE;
98 #endif
99 }
100
101 static void
102 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
103 {
104 #if defined(PLATFORM_WIN32)
105         fprintf (fp, ".section %s\n", section_name);
106 #elif defined(sparc)
107         /* For solaris as, GNU as should accept the same */
108         fprintf (fp, ".section \"%s\"\n", section_name);
109 #elif defined(__ppc__) && defined(__MACH__)
110         /* This needs to be made more precise on mach. */
111         fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
112 #else
113         fprintf (fp, "%s %d\n", section_name, subsection_index);
114 #endif
115 }
116
117 static void
118 emit_symbol_type (FILE *fp, const char *name, gboolean func)
119 {
120         const char *stype;
121
122         if (func)
123                 stype = "function";
124         else
125                 stype = "object";
126
127 #if defined(sparc)
128         fprintf (fp, "\t.type %s,#%s\n", name, stype);
129 #elif defined(PLATFORM_WIN32)
130
131 #elif !(defined(__ppc__) && defined(__MACH__))
132         fprintf (fp, "\t.type %s,@%s\n", name, stype);
133 #elif defined(__x86_64__) || defined(__i386__)
134         fprintf (fp, "\t.type %s,@%s\n", name, stype);
135 #endif
136 }
137
138 static void
139 emit_global (FILE *fp, const char *name, gboolean func)
140 {
141 #if  (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
142     // mach-o always uses a '_' prefix.
143         fprintf (fp, "\t.globl _%s\n", name);
144 #else
145         fprintf (fp, "\t.globl %s\n", name);
146 #endif
147
148         emit_symbol_type (fp, name, func);
149 }
150
151 static void
152 emit_label (FILE *fp, const char *name)
153 {
154 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
155     // mach-o always uses a '_' prefix.
156         fprintf (fp, "_%s:\n", name);
157 #else
158         fprintf (fp, "%s:\n", name);
159 #endif
160
161 #if defined(PLATFORM_WIN32)
162         /* Emit a normal label too */
163         fprintf (fp, "%s:\n", name);
164 #endif
165 }
166
167 static void
168 emit_string_symbol (FILE *fp, const char *name, const char *value)
169 {
170         emit_section_change (fp, ".text", 1);
171         emit_global(fp, name, FALSE);
172         emit_label(fp, name);
173         fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
174 }
175
176 #if defined(__ppc__) && defined(__MACH__)
177 static int
178 ilog2(register int value)
179 {
180     int count = -1;
181     while (value & ~0xf) count += 4, value >>= 4;
182     while (value) count++, value >>= 1;
183     return count;
184 }
185 #endif
186
187 static void 
188 emit_alignment(FILE *fp, int size)
189 {
190 #if defined(__ppc__) && defined(__MACH__)
191         // the mach-o assembler specifies alignments as powers of 2.
192         fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
193 #elif defined(__powerpc__)
194         /* ignore on linux/ppc */
195 #else
196         fprintf (fp, "\t.align %d\n", size);
197 #endif
198 }
199
200 G_GNUC_UNUSED static void
201 emit_pointer (FILE *fp, const char *target)
202 {
203         emit_alignment (fp, sizeof (gpointer));
204 #if defined(__x86_64__)
205         fprintf (fp, "\t.quad %s\n", target);
206 #elif defined(sparc) && SIZEOF_VOID_P == 8
207         fprintf (fp, "\t.xword %s\n", target);
208 #else
209         fprintf (fp, "\t.long %s\n", target);
210 #endif
211 }
212
213 static guint32
214 mono_get_field_token (MonoClassField *field) 
215 {
216         MonoClass *klass = field->parent;
217         int i;
218
219         for (i = 0; i < klass->field.count; ++i) {
220                 if (field == &klass->fields [i])
221                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
222         }
223
224         g_assert_not_reached ();
225         return 0;
226 }
227
228 static inline void
229 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
230 {
231         guint8 *p = buf;
232
233         //printf ("ENCODE: %d 0x%x.\n", value, value);
234
235         /* 
236          * Same encoding as the one used in the metadata, extended to handle values
237          * greater than 0x1fffffff.
238          */
239         if ((value >= 0) && (value <= 127))
240                 *p++ = value;
241         else if ((value >= 0) && (value <= 16383)) {
242                 p [0] = 0x80 | (value >> 8);
243                 p [1] = value & 0xff;
244                 p += 2;
245         } else if ((value >= 0) && (value <= 0x1fffffff)) {
246                 p [0] = (value >> 24) | 0xc0;
247                 p [1] = (value >> 16) & 0xff;
248                 p [2] = (value >> 8) & 0xff;
249                 p [3] = value & 0xff;
250                 p += 4;
251         }
252         else {
253                 p [0] = 0xff;
254                 p [1] = (value >> 24) & 0xff;
255                 p [2] = (value >> 16) & 0xff;
256                 p [3] = (value >> 8) & 0xff;
257                 p [4] = value & 0xff;
258                 p += 5;
259         }
260         if (endbuf)
261                 *endbuf = p;
262 }
263
264 static guint32
265 get_image_index (MonoAotCompile *cfg, MonoImage *image)
266 {
267         guint32 index;
268
269         index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
270         if (index)
271                 return index - 1;
272         else {
273                 index = g_hash_table_size (cfg->image_hash);
274                 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
275                 g_ptr_array_add (cfg->image_table, image);
276                 return index;
277         }
278 }
279
280 static void
281 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
282 {
283         if (!klass->type_token) {
284                 /* Array class */
285                 g_assert (klass->rank > 0);
286                 g_assert (klass->element_class->type_token);
287                 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
288                 encode_value (get_image_index (cfg, klass->image), buf, &buf);
289                 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
290                 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
291                 encode_value (klass->rank, buf, &buf);
292         }
293         else {
294                 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
295                 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
296                 encode_value (get_image_index (cfg, klass->image), buf, &buf);
297         }
298         *endbuf = buf;
299 }
300
301 static void
302 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
303 {
304         guint32 token = mono_get_field_token (field);
305
306         encode_klass_info (cfg, field->parent, buf, &buf);
307         g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
308         encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
309         *endbuf = buf;
310 }
311
312 static void
313 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
314 {
315         guint32 image_index = get_image_index (acfg, method->klass->image);
316         guint32 token = method->token;
317         g_assert (image_index < 256);
318         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
319
320         encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
321         *endbuf = buf;
322 }
323
324 static gint
325 compare_patches (gconstpointer a, gconstpointer b)
326 {
327         int i, j;
328
329         i = (*(MonoJumpInfo**)a)->ip.i;
330         j = (*(MonoJumpInfo**)b)->ip.i;
331
332         if (i < j)
333                 return -1;
334         else
335                 if (i > j)
336                         return 1;
337         else
338                 return 0;
339 }
340
341 static int
342 get_plt_index (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
343 {
344         int res = -1;
345         int idx;
346
347         switch (patch_info->type) {
348         case MONO_PATCH_INFO_METHOD:
349         case MONO_PATCH_INFO_WRAPPER:
350         case MONO_PATCH_INFO_INTERNAL_METHOD:
351         case MONO_PATCH_INFO_CLASS_INIT: {
352                 MonoJumpInfo *new_ji = g_new0 (MonoJumpInfo, 1);
353
354                 memcpy (new_ji, patch_info, sizeof (MonoJumpInfo));
355
356                 /* First check for an existing patch */
357                 switch (patch_info->type) {
358                 case MONO_PATCH_INFO_METHOD:
359                         idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info->data.method));
360                         if (idx)
361                                 res = idx;
362                         else
363                                 g_hash_table_insert (acfg->patch_to_plt_offset, patch_info->data.method, GUINT_TO_POINTER (acfg->plt_offset));
364                         break;
365                 case MONO_PATCH_INFO_INTERNAL_METHOD:
366                         idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info->data.name));
367                         if (idx)
368                                 res = idx;
369                         else
370                                 g_hash_table_insert (acfg->patch_to_plt_offset, (char*)patch_info->data.name, GUINT_TO_POINTER (acfg->plt_offset));
371                         break;
372                 case MONO_PATCH_INFO_CLASS_INIT:
373                         idx = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->patch_to_plt_offset, patch_info->data.klass));
374                         if (idx)
375                                 res = idx;
376                         else
377                                 g_hash_table_insert (acfg->patch_to_plt_offset, (char*)patch_info->data.klass, GUINT_TO_POINTER (acfg->plt_offset));
378
379                         break;
380                 default:
381                         break;
382                 }
383
384                 if (res == -1) {
385                         res = acfg->plt_offset;
386                         g_hash_table_insert (acfg->plt_offset_to_patch, GUINT_TO_POINTER (acfg->plt_offset), new_ji);
387                         acfg->plt_offset ++;
388                 }
389
390                 /* Nullify the patch */
391                 patch_info->type = MONO_PATCH_INFO_NONE;
392
393                 return res;
394         }
395         default:
396                 return -1;
397         }
398 }
399
400 static guint32
401 get_got_offset (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
402 {
403         guint32 res;
404
405         switch (patch_info->type) {
406         case MONO_PATCH_INFO_IMAGE:
407                 if (patch_info->data.image == acfg->image)
408                         res = 0;
409                 else {
410                         res = acfg->got_offset;
411                         acfg->got_offset ++;
412                 }
413                 break;
414         default:
415                 res = acfg->got_offset;
416                 acfg->got_offset ++;
417                 break;
418         }
419
420         return res;
421 }
422
423 static void
424 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
425 {
426         MonoMethod *method;
427         FILE *tmpfp;
428         int i, j, pindex, byte_index, method_index;
429         guint8 *code;
430         char *symbol;
431         int func_alignment = 16;
432         GPtrArray *patches;
433         MonoJumpInfo *patch_info;
434         MonoMethodHeader *header;
435 #ifdef MONO_ARCH_HAVE_PIC_AOT
436         gboolean skip;
437         guint32 got_slot;
438 #endif
439
440         tmpfp = acfg->fp;
441         method = cfg->method;
442         code = cfg->native_code;
443         header = mono_method_get_header (method);
444
445         method_index = mono_metadata_token_index (method->token);
446
447         /* Make the labels local */
448         symbol = g_strdup_printf (".Lm_%x", method_index);
449
450         emit_alignment(tmpfp, func_alignment);
451         emit_label(tmpfp, symbol);
452         if (acfg->aot_opts.write_symbols)
453                 emit_global (tmpfp, symbol, TRUE);
454
455         if (cfg->verbose_level > 0)
456                 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
457
458         acfg->code_size += cfg->code_len;
459
460         /* Collect and sort relocations */
461         patches = g_ptr_array_new ();
462         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
463                 g_ptr_array_add (patches, patch_info);
464         g_ptr_array_sort (patches, compare_patches);
465
466 #ifdef MONO_ARCH_HAVE_PIC_AOT
467         acfg->method_got_offsets [method_index] = acfg->got_offset;
468         byte_index = 0;
469         for (i = 0; i < cfg->code_len; i++) {
470                 patch_info = NULL;
471                 for (pindex = 0; pindex < patches->len; ++pindex) {
472                         patch_info = g_ptr_array_index (patches, pindex);
473                         if (patch_info->ip.i == i)
474                                 break;
475                 }
476
477                 skip = FALSE;
478                 if (patch_info && (pindex < patches->len)) {
479                         switch (patch_info->type) {
480                         case MONO_PATCH_INFO_LABEL:
481                         case MONO_PATCH_INFO_BB:
482                         case MONO_PATCH_INFO_NONE:
483                                 break;
484                         case MONO_PATCH_INFO_GOT_OFFSET: {
485                                 guint32 offset = mono_arch_get_patch_offset (code + i);
486                                 fprintf (tmpfp, "\n.byte ");
487                                 for (j = 0; j < offset; ++j)
488                                         fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
489                                 fprintf (tmpfp, "\n.int got - . + %d", offset);
490
491                                 i += offset + 4 - 1;
492                                 skip = TRUE;
493                                 break;
494                         }
495                         default: {
496                                 int plt_index;
497                                 char *direct_call_target;
498
499                                 if (!is_got_patch (patch_info->type))
500                                         break;
501
502                                 /*
503                                  * If this patch is a call, try emitting a direct call instead of
504                                  * through a PLT entry. This is possible if the called method is in
505                                  * the same assembly and requires no initialization.
506                                  */
507                                 direct_call_target = NULL;
508                                 if ((patch_info->type == MONO_PATCH_INFO_METHOD) && (patch_info->data.method->klass->image == cfg->method->klass->image)) {
509                                         MonoCompile *callee_cfg = g_hash_table_lookup (acfg->method_to_cfg, patch_info->data.method);
510
511                                         if (callee_cfg && !callee_cfg->got_var && (callee_cfg->method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)) {
512                                                 //printf ("DIRECT: %s %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (callee_cfg->method, TRUE));
513                                                 direct_call_target = g_strdup_printf (".Lm_%x", mono_metadata_token_index (callee_cfg->method->token));
514                                                 patch_info->type = MONO_PATCH_INFO_NONE;
515                                         }
516                                 }
517
518                                 if (!direct_call_target) {
519                                         plt_index = get_plt_index (acfg, patch_info);
520                                         if (plt_index != -1) {
521                                                 /* This patch has a PLT entry, so we must emit a call to the PLT entry */
522                                                 direct_call_target = g_strdup_printf (".Lp_%d", plt_index);
523                                         }
524                                 }
525
526                                 if (direct_call_target) {
527 #if defined(__i386__) || defined(__x86_64__)
528                                         g_assert (code [i] == 0xe8);
529                                         /* Need to make sure this is exactly 5 bytes long */
530                                         fprintf (tmpfp, "\n.byte 0xe8");
531                                         fprintf (tmpfp, "\n.long %s - . - 4\n", direct_call_target);
532                                         i += 4;
533 #else
534                                         g_assert_not_reached ();
535 #endif
536                                 } else {
537                                         got_slot = get_got_offset (acfg, patch_info);
538
539                                         fprintf (tmpfp, "\n.byte ");
540                                         for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
541                                                 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
542 #ifdef __x86_64__
543                                         fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
544 #elif defined(__i386__)
545                                         fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((got_slot * sizeof (gpointer))));
546 #endif
547                                         
548                                         i += mono_arch_get_patch_offset (code + i) + 4 - 1;
549                                 }
550                                 skip = TRUE;
551                         }
552                         }
553                 }
554
555                 if (!skip) {
556                         if (byte_index == 0)
557                                 fprintf (tmpfp, "\n.byte ");
558                         fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
559                         byte_index = (byte_index + 1) % 32;
560                 }
561                 else
562                         byte_index = 0;
563         }
564 #else
565         for (i = 0; i < cfg->code_len; i++) {
566                 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
567         }
568 #endif
569         fprintf (tmpfp, "\n");
570 }
571
572 static void
573 encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint8 **endbuf)
574 {
575         guint8 *p = buf;
576
577         switch (patch_info->type) {
578         case MONO_PATCH_INFO_NONE:
579                 break;
580         case MONO_PATCH_INFO_IMAGE:
581                 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
582                 break;
583         case MONO_PATCH_INFO_METHOD_REL:
584                 encode_value ((gint)patch_info->data.offset, p, &p);
585                 break;
586         case MONO_PATCH_INFO_SWITCH: {
587                 gpointer *table = (gpointer *)patch_info->data.table->table;
588                 int k;
589
590                 encode_value (patch_info->data.table->table_size, p, &p);
591                 for (k = 0; k < patch_info->data.table->table_size; k++)
592                         encode_value ((int)(gssize)table [k], p, &p);
593                 break;
594         }
595         case MONO_PATCH_INFO_METHODCONST:
596         case MONO_PATCH_INFO_METHOD:
597         case MONO_PATCH_INFO_METHOD_JUMP:
598                 encode_method_ref (acfg, patch_info->data.method, p, &p);
599                 break;
600         case MONO_PATCH_INFO_INTERNAL_METHOD: {
601                 guint32 len = strlen (patch_info->data.name);
602
603                 encode_value (len, p, &p);
604
605                 memcpy (p, patch_info->data.name, len);
606                 p += len;
607                 *p++ = '\0';
608                 break;
609         }
610         case MONO_PATCH_INFO_LDSTR: {
611                 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
612                 guint32 token = patch_info->data.token->token;
613                 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
614                 /* 
615                  * An optimization would be to emit shared code for ldstr 
616                  * statements followed by a throw.
617                  */
618                 encode_value (image_index, p, &p);
619                 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
620                 break;
621         }
622         case MONO_PATCH_INFO_DECLSEC:
623         case MONO_PATCH_INFO_LDTOKEN:
624         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
625                 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
626                 encode_value (patch_info->data.token->token, p, &p);
627                 break;
628         case MONO_PATCH_INFO_EXC_NAME: {
629                 MonoClass *ex_class;
630
631                 ex_class =
632                         mono_class_from_name (mono_defaults.exception_class->image,
633                                                                   "System", patch_info->data.target);
634                 g_assert (ex_class);
635                 encode_klass_info (acfg, ex_class, p, &p);
636                 break;
637         }
638         case MONO_PATCH_INFO_R4:
639                 encode_value (*((guint32 *)patch_info->data.target), p, &p);
640                 break;
641         case MONO_PATCH_INFO_R8:
642                 encode_value (*((guint32 *)patch_info->data.target), p, &p);
643                 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
644                 break;
645         case MONO_PATCH_INFO_VTABLE:
646         case MONO_PATCH_INFO_CLASS_INIT:
647         case MONO_PATCH_INFO_CLASS:
648         case MONO_PATCH_INFO_IID:
649         case MONO_PATCH_INFO_ADJUSTED_IID:
650                 encode_klass_info (acfg, patch_info->data.klass, p, &p);
651                 break;
652         case MONO_PATCH_INFO_FIELD:
653         case MONO_PATCH_INFO_SFLDA:
654                 encode_field_info (acfg, patch_info->data.field, p, &p);
655                 break;
656         case MONO_PATCH_INFO_WRAPPER: {
657                 encode_value (patch_info->data.method->wrapper_type, p, &p);
658
659                 switch (patch_info->data.method->wrapper_type) {
660                 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
661                         MonoMethod *m;
662                         guint32 image_index;
663                         guint32 token;
664
665                         m = mono_marshal_method_from_wrapper (patch_info->data.method);
666                         image_index = get_image_index (acfg, m->klass->image);
667                         token = m->token;
668                         g_assert (image_index < 256);
669                         g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
670
671                         encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
672                         break;
673                 }
674                 case MONO_WRAPPER_PROXY_ISINST:
675                 case MONO_WRAPPER_LDFLD:
676                 case MONO_WRAPPER_LDFLDA:
677                 case MONO_WRAPPER_STFLD:
678                 case MONO_WRAPPER_LDFLD_REMOTE:
679                 case MONO_WRAPPER_STFLD_REMOTE:
680                 case MONO_WRAPPER_ISINST: {
681                         MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
682                         encode_klass_info (acfg, proxy_class, p, &p);
683                         break;
684                 }
685                 case MONO_WRAPPER_STELEMREF:
686                         break;
687                 default:
688                         g_assert_not_reached ();
689                 }
690                 break;
691         }
692         default:
693                 g_warning ("unable to handle jump info %d", patch_info->type);
694                 g_assert_not_reached ();
695         }
696
697         *endbuf = p;
698 }
699
700 static void
701 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
702 {
703         MonoMethod *method;
704         GList *l;
705         FILE *tmpfp;
706         int i, j, pindex, buf_size, n_patches;
707         guint8 *code;
708         char *symbol;
709         GPtrArray *patches;
710         MonoJumpInfo *patch_info;
711         MonoMethodHeader *header;
712         guint32 last_offset, method_idx;
713         guint8 *p, *buf;
714 #ifdef MONO_ARCH_HAVE_PIC_AOT
715         guint32 first_got_offset;
716 #endif
717
718         tmpfp = acfg->fp;
719         method = cfg->method;
720         code = cfg->native_code;
721         header = mono_method_get_header (method);
722
723         method_idx = mono_metadata_token_index (method->token);
724
725         /* Make the labels local */
726         symbol = g_strdup_printf (".Lm_%x_p", method_idx);
727
728         /* Sort relocations */
729         patches = g_ptr_array_new ();
730         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
731                 g_ptr_array_add (patches, patch_info);
732         g_ptr_array_sort (patches, compare_patches);
733
734 #ifdef MONO_ARCH_HAVE_PIC_AOT
735         first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
736 #endif
737
738         /**********************/
739         /* Encode method info */
740         /**********************/
741
742         buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
743         p = buf = g_malloc (buf_size);
744
745         if (mono_class_get_cctor (method->klass))
746                 encode_klass_info (acfg, method->klass, p, &p);
747         else
748                 /* Not needed when loading the method */
749                 encode_value (0, p, &p);
750
751         /* String table */
752         if (cfg->opt & MONO_OPT_SHARED) {
753                 encode_value (g_list_length (cfg->ldstr_list), p, &p);
754                 for (l = cfg->ldstr_list; l; l = l->next) {
755                         encode_value ((long)l->data, p, &p);
756                 }
757         }
758         else
759                 /* Used only in shared mode */
760                 g_assert (!cfg->ldstr_list);
761
762         n_patches = 0;
763         for (pindex = 0; pindex < patches->len; ++pindex) {
764                 patch_info = g_ptr_array_index (patches, pindex);
765                 
766                 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
767                         (patch_info->type == MONO_PATCH_INFO_BB) ||
768                         (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
769                         (patch_info->type == MONO_PATCH_INFO_NONE)) {
770                         patch_info->type = MONO_PATCH_INFO_NONE;
771                         /* Nothing to do */
772                         continue;
773                 }
774
775                 if ((patch_info->type == MONO_PATCH_INFO_IMAGE) && (patch_info->data.image == acfg->image)) {
776                         /* Stored in GOT slot 0 */
777                         patch_info->type = MONO_PATCH_INFO_NONE;
778                         continue;
779                 }
780
781                 n_patches ++;
782         }
783
784         encode_value (n_patches, p, &p);
785
786 #ifdef MONO_ARCH_HAVE_PIC_AOT
787         if (n_patches)
788                 encode_value (first_got_offset, p, &p);
789 #endif
790
791         /* First encode the type+position table */
792         last_offset = 0;
793         j = 0;
794         for (pindex = 0; pindex < patches->len; ++pindex) {
795                 guint32 offset;
796                 patch_info = g_ptr_array_index (patches, pindex);
797                 
798                 if (patch_info->type == MONO_PATCH_INFO_NONE)
799                         /* Nothing to do */
800                         continue;
801
802                 j ++;
803                 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
804                 offset = patch_info->ip.i - last_offset;
805                 last_offset = patch_info->ip.i;
806
807 #if defined(MONO_ARCH_HAVE_PIC_AOT)
808                 /* Only the type is needed */
809                 *p = patch_info->type;
810                 p++;
811 #else
812                 /* Encode type+position compactly */
813                 g_assert (patch_info->type < 64);
814                 if (offset < 1024 - 1) {
815                         *p = (patch_info->type << 2) + (offset >> 8);
816                         p++;
817                         *p = offset & ((1 << 8) - 1);
818                         p ++;
819                 }
820                 else {
821                         *p = (patch_info->type << 2) + 3;
822                         p ++;
823                         *p = 255;
824                         p ++;
825                         encode_value (offset, p, &p);
826                 }
827 #endif
828         }
829
830         /* Then encode the other info */
831         for (pindex = 0; pindex < patches->len; ++pindex) {
832                 patch_info = g_ptr_array_index (patches, pindex);
833
834                 encode_patch (acfg, patch_info, p, &p);
835         }
836
837         acfg->info_size += p - buf;
838
839         /* Emit method info */
840
841         emit_label (tmpfp, symbol);
842
843         g_assert (p - buf < buf_size);
844         for (i = 0; i < p - buf; ++i) {
845                 if ((i % 32) == 0)
846                         fprintf (tmpfp, "\n.byte ");
847                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
848         }
849         fprintf (tmpfp, "\n");
850         g_free (buf);
851
852         g_free (symbol);
853 }
854
855 static void
856 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
857 {
858         MonoMethod *method;
859         FILE *tmpfp;
860         int i, k, buf_size;
861         guint32 debug_info_size;
862         guint8 *code;
863         char *symbol;
864         MonoMethodHeader *header;
865         guint8 *p, *buf, *debug_info;
866
867         tmpfp = acfg->fp;
868         method = cfg->method;
869         code = cfg->native_code;
870         header = mono_method_get_header (method);
871
872         /* Make the labels local */
873         symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
874
875         buf_size = header->num_clauses * 256 + 128;
876         p = buf = g_malloc (buf_size);
877
878         encode_value (cfg->code_len, p, &p);
879         encode_value (cfg->used_int_regs, p, &p);
880
881         /* Exception table */
882         if (header->num_clauses) {
883                 MonoJitInfo *jinfo = cfg->jit_info;
884
885                 for (k = 0; k < header->num_clauses; ++k) {
886                         MonoJitExceptionInfo *ei = &jinfo->clauses [k];
887
888                         encode_value (ei->exvar_offset, p, &p);
889
890                         if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
891                                 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
892
893                         encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
894                         encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
895                         encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
896                 }
897         }
898
899         mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
900
901         encode_value (debug_info_size, p, &p);
902         if (debug_info_size) {
903                 memcpy (p, debug_info, debug_info_size);
904                 p += debug_info_size;
905                 g_free (debug_info);
906         }
907
908         acfg->ex_info_size += p - buf;
909
910         /* Emit info */
911
912         emit_label (tmpfp, symbol);
913
914         g_assert (p - buf < buf_size);
915         for (i = 0; i < p - buf; ++i) {
916                 if ((i % 32) == 0)
917                         fprintf (tmpfp, "\n.byte ");
918                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
919         }
920         fprintf (tmpfp, "\n");
921         g_free (buf);
922
923         g_free (symbol);
924 }
925
926 static void
927 emit_klass_info (MonoAotCompile *acfg, guint32 token)
928 {
929         MonoClass *klass = mono_class_get (acfg->image, token);
930         guint8 *p, *buf;
931         int i, buf_size;
932         char *label;
933         FILE *tmpfp = acfg->fp;
934         gboolean no_special_static;
935
936         buf_size = 10240;
937         p = buf = g_malloc (buf_size);
938
939         g_assert (klass);
940
941         mono_class_init (klass);
942
943         /* 
944          * Emit all the information which is required for creating vtables so
945          * the runtime does not need to create the MonoMethod structures which
946          * take up a lot of space.
947          */
948
949         no_special_static = !mono_class_has_special_static_fields (klass);
950
951         if (1) {
952                 encode_value (klass->vtable_size, p, &p);
953                 encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (klass->nested_classes ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
954                 if (klass->has_cctor)
955                         encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
956                 if (klass->has_finalize)
957                         encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
958  
959                 encode_value (klass->instance_size, p, &p);
960                 encode_value (klass->class_size, p, &p);
961                 encode_value (klass->packing_size, p, &p);
962                 encode_value (klass->min_align, p, &p);
963
964                 for (i = 0; i < klass->vtable_size; ++i) {
965                         MonoMethod *cm = klass->vtable [i];
966
967                         if (cm)
968                                 encode_method_ref (acfg, cm, p, &p);
969                         else
970                                 encode_value (0, p, &p);
971                 }
972         }
973
974         acfg->class_info_size += p - buf;
975
976         /* Emit the info */
977         label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
978         emit_label (tmpfp, label);
979
980         g_assert (p - buf < buf_size);
981         for (i = 0; i < p - buf; ++i) {
982                 if ((i % 32) == 0)
983                         fprintf (tmpfp, "\n.byte ");
984                 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
985         }
986         fprintf (tmpfp, "\n");
987         g_free (buf);
988 }
989
990 /*
991  * Calls made from AOTed code are routed through a table of jumps similar to the
992  * ELF PLT (Program Linkage Table). The differences are the following:
993  * - the ELF PLT entries make an indirect jump though the GOT so they expect the
994  *   GOT pointer to the in EBX. We want to avoid this, so our table contains direct
995  *   jumps. This means the jumps need to be patched when the address of the callee is
996  *   known. Initially the PLT entries jump to code which transfer control to the
997  *   AOT runtime through the first PLT entry.
998  */
999 static void
1000 emit_plt (MonoAotCompile *acfg)
1001 {
1002         char *symbol;
1003         int i, buf_size;
1004         guint8 *p, *buf;
1005         guint32 *plt_info_offsets;
1006
1007         fprintf (acfg->fp, "\n");
1008         symbol = g_strdup_printf ("plt");
1009
1010         /* This section will be made read-write by the AOT loader */
1011         emit_section_change (acfg->fp, ".text", 0);
1012         emit_global (acfg->fp, symbol, TRUE);
1013         emit_alignment (acfg->fp, PAGESIZE);
1014         emit_label (acfg->fp, symbol);
1015
1016         /* 
1017          * The first plt entry is used to transfer code to the AOT loader. It is filled up
1018          * during loading by the AOT loader.
1019          */
1020         emit_label (acfg->fp, ".Lp_0");
1021         for (i = 0; i < 16; ++i)
1022                 fprintf (acfg->fp, "\t.long 0\n");
1023
1024         for (i = 1; i < acfg->plt_offset; ++i) {
1025                 char *label;
1026
1027                 label = g_strdup_printf (".Lp_%d", i);
1028                 emit_label (acfg->fp, label);
1029                 g_free (label);
1030 #if defined(__i386__) || defined (__x86_64__)
1031                 /* Need to make sure this is 5 bytes long */
1032                 fprintf (acfg->fp, "\t.byte 0xe9\n");
1033                 fprintf (acfg->fp, "\t.long .Lpd_%d - . - 4\n", i);
1034 #else
1035                 g_assert_not_reached ();
1036 #endif
1037         }
1038
1039         symbol = g_strdup_printf ("plt_end");
1040         emit_global (acfg->fp, symbol, TRUE);
1041         emit_label (acfg->fp, symbol);
1042
1043         /*
1044          * Encode info need to resolve PLT entries.
1045          */
1046         buf_size = acfg->plt_offset * 128;
1047         p = buf = g_malloc (buf_size);
1048
1049         plt_info_offsets = g_new0 (guint32, acfg->plt_offset);
1050
1051         for (i = 1; i < acfg->plt_offset; ++i) {
1052                 MonoJumpInfo *patch_info = g_hash_table_lookup (acfg->plt_offset_to_patch, GUINT_TO_POINTER (i));
1053
1054                 plt_info_offsets [i] = p - buf;
1055                 encode_value (patch_info->type, p, &p);
1056                 encode_patch (acfg, patch_info, p, &p);
1057         }
1058
1059         /* 
1060          * Emit the default targets for the PLT entries separately since these will not
1061          * be modified at runtime.
1062          */
1063
1064         for (i = 1; i < acfg->plt_offset; ++i) {
1065                 char *label;
1066
1067                 label = g_strdup_printf (".Lpd_%d", i);
1068                 emit_label (acfg->fp, label);
1069                 g_free (label);
1070
1071                 /* Put the offset into the register expected by mono_aot_plt_trampoline */
1072 #if defined(__i386__)
1073                 fprintf (acfg->fp, "\tmovl $%d, %%eax\n", plt_info_offsets [i]);
1074                 fprintf (acfg->fp, "\tjmp .Lp_0\n");
1075 #elif defined(__x86_64__)
1076                 fprintf (acfg->fp, "\tpush $%d\n", plt_info_offsets [i]);
1077                 fprintf (acfg->fp, "\tjmp .Lp_0\n");
1078 #else
1079                 g_assert_not_reached ();
1080 #endif
1081         }
1082
1083         /* Emit PLT info */
1084         symbol = g_strdup_printf ("plt_info");
1085         emit_global (acfg->fp, symbol, FALSE);
1086         emit_label (acfg->fp, symbol);
1087
1088         g_assert (p - buf < buf_size);
1089         for (i = 0; i < p - buf; ++i) {
1090                 if ((i % 32) == 0)
1091                         fprintf (acfg->fp, "\n.byte ");
1092                 fprintf (acfg->fp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
1093         }
1094         fprintf (acfg->fp, "\n");
1095         g_free (buf);
1096 }
1097
1098 static gboolean
1099 str_begins_with (const char *str1, const char *str2)
1100 {
1101         int len = strlen (str2);
1102         return strncmp (str1, str2, len) == 0;
1103 }
1104
1105 static void
1106 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1107 {
1108         gchar **args, **ptr;
1109
1110         memset (opts, 0, sizeof (*opts));
1111
1112         args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1113         for (ptr = args; ptr && *ptr; ptr ++) {
1114                 const char *arg = *ptr;
1115
1116                 if (str_begins_with (arg, "outfile=")) {
1117                         opts->outfile = g_strdup (arg + strlen ("outfile="));
1118                 } else if (str_begins_with (arg, "save-temps")) {
1119                         opts->save_temps = TRUE;
1120                 } else if (str_begins_with (arg, "write-symbols")) {
1121                         opts->write_symbols = TRUE;
1122                 } else {
1123                         fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1124                         exit (1);
1125                 }
1126         }
1127 }
1128
1129 static void
1130 compile_method (MonoAotCompile *acfg, int index)
1131 {
1132         MonoCompile *cfg;
1133         MonoMethod *method;
1134         MonoJumpInfo *patch_info;
1135         gboolean skip;
1136         guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
1137         
1138         method = mono_get_method (acfg->image, token, NULL);
1139                 
1140         /* fixme: maybe we can also precompile wrapper methods */
1141         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1142                 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1143                 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1144                 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1145                 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1146                 return;
1147         }
1148
1149         acfg->mcount++;
1150
1151         /* fixme: we need to patch the IP for the LMF in that case */
1152         if (method->save_lmf) {
1153                 //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
1154                 acfg->lmfcount++;
1155                 return;
1156         }
1157
1158         /*
1159          * Since these methods are the only ones which are compiled with
1160          * AOT support, and they are not used by runtime startup/shutdown code,
1161          * the runtime will not see AOT methods during AOT compilation,so it
1162          * does not need to support them by creating a fake GOT etc.
1163          */
1164         cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
1165         if (cfg->exception_type != MONO_EXCEPTION_NONE) {
1166                 /* Let the exception happen at runtime */
1167                 return;
1168         }
1169
1170         if (cfg->disable_aot) {
1171                 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1172                 acfg->ocount++;
1173                 mono_destroy_compile (cfg);
1174                 return;
1175         }
1176
1177         skip = FALSE;
1178         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1179                 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1180                         /* unable to handle this */
1181                         //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1182                         skip = TRUE;    
1183                         break;
1184                 }
1185         }
1186
1187         if (skip) {
1188                 acfg->abscount++;
1189                 mono_destroy_compile (cfg);
1190                 return;
1191         }
1192
1193         /* some wrappers are very common */
1194         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1195                 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1196                         switch (patch_info->data.method->wrapper_type) {
1197                         case MONO_WRAPPER_PROXY_ISINST:
1198                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1199                         }
1200                 }
1201
1202                 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1203                         switch (patch_info->data.method->wrapper_type) {
1204                         case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1205                         case MONO_WRAPPER_STFLD:
1206                         case MONO_WRAPPER_LDFLD:
1207                         case MONO_WRAPPER_LDFLDA:
1208                         case MONO_WRAPPER_LDFLD_REMOTE:
1209                         case MONO_WRAPPER_STFLD_REMOTE:
1210                         case MONO_WRAPPER_STELEMREF:
1211                         case MONO_WRAPPER_ISINST:
1212                         case MONO_WRAPPER_PROXY_ISINST:
1213                                 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1214                                 break;
1215                         }
1216                 }
1217         }
1218
1219         skip = FALSE;
1220         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1221                 switch (patch_info->type) {
1222                 case MONO_PATCH_INFO_METHOD:
1223                 case MONO_PATCH_INFO_METHODCONST:
1224                         if (patch_info->data.method->wrapper_type) {
1225                                 /* unable to handle this */
1226                                 //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));
1227                                 skip = TRUE;
1228                                 break;
1229                         }
1230                         if (!patch_info->data.method->token)
1231                                 /*
1232                                  * The method is part of a constructed type like Int[,].Set (). It doesn't
1233                                  * have a token, and we can't make one, since the parent type is part of
1234                                  * assembly which contains the element type, and not the assembly which
1235                                  * referenced this type.
1236                                  */
1237                                 skip = TRUE;
1238                         break;
1239                 case MONO_PATCH_INFO_VTABLE:
1240                 case MONO_PATCH_INFO_CLASS_INIT:
1241                 case MONO_PATCH_INFO_CLASS:
1242                 case MONO_PATCH_INFO_IID:
1243                 case MONO_PATCH_INFO_ADJUSTED_IID:
1244                         if (!patch_info->data.klass->type_token)
1245                                 if (!patch_info->data.klass->element_class->type_token)
1246                                         skip = TRUE;
1247                         break;
1248                 default:
1249                         break;
1250                 }
1251         }
1252
1253         if (skip) {
1254                 acfg->wrappercount++;
1255                 mono_destroy_compile (cfg);
1256                 return;
1257         }
1258
1259         //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
1260
1261         acfg->cfgs [index] = cfg;
1262
1263         g_hash_table_insert (acfg->method_to_cfg, cfg->method, cfg);
1264
1265         acfg->ccount++;
1266 }
1267
1268 static void
1269 load_profile_files (MonoAotCompile *acfg)
1270 {
1271         FILE *infile;
1272         char *tmp;
1273         int file_index, res, method_index, i;
1274         char ver [256];
1275         guint32 token;
1276
1277         file_index = 0;
1278         while (TRUE) {
1279                 tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
1280
1281                 if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
1282                         break;
1283
1284                 infile = fopen (tmp, "r");
1285                 g_assert (infile);
1286
1287                 printf ("Using profile data file '%s'\n", tmp);
1288
1289                 file_index ++;
1290
1291                 res = fscanf (infile, "%32s\n", ver);
1292                 if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
1293                         printf ("Profile file has wrong version or invalid.\n");
1294                         continue;
1295                 }
1296
1297                 while (TRUE) {
1298                         res = fscanf (infile, "%d\n", &token);
1299                         if (res < 1)
1300                                 break;
1301
1302                         method_index = mono_metadata_token_index (token) - 1;
1303
1304                         if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
1305                                 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
1306                 }
1307         }
1308
1309         /* Add missing methods */
1310         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1311                 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
1312                         acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (i));
1313         }               
1314 }
1315
1316 static void
1317 emit_code (MonoAotCompile *acfg)
1318 {
1319         int i;
1320         char *symbol;
1321         GList *l;
1322
1323         symbol = g_strdup_printf ("methods");
1324         emit_section_change (acfg->fp, ".text", 0);
1325         emit_global (acfg->fp, symbol, TRUE);
1326         emit_alignment (acfg->fp, 8);
1327         emit_label (acfg->fp, symbol);
1328
1329         for (l = acfg->method_order; l != NULL; l = l->next) {
1330                 i = GPOINTER_TO_UINT (l->data);
1331
1332                 if (acfg->cfgs [i])
1333                         emit_method_code (acfg, acfg->cfgs [i]);
1334         }
1335
1336         symbol = g_strdup_printf ("methods_end");
1337         emit_section_change (acfg->fp, ".text", 0);
1338         emit_global (acfg->fp, symbol, FALSE);
1339         emit_alignment (acfg->fp, 8);
1340         emit_label (acfg->fp, symbol);
1341
1342         symbol = g_strdup_printf ("method_offsets");
1343         emit_section_change (acfg->fp, ".text", 1);
1344         emit_global (acfg->fp, symbol, FALSE);
1345         emit_alignment (acfg->fp, 8);
1346         emit_label(acfg->fp, symbol);
1347
1348         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1349                 const char *sep;
1350                 if ((i % 32) == 0) {
1351                         fprintf (acfg->fp, "\n.long ");
1352                         sep = "";
1353                 }
1354                 else
1355                         sep = ",";
1356                 if (acfg->cfgs [i]) {
1357                         symbol = g_strdup_printf (".Lm_%x", i + 1);
1358                         fprintf (acfg->fp, "%s%s-methods", sep, symbol);
1359                 }
1360                 else
1361                         fprintf (acfg->fp, "%s0xffffffff", sep);
1362         }
1363         fprintf (acfg->fp, "\n");
1364 }
1365
1366 static void
1367 emit_info (MonoAotCompile *acfg)
1368 {
1369         int i;
1370         char *symbol;
1371         GList *l;
1372
1373         /* Emit method info */
1374         symbol = g_strdup_printf ("method_infos");
1375         emit_section_change (acfg->fp, ".text", 1);
1376         emit_global (acfg->fp, symbol, FALSE);
1377         emit_alignment (acfg->fp, 8);
1378         emit_label (acfg->fp, symbol);
1379
1380         /* To reduce size of generated assembly code */
1381         symbol = g_strdup_printf ("mi");
1382         emit_label (acfg->fp, symbol);
1383
1384         for (l = acfg->method_order; l != NULL; l = l->next) {
1385                 i = GPOINTER_TO_UINT (l->data);
1386
1387                 if (acfg->cfgs [i])
1388                         emit_method_info (acfg, acfg->cfgs [i]);
1389         }
1390
1391         symbol = g_strdup_printf ("method_info_offsets");
1392         emit_section_change (acfg->fp, ".text", 1);
1393         emit_global (acfg->fp, symbol, FALSE);
1394         emit_alignment (acfg->fp, 8);
1395         emit_label(acfg->fp, symbol);
1396
1397         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1398                 const char *sep;
1399                 if ((i % 32) == 0) {
1400                         fprintf (acfg->fp, "\n.long ");
1401                         sep = "";
1402                 }
1403                 else
1404                         sep = ",";
1405                 if (acfg->cfgs [i]) {
1406                         symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1407                         fprintf (acfg->fp, "%s%s - mi", sep, symbol);
1408                 }
1409                 else
1410                         fprintf (acfg->fp, "%s0", sep);
1411         }
1412         fprintf (acfg->fp, "\n");
1413 }
1414
1415 static void
1416 emit_method_order (MonoAotCompile *acfg)
1417 {
1418         int i, index, len;
1419         char *symbol;
1420         GList *l;
1421
1422         symbol = g_strdup_printf ("method_order");
1423         emit_section_change (acfg->fp, ".text", 1);
1424         emit_global (acfg->fp, symbol, FALSE);
1425         emit_alignment (acfg->fp, 8);
1426         emit_label(acfg->fp, symbol);
1427
1428         /* First emit an index table */
1429         index = 0;
1430         len = 0;
1431         for (l = acfg->method_order; l != NULL; l = l->next) {
1432                 i = GPOINTER_TO_UINT (l->data);
1433
1434                 if (acfg->cfgs [i]) {
1435                         if ((index % 1024) == 0) {
1436                                 fprintf (acfg->fp, ".long %d\n", i);
1437                         }
1438
1439                         index ++;
1440                 }
1441
1442                 len ++;
1443         }
1444         fprintf (acfg->fp, ".long 0xffffff\n");
1445
1446         /* Then emit the whole method order */
1447         for (l = acfg->method_order; l != NULL; l = l->next) {
1448                 i = GPOINTER_TO_UINT (l->data);
1449
1450                 if (acfg->cfgs [i]) {
1451                         fprintf (acfg->fp, ".long %d\n", i);
1452                 }
1453         }       
1454         fprintf (acfg->fp, "\n");
1455
1456         symbol = g_strdup_printf ("method_order_end");
1457         emit_section_change (acfg->fp, ".text", 1);
1458         emit_global (acfg->fp, symbol, FALSE);
1459         emit_label(acfg->fp, symbol);
1460 }
1461
1462 static void
1463 emit_exception_info (MonoAotCompile *acfg)
1464 {
1465         int i;
1466         char *symbol;
1467
1468         symbol = g_strdup_printf ("ex_infos");
1469         emit_section_change (acfg->fp, ".text", 1);
1470         emit_global (acfg->fp, symbol, FALSE);
1471         emit_alignment (acfg->fp, 8);
1472         emit_label (acfg->fp, symbol);
1473
1474         /* To reduce size of generate assembly */
1475         symbol = g_strdup_printf ("ex");
1476         emit_label (acfg->fp, symbol);
1477
1478         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1479                 if (acfg->cfgs [i])
1480                         emit_exception_debug_info (acfg, acfg->cfgs [i]);
1481         }
1482
1483         symbol = g_strdup_printf ("ex_info_offsets");
1484         emit_section_change (acfg->fp, ".text", 1);
1485         emit_global (acfg->fp, symbol, FALSE);
1486         emit_alignment (acfg->fp, 8);
1487         emit_label(acfg->fp, symbol);
1488
1489         for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
1490                 const char *sep;
1491                 if ((i % 32) == 0) {
1492                         fprintf (acfg->fp, "\n.long ");
1493                         sep = "";
1494                 }
1495                 else
1496                         sep = ",";
1497                 if (acfg->cfgs [i]) {
1498                         symbol = g_strdup_printf (".Le_%x_p", i + 1);
1499                         fprintf (acfg->fp, "%s%s - ex", sep, symbol);
1500                 }
1501                 else
1502                         fprintf (acfg->fp, "%s0", sep);
1503         }
1504         fprintf (acfg->fp, "\n");
1505 }
1506
1507 static void
1508 emit_class_info (MonoAotCompile *acfg)
1509 {
1510         int i;
1511         char *symbol;
1512
1513         symbol = g_strdup_printf ("class_infos");
1514         emit_section_change (acfg->fp, ".text", 1);
1515         emit_global (acfg->fp, symbol, FALSE);
1516         emit_alignment (acfg->fp, 8);
1517         emit_label (acfg->fp, symbol);
1518
1519         for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
1520                 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
1521
1522         symbol = g_strdup_printf ("class_info_offsets");
1523         emit_section_change (acfg->fp, ".text", 1);
1524         emit_global (acfg->fp, symbol, FALSE);
1525         emit_alignment (acfg->fp, 8);
1526         emit_label(acfg->fp, symbol);
1527
1528         for (i = 0; i < acfg->image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
1529                 const char *sep;
1530                 if ((i % 32) == 0) {
1531                         fprintf (acfg->fp, "\n.long ");
1532                         sep = "";
1533                 }
1534                 else
1535                         sep = ",";
1536
1537                 symbol = g_strdup_printf (".LK_I_%x", i);
1538                 fprintf (acfg->fp, "%s%s - class_infos", sep, symbol);
1539         }
1540         fprintf (acfg->fp, "\n");
1541 }
1542
1543 static void
1544 emit_image_table (MonoAotCompile *acfg)
1545 {
1546         int i;
1547         char *symbol;
1548
1549         /*
1550          * The image table is small but referenced in a lot of places.
1551          * So we emit it at once, and reference its elements by an index.
1552          */
1553
1554         symbol = g_strdup_printf ("mono_image_table");
1555         emit_section_change (acfg->fp, ".text", 1);
1556         emit_global(acfg->fp, symbol, FALSE);
1557         emit_alignment(acfg->fp, 8);
1558         emit_label(acfg->fp, symbol);
1559         fprintf (acfg->fp, ".long %d\n", acfg->image_table->len);
1560         for (i = 0; i < acfg->image_table->len; i++) {
1561                 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1562                 MonoAssemblyName *aname = &image->assembly->aname;
1563
1564                 /* FIXME: Support multi-module assemblies */
1565                 g_assert (image->assembly->image == image);
1566
1567                 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1568                 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1569                 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1570                 fprintf (acfg->fp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1571
1572                 emit_alignment (acfg->fp, 8);
1573                 fprintf (acfg->fp, ".long %d\n", aname->flags);
1574                 fprintf (acfg->fp, ".long %d\n", aname->major);
1575                 fprintf (acfg->fp, ".long %d\n", aname->minor);
1576                 fprintf (acfg->fp, ".long %d\n", aname->build);
1577                 fprintf (acfg->fp, ".long %d\n", aname->revision);
1578         }
1579 }
1580
1581 static void
1582 emit_got (MonoAotCompile *acfg)
1583 {
1584         char *symbol;
1585
1586         /* Don't make GOT global so accesses to it don't need relocations */
1587         symbol = g_strdup_printf ("got");
1588         emit_section_change (acfg->fp, ".bss", 1);
1589         emit_alignment (acfg->fp, 8);
1590         emit_label(acfg->fp, symbol);
1591         if (acfg->got_offset > 0)
1592                 fprintf (acfg->fp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1593
1594         symbol = g_strdup_printf ("got_addr");
1595         emit_section_change (acfg->fp, ".data", 1);
1596         emit_global (acfg->fp, symbol, FALSE);
1597         emit_alignment (acfg->fp, 8);
1598         emit_label(acfg->fp, symbol);
1599         emit_pointer (acfg->fp, "got");
1600
1601         symbol = g_strdup_printf ("got_size");
1602         emit_section_change (acfg->fp, ".data", 1);
1603         emit_global (acfg->fp, symbol, FALSE);
1604         emit_alignment (acfg->fp, 8);
1605         emit_label(acfg->fp, symbol);
1606         fprintf (acfg->fp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1607 }
1608
1609 static void
1610 emit_globals (MonoAotCompile *acfg)
1611 {
1612         char *opts_str;
1613
1614         emit_string_symbol (acfg->fp, "mono_assembly_guid" , acfg->image->guid);
1615
1616         emit_string_symbol (acfg->fp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1617
1618         opts_str = g_strdup_printf ("%d", acfg->opts);
1619         emit_string_symbol (acfg->fp, "mono_aot_opt_flags", opts_str);
1620         g_free (opts_str);
1621 }
1622
1623 int
1624 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1625 {
1626         MonoImage *image = ass->image;
1627         char *command, *objfile, *tmpfname, *symbol;
1628         int i;
1629         MonoAotCompile *acfg;
1630         MonoCompile **cfgs;
1631         char *outfile_name, *tmp_outfile_name;
1632
1633         printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1634
1635         acfg = g_new0 (MonoAotCompile, 1);
1636         acfg->plt_offset_to_patch = g_hash_table_new (NULL, NULL);
1637         acfg->patch_to_plt_offset = g_hash_table_new (NULL, NULL);
1638         acfg->method_to_cfg = g_hash_table_new (NULL, NULL);
1639         acfg->image_hash = g_hash_table_new (NULL, NULL);
1640         acfg->image_table = g_ptr_array_new ();
1641         acfg->image = image;
1642         acfg->opts = opts;
1643
1644         mono_aot_parse_options (aot_options, &acfg->aot_opts);
1645
1646         load_profile_files (acfg);
1647
1648         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1649         acfg->fp = fdopen (i, "w+");
1650         g_assert (acfg->fp);
1651
1652         cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
1653         acfg->cfgs = cfgs;
1654         acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
1655         acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
1656
1657         /* Slot 0 is reserved for the address of the current assembly */
1658         acfg->got_offset = 1;
1659         /* PLT offset 0 is reserved for the PLT trampoline */
1660         acfg->plt_offset = 1;
1661
1662         /* Compile methods */
1663         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
1664                 compile_method (acfg, i);
1665
1666         emit_code (acfg);
1667
1668         emit_info (acfg);
1669
1670         emit_method_order (acfg);
1671
1672         emit_exception_info (acfg);
1673
1674         emit_class_info (acfg);
1675
1676         emit_plt (acfg);
1677
1678         emit_image_table (acfg);
1679
1680 #ifdef MONO_ARCH_HAVE_PIC_AOT
1681         emit_got (acfg);
1682 #endif
1683
1684         emit_globals (acfg);
1685
1686         symbol = g_strdup_printf ("mem_end");
1687         emit_section_change (acfg->fp, ".text", 1);
1688         emit_global (acfg->fp, symbol, FALSE);
1689         emit_alignment (acfg->fp, 8);
1690         emit_label(acfg->fp, symbol);
1691
1692         fclose (acfg->fp);
1693
1694         printf ("Code: %d Info: %d Ex Info: %d Class Info: %d PLT: %d GOT: %d\n", acfg->code_size, acfg->info_size, acfg->ex_info_size, acfg->class_info_size, acfg->plt_offset, (int)(acfg->got_offset * sizeof (gpointer)));
1695
1696 #if defined(__x86_64__)
1697         command = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1698 #elif defined(sparc) && SIZEOF_VOID_P == 8
1699         command = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1700 #else
1701         command = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1702         
1703 #endif
1704         printf ("Executing the native assembler: %s\n", command);
1705         if (system (command) != 0) {
1706                 g_free (command);
1707                 return 1;
1708         }
1709
1710         g_free (command);
1711
1712         if (acfg->aot_opts.outfile)
1713                 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
1714         else
1715                 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1716
1717         tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1718
1719 #if defined(sparc)
1720         command = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1721 #elif defined(__ppc__) && defined(__MACH__)
1722         command = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1723 #elif defined(PLATFORM_WIN32)
1724         command = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, tmpfname);
1725 #else
1726         command = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1727 #endif
1728         printf ("Executing the native linker: %s\n", command);
1729         if (system (command) != 0) {
1730                 g_free (tmp_outfile_name);
1731                 g_free (outfile_name);
1732                 g_free (command);
1733                 return 1;
1734         }
1735
1736         g_free (command);
1737         objfile = g_strdup_printf ("%s.o", tmpfname);
1738         unlink (objfile);
1739         g_free (objfile);
1740         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1741         printf ("Stripping the binary: %s\n", com);
1742         system (com);
1743         g_free (com);*/
1744
1745         rename (tmp_outfile_name, outfile_name);
1746
1747         g_free (tmp_outfile_name);
1748         g_free (outfile_name);
1749
1750         printf ("Compiled %d out of %d methods (%d%%)\n", acfg->ccount, acfg->mcount, acfg->mcount ? (acfg->ccount*100)/acfg->mcount : 100);
1751         printf ("%d methods contain absolute addresses (%d%%)\n", acfg->abscount, acfg->mcount ? (acfg->abscount*100)/acfg->mcount : 100);
1752         printf ("%d methods contain wrapper references (%d%%)\n", acfg->wrappercount, acfg->mcount ? (acfg->wrappercount*100)/acfg->mcount : 100);
1753         printf ("%d methods contain lmf pointers (%d%%)\n", acfg->lmfcount, acfg->mcount ? (acfg->lmfcount*100)/acfg->mcount : 100);
1754         printf ("%d methods have other problems (%d%%)\n", acfg->ocount, acfg->mcount ? (acfg->ocount*100)/acfg->mcount : 100);
1755         if (acfg->aot_opts.save_temps)
1756                 printf ("Retained input file.\n");
1757         else
1758                 unlink (tmpfname);
1759
1760         return 0;
1761 }
1762
1763 #else
1764
1765 /* AOT disabled */
1766
1767 int
1768 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1769 {
1770         return 0;
1771 }
1772
1773 #endif