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/os/gc_wrapper.h>
38 #define SHARED_EXT ".dll"
40 #define SHARED_EXT ".so"
43 typedef struct MonoAotMethod {
45 MonoJumpInfo *patch_info;
48 typedef struct MonoAotModule {
49 /* Optimization flags used to compile the module */
51 /* Maps MonoMethods to MonoAotMethodInfos */
52 MonoGHashTable *methods;
54 MonoImage **image_table;
55 guint32* methods_present_table;
58 typedef struct MonoAotCompile {
61 GHashTable *icall_hash;
62 GPtrArray *icall_table;
63 GHashTable *image_hash;
64 GPtrArray *image_table;
67 static MonoGHashTable *aot_modules;
69 static CRITICAL_SECTION aot_mutex;
71 static guint32 mono_aot_verbose = 0;
74 decode_class_info (MonoAotModule *module, gpointer *data)
79 image = module->image_table [(guint32)data [1]];
83 return mono_class_get (image, (guint32)data [0]);
85 klass = decode_class_info (module, data [3]);
86 return mono_array_class_get (klass, (guint32)data [2]);
93 load_aot_module (MonoAssembly *assembly, gpointer user_data)
97 gboolean usable = TRUE;
98 char *saved_guid = NULL;
99 char *aot_version = NULL;
100 char *opt_flags = NULL;
105 aot_name = g_strdup_printf ("%s.so", assembly->image->name);
107 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
109 if (!assembly->aot_module)
112 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
113 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
114 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
116 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
117 if (mono_aot_verbose > 0)
118 printf ("AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
122 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
123 if (mono_aot_verbose > 0)
124 printf ("AOT module %s is out of date.\n", aot_name);
130 g_module_close (assembly->aot_module);
131 assembly->aot_module = NULL;
136 * It seems that MonoGHashTables are in the GC heap, so structures
137 * containing them must be in the GC heap as well :(
140 info = GC_MALLOC (sizeof (MonoAotModule));
142 info = g_new0 (MonoAotModule, 1);
144 info->methods = mono_g_hash_table_new (NULL, NULL);
145 sscanf (opt_flags, "%d", &info->opts);
147 /* Read image table */
149 guint32 table_len, i;
152 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
155 table_len = *(guint32*)table;
156 table += sizeof (guint32);
157 info->image_table = g_new0 (MonoImage*, table_len);
158 for (i = 0; i < table_len; ++i) {
159 info->image_table [i] = mono_image_loaded_by_guid (table);
160 if (!info->image_table [i]) {
161 if (mono_aot_verbose > 0)
162 printf ("AOT module %s is out of date.\n", aot_name);
163 g_free (info->methods);
164 g_free (info->image_table);
167 g_module_close (assembly->aot_module);
168 assembly->aot_module = NULL;
171 table += strlen (table) + 1;
175 /* Read icall table */
177 guint32 table_len, i;
180 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
183 table_len = *(guint32*)table;
184 table += sizeof (guint32);
185 info->icall_table = g_new0 (char*, table_len);
186 for (i = 0; i < table_len; ++i) {
187 info->icall_table [i] = table;
188 table += strlen (table) + 1;
192 /* Read methods present table */
193 g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
194 g_assert (info->methods_present_table);
196 EnterCriticalSection (&aot_mutex);
197 mono_g_hash_table_insert (aot_modules, assembly, info);
198 LeaveCriticalSection (&aot_mutex);
200 if (mono_aot_verbose > 0)
201 printf ("Loaded AOT Module for %s.\n", assembly->image->name);
207 InitializeCriticalSection (&aot_mutex);
209 aot_modules = mono_g_hash_table_new (NULL, NULL);
211 mono_install_assembly_load_hook (load_aot_module, NULL);
215 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
217 MonoClass *klass = method->klass;
218 MonoAssembly *ass = klass->image->assembly;
219 MonoJumpInfo *patch_info = NULL;
220 GModule *module = ass->aot_module;
221 char method_label [256];
222 char info_label [256];
225 guint code_len, used_int_regs, used_strings;
226 MonoAotModule *aot_module;
227 MonoAotMethod *minfo;
229 MonoMethodHeader *header = ((MonoMethodNormal*)method)->header;
238 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
239 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
240 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
241 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
244 aot_module = (MonoAotModule*)mono_g_hash_table_lookup (aot_modules, ass);
246 g_assert (klass->inited);
248 minfo = mono_g_hash_table_lookup (aot_module->methods, method);
250 /* Duplicate jinfo */
251 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
252 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
253 if (jinfo->clauses) {
255 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
256 memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
259 /* This method was already loaded in another appdomain */
260 if (aot_module->opts & MONO_OPT_SHARED)
261 /* Use the same method in the new appdomain */
263 else if (!minfo->patch_info)
264 /* Use the same method in the new appdomain */
267 /* Create a copy of the original method and apply relocations */
269 code = mono_mempool_alloc (domain->code_mp, minfo->info->code_size);
270 memcpy (code, minfo->info->code_start, minfo->info->code_size);
272 if (mono_aot_verbose > 1)
273 printf ("REUSE METHOD: %s %p - %p.\n", mono_method_full_name (method, TRUE), code, (char*)code + code_len);
275 /* Do this outside the lock to avoid deadlocks */
276 LeaveCriticalSection (&aot_mutex);
277 mono_arch_patch_code (method, domain, code, minfo->patch_info);
278 EnterCriticalSection (&aot_mutex);
281 jinfo->code_start = code;
282 if (jinfo->clauses) {
283 for (i = 0; i < header->num_clauses; ++i) {
284 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
285 gint32 offset = code - (guint8*)minfo->info->code_start;
287 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
288 ei->data.filter = (guint8*)ei->data.filter + offset;
289 ei->try_start = (guint8*)ei->try_start + offset;
290 ei->try_end = (guint8*)ei->try_end + offset;
291 ei->handler_start = (guint8*)ei->handler_start + offset;
299 /* Do a fast check to see whenever the method exists */
301 guint32 index = mono_metadata_token_index (method->token) - 1;
303 w = aot_module->methods_present_table [index / 32];
304 if (! (w & (1 << (index % 32)))) {
305 if (mono_aot_verbose > 1)
306 printf ("NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
311 sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
313 if (!g_module_symbol (module, method_label, (gpointer *)&code))
316 sprintf (info_label, "%s_p", method_label);
318 if (!g_module_symbol (module, info_label, (gpointer *)&info))
322 static int count = 0;
326 if (getenv ("MONO_LASTAOT")) {
327 if (count > atoi(getenv ("MONO_LASTAOT"))) {
331 if (count == atoi(getenv ("MONO_LASTAOT")))
332 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
337 minfo = GC_MALLOC (sizeof (MonoAotMethod));
339 minfo = g_new0 (MonoAotMethod, 1);
342 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
344 code_len = GPOINTER_TO_UINT (*((gpointer **)info));
346 used_int_regs = GPOINTER_TO_UINT (*((gpointer **)info));
349 if (mono_aot_verbose > 1)
350 printf ("FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
352 /* Exception table */
353 if (header->num_clauses) {
355 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
356 jinfo->num_clauses = header->num_clauses;
358 jinfo->exvar_offset = GPOINTER_TO_UINT (*((gpointer**)info));
361 for (i = 0; i < header->num_clauses; ++i) {
362 MonoExceptionClause *ec = &header->clauses [i];
363 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
365 ei->flags = ec->flags;
366 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
367 ei->data.filter = code + GPOINTER_TO_UINT (*((gpointer**)info));
369 ei->data.token = GPOINTER_TO_UINT (*((gpointer**)info));
371 ei->try_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
373 ei->try_end = code + GPOINTER_TO_UINT (*((gpointer**)info));
375 ei->handler_start = code + GPOINTER_TO_UINT (*((gpointer**)info));
380 if (aot_module->opts & MONO_OPT_SHARED) {
381 used_strings = GPOINTER_TO_UINT (*((gpointer **)info));
387 for (i = 0; i < used_strings; i++) {
388 guint token = GPOINTER_TO_UINT (*((gpointer **)info));
390 mono_ldstr (mono_root_domain, klass->image, mono_metadata_token_index (token));
402 if (aot_module->opts & MONO_OPT_SHARED)
403 mp = mono_mempool_new ();
409 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
413 b2 = *((guint8*)info + 1);
415 info = (gpointer*)((guint8*)info + 2);
419 if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
420 ji->ip.i = GPOINTER_TO_UINT (*info);
424 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
426 ji->ip.i += last_offset;
427 last_offset = ji->ip.i;
428 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
430 gpointer *data = *((gpointer **)info);
433 case MONO_PATCH_INFO_CLASS:
434 case MONO_PATCH_INFO_IID:
435 ji->data.klass = decode_class_info (aot_module, data);
436 g_assert (ji->data.klass);
437 mono_class_init (ji->data.klass);
439 case MONO_PATCH_INFO_VTABLE:
440 ji->data.klass = decode_class_info (aot_module, data);
441 g_assert (ji->data.klass);
442 mono_class_init (ji->data.klass);
444 case MONO_PATCH_INFO_IMAGE:
445 ji->data.image = aot_module->image_table [(guint32)data];
446 g_assert (ji->data.image);
448 case MONO_PATCH_INFO_METHOD:
449 case MONO_PATCH_INFO_METHODCONST: {
450 guint32 image_index, token;
452 image_index = (guint32)data >> 24;
453 token = MONO_TOKEN_METHOD_DEF | ((guint32)data & 0xffffff);
455 image = aot_module->image_table [image_index];
456 ji->data.method = mono_get_method (image, token, NULL);
457 g_assert (ji->data.method);
458 mono_class_init (ji->data.method->klass);
462 case MONO_PATCH_INFO_FIELD:
463 case MONO_PATCH_INFO_SFLDA: {
464 MonoClass *klass = decode_class_info (aot_module, data [1]);
465 mono_class_init (klass);
466 ji->data.field = mono_class_get_field (klass, (guint32)data [0]);
469 case MONO_PATCH_INFO_INTERNAL_METHOD:
470 ji->data.name = aot_module->icall_table [(guint32)data];
471 g_assert (ji->data.name);
472 //printf ("A: %s.\n", ji->data.name);
474 case MONO_PATCH_INFO_SWITCH:
475 ji->table_size = (int)data [0];
476 table = g_new (gpointer, ji->table_size);
477 ji->data.target = table;
478 for (i = 0; i < ji->table_size; i++) {
479 table [i] = data [i + 1];
482 case MONO_PATCH_INFO_R4:
483 case MONO_PATCH_INFO_R8:
484 ji->data.target = data;
486 case MONO_PATCH_INFO_LDSTR:
487 case MONO_PATCH_INFO_LDTOKEN:
488 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
489 ji->data.target = *data;
491 case MONO_PATCH_INFO_EXC_NAME:
492 ji->data.klass = decode_class_info (aot_module, data);
493 g_assert (ji->data.klass);
494 mono_class_init (ji->data.klass);
495 ji->data.name = ji->data.klass->name;
497 case MONO_PATCH_INFO_METHOD_REL:
498 ji->data.offset = (int)data [0];
501 g_warning ("unhandled type %d", ji->type);
502 g_assert_not_reached ();
506 ji->next = patch_info;
510 #ifndef PLATFORM_WIN32
511 /* disable write protection */
512 page_start = (char *) (((int) (code)) & ~ (PAGESIZE - 1));
513 pages = (code + code_len - page_start + PAGESIZE - 1) / PAGESIZE;
514 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
519 g_assert (VirtualProtect (code, code_len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
523 /* Do this outside the lock to avoid deadlocks */
524 LeaveCriticalSection (&aot_mutex);
525 mono_arch_patch_code (method, domain, code, patch_info);
526 EnterCriticalSection (&aot_mutex);
528 if (aot_module->opts & MONO_OPT_SHARED)
529 /* No need to cache patches */
530 mono_mempool_destroy (mp);
532 minfo->patch_info = patch_info;
535 mono_jit_stats.methods_aot++;
538 jinfo->code_size = code_len;
539 jinfo->used_regs = used_int_regs;
540 jinfo->method = method;
541 jinfo->code_start = code;
542 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
545 mono_g_hash_table_insert (aot_module->methods, method, minfo);
552 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
556 EnterCriticalSection (&aot_mutex);
557 info = mono_aot_get_method_inner (domain, method);
558 LeaveCriticalSection (&aot_mutex);
560 /* Do this outside the lock */
562 mono_jit_info_table_add (domain, info);
571 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
575 fprintf (fp, ".globl %s\n", name);
576 fprintf (fp, ".text 1 \n\t.align %d\n", align);
577 fprintf (fp, "\t.type %s,@object\n", name);
578 fprintf (fp, "\t.size %s,%d\n", name, size);
579 fprintf (fp, "%s:\n", name);
580 for (i = 0; i < size; i++) {
581 fprintf (fp, ".byte %d\n", buf [i]);
588 write_string_symbol (FILE *fp, const char *name, const char *value)
590 fprintf (fp, ".globl %s\n", name);
591 fprintf (fp, ".text 1\n");
592 fprintf (fp, "%s:\n", name);
593 fprintf (fp, "\t.string \"%s\"\n", value);
597 mono_get_field_token (MonoClassField *field)
599 MonoClass *klass = field->parent;
602 for (i = 0; i < klass->field.count; ++i) {
603 if (field == &klass->fields [i])
604 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
607 g_assert_not_reached ();
612 get_image_index (MonoAotCompile *cfg, MonoImage *image)
616 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
620 index = g_hash_table_size (cfg->image_hash);
621 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
622 g_ptr_array_add (cfg->image_table, image);
628 emit_image_index (MonoAotCompile *cfg, MonoImage *image)
632 image_index = get_image_index (cfg, image);
634 fprintf (cfg->fp, "\t.long %d\n", image_index);
638 cond_emit_klass_label (MonoAotCompile *cfg, MonoClass *klass)
640 char *l1, *el = NULL;
642 if ((l1 = g_hash_table_lookup (cfg->ref_hash, klass)))
645 if (!klass->type_token) {
646 g_assert (klass->rank > 0);
647 el = cond_emit_klass_label (cfg, klass->element_class);
650 fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
651 l1 = g_strdup_printf ("klass_p_%08x_%p", klass->type_token, klass);
652 fprintf (cfg->fp, "%s:\n", l1);
653 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
654 emit_image_index (cfg, klass->image);
657 fprintf (cfg->fp, "\t.long %d\n", klass->rank);
658 fprintf (cfg->fp, "\t.long %s\n", el);
661 g_hash_table_insert (cfg->ref_hash, klass, l1);
667 cond_emit_field_label (MonoAotCompile *cfg, MonoJumpInfo *patch_info)
669 MonoClassField *field = patch_info->data.field;
673 if ((l1 = g_hash_table_lookup (cfg->ref_hash, field)))
676 l2 = cond_emit_klass_label (cfg, field->parent);
677 fprintf (cfg->fp, "\t.align %d\n", sizeof (gpointer));
678 token = mono_get_field_token (field);
680 l1 = g_strdup_printf ("klass_p_%08x_%p", token, field);
681 fprintf (cfg->fp, "%s:\n", l1);
682 fprintf (cfg->fp, "\t.long 0x%08x\n", token);
683 fprintf (cfg->fp, "\t.long %s\n", l2);
685 g_hash_table_insert (cfg->ref_hash, field, l1);
691 compare_patches (gconstpointer a, gconstpointer b)
695 i = (*(MonoJumpInfo**)a)->ip.i;
696 j = (*(MonoJumpInfo**)b)->ip.i;
708 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
714 guint8 *code, *mname;
715 int func_alignment = 16;
717 MonoJumpInfo *patch_info;
718 MonoMethodHeader *header;
721 method = cfg->method;
722 code = cfg->native_code;
723 header = ((MonoMethodNormal*)method)->header;
725 fprintf (tmpfp, ".text 0\n");
726 mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
727 fprintf (tmpfp, "\t.align %d\n", func_alignment);
728 fprintf (tmpfp, ".globl %s\n", mname);
729 fprintf (tmpfp, "\t.type %s,@function\n", mname);
730 fprintf (tmpfp, "%s:\n", mname);
732 for (i = 0; i < cfg->code_len; i++)
733 fprintf (tmpfp, ".byte %d\n", (unsigned int) code [i]);
735 fprintf (tmpfp, ".text 1\n");
737 /* Sort relocations */
738 patches = g_ptr_array_new ();
739 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
740 g_ptr_array_add (patches, patch_info);
741 g_ptr_array_sort (patches, compare_patches);
744 for (pindex = 0; pindex < patches->len; ++pindex) {
745 patch_info = g_ptr_array_index (patches, pindex);
746 switch (patch_info->type) {
747 case MONO_PATCH_INFO_LABEL:
748 case MONO_PATCH_INFO_BB:
749 /* relative jumps are no problem, there is no need to handle then here */
751 case MONO_PATCH_INFO_SWITCH: {
752 gpointer *table = (gpointer *)patch_info->data.target;
755 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
756 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
757 fprintf (tmpfp, "\t.long %d\n", patch_info->table_size);
759 for (k = 0; k < patch_info->table_size; k++) {
760 fprintf (tmpfp, "\t.long %d\n", (int)table [k]);
765 case MONO_PATCH_INFO_INTERNAL_METHOD: {
768 icall_index = (guint32)g_hash_table_lookup (acfg->icall_hash, patch_info->data.name);
770 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
771 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
772 GUINT_TO_POINTER (icall_index));
773 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
775 patch_info->data.name = g_strdup_printf ("%d", icall_index - 1);
779 case MONO_PATCH_INFO_METHODCONST:
780 case MONO_PATCH_INFO_METHOD: {
782 * The majority of patches are for methods, so we emit
783 * them inline instead of defining a label for them to
784 * decrease the number of relocations.
786 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
787 guint32 token = patch_info->data.method->token;
788 g_assert (image_index < 256);
789 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
791 patch_info->data.name =
792 g_strdup_printf ("%d", (image_index << 24) + (mono_metadata_token_index (token)));
796 case MONO_PATCH_INFO_FIELD:
797 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
800 case MONO_PATCH_INFO_CLASS:
801 case MONO_PATCH_INFO_IID:
802 patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
805 case MONO_PATCH_INFO_IMAGE:
806 patch_info->data.name = g_strdup_printf ("%d", get_image_index (acfg, patch_info->data.image));
809 case MONO_PATCH_INFO_EXC_NAME: {
813 mono_class_from_name (mono_defaults.exception_class->image,
814 "System", patch_info->data.target);
816 patch_info->data.name = cond_emit_klass_label (acfg, ex_class);
820 case MONO_PATCH_INFO_R4:
821 fprintf (tmpfp, "\t.align 8\n");
822 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
823 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
826 case MONO_PATCH_INFO_R8:
827 fprintf (tmpfp, "\t.align 8\n");
828 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
829 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
830 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target + 1));
833 case MONO_PATCH_INFO_METHOD_REL:
834 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
835 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
836 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.offset);
839 case MONO_PATCH_INFO_VTABLE:
840 patch_info->data.name = cond_emit_klass_label (acfg, patch_info->data.klass);
843 case MONO_PATCH_INFO_SFLDA:
844 patch_info->data.name = cond_emit_field_label (acfg, patch_info);
847 case MONO_PATCH_INFO_LDSTR:
848 case MONO_PATCH_INFO_LDTOKEN:
849 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
850 fprintf (tmpfp, "\t.align 8\n");
851 fprintf (tmpfp, "%s_p_%d:\n", mname, j);
852 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token);
856 g_warning ("unable to handle jump info %d", patch_info->type);
857 g_assert_not_reached ();
861 fprintf (tmpfp, ".globl %s_p\n", mname);
862 fprintf (tmpfp, "\t.align %d\n", sizeof (gpointer));
863 fprintf (tmpfp, "%s_p:\n", mname);
865 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
866 fprintf (tmpfp, "\t.long %d\n", cfg->used_int_regs);
868 /* Exception table */
869 if (header->num_clauses) {
870 MonoJitInfo *jinfo = cfg->jit_info;
872 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
874 for (k = 0; k < header->num_clauses; ++k) {
875 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
877 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
878 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->data.filter - code);
880 /* fixme: tokens are not global */
881 fprintf (tmpfp, "\t.long %d\n", ei->data.token);
883 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_start - code);
884 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->try_end - code);
885 fprintf (tmpfp, "\t.long %d\n", (guint8*)ei->handler_start - code);
890 if (cfg->opt & MONO_OPT_SHARED) {
891 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
892 for (l = cfg->ldstr_list; l; l = l->next) {
893 fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
897 /* Used only in shared mode */
898 g_assert (!cfg->ldstr_list);
900 //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
907 for (pindex = 0; pindex < patches->len; ++pindex) {
909 patch_info = g_ptr_array_index (patches, pindex);
911 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
912 (patch_info->type == MONO_PATCH_INFO_BB))
916 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
917 offset = patch_info->ip.i - last_offset;
918 last_offset = patch_info->ip.i;
920 /* Encode type+position compactly */
921 g_assert (patch_info->type < 64);
922 if (offset < 1024 - 1) {
923 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
924 fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
927 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
928 fprintf (tmpfp, "\t.byte %d\n", 255);
929 fprintf (tmpfp, "\t.long %d\n", offset);
932 switch (patch_info->type) {
933 case MONO_PATCH_INFO_METHODCONST:
934 case MONO_PATCH_INFO_METHOD:
935 case MONO_PATCH_INFO_CLASS:
936 case MONO_PATCH_INFO_IID:
937 case MONO_PATCH_INFO_FIELD:
938 case MONO_PATCH_INFO_INTERNAL_METHOD:
939 case MONO_PATCH_INFO_IMAGE:
940 case MONO_PATCH_INFO_VTABLE:
941 case MONO_PATCH_INFO_SFLDA:
942 case MONO_PATCH_INFO_EXC_NAME:
943 fprintf (tmpfp, "\t.long %s\n", patch_info->data.name);
946 case MONO_PATCH_INFO_SWITCH:
947 case MONO_PATCH_INFO_R4:
948 case MONO_PATCH_INFO_R8:
949 case MONO_PATCH_INFO_METHOD_REL:
950 case MONO_PATCH_INFO_LDSTR:
951 case MONO_PATCH_INFO_LDTOKEN:
952 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
953 fprintf (tmpfp, "\t.long %s_p_%d\n", mname, j);
956 case MONO_PATCH_INFO_LABEL:
957 case MONO_PATCH_INFO_BB:
960 g_warning ("unable to handle jump info %d", patch_info->type);
961 g_assert_not_reached ();
968 * 0 is PATCH_INFO_BB, which can't be in the file.
970 /* NULL terminated array */
971 fprintf (tmpfp, "\t.long 0\n");
973 /* fixme: save the rest of the required infos */
979 mono_compile_assembly (MonoAssembly *ass, guint32 opts)
982 MonoImage *image = ass->image;
984 char *com, *tmpfname, *opts_str;
988 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
989 GHashTable *ref_hash;
990 MonoAotCompile *acfg;
993 printf ("Mono AOT compiler - compiling assembly %s\n", image->name);
995 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
996 tmpfp = fdopen (i, "w+");
999 ref_hash = g_hash_table_new (NULL, NULL);
1001 acfg = g_new0 (MonoAotCompile, 1);
1003 acfg->ref_hash = ref_hash;
1004 acfg->icall_hash = g_hash_table_new (NULL, NULL);
1005 acfg->icall_table = g_ptr_array_new ();
1006 acfg->image_hash = g_hash_table_new (NULL, NULL);
1007 acfg->image_table = g_ptr_array_new ();
1009 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1011 write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1013 opts_str = g_strdup_printf ("%d", opts);
1014 write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1017 emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows);
1019 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1020 MonoJumpInfo *patch_info;
1022 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1023 method = mono_get_method (image, token, NULL);
1025 /* fixme: maybe we can also precompile wrapper methods */
1026 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1027 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1028 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1029 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1030 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1036 /* fixme: we need to patch the IP for the LMF in that case */
1037 if (method->save_lmf) {
1038 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1043 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1044 //mono_compile_method (method);
1046 cfg = mini_method_compile (method, opts, mono_root_domain, 0);
1049 if (cfg->disable_aot) {
1050 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1056 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1057 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1058 /* unable to handle this */
1059 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1071 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1072 if ((patch_info->type == MONO_PATCH_INFO_METHOD ||
1073 patch_info->type == MONO_PATCH_INFO_METHODCONST) &&
1074 patch_info->data.method->wrapper_type) {
1075 /* unable to handle this */
1076 //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));
1087 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1090 emit_method (acfg, cfg);
1092 mono_destroy_compile (cfg);
1098 * The icall and image tables are small but referenced in a lot of places.
1099 * So we emit them at once, and reference their elements by an index
1100 * instead of an assembly label to cut back on the number of relocations.
1103 /* Emit icall table */
1105 symbol = g_strdup_printf ("mono_icall_table");
1106 fprintf (tmpfp, ".globl %s\n", symbol);
1107 fprintf (tmpfp, ".text 1 \n");
1108 fprintf (tmpfp, "\t.align 8\n");
1109 fprintf (tmpfp, "%s:\n", symbol);
1110 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1111 for (i = 0; i < acfg->icall_table->len; i++)
1112 fprintf (tmpfp, ".string \"%s\"\n", (char*)g_ptr_array_index (acfg->icall_table, i));
1114 /* Emit image table */
1116 symbol = g_strdup_printf ("mono_image_table");
1117 fprintf (tmpfp, ".globl %s\n", symbol);
1118 fprintf (tmpfp, ".text 1 \n");
1119 fprintf (tmpfp, "\t.align 8\n");
1120 fprintf (tmpfp, "%s:\n", symbol);
1121 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1122 for (i = 0; i < acfg->image_table->len; i++)
1123 fprintf (tmpfp, ".string \"%s\"\n", ((MonoImage*)g_ptr_array_index (acfg->image_table, i))->guid);
1126 * g_module_symbol takes a lot of time for failed lookups, so we emit
1127 * a table which contains one bit for each method. This bit specifies
1128 * whenever the method is emitted or not.
1131 symbol = g_strdup_printf ("mono_methods_present_table");
1132 fprintf (tmpfp, ".globl %s\n", symbol);
1133 fprintf (tmpfp, ".text 1 \n");
1134 fprintf (tmpfp, "\t.align 8\n");
1135 fprintf (tmpfp, "%s:\n", symbol);
1140 nrows = image->tables [MONO_TABLE_METHOD].rows;
1141 for (i = 0; i < nrows / 32 + 1; ++i) {
1143 for (k = 0; k < 32; ++k) {
1144 if (emitted [(i * 32) + k])
1147 //printf ("EMITTED [%d] = %d.\n", i, b);
1148 fprintf (tmpfp, "\t.long %d\n", w);
1154 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1155 printf ("Executing the native assembler: %s\n", com);
1158 com = g_strdup_printf ("ld -shared -o %s%s %s.o", image->name, SHARED_EXT, tmpfname);
1159 printf ("Executing the native linker: %s\n", com);
1162 com = g_strdup_printf ("%s.o", tmpfname);
1165 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1166 printf ("Stripping the binary: %s\n", com);
1170 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, (ccount*100)/mcount);
1171 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, (abscount*100)/mcount);
1172 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, (wrappercount*100)/mcount);
1173 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, (lmfcount*100)/mcount);
1174 printf ("%d methods have other problems (%d%%)\n", ocount, (ocount*100)/mcount);