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