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"
58 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
60 typedef struct MonoAotMethod {
62 MonoJumpInfo *patch_info;
66 typedef struct MonoAotModule {
68 /* Optimization flags used to compile the module */
70 /* Maps MonoMethods to MonoAotMethodInfos */
72 /* Pointer to the Global Offset Table */
76 MonoAssemblyName *image_names;
78 MonoImage **image_table;
81 guint32 *code_offsets;
83 guint32 *method_info_offsets;
86 typedef struct MonoAotOptions {
89 gboolean write_symbols;
92 typedef struct MonoAotCompile {
94 GHashTable *icall_hash;
95 GPtrArray *icall_table;
96 GHashTable *image_hash;
97 GPtrArray *image_table;
99 guint32 *method_got_offsets;
100 MonoAotOptions aot_opts;
103 static GHashTable *aot_modules;
105 static CRITICAL_SECTION aot_mutex;
108 * Disabling this will make a copy of the loaded code and use the copy instead
109 * of the original. This will place the caller and the callee close to each
110 * other in memory, possibly improving cache behavior. Since the original
111 * code is in copy-on-write memory, this will not increase the memory usage
114 #ifdef MONO_ARCH_HAVE_PIC_AOT
115 static gboolean use_loaded_code = TRUE;
117 static gboolean use_loaded_code = FALSE;
121 * Whenever to AOT compile loaded assemblies on demand and store them in
122 * a cache under $HOME/.mono/aot-cache.
124 static gboolean use_aot_cache = FALSE;
127 static gint32 mono_last_aot_method = -1;
130 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info);
133 is_got_patch (MonoJumpInfoType patch_type)
137 #elif defined(__i386__)
144 /*****************************************************/
146 /*****************************************************/
149 load_image (MonoAotModule *module, int index)
151 MonoAssembly *assembly;
152 MonoImageOpenStatus status;
154 if (module->image_table [index])
155 return module->image_table [index];
156 if (module->out_of_date)
159 assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
161 module->out_of_date = TRUE;
165 if (strcmp (assembly->image->guid, module->image_guids [index])) {
166 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);
167 module->out_of_date = TRUE;
171 module->image_table [index] = assembly->image;
172 return assembly->image;
177 decode_value (char *_ptr, char **rptr)
179 unsigned char *ptr = (unsigned char *) _ptr;
180 unsigned char b = *ptr;
183 if ((b & 0x80) == 0){
186 } else if ((b & 0x40) == 0){
187 len = ((b & 0x3f) << 8 | ptr [1]);
189 } else if (b != 0xff) {
190 len = ((b & 0x1f) << 24) |
197 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
203 //printf ("DECODE: %d.\n", len);
208 decode_klass_info (MonoAotModule *module, char *buf, char **endbuf)
212 guint32 token, rank, image_index;
214 image_index = decode_value (buf, &buf);
215 image = load_image (module, image_index);
218 token = decode_value (buf, &buf);
219 if (mono_metadata_token_code (token) == 0) {
220 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
222 token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
223 rank = decode_value (buf, &buf);
224 klass = mono_class_get (image, token);
226 klass = mono_array_class_get (klass, rank);
229 mono_class_init (klass);
235 static MonoClassField*
236 decode_field_info (MonoAotModule *module, char *buf, char **endbuf)
238 MonoClass *klass = decode_klass_info (module, buf, &buf);
244 token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf);
248 return mono_class_get_field (klass, token);
253 make_writable (guint8* addr, guint32 len)
255 #ifndef PLATFORM_WIN32
259 page_start = (char *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
260 pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
261 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
266 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
272 create_cache_structure (void)
278 home = g_get_home_dir ();
282 tmp = g_build_filename (home, ".mono", NULL);
283 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
284 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
285 #ifdef PLATFORM_WIN32
288 err = mkdir (tmp, 0777);
291 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
297 tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
298 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
299 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
300 #ifdef PLATFORM_WIN32
303 err = mkdir (tmp, 0777);
306 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
315 * load_aot_module_from_cache:
317 * Experimental code to AOT compile loaded assemblies on demand.
320 * - Add environment variable MONO_AOT_CACHE_OPTIONS
321 * - Add options for controlling the cache size
322 * - Handle full cache by deleting old assemblies lru style
323 * - Add options for excluding assemblies during development
324 * - Maybe add a threshold after an assembly is AOT compiled
325 * - invoking a new mono process is a security risk
328 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
330 char *fname, *cmd, *tmp2;
338 if (assembly->image->dynamic)
341 create_cache_structure ();
343 home = g_get_home_dir ();
345 tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
346 fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
350 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
351 module = g_module_open (fname, G_MODULE_BIND_LAZY);
354 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
356 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
358 /* FIXME: security */
359 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
361 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
364 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
368 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
370 module = g_module_open (fname, G_MODULE_BIND_LAZY);
377 load_aot_module (MonoAssembly *assembly, gpointer user_data)
381 gboolean usable = TRUE;
382 char *saved_guid = NULL;
383 char *aot_version = NULL;
384 char *opt_flags = NULL;
386 #ifdef MONO_ARCH_HAVE_PIC_AOT
387 gpointer *got_addr = NULL;
388 gpointer *got = NULL;
389 guint32 *got_size_ptr = NULL;
392 if (mono_compile_aot)
396 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
398 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
400 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
402 if (!assembly->aot_module) {
403 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
407 if (!assembly->aot_module) {
412 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
413 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
414 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
416 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
417 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);
421 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
422 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
429 g_module_close (assembly->aot_module);
430 assembly->aot_module = NULL;
434 #ifdef MONO_ARCH_HAVE_PIC_AOT
435 g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
437 got = (gpointer*)*got_addr;
439 g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
440 g_assert (got_size_ptr);
443 info = g_new0 (MonoAotModule, 1);
444 info->aot_name = aot_name;
445 info->methods = g_hash_table_new (NULL, NULL);
446 #ifdef MONO_ARCH_HAVE_PIC_AOT
448 info->got_size = *got_size_ptr;
450 sscanf (opt_flags, "%d", &info->opts);
452 /* Read image table */
454 guint32 table_len, i;
457 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
460 table_len = *(guint32*)table;
461 table += sizeof (guint32);
462 info->image_table = g_new0 (MonoImage*, table_len);
463 info->image_names = g_new0 (MonoAssemblyName, table_len);
464 info->image_guids = g_new0 (char*, table_len);
465 for (i = 0; i < table_len; ++i) {
466 MonoAssemblyName *aname = &(info->image_names [i]);
468 aname->name = g_strdup (table);
469 table += strlen (table) + 1;
470 info->image_guids [i] = g_strdup (table);
471 table += strlen (table) + 1;
473 aname->culture = g_strdup (table);
474 table += strlen (table) + 1;
475 memcpy (aname->public_key_token, table, strlen (table) + 1);
476 table += strlen (table) + 1;
478 table = ALIGN_PTR_TO (table, 8);
479 aname->flags = *(guint32*)table;
481 aname->major = *(guint32*)table;
483 aname->minor = *(guint32*)table;
485 aname->build = *(guint32*)table;
487 aname->revision = *(guint32*)table;
492 /* Read icall table */
494 guint32 table_len, i;
497 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
500 table_len = *(guint32*)table;
501 table += sizeof (guint32);
502 info->icall_table = g_new0 (char*, table_len);
503 for (i = 0; i < table_len; ++i) {
504 info->icall_table [i] = table;
505 table += strlen (table) + 1;
509 /* Read method and method_info tables */
510 g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
511 g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
512 g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
513 g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
515 EnterCriticalSection (&aot_mutex);
516 g_hash_table_insert (aot_modules, assembly, info);
517 LeaveCriticalSection (&aot_mutex);
519 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
525 InitializeCriticalSection (&aot_mutex);
526 aot_modules = g_hash_table_new (NULL, NULL);
528 mono_install_assembly_load_hook (load_aot_module, NULL);
530 if (getenv ("MONO_LASTAOT"))
531 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
532 if (getenv ("MONO_AOT_CACHE"))
533 use_aot_cache = TRUE;
537 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
539 MonoClass *klass = method->klass;
540 MonoAssembly *ass = klass->image->assembly;
541 GModule *module = ass->aot_module;
544 MonoAotModule *aot_module;
545 MonoAotMethod *minfo;
554 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
557 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
558 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
559 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
560 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
563 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
565 g_assert (klass->inited);
567 if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
568 /* Non shared AOT code can't be used in other appdomains */
571 minfo = g_hash_table_lookup (aot_module->methods, method);
572 /* Can't use code from non-root domains since they can be unloaded */
573 if (minfo && (minfo->domain == mono_get_root_domain ())) {
574 /* This method was already loaded in another appdomain */
576 /* Duplicate jinfo */
577 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
578 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo));
579 if (jinfo->clauses) {
580 MonoMethodHeader *header = mono_method_get_header (method);
583 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
584 memcpy (jinfo->clauses, minfo->info->clauses, sizeof (MonoJitExceptionInfo) * header->num_clauses);
590 if (aot_module->out_of_date)
593 if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
594 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", mono_method_full_name (method, TRUE));
598 code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
599 info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
601 if (mono_last_aot_method != -1) {
602 if (mono_jit_stats.methods_aot > mono_last_aot_method)
605 if (mono_jit_stats.methods_aot == mono_last_aot_method)
606 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
609 return mono_aot_load_method (domain, aot_module, method, code, info);
613 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
615 MonoClass *klass = method->klass;
616 MonoJumpInfo *patch_info = NULL;
617 guint code_len, used_int_regs, used_strings;
618 MonoAotMethod *minfo;
622 int i, pindex, got_index;
623 gboolean non_got_patches, keep_patches = TRUE;
624 gboolean has_clauses;
627 minfo = g_new0 (MonoAotMethod, 1);
629 minfo->domain = domain;
630 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
633 code_len = decode_value (p, &p);
634 used_int_regs = decode_value (p, &p);
636 if (!use_loaded_code) {
638 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
639 memcpy (code2, code, code_len);
640 mono_arch_flush_icache (code2, code_len);
644 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);
646 /* Exception table */
647 has_clauses = decode_value (p, &p);
649 MonoMethodHeader *header = mono_method_get_header (method);
651 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitExceptionInfo) * header->num_clauses);
652 jinfo->num_clauses = header->num_clauses;
654 for (i = 0; i < header->num_clauses; ++i) {
655 MonoExceptionClause *ec = &header->clauses [i];
656 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
658 ei->flags = ec->flags;
659 ei->exvar_offset = decode_value (p, &p);
661 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
662 ei->data.filter = code + decode_value (p, &p);
664 ei->data.catch_class = ec->data.catch_class;
666 ei->try_start = code + decode_value (p, &p);
667 ei->try_end = code + decode_value (p, &p);
668 ei->handler_start = code + decode_value (p, &p);
672 if (aot_module->opts & MONO_OPT_SHARED)
673 used_strings = decode_value (p, &p);
677 for (i = 0; i < used_strings; i++) {
678 guint token = decode_value (p, &p);
679 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
682 if (aot_module->opts & MONO_OPT_SHARED)
683 keep_patches = FALSE;
685 #ifdef MONO_ARCH_HAVE_PIC_AOT
686 got_index = decode_value (p, &p);
687 keep_patches = FALSE;
694 guint32 last_offset, buf_len;
699 mp = mono_mempool_new ();
701 /* First load the type + offset table */
703 patches = g_ptr_array_new ();
705 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
707 #if defined(MONO_ARCH_HAVE_PIC_AOT)
714 b2 = *((guint8*)p + 1);
719 if (((b1 & (1 + 2)) == 3) && (b2 == 255))
720 ji->ip.i = decode_value (p, &p);
722 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
724 ji->ip.i += last_offset;
725 last_offset = ji->ip.i;
727 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
729 ji->next = patch_info;
732 g_ptr_array_add (patches, ji);
735 /* Null terminated array */
738 /* Then load the other data */
739 for (pindex = 0; pindex < patches->len; ++pindex) {
740 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
743 case MONO_PATCH_INFO_CLASS:
744 case MONO_PATCH_INFO_IID:
745 case MONO_PATCH_INFO_VTABLE:
746 case MONO_PATCH_INFO_CLASS_INIT:
747 ji->data.klass = decode_klass_info (aot_module, p, &p);
751 case MONO_PATCH_INFO_IMAGE:
752 ji->data.image = load_image (aot_module, decode_value (p, &p));
756 case MONO_PATCH_INFO_METHOD:
757 case MONO_PATCH_INFO_METHODCONST:
758 case MONO_PATCH_INFO_METHOD_JUMP: {
759 guint32 image_index, token, value;
761 value = decode_value (p, &p);
762 image_index = value >> 24;
763 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
765 image = load_image (aot_module, image_index);
768 ji->data.method = mono_get_method (image, token, NULL);
769 g_assert (ji->data.method);
770 mono_class_init (ji->data.method->klass);
774 case MONO_PATCH_INFO_WRAPPER: {
775 guint32 wrapper_type;
777 wrapper_type = decode_value (p, &p);
779 switch (wrapper_type) {
780 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
781 guint32 image_index, token, value;
783 value = decode_value (p, &p);
784 image_index = value >> 24;
785 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
787 image = load_image (aot_module, image_index);
790 ji->data.method = mono_get_method (image, token, NULL);
791 g_assert (ji->data.method);
792 mono_class_init (ji->data.method->klass);
794 ji->type = MONO_PATCH_INFO_METHOD;
795 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
798 case MONO_WRAPPER_PROXY_ISINST: {
799 MonoClass *klass = decode_klass_info (aot_module, p, &p);
802 ji->type = MONO_PATCH_INFO_METHOD;
803 ji->data.method = mono_marshal_get_proxy_cancast (klass);
806 case MONO_WRAPPER_LDFLD:
807 case MONO_WRAPPER_STFLD:
808 case MONO_WRAPPER_ISINST: {
809 MonoClass *klass = decode_klass_info (aot_module, p, &p);
812 ji->type = MONO_PATCH_INFO_METHOD;
813 if (wrapper_type == MONO_WRAPPER_LDFLD)
814 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
815 else if (wrapper_type == MONO_WRAPPER_STFLD)
816 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
818 ji->data.method = mono_marshal_get_isinst (klass);
821 case MONO_WRAPPER_STELEMREF:
822 ji->type = MONO_PATCH_INFO_METHOD;
823 ji->data.method = mono_marshal_get_stelemref ();
826 g_assert_not_reached ();
830 case MONO_PATCH_INFO_FIELD:
831 case MONO_PATCH_INFO_SFLDA:
832 ji->data.field = decode_field_info (aot_module, p, &p);
836 case MONO_PATCH_INFO_INTERNAL_METHOD:
837 ji->data.name = aot_module->icall_table [decode_value (p, &p)];
838 g_assert (ji->data.name);
839 //printf ("A: %s.\n", ji->data.name);
841 case MONO_PATCH_INFO_SWITCH:
842 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
843 ji->data.table->table_size = decode_value (p, &p);
844 table = g_new (gpointer, ji->data.table->table_size);
845 ji->data.table->table = (MonoBasicBlock**)table;
846 for (i = 0; i < ji->data.table->table_size; i++)
847 table [i] = (gpointer)(gssize)decode_value (p, &p);
849 case MONO_PATCH_INFO_R4:
850 ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
853 val = decode_value (p, &p);
854 *(float*)ji->data.target = *(float*)&val;
856 case MONO_PATCH_INFO_R8: {
857 ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
860 val [0] = decode_value (p, &p);
861 val [1] = decode_value (p, &p);
862 *(double*)ji->data.target = *(double*)val;
865 case MONO_PATCH_INFO_LDSTR:
866 image = load_image (aot_module, decode_value (p, &p));
869 ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
871 case MONO_PATCH_INFO_DECLSEC:
872 case MONO_PATCH_INFO_LDTOKEN:
873 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
874 image = load_image (aot_module, decode_value (p, &p));
877 ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
879 case MONO_PATCH_INFO_EXC_NAME:
880 ji->data.klass = decode_klass_info (aot_module, p, &p);
883 ji->data.name = ji->data.klass->name;
885 case MONO_PATCH_INFO_METHOD_REL:
886 ji->data.offset = decode_value (p, &p);
889 g_warning ("unhandled type %d", ji->type);
890 g_assert_not_reached ();
894 buf_len = decode_value (p, &p);
895 mono_debug_add_aot_method (domain, method, code, p, buf_len);
897 #if MONO_ARCH_HAVE_PIC_AOT
898 mono_arch_flush_icache (code, code_len);
901 make_writable (code, code_len);
903 /* Do this outside the lock to avoid deadlocks */
904 LeaveCriticalSection (&aot_mutex);
905 non_got_patches = FALSE;
906 for (pindex = 0; pindex < patches->len; ++pindex) {
907 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
909 if (is_got_patch (ji->type)) {
910 aot_module->got [got_index] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
912 ji->type = MONO_PATCH_INFO_NONE;
915 non_got_patches = TRUE;
917 if (non_got_patches) {
918 make_writable (code, code_len);
919 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
921 EnterCriticalSection (&aot_mutex);
924 /* disable write protection */
925 make_writable (code, code_len);
927 /* Do this outside the lock to avoid deadlocks */
928 LeaveCriticalSection (&aot_mutex);
929 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
930 EnterCriticalSection (&aot_mutex);
933 g_ptr_array_free (patches, TRUE);
936 mono_mempool_destroy (mp);
939 mono_jit_stats.methods_aot++;
942 jinfo->code_size = code_len;
943 jinfo->used_regs = used_int_regs;
944 jinfo->method = method;
945 jinfo->code_start = code;
946 #ifdef MONO_ARCH_HAVE_PIC_AOT
947 jinfo->domain_neutral = 0;
949 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
953 g_hash_table_insert (aot_module->methods, method, minfo);
959 g_ptr_array_free (patches, TRUE);
961 /* FIXME: The space in domain->mp is wasted */
962 if (aot_module->opts & MONO_OPT_SHARED)
963 /* No need to cache patches */
964 mono_mempool_destroy (mp);
970 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
974 EnterCriticalSection (&aot_mutex);
975 info = mono_aot_get_method_inner (domain, method);
976 LeaveCriticalSection (&aot_mutex);
978 /* Do this outside the lock */
980 mono_jit_info_table_add (domain, info);
988 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
992 MonoAotModule *aot_module;
994 ji = mono_jit_info_table_find (mono_domain_get (), code);
998 ass = ji->method->klass->image->assembly;
1002 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1003 if (!aot_module || !aot_module->got)
1006 return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
1009 /*****************************************************/
1011 /*****************************************************/
1014 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1017 /* For solaris as, GNU as should accept the same */
1018 fprintf (fp, ".section \"%s\"\n", section_name);
1019 #elif defined(__ppc__) && defined(__MACH__)
1020 /* This needs to be made more precise on mach. */
1021 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1023 fprintf (fp, "%s %d\n", section_name, subsection_index);
1028 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1038 fprintf (fp, "\t.type %s,#%s\n", name, stype);
1039 #elif !(defined(__ppc__) && defined(__MACH__))
1040 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1041 #elif defined(__x86_64__) || defined(__i386__)
1042 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1047 emit_global (FILE *fp, const char *name, gboolean func)
1049 #if defined(__ppc__) && defined(__MACH__)
1050 // mach-o always uses a '_' prefix.
1051 fprintf (fp, "\t.globl _%s\n", name);
1053 fprintf (fp, "\t.globl %s\n", name);
1056 emit_symbol_type (fp, name, func);
1060 emit_label (FILE *fp, const char *name)
1062 #if defined(__ppc__) && defined(__MACH__)
1063 // mach-o always uses a '_' prefix.
1064 fprintf (fp, "_%s:\n", name);
1066 fprintf (fp, "%s:\n", name);
1071 emit_string_symbol (FILE *fp, const char *name, const char *value)
1073 emit_section_change (fp, ".text", 1);
1074 emit_global(fp, name, FALSE);
1075 emit_label(fp, name);
1076 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1079 #if defined(__ppc__) && defined(__MACH__)
1081 ilog2(register int value)
1084 while (value & ~0xf) count += 4, value >>= 4;
1085 while (value) count++, value >>= 1;
1091 emit_alignment(FILE *fp, int size)
1093 #if defined(__ppc__) && defined(__MACH__)
1094 // the mach-o assembler specifies alignments as powers of 2.
1095 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1096 #elif defined(__powerpc__)
1097 /* ignore on linux/ppc */
1099 fprintf (fp, "\t.align %d\n", size);
1103 G_GNUC_UNUSED static void
1104 emit_pointer (FILE *fp, const char *target)
1106 emit_alignment (fp, sizeof (gpointer));
1107 #if defined(__x86_64__)
1108 fprintf (fp, "\t.quad %s\n", target);
1109 #elif defined(sparc) && SIZEOF_VOID_P == 8
1110 fprintf (fp, "\t.xword %s\n", target);
1112 fprintf (fp, "\t.long %s\n", target);
1117 mono_get_field_token (MonoClassField *field)
1119 MonoClass *klass = field->parent;
1122 for (i = 0; i < klass->field.count; ++i) {
1123 if (field == &klass->fields [i])
1124 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1127 g_assert_not_reached ();
1132 encode_value (gint32 value, char *buf, char **endbuf)
1136 //printf ("ENCODE: %d 0x%x.\n", value, value);
1139 * Same encoding as the one used in the metadata, extended to handle values
1140 * greater than 0x1fffffff.
1142 if ((value >= 0) && (value <= 127))
1144 else if ((value >= 0) && (value <= 16383)) {
1145 p [0] = 0x80 | (value >> 8);
1146 p [1] = value & 0xff;
1148 } else if ((value >= 0) && (value <= 0x1fffffff)) {
1149 p [0] = (value >> 24) | 0xc0;
1150 p [1] = (value >> 16) & 0xff;
1151 p [2] = (value >> 8) & 0xff;
1152 p [3] = value & 0xff;
1157 p [1] = (value >> 24) & 0xff;
1158 p [2] = (value >> 16) & 0xff;
1159 p [3] = (value >> 8) & 0xff;
1160 p [4] = value & 0xff;
1168 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1172 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1176 index = g_hash_table_size (cfg->image_hash);
1177 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1178 g_ptr_array_add (cfg->image_table, image);
1184 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, char *buf, char **endbuf)
1186 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1187 if (!klass->type_token) {
1189 g_assert (klass->rank > 0);
1190 g_assert (klass->element_class->type_token);
1191 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1192 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1193 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1194 encode_value (klass->rank, buf, &buf);
1197 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1198 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1204 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, char *buf, char **endbuf)
1206 guint32 token = mono_get_field_token (field);
1208 encode_klass_info (cfg, field->parent, buf, &buf);
1209 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1210 encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1215 compare_patches (gconstpointer a, gconstpointer b)
1219 i = (*(MonoJumpInfo**)a)->ip.i;
1220 j = (*(MonoJumpInfo**)b)->ip.i;
1232 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1236 int i, j, pindex, byte_index;
1237 guint8 *code, *mname, *mname_p;
1238 int func_alignment = 16;
1240 MonoJumpInfo *patch_info;
1241 MonoMethodHeader *header;
1242 #ifdef MONO_ARCH_HAVE_PIC_AOT
1247 method = cfg->method;
1248 code = cfg->native_code;
1249 header = mono_method_get_header (method);
1251 emit_section_change (tmpfp, ".text", 0);
1253 /* Make the labels local */
1254 mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1255 mname_p = g_strdup_printf ("%s_p", mname);
1257 emit_alignment(tmpfp, func_alignment);
1258 emit_label(tmpfp, mname);
1259 if (acfg->aot_opts.write_symbols)
1260 emit_global (tmpfp, mname, TRUE);
1262 if (cfg->verbose_level > 0)
1263 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), mname);
1265 /* Sort relocations */
1266 patches = g_ptr_array_new ();
1267 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1268 g_ptr_array_add (patches, patch_info);
1269 g_ptr_array_sort (patches, compare_patches);
1271 #ifdef MONO_ARCH_HAVE_PIC_AOT
1272 acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1274 for (i = 0; i < cfg->code_len; i++) {
1276 for (pindex = 0; pindex < patches->len; ++pindex) {
1277 patch_info = g_ptr_array_index (patches, pindex);
1278 if (patch_info->ip.i == i)
1283 if (patch_info && (pindex < patches->len)) {
1284 switch (patch_info->type) {
1285 case MONO_PATCH_INFO_LABEL:
1286 case MONO_PATCH_INFO_BB:
1287 case MONO_PATCH_INFO_NONE:
1289 case MONO_PATCH_INFO_GOT_OFFSET: {
1290 guint32 offset = mono_arch_get_patch_offset (code + i);
1291 fprintf (tmpfp, "\n.byte ");
1292 for (j = 0; j < offset; ++j)
1293 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1294 fprintf (tmpfp, "\n.int got - . + %d", offset);
1296 i += offset + 4 - 1;
1301 if (!is_got_patch (patch_info->type))
1304 fprintf (tmpfp, "\n.byte ");
1305 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1306 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1308 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4));
1309 #elif defined(__i386__)
1310 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer))));
1312 acfg->got_offset ++;
1314 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1320 if (byte_index == 0)
1321 fprintf (tmpfp, "\n.byte ");
1322 fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
1323 byte_index = (byte_index + 1) % 32;
1329 for (i = 0; i < cfg->code_len; i++) {
1330 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1333 fprintf (tmpfp, "\n");
1337 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
1342 int i, j, k, pindex, buf_size;
1343 guint32 debug_info_size;
1344 guint8 *code, *mname, *mname_p;
1346 MonoJumpInfo *patch_info;
1347 MonoMethodHeader *header;
1348 guint32 last_offset;
1351 #ifdef MONO_ARCH_HAVE_PIC_AOT
1352 guint32 first_got_offset;
1356 method = cfg->method;
1357 code = cfg->native_code;
1358 header = mono_method_get_header (method);
1360 /* Make the labels local */
1361 mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1362 mname_p = g_strdup_printf ("%s_p", mname);
1364 /* Sort relocations */
1365 patches = g_ptr_array_new ();
1366 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1367 g_ptr_array_add (patches, patch_info);
1368 g_ptr_array_sort (patches, compare_patches);
1370 #ifdef MONO_ARCH_HAVE_PIC_AOT
1371 first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
1374 /**********************/
1375 /* Encode method info */
1376 /**********************/
1378 buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
1379 p = buf = g_malloc (buf_size);
1381 encode_value (cfg->code_len, p, &p);
1382 encode_value (cfg->used_int_regs, p, &p);
1384 /* Exception table */
1385 encode_value (header->num_clauses ? 1 : 0, p, &p);
1386 if (header->num_clauses) {
1387 MonoJitInfo *jinfo = cfg->jit_info;
1389 for (k = 0; k < header->num_clauses; ++k) {
1390 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1392 encode_value (ei->exvar_offset, p, &p);
1394 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1395 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
1397 encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
1398 encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
1399 encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
1404 if (cfg->opt & MONO_OPT_SHARED) {
1405 encode_value (g_list_length (cfg->ldstr_list), p, &p);
1406 for (l = cfg->ldstr_list; l; l = l->next) {
1407 encode_value ((long)l->data, p, &p);
1411 /* Used only in shared mode */
1412 g_assert (!cfg->ldstr_list);
1414 #ifdef MONO_ARCH_HAVE_PIC_AOT
1415 encode_value (first_got_offset, p, &p);
1418 /* First emit the type+position table */
1421 for (pindex = 0; pindex < patches->len; ++pindex) {
1423 patch_info = g_ptr_array_index (patches, pindex);
1425 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1426 (patch_info->type == MONO_PATCH_INFO_BB) ||
1427 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1428 (patch_info->type == MONO_PATCH_INFO_NONE))
1433 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1434 offset = patch_info->ip.i - last_offset;
1435 last_offset = patch_info->ip.i;
1437 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1438 /* Only the type is needed */
1439 *p = patch_info->type;
1442 /* Encode type+position compactly */
1443 g_assert (patch_info->type < 64);
1444 if (offset < 1024 - 1) {
1445 *p = (patch_info->type << 2) + (offset >> 8);
1447 *p = offset & ((1 << 8) - 1);
1451 *p = (patch_info->type << 2) + 3;
1455 encode_value (offset, p, &p);
1461 * 0 is PATCH_INFO_BB, which can't be in the file.
1463 /* NULL terminated array */
1467 /* Then emit the other info */
1468 for (pindex = 0; pindex < patches->len; ++pindex) {
1469 patch_info = g_ptr_array_index (patches, pindex);
1471 switch (patch_info->type) {
1472 case MONO_PATCH_INFO_LABEL:
1473 case MONO_PATCH_INFO_BB:
1474 case MONO_PATCH_INFO_GOT_OFFSET:
1475 case MONO_PATCH_INFO_NONE:
1477 case MONO_PATCH_INFO_IMAGE:
1478 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
1480 case MONO_PATCH_INFO_METHOD_REL:
1481 encode_value ((gint)patch_info->data.offset, p, &p);
1483 case MONO_PATCH_INFO_SWITCH: {
1484 gpointer *table = (gpointer *)patch_info->data.table->table;
1487 encode_value (patch_info->data.table->table_size, p, &p);
1488 for (k = 0; k < patch_info->data.table->table_size; k++)
1489 encode_value ((int)(gssize)table [k], p, &p);
1492 case MONO_PATCH_INFO_METHODCONST:
1493 case MONO_PATCH_INFO_METHOD:
1494 case MONO_PATCH_INFO_METHOD_JUMP: {
1495 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1496 guint32 token = patch_info->data.method->token;
1497 g_assert (image_index < 256);
1498 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1500 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
1503 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1504 guint32 icall_index;
1506 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1508 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1509 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1510 GUINT_TO_POINTER (icall_index));
1511 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1513 encode_value (icall_index - 1, p, &p);
1516 case MONO_PATCH_INFO_LDSTR: {
1517 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
1518 guint32 token = patch_info->data.token->token;
1519 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
1521 * An optimization would be to emit shared code for ldstr
1522 * statements followed by a throw.
1524 encode_value (image_index, p, &p);
1525 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
1528 case MONO_PATCH_INFO_DECLSEC:
1529 case MONO_PATCH_INFO_LDTOKEN:
1530 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1531 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
1532 encode_value (patch_info->data.token->token, p, &p);
1534 case MONO_PATCH_INFO_EXC_NAME: {
1535 MonoClass *ex_class;
1538 mono_class_from_name (mono_defaults.exception_class->image,
1539 "System", patch_info->data.target);
1540 g_assert (ex_class);
1541 encode_klass_info (acfg, ex_class, p, &p);
1544 case MONO_PATCH_INFO_R4:
1545 encode_value (*((guint32 *)patch_info->data.target), p, &p);
1547 case MONO_PATCH_INFO_R8:
1548 encode_value (*((guint32 *)patch_info->data.target), p, &p);
1549 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
1551 case MONO_PATCH_INFO_VTABLE:
1552 case MONO_PATCH_INFO_CLASS_INIT:
1553 case MONO_PATCH_INFO_CLASS:
1554 case MONO_PATCH_INFO_IID:
1555 encode_klass_info (acfg, patch_info->data.klass, p, &p);
1557 case MONO_PATCH_INFO_FIELD:
1558 case MONO_PATCH_INFO_SFLDA:
1559 encode_field_info (acfg, patch_info->data.field, p, &p);
1561 case MONO_PATCH_INFO_WRAPPER: {
1562 encode_value (patch_info->data.method->wrapper_type, p, &p);
1564 switch (patch_info->data.method->wrapper_type) {
1565 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1567 guint32 image_index;
1570 m = mono_marshal_method_from_wrapper (patch_info->data.method);
1571 image_index = get_image_index (acfg, m->klass->image);
1573 g_assert (image_index < 256);
1574 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1576 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
1579 case MONO_WRAPPER_PROXY_ISINST:
1580 case MONO_WRAPPER_LDFLD:
1581 case MONO_WRAPPER_STFLD:
1582 case MONO_WRAPPER_ISINST: {
1583 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1584 encode_klass_info (acfg, proxy_class, p, &p);
1587 case MONO_WRAPPER_STELEMREF:
1590 g_assert_not_reached ();
1595 g_warning ("unable to handle jump info %d", patch_info->type);
1596 g_assert_not_reached ();
1600 mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
1602 encode_value (debug_info_size, p, &p);
1603 if (debug_info_size) {
1604 memcpy (p, debug_info, debug_info_size);
1605 p += debug_info_size;
1606 g_free (debug_info);
1609 /* Emit method info */
1611 emit_section_change (tmpfp, ".text", 1);
1612 emit_label (tmpfp, mname_p);
1614 g_assert (p - buf < buf_size);
1615 for (i = 0; i < p - buf; ++i) {
1617 fprintf (tmpfp, "\n.byte ");
1618 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
1620 fprintf (tmpfp, "\n");
1628 str_begins_with (const char *str1, const char *str2)
1630 int len = strlen (str2);
1631 return strncmp (str1, str2, len) == 0;
1635 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1637 gchar **args, **ptr;
1639 memset (opts, 0, sizeof (*opts));
1641 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1642 for (ptr = args; ptr && *ptr; ptr ++) {
1643 const char *arg = *ptr;
1645 if (str_begins_with (arg, "outfile=")) {
1646 opts->outfile = g_strdup (arg + strlen ("outfile="));
1647 } else if (str_begins_with (arg, "save-temps")) {
1648 opts->save_temps = TRUE;
1649 } else if (str_begins_with (arg, "write-symbols")) {
1650 opts->write_symbols = TRUE;
1652 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1659 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1662 MonoImage *image = ass->image;
1664 char *com, *tmpfname, *opts_str;
1668 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1669 MonoAotCompile *acfg;
1671 char *outfile_name, *tmp_outfile_name;
1673 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1675 acfg = g_new0 (MonoAotCompile, 1);
1676 acfg->icall_hash = g_hash_table_new (NULL, NULL);
1677 acfg->icall_table = g_ptr_array_new ();
1678 acfg->image_hash = g_hash_table_new (NULL, NULL);
1679 acfg->image_table = g_ptr_array_new ();
1681 mono_aot_parse_options (aot_options, &acfg->aot_opts);
1683 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1684 tmpfp = fdopen (i, "w+");
1688 emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1690 emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1692 opts_str = g_strdup_printf ("%d", opts);
1693 emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1696 symbol = g_strdup_printf ("methods");
1697 emit_section_change (tmpfp, ".text", 0);
1698 emit_global (tmpfp, symbol, FALSE);
1699 emit_alignment (tmpfp, 8);
1700 emit_label (tmpfp, symbol);
1702 symbol = g_strdup_printf ("method_infos");
1703 emit_section_change (tmpfp, ".text", 1);
1704 emit_global (tmpfp, symbol, FALSE);
1705 emit_alignment (tmpfp, 8);
1706 emit_label (tmpfp, symbol);
1708 cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
1709 acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
1711 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1712 MonoJumpInfo *patch_info;
1714 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1715 method = mono_get_method (image, token, NULL);
1717 /* fixme: maybe we can also precompile wrapper methods */
1718 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1719 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1720 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1721 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1722 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1728 /* fixme: we need to patch the IP for the LMF in that case */
1729 if (method->save_lmf) {
1730 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1735 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1736 //mono_compile_method (method);
1739 * Since these methods are the only ones which are compiled with
1740 * AOT support, and they are not used by runtime startup/shutdown code,
1741 * the runtime will not see AOT methods during AOT compilation,so it
1742 * does not need to support them by creating a fake GOT etc.
1744 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, TRUE, 0);
1747 if (cfg->disable_aot) {
1748 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1754 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1755 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1756 /* unable to handle this */
1757 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1768 /* some wrappers are very common */
1769 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1770 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1771 switch (patch_info->data.method->wrapper_type) {
1772 case MONO_WRAPPER_PROXY_ISINST:
1773 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1777 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1778 switch (patch_info->data.method->wrapper_type) {
1779 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1780 case MONO_WRAPPER_STFLD:
1781 case MONO_WRAPPER_LDFLD:
1782 case MONO_WRAPPER_STELEMREF:
1783 case MONO_WRAPPER_ISINST:
1784 case MONO_WRAPPER_PROXY_ISINST:
1785 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1792 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1793 switch (patch_info->type) {
1794 case MONO_PATCH_INFO_METHOD:
1795 case MONO_PATCH_INFO_METHODCONST:
1796 if (patch_info->data.method->wrapper_type) {
1797 /* unable to handle this */
1798 //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));
1802 if (!patch_info->data.method->token)
1804 * The method is part of a constructed type like Int[,].Set (). It doesn't
1805 * have a token, and we can't make one, since the parent type is part of
1806 * assembly which contains the element type, and not the assembly which
1807 * referenced this type.
1811 case MONO_PATCH_INFO_VTABLE:
1812 case MONO_PATCH_INFO_CLASS_INIT:
1813 case MONO_PATCH_INFO_CLASS:
1814 case MONO_PATCH_INFO_IID:
1815 if (!patch_info->data.klass->type_token)
1816 if (!patch_info->data.klass->element_class->type_token)
1826 mono_destroy_compile (cfg);
1830 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1838 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1840 emit_method_code (acfg, cfgs [i]);
1843 /* Emit method info */
1844 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1846 emit_method_info (acfg, cfgs [i]);
1850 * The icall and image tables are small but referenced in a lot of places.
1851 * So we emit them at once, and reference their elements by an index.
1854 /* Emit icall table */
1856 symbol = g_strdup_printf ("mono_icall_table");
1857 emit_section_change (tmpfp, ".text", 1);
1858 emit_global(tmpfp, symbol, FALSE);
1859 emit_alignment(tmpfp, 8);
1860 emit_label(tmpfp, symbol);
1861 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1862 for (i = 0; i < acfg->icall_table->len; i++)
1863 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1865 /* Emit image table */
1867 symbol = g_strdup_printf ("mono_image_table");
1868 emit_section_change (tmpfp, ".text", 1);
1869 emit_global(tmpfp, symbol, FALSE);
1870 emit_alignment(tmpfp, 8);
1871 emit_label(tmpfp, symbol);
1872 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1873 for (i = 0; i < acfg->image_table->len; i++) {
1874 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1875 MonoAssemblyName *aname = &image->assembly->aname;
1877 /* FIXME: Support multi-module assemblies */
1878 g_assert (image->assembly->image == image);
1880 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1881 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1882 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1883 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1885 emit_alignment (tmpfp, 8);
1886 fprintf (tmpfp, ".long %d\n", aname->flags);
1887 fprintf (tmpfp, ".long %d\n", aname->major);
1888 fprintf (tmpfp, ".long %d\n", aname->minor);
1889 fprintf (tmpfp, ".long %d\n", aname->build);
1890 fprintf (tmpfp, ".long %d\n", aname->revision);
1893 #ifdef MONO_ARCH_HAVE_PIC_AOT
1896 /* Don't make GOT global so accesses to it don't need relocations */
1897 symbol = g_strdup_printf ("got");
1899 emit_section_change (tmpfp, ".bss", 1);
1901 emit_section_change (tmpfp, ".data", 1);
1903 emit_alignment (tmpfp, 8);
1904 emit_label(tmpfp, symbol);
1905 if (acfg->got_offset > 0)
1906 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1908 symbol = g_strdup_printf ("got_addr");
1909 emit_section_change (tmpfp, ".data", 1);
1910 emit_global (tmpfp, symbol, FALSE);
1911 emit_alignment (tmpfp, 8);
1912 emit_label(tmpfp, symbol);
1913 emit_pointer (tmpfp, "got");
1915 symbol = g_strdup_printf ("got_size");
1916 emit_section_change (tmpfp, ".data", 1);
1917 emit_global (tmpfp, symbol, FALSE);
1918 emit_alignment (tmpfp, 8);
1919 emit_label(tmpfp, symbol);
1920 fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1923 symbol = g_strdup_printf ("method_offsets");
1924 emit_section_change (tmpfp, ".text", 1);
1925 emit_global (tmpfp, symbol, FALSE);
1926 emit_alignment (tmpfp, 8);
1927 emit_label(tmpfp, symbol);
1929 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1931 if ((i % 32) == 0) {
1932 fprintf (tmpfp, "\n.long ");
1938 symbol = g_strdup_printf (".Lm_%x", i + 1);
1939 fprintf (tmpfp, "%s%s-methods", sep, symbol);
1942 fprintf (tmpfp, "%s0xffffffff", sep);
1944 fprintf (tmpfp, "\n");
1946 symbol = g_strdup_printf ("method_info_offsets");
1947 emit_section_change (tmpfp, ".text", 1);
1948 emit_global (tmpfp, symbol, FALSE);
1949 emit_alignment (tmpfp, 8);
1950 emit_label(tmpfp, symbol);
1952 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1954 if ((i % 32) == 0) {
1955 fprintf (tmpfp, "\n.long ");
1961 symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1962 fprintf (tmpfp, "%s%s - method_infos", sep, symbol);
1965 fprintf (tmpfp, "%s0", sep);
1967 fprintf (tmpfp, "\n");
1971 #if defined(__x86_64__)
1972 com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1973 #elif defined(sparc) && SIZEOF_VOID_P == 8
1974 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1976 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1978 printf ("Executing the native assembler: %s\n", com);
1979 if (system (com) != 0) {
1986 if (acfg->aot_opts.outfile)
1987 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
1989 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1991 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1994 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1995 #elif defined(__ppc__) && defined(__MACH__)
1996 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
1998 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
2000 printf ("Executing the native linker: %s\n", com);
2001 if (system (com) != 0) {
2002 g_free (tmp_outfile_name);
2003 g_free (outfile_name);
2009 com = g_strdup_printf ("%s.o", tmpfname);
2012 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
2013 printf ("Stripping the binary: %s\n", com);
2017 rename (tmp_outfile_name, outfile_name);
2019 g_free (tmp_outfile_name);
2020 g_free (outfile_name);
2022 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
2023 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
2024 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
2025 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
2026 printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
2027 if (acfg->aot_opts.save_temps)
2028 printf ("Retained input file.\n");
2039 mono_aot_init (void)
2044 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
2050 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2056 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)