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