2003-09-04 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/os/gc_wrapper.h>
34
35 #include "mini.h"
36
37 #define ENCODE_TYPE_POS(t,l) (((t) << 24) | (l))
38 #define DECODE_TYPE(v) ((v) >> 24)
39 #define DECODE_POS(v) ((v) & 0xffffff)
40
41 #ifdef PLATFORM_WIN32
42 #define SHARED_EXT ".dll"
43 #else
44 #define SHARED_EXT ".so"
45 #endif
46
47 typedef struct MonoAotMethodInfo {
48         MonoJitInfo *info;
49         MonoJumpInfo *patch_info;
50 } MonoAotMethodInfo;
51
52 typedef struct MonoAotModuleInfo {
53         /* Optimization flags used to compile the module */
54         guint32 opts;
55         /* Maps MonoMethods to MonoAotMethodInfos */
56         MonoGHashTable *methods;
57 } MonoAotModuleInfo;
58
59 static MonoGHashTable *aot_modules;
60
61 static CRITICAL_SECTION aot_mutex;
62
63 static MonoClass * 
64 decode_class_info (gpointer *data)
65 {
66         MonoImage *image;
67         MonoClass *klass;
68         
69         image = mono_image_loaded_by_guid ((char *)data [1]);
70         g_assert (image);
71
72         if (data [0]) {
73                 return mono_class_get (image, (guint32)data [0]);
74         } else {
75                 klass = decode_class_info (data [3]);
76                 return mono_array_class_get (klass, (guint32)data [2]);
77         }
78
79         return NULL;
80 }
81
82 static void
83 load_aot_module (MonoAssembly *assembly, gpointer user_data)
84 {
85         char *aot_name;
86         MonoAotModuleInfo *info;
87         gboolean usable = TRUE;
88         char *saved_guid = NULL;
89         char *aot_version = NULL;
90         char *opt_flags = NULL;
91
92         aot_name = g_strdup_printf ("%s.so", assembly->image->name);
93
94         assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
95
96         if (!assembly->aot_module)
97                 return;
98
99         g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
100         g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
101         g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
102
103         if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
104                 printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
105                 usable = FALSE;
106         }
107         else
108                 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
109                         printf ("AOT module %s has a different GUID than the corresponding assembly.\n", aot_name);
110                         usable = FALSE;
111                 }
112         g_free (aot_name);
113
114         if (!usable) {
115                 g_module_close (assembly->aot_module);
116                 assembly->aot_module = NULL;
117                 return;
118         }
119
120         /*
121          * It seems that MonoGHashTables are in the GC heap, so structures
122          * containing them must be in the GC heap as well :(
123          */
124 #ifdef HAVE_BOEHM_GC
125         info = GC_MALLOC (sizeof (MonoAotModuleInfo));
126 #else
127         info = g_new0 (MonoAotModuleInfo, 1);
128 #endif
129         info->methods = mono_g_hash_table_new (NULL, NULL);
130         sscanf (opt_flags, "%d", &info->opts);
131
132         EnterCriticalSection (&aot_mutex);
133         mono_g_hash_table_insert (aot_modules, assembly, info);
134         LeaveCriticalSection (&aot_mutex);
135
136         printf ("Loaded AOT Module for %s.\n", assembly->image->name);
137 }
138
139 void
140 mono_aot_init (void)
141 {
142         InitializeCriticalSection (&aot_mutex);
143
144         aot_modules = mono_g_hash_table_new (NULL, NULL);
145
146         mono_install_assembly_load_hook (load_aot_module, NULL);
147 }
148  
149 static gpointer
150 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
151 {
152         MonoClass *klass = method->klass;
153         MonoAssembly *ass = klass->image->assembly;
154         MonoJumpInfo *patch_info = NULL;
155         GModule *module = ass->aot_module;
156         char *method_label, *info_label;
157         guint8 *code = NULL;
158         gpointer *info;
159         guint code_len, used_int_regs, used_strings;
160         MonoAotModuleInfo *aot_module;
161         MonoAotMethodInfo *minfo;
162         int i;
163
164         if (!module)
165                 return NULL;
166
167         if (!method->token)
168                 return NULL;
169
170         aot_module = (MonoAotModuleInfo*)mono_g_hash_table_lookup (aot_modules, ass);
171
172         g_assert (klass->inited);
173
174         minfo = mono_g_hash_table_lookup (aot_module->methods, method);
175         if (minfo) {
176                 MonoJitInfo *jinfo;
177
178                 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
179                 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
180
181                 /* This method was already loaded in another appdomain */
182                 if (aot_module->opts & MONO_OPT_SHARED)
183                         /* Use the same method in the new appdomain */
184                         ;
185                 else {
186                         /* Create a copy of the original method and apply relocations */
187
188                         code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
189                         memcpy (code, minfo->info->code_start, minfo->info->code_size);
190
191                         //printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
192
193                         /* Do this outside the lock to avoid deadlocks */
194                         LeaveCriticalSection (&aot_mutex);
195                         mono_arch_patch_code (method, domain, code, minfo->patch_info);
196                         EnterCriticalSection (&aot_mutex);
197
198                         jinfo->code_start = code;
199                 }
200
201                 mono_jit_info_table_add (domain, jinfo);
202                 return jinfo->code_start;
203         }
204
205         method_label = g_strdup_printf ("method_%08X", method->token);
206
207         if (!g_module_symbol (module, method_label, (gpointer *)&code)) {
208                 g_free (method_label);          
209                 return NULL;
210         }
211
212         info_label = g_strdup_printf ("%s_patch_info", method_label);
213         if (!g_module_symbol (module, info_label, (gpointer *)&info)) {
214                 g_free (method_label);          
215                 g_free (info_label);
216                 return NULL;
217         }
218
219         {
220                 static int count = 0;
221
222                 count ++;
223
224                 if (getenv ("MONO_LASTAOT")) {
225                         if (count > atoi(getenv ("MONO_LASTAOT"))) {
226                                 return NULL;
227                         }
228                         else
229                                 if (count == atoi(getenv ("MONO_LASTAOT")))
230                                         printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
231                 }
232         }
233
234         code_len = GPOINTER_TO_UINT (*((gpointer **)info));
235         info++;
236         used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
237         info++;
238         used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
239         info++;
240
241         //printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
242
243         for (i = 0; i < used_strings; i++) {
244                 guint token =  GPOINTER_TO_UINT (*((gpointer **)info));
245                 info++;
246                 mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
247         }
248
249 #ifdef HAVE_BOEHM_GC
250         minfo = GC_MALLOC (sizeof (MonoAotMethodInfo));
251 #else
252         minfo = g_new0 (MonoAotMethodInfo, 1);
253 #endif
254
255         if (info) {
256                 MonoMemPool *mp = mono_mempool_new (); 
257                 MonoImage *image;
258                 guint8 *page_start;
259                 gpointer *table;
260                 int pages;
261                 int i, err;
262
263                 while (*info) {
264                         MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
265                         gpointer *data = *((gpointer **)info);
266                         info++;
267                         ji->type = DECODE_TYPE (GPOINTER_TO_UINT (*info));
268                         ji->ip.i = DECODE_POS (GPOINTER_TO_UINT (*info));
269
270                         switch (ji->type) {
271                         case MONO_PATCH_INFO_CLASS:
272                                 ji->data.klass = decode_class_info (data);
273                                 g_assert (ji->data.klass);
274                                 mono_class_init (ji->data.klass);
275                                 break;
276                         case MONO_PATCH_INFO_VTABLE:
277                                 ji->data.klass = decode_class_info (data);
278                                 g_assert (ji->data.klass);
279                                 mono_class_init (ji->data.klass);
280                                 break;
281                         case MONO_PATCH_INFO_IMAGE:
282                                 ji->data.image = mono_image_loaded_by_guid ((char *)data);
283                                 g_assert (ji->data.image);
284                                 break;
285                         case MONO_PATCH_INFO_METHOD:
286                         case MONO_PATCH_INFO_METHODCONST:
287                                 image = mono_image_loaded_by_guid ((char *)data [1]);
288                                 g_assert (image);
289                                 ji->data.method = mono_get_method (image, (guint32)data [0], NULL);
290                                 g_assert (ji->data.method);
291                                 mono_class_init (ji->data.method->klass);
292                                 break;
293                         case MONO_PATCH_INFO_FIELD:
294                         case MONO_PATCH_INFO_SFLDA:
295                                 image = mono_image_loaded_by_guid ((char *)data [1]);
296                                 g_assert (image);
297                                 ji->data.field = mono_field_from_token (image, (guint32)data [0], NULL);
298                                 mono_class_init (ji->data.field->parent);
299                                 g_assert (ji->data.field);
300                                 break;
301                         case MONO_PATCH_INFO_INTERNAL_METHOD:
302                                 ji->data.name = (char *)data;
303                                 g_assert (ji->data.name);
304                                 break;
305                         case MONO_PATCH_INFO_SWITCH:
306                                 ji->table_size = (int)data [0];
307                                 table = g_new (gpointer, ji->table_size);
308                                 ji->data.target = table;
309                                 for (i = 0; i < ji->table_size; i++) {
310                                         table [i] = data [i + 1];
311                                 }
312                                 break;
313                         case MONO_PATCH_INFO_R4:
314                         case MONO_PATCH_INFO_R8:
315                                 ji->data.target = data;
316                                 break;
317                         case MONO_PATCH_INFO_LDSTR:
318                         case MONO_PATCH_INFO_LDTOKEN:
319                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
320                                 ji->data.target = *data;
321                                 break;
322                         case MONO_PATCH_INFO_EXC_NAME:
323                                 ji->data.klass = decode_class_info (data);
324                                 g_assert (ji->data.klass);
325                                 mono_class_init (ji->data.klass);
326                                 ji->data.name = ji->data.klass->name;
327                                 break;
328                         case MONO_PATCH_INFO_METHOD_REL:
329                                 ji->data.offset = (int)data [0];
330                                 break;
331                         default:
332                                 g_warning ("unhandled type %d", ji->type);
333                                 g_assert_not_reached ();
334                         }
335
336                         info++;
337                         ji->next = patch_info;
338                         patch_info = ji;
339                 }
340
341 #ifndef PLATFORM_WIN32
342                 /* disable write protection */
343                 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
344                 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
345                 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
346                 g_assert (err == 0);
347 #else
348                 {
349                         DWORD oldp;
350                         g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
351                 }
352 #endif
353
354                 /* Do this outside the lock to avoid deadlocks */
355                 LeaveCriticalSection (&aot_mutex);
356                 mono_arch_patch_code (method, domain, code, patch_info);
357                 EnterCriticalSection (&aot_mutex);
358
359                 if (aot_module->opts & MONO_OPT_SHARED)
360                         /* No need to cache this */
361                         mono_mempool_destroy (mp);
362                 else
363                         minfo->patch_info = patch_info;
364         }
365
366         g_free (info_label);
367         g_free (method_label);
368
369         {
370                 MonoJitInfo *info;
371                 info = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
372                 info->code_size = code_len;
373                 info->used_regs = used_int_regs;
374                 info->method = method;
375                 info->code_start = code;
376                 info->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
377                 mono_jit_info_table_add (domain, info);
378
379                 minfo->info = info;
380                 mono_g_hash_table_insert (aot_module->methods, method, minfo);
381         }
382         mono_jit_stats.methods_aot++;
383
384         return code;
385 }
386
387 gpointer
388 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
389 {
390         gpointer res;
391
392         EnterCriticalSection (&aot_mutex);
393         res = mono_aot_get_method_inner (domain, method);
394         LeaveCriticalSection (&aot_mutex);
395         return res;
396 }
397
398 #if 0
399 static void
400 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
401 {
402         int i;
403
404         fprintf (fp, ".globl %s\n", name);
405         fprintf (fp, ".data\n\t.align %d\n", align);
406         fprintf (fp, "\t.type %s,@object\n", name);
407         fprintf (fp, "\t.size %s,%d\n", name, size);
408         fprintf (fp, "%s:\n", name);
409         for (i = 0; i < size; i++) { 
410                 fprintf (fp, ".byte %d\n", buf [i]);
411         }
412         
413 }
414 #endif
415
416 static void
417 write_string_symbol (FILE *fp, const char *name, const char *value)
418 {
419         fprintf (fp, ".globl %s\n", name);
420         fprintf (fp, ".data\n");
421         fprintf (fp, "%s:\n", name);
422         fprintf (fp, "\t.string \"%s\"\n", value);
423 }
424
425 static guint32
426 mono_get_field_token (MonoClassField *field) 
427 {
428         MonoClass *klass = field->parent;
429         int i;
430
431         for (i = 0; i < klass->field.count; ++i) {
432                 if (field == &klass->fields [i])
433                         return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
434         }
435
436         g_assert_not_reached ();
437         return 0;
438 }
439
440 static char *
441 cond_emit_image_label (FILE *tmpfp, GHashTable *image_hash, MonoImage *image)
442 {
443         char *label;
444         
445         if ((label = g_hash_table_lookup (image_hash, image))) 
446                 return label;
447
448         label = g_strdup_printf ("image_patch_info_%p", image);
449         fprintf (tmpfp, "%s:\n", label);
450         fprintf (tmpfp, "\t.string \"%s\"\n", image->guid);
451
452         g_hash_table_insert (image_hash, image, label);
453
454         return label;
455 }
456
457 static char *
458 cond_emit_icall_label (FILE *tmpfp, GHashTable *hash, const char *icall_name)
459 {
460         char *label;
461
462         if ((label = g_hash_table_lookup (hash, icall_name))) 
463                 return label;
464
465         label = g_strdup_printf ("icall_patch_info_%s", icall_name);
466         fprintf (tmpfp, "%s:\n", label);
467         fprintf (tmpfp, "\t.string \"%s\"\n", icall_name);
468
469         g_hash_table_insert (hash, (gpointer)icall_name, label);
470
471         return label;
472 }
473
474 static char *
475 cond_emit_method_label (FILE *tmpfp, GHashTable *hash, MonoJumpInfo *patch_info)
476 {
477         MonoMethod *method = patch_info->data.method;
478         char *l1, *l2;
479
480         if ((l1 = g_hash_table_lookup (hash, method))) 
481                 return l1;
482         
483         l2 = cond_emit_image_label (tmpfp, hash, method->klass->image);
484         fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
485         l1 = g_strdup_printf ("method_patch_info_%08x_%p", method->token, method);
486         fprintf (tmpfp, "%s:\n", l1);
487         fprintf (tmpfp, "\t.long 0x%08x\n", method->token);
488         g_assert (method->token);
489         fprintf (tmpfp, "\t.long %s\n", l2);
490                 
491         g_hash_table_insert (hash, method, l1);
492
493         return l1;
494 }
495
496 static char *
497 cond_emit_klass_label (FILE *tmpfp, GHashTable *hash, MonoClass *klass)
498 {
499         char *l1, *l2, *el = NULL;
500
501         if ((l1 = g_hash_table_lookup (hash, klass))) 
502                 return l1;
503
504         if (!klass->type_token) {
505                 g_assert (klass->rank > 0);
506                 el = cond_emit_klass_label (tmpfp, hash, klass->element_class);
507         }
508         
509         l2 = cond_emit_image_label (tmpfp, hash, klass->image);
510         fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
511         l1 = g_strdup_printf ("klass_patch_info_%08x_%p", klass->type_token, klass);
512         fprintf (tmpfp, "%s:\n", l1);
513         fprintf (tmpfp, "\t.long 0x%08x\n", klass->type_token);
514         fprintf (tmpfp, "\t.long %s\n", l2);
515
516         if (el) {
517                 fprintf (tmpfp, "\t.long %d\n", klass->rank);   
518                 fprintf (tmpfp, "\t.long %s\n", el);
519         }
520
521         g_hash_table_insert (hash, klass, l1);
522
523         return l1;
524 }
525
526 static char *
527 cond_emit_field_label (FILE *tmpfp, GHashTable *hash, MonoJumpInfo *patch_info)
528 {
529         MonoClassField *field = patch_info->data.field;
530         char *l1, *l2;
531         guint token;
532
533         if ((l1 = g_hash_table_lookup (hash, field))) 
534                 return l1;
535         
536         l2 = cond_emit_image_label (tmpfp, hash, field->parent->image);
537         fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
538         token = mono_get_field_token (field);
539         l1 = g_strdup_printf ("klass_patch_info_%08x_%p", token, field);
540         fprintf (tmpfp, "%s:\n", l1);
541         fprintf (tmpfp, "\t.long 0x%08x\n", token);
542         g_assert (token);
543         fprintf (tmpfp, "\t.long %s\n", l2);
544                 
545         g_hash_table_insert (hash, field, l1);
546
547         return l1;
548 }
549
550 int
551 mono_compile_assembly (MonoAssembly *ass, guint32 opts)
552 {
553         MonoCompile *cfg;
554         MonoImage *image = ass->image;
555         MonoMethod *method;
556         GList *l;
557         char *com, *tmpfname, *opts_str;
558         FILE *tmpfp;
559         int i, j;
560         guint8 *code, *mname;
561         int ccount = 0, mcount = 0, lmfcount = 0, ecount = 0, abscount = 0, wrappercount = 0, ocount = 0;
562         GHashTable *ref_hash;
563         int func_alignment = 16;
564
565         printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
566
567         i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
568         tmpfp = fdopen (i, "w+");
569         g_assert (tmpfp);
570
571         ref_hash = g_hash_table_new (NULL, NULL);
572
573         write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
574
575         write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
576
577         opts_str = g_strdup_printf ("%d", opts);
578         write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
579         g_free (opts_str);
580
581         for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
582                 MonoJumpInfo *patch_info;
583                 gboolean skip;
584                 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
585                 method = mono_get_method (image, token, NULL);
586                 
587                 /* fixme: maybe we can also precompile wrapper methods */
588                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
589                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
590                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
591                     (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
592                         //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
593                         continue;
594                 }
595
596                 mcount++;
597
598                 /* fixme: we need to patch the IP for the LMF in that case */
599                 if (method->save_lmf) {
600                         //printf ("Skip (needs lmf):  %s\n", mono_method_full_name (method, TRUE));
601                         lmfcount++;
602                         continue;
603                 }
604
605                 /* fixme: add methods with exception tables */
606                 if (((MonoMethodNormal *)method)->header->num_clauses) {
607                         //printf ("Skip (exceptions): %s\n", mono_method_full_name (method, TRUE));
608                         ecount++;
609                         continue;
610                 }
611
612                 //printf ("START:           %s\n", mono_method_full_name (method, TRUE));
613                 //mono_compile_method (method);
614
615                 cfg = mini_method_compile (method, opts, mono_root_domain, 0);
616                 g_assert (cfg);
617
618                 if (cfg->disable_aot) {
619                         ocount++;
620                         continue;
621                 }
622
623                 skip = FALSE;
624                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
625                         if (patch_info->type == MONO_PATCH_INFO_ABS) {
626                                 /* unable to handle this */
627                                 //printf ("Skip (abs addr):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
628                                 skip = TRUE;    
629                                 break;
630                         }
631                 }
632
633                 if (skip) {
634                         abscount++;
635                         continue;
636                 }
637
638                 skip = FALSE;
639                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
640                         if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
641                              patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
642                             patch_info->data.method->wrapper_type) {
643                                 /* unable to handle this */
644                                 //printf ("Skip (wrapper call):   %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
645                                 skip = TRUE;    
646                                 break;
647                         }
648                 }
649
650                 if (skip) {
651                         wrappercount++;
652                         continue;
653                 }
654
655                 //printf ("Compile:           %s\n", mono_method_full_name (method, TRUE));
656
657                 code = cfg->native_code;
658
659                 fprintf (tmpfp, ".text\n");
660                 mname = g_strdup_printf ("method_%08X", token);
661                 fprintf (tmpfp, "\t.align %d\n", func_alignment);
662                 fprintf (tmpfp, ".globl %s\n", mname);
663                 fprintf (tmpfp, "\t.type %s,@function\n", mname);
664                 fprintf (tmpfp, "%s:\n", mname);
665
666                 for (j = 0; j < cfg->code_len; j++) 
667                         fprintf (tmpfp, ".byte %d\n", (unsigned int) code [j]);
668
669                 fprintf (tmpfp, ".data\n");
670
671                 j = 0;
672                 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
673                         switch (patch_info->type) {
674                         case MONO_PATCH_INFO_LABEL:
675                         case MONO_PATCH_INFO_BB:
676                                 /* relative jumps are no problem, there is no need to handle then here */
677                                 break;
678                         case MONO_PATCH_INFO_SWITCH: {
679                                 gpointer *table = (gpointer *)patch_info->data.target;
680                                 int k;
681
682                                 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
683                                 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
684                                 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
685
686                                 for (k = 0; k < patch_info->table_size; k++) {
687                                         fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
688                                 }
689                                 j++;
690                                 break;
691                         }
692                         case MONO_PATCH_INFO_INTERNAL_METHOD:
693                                 patch_info->data.name = cond_emit_icall_label (tmpfp, ref_hash, patch_info->data.name);
694                                 j++;
695                                 break;
696                         case MONO_PATCH_INFO_METHODCONST:
697                         case MONO_PATCH_INFO_METHOD:
698                                 patch_info->data.name = cond_emit_method_label (tmpfp, ref_hash, patch_info);
699                                 j++;
700                                 break;
701                         case MONO_PATCH_INFO_FIELD:
702                                 patch_info->data.name = cond_emit_field_label (tmpfp, ref_hash, patch_info);
703                                 j++;
704                                 break;
705                         case MONO_PATCH_INFO_CLASS:
706                                 patch_info->data.name = cond_emit_klass_label (tmpfp, ref_hash, patch_info->data.klass);
707                                 j++;
708                                 break;
709                         case MONO_PATCH_INFO_IMAGE:
710                                 patch_info->data.name = cond_emit_image_label (tmpfp, ref_hash, patch_info->data.image);
711                                 j++;
712                                 break;
713                         case MONO_PATCH_INFO_EXC_NAME: {
714                                 MonoClass *ex_class;
715
716                                 ex_class =
717                                         mono_class_from_name (mono_defaults.exception_class->image,
718                                                                                   "System", patch_info->data.target);
719                                 g_assert (ex_class);
720                                 patch_info->data.name = cond_emit_klass_label (tmpfp, ref_hash, ex_class);
721                                 j++;
722                                 break;
723                         }
724                         case MONO_PATCH_INFO_R4:
725                                 fprintf (tmpfp, "\t.align 8\n");
726                                 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
727                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
728                                 
729                                 j++;
730                                 break;
731                         case MONO_PATCH_INFO_R8:
732                                 fprintf (tmpfp, "\t.align 8\n");
733                                 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
734                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
735                                 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
736                                 
737                                 j++;
738                                 break;
739                         case MONO_PATCH_INFO_METHOD_REL:
740                                 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
741                                 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
742                                 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
743                                 j++;
744                                 break;
745                         case MONO_PATCH_INFO_VTABLE:
746                                 patch_info->data.name = cond_emit_klass_label (tmpfp, ref_hash, patch_info->data.klass);
747                                 j++;
748                                 break;
749                         case MONO_PATCH_INFO_SFLDA:
750                                 patch_info->data.name = cond_emit_field_label (tmpfp, ref_hash, patch_info);
751                                 j++;
752                                 break;
753                         case MONO_PATCH_INFO_LDSTR:
754                         case MONO_PATCH_INFO_LDTOKEN:
755                         case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
756                                 fprintf (tmpfp, "\t.align 8\n");
757                                 fprintf (tmpfp, "%s_patch_info_%d:\n", mname, j);
758                                 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
759                                 j++;
760                                 break;
761                         default:
762                                 g_warning ("unable to handle jump info %d", patch_info->type);
763                                 g_assert_not_reached ();
764                         }
765                 }
766                 
767                 fprintf (tmpfp, ".globl %s_patch_info\n", mname);
768                 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
769                 fprintf (tmpfp, "%s_patch_info:\n", mname);
770                 
771                 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
772                 fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
773
774                 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
775                 for (l = cfg->ldstr_list; l; l = l->next) {
776                         fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
777                 }
778
779                 if (j) {
780                         j = 0;
781                         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
782                                 switch (patch_info->type) {
783                                 case MONO_PATCH_INFO_METHODCONST:
784                                 case MONO_PATCH_INFO_METHOD:
785                                 case MONO_PATCH_INFO_CLASS:
786                                 case MONO_PATCH_INFO_FIELD:
787                                 case MONO_PATCH_INFO_INTERNAL_METHOD:
788                                 case MONO_PATCH_INFO_IMAGE:
789                                 case MONO_PATCH_INFO_VTABLE:
790                                 case MONO_PATCH_INFO_SFLDA:
791                                 case MONO_PATCH_INFO_EXC_NAME:
792                                         fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
793                                         fprintf (tmpfp, "\t.long 0x%08x\n", ENCODE_TYPE_POS (patch_info->type, patch_info->ip.i));
794                                         j++;
795                                         break;
796                                 case MONO_PATCH_INFO_SWITCH:
797                                 case MONO_PATCH_INFO_R4:
798                                 case MONO_PATCH_INFO_R8:
799                                 case MONO_PATCH_INFO_METHOD_REL:
800                                 case MONO_PATCH_INFO_LDSTR:
801                                 case MONO_PATCH_INFO_LDTOKEN:
802                                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
803                                         fprintf (tmpfp, "\t.long %s_patch_info_%d\n", mname, j);
804                                         fprintf (tmpfp, "\t.long 0x%08x\n", ENCODE_TYPE_POS (patch_info->type, patch_info->ip.i));
805                                         j++;
806                                         break;
807                                 case MONO_PATCH_INFO_LABEL:
808                                 case MONO_PATCH_INFO_BB:
809                                         break;
810                                 default:
811                                         g_warning ("unable to handle jump info %d", patch_info->type);
812                                         g_assert_not_reached ();
813                                 }
814
815                         }
816                 }
817                 /* NULL terminated array */
818                 fprintf (tmpfp, "\t.long 0\n");
819
820                 /* fixme: save the rest of the required infos */
821
822                 g_free (mname);
823                 mono_destroy_compile (cfg);
824
825                 ccount++;
826         }
827
828         fclose (tmpfp);
829
830         com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
831         printf ("Executing the native assembler: %s\n", com);
832         system (com);
833         g_free (com);
834         com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
835         printf ("Executing the native linker: %s\n", com);
836         system (com);
837         g_free (com);
838         com = g_strdup_printf ("%s.o", tmpfname);
839         unlink (com);
840         g_free (com);
841         /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
842         printf ("Stripping the binary: %s\n", com);
843         system (com);
844         g_free (com);*/
845
846         printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
847         printf ("%d methods contain exception tables (%d%%)\n", ecount, (ecount*100)/mcount);
848         printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
849         printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
850         printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
851         printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);
852         unlink (tmpfname);
853
854         return 0;
855 }