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
23 #include <limits.h> /* for PAGESIZE */
28 #include <mono/metadata/tabledefs.h>
29 #include <mono/metadata/class.h>
30 #include <mono/metadata/object.h>
31 #include <mono/metadata/tokentype.h>
32 #include <mono/metadata/appdomain.h>
33 #include <mono/metadata/debug-helpers.h>
34 #include <mono/metadata/assembly.h>
35 #include <mono/metadata/metadata-internals.h>
36 #include <mono/metadata/marshal.h>
37 #include <mono/utils/mono-logger.h>
44 #define SHARED_EXT ".dll"
45 #elif defined(__ppc__) && defined(__MACH__)
46 #define SHARED_EXT ".dylib"
48 #define SHARED_EXT ".so"
51 #if defined(sparc) || defined(__ppc__)
52 #define AS_STRING_DIRECTIVE ".asciz"
55 #define AS_STRING_DIRECTIVE ".string"
56 #define AS_HAS_SUBSECTIONS 1
59 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
61 typedef struct MonoAotMethod {
63 MonoJumpInfo *patch_info;
67 typedef struct MonoAotModule {
69 /* Optimization flags used to compile the module */
71 /* Maps MonoMethods to MonoAotMethodInfos */
73 /* Pointer to the Global Offset Table */
77 MonoAssemblyName *image_names;
79 MonoImage **image_table;
80 guint32* methods_present_table;
83 guint32 *code_offsets;
85 guint32 *method_info_offsets;
88 typedef struct MonoAotCompile {
91 GHashTable *icall_hash;
92 GPtrArray *icall_table;
93 GHashTable *image_hash;
94 GPtrArray *image_table;
98 typedef struct MonoAotOptions {
102 static GHashTable *aot_modules;
104 static CRITICAL_SECTION aot_mutex;
107 * Disabling this will make a copy of the loaded code and use the copy instead
108 * of the original. This will place the caller and the callee close to each
109 * other in memory, possibly improving cache behavior. Since the original
110 * code is in copy-on-write memory, this will not increase the memory usage
113 #ifdef MONO_ARCH_HAVE_PIC_AOT
114 static gboolean use_loaded_code = TRUE;
116 static gboolean use_loaded_code = FALSE;
120 * Whenever to AOT compile loaded assemblies on demand and store them in
121 * a cache under $HOME/.mono/aot-cache.
123 static gboolean use_aot_cache = FALSE;
126 static gint32 mono_last_aot_method = -1;
129 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
132 is_got_patch (MonoJumpInfoType patch_type)
136 #elif defined(__i386__)
143 /*****************************************************/
145 /*****************************************************/
148 load_image (MonoAotModule *module, int index)
150 MonoAssembly *assembly;
151 MonoImageOpenStatus status;
153 if (module->image_table [index])
154 return module->image_table [index];
155 if (module->out_of_date)
158 assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
160 module->out_of_date = TRUE;
164 if (strcmp (assembly->image->guid, module->image_guids [index])) {
165 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date (Older than dependency %s).\n", module->aot_name, module->image_names [index].name);
166 module->out_of_date = TRUE;
170 module->image_table [index] = assembly->image;
171 return assembly->image;
175 decode_klass_info (MonoAotModule *module, guint32 *info, guint32 **out_info)
181 image = load_image (module, info [0]);
187 klass = mono_class_get (image, token);
192 klass = mono_class_get (image, token);
194 klass = mono_array_class_get (klass, rank);
197 mono_class_init (klass);
203 static MonoClassField*
204 decode_field_info (MonoAotModule *module, guint32 *info, guint32 **out_info)
206 MonoClass *klass = decode_klass_info (module, info, &info);
216 return mono_class_get_field (klass, token);
221 make_writable (guint8* addr, guint32 len)
223 #ifndef PLATFORM_WIN32
227 page_start = (char *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
228 pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
229 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
234 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
240 create_cache_structure (void)
246 home = g_get_home_dir ();
250 tmp = g_build_filename (home, ".mono", NULL);
251 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
252 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
253 #ifdef PLATFORM_WIN32
256 err = mkdir (tmp, 0777);
259 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
265 tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
266 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
267 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
268 #ifdef PLATFORM_WIN32
271 err = mkdir (tmp, 0777);
274 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
283 * load_aot_module_from_cache:
285 * Experimental code to AOT compile loaded assemblies on demand.
288 * - Add environment variable MONO_AOT_CACHE_OPTIONS
289 * - Add options for controlling the cache size
290 * - Handle full cache by deleting old assemblies lru style
291 * - Add options for excluding assemblies during development
292 * - Maybe add a threshold after an assembly is AOT compiled
293 * - invoking a new mono process is a security risk
296 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
298 char *fname, *cmd, *tmp2;
306 if (assembly->image->dynamic)
309 create_cache_structure ();
311 home = g_get_home_dir ();
313 tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
314 fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
318 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
319 module = g_module_open (fname, G_MODULE_BIND_LAZY);
322 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
324 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
326 /* FIXME: security */
327 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
329 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
332 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
336 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
338 module = g_module_open (fname, G_MODULE_BIND_LAZY);
345 load_aot_module (MonoAssembly *assembly, gpointer user_data)
349 gboolean usable = TRUE;
350 char *saved_guid = NULL;
351 char *aot_version = NULL;
352 char *opt_flags = NULL;
354 #ifdef MONO_ARCH_HAVE_PIC_AOT
355 gpointer *got_addr = NULL;
356 gpointer *got = NULL;
357 guint32 *got_size_ptr = NULL;
360 if (mono_compile_aot)
364 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
366 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
368 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
370 if (!assembly->aot_module) {
371 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
375 if (!assembly->aot_module) {
380 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
381 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
382 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
384 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
385 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s has wrong file format version (expected %s got %s)\n", aot_name, MONO_AOT_FILE_VERSION, aot_version);
389 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
390 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
397 g_module_close (assembly->aot_module);
398 assembly->aot_module = NULL;
402 #ifdef MONO_ARCH_HAVE_PIC_AOT
403 g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
405 got = (gpointer*)*got_addr;
407 g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
408 g_assert (got_size_ptr);
411 info = g_new0 (MonoAotModule, 1);
412 info->aot_name = aot_name;
413 info->methods = g_hash_table_new (NULL, NULL);
414 #ifdef MONO_ARCH_HAVE_PIC_AOT
416 info->got_size = *got_size_ptr;
418 sscanf (opt_flags, "%d", &info->opts);
420 /* Read image table */
422 guint32 table_len, i;
425 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
428 table_len = *(guint32*)table;
429 table += sizeof (guint32);
430 info->image_table = g_new0 (MonoImage*, table_len);
431 info->image_names = g_new0 (MonoAssemblyName, table_len);
432 info->image_guids = g_new0 (char*, table_len);
433 for (i = 0; i < table_len; ++i) {
434 MonoAssemblyName *aname = &(info->image_names [i]);
436 aname->name = g_strdup (table);
437 table += strlen (table) + 1;
438 info->image_guids [i] = g_strdup (table);
439 table += strlen (table) + 1;
441 aname->culture = g_strdup (table);
442 table += strlen (table) + 1;
443 memcpy (aname->public_key_token, table, strlen (table) + 1);
444 table += strlen (table) + 1;
446 table = ALIGN_PTR_TO (table, 8);
447 aname->flags = *(guint32*)table;
449 aname->major = *(guint32*)table;
451 aname->minor = *(guint32*)table;
453 aname->build = *(guint32*)table;
455 aname->revision = *(guint32*)table;
460 /* Read icall table */
462 guint32 table_len, i;
465 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
468 table_len = *(guint32*)table;
469 table += sizeof (guint32);
470 info->icall_table = g_new0 (char*, table_len);
471 for (i = 0; i < table_len; ++i) {
472 info->icall_table [i] = table;
473 table += strlen (table) + 1;
477 /* Read methods present table */
478 g_module_symbol (assembly->aot_module, "mono_methods_present_table", (gpointer *)&info->methods_present_table);
480 /* Read method and method_info tables */
481 g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
482 g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
483 g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
484 g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
486 EnterCriticalSection (&aot_mutex);
487 g_hash_table_insert (aot_modules, assembly, info);
488 LeaveCriticalSection (&aot_mutex);
490 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
496 InitializeCriticalSection (&aot_mutex);
497 aot_modules = g_hash_table_new (NULL, NULL);
499 mono_install_assembly_load_hook (load_aot_module, NULL);
501 if (getenv ("MONO_LASTAOT"))
502 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
503 if (getenv ("MONO_AOT_CACHE"))
504 use_aot_cache = TRUE;
508 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
510 MonoClass *klass = method->klass;
511 MonoAssembly *ass = klass->image->assembly;
512 GModule *module = ass->aot_module;
513 char method_label [256];
514 char info_label [256];
517 MonoAotModule *aot_module;
518 MonoAotMethod *minfo;
520 MonoMethodHeader *header;
528 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
531 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
532 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
533 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
534 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
537 header = mono_method_get_header (method);
539 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
541 g_assert (klass->inited);
543 if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
544 /* Non shared AOT code can't be used in other appdomains */
547 minfo = g_hash_table_lookup (aot_module->methods, method);
548 /* Can't use code from non-root domains since they can be unloaded */
549 if (minfo && (minfo->domain == mono_get_root_domain ())) {
550 /* This method was already loaded in another appdomain */
552 /* Duplicate jinfo */
553 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
554 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
555 if (jinfo->clauses) {
557 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
558 memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
564 if (aot_module->out_of_date)
567 if (aot_module->code) {
568 if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
569 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
573 code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
574 info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
576 /* Do a fast check to see whenever the method exists */
578 guint32 index = mono_metadata_token_index (method->token) - 1;
580 w = aot_module->methods_present_table [index / 32];
581 if (! (w & (1 << (index % 32)))) {
582 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
586 sprintf (method_label, "m_%x", mono_metadata_token_index (method->token));
587 if (!g_module_symbol (module, method_label, (gpointer *)&code))
590 sprintf (info_label, "%s_p", method_label);
592 if (!g_module_symbol (module, info_label, (gpointer *)&info))
596 if (mono_last_aot_method != -1) {
597 if (mono_jit_stats.methods_aot > mono_last_aot_method)
600 if (mono_jit_stats.methods_aot == mono_last_aot_method)
601 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
604 return mono_aot_load_method (domain, aot_module, method, code, info);
608 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
610 MonoClass *klass = method->klass;
611 MonoJumpInfo *patch_info = NULL;
612 guint code_len, used_int_regs, used_strings;
613 MonoAotMethod *minfo;
615 MonoMethodHeader *header = mono_method_get_header (method);
618 int i, pindex, got_index;
619 gboolean non_got_patches;
621 minfo = g_new0 (MonoAotMethod, 1);
623 minfo->domain = domain;
624 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
626 code_len = *(guint32*)info;
628 used_int_regs = *(guint32*)info;
631 if (!use_loaded_code) {
633 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
634 memcpy (code2, code, code_len);
635 mono_arch_flush_icache (code2, code_len);
639 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", mono_method_full_name (method, TRUE), code, code + code_len, info);
641 /* Exception table */
642 if (header->num_clauses) {
644 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
645 jinfo->num_clauses = header->num_clauses;
647 jinfo->exvar_offset = *(guint32*)info;
650 for (i = 0; i < header->num_clauses; ++i) {
651 MonoExceptionClause *ec = &header->clauses [i];
652 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
654 ei->flags = ec->flags;
655 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
656 ei->data.filter = code + *(guint32*)info;
658 ei->data.catch_class = ec->data.catch_class;
660 ei->try_start = code + *(guint32*)info;
662 ei->try_end = code + *(guint32*)info;
664 ei->handler_start = code + *(guint32*)info;
669 if (aot_module->opts & MONO_OPT_SHARED) {
670 used_strings = *(guint32*)info;
676 for (i = 0; i < used_strings; i++) {
677 guint token = *(guint32*)info;
679 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
682 #ifdef MONO_ARCH_HAVE_PIC_AOT
683 got_index = *(guint32*)info;
691 guint32 last_offset, buf_len;
694 if (aot_module->opts & MONO_OPT_SHARED)
695 mp = mono_mempool_new ();
699 /* First load the type + offset table */
701 patches = g_ptr_array_new ();
703 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
705 #if defined(MONO_ARCH_HAVE_PIC_AOT)
706 ji->type = *(guint8*)info;
712 b2 = *((guint8*)info + 1);
718 if (((b1 & (1 + 2)) == 3) && (b2 == 255)) {
719 info = ALIGN_PTR_TO (info, 4);
720 ji->ip.i = *(guint32*)info;
724 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
726 ji->ip.i += last_offset;
727 last_offset = ji->ip.i;
729 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
731 ji->next = patch_info;
734 g_ptr_array_add (patches, ji);
738 info = ALIGN_PTR_TO (info, sizeof (gpointer));
740 info32 = (guint32*)info;
742 /* Then load the other data */
743 for (pindex = 0; pindex < patches->len; ++pindex) {
744 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
747 case MONO_PATCH_INFO_CLASS:
748 case MONO_PATCH_INFO_IID:
749 case MONO_PATCH_INFO_VTABLE:
750 case MONO_PATCH_INFO_CLASS_INIT:
751 ji->data.klass = decode_klass_info (aot_module, info32, &info32);
755 case MONO_PATCH_INFO_IMAGE:
756 ji->data.image = load_image (aot_module, info32 [0]);
759 g_assert (ji->data.image);
762 case MONO_PATCH_INFO_METHOD:
763 case MONO_PATCH_INFO_METHODCONST:
764 case MONO_PATCH_INFO_METHOD_JUMP: {
765 guint32 image_index, token;
767 image_index = info32 [0] >> 24;
768 token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff);
770 image = load_image (aot_module, image_index);
773 ji->data.method = mono_get_method (image, token, NULL);
774 g_assert (ji->data.method);
775 mono_class_init (ji->data.method->klass);
780 case MONO_PATCH_INFO_WRAPPER: {
781 guint32 wrapper_type;
783 wrapper_type = info32 [0];
786 switch (wrapper_type) {
787 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
788 guint32 image_index, token;
790 image_index = info32 [0] >> 24;
791 token = MONO_TOKEN_METHOD_DEF | (info32 [0] & 0xffffff);
793 image = load_image (aot_module, image_index);
796 ji->data.method = mono_get_method (image, token, NULL);
797 g_assert (ji->data.method);
798 mono_class_init (ji->data.method->klass);
800 ji->type = MONO_PATCH_INFO_METHOD;
801 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
805 case MONO_WRAPPER_PROXY_ISINST: {
806 MonoClass *klass = decode_klass_info (aot_module, info32, &info32);
809 ji->type = MONO_PATCH_INFO_METHOD;
810 ji->data.method = mono_marshal_get_proxy_cancast (klass);
813 case MONO_WRAPPER_LDFLD:
814 case MONO_WRAPPER_STFLD:
815 case MONO_WRAPPER_ISINST: {
816 MonoClass *klass = decode_klass_info (aot_module, info32, &info32);
819 ji->type = MONO_PATCH_INFO_METHOD;
820 if (wrapper_type == MONO_WRAPPER_LDFLD)
821 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
822 else if (wrapper_type == MONO_WRAPPER_STFLD)
823 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
825 ji->data.method = mono_marshal_get_isinst (klass);
828 case MONO_WRAPPER_STELEMREF:
829 ji->type = MONO_PATCH_INFO_METHOD;
830 ji->data.method = mono_marshal_get_stelemref ();
833 g_assert_not_reached ();
837 case MONO_PATCH_INFO_FIELD:
838 case MONO_PATCH_INFO_SFLDA:
839 ji->data.field = decode_field_info (aot_module, info32, &info32);
843 case MONO_PATCH_INFO_INTERNAL_METHOD:
844 ji->data.name = aot_module->icall_table [info32 [0]];
845 g_assert (ji->data.name);
847 //printf ("A: %s.\n", ji->data.name);
849 case MONO_PATCH_INFO_SWITCH:
850 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
851 ji->data.table->table_size = info32 [0];
852 table = g_new (gpointer, ji->data.table->table_size);
853 ji->data.table->table = (MonoBasicBlock**)table;
854 for (i = 0; i < ji->data.table->table_size; i++) {
855 table [i] = (gpointer)(gssize)info32 [i + 1];
857 info32 += (ji->data.table->table_size + 1);
859 case MONO_PATCH_INFO_R4:
860 ji->data.target = info32;
863 case MONO_PATCH_INFO_R8:
864 info32 = ALIGN_PTR_TO (info32, 8);
865 ji->data.target = info32;
868 case MONO_PATCH_INFO_LDSTR:
869 case MONO_PATCH_INFO_LDTOKEN:
870 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
871 image = load_image (aot_module, info32 [0]);
874 ji->data.token = mono_jump_info_token_new (mp, image, info32 [1]);
877 case MONO_PATCH_INFO_EXC_NAME:
878 ji->data.klass = decode_klass_info (aot_module, info32, &info32);
881 ji->data.name = ji->data.klass->name;
883 case MONO_PATCH_INFO_METHOD_REL:
884 ji->data.offset = info32 [0];
888 g_warning ("unhandled type %d", ji->type);
889 g_assert_not_reached ();
893 info = (guint8*)info32;
895 buf_len = *(guint32*)info;
897 mono_debug_add_aot_method (domain, method, code, info, buf_len);
899 #if MONO_ARCH_HAVE_PIC_AOT
900 mono_arch_flush_icache (code, code_len);
903 make_writable (code, code_len);
905 /* Do this outside the lock to avoid deadlocks */
906 LeaveCriticalSection (&aot_mutex);
907 non_got_patches = FALSE;
908 for (pindex = 0; pindex < patches->len; ++pindex) {
909 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
911 if (is_got_patch (ji->type)) {
912 aot_module->got [got_index] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
914 ji->type = MONO_PATCH_INFO_NONE;
917 non_got_patches = TRUE;
919 if (non_got_patches) {
920 make_writable (code, code_len);
921 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
923 EnterCriticalSection (&aot_mutex);
926 /* disable write protection */
927 make_writable (code, code_len);
929 /* Do this outside the lock to avoid deadlocks */
930 LeaveCriticalSection (&aot_mutex);
931 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
932 EnterCriticalSection (&aot_mutex);
935 g_ptr_array_free (patches, TRUE);
937 if (aot_module->opts & MONO_OPT_SHARED)
938 /* No need to cache patches */
939 mono_mempool_destroy (mp);
941 minfo->patch_info = patch_info;
944 mono_jit_stats.methods_aot++;
947 jinfo->code_size = code_len;
948 jinfo->used_regs = used_int_regs;
949 jinfo->method = method;
950 jinfo->code_start = code;
951 #ifdef MONO_ARCH_HAVE_PIC_AOT
952 jinfo->domain_neutral = 0;
954 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
958 g_hash_table_insert (aot_module->methods, method, minfo);
964 g_ptr_array_free (patches, TRUE);
966 /* FIXME: The space in domain->mp is wasted */
967 if (aot_module->opts & MONO_OPT_SHARED)
968 /* No need to cache patches */
969 mono_mempool_destroy (mp);
975 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
979 EnterCriticalSection (&aot_mutex);
980 info = mono_aot_get_method_inner (domain, method);
981 LeaveCriticalSection (&aot_mutex);
983 /* Do this outside the lock */
985 mono_jit_info_table_add (domain, info);
993 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
997 MonoAotModule *aot_module;
999 ji = mono_jit_info_table_find (mono_domain_get (), code);
1003 ass = ji->method->klass->image->assembly;
1007 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1008 if (!aot_module || !aot_module->got)
1011 return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
1014 /*****************************************************/
1016 /*****************************************************/
1019 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1022 /* For solaris as, GNU as should accept the same */
1023 fprintf (fp, ".section \"%s\"\n", section_name);
1024 #elif defined(__ppc__) && defined(__MACH__)
1025 /* This needs to be made more precise on mach. */
1026 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1028 fprintf (fp, "%s %d\n", section_name, subsection_index);
1033 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1043 fprintf (fp, "\t.type %s,#%s\n", name, stype);
1044 #elif !(defined(__ppc__) && defined(__MACH__))
1045 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1046 #elif defined(__x86_64__) || defined(__i386__)
1047 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1052 emit_global (FILE *fp, const char *name, gboolean func)
1054 #if defined(__ppc__) && defined(__MACH__)
1055 // mach-o always uses a '_' prefix.
1056 fprintf (fp, ".globl _%s\n", name);
1058 fprintf (fp, ".globl %s\n", name);
1061 emit_symbol_type (fp, name, func);
1065 emit_label (FILE *fp, const char *name)
1067 #if defined(__ppc__) && defined(__MACH__)
1068 // mach-o always uses a '_' prefix.
1069 fprintf (fp, "_%s:\n", name);
1071 fprintf (fp, "%s:\n", name);
1077 write_data_symbol (FILE *fp, const char *name, guint8 *buf, int size, int align)
1081 emit_section_change (fp, ".text", 1);
1083 fprintf (fp, ".globl %s\n", name);
1084 fprintf (fp, "\t.align %d\n", align);
1085 fprintf (fp, "\t.type %s,#object\n", name);
1086 fprintf (fp, "\t.size %s,%d\n", name, size);
1087 fprintf (fp, "%s:\n", name);
1088 for (i = 0; i < size; i++) {
1089 fprintf (fp, ".byte %d\n", buf [i]);
1096 write_string_symbol (FILE *fp, const char *name, const char *value)
1098 emit_section_change (fp, ".text", 1);
1099 emit_global(fp, name, FALSE);
1100 emit_label(fp, name);
1101 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1105 mono_get_field_token (MonoClassField *field)
1107 MonoClass *klass = field->parent;
1110 for (i = 0; i < klass->field.count; ++i) {
1111 if (field == &klass->fields [i])
1112 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1115 g_assert_not_reached ();
1120 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1124 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1128 index = g_hash_table_size (cfg->image_hash);
1129 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1130 g_ptr_array_add (cfg->image_table, image);
1136 emit_klass_info (MonoAotCompile *cfg, MonoClass *klass)
1138 fprintf (cfg->fp, "\t.long 0x%08x\n", get_image_index (cfg, klass->image));
1139 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->type_token);
1140 if (!klass->type_token) {
1142 g_assert (klass->rank > 0);
1143 g_assert (klass->element_class->type_token);
1144 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->element_class->type_token);
1145 fprintf (cfg->fp, "\t.long 0x%08x\n", klass->rank);
1150 emit_field_info (MonoAotCompile *cfg, MonoClassField *field)
1152 emit_klass_info (cfg, field->parent);
1153 fprintf (cfg->fp, "\t.long 0x%08x\n", mono_get_field_token (field));
1156 #if defined(__ppc__) && defined(__MACH__)
1158 ilog2(register int value)
1161 while (value & ~0xf) count += 4, value >>= 4;
1162 while (value) count++, value >>= 1;
1168 emit_alignment(FILE *fp, int size)
1170 #if defined(__ppc__) && defined(__MACH__)
1171 // the mach-o assembler specifies alignments as powers of 2.
1172 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1173 #elif defined(__powerpc__)
1174 /* ignore on linux/ppc */
1176 fprintf (fp, "\t.align %d\n", size);
1180 G_GNUC_UNUSED static void
1181 emit_pointer (FILE *fp, const char *target)
1183 emit_alignment (fp, sizeof (gpointer));
1184 #if defined(__x86_64__)
1185 fprintf (fp, "\t.quad %s\n", target);
1186 #elif defined(sparc) && SIZEOF_VOID_P == 8
1187 fprintf (fp, "\t.xword %s\n", target);
1189 fprintf (fp, "\t.long %s\n", target);
1194 compare_patches (gconstpointer a, gconstpointer b)
1198 i = (*(MonoJumpInfo**)a)->ip.i;
1199 j = (*(MonoJumpInfo**)b)->ip.i;
1211 emit_method (MonoAotCompile *acfg, MonoCompile *cfg)
1216 int i, j, k, pindex;
1217 guint8 *code, *mname, *mname_p;
1218 int func_alignment = 16;
1220 MonoJumpInfo *patch_info;
1221 MonoMethodHeader *header;
1222 guint32 last_offset;
1223 #ifdef MONO_ARCH_HAVE_PIC_AOT
1224 guint32 first_got_offset;
1229 method = cfg->method;
1230 code = cfg->native_code;
1231 header = mono_method_get_header (method);
1233 emit_section_change (tmpfp, ".text", 0);
1235 #ifdef AS_HAS_SUBSECTIONS
1236 /* Make the labels local */
1237 mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1239 mname = g_strdup_printf ("m_%x", mono_metadata_token_index (method->token));
1241 mname_p = g_strdup_printf ("%s_p", mname);
1243 emit_alignment(tmpfp, func_alignment);
1244 #ifndef AS_HAS_SUBSECTIONS
1245 emit_global(tmpfp, mname, TRUE);
1247 emit_label(tmpfp, mname);
1249 if (cfg->verbose_level > 0)
1250 g_print ("Emitted as %s\n", mname);
1252 /* Sort relocations */
1253 patches = g_ptr_array_new ();
1254 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1255 g_ptr_array_add (patches, patch_info);
1256 g_ptr_array_sort (patches, compare_patches);
1258 #ifdef MONO_ARCH_HAVE_PIC_AOT
1259 first_got_offset = acfg->got_offset;
1260 for (i = 0; i < cfg->code_len; i++) {
1262 for (pindex = 0; pindex < patches->len; ++pindex) {
1263 patch_info = g_ptr_array_index (patches, pindex);
1264 if (patch_info->ip.i == i)
1269 if (patch_info && (pindex < patches->len)) {
1270 switch (patch_info->type) {
1271 case MONO_PATCH_INFO_LABEL:
1272 case MONO_PATCH_INFO_BB:
1273 case MONO_PATCH_INFO_NONE:
1275 case MONO_PATCH_INFO_GOT_OFFSET: {
1276 guint32 offset = mono_arch_get_patch_offset (code + i);
1277 for (j = 0; j < offset; ++j)
1278 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i + j]);
1279 fprintf (tmpfp, ".int got - . + %d\n", offset);
1281 i += offset + 4 - 1;
1286 if (!is_got_patch (patch_info->type))
1289 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1290 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i + j]);
1292 fprintf (tmpfp, ".int got - . + %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4));
1293 #elif defined(__i386__)
1294 fprintf (tmpfp, ".int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer))));
1296 acfg->got_offset ++;
1298 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1304 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1307 for (i = 0; i < cfg->code_len; i++) {
1308 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1312 emit_section_change (tmpfp, ".text", 1);
1314 #ifndef AS_HAS_SUBSECTIONS
1315 emit_global (tmpfp, mname_p, FALSE);
1318 emit_alignment (tmpfp, 4);
1320 emit_label (tmpfp, mname_p);
1322 fprintf (tmpfp, "\t.long %d\n", cfg->code_len);
1323 fprintf (tmpfp, "\t.long %ld\n", (long)cfg->used_int_regs);
1325 /* Exception table */
1326 if (header->num_clauses) {
1327 MonoJitInfo *jinfo = cfg->jit_info;
1329 fprintf (tmpfp, "\t.long %d\n", jinfo->exvar_offset);
1331 for (k = 0; k < header->num_clauses; ++k) {
1332 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1334 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1335 fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->data.filter - code));
1337 /* the class is loaded from the header: optimize away later */
1338 fprintf (tmpfp, "\t.long %d\n", 0);
1340 fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_start - code));
1341 fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->try_end - code));
1342 fprintf (tmpfp, "\t.long %d\n", (gint)((guint8*)ei->handler_start - code));
1347 if (cfg->opt & MONO_OPT_SHARED) {
1348 fprintf (tmpfp, "\t.long %d\n", g_list_length (cfg->ldstr_list));
1349 for (l = cfg->ldstr_list; l; l = l->next) {
1350 fprintf (tmpfp, "\t.long 0x%08lx\n", (long)l->data);
1354 /* Used only in shared mode */
1355 g_assert (!cfg->ldstr_list);
1357 //printf ("M: %s (%s).\n", mono_method_full_name (method, TRUE), mname);
1359 #ifdef MONO_ARCH_HAVE_PIC_AOT
1360 fprintf (tmpfp, "\t.long %d\n", first_got_offset);
1363 /* First emit the type+position table */
1366 for (pindex = 0; pindex < patches->len; ++pindex) {
1368 patch_info = g_ptr_array_index (patches, pindex);
1370 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1371 (patch_info->type == MONO_PATCH_INFO_BB) ||
1372 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1373 (patch_info->type == MONO_PATCH_INFO_NONE))
1378 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1379 offset = patch_info->ip.i - last_offset;
1380 last_offset = patch_info->ip.i;
1382 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1383 /* Only the type is needed */
1384 fprintf (tmpfp, "\t.byte %d\n", patch_info->type);
1386 /* Encode type+position compactly */
1387 g_assert (patch_info->type < 64);
1388 if (offset < 1024 - 1) {
1389 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + (offset >> 8));
1390 fprintf (tmpfp, "\t.byte %d\n", offset & ((1 << 8) - 1));
1393 fprintf (tmpfp, "\t.byte %d\n", (patch_info->type << 2) + 3);
1394 fprintf (tmpfp, "\t.byte %d\n", 255);
1395 emit_alignment(tmpfp, 4);
1396 fprintf (tmpfp, "\t.long %d\n", offset);
1403 * 0 is PATCH_INFO_BB, which can't be in the file.
1405 /* NULL terminated array */
1406 fprintf (tmpfp, "\t.byte 0\n");
1408 emit_alignment (tmpfp, sizeof (gpointer));
1410 /* Then emit the other info */
1411 for (pindex = 0; pindex < patches->len; ++pindex) {
1412 patch_info = g_ptr_array_index (patches, pindex);
1414 switch (patch_info->type) {
1415 case MONO_PATCH_INFO_LABEL:
1416 case MONO_PATCH_INFO_BB:
1417 case MONO_PATCH_INFO_GOT_OFFSET:
1418 case MONO_PATCH_INFO_NONE:
1420 case MONO_PATCH_INFO_IMAGE:
1421 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.image));
1423 case MONO_PATCH_INFO_METHOD_REL:
1424 fprintf (tmpfp, "\t.long 0x%08x\n", (gint)patch_info->data.offset);
1426 case MONO_PATCH_INFO_SWITCH: {
1427 gpointer *table = (gpointer *)patch_info->data.table->table;
1430 fprintf (tmpfp, "\t.long %d\n", patch_info->data.table->table_size);
1432 for (k = 0; k < patch_info->data.table->table_size; k++) {
1433 fprintf (tmpfp, "\t.long %d\n", (int)(gssize)table [k]);
1437 case MONO_PATCH_INFO_METHODCONST:
1438 case MONO_PATCH_INFO_METHOD:
1439 case MONO_PATCH_INFO_METHOD_JUMP: {
1440 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1441 guint32 token = patch_info->data.method->token;
1442 g_assert (image_index < 256);
1443 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1445 fprintf (tmpfp, "\t.long 0x%08x\n", (image_index << 24) + (mono_metadata_token_index (token)));
1448 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1449 guint32 icall_index;
1451 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1453 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1454 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1455 GUINT_TO_POINTER (icall_index));
1456 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1458 fprintf (tmpfp, "\t.long 0x%08x\n", icall_index - 1);
1461 case MONO_PATCH_INFO_LDSTR:
1462 case MONO_PATCH_INFO_LDTOKEN:
1463 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1464 fprintf (tmpfp, "\t.long 0x%08x\n", get_image_index (acfg, patch_info->data.token->image));
1465 fprintf (tmpfp, "\t.long 0x%08x\n", patch_info->data.token->token);
1467 case MONO_PATCH_INFO_EXC_NAME: {
1468 MonoClass *ex_class;
1471 mono_class_from_name (mono_defaults.exception_class->image,
1472 "System", patch_info->data.target);
1473 g_assert (ex_class);
1474 emit_klass_info (acfg, ex_class);
1477 case MONO_PATCH_INFO_R4:
1478 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1480 case MONO_PATCH_INFO_R8:
1481 emit_alignment (tmpfp, 8);
1482 fprintf (tmpfp, "\t.long 0x%08x\n", *((guint32 *)patch_info->data.target));
1483 fprintf (tmpfp, "\t.long 0x%08x\n", *(((guint32 *)patch_info->data.target) + 1));
1485 case MONO_PATCH_INFO_VTABLE:
1486 case MONO_PATCH_INFO_CLASS_INIT:
1487 case MONO_PATCH_INFO_CLASS:
1488 case MONO_PATCH_INFO_IID:
1489 emit_klass_info (acfg, patch_info->data.klass);
1491 case MONO_PATCH_INFO_FIELD:
1492 case MONO_PATCH_INFO_SFLDA:
1493 emit_field_info (acfg, patch_info->data.field);
1495 case MONO_PATCH_INFO_WRAPPER: {
1496 fprintf (tmpfp, "\t.long %d\n", patch_info->data.method->wrapper_type);
1498 switch (patch_info->data.method->wrapper_type) {
1499 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1501 guint32 image_index;
1504 m = mono_marshal_method_from_wrapper (patch_info->data.method);
1505 image_index = get_image_index (acfg, m->klass->image);
1507 g_assert (image_index < 256);
1508 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1510 fprintf (tmpfp, "\t.long %d\n", (image_index << 24) + (mono_metadata_token_index (token)));
1513 case MONO_WRAPPER_PROXY_ISINST:
1514 case MONO_WRAPPER_LDFLD:
1515 case MONO_WRAPPER_STFLD:
1516 case MONO_WRAPPER_ISINST: {
1517 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1518 emit_klass_info (acfg, proxy_class);
1521 case MONO_WRAPPER_STELEMREF:
1524 g_assert_not_reached ();
1529 g_warning ("unable to handle jump info %d", patch_info->type);
1530 g_assert_not_reached ();
1539 mono_debug_serialize_debug_info (cfg, &buf, &buf_len);
1541 fprintf (tmpfp, "\t.long %d\n", buf_len);
1543 for (i = 0; i < buf_len; ++i)
1544 fprintf (tmpfp, ".byte %d\n", (unsigned int) buf [i]);
1550 /* fixme: save the rest of the required infos */
1557 str_begins_with (const char *str1, const char *str2)
1559 int len = strlen (str2);
1560 return strncmp (str1, str2, len) == 0;
1564 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1566 gchar **args, **ptr;
1568 memset (opts, 0, sizeof (*opts));
1570 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1571 for (ptr = args; ptr && *ptr; ptr ++) {
1572 const char *arg = *ptr;
1574 if (str_begins_with (arg, "outfile=")) {
1575 opts->outfile = g_strdup (arg + strlen ("outfile="));
1578 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1585 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1588 MonoImage *image = ass->image;
1590 char *com, *tmpfname, *opts_str;
1594 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1595 GHashTable *ref_hash;
1596 MonoAotCompile *acfg;
1598 MonoAotOptions aot_opts;
1599 char *outfile_name, *tmp_outfile_name;
1601 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1603 mono_aot_parse_options (aot_options, &aot_opts);
1605 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1606 tmpfp = fdopen (i, "w+");
1609 ref_hash = g_hash_table_new (NULL, NULL);
1611 acfg = g_new0 (MonoAotCompile, 1);
1613 acfg->ref_hash = ref_hash;
1614 acfg->icall_hash = g_hash_table_new (NULL, NULL);
1615 acfg->icall_table = g_ptr_array_new ();
1616 acfg->image_hash = g_hash_table_new (NULL, NULL);
1617 acfg->image_table = g_ptr_array_new ();
1619 write_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1621 write_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1623 opts_str = g_strdup_printf ("%d", opts);
1624 write_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1629 * Emit code and method infos into two gas subsections sequentially, so we
1630 * access them without defining a separate global symbol for each one.
1631 * This only works with gas.
1633 #ifdef AS_HAS_SUBSECTIONS
1634 symbol = g_strdup_printf ("methods");
1635 emit_section_change (tmpfp, ".text", 0);
1636 emit_global (tmpfp, symbol, FALSE);
1637 emit_alignment (tmpfp, 8);
1638 emit_label (tmpfp, symbol);
1640 symbol = g_strdup_printf ("method_infos");
1641 emit_section_change (tmpfp, ".text", 1);
1642 emit_global (tmpfp, symbol, FALSE);
1643 emit_alignment (tmpfp, 8);
1644 emit_label (tmpfp, symbol);
1647 emitted = g_new0 (gboolean, image->tables [MONO_TABLE_METHOD].rows + 32);
1649 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1650 MonoJumpInfo *patch_info;
1652 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1653 method = mono_get_method (image, token, NULL);
1655 /* fixme: maybe we can also precompile wrapper methods */
1656 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1657 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1658 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1659 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1660 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1666 /* fixme: we need to patch the IP for the LMF in that case */
1667 if (method->save_lmf) {
1668 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1673 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1674 //mono_compile_method (method);
1677 * Since these methods are the only ones which are compiled with
1678 * AOT support, and they are not used by runtime startup/shutdown code,
1679 * the runtime will not see AOT methods during AOT compilation,so it
1680 * does not need to support them by creating a fake GOT etc.
1682 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, TRUE, 0);
1685 if (cfg->disable_aot) {
1686 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1692 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1693 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1694 /* unable to handle this */
1695 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1706 /* some wrappers are very common */
1707 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1708 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1709 switch (patch_info->data.method->wrapper_type) {
1710 case MONO_WRAPPER_PROXY_ISINST:
1711 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1715 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1716 switch (patch_info->data.method->wrapper_type) {
1717 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1718 case MONO_WRAPPER_STFLD:
1719 case MONO_WRAPPER_LDFLD:
1720 case MONO_WRAPPER_STELEMREF:
1721 case MONO_WRAPPER_ISINST:
1722 case MONO_WRAPPER_PROXY_ISINST:
1723 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1730 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1731 switch (patch_info->type) {
1732 case MONO_PATCH_INFO_METHOD:
1733 case MONO_PATCH_INFO_METHODCONST:
1734 if (patch_info->data.method->wrapper_type) {
1735 /* unable to handle this */
1736 //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));
1740 if (!patch_info->data.method->token)
1742 * The method is part of a constructed type like Int[,].Set (). It doesn't
1743 * have a token, and we can't make one, since the parent type is part of
1744 * assembly which contains the element type, and not the assembly which
1745 * referenced this type.
1749 case MONO_PATCH_INFO_VTABLE:
1750 case MONO_PATCH_INFO_CLASS_INIT:
1751 case MONO_PATCH_INFO_CLASS:
1752 case MONO_PATCH_INFO_IID:
1753 if (!patch_info->data.klass->type_token)
1754 if (!patch_info->data.klass->element_class->type_token)
1767 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1770 emit_method (acfg, cfg);
1772 mono_destroy_compile (cfg);
1778 * The icall and image tables are small but referenced in a lot of places.
1779 * So we emit them at once, and reference their elements by an index
1780 * instead of an assembly label to cut back on the number of relocations.
1783 /* Emit icall table */
1785 symbol = g_strdup_printf ("mono_icall_table");
1786 emit_section_change (tmpfp, ".text", 1);
1787 emit_global(tmpfp, symbol, FALSE);
1788 emit_alignment(tmpfp, 8);
1789 emit_label(tmpfp, symbol);
1790 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1791 for (i = 0; i < acfg->icall_table->len; i++)
1792 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1794 /* Emit image table */
1796 symbol = g_strdup_printf ("mono_image_table");
1797 emit_section_change (tmpfp, ".text", 1);
1798 emit_global(tmpfp, symbol, FALSE);
1799 emit_alignment(tmpfp, 8);
1800 emit_label(tmpfp, symbol);
1801 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1802 for (i = 0; i < acfg->image_table->len; i++) {
1803 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1804 MonoAssemblyName *aname = &image->assembly->aname;
1806 /* FIXME: Support multi-module assemblies */
1807 g_assert (image->assembly->image == image);
1809 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1810 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1811 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1812 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1814 emit_alignment (tmpfp, 8);
1815 fprintf (tmpfp, ".long %d\n", aname->flags);
1816 fprintf (tmpfp, ".long %d\n", aname->major);
1817 fprintf (tmpfp, ".long %d\n", aname->minor);
1818 fprintf (tmpfp, ".long %d\n", aname->build);
1819 fprintf (tmpfp, ".long %d\n", aname->revision);
1822 #ifdef MONO_ARCH_HAVE_PIC_AOT
1825 /* Don't make GOT global so accesses to it don't need relocations */
1826 symbol = g_strdup_printf ("got");
1828 emit_section_change (tmpfp, ".bss", 1);
1830 emit_section_change (tmpfp, ".data", 1);
1832 emit_alignment (tmpfp, 8);
1833 emit_label(tmpfp, symbol);
1834 if (acfg->got_offset > 0)
1835 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1837 symbol = g_strdup_printf ("got_addr");
1838 emit_section_change (tmpfp, ".data", 1);
1839 emit_global (tmpfp, symbol, FALSE);
1840 emit_alignment (tmpfp, 8);
1841 emit_label(tmpfp, symbol);
1842 emit_pointer (tmpfp, "got");
1844 symbol = g_strdup_printf ("got_size");
1845 emit_section_change (tmpfp, ".data", 1);
1846 emit_global (tmpfp, symbol, FALSE);
1847 emit_alignment (tmpfp, 8);
1848 emit_label(tmpfp, symbol);
1849 fprintf (tmpfp, ".long %d\n", acfg->got_offset * sizeof (gpointer));
1852 #ifdef AS_HAS_SUBSECTIONS
1853 symbol = g_strdup_printf ("method_offsets");
1854 emit_section_change (tmpfp, ".text", 1);
1855 emit_global (tmpfp, symbol, FALSE);
1856 emit_alignment (tmpfp, 8);
1857 emit_label(tmpfp, symbol);
1859 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1861 symbol = g_strdup_printf (".Lm_%x", i + 1);
1862 fprintf (tmpfp, ".long %s - methods\n", symbol);
1865 fprintf (tmpfp, ".long 0xffffffff\n");
1868 symbol = g_strdup_printf ("method_info_offsets");
1869 emit_section_change (tmpfp, ".text", 1);
1870 emit_global (tmpfp, symbol, FALSE);
1871 emit_alignment (tmpfp, 8);
1872 emit_label(tmpfp, symbol);
1874 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1876 symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1877 fprintf (tmpfp, ".long %s - method_infos\n", symbol);
1880 fprintf (tmpfp, ".long 0\n");
1884 * g_module_symbol takes a lot of time for failed lookups, so we emit
1885 * a table which contains one bit for each method. This bit specifies
1886 * whenever the method is emitted or not.
1888 symbol = g_strdup_printf ("mono_methods_present_table");
1889 emit_section_change (tmpfp, ".text", 1);
1890 emit_global (tmpfp, symbol, FALSE);
1891 emit_alignment (tmpfp, 8);
1892 emit_label (tmpfp, symbol);
1897 nrows = image->tables [MONO_TABLE_METHOD].rows;
1898 for (i = 0; i < nrows / 32 + 1; ++i) {
1900 for (k = 0; k < 32; ++k) {
1901 if (emitted [(i * 32) + k])
1904 //printf ("EMITTED [%d] = %d.\n", i, b);
1905 fprintf (tmpfp, "\t.long %d\n", w);
1912 #if defined(__x86_64__)
1913 com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1914 #elif defined(sparc) && SIZEOF_VOID_P == 8
1915 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1917 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1919 printf ("Executing the native assembler: %s\n", com);
1920 if (system (com) != 0) {
1927 if (aot_opts.outfile)
1928 outfile_name = g_strdup_printf ("%s", aot_opts.outfile);
1930 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1932 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1935 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1936 #elif defined(__ppc__) && defined(__MACH__)
1937 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1939 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
1941 printf ("Executing the native linker: %s\n", com);
1942 if (system (com) != 0) {
1943 g_free (tmp_outfile_name);
1944 g_free (outfile_name);
1950 com = g_strdup_printf ("%s.o", tmpfname);
1953 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
1954 printf ("Stripping the binary: %s\n", com);
1958 rename (tmp_outfile_name, outfile_name);
1960 g_free (tmp_outfile_name);
1961 g_free (outfile_name);
1963 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
1964 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
1965 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
1966 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
1967 printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
1968 //printf ("Retained input file.\n");
1978 mono_aot_init (void)
1983 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1989 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
1995 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)