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) + (minfo->info->num_clauses * sizeof (MonoJitExceptionInfo)));
578 memcpy (jinfo, minfo->info, sizeof (MonoJitInfo) + (minfo->info->num_clauses * sizeof (MonoJitExceptionInfo)));
583 if (aot_module->out_of_date)
586 if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
587 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
588 char *full_name = mono_method_full_name (method, TRUE);
589 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
595 code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
596 info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
598 if (mono_last_aot_method != -1) {
599 if (mono_jit_stats.methods_aot > mono_last_aot_method)
602 if (mono_jit_stats.methods_aot == mono_last_aot_method)
603 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
606 return mono_aot_load_method (domain, aot_module, method, code, info);
610 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info)
612 MonoClass *klass = method->klass;
613 MonoJumpInfo *patch_info = NULL;
614 guint code_len, used_int_regs, used_strings;
615 MonoAotMethod *minfo;
619 int i, pindex, got_index;
620 gboolean non_got_patches, keep_patches = TRUE;
621 gboolean has_clauses;
624 minfo = g_new0 (MonoAotMethod, 1);
626 minfo->domain = domain;
629 code_len = decode_value (p, &p);
630 used_int_regs = decode_value (p, &p);
632 if (!use_loaded_code) {
634 code2 = mono_code_manager_reserve (domain->code_mp, code_len);
635 memcpy (code2, code, code_len);
636 mono_arch_flush_icache (code2, code_len);
640 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
641 char *full_name = mono_method_full_name (method, TRUE);
642 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, 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 (MonoJitInfo) + (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 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
674 if (aot_module->opts & MONO_OPT_SHARED)
675 used_strings = decode_value (p, &p);
679 for (i = 0; i < used_strings; i++) {
680 guint token = decode_value (p, &p);
681 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
684 if (aot_module->opts & MONO_OPT_SHARED)
685 keep_patches = FALSE;
687 #ifdef MONO_ARCH_HAVE_PIC_AOT
688 got_index = decode_value (p, &p);
689 keep_patches = FALSE;
696 guint32 last_offset, buf_len;
701 mp = mono_mempool_new ();
703 /* First load the type + offset table */
705 patches = g_ptr_array_new ();
707 MonoJumpInfo *ji = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
709 #if defined(MONO_ARCH_HAVE_PIC_AOT)
716 b2 = *((guint8*)p + 1);
721 if (((b1 & (1 + 2)) == 3) && (b2 == 255))
722 ji->ip.i = decode_value (p, &p);
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);
737 /* Null terminated array */
740 /* Then load the other data */
741 for (pindex = 0; pindex < patches->len; ++pindex) {
742 MonoJumpInfo *ji = g_ptr_array_index (patches, pindex);
745 case MONO_PATCH_INFO_CLASS:
746 case MONO_PATCH_INFO_IID:
747 case MONO_PATCH_INFO_VTABLE:
748 case MONO_PATCH_INFO_CLASS_INIT:
749 ji->data.klass = decode_klass_info (aot_module, p, &p);
753 case MONO_PATCH_INFO_IMAGE:
754 ji->data.image = load_image (aot_module, decode_value (p, &p));
758 case MONO_PATCH_INFO_METHOD:
759 case MONO_PATCH_INFO_METHODCONST:
760 case MONO_PATCH_INFO_METHOD_JUMP: {
761 guint32 image_index, token, value;
763 value = decode_value (p, &p);
764 image_index = value >> 24;
765 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
767 image = load_image (aot_module, image_index);
770 ji->data.method = mono_get_method (image, token, NULL);
771 g_assert (ji->data.method);
772 mono_class_init (ji->data.method->klass);
776 case MONO_PATCH_INFO_WRAPPER: {
777 guint32 wrapper_type;
779 wrapper_type = decode_value (p, &p);
781 switch (wrapper_type) {
782 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
783 guint32 image_index, token, value;
785 value = decode_value (p, &p);
786 image_index = value >> 24;
787 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
789 image = load_image (aot_module, image_index);
792 ji->data.method = mono_get_method (image, token, NULL);
793 g_assert (ji->data.method);
794 mono_class_init (ji->data.method->klass);
796 ji->type = MONO_PATCH_INFO_METHOD;
797 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
800 case MONO_WRAPPER_PROXY_ISINST: {
801 MonoClass *klass = decode_klass_info (aot_module, p, &p);
804 ji->type = MONO_PATCH_INFO_METHOD;
805 ji->data.method = mono_marshal_get_proxy_cancast (klass);
808 case MONO_WRAPPER_LDFLD:
809 case MONO_WRAPPER_STFLD:
810 case MONO_WRAPPER_ISINST: {
811 MonoClass *klass = decode_klass_info (aot_module, p, &p);
814 ji->type = MONO_PATCH_INFO_METHOD;
815 if (wrapper_type == MONO_WRAPPER_LDFLD)
816 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
817 else if (wrapper_type == MONO_WRAPPER_STFLD)
818 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
820 ji->data.method = mono_marshal_get_isinst (klass);
823 case MONO_WRAPPER_STELEMREF:
824 ji->type = MONO_PATCH_INFO_METHOD;
825 ji->data.method = mono_marshal_get_stelemref ();
828 g_assert_not_reached ();
832 case MONO_PATCH_INFO_FIELD:
833 case MONO_PATCH_INFO_SFLDA:
834 ji->data.field = decode_field_info (aot_module, p, &p);
838 case MONO_PATCH_INFO_INTERNAL_METHOD:
839 ji->data.name = aot_module->icall_table [decode_value (p, &p)];
840 g_assert (ji->data.name);
841 //printf ("A: %s.\n", ji->data.name);
843 case MONO_PATCH_INFO_SWITCH:
844 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
845 ji->data.table->table_size = decode_value (p, &p);
846 table = g_new (gpointer, ji->data.table->table_size);
847 ji->data.table->table = (MonoBasicBlock**)table;
848 for (i = 0; i < ji->data.table->table_size; i++)
849 table [i] = (gpointer)(gssize)decode_value (p, &p);
851 case MONO_PATCH_INFO_R4:
852 ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
855 val = decode_value (p, &p);
856 *(float*)ji->data.target = *(float*)&val;
858 case MONO_PATCH_INFO_R8: {
859 ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
862 val [0] = decode_value (p, &p);
863 val [1] = decode_value (p, &p);
864 *(double*)ji->data.target = *(double*)val;
867 case MONO_PATCH_INFO_LDSTR:
868 image = load_image (aot_module, decode_value (p, &p));
871 ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
873 case MONO_PATCH_INFO_DECLSEC:
874 case MONO_PATCH_INFO_LDTOKEN:
875 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
876 image = load_image (aot_module, decode_value (p, &p));
879 ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
881 case MONO_PATCH_INFO_EXC_NAME:
882 ji->data.klass = decode_klass_info (aot_module, p, &p);
885 ji->data.name = ji->data.klass->name;
887 case MONO_PATCH_INFO_METHOD_REL:
888 ji->data.offset = decode_value (p, &p);
891 g_warning ("unhandled type %d", ji->type);
892 g_assert_not_reached ();
896 buf_len = decode_value (p, &p);
897 mono_debug_add_aot_method (domain, method, code, p, 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);
938 mono_mempool_destroy (mp);
941 mono_jit_stats.methods_aot++;
944 jinfo->code_size = code_len;
945 jinfo->used_regs = used_int_regs;
946 jinfo->method = method;
947 jinfo->code_start = code;
948 #ifdef MONO_ARCH_HAVE_PIC_AOT
949 jinfo->domain_neutral = 0;
951 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
955 g_hash_table_insert (aot_module->methods, method, minfo);
961 g_ptr_array_free (patches, TRUE);
963 /* FIXME: The space in domain->mp is wasted */
964 if (aot_module->opts & MONO_OPT_SHARED)
965 /* No need to cache patches */
966 mono_mempool_destroy (mp);
972 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
976 EnterCriticalSection (&aot_mutex);
977 info = mono_aot_get_method_inner (domain, method);
978 LeaveCriticalSection (&aot_mutex);
980 /* Do this outside the lock */
982 mono_jit_info_table_add (domain, info);
990 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
994 MonoAotModule *aot_module;
996 ji = mono_jit_info_table_find (mono_domain_get (), code);
1000 ass = ji->method->klass->image->assembly;
1004 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1005 if (!aot_module || !aot_module->got)
1008 return ((addr >= (guint8*)(aot_module->got)) && (addr < (guint8*)(aot_module->got + aot_module->got_size)));
1011 /*****************************************************/
1013 /*****************************************************/
1016 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1019 /* For solaris as, GNU as should accept the same */
1020 fprintf (fp, ".section \"%s\"\n", section_name);
1021 #elif defined(__ppc__) && defined(__MACH__)
1022 /* This needs to be made more precise on mach. */
1023 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1025 fprintf (fp, "%s %d\n", section_name, subsection_index);
1030 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1040 fprintf (fp, "\t.type %s,#%s\n", name, stype);
1041 #elif !(defined(__ppc__) && defined(__MACH__))
1042 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1043 #elif defined(__x86_64__) || defined(__i386__)
1044 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1049 emit_global (FILE *fp, const char *name, gboolean func)
1051 #if defined(__ppc__) && defined(__MACH__)
1052 // mach-o always uses a '_' prefix.
1053 fprintf (fp, "\t.globl _%s\n", name);
1055 fprintf (fp, "\t.globl %s\n", name);
1058 emit_symbol_type (fp, name, func);
1062 emit_label (FILE *fp, const char *name)
1064 #if defined(__ppc__) && defined(__MACH__)
1065 // mach-o always uses a '_' prefix.
1066 fprintf (fp, "_%s:\n", name);
1068 fprintf (fp, "%s:\n", name);
1073 emit_string_symbol (FILE *fp, const char *name, const char *value)
1075 emit_section_change (fp, ".text", 1);
1076 emit_global(fp, name, FALSE);
1077 emit_label(fp, name);
1078 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1081 #if defined(__ppc__) && defined(__MACH__)
1083 ilog2(register int value)
1086 while (value & ~0xf) count += 4, value >>= 4;
1087 while (value) count++, value >>= 1;
1093 emit_alignment(FILE *fp, int size)
1095 #if defined(__ppc__) && defined(__MACH__)
1096 // the mach-o assembler specifies alignments as powers of 2.
1097 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1098 #elif defined(__powerpc__)
1099 /* ignore on linux/ppc */
1101 fprintf (fp, "\t.align %d\n", size);
1105 G_GNUC_UNUSED static void
1106 emit_pointer (FILE *fp, const char *target)
1108 emit_alignment (fp, sizeof (gpointer));
1109 #if defined(__x86_64__)
1110 fprintf (fp, "\t.quad %s\n", target);
1111 #elif defined(sparc) && SIZEOF_VOID_P == 8
1112 fprintf (fp, "\t.xword %s\n", target);
1114 fprintf (fp, "\t.long %s\n", target);
1119 mono_get_field_token (MonoClassField *field)
1121 MonoClass *klass = field->parent;
1124 for (i = 0; i < klass->field.count; ++i) {
1125 if (field == &klass->fields [i])
1126 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1129 g_assert_not_reached ();
1134 encode_value (gint32 value, char *buf, char **endbuf)
1138 //printf ("ENCODE: %d 0x%x.\n", value, value);
1141 * Same encoding as the one used in the metadata, extended to handle values
1142 * greater than 0x1fffffff.
1144 if ((value >= 0) && (value <= 127))
1146 else if ((value >= 0) && (value <= 16383)) {
1147 p [0] = 0x80 | (value >> 8);
1148 p [1] = value & 0xff;
1150 } else if ((value >= 0) && (value <= 0x1fffffff)) {
1151 p [0] = (value >> 24) | 0xc0;
1152 p [1] = (value >> 16) & 0xff;
1153 p [2] = (value >> 8) & 0xff;
1154 p [3] = value & 0xff;
1159 p [1] = (value >> 24) & 0xff;
1160 p [2] = (value >> 16) & 0xff;
1161 p [3] = (value >> 8) & 0xff;
1162 p [4] = value & 0xff;
1170 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1174 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1178 index = g_hash_table_size (cfg->image_hash);
1179 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1180 g_ptr_array_add (cfg->image_table, image);
1186 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, char *buf, char **endbuf)
1188 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1189 if (!klass->type_token) {
1191 g_assert (klass->rank > 0);
1192 g_assert (klass->element_class->type_token);
1193 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1194 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1195 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1196 encode_value (klass->rank, buf, &buf);
1199 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1200 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1206 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, char *buf, char **endbuf)
1208 guint32 token = mono_get_field_token (field);
1210 encode_klass_info (cfg, field->parent, buf, &buf);
1211 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1212 encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1217 compare_patches (gconstpointer a, gconstpointer b)
1221 i = (*(MonoJumpInfo**)a)->ip.i;
1222 j = (*(MonoJumpInfo**)b)->ip.i;
1234 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1238 int i, j, pindex, byte_index;
1239 guint8 *code, *mname, *mname_p;
1240 int func_alignment = 16;
1242 MonoJumpInfo *patch_info;
1243 MonoMethodHeader *header;
1244 #ifdef MONO_ARCH_HAVE_PIC_AOT
1249 method = cfg->method;
1250 code = cfg->native_code;
1251 header = mono_method_get_header (method);
1253 emit_section_change (tmpfp, ".text", 0);
1255 /* Make the labels local */
1256 mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1257 mname_p = g_strdup_printf ("%s_p", mname);
1259 emit_alignment(tmpfp, func_alignment);
1260 emit_label(tmpfp, mname);
1261 if (acfg->aot_opts.write_symbols)
1262 emit_global (tmpfp, mname, TRUE);
1264 if (cfg->verbose_level > 0)
1265 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), mname);
1267 /* Sort relocations */
1268 patches = g_ptr_array_new ();
1269 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1270 g_ptr_array_add (patches, patch_info);
1271 g_ptr_array_sort (patches, compare_patches);
1273 #ifdef MONO_ARCH_HAVE_PIC_AOT
1274 acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1276 for (i = 0; i < cfg->code_len; i++) {
1278 for (pindex = 0; pindex < patches->len; ++pindex) {
1279 patch_info = g_ptr_array_index (patches, pindex);
1280 if (patch_info->ip.i == i)
1285 if (patch_info && (pindex < patches->len)) {
1286 switch (patch_info->type) {
1287 case MONO_PATCH_INFO_LABEL:
1288 case MONO_PATCH_INFO_BB:
1289 case MONO_PATCH_INFO_NONE:
1291 case MONO_PATCH_INFO_GOT_OFFSET: {
1292 guint32 offset = mono_arch_get_patch_offset (code + i);
1293 fprintf (tmpfp, "\n.byte ");
1294 for (j = 0; j < offset; ++j)
1295 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1296 fprintf (tmpfp, "\n.int got - . + %d", offset);
1298 i += offset + 4 - 1;
1303 if (!is_got_patch (patch_info->type))
1306 fprintf (tmpfp, "\n.byte ");
1307 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1308 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1310 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((acfg->got_offset * sizeof (gpointer)) - 4));
1311 #elif defined(__i386__)
1312 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((acfg->got_offset * sizeof (gpointer))));
1314 acfg->got_offset ++;
1316 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1322 if (byte_index == 0)
1323 fprintf (tmpfp, "\n.byte ");
1324 fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
1325 byte_index = (byte_index + 1) % 32;
1331 for (i = 0; i < cfg->code_len; i++) {
1332 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1335 fprintf (tmpfp, "\n");
1339 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
1344 int i, j, k, pindex, buf_size;
1345 guint32 debug_info_size;
1346 guint8 *code, *mname, *mname_p;
1348 MonoJumpInfo *patch_info;
1349 MonoMethodHeader *header;
1350 guint32 last_offset;
1353 #ifdef MONO_ARCH_HAVE_PIC_AOT
1354 guint32 first_got_offset;
1358 method = cfg->method;
1359 code = cfg->native_code;
1360 header = mono_method_get_header (method);
1362 /* Make the labels local */
1363 mname = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1364 mname_p = g_strdup_printf ("%s_p", mname);
1366 /* Sort relocations */
1367 patches = g_ptr_array_new ();
1368 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1369 g_ptr_array_add (patches, patch_info);
1370 g_ptr_array_sort (patches, compare_patches);
1372 #ifdef MONO_ARCH_HAVE_PIC_AOT
1373 first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
1376 /**********************/
1377 /* Encode method info */
1378 /**********************/
1380 buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
1381 p = buf = g_malloc (buf_size);
1383 encode_value (cfg->code_len, p, &p);
1384 encode_value (cfg->used_int_regs, p, &p);
1386 /* Exception table */
1387 encode_value (header->num_clauses ? 1 : 0, p, &p);
1388 if (header->num_clauses) {
1389 MonoJitInfo *jinfo = cfg->jit_info;
1391 for (k = 0; k < header->num_clauses; ++k) {
1392 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
1394 encode_value (ei->exvar_offset, p, &p);
1396 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
1397 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
1399 encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
1400 encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
1401 encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
1406 if (cfg->opt & MONO_OPT_SHARED) {
1407 encode_value (g_list_length (cfg->ldstr_list), p, &p);
1408 for (l = cfg->ldstr_list; l; l = l->next) {
1409 encode_value ((long)l->data, p, &p);
1413 /* Used only in shared mode */
1414 g_assert (!cfg->ldstr_list);
1416 #ifdef MONO_ARCH_HAVE_PIC_AOT
1417 encode_value (first_got_offset, p, &p);
1420 /* First emit the type+position table */
1423 for (pindex = 0; pindex < patches->len; ++pindex) {
1425 patch_info = g_ptr_array_index (patches, pindex);
1427 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1428 (patch_info->type == MONO_PATCH_INFO_BB) ||
1429 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1430 (patch_info->type == MONO_PATCH_INFO_NONE))
1435 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1436 offset = patch_info->ip.i - last_offset;
1437 last_offset = patch_info->ip.i;
1439 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1440 /* Only the type is needed */
1441 *p = patch_info->type;
1444 /* Encode type+position compactly */
1445 g_assert (patch_info->type < 64);
1446 if (offset < 1024 - 1) {
1447 *p = (patch_info->type << 2) + (offset >> 8);
1449 *p = offset & ((1 << 8) - 1);
1453 *p = (patch_info->type << 2) + 3;
1457 encode_value (offset, p, &p);
1463 * 0 is PATCH_INFO_BB, which can't be in the file.
1465 /* NULL terminated array */
1469 /* Then emit the other info */
1470 for (pindex = 0; pindex < patches->len; ++pindex) {
1471 patch_info = g_ptr_array_index (patches, pindex);
1473 switch (patch_info->type) {
1474 case MONO_PATCH_INFO_LABEL:
1475 case MONO_PATCH_INFO_BB:
1476 case MONO_PATCH_INFO_GOT_OFFSET:
1477 case MONO_PATCH_INFO_NONE:
1479 case MONO_PATCH_INFO_IMAGE:
1480 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
1482 case MONO_PATCH_INFO_METHOD_REL:
1483 encode_value ((gint)patch_info->data.offset, p, &p);
1485 case MONO_PATCH_INFO_SWITCH: {
1486 gpointer *table = (gpointer *)patch_info->data.table->table;
1489 encode_value (patch_info->data.table->table_size, p, &p);
1490 for (k = 0; k < patch_info->data.table->table_size; k++)
1491 encode_value ((int)(gssize)table [k], p, &p);
1494 case MONO_PATCH_INFO_METHODCONST:
1495 case MONO_PATCH_INFO_METHOD:
1496 case MONO_PATCH_INFO_METHOD_JUMP: {
1497 guint32 image_index = get_image_index (acfg, patch_info->data.method->klass->image);
1498 guint32 token = patch_info->data.method->token;
1499 g_assert (image_index < 256);
1500 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1502 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
1505 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1506 guint32 icall_index;
1508 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1510 icall_index = g_hash_table_size (acfg->icall_hash) + 1;
1511 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1512 GUINT_TO_POINTER (icall_index));
1513 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1515 encode_value (icall_index - 1, p, &p);
1518 case MONO_PATCH_INFO_LDSTR: {
1519 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
1520 guint32 token = patch_info->data.token->token;
1521 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
1523 * An optimization would be to emit shared code for ldstr
1524 * statements followed by a throw.
1526 encode_value (image_index, p, &p);
1527 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
1530 case MONO_PATCH_INFO_DECLSEC:
1531 case MONO_PATCH_INFO_LDTOKEN:
1532 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1533 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
1534 encode_value (patch_info->data.token->token, p, &p);
1536 case MONO_PATCH_INFO_EXC_NAME: {
1537 MonoClass *ex_class;
1540 mono_class_from_name (mono_defaults.exception_class->image,
1541 "System", patch_info->data.target);
1542 g_assert (ex_class);
1543 encode_klass_info (acfg, ex_class, p, &p);
1546 case MONO_PATCH_INFO_R4:
1547 encode_value (*((guint32 *)patch_info->data.target), p, &p);
1549 case MONO_PATCH_INFO_R8:
1550 encode_value (*((guint32 *)patch_info->data.target), p, &p);
1551 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
1553 case MONO_PATCH_INFO_VTABLE:
1554 case MONO_PATCH_INFO_CLASS_INIT:
1555 case MONO_PATCH_INFO_CLASS:
1556 case MONO_PATCH_INFO_IID:
1557 encode_klass_info (acfg, patch_info->data.klass, p, &p);
1559 case MONO_PATCH_INFO_FIELD:
1560 case MONO_PATCH_INFO_SFLDA:
1561 encode_field_info (acfg, patch_info->data.field, p, &p);
1563 case MONO_PATCH_INFO_WRAPPER: {
1564 encode_value (patch_info->data.method->wrapper_type, p, &p);
1566 switch (patch_info->data.method->wrapper_type) {
1567 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1569 guint32 image_index;
1572 m = mono_marshal_method_from_wrapper (patch_info->data.method);
1573 image_index = get_image_index (acfg, m->klass->image);
1575 g_assert (image_index < 256);
1576 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1578 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
1581 case MONO_WRAPPER_PROXY_ISINST:
1582 case MONO_WRAPPER_LDFLD:
1583 case MONO_WRAPPER_STFLD:
1584 case MONO_WRAPPER_ISINST: {
1585 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
1586 encode_klass_info (acfg, proxy_class, p, &p);
1589 case MONO_WRAPPER_STELEMREF:
1592 g_assert_not_reached ();
1597 g_warning ("unable to handle jump info %d", patch_info->type);
1598 g_assert_not_reached ();
1602 mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
1604 encode_value (debug_info_size, p, &p);
1605 if (debug_info_size) {
1606 memcpy (p, debug_info, debug_info_size);
1607 p += debug_info_size;
1608 g_free (debug_info);
1611 /* Emit method info */
1613 emit_section_change (tmpfp, ".text", 1);
1614 emit_label (tmpfp, mname_p);
1616 g_assert (p - buf < buf_size);
1617 for (i = 0; i < p - buf; ++i) {
1619 fprintf (tmpfp, "\n.byte ");
1620 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
1622 fprintf (tmpfp, "\n");
1630 str_begins_with (const char *str1, const char *str2)
1632 int len = strlen (str2);
1633 return strncmp (str1, str2, len) == 0;
1637 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
1639 gchar **args, **ptr;
1641 memset (opts, 0, sizeof (*opts));
1643 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
1644 for (ptr = args; ptr && *ptr; ptr ++) {
1645 const char *arg = *ptr;
1647 if (str_begins_with (arg, "outfile=")) {
1648 opts->outfile = g_strdup (arg + strlen ("outfile="));
1649 } else if (str_begins_with (arg, "save-temps")) {
1650 opts->save_temps = TRUE;
1651 } else if (str_begins_with (arg, "write-symbols")) {
1652 opts->write_symbols = TRUE;
1654 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
1661 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
1664 MonoImage *image = ass->image;
1666 char *com, *tmpfname, *opts_str;
1670 int ccount = 0, mcount = 0, lmfcount = 0, abscount = 0, wrappercount = 0, ocount = 0;
1671 MonoAotCompile *acfg;
1673 char *outfile_name, *tmp_outfile_name;
1675 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
1677 acfg = g_new0 (MonoAotCompile, 1);
1678 acfg->icall_hash = g_hash_table_new (NULL, NULL);
1679 acfg->icall_table = g_ptr_array_new ();
1680 acfg->image_hash = g_hash_table_new (NULL, NULL);
1681 acfg->image_table = g_ptr_array_new ();
1683 mono_aot_parse_options (aot_options, &acfg->aot_opts);
1685 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
1686 tmpfp = fdopen (i, "w+");
1690 emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
1692 emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
1694 opts_str = g_strdup_printf ("%d", opts);
1695 emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
1698 symbol = g_strdup_printf ("methods");
1699 emit_section_change (tmpfp, ".text", 0);
1700 emit_global (tmpfp, symbol, FALSE);
1701 emit_alignment (tmpfp, 8);
1702 emit_label (tmpfp, symbol);
1704 symbol = g_strdup_printf ("method_infos");
1705 emit_section_change (tmpfp, ".text", 1);
1706 emit_global (tmpfp, symbol, FALSE);
1707 emit_alignment (tmpfp, 8);
1708 emit_label (tmpfp, symbol);
1710 cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
1711 acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
1713 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1714 MonoJumpInfo *patch_info;
1716 guint32 token = MONO_TOKEN_METHOD_DEF | (i + 1);
1717 method = mono_get_method (image, token, NULL);
1719 /* fixme: maybe we can also precompile wrapper methods */
1720 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1721 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1722 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1723 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
1724 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
1730 /* fixme: we need to patch the IP for the LMF in that case */
1731 if (method->save_lmf) {
1732 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
1737 //printf ("START: %s\n", mono_method_full_name (method, TRUE));
1738 //mono_compile_method (method);
1741 * Since these methods are the only ones which are compiled with
1742 * AOT support, and they are not used by runtime startup/shutdown code,
1743 * the runtime will not see AOT methods during AOT compilation,so it
1744 * does not need to support them by creating a fake GOT etc.
1746 cfg = mini_method_compile (method, opts, mono_get_root_domain (), FALSE, TRUE, 0);
1749 if (cfg->disable_aot) {
1750 printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
1756 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1757 if (patch_info->type == MONO_PATCH_INFO_ABS) {
1758 /* unable to handle this */
1759 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
1770 /* some wrappers are very common */
1771 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1772 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
1773 switch (patch_info->data.method->wrapper_type) {
1774 case MONO_WRAPPER_PROXY_ISINST:
1775 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1779 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
1780 switch (patch_info->data.method->wrapper_type) {
1781 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
1782 case MONO_WRAPPER_STFLD:
1783 case MONO_WRAPPER_LDFLD:
1784 case MONO_WRAPPER_STELEMREF:
1785 case MONO_WRAPPER_ISINST:
1786 case MONO_WRAPPER_PROXY_ISINST:
1787 patch_info->type = MONO_PATCH_INFO_WRAPPER;
1794 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1795 switch (patch_info->type) {
1796 case MONO_PATCH_INFO_METHOD:
1797 case MONO_PATCH_INFO_METHODCONST:
1798 if (patch_info->data.method->wrapper_type) {
1799 /* unable to handle this */
1800 //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));
1804 if (!patch_info->data.method->token)
1806 * The method is part of a constructed type like Int[,].Set (). It doesn't
1807 * have a token, and we can't make one, since the parent type is part of
1808 * assembly which contains the element type, and not the assembly which
1809 * referenced this type.
1813 case MONO_PATCH_INFO_VTABLE:
1814 case MONO_PATCH_INFO_CLASS_INIT:
1815 case MONO_PATCH_INFO_CLASS:
1816 case MONO_PATCH_INFO_IID:
1817 if (!patch_info->data.klass->type_token)
1818 if (!patch_info->data.klass->element_class->type_token)
1828 mono_destroy_compile (cfg);
1832 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
1840 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1842 emit_method_code (acfg, cfgs [i]);
1845 /* Emit method info */
1846 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1848 emit_method_info (acfg, cfgs [i]);
1852 * The icall and image tables are small but referenced in a lot of places.
1853 * So we emit them at once, and reference their elements by an index.
1856 /* Emit icall table */
1858 symbol = g_strdup_printf ("mono_icall_table");
1859 emit_section_change (tmpfp, ".text", 1);
1860 emit_global(tmpfp, symbol, FALSE);
1861 emit_alignment(tmpfp, 8);
1862 emit_label(tmpfp, symbol);
1863 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
1864 for (i = 0; i < acfg->icall_table->len; i++)
1865 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
1867 /* Emit image table */
1869 symbol = g_strdup_printf ("mono_image_table");
1870 emit_section_change (tmpfp, ".text", 1);
1871 emit_global(tmpfp, symbol, FALSE);
1872 emit_alignment(tmpfp, 8);
1873 emit_label(tmpfp, symbol);
1874 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
1875 for (i = 0; i < acfg->image_table->len; i++) {
1876 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
1877 MonoAssemblyName *aname = &image->assembly->aname;
1879 /* FIXME: Support multi-module assemblies */
1880 g_assert (image->assembly->image == image);
1882 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
1883 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
1884 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
1885 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
1887 emit_alignment (tmpfp, 8);
1888 fprintf (tmpfp, ".long %d\n", aname->flags);
1889 fprintf (tmpfp, ".long %d\n", aname->major);
1890 fprintf (tmpfp, ".long %d\n", aname->minor);
1891 fprintf (tmpfp, ".long %d\n", aname->build);
1892 fprintf (tmpfp, ".long %d\n", aname->revision);
1895 #ifdef MONO_ARCH_HAVE_PIC_AOT
1898 /* Don't make GOT global so accesses to it don't need relocations */
1899 symbol = g_strdup_printf ("got");
1901 emit_section_change (tmpfp, ".bss", 1);
1903 emit_section_change (tmpfp, ".data", 1);
1905 emit_alignment (tmpfp, 8);
1906 emit_label(tmpfp, symbol);
1907 if (acfg->got_offset > 0)
1908 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1910 symbol = g_strdup_printf ("got_addr");
1911 emit_section_change (tmpfp, ".data", 1);
1912 emit_global (tmpfp, symbol, FALSE);
1913 emit_alignment (tmpfp, 8);
1914 emit_label(tmpfp, symbol);
1915 emit_pointer (tmpfp, "got");
1917 symbol = g_strdup_printf ("got_size");
1918 emit_section_change (tmpfp, ".data", 1);
1919 emit_global (tmpfp, symbol, FALSE);
1920 emit_alignment (tmpfp, 8);
1921 emit_label(tmpfp, symbol);
1922 fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
1925 symbol = g_strdup_printf ("method_offsets");
1926 emit_section_change (tmpfp, ".text", 1);
1927 emit_global (tmpfp, symbol, FALSE);
1928 emit_alignment (tmpfp, 8);
1929 emit_label(tmpfp, symbol);
1931 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1933 if ((i % 32) == 0) {
1934 fprintf (tmpfp, "\n.long ");
1940 symbol = g_strdup_printf (".Lm_%x", i + 1);
1941 fprintf (tmpfp, "%s%s-methods", sep, symbol);
1944 fprintf (tmpfp, "%s0xffffffff", sep);
1946 fprintf (tmpfp, "\n");
1948 symbol = g_strdup_printf ("method_info_offsets");
1949 emit_section_change (tmpfp, ".text", 1);
1950 emit_global (tmpfp, symbol, FALSE);
1951 emit_alignment (tmpfp, 8);
1952 emit_label(tmpfp, symbol);
1954 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
1956 if ((i % 32) == 0) {
1957 fprintf (tmpfp, "\n.long ");
1963 symbol = g_strdup_printf (".Lm_%x_p", i + 1);
1964 fprintf (tmpfp, "%s%s - method_infos", sep, symbol);
1967 fprintf (tmpfp, "%s0", sep);
1969 fprintf (tmpfp, "\n");
1973 #if defined(__x86_64__)
1974 com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
1975 #elif defined(sparc) && SIZEOF_VOID_P == 8
1976 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
1978 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
1980 printf ("Executing the native assembler: %s\n", com);
1981 if (system (com) != 0) {
1988 if (acfg->aot_opts.outfile)
1989 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
1991 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
1993 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
1996 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
1997 #elif defined(__ppc__) && defined(__MACH__)
1998 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
2000 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
2002 printf ("Executing the native linker: %s\n", com);
2003 if (system (com) != 0) {
2004 g_free (tmp_outfile_name);
2005 g_free (outfile_name);
2011 com = g_strdup_printf ("%s.o", tmpfname);
2014 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
2015 printf ("Stripping the binary: %s\n", com);
2019 rename (tmp_outfile_name, outfile_name);
2021 g_free (tmp_outfile_name);
2022 g_free (outfile_name);
2024 printf ("Compiled %d out of %d methods (%d%%)\n", ccount, mcount, mcount ? (ccount*100)/mcount : 100);
2025 printf ("%d methods contain absolute addresses (%d%%)\n", abscount, mcount ? (abscount*100)/mcount : 100);
2026 printf ("%d methods contain wrapper references (%d%%)\n", wrappercount, mcount ? (wrappercount*100)/mcount : 100);
2027 printf ("%d methods contain lmf pointers (%d%%)\n", lmfcount, mcount ? (lmfcount*100)/mcount : 100);
2028 printf ("%d methods have other problems (%d%%)\n", ocount, mcount ? (ocount*100)/mcount : 100);
2029 if (acfg->aot_opts.save_temps)
2030 printf ("Retained input file.\n");
2041 mono_aot_init (void)
2046 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
2052 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2058 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)