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