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