2 * aot.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
7 * (C) 2002 Ximian, Inc.
11 #include <sys/types.h>
15 #ifndef PLATFORM_WIN32
21 #include <limits.h> /* for PAGESIZE */
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>
39 #define SHARED_EXT ".dll"
41 #define SHARED_EXT ".so"
44 typedef struct MonoAotMethod {
46 MonoJumpInfo *patch_info;
49 typedef struct MonoAotModule {
50 /* Optimization flags used to compile the module */
52 /* Maps MonoMethods to MonoAotMethodInfos */
53 MonoGHashTable *methods;
55 MonoImage **image_table;
56 guint32* methods_present_table;
59 typedef struct MonoAotCompile {
62 GHashTable *icall_hash;
63 GPtrArray *icall_table;
64 GHashTable *image_hash;
65 GPtrArray *image_table;
68 static MonoGHashTable *aot_modules;
70 static CRITICAL_SECTION aot_mutex;
72 static guint32 mono_aot_verbose = 0;
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
81 static gboolean use_loaded_code = FALSE;
84 static gint32 mono_last_aot_method = -1;
87 decode_class_info (MonoAotModule *module, gpointer *data)
92 image = module->image_table [(guint32)data [1]];
96 return mono_class_get (image, (guint32)data [0]);
98 klass = decode_class_info (module, data [3]);
99 return mono_array_class_get (klass, (guint32)data [2]);
106 load_aot_module (MonoAssembly *assembly, gpointer user_data)
110 gboolean usable = TRUE;
111 char *saved_guid = NULL;
112 char *aot_version = NULL;
113 char *opt_flags = NULL;
115 aot_name = g_strdup_printf ("%s.so", assembly->image->name);
117 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
119 if (!assembly->aot_module)
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);
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);
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);
140 g_module_close (assembly->aot_module);
141 assembly->aot_module = NULL;
146 * It seems that MonoGHashTables are in the GC heap, so structures
147 * containing them must be in the GC heap as well :(
150 info = GC_MALLOC (sizeof (MonoAotModule));
152 info = g_new0 (MonoAotModule, 1);
154 info->methods = mono_g_hash_table_new (NULL, NULL);
155 sscanf (opt_flags, "%d", &info->opts);
157 /* Read image table */
159 guint32 table_len, i;
162 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
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);
177 g_module_close (assembly->aot_module);
178 assembly->aot_module = NULL;
181 table += strlen (table) + 1;
185 /* Read icall table */
187 guint32 table_len, i;
190 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
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;
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);
206 EnterCriticalSection (&aot_mutex);
207 mono_g_hash_table_insert (aot_modules, assembly, info);
208 LeaveCriticalSection (&aot_mutex);
210 if (mono_aot_verbose > 0)
211 printf ("Loaded AOT Module for %s.\n", assembly->image->name);
217 InitializeCriticalSection (&aot_mutex);
219 aot_modules = mono_g_hash_table_new (NULL, NULL);
221 mono_install_assembly_load_hook (load_aot_module, NULL);
223 if (getenv ("MONO_LASTAOT"))
224 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
228 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
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];
238 guint code_len, used_int_regs, used_strings;
239 MonoAotModule *aot_module;
240 MonoAotMethod *minfo;
242 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
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))
257 aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
259 g_assert (klass->inited);
261 minfo = mono_g_hash_table_lookup (aot_module->methods, method);
263 /* Duplicate jinfo */
264 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
265 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
266 if (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);
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 */
276 else if (!minfo->patch_info)
277 /* Use the same method in the new appdomain */
280 /* Create a copy of the original method and apply relocations */
282 code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
283 memcpy (code, minfo->info->code_start, minfo->info->code_size);
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);
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);
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;
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;
312 /* Do a fast check to see whenever the method exists */
314 guint32 index = mono_metadata_token_index (method->token) - 1;
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));
324 sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
326 if (!g_module_symbol (module, method_label, (gpointer *)&code))
329 sprintf (info_label, "%s_p", method_label);
331 if (!g_module_symbol (module, info_label, (gpointer *)&info))
334 if (mono_last_aot_method != -1) {
335 if (mono_jit_stats.methods_aot > mono_last_aot_method)
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);
343 minfo = GC_MALLOC (sizeof (MonoAotMethod));
345 minfo = g_new0 (MonoAotMethod, 1);
348 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
350 code_len = GPOINTER_TO_UINT (*((gpointer **)info));
352 used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
355 if (!use_loaded_code) {
357 code2 = mono_mempool_alloc (domain->code_mp, code_len);
358 memcpy (code2, code, code_len);
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);
365 /* Exception table */
366 if (header->num_clauses) {
368 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
369 jinfo->num_clauses = header->num_clauses;
371 jinfo->exvar_offset = GPOINTER_TO_UINT (*((gpointer**)info));
374 for (i = 0; i < header->num_clauses; ++i) {
375 MonoExceptionClause *ec = &header->clauses [i];
376 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
378 ei->flags = ec->flags;
379 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
380 ei->data.filter = code + GPOINTER_TO_UINT (*((gpointer**)info));
382 ei->data.token = GPOINTER_TO_UINT (*((gpointer**)info));
384 ei->try_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
386 ei->try_end = code + GPOINTER_TO_UINT (*((gpointer**)info));
388 ei->handler_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
393 if (aot_module->opts & MONO_OPT_SHARED) {
394 used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
400 for (i = 0; i < used_strings; i++) {
401 guint token = GPOINTER_TO_UINT (*((gpointer **)info));
403 mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
415 if (aot_module->opts & MONO_OPT_SHARED)
416 mp = mono_mempool_new ();
422 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
428 b2 = *((guint8*)info + 1);
430 info = (gpointer*)((guint8*)info + 2);
434 if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
435 ji->ip.i = GPOINTER_TO_UINT (*info);
439 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
441 ji->ip.i += last_offset;
442 last_offset = ji->ip.i;
443 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
445 data = *((gpointer **)info);
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);
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);
460 case MONO_PATCH_INFO_IMAGE:
461 ji->data.image = aot_module->image_table [(guint32)data];
462 g_assert (ji->data.image);
464 case MONO_PATCH_INFO_METHOD:
465 case MONO_PATCH_INFO_METHODCONST:
466 case MONO_PATCH_INFO_METHOD_JUMP: {
467 guint32 image_index, token;
469 image_index = (guint32)data >> 24;
470 token = MONO_TOKEN_METHOD_DEF | ((guint32)data & 0xffffff);
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);
479 case MONO_PATCH_INFO_WRAPPER: {
480 guint32 image_index, token;
481 guint32 wrapper_type;
483 wrapper_type = (guint32)data[0];
484 image_index = (guint32)data[1] >> 24;
485 token = MONO_TOKEN_METHOD_DEF | ((guint32)data[1] & 0xffffff);
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);
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);
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]);
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);
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];
517 case MONO_PATCH_INFO_R4:
518 case MONO_PATCH_INFO_R8:
519 ji->data.target = data;
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]);
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;
533 case MONO_PATCH_INFO_METHOD_REL:
534 ji->data.offset = (int)data [0];
537 g_warning ("unhandled type %d", ji->type);
538 g_assert_not_reached ();
542 ji->next = patch_info;
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);
556 g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
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);
566 if (aot_module->opts & MONO_OPT_SHARED)
567 /* No need to cache patches */
568 mono_mempool_destroy (mp);
570 minfo->patch_info = patch_info;
573 mono_jit_stats.methods_aot++;
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;
583 mono_g_hash_table_insert (aot_module->methods, method, minfo);
590 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
594 EnterCriticalSection (&aot_mutex);
595 info = mono_aot_get_method_inner (domain, method);
596 LeaveCriticalSection (&aot_mutex);
598 /* Do this outside the lock */
600 mono_jit_info_table_add (domain, info);
609 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
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]);
626 write_string_symbol (FILE *fp, const char *name, const char *value)
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);
635 mono_get_field_token (MonoClassField *field)
637 MonoClass *klass = field->parent;
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);
645 g_assert_not_reached ();
650 get_image_index (MonoAotCompile *cfg, MonoImage *image)
654 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
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);
666 emit_image_index (MonoAotCompile *cfg, MonoImage *image)
670 image_index = get_image_index (cfg, image);
672 fprintf (cfg->fp, "\t.long %d\n", image_index);
676 cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
678 char *l1, *el = NULL;
680 if ((l1 = g_hash_table_lookup (cfg->ref_hash, klass)))
683 if (!klass->type_token) {
684 g_assert (klass->rank > 0);
685 el = cond_emit_klass_label (cfg, klass->element_class);
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);
695 fprintf (cfg->fp, "\t.long %d\n", klass->rank);
696 fprintf (cfg->fp, "\t.long %s\n", el);
699 g_hash_table_insert (cfg->ref_hash, klass, l1);
705 cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
707 MonoClassField *field = patch_info->data.field;
711 if ((l1 = g_hash_table_lookup (cfg->ref_hash, field)))
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);
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);
723 g_hash_table_insert (cfg->ref_hash, field, l1);
729 compare_patches (gconstpointer a, gconstpointer b)
733 i = (*(MonoJumpInfo**)a)->ip.i;
734 j = (*(MonoJumpInfo**)b)->ip.i;
746 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
752 guint8 *code, *mname;
753 int func_alignment = 16;
755 MonoJumpInfo *patch_info;
756 MonoMethodHeader *header;
759 method = cfg->method;
760 code = cfg->native_code;
761 header = ((MonoMethodNormal*)method)->header;
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);
770 for (i = 0; i < cfg->code_len; i++)
771 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
773 fprintf (tmpfp, ".text 1\n");
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);
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 */
789 case MONO_PATCH_INFO_SWITCH: {
790 gpointer *table = (gpointer *)patch_info->data.target;
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);
797 for (k = 0; k < patch_info->table_size; k++) {
798 fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
803 case MONO_PATCH_INFO_INTERNAL_METHOD: {
806 icall_index = (guint32)g_hash_table_lookup (acfg->icall_hash, patch_info->data.name);
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);
813 patch_info->data.name = g_strdup_printf ("%d", icall_index - 1);
817 case MONO_PATCH_INFO_METHODCONST:
818 case MONO_PATCH_INFO_METHOD:
819 case MONO_PATCH_INFO_METHOD_JUMP: {
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.
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);
830 patch_info->data.name =
831 g_strdup_printf ("%d", (image_index << 24) + (mono_metadata_token_index (token)));
835 case MONO_PATCH_INFO_WRAPPER: {
840 m = mono_marshal_method_from_wrapper (patch_info->data.method);
841 image_index = get_image_index (acfg, m->klass->image);
843 g_assert (image_index < 256);
844 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
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)));
853 case MONO_PATCH_INFO_FIELD:
854 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
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);
862 case MONO_PATCH_INFO_IMAGE:
863 patch_info->data.name = g_strdup_printf ("%d", get_image_index (acfg, patch_info->data.image));
866 case MONO_PATCH_INFO_EXC_NAME: {
870 mono_class_from_name (mono_defaults.exception_class->image,
871 "System", patch_info->data.target);
873 patch_info->data.name = cond_emit_klass_label (acfg, ex_class);
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));
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));
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);
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);
901 case MONO_PATCH_INFO_SFLDA:
902 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
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);
915 g_warning ("unable to handle jump info %d", patch_info->type);
916 g_assert_not_reached ();
920 fprintf (tmpfp, ".globl %s_p\n", mname);
921 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
922 fprintf (tmpfp, "%s_p:\n", mname);
924 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
925 fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
927 /* Exception table */
928 if (header->num_clauses) {
929 MonoJitInfo *jinfo = cfg->jit_info;
931 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
933 for (k = 0; k < header->num_clauses; ++k) {
934 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
936 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
937 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->data.filter - code);
939 /* fixme: tokens are not global */
940 fprintf (tmpfp, "\t.long %d\n", ei->data.token);
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);
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);
956 /* Used only in shared mode */
957 g_assert (!cfg->ldstr_list);
959 //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
966 for (pindex = 0; pindex < patches->len; ++pindex) {
968 patch_info = g_ptr_array_index (patches, pindex);
970 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
971 (patch_info->type == MONO_PATCH_INFO_BB))
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;
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));
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);
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);
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);
1018 case MONO_PATCH_INFO_LABEL:
1019 case MONO_PATCH_INFO_BB:
1022 g_warning ("unable to handle jump info %d", patch_info->type);
1023 g_assert_not_reached ();
1030 * 0 is PATCH_INFO_BB, which can't be in the file.
1032 /* NULL terminated array */
1033 fprintf (tmpfp, "\t.long 0\n");
1035 /* fixme: save the rest of the required infos */
1041 mono_compile_assembly (MonoAssembly *ass, guint32 opts)
1044 MonoImage *image = ass->image;
1046 char *com, *tmpfname, *opts_str;
1050 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1051 GHashTable *ref_hash;
1052 MonoAotCompile *acfg;
1055 printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
1057 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1058 tmpfp = fdopen (i, "w+");
1061 ref_hash = g_hash_table_new (NULL, NULL);
1063 acfg = g_new0 (MonoAotCompile, 1);
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 ();
1071 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1073 write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1075 opts_str = g_strdup_printf ("%d", opts);
1076 write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1079 emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
1081 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1082 MonoJumpInfo *patch_info;
1084 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1085 method = mono_get_method (image, token, NULL);
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));
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));
1105 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1106 //mono_compile_method (method);
1108 cfg = mini_method_compile (method, opts, mono_root_domain, 0);
1111 if (cfg->disable_aot) {
1112 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
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);
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;
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));
1156 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1159 emit_method (acfg, cfg);
1161 mono_destroy_compile (cfg);
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.
1172 /* Emit icall table */
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));
1183 /* Emit image table */
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);
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.
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);
1209 nrows = image->tables [MONO_TABLE_METHOD].rows;
1210 for (i = 0; i < nrows / 32 + 1; ++i) {
1212 for (k = 0; k < 32; ++k) {
1213 if (emitted [(i * 32) + k])
1216 //printf ("EMITTED [%d] = %d.\n", i, b);
1217 fprintf (tmpfp, "\t.long %d\n", w);
1223 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1224 printf ("Executing the native assembler: %s\n", 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);
1231 com = g_strdup_printf ("%s.o", tmpfname);
1234 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1235 printf ("Stripping the binary: %s\n", com);
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);