2 * aot.c: mono Ahead of Time compiler
5 * Dietmar Maurer (dietmar@ximian.com)
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2002 Ximian, Inc.
12 #include <sys/types.h>
16 #ifndef PLATFORM_WIN32
25 #include <limits.h> /* for PAGESIZE */
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/tokentype.h>
34 #include <mono/metadata/appdomain.h>
35 #include <mono/metadata/debug-helpers.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/metadata-internals.h>
38 #include <mono/metadata/marshal.h>
39 #include <mono/utils/mono-logger.h>
40 #include "mono/utils/mono-compiler.h"
47 #define SHARED_EXT ".dll"
48 #elif defined(__ppc__) && defined(__MACH__)
49 #define SHARED_EXT ".dylib"
51 #define SHARED_EXT ".so"
54 #if defined(sparc) || defined(__ppc__)
55 #define AS_STRING_DIRECTIVE ".asciz"
58 #define AS_STRING_DIRECTIVE ".string"
61 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
63 typedef struct MonoAotModule {
65 /* Optimization flags used to compile the module */
67 /* Pointer to the Global Offset Table */
71 MonoAssemblyName *image_names;
73 MonoImage **image_table;
77 guint32 *code_offsets;
79 guint32 *method_info_offsets;
81 guint32 *ex_info_offsets;
83 guint32 *class_info_offsets;
84 guint32 *methods_loaded;
87 typedef struct MonoAotOptions {
90 gboolean write_symbols;
93 typedef struct MonoAotCompile {
97 GHashTable *icall_hash;
98 GHashTable *icall_to_got_offset_hash;
99 GPtrArray *icall_table;
100 GHashTable *image_hash;
101 GPtrArray *image_table;
103 guint32 *method_got_offsets;
104 MonoAotOptions aot_opts;
107 int ccount, mcount, lmfcount, abscount, wrappercount, ocount;
110 static GHashTable *aot_modules;
112 static CRITICAL_SECTION aot_mutex;
115 * Disabling this will make a copy of the loaded code and use the copy instead
116 * of the original. This will place the caller and the callee close to each
117 * other in memory, possibly improving cache behavior. Since the original
118 * code is in copy-on-write memory, this will not increase the memory usage
121 #ifdef MONO_ARCH_HAVE_PIC_AOT
122 static gboolean use_loaded_code = TRUE;
124 static gboolean use_loaded_code = FALSE;
128 * Whenever to AOT compile loaded assemblies on demand and store them in
129 * a cache under $HOME/.mono/aot-cache.
131 static gboolean use_aot_cache = FALSE;
134 static gint32 mono_last_aot_method = -1;
137 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8 *ex_info);
140 is_got_patch (MonoJumpInfoType patch_type)
144 #elif defined(__i386__)
151 /*****************************************************/
153 /*****************************************************/
156 load_image (MonoAotModule *module, int index)
158 MonoAssembly *assembly;
159 MonoImageOpenStatus status;
161 if (module->image_table [index])
162 return module->image_table [index];
163 if (module->out_of_date)
166 assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
168 module->out_of_date = TRUE;
172 if (strcmp (assembly->image->guid, module->image_guids [index])) {
173 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);
174 module->out_of_date = TRUE;
178 module->image_table [index] = assembly->image;
179 return assembly->image;
184 decode_value (guint8 *ptr, guint8 **rptr)
189 if ((b & 0x80) == 0){
192 } else if ((b & 0x40) == 0){
193 len = ((b & 0x3f) << 8 | ptr [1]);
195 } else if (b != 0xff) {
196 len = ((b & 0x1f) << 24) |
203 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
209 //printf ("DECODE: %d.\n", len);
214 decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
218 guint32 token, rank, image_index;
220 image_index = decode_value (buf, &buf);
221 image = load_image (module, image_index);
224 token = decode_value (buf, &buf);
225 if (mono_metadata_token_code (token) == 0) {
226 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
228 token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
229 rank = decode_value (buf, &buf);
230 klass = mono_class_get (image, token);
232 klass = mono_array_class_get (klass, rank);
235 mono_class_init (klass);
241 static MonoClassField*
242 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
244 MonoClass *klass = decode_klass_info (module, buf, &buf);
250 token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf);
254 return mono_class_get_field (klass, token);
257 static inline MonoImage*
258 decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **endbuf)
260 guint32 image_index, value;
263 value = decode_value (buf, &buf);
265 image_index = value >> 24;
266 *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
268 image = load_image (module, image_index);
277 make_writable (guint8* addr, guint32 len)
279 #ifndef PLATFORM_WIN32
283 page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
284 pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
285 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
290 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
296 create_cache_structure (void)
302 home = g_get_home_dir ();
306 tmp = g_build_filename (home, ".mono", NULL);
307 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
308 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
309 #ifdef PLATFORM_WIN32
312 err = mkdir (tmp, 0777);
315 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
321 tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
322 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
323 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
324 #ifdef PLATFORM_WIN32
327 err = mkdir (tmp, 0777);
330 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
339 * load_aot_module_from_cache:
341 * Experimental code to AOT compile loaded assemblies on demand.
344 * - Add environment variable MONO_AOT_CACHE_OPTIONS
345 * - Add options for controlling the cache size
346 * - Handle full cache by deleting old assemblies lru style
347 * - Add options for excluding assemblies during development
348 * - Maybe add a threshold after an assembly is AOT compiled
349 * - invoking a new mono process is a security risk
352 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
354 char *fname, *cmd, *tmp2;
362 if (assembly->image->dynamic)
365 create_cache_structure ();
367 home = g_get_home_dir ();
369 tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
370 fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
374 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
375 module = g_module_open (fname, G_MODULE_BIND_LAZY);
378 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
380 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
382 /* FIXME: security */
383 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
385 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
388 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
392 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
394 module = g_module_open (fname, G_MODULE_BIND_LAZY);
401 load_aot_module (MonoAssembly *assembly, gpointer user_data)
405 gboolean usable = TRUE;
406 char *saved_guid = NULL;
407 char *aot_version = NULL;
408 char *opt_flags = NULL;
410 #ifdef MONO_ARCH_HAVE_PIC_AOT
411 gpointer *got_addr = NULL;
412 gpointer *got = NULL;
413 guint32 *got_size_ptr = NULL;
416 if (mono_compile_aot)
420 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
422 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
424 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
426 if (!assembly->aot_module) {
427 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
431 if (!assembly->aot_module) {
436 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
437 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
438 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
440 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
441 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);
445 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
446 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
453 g_module_close (assembly->aot_module);
454 assembly->aot_module = NULL;
458 #ifdef MONO_ARCH_HAVE_PIC_AOT
459 g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
461 got = (gpointer*)*got_addr;
463 g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
464 g_assert (got_size_ptr);
467 info = g_new0 (MonoAotModule, 1);
468 info->aot_name = aot_name;
469 #ifdef MONO_ARCH_HAVE_PIC_AOT
471 info->got_size = *got_size_ptr;
473 sscanf (opt_flags, "%d", &info->opts);
475 /* Read image table */
477 guint32 table_len, i;
480 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
483 table_len = *(guint32*)table;
484 table += sizeof (guint32);
485 info->image_table = g_new0 (MonoImage*, table_len);
486 info->image_names = g_new0 (MonoAssemblyName, table_len);
487 info->image_guids = g_new0 (char*, table_len);
488 for (i = 0; i < table_len; ++i) {
489 MonoAssemblyName *aname = &(info->image_names [i]);
491 aname->name = g_strdup (table);
492 table += strlen (table) + 1;
493 info->image_guids [i] = g_strdup (table);
494 table += strlen (table) + 1;
496 aname->culture = g_strdup (table);
497 table += strlen (table) + 1;
498 memcpy (aname->public_key_token, table, strlen (table) + 1);
499 table += strlen (table) + 1;
501 table = ALIGN_PTR_TO (table, 8);
502 aname->flags = *(guint32*)table;
504 aname->major = *(guint32*)table;
506 aname->minor = *(guint32*)table;
508 aname->build = *(guint32*)table;
510 aname->revision = *(guint32*)table;
515 /* Read icall table */
517 guint32 table_len, i;
520 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
523 table_len = *(guint32*)table;
524 table += sizeof (guint32);
525 info->icall_table = g_new0 (char*, table_len);
526 for (i = 0; i < table_len; ++i) {
527 info->icall_table [i] = table;
528 table += strlen (table) + 1;
532 /* Read method and method_info tables */
533 g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
534 g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
535 g_module_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end);
536 g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
537 g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
538 g_module_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets);
539 g_module_symbol (assembly->aot_module, "ex_infos", (gpointer*)&info->ex_infos);
540 g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos);
541 g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
543 EnterCriticalSection (&aot_mutex);
544 g_hash_table_insert (aot_modules, assembly, info);
545 LeaveCriticalSection (&aot_mutex);
547 mono_jit_info_add_aot_module (assembly->image, info->code, info->code_end);
549 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
555 InitializeCriticalSection (&aot_mutex);
556 aot_modules = g_hash_table_new (NULL, NULL);
558 mono_install_assembly_load_hook (load_aot_module, NULL);
560 if (getenv ("MONO_LASTAOT"))
561 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
562 if (getenv ("MONO_AOT_CACHE"))
563 use_aot_cache = TRUE;
567 decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guint8 *buf, guint8 **endbuf)
571 info->vtable_size = decode_value (buf, &buf);
572 flags = decode_value (buf, &buf);
573 info->ghcimpl = (flags >> 0) & 0x1;
574 info->has_finalize = (flags >> 1) & 0x1;
575 info->has_cctor = (flags >> 2) & 0x1;
576 if (info->has_cctor) {
577 MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf);
581 if (info->has_finalize) {
582 info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf);
583 if (!info->finalize_image)
593 mono_aot_init_vtable (MonoVTable *vtable)
596 MonoAotModule *aot_module;
597 MonoClass *klass = vtable->klass;
599 MonoCachedClassInfo class_info;
602 if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
605 EnterCriticalSection (&aot_mutex);
607 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
609 LeaveCriticalSection (&aot_mutex);
613 info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
616 err = decode_cached_class_info (aot_module, &class_info, p, &p);
618 LeaveCriticalSection (&aot_mutex);
622 //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
623 for (i = 0; i < class_info.vtable_size; ++i) {
624 guint32 image_index, token, value;
626 #ifndef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
630 vtable->vtable [i] = 0;
632 value = decode_value (p, &p);
636 image_index = value >> 24;
637 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
639 image = load_image (aot_module, image_index);
641 LeaveCriticalSection (&aot_mutex);
645 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
646 vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
648 m = mono_get_method (image, token, NULL);
651 //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
652 vtable->vtable [i] = mono_create_jit_trampoline (m);
656 LeaveCriticalSection (&aot_mutex);
662 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
664 MonoAotModule *aot_module;
668 if (klass->rank || !klass->image->assembly->aot_module)
671 EnterCriticalSection (&aot_mutex);
673 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
675 LeaveCriticalSection (&aot_mutex);
679 p = (guint8*)&aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
681 err = decode_cached_class_info (aot_module, res, p, &p);
683 LeaveCriticalSection (&aot_mutex);
687 LeaveCriticalSection (&aot_mutex);
693 decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain,
694 MonoMethod *method, guint8* ex_info, guint8 *code)
698 guint code_len, used_int_regs;
700 MonoMethodHeader *header;
702 header = mono_method_get_header (method);
704 /* Load the method info from the AOT file */
707 code_len = decode_value (p, &p);
708 used_int_regs = decode_value (p, &p);
710 /* Exception table */
711 if (header->num_clauses) {
713 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
714 jinfo->num_clauses = header->num_clauses;
716 for (i = 0; i < header->num_clauses; ++i) {
717 MonoExceptionClause *ec = &header->clauses [i];
718 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
720 ei->flags = ec->flags;
721 ei->exvar_offset = decode_value (p, &p);
723 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
724 ei->data.filter = code + decode_value (p, &p);
726 ei->data.catch_class = ec->data.catch_class;
728 ei->try_start = code + decode_value (p, &p);
729 ei->try_end = code + decode_value (p, &p);
730 ei->handler_start = code + decode_value (p, &p);
734 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
736 jinfo->code_size = code_len;
737 jinfo->used_regs = used_int_regs;
738 jinfo->method = method;
739 jinfo->code_start = code;
740 #ifdef MONO_ARCH_HAVE_PIC_AOT
741 jinfo->domain_neutral = 0;
743 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
746 /* Load debug info */
747 buf_len = decode_value (p, &p);
748 mono_debug_add_aot_method (domain, method, code, p, buf_len);
754 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
756 MonoAssembly *ass = image->assembly;
757 GModule *module = ass->aot_module;
758 int pos, pos2, orig_pos, left, right, len, offset, offset1, offset2;
760 MonoAotModule *aot_module;
763 guint8 *code, *ex_info;
768 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
770 if (domain != mono_get_root_domain ())
774 /* Binary search inside the code_offsets table to find the method */
776 len = image->tables [MONO_TABLE_METHOD].rows;
779 offset = (guint8*)addr - aot_module->code;
785 pos = (left + right) / 2;
788 while ((pos < len) && (aot_module->code_offsets [pos] == 0xffffffff))
794 offset1 = aot_module->code_offsets [pos];
796 /* Find the end of the method by searching for the next valid entry */
798 while ((pos2 < len) && (aot_module->code_offsets [pos2] == 0xffffffff))
803 offset2 = aot_module->code_offsets [pos2];
805 if (offset < offset1)
807 else if (offset >= offset2)
813 token = mono_metadata_make_token (MONO_TABLE_METHOD, pos + 1);
814 method = mono_get_method (image, token, NULL);
819 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
821 code = &aot_module->code [aot_module->code_offsets [pos]];
822 ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [pos]];
824 jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
826 g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
827 g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
829 /* Add it to the normal JitInfo tables */
830 mono_jit_info_table_add (domain, jinfo);
836 load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches,
837 guint32 got_index, guint32 **got_slots,
838 guint8 *buf, guint8 **endbuf)
840 MonoJumpInfo *patches;
841 MonoJumpInfo *patch_info;
850 /* First load the type + offset table */
852 patches = mono_mempool_alloc (mp, sizeof (MonoJumpInfo) * n_patches);
854 for (pindex = 0; pindex < n_patches; ++pindex) {
855 MonoJumpInfo *ji = &patches [pindex];
857 #if defined(MONO_ARCH_HAVE_PIC_AOT)
864 b2 = *((guint8*)p + 1);
869 if (((b1 & (1 + 2)) == 3) && (b2 == 255))
870 ji->ip.i = decode_value (p, &p);
872 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
874 ji->ip.i += last_offset;
875 last_offset = ji->ip.i;
877 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
878 ji->next = patch_info;
882 *got_slots = g_malloc (sizeof (guint32) * n_patches);
883 memset (*got_slots, 0xff, sizeof (guint32) * n_patches);
885 /* Then load the other data */
886 for (pindex = 0; pindex < n_patches; ++pindex) {
887 MonoJumpInfo *ji = &patches [pindex];
890 case MONO_PATCH_INFO_CLASS:
891 case MONO_PATCH_INFO_IID:
892 case MONO_PATCH_INFO_VTABLE:
893 case MONO_PATCH_INFO_CLASS_INIT:
894 ji->data.klass = decode_klass_info (aot_module, p, &p);
898 case MONO_PATCH_INFO_IMAGE:
899 ji->data.image = load_image (aot_module, decode_value (p, &p));
903 case MONO_PATCH_INFO_METHOD:
904 case MONO_PATCH_INFO_METHODCONST:
905 case MONO_PATCH_INFO_METHOD_JUMP: {
906 guint32 image_index, token, value;
908 value = decode_value (p, &p);
909 image_index = value >> 24;
910 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
912 image = load_image (aot_module, image_index);
916 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
917 if (ji->type == MONO_PATCH_INFO_METHOD) {
918 ji->data.target = mono_create_jit_trampoline_from_token (image, token);
919 ji->type = MONO_PATCH_INFO_ABS;
922 ji->data.method = mono_get_method (image, token, NULL);
923 g_assert (ji->data.method);
924 mono_class_init (ji->data.method->klass);
927 ji->data.method = mono_get_method (image, token, NULL);
928 g_assert (ji->data.method);
929 mono_class_init (ji->data.method->klass);
934 case MONO_PATCH_INFO_WRAPPER: {
935 guint32 wrapper_type;
937 wrapper_type = decode_value (p, &p);
939 switch (wrapper_type) {
940 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
941 guint32 image_index, token, value;
943 value = decode_value (p, &p);
944 image_index = value >> 24;
945 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
947 image = load_image (aot_module, image_index);
950 ji->data.method = mono_get_method (image, token, NULL);
951 g_assert (ji->data.method);
952 mono_class_init (ji->data.method->klass);
954 ji->type = MONO_PATCH_INFO_METHOD;
955 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
958 case MONO_WRAPPER_PROXY_ISINST: {
959 MonoClass *klass = decode_klass_info (aot_module, p, &p);
962 ji->type = MONO_PATCH_INFO_METHOD;
963 ji->data.method = mono_marshal_get_proxy_cancast (klass);
966 case MONO_WRAPPER_LDFLD:
967 case MONO_WRAPPER_STFLD:
968 case MONO_WRAPPER_LDFLD_REMOTE:
969 case MONO_WRAPPER_STFLD_REMOTE:
970 case MONO_WRAPPER_ISINST: {
971 MonoClass *klass = decode_klass_info (aot_module, p, &p);
974 ji->type = MONO_PATCH_INFO_METHOD;
975 if (wrapper_type == MONO_WRAPPER_LDFLD)
976 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
977 else if (wrapper_type == MONO_WRAPPER_STFLD)
978 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
979 else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
980 ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
982 ji->data.method = mono_marshal_get_isinst (klass);
985 case MONO_WRAPPER_STELEMREF:
986 ji->type = MONO_PATCH_INFO_METHOD;
987 ji->data.method = mono_marshal_get_stelemref ();
990 g_assert_not_reached ();
994 case MONO_PATCH_INFO_FIELD:
995 case MONO_PATCH_INFO_SFLDA:
996 ji->data.field = decode_field_info (aot_module, p, &p);
1000 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1001 guint32 icall_index = decode_value (p, &p);
1003 ji->data.name = aot_module->icall_table [icall_index];
1004 g_assert (ji->data.name);
1006 #if MONO_ARCH_HAVE_PIC_AOT
1007 /* GOT entries for icalls are at the start of the got */
1008 (*got_slots) [pindex] = icall_index;
1012 case MONO_PATCH_INFO_SWITCH:
1013 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
1014 ji->data.table->table_size = decode_value (p, &p);
1015 table = g_new (gpointer, ji->data.table->table_size);
1016 ji->data.table->table = (MonoBasicBlock**)table;
1017 for (i = 0; i < ji->data.table->table_size; i++)
1018 table [i] = (gpointer)(gssize)decode_value (p, &p);
1020 case MONO_PATCH_INFO_R4: {
1023 ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
1024 val = decode_value (p, &p);
1025 *(float*)ji->data.target = *(float*)&val;
1028 case MONO_PATCH_INFO_R8: {
1031 ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
1033 val [0] = decode_value (p, &p);
1034 val [1] = decode_value (p, &p);
1035 *(double*)ji->data.target = *(double*)val;
1038 case MONO_PATCH_INFO_LDSTR:
1039 image = load_image (aot_module, decode_value (p, &p));
1042 ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
1044 case MONO_PATCH_INFO_DECLSEC:
1045 case MONO_PATCH_INFO_LDTOKEN:
1046 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1047 image = load_image (aot_module, decode_value (p, &p));
1050 ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
1052 case MONO_PATCH_INFO_EXC_NAME:
1053 ji->data.klass = decode_klass_info (aot_module, p, &p);
1054 if (!ji->data.klass)
1056 ji->data.name = ji->data.klass->name;
1058 case MONO_PATCH_INFO_METHOD_REL:
1059 ji->data.offset = decode_value (p, &p);
1062 g_warning ("unhandled type %d", ji->type);
1063 g_assert_not_reached ();
1066 #if MONO_ARCH_HAVE_PIC_AOT
1067 if ((*got_slots) [pindex] == 0xffffffff)
1068 (*got_slots) [pindex] = got_index ++;
1076 g_free (*got_slots);
1082 static MonoJitInfo *
1083 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
1085 MonoClass *klass = method->klass;
1086 MonoAssembly *ass = klass->image->assembly;
1087 GModule *module = ass->aot_module;
1088 guint8 *code, *info, *ex_info;
1089 MonoAotModule *aot_module;
1097 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1100 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1101 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1102 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1103 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1106 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1108 g_assert (klass->inited);
1110 if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
1111 /* Non shared AOT code can't be used in other appdomains */
1114 if (aot_module->out_of_date)
1117 if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
1118 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1119 char *full_name = mono_method_full_name (method, TRUE);
1120 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
1126 code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
1127 info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
1128 ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]];
1130 if (mono_last_aot_method != -1) {
1131 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1134 if (mono_jit_stats.methods_aot == mono_last_aot_method)
1135 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
1138 return mono_aot_load_method (domain, aot_module, method, code, info, ex_info);
1142 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8* ex_info)
1144 MonoClass *klass = method->klass;
1145 MonoJumpInfo *patch_info = NULL;
1148 int i, pindex, got_index, n_patches, used_strings;
1149 gboolean non_got_patches, keep_patches = TRUE;
1152 jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
1155 decode_klass_info (aot_module, p, &p);
1157 if (!use_loaded_code) {
1159 code2 = mono_code_manager_reserve (domain->code_mp, jinfo->code_size);
1160 memcpy (code2, code, jinfo->code_size);
1161 mono_arch_flush_icache (code2, jinfo->code_size);
1165 if (aot_module->opts & MONO_OPT_SHARED)
1166 used_strings = decode_value (p, &p);
1170 for (i = 0; i < used_strings; i++) {
1171 guint token = decode_value (p, &p);
1172 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
1175 if (aot_module->opts & MONO_OPT_SHARED)
1176 keep_patches = FALSE;
1178 #ifdef MONO_ARCH_HAVE_PIC_AOT
1179 got_index = decode_value (p, &p);
1180 keep_patches = FALSE;
1183 n_patches = decode_value (p, &p);
1186 MonoJumpInfo *patches;
1192 mp = mono_mempool_new ();
1194 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1195 if (patches == NULL)
1198 #if MONO_ARCH_HAVE_PIC_AOT
1199 /* Do this outside the lock to avoid deadlocks */
1200 LeaveCriticalSection (&aot_mutex);
1201 non_got_patches = FALSE;
1202 for (pindex = 0; pindex < n_patches; ++pindex) {
1203 MonoJumpInfo *ji = &patches [pindex];
1205 if (is_got_patch (ji->type)) {
1206 if (!aot_module->got [got_slots [pindex]])
1207 aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
1208 ji->type = MONO_PATCH_INFO_NONE;
1211 non_got_patches = TRUE;
1213 if (non_got_patches) {
1214 mono_arch_flush_icache (code, jinfo->code_size);
1215 make_writable (code, jinfo->code_size);
1216 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1218 EnterCriticalSection (&aot_mutex);
1220 if (use_loaded_code)
1221 /* disable write protection */
1222 make_writable (code, jinfo->code_size);
1224 /* Do this outside the lock to avoid deadlocks */
1225 LeaveCriticalSection (&aot_mutex);
1226 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1227 EnterCriticalSection (&aot_mutex);
1232 mono_mempool_destroy (mp);
1235 mono_jit_stats.methods_aot++;
1237 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1238 char *full_name = mono_method_full_name (method, TRUE);
1239 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p - %p %p\n", full_name, code, code + jinfo->code_size, info);
1246 /* FIXME: The space in domain->mp is wasted */
1247 if (aot_module->opts & MONO_OPT_SHARED)
1248 /* No need to cache patches */
1249 mono_mempool_destroy (mp);
1255 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1259 EnterCriticalSection (&aot_mutex);
1260 info = mono_aot_get_method_inner (domain, method);
1261 LeaveCriticalSection (&aot_mutex);
1263 /* Do this outside the lock */
1265 mono_jit_info_table_add (domain, info);
1273 mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guint32 token, MonoClass **klass)
1275 MonoAssembly *ass = image->assembly;
1277 int i, method_index, pindex, got_index, n_patches, used_strings;
1278 gboolean keep_patches = TRUE;
1280 GModule *module = ass->aot_module;
1281 guint8 *code = NULL;
1283 MonoAotModule *aot_module;
1290 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1293 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1295 if (domain != mono_get_root_domain ())
1298 if (aot_module->out_of_date)
1301 if (aot_module->code_offsets [mono_metadata_token_index (token) - 1] == 0xffffffff) {
1305 method_index = mono_metadata_token_index (token) - 1;
1306 code = &aot_module->code [aot_module->code_offsets [method_index]];
1307 info = &aot_module->method_infos [aot_module->method_info_offsets [method_index]];
1309 if (mono_last_aot_method != -1) {
1310 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1313 if (mono_jit_stats.methods_aot == mono_last_aot_method) {
1314 MonoMethod *method = mono_get_method (image, token, NULL);
1315 printf ("LAST AOT METHOD: %s.%s.%s.\n", method->klass->name_space, method->klass->name, method->name);
1319 if (!aot_module->methods_loaded)
1320 aot_module->methods_loaded = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 1);
1322 if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
1325 aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
1328 *klass = decode_klass_info (aot_module, p, &p);
1330 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1331 MonoMethod *method = mono_get_method (image, token, NULL);
1332 char *full_name = mono_method_full_name (method, TRUE);
1333 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p %p\n", full_name, code, info);
1337 if (aot_module->opts & MONO_OPT_SHARED)
1338 used_strings = decode_value (p, &p);
1342 for (i = 0; i < used_strings; i++) {
1343 guint string_token = decode_value (p, &p);
1344 mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (string_token));
1347 if (aot_module->opts & MONO_OPT_SHARED)
1348 keep_patches = FALSE;
1350 got_index = decode_value (p, &p);
1351 keep_patches = FALSE;
1353 n_patches = decode_value (p, &p);
1356 MonoJumpInfo *patches;
1362 mp = mono_mempool_new ();
1364 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1365 if (patches == NULL)
1368 /* Do this outside the lock to avoid deadlocks */
1369 LeaveCriticalSection (&aot_mutex);
1371 for (pindex = 0; pindex < n_patches; ++pindex) {
1372 MonoJumpInfo *ji = &patches [pindex];
1374 if (is_got_patch (ji->type)) {
1375 if (!aot_module->got [got_slots [pindex]])
1376 aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (NULL, domain, code, ji, TRUE);
1377 ji->type = MONO_PATCH_INFO_NONE;
1381 EnterCriticalSection (&aot_mutex);
1386 mono_mempool_destroy (mp);
1389 mono_jit_stats.methods_aot++;
1394 /* FIXME: The space in domain->mp is wasted */
1395 if (aot_module->opts & MONO_OPT_SHARED)
1396 /* No need to cache patches */
1397 mono_mempool_destroy (mp);
1403 * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
1407 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1412 EnterCriticalSection (&aot_mutex);
1413 res = mono_aot_get_method_from_token_inner (domain, image, token, &klass);
1414 LeaveCriticalSection (&aot_mutex);
1417 mono_runtime_class_init (mono_class_vtable (domain, klass));
1425 } IsGotEntryUserData;
1428 check_is_got_entry (gpointer key, gpointer value, gpointer user_data)
1430 IsGotEntryUserData *data = (IsGotEntryUserData*)user_data;
1431 MonoAotModule *aot_module = (MonoAotModule*)value;
1433 if (aot_module->got && (data->addr >= (guint8*)(aot_module->got)) && (data->addr < (guint8*)(aot_module->got + aot_module->got_size)))
1438 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
1440 IsGotEntryUserData user_data;
1445 user_data.addr = addr;
1446 user_data.res = FALSE;
1447 EnterCriticalSection (&aot_mutex);
1448 g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data);
1449 LeaveCriticalSection (&aot_mutex);
1451 return user_data.res;
1454 /*****************************************************/
1456 /*****************************************************/
1459 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1462 /* For solaris as, GNU as should accept the same */
1463 fprintf (fp, ".section \"%s\"\n", section_name);
1464 #elif defined(__ppc__) && defined(__MACH__)
1465 /* This needs to be made more precise on mach. */
1466 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1468 fprintf (fp, "%s %d\n", section_name, subsection_index);
1473 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1483 fprintf (fp, "\t.type %s,#%s\n", name, stype);
1484 #elif defined(PLATFORM_WIN32)
1486 #elif !(defined(__ppc__) && defined(__MACH__))
1487 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1488 #elif defined(__x86_64__) || defined(__i386__)
1489 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1494 emit_global (FILE *fp, const char *name, gboolean func)
1496 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1497 // mach-o always uses a '_' prefix.
1498 fprintf (fp, "\t.globl _%s\n", name);
1500 fprintf (fp, "\t.globl %s\n", name);
1503 emit_symbol_type (fp, name, func);
1507 emit_label (FILE *fp, const char *name)
1509 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1510 // mach-o always uses a '_' prefix.
1511 fprintf (fp, "_%s:\n", name);
1513 fprintf (fp, "%s:\n", name);
1516 #if defined(PLATFORM_WIN32)
1517 /* Emit a normal label too */
1518 fprintf (fp, "%s:\n", name);
1523 emit_string_symbol (FILE *fp, const char *name, const char *value)
1525 emit_section_change (fp, ".text", 1);
1526 emit_global(fp, name, FALSE);
1527 emit_label(fp, name);
1528 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1531 #if defined(__ppc__) && defined(__MACH__)
1533 ilog2(register int value)
1536 while (value & ~0xf) count += 4, value >>= 4;
1537 while (value) count++, value >>= 1;
1543 emit_alignment(FILE *fp, int size)
1545 #if defined(__ppc__) && defined(__MACH__)
1546 // the mach-o assembler specifies alignments as powers of 2.
1547 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1548 #elif defined(__powerpc__)
1549 /* ignore on linux/ppc */
1551 fprintf (fp, "\t.align %d\n", size);
1555 G_GNUC_UNUSED static void
1556 emit_pointer (FILE *fp, const char *target)
1558 emit_alignment (fp, sizeof (gpointer));
1559 #if defined(__x86_64__)
1560 fprintf (fp, "\t.quad %s\n", target);
1561 #elif defined(sparc) && SIZEOF_VOID_P == 8
1562 fprintf (fp, "\t.xword %s\n", target);
1564 fprintf (fp, "\t.long %s\n", target);
1569 mono_get_field_token (MonoClassField *field)
1571 MonoClass *klass = field->parent;
1574 for (i = 0; i < klass->field.count; ++i) {
1575 if (field == &klass->fields [i])
1576 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1579 g_assert_not_reached ();
1584 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
1588 //printf ("ENCODE: %d 0x%x.\n", value, value);
1591 * Same encoding as the one used in the metadata, extended to handle values
1592 * greater than 0x1fffffff.
1594 if ((value >= 0) && (value <= 127))
1596 else if ((value >= 0) && (value <= 16383)) {
1597 p [0] = 0x80 | (value >> 8);
1598 p [1] = value & 0xff;
1600 } else if ((value >= 0) && (value <= 0x1fffffff)) {
1601 p [0] = (value >> 24) | 0xc0;
1602 p [1] = (value >> 16) & 0xff;
1603 p [2] = (value >> 8) & 0xff;
1604 p [3] = value & 0xff;
1609 p [1] = (value >> 24) & 0xff;
1610 p [2] = (value >> 16) & 0xff;
1611 p [3] = (value >> 8) & 0xff;
1612 p [4] = value & 0xff;
1620 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1624 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1628 index = g_hash_table_size (cfg->image_hash);
1629 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1630 g_ptr_array_add (cfg->image_table, image);
1636 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
1638 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1639 if (!klass->type_token) {
1641 g_assert (klass->rank > 0);
1642 g_assert (klass->element_class->type_token);
1643 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1644 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1645 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1646 encode_value (klass->rank, buf, &buf);
1649 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1650 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1656 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
1658 guint32 token = mono_get_field_token (field);
1660 encode_klass_info (cfg, field->parent, buf, &buf);
1661 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1662 encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1667 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
1669 guint32 image_index = get_image_index (acfg, method->klass->image);
1670 guint32 token = method->token;
1671 g_assert (image_index < 256);
1672 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1674 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
1679 compare_patches (gconstpointer a, gconstpointer b)
1683 i = (*(MonoJumpInfo**)a)->ip.i;
1684 j = (*(MonoJumpInfo**)b)->ip.i;
1696 get_got_slot (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
1700 switch (patch_info->type) {
1701 case MONO_PATCH_INFO_INTERNAL_METHOD:
1702 res = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_to_got_offset_hash, patch_info->data.name));
1705 res = acfg->got_offset;
1706 acfg->got_offset ++;
1714 collect_icalls (MonoAotCompile *acfg)
1717 MonoJumpInfo *patch_info;
1719 for (mindex = 0; mindex < acfg->nmethods; ++mindex) {
1722 cfg = acfg->cfgs [mindex];
1726 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1727 switch (patch_info->type) {
1728 case MONO_PATCH_INFO_INTERNAL_METHOD:
1729 index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1731 index = g_hash_table_size (acfg->icall_hash) + 1;
1732 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1733 GUINT_TO_POINTER (index));
1734 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1736 /* Allocate a GOT slot */
1737 g_hash_table_insert (acfg->icall_to_got_offset_hash, (gpointer)patch_info->data.name, GUINT_TO_POINTER (acfg->got_offset));
1738 acfg->got_offset ++;
1749 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1753 int i, j, pindex, byte_index;
1756 int func_alignment = 16;
1758 MonoJumpInfo *patch_info;
1759 MonoMethodHeader *header;
1760 #ifdef MONO_ARCH_HAVE_PIC_AOT
1766 method = cfg->method;
1767 code = cfg->native_code;
1768 header = mono_method_get_header (method);
1770 /* Make the labels local */
1771 symbol = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1773 emit_alignment(tmpfp, func_alignment);
1774 emit_label(tmpfp, symbol);
1775 if (acfg->aot_opts.write_symbols)
1776 emit_global (tmpfp, symbol, TRUE);
1778 if (cfg->verbose_level > 0)
1779 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
1781 /* Sort relocations */
1782 patches = g_ptr_array_new ();
1783 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1784 g_ptr_array_add (patches, patch_info);
1785 g_ptr_array_sort (patches, compare_patches);
1787 #ifdef MONO_ARCH_HAVE_PIC_AOT
1788 acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1790 for (i = 0; i < cfg->code_len; i++) {
1792 for (pindex = 0; pindex < patches->len; ++pindex) {
1793 patch_info = g_ptr_array_index (patches, pindex);
1794 if (patch_info->ip.i == i)
1799 if (patch_info && (pindex < patches->len)) {
1800 switch (patch_info->type) {
1801 case MONO_PATCH_INFO_LABEL:
1802 case MONO_PATCH_INFO_BB:
1803 case MONO_PATCH_INFO_NONE:
1805 case MONO_PATCH_INFO_GOT_OFFSET: {
1806 guint32 offset = mono_arch_get_patch_offset (code + i);
1807 fprintf (tmpfp, "\n.byte ");
1808 for (j = 0; j < offset; ++j)
1809 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1810 fprintf (tmpfp, "\n.int got - . + %d", offset);
1812 i += offset + 4 - 1;
1817 if (!is_got_patch (patch_info->type))
1820 got_slot = get_got_slot (acfg, patch_info);
1821 fprintf (tmpfp, "\n.byte ");
1822 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
1823 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
1825 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
1826 #elif defined(__i386__)
1827 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((got_slot * sizeof (gpointer))));
1830 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
1836 if (byte_index == 0)
1837 fprintf (tmpfp, "\n.byte ");
1838 fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
1839 byte_index = (byte_index + 1) % 32;
1845 for (i = 0; i < cfg->code_len; i++) {
1846 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
1849 fprintf (tmpfp, "\n");
1853 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
1858 int i, j, pindex, buf_size, n_patches;
1862 MonoJumpInfo *patch_info;
1863 MonoMethodHeader *header;
1864 guint32 last_offset;
1866 #ifdef MONO_ARCH_HAVE_PIC_AOT
1867 guint32 first_got_offset;
1871 method = cfg->method;
1872 code = cfg->native_code;
1873 header = mono_method_get_header (method);
1875 /* Make the labels local */
1876 symbol = g_strdup_printf (".Lm_%x_p", mono_metadata_token_index (method->token));
1878 /* Sort relocations */
1879 patches = g_ptr_array_new ();
1880 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1881 g_ptr_array_add (patches, patch_info);
1882 g_ptr_array_sort (patches, compare_patches);
1884 #ifdef MONO_ARCH_HAVE_PIC_AOT
1885 first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
1888 /**********************/
1889 /* Encode method info */
1890 /**********************/
1892 buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
1893 p = buf = g_malloc (buf_size);
1895 encode_klass_info (acfg, method->klass, p, &p);
1898 if (cfg->opt & MONO_OPT_SHARED) {
1899 encode_value (g_list_length (cfg->ldstr_list), p, &p);
1900 for (l = cfg->ldstr_list; l; l = l->next) {
1901 encode_value ((long)l->data, p, &p);
1905 /* Used only in shared mode */
1906 g_assert (!cfg->ldstr_list);
1908 #ifdef MONO_ARCH_HAVE_PIC_AOT
1909 encode_value (first_got_offset, p, &p);
1913 for (pindex = 0; pindex < patches->len; ++pindex) {
1914 patch_info = g_ptr_array_index (patches, pindex);
1916 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1917 (patch_info->type == MONO_PATCH_INFO_BB) ||
1918 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1919 (patch_info->type == MONO_PATCH_INFO_NONE))
1926 encode_value (n_patches, p, &p);
1928 /* First emit the type+position table */
1931 for (pindex = 0; pindex < patches->len; ++pindex) {
1933 patch_info = g_ptr_array_index (patches, pindex);
1935 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
1936 (patch_info->type == MONO_PATCH_INFO_BB) ||
1937 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
1938 (patch_info->type == MONO_PATCH_INFO_NONE))
1943 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
1944 offset = patch_info->ip.i - last_offset;
1945 last_offset = patch_info->ip.i;
1947 #if defined(MONO_ARCH_HAVE_PIC_AOT)
1948 /* Only the type is needed */
1949 *p = patch_info->type;
1952 /* Encode type+position compactly */
1953 g_assert (patch_info->type < 64);
1954 if (offset < 1024 - 1) {
1955 *p = (patch_info->type << 2) + (offset >> 8);
1957 *p = offset & ((1 << 8) - 1);
1961 *p = (patch_info->type << 2) + 3;
1965 encode_value (offset, p, &p);
1970 /* Then emit the other info */
1971 for (pindex = 0; pindex < patches->len; ++pindex) {
1972 patch_info = g_ptr_array_index (patches, pindex);
1974 switch (patch_info->type) {
1975 case MONO_PATCH_INFO_LABEL:
1976 case MONO_PATCH_INFO_BB:
1977 case MONO_PATCH_INFO_GOT_OFFSET:
1978 case MONO_PATCH_INFO_NONE:
1980 case MONO_PATCH_INFO_IMAGE:
1981 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
1983 case MONO_PATCH_INFO_METHOD_REL:
1984 encode_value ((gint)patch_info->data.offset, p, &p);
1986 case MONO_PATCH_INFO_SWITCH: {
1987 gpointer *table = (gpointer *)patch_info->data.table->table;
1990 encode_value (patch_info->data.table->table_size, p, &p);
1991 for (k = 0; k < patch_info->data.table->table_size; k++)
1992 encode_value ((int)(gssize)table [k], p, &p);
1995 case MONO_PATCH_INFO_METHODCONST:
1996 case MONO_PATCH_INFO_METHOD:
1997 case MONO_PATCH_INFO_METHOD_JUMP:
1998 encode_method_ref (acfg, patch_info->data.method, p, &p);
2000 case MONO_PATCH_INFO_INTERNAL_METHOD: {
2001 guint32 icall_index;
2003 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
2004 g_assert (icall_index);
2005 encode_value (icall_index - 1, p, &p);
2008 case MONO_PATCH_INFO_LDSTR: {
2009 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
2010 guint32 token = patch_info->data.token->token;
2011 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
2013 * An optimization would be to emit shared code for ldstr
2014 * statements followed by a throw.
2016 encode_value (image_index, p, &p);
2017 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
2020 case MONO_PATCH_INFO_DECLSEC:
2021 case MONO_PATCH_INFO_LDTOKEN:
2022 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2023 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
2024 encode_value (patch_info->data.token->token, p, &p);
2026 case MONO_PATCH_INFO_EXC_NAME: {
2027 MonoClass *ex_class;
2030 mono_class_from_name (mono_defaults.exception_class->image,
2031 "System", patch_info->data.target);
2032 g_assert (ex_class);
2033 encode_klass_info (acfg, ex_class, p, &p);
2036 case MONO_PATCH_INFO_R4:
2037 encode_value (*((guint32 *)patch_info->data.target), p, &p);
2039 case MONO_PATCH_INFO_R8:
2040 encode_value (*((guint32 *)patch_info->data.target), p, &p);
2041 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
2043 case MONO_PATCH_INFO_VTABLE:
2044 case MONO_PATCH_INFO_CLASS_INIT:
2045 case MONO_PATCH_INFO_CLASS:
2046 case MONO_PATCH_INFO_IID:
2047 encode_klass_info (acfg, patch_info->data.klass, p, &p);
2049 case MONO_PATCH_INFO_FIELD:
2050 case MONO_PATCH_INFO_SFLDA:
2051 encode_field_info (acfg, patch_info->data.field, p, &p);
2053 case MONO_PATCH_INFO_WRAPPER: {
2054 encode_value (patch_info->data.method->wrapper_type, p, &p);
2056 switch (patch_info->data.method->wrapper_type) {
2057 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
2059 guint32 image_index;
2062 m = mono_marshal_method_from_wrapper (patch_info->data.method);
2063 image_index = get_image_index (acfg, m->klass->image);
2065 g_assert (image_index < 256);
2066 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
2068 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
2071 case MONO_WRAPPER_PROXY_ISINST:
2072 case MONO_WRAPPER_LDFLD:
2073 case MONO_WRAPPER_STFLD:
2074 case MONO_WRAPPER_LDFLD_REMOTE:
2075 case MONO_WRAPPER_STFLD_REMOTE:
2076 case MONO_WRAPPER_ISINST: {
2077 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
2078 encode_klass_info (acfg, proxy_class, p, &p);
2081 case MONO_WRAPPER_STELEMREF:
2084 g_assert_not_reached ();
2089 g_warning ("unable to handle jump info %d", patch_info->type);
2090 g_assert_not_reached ();
2094 /* Emit method info */
2096 emit_label (tmpfp, symbol);
2098 g_assert (p - buf < buf_size);
2099 for (i = 0; i < p - buf; ++i) {
2101 fprintf (tmpfp, "\n.byte ");
2102 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2104 fprintf (tmpfp, "\n");
2111 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
2116 guint32 debug_info_size;
2119 MonoMethodHeader *header;
2120 guint8 *p, *buf, *debug_info;
2123 method = cfg->method;
2124 code = cfg->native_code;
2125 header = mono_method_get_header (method);
2127 /* Make the labels local */
2128 symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
2130 buf_size = header->num_clauses * 256 + 128;
2131 p = buf = g_malloc (buf_size);
2133 encode_value (cfg->code_len, p, &p);
2134 encode_value (cfg->used_int_regs, p, &p);
2136 /* Exception table */
2137 if (header->num_clauses) {
2138 MonoJitInfo *jinfo = cfg->jit_info;
2140 for (k = 0; k < header->num_clauses; ++k) {
2141 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
2143 encode_value (ei->exvar_offset, p, &p);
2145 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
2146 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
2148 encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
2149 encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
2150 encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
2154 mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
2156 encode_value (debug_info_size, p, &p);
2157 if (debug_info_size) {
2158 memcpy (p, debug_info, debug_info_size);
2159 p += debug_info_size;
2160 g_free (debug_info);
2165 emit_label (tmpfp, symbol);
2167 g_assert (p - buf < buf_size);
2168 for (i = 0; i < p - buf; ++i) {
2170 fprintf (tmpfp, "\n.byte ");
2171 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2173 fprintf (tmpfp, "\n");
2180 emit_klass_info (MonoAotCompile *acfg, guint32 token)
2182 MonoClass *klass = mono_class_get (acfg->image, token);
2186 FILE *tmpfp = acfg->fp;
2189 p = buf = g_malloc (buf_size);
2193 mono_class_init (klass);
2196 * Emit all the information which is required for creating vtables so
2197 * the runtime does not need to create the MonoMethod structures which
2198 * take up a lot of space.
2201 if (1) {//!MONO_CLASS_IS_INTERFACE (klass)) {
2202 encode_value (klass->vtable_size, p, &p);
2203 encode_value ((klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
2204 if (klass->has_cctor)
2205 encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
2206 if (klass->has_finalize)
2207 encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
2209 for (i = 0; i < klass->vtable_size; ++i) {
2210 MonoMethod *cm = klass->vtable [i];
2213 encode_method_ref (acfg, cm, p, &p);
2215 encode_value (0, p, &p);
2220 label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
2221 emit_label (tmpfp, label);
2223 g_assert (p - buf < buf_size);
2224 for (i = 0; i < p - buf; ++i) {
2226 fprintf (tmpfp, "\n.byte ");
2227 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2229 fprintf (tmpfp, "\n");
2234 str_begins_with (const char *str1, const char *str2)
2236 int len = strlen (str2);
2237 return strncmp (str1, str2, len) == 0;
2241 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
2243 gchar **args, **ptr;
2245 memset (opts, 0, sizeof (*opts));
2247 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
2248 for (ptr = args; ptr && *ptr; ptr ++) {
2249 const char *arg = *ptr;
2251 if (str_begins_with (arg, "outfile=")) {
2252 opts->outfile = g_strdup (arg + strlen ("outfile="));
2253 } else if (str_begins_with (arg, "save-temps")) {
2254 opts->save_temps = TRUE;
2255 } else if (str_begins_with (arg, "write-symbols")) {
2256 opts->write_symbols = TRUE;
2258 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
2265 compile_method (MonoAotCompile *acfg, int index)
2269 MonoJumpInfo *patch_info;
2271 guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
2273 method = mono_get_method (acfg->image, token, NULL);
2275 /* fixme: maybe we can also precompile wrapper methods */
2276 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2277 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2278 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2279 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
2280 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
2286 /* fixme: we need to patch the IP for the LMF in that case */
2287 if (method->save_lmf) {
2288 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
2294 * Since these methods are the only ones which are compiled with
2295 * AOT support, and they are not used by runtime startup/shutdown code,
2296 * the runtime will not see AOT methods during AOT compilation,so it
2297 * does not need to support them by creating a fake GOT etc.
2299 cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
2302 if (cfg->disable_aot) {
2303 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
2305 mono_destroy_compile (cfg);
2310 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2311 if (patch_info->type == MONO_PATCH_INFO_ABS) {
2312 /* unable to handle this */
2313 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
2321 mono_destroy_compile (cfg);
2325 /* some wrappers are very common */
2326 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2327 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
2328 switch (patch_info->data.method->wrapper_type) {
2329 case MONO_WRAPPER_PROXY_ISINST:
2330 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2334 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
2335 switch (patch_info->data.method->wrapper_type) {
2336 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2337 case MONO_WRAPPER_STFLD:
2338 case MONO_WRAPPER_LDFLD:
2339 case MONO_WRAPPER_LDFLD_REMOTE:
2340 case MONO_WRAPPER_STFLD_REMOTE:
2341 case MONO_WRAPPER_STELEMREF:
2342 case MONO_WRAPPER_ISINST:
2343 case MONO_WRAPPER_PROXY_ISINST:
2344 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2351 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2352 switch (patch_info->type) {
2353 case MONO_PATCH_INFO_METHOD:
2354 case MONO_PATCH_INFO_METHODCONST:
2355 if (patch_info->data.method->wrapper_type) {
2356 /* unable to handle this */
2357 //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));
2361 if (!patch_info->data.method->token)
2363 * The method is part of a constructed type like Int[,].Set (). It doesn't
2364 * have a token, and we can't make one, since the parent type is part of
2365 * assembly which contains the element type, and not the assembly which
2366 * referenced this type.
2370 case MONO_PATCH_INFO_VTABLE:
2371 case MONO_PATCH_INFO_CLASS_INIT:
2372 case MONO_PATCH_INFO_CLASS:
2373 case MONO_PATCH_INFO_IID:
2374 if (!patch_info->data.klass->type_token)
2375 if (!patch_info->data.klass->element_class->type_token)
2384 acfg->wrappercount++;
2385 mono_destroy_compile (cfg);
2389 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
2391 acfg->cfgs [index] = cfg;
2397 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
2399 MonoImage *image = ass->image;
2400 char *com, *tmpfname, *opts_str, *symbol;
2403 MonoAotCompile *acfg;
2405 char *outfile_name, *tmp_outfile_name;
2407 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
2409 acfg = g_new0 (MonoAotCompile, 1);
2410 acfg->icall_hash = g_hash_table_new (NULL, NULL);
2411 acfg->icall_to_got_offset_hash = g_hash_table_new (NULL, NULL);
2412 acfg->icall_table = g_ptr_array_new ();
2413 acfg->image_hash = g_hash_table_new (NULL, NULL);
2414 acfg->image_table = g_ptr_array_new ();
2415 acfg->image = image;
2418 mono_aot_parse_options (aot_options, &acfg->aot_opts);
2420 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
2421 tmpfp = fdopen (i, "w+");
2425 emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
2427 emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
2429 opts_str = g_strdup_printf ("%d", opts);
2430 emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
2433 cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
2435 acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
2436 acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
2438 /* Compile methods */
2439 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
2440 compile_method (acfg, i);
2442 collect_icalls (acfg);
2445 symbol = g_strdup_printf ("methods");
2446 emit_section_change (tmpfp, ".text", 0);
2447 emit_global (tmpfp, symbol, TRUE);
2448 emit_alignment (tmpfp, 8);
2449 emit_label (tmpfp, symbol);
2451 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2453 emit_method_code (acfg, cfgs [i]);
2456 symbol = g_strdup_printf ("methods_end");
2457 emit_section_change (tmpfp, ".text", 0);
2458 emit_global (tmpfp, symbol, FALSE);
2459 emit_alignment (tmpfp, 8);
2460 emit_label (tmpfp, symbol);
2462 /* Emit method info */
2463 symbol = g_strdup_printf ("method_infos");
2464 emit_section_change (tmpfp, ".text", 1);
2465 emit_global (tmpfp, symbol, FALSE);
2466 emit_alignment (tmpfp, 8);
2467 emit_label (tmpfp, symbol);
2469 /* To reduce size of generate assembly */
2470 symbol = g_strdup_printf ("mi");
2471 emit_label (tmpfp, symbol);
2473 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2475 emit_method_info (acfg, cfgs [i]);
2478 /* Emit exception info */
2479 symbol = g_strdup_printf ("ex_infos");
2480 emit_section_change (tmpfp, ".text", 1);
2481 emit_global (tmpfp, symbol, FALSE);
2482 emit_alignment (tmpfp, 8);
2483 emit_label (tmpfp, symbol);
2485 /* To reduce size of generate assembly */
2486 symbol = g_strdup_printf ("ex");
2487 emit_label (tmpfp, symbol);
2489 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2491 emit_exception_debug_info (acfg, cfgs [i]);
2494 /* Emit class info */
2495 symbol = g_strdup_printf ("class_infos");
2496 emit_section_change (tmpfp, ".text", 1);
2497 emit_global (tmpfp, symbol, FALSE);
2498 emit_alignment (tmpfp, 8);
2499 emit_label (tmpfp, symbol);
2501 for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
2502 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
2504 symbol = g_strdup_printf ("class_info_offsets");
2505 emit_section_change (tmpfp, ".text", 1);
2506 emit_global (tmpfp, symbol, FALSE);
2507 emit_alignment (tmpfp, 8);
2508 emit_label(tmpfp, symbol);
2510 for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
2512 if ((i % 32) == 0) {
2513 fprintf (tmpfp, "\n.long ");
2519 symbol = g_strdup_printf (".LK_I_%x", i);
2520 fprintf (tmpfp, "%s%s - class_infos", sep, symbol);
2522 fprintf (tmpfp, "\n");
2525 * The icall and image tables are small but referenced in a lot of places.
2526 * So we emit them at once, and reference their elements by an index.
2529 /* Emit icall table */
2531 symbol = g_strdup_printf ("mono_icall_table");
2532 emit_section_change (tmpfp, ".text", 1);
2533 emit_global(tmpfp, symbol, FALSE);
2534 emit_alignment(tmpfp, 8);
2535 emit_label(tmpfp, symbol);
2536 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
2537 for (i = 0; i < acfg->icall_table->len; i++)
2538 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
2540 /* Emit image table */
2542 symbol = g_strdup_printf ("mono_image_table");
2543 emit_section_change (tmpfp, ".text", 1);
2544 emit_global(tmpfp, symbol, FALSE);
2545 emit_alignment(tmpfp, 8);
2546 emit_label(tmpfp, symbol);
2547 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
2548 for (i = 0; i < acfg->image_table->len; i++) {
2549 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
2550 MonoAssemblyName *aname = &image->assembly->aname;
2552 /* FIXME: Support multi-module assemblies */
2553 g_assert (image->assembly->image == image);
2555 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
2556 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
2557 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
2558 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
2560 emit_alignment (tmpfp, 8);
2561 fprintf (tmpfp, ".long %d\n", aname->flags);
2562 fprintf (tmpfp, ".long %d\n", aname->major);
2563 fprintf (tmpfp, ".long %d\n", aname->minor);
2564 fprintf (tmpfp, ".long %d\n", aname->build);
2565 fprintf (tmpfp, ".long %d\n", aname->revision);
2568 #ifdef MONO_ARCH_HAVE_PIC_AOT
2571 /* Don't make GOT global so accesses to it don't need relocations */
2572 symbol = g_strdup_printf ("got");
2573 emit_section_change (tmpfp, ".bss", 1);
2574 emit_alignment (tmpfp, 8);
2575 emit_label(tmpfp, symbol);
2576 if (acfg->got_offset > 0)
2577 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2579 printf ("GOT SIZE: %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2581 symbol = g_strdup_printf ("got_addr");
2582 emit_section_change (tmpfp, ".data", 1);
2583 emit_global (tmpfp, symbol, FALSE);
2584 emit_alignment (tmpfp, 8);
2585 emit_label(tmpfp, symbol);
2586 emit_pointer (tmpfp, "got");
2588 symbol = g_strdup_printf ("got_size");
2589 emit_section_change (tmpfp, ".data", 1);
2590 emit_global (tmpfp, symbol, FALSE);
2591 emit_alignment (tmpfp, 8);
2592 emit_label(tmpfp, symbol);
2593 fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2596 symbol = g_strdup_printf ("method_offsets");
2597 emit_section_change (tmpfp, ".text", 1);
2598 emit_global (tmpfp, symbol, FALSE);
2599 emit_alignment (tmpfp, 8);
2600 emit_label(tmpfp, symbol);
2602 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2604 if ((i % 32) == 0) {
2605 fprintf (tmpfp, "\n.long ");
2611 symbol = g_strdup_printf (".Lm_%x", i + 1);
2612 fprintf (tmpfp, "%s%s-methods", sep, symbol);
2615 fprintf (tmpfp, "%s0xffffffff", sep);
2617 fprintf (tmpfp, "\n");
2619 symbol = g_strdup_printf ("method_info_offsets");
2620 emit_section_change (tmpfp, ".text", 1);
2621 emit_global (tmpfp, symbol, FALSE);
2622 emit_alignment (tmpfp, 8);
2623 emit_label(tmpfp, symbol);
2625 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2627 if ((i % 32) == 0) {
2628 fprintf (tmpfp, "\n.long ");
2634 symbol = g_strdup_printf (".Lm_%x_p", i + 1);
2635 fprintf (tmpfp, "%s%s - mi", sep, symbol);
2638 fprintf (tmpfp, "%s0", sep);
2640 fprintf (tmpfp, "\n");
2642 symbol = g_strdup_printf ("ex_info_offsets");
2643 emit_section_change (tmpfp, ".text", 1);
2644 emit_global (tmpfp, symbol, FALSE);
2645 emit_alignment (tmpfp, 8);
2646 emit_label(tmpfp, symbol);
2648 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2650 if ((i % 32) == 0) {
2651 fprintf (tmpfp, "\n.long ");
2657 symbol = g_strdup_printf (".Le_%x_p", i + 1);
2658 fprintf (tmpfp, "%s%s - ex", sep, symbol);
2661 fprintf (tmpfp, "%s0", sep);
2663 fprintf (tmpfp, "\n");
2667 #if defined(__x86_64__)
2668 com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
2669 #elif defined(sparc) && SIZEOF_VOID_P == 8
2670 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
2672 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
2675 printf ("Executing the native assembler: %s\n", com);
2676 if (system (com) != 0) {
2683 if (acfg->aot_opts.outfile)
2684 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
2686 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
2688 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
2691 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
2692 #elif defined(__ppc__) && defined(__MACH__)
2693 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
2694 #elif defined(PLATFORM_WIN32)
2695 com = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, tmpfname);
2697 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
2699 printf ("Executing the native linker: %s\n", com);
2700 if (system (com) != 0) {
2701 g_free (tmp_outfile_name);
2702 g_free (outfile_name);
2708 com = g_strdup_printf ("%s.o", tmpfname);
2711 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
2712 printf ("Stripping the binary: %s\n", com);
2716 rename (tmp_outfile_name, outfile_name);
2718 g_free (tmp_outfile_name);
2719 g_free (outfile_name);
2721 printf ("Compiled %d out of %d methods (%d%%)\n", acfg->ccount, acfg->mcount, acfg->mcount ? (acfg->ccount*100)/acfg->mcount : 100);
2722 printf ("%d methods contain absolute addresses (%d%%)\n", acfg->abscount, acfg->mcount ? (acfg->abscount*100)/acfg->mcount : 100);
2723 printf ("%d methods contain wrapper references (%d%%)\n", acfg->wrappercount, acfg->mcount ? (acfg->wrappercount*100)/acfg->mcount : 100);
2724 printf ("%d methods contain lmf pointers (%d%%)\n", acfg->lmfcount, acfg->mcount ? (acfg->lmfcount*100)/acfg->mcount : 100);
2725 printf ("%d methods have other problems (%d%%)\n", acfg->ocount, acfg->mcount ? (acfg->ocount*100)/acfg->mcount : 100);
2726 if (acfg->aot_opts.save_temps)
2727 printf ("Retained input file.\n");
2738 mono_aot_init (void)
2743 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
2749 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
2755 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)