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 N_RESERVED_GOT_SLOTS 1
62 #define ICALL_GOT_SLOTS_START_INDEX N_RESERVED_GOT_SLOTS
64 #define ALIGN_PTR_TO(ptr,align) (gpointer)((((gssize)(ptr)) + (align - 1)) & (~(align - 1)))
65 #define ROUND_DOWN(VALUE,SIZE) ((VALUE) & ~((SIZE) - 1))
67 typedef struct MonoAotModule {
69 /* Optimization flags used to compile the module */
71 /* Pointer to the Global Offset Table */
75 MonoAssemblyName *image_names;
77 MonoImage **image_table;
83 guint32 *code_offsets;
85 guint32 *method_info_offsets;
87 guint32 *ex_info_offsets;
88 guint32 *method_order;
89 guint32 *method_order_end;
91 guint32 *class_info_offsets;
92 guint32 *methods_loaded;
95 typedef struct MonoAotOptions {
98 gboolean write_symbols;
101 typedef struct MonoAotCompile {
105 GHashTable *icall_hash;
106 GHashTable *icall_to_got_offset_hash;
107 GPtrArray *icall_table;
108 GHashTable *image_hash;
109 GPtrArray *image_table;
112 guint32 *method_got_offsets;
113 MonoAotOptions aot_opts;
116 int ccount, mcount, lmfcount, abscount, wrappercount, ocount;
117 int code_size, info_size, ex_info_size, got_size, class_info_size;
120 static GHashTable *aot_modules;
121 #define mono_aot_lock() EnterCriticalSection (&aot_mutex)
122 #define mono_aot_unlock() LeaveCriticalSection (&aot_mutex)
123 static CRITICAL_SECTION aot_mutex;
126 * Disabling this will make a copy of the loaded code and use the copy instead
127 * of the original. This will place the caller and the callee close to each
128 * other in memory, possibly improving cache behavior. Since the original
129 * code is in copy-on-write memory, this will not increase the memory usage
132 #ifdef MONO_ARCH_HAVE_PIC_AOT
133 static gboolean use_loaded_code = TRUE;
135 static gboolean use_loaded_code = FALSE;
139 * Whenever to AOT compile loaded assemblies on demand and store them in
140 * a cache under $HOME/.mono/aot-cache.
142 static gboolean use_aot_cache = FALSE;
145 static gint32 mono_last_aot_method = -1;
147 static gboolean make_unreadable = FALSE;
148 static guint32 n_pagefaults = 0;
151 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8 *ex_info);
154 is_got_patch (MonoJumpInfoType patch_type)
158 #elif defined(__i386__)
165 /*****************************************************/
167 /*****************************************************/
170 load_image (MonoAotModule *module, int index)
172 MonoAssembly *assembly;
173 MonoImageOpenStatus status;
175 if (module->image_table [index])
176 return module->image_table [index];
177 if (module->out_of_date)
180 assembly = mono_assembly_load (&module->image_names [index], NULL, &status);
182 module->out_of_date = TRUE;
186 if (strcmp (assembly->image->guid, module->image_guids [index])) {
187 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);
188 module->out_of_date = TRUE;
192 module->image_table [index] = assembly->image;
193 return assembly->image;
198 decode_value (guint8 *ptr, guint8 **rptr)
203 if ((b & 0x80) == 0){
206 } else if ((b & 0x40) == 0){
207 len = ((b & 0x3f) << 8 | ptr [1]);
209 } else if (b != 0xff) {
210 len = ((b & 0x1f) << 24) |
217 len = (ptr [1] << 24) | (ptr [2] << 16) | (ptr [3] << 8) | ptr [4];
223 //printf ("DECODE: %d.\n", len);
228 decode_klass_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
232 guint32 token, rank, image_index;
234 token = decode_value (buf, &buf);
239 image_index = decode_value (buf, &buf);
240 image = load_image (module, image_index);
243 if (mono_metadata_token_code (token) == 0) {
244 klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF + token);
246 token = MONO_TOKEN_TYPE_DEF + decode_value (buf, &buf);
247 rank = decode_value (buf, &buf);
248 klass = mono_class_get (image, token);
250 klass = mono_array_class_get (klass, rank);
253 mono_class_init (klass);
259 static MonoClassField*
260 decode_field_info (MonoAotModule *module, guint8 *buf, guint8 **endbuf)
262 MonoClass *klass = decode_klass_info (module, buf, &buf);
268 token = MONO_TOKEN_FIELD_DEF + decode_value (buf, &buf);
272 return mono_class_get_field (klass, token);
275 static inline MonoImage*
276 decode_method_ref (MonoAotModule *module, guint32 *token, guint8 *buf, guint8 **endbuf)
278 guint32 image_index, value;
281 value = decode_value (buf, &buf);
283 image_index = value >> 24;
284 *token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
286 image = load_image (module, image_index);
295 make_writable (guint8* addr, guint32 len)
297 #ifndef PLATFORM_WIN32
301 page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1));
302 pages = (addr + len - page_start + PAGESIZE - 1) / PAGESIZE;
303 err = mprotect (page_start, pages * PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
308 g_assert (VirtualProtect (addr, len, PAGE_EXECUTE_READWRITE, &oldp) != 0);
314 create_cache_structure (void)
320 home = g_get_home_dir ();
324 tmp = g_build_filename (home, ".mono", NULL);
325 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
326 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
327 #ifdef PLATFORM_WIN32
330 err = mkdir (tmp, 0777);
333 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
339 tmp = g_build_filename (home, ".mono", "aot-cache", NULL);
340 if (!g_file_test (tmp, G_FILE_TEST_IS_DIR)) {
341 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT creating directory %s", tmp);
342 #ifdef PLATFORM_WIN32
345 err = mkdir (tmp, 0777);
348 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed: %s", g_strerror (errno));
357 * load_aot_module_from_cache:
359 * Experimental code to AOT compile loaded assemblies on demand.
362 * - Add environment variable MONO_AOT_CACHE_OPTIONS
363 * - Add options for controlling the cache size
364 * - Handle full cache by deleting old assemblies lru style
365 * - Add options for excluding assemblies during development
366 * - Maybe add a threshold after an assembly is AOT compiled
367 * - invoking a new mono process is a security risk
370 load_aot_module_from_cache (MonoAssembly *assembly, char **aot_name)
372 char *fname, *cmd, *tmp2;
380 if (assembly->image->dynamic)
383 create_cache_structure ();
385 home = g_get_home_dir ();
387 tmp2 = g_strdup_printf ("%s-%s%s", assembly->image->assembly_name, assembly->image->guid, SHARED_EXT);
388 fname = g_build_filename (home, ".mono", "aot-cache", tmp2, NULL);
392 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT trying to load from cache: '%s'.", fname);
393 module = g_module_open (fname, G_MODULE_BIND_LAZY);
396 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT not found.");
398 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT precompiling assembly '%s'... ", assembly->image->name);
400 /* FIXME: security */
401 cmd = g_strdup_printf ("mono -O=all --aot=outfile=%s %s", fname, assembly->image->name);
403 res = g_spawn_command_line_sync (cmd, &out, &err, NULL, NULL);
406 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT failed.");
410 mono_trace (G_LOG_LEVEL_MESSAGE, MONO_TRACE_AOT, "AOT succeeded.");
412 module = g_module_open (fname, G_MODULE_BIND_LAZY);
419 load_aot_module (MonoAssembly *assembly, gpointer user_data)
423 gboolean usable = TRUE;
424 char *saved_guid = NULL;
425 char *aot_version = NULL;
426 char *opt_flags = NULL;
428 #ifdef MONO_ARCH_HAVE_PIC_AOT
429 gpointer *got_addr = NULL;
430 gpointer *got = NULL;
431 guint32 *got_size_ptr = NULL;
434 if (mono_compile_aot)
438 assembly->aot_module = load_aot_module_from_cache (assembly, &aot_name);
440 aot_name = g_strdup_printf ("%s%s", assembly->image->name, SHARED_EXT);
442 assembly->aot_module = g_module_open (aot_name, G_MODULE_BIND_LAZY);
444 if (!assembly->aot_module) {
445 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT failed to load AOT module %s: %s\n", aot_name, g_module_error ());
449 if (!assembly->aot_module) {
454 g_module_symbol (assembly->aot_module, "mono_assembly_guid", (gpointer *) &saved_guid);
455 g_module_symbol (assembly->aot_module, "mono_aot_version", (gpointer *) &aot_version);
456 g_module_symbol (assembly->aot_module, "mono_aot_opt_flags", (gpointer *)&opt_flags);
458 if (!aot_version || strcmp (aot_version, MONO_AOT_FILE_VERSION)) {
459 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);
463 if (!saved_guid || strcmp (assembly->image->guid, saved_guid)) {
464 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module %s is out of date.\n", aot_name);
471 g_module_close (assembly->aot_module);
472 assembly->aot_module = NULL;
476 #ifdef MONO_ARCH_HAVE_PIC_AOT
477 g_module_symbol (assembly->aot_module, "got_addr", (gpointer *)&got_addr);
479 got = (gpointer*)*got_addr;
481 g_module_symbol (assembly->aot_module, "got_size", (gpointer *)&got_size_ptr);
482 g_assert (got_size_ptr);
485 info = g_new0 (MonoAotModule, 1);
486 info->aot_name = aot_name;
487 #ifdef MONO_ARCH_HAVE_PIC_AOT
489 info->got_size = *got_size_ptr;
490 info->got [0] = assembly->image;
492 sscanf (opt_flags, "%d", &info->opts);
494 /* Read image table */
496 guint32 table_len, i;
499 g_module_symbol (assembly->aot_module, "mono_image_table", (gpointer *)&table);
502 table_len = *(guint32*)table;
503 table += sizeof (guint32);
504 info->image_table = g_new0 (MonoImage*, table_len);
505 info->image_names = g_new0 (MonoAssemblyName, table_len);
506 info->image_guids = g_new0 (char*, table_len);
507 for (i = 0; i < table_len; ++i) {
508 MonoAssemblyName *aname = &(info->image_names [i]);
510 aname->name = g_strdup (table);
511 table += strlen (table) + 1;
512 info->image_guids [i] = g_strdup (table);
513 table += strlen (table) + 1;
515 aname->culture = g_strdup (table);
516 table += strlen (table) + 1;
517 memcpy (aname->public_key_token, table, strlen (table) + 1);
518 table += strlen (table) + 1;
520 table = ALIGN_PTR_TO (table, 8);
521 aname->flags = *(guint32*)table;
523 aname->major = *(guint32*)table;
525 aname->minor = *(guint32*)table;
527 aname->build = *(guint32*)table;
529 aname->revision = *(guint32*)table;
534 /* Read icall table */
536 guint32 table_len, i;
539 g_module_symbol (assembly->aot_module, "mono_icall_table", (gpointer *)&table);
542 table_len = *(guint32*)table;
543 table += sizeof (guint32);
544 info->icall_table = g_new0 (char*, table_len);
545 for (i = 0; i < table_len; ++i) {
546 info->icall_table [i] = table;
547 table += strlen (table) + 1;
551 /* Read method and method_info tables */
552 g_module_symbol (assembly->aot_module, "method_offsets", (gpointer*)&info->code_offsets);
553 g_module_symbol (assembly->aot_module, "methods", (gpointer*)&info->code);
554 g_module_symbol (assembly->aot_module, "methods_end", (gpointer*)&info->code_end);
555 g_module_symbol (assembly->aot_module, "method_info_offsets", (gpointer*)&info->method_info_offsets);
556 g_module_symbol (assembly->aot_module, "method_infos", (gpointer*)&info->method_infos);
557 g_module_symbol (assembly->aot_module, "ex_info_offsets", (gpointer*)&info->ex_info_offsets);
558 g_module_symbol (assembly->aot_module, "ex_infos", (gpointer*)&info->ex_infos);
559 g_module_symbol (assembly->aot_module, "method_order", (gpointer*)&info->method_order);
560 g_module_symbol (assembly->aot_module, "method_order_end", (gpointer*)&info->method_order_end);
561 g_module_symbol (assembly->aot_module, "class_infos", (gpointer*)&info->class_infos);
562 g_module_symbol (assembly->aot_module, "class_info_offsets", (gpointer*)&info->class_info_offsets);
563 g_module_symbol (assembly->aot_module, "mem_end", (gpointer*)&info->mem_end);
565 info->mem_begin = info->code;
567 if (make_unreadable) {
568 #ifndef PLATFORM_WIN32
573 addr = info->mem_begin;
574 len = info->mem_end - info->mem_begin;
576 /* Round down in both directions to avoid modifying data which is not ours */
577 page_start = (guint8 *) (((gssize) (addr)) & ~ (PAGESIZE - 1)) + PAGESIZE;
578 pages = ((addr + len - page_start + PAGESIZE - 1) / PAGESIZE) - 1;
579 err = mprotect (page_start, pages * PAGESIZE, 0);
585 g_hash_table_insert (aot_modules, assembly, info);
588 mono_jit_info_add_aot_module (assembly->image, info->code, info->code_end);
590 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT loaded AOT Module for %s.\n", assembly->image->name);
596 InitializeCriticalSection (&aot_mutex);
597 aot_modules = g_hash_table_new (NULL, NULL);
599 mono_install_assembly_load_hook (load_aot_module, NULL);
601 if (getenv ("MONO_LASTAOT"))
602 mono_last_aot_method = atoi (getenv ("MONO_LASTAOT"));
603 if (getenv ("MONO_AOT_CACHE"))
604 use_aot_cache = TRUE;
608 decode_cached_class_info (MonoAotModule *module, MonoCachedClassInfo *info, guint8 *buf, guint8 **endbuf)
612 info->vtable_size = decode_value (buf, &buf);
613 flags = decode_value (buf, &buf);
614 info->ghcimpl = (flags >> 0) & 0x1;
615 info->has_finalize = (flags >> 1) & 0x1;
616 info->has_cctor = (flags >> 2) & 0x1;
617 info->has_nested_classes = (flags >> 3) & 0x1;
618 info->blittable = (flags >> 4) & 0x1;
619 info->has_references = (flags >> 5) & 0x1;
620 info->has_static_refs = (flags >> 6) & 0x1;
621 info->no_special_static_fields = (flags >> 7) & 0x1;
623 if (info->has_cctor) {
624 MonoImage *cctor_image = decode_method_ref (module, &info->cctor_token, buf, &buf);
628 if (info->has_finalize) {
629 info->finalize_image = decode_method_ref (module, &info->finalize_token, buf, &buf);
630 if (!info->finalize_image)
634 info->instance_size = decode_value (buf, &buf);
635 info->class_size = decode_value (buf, &buf);
636 info->packing_size = decode_value (buf, &buf);
637 info->min_align = decode_value (buf, &buf);
645 mono_aot_init_vtable (MonoVTable *vtable)
648 MonoAotModule *aot_module;
649 MonoClass *klass = vtable->klass;
651 MonoCachedClassInfo class_info;
654 if (MONO_CLASS_IS_INTERFACE (klass) || klass->rank || !klass->image->assembly->aot_module)
659 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
665 info = &aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
668 err = decode_cached_class_info (aot_module, &class_info, p, &p);
674 //printf ("VT0: %s.%s %d\n", klass->name_space, klass->name, vtable_size);
675 for (i = 0; i < class_info.vtable_size; ++i) {
676 guint32 image_index, token, value;
678 #ifndef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
682 vtable->vtable [i] = 0;
684 value = decode_value (p, &p);
688 image_index = value >> 24;
689 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
691 image = load_image (aot_module, image_index);
697 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
698 vtable->vtable [i] = mono_create_jit_trampoline_from_token (image, token);
700 m = mono_get_method (image, token, NULL);
703 //printf ("M: %d %p %s\n", i, &(vtable->vtable [i]), mono_method_full_name (m, TRUE));
704 vtable->vtable [i] = mono_create_jit_trampoline (m);
714 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
716 MonoAotModule *aot_module;
720 if (klass->rank || !klass->image->assembly->aot_module)
725 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, klass->image->assembly);
731 p = (guint8*)&aot_module->class_infos [aot_module->class_info_offsets [mono_metadata_token_index (klass->type_token) - 1]];
733 err = decode_cached_class_info (aot_module, res, p, &p);
745 decode_exception_debug_info (MonoAotModule *aot_module, MonoDomain *domain,
746 MonoMethod *method, guint8* ex_info, guint8 *code)
750 guint code_len, used_int_regs;
752 MonoMethodHeader *header;
754 header = mono_method_get_header (method);
756 /* Load the method info from the AOT file */
759 code_len = decode_value (p, &p);
760 used_int_regs = decode_value (p, &p);
762 /* Exception table */
763 if (header->num_clauses) {
765 mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo) + (sizeof (MonoJitExceptionInfo) * header->num_clauses));
766 jinfo->num_clauses = header->num_clauses;
768 for (i = 0; i < header->num_clauses; ++i) {
769 MonoExceptionClause *ec = &header->clauses [i];
770 MonoJitExceptionInfo *ei = &jinfo->clauses [i];
772 ei->flags = ec->flags;
773 ei->exvar_offset = decode_value (p, &p);
775 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
776 ei->data.filter = code + decode_value (p, &p);
778 ei->data.catch_class = ec->data.catch_class;
780 ei->try_start = code + decode_value (p, &p);
781 ei->try_end = code + decode_value (p, &p);
782 ei->handler_start = code + decode_value (p, &p);
786 jinfo = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
788 jinfo->code_size = code_len;
789 jinfo->used_regs = used_int_regs;
790 jinfo->method = method;
791 jinfo->code_start = code;
792 #ifdef MONO_ARCH_HAVE_PIC_AOT
793 jinfo->domain_neutral = 0;
795 jinfo->domain_neutral = (aot_module->opts & MONO_OPT_SHARED) != 0;
798 /* Load debug info */
799 buf_len = decode_value (p, &p);
800 mono_debug_add_aot_method (domain, method, code, p, buf_len);
806 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
808 MonoAssembly *ass = image->assembly;
809 GModule *module = ass->aot_module;
810 int pos, left, right, offset, offset1, offset2, last_offset, new_offset, page_index, method_index, table_len;
812 MonoAotModule *aot_module;
815 guint8 *code, *ex_info;
816 guint32 *table, *ptr;
822 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
824 if (domain != mono_get_root_domain ())
828 offset = (guint8*)addr - aot_module->code;
830 /* First search through the index */
831 ptr = aot_module->method_order;
836 if (*ptr == 0xffffff)
840 while (*ptr != 0xffffff) {
841 guint32 method_index = ptr [0];
842 new_offset = aot_module->code_offsets [method_index];
844 if (offset >= last_offset && offset < new_offset) {
850 last_offset = new_offset;
854 /* Skip rest of index */
855 while (*ptr != 0xffffff)
860 table_len = aot_module->method_order_end - table;
862 g_assert (table <= aot_module->method_order_end);
865 left = (page_index * 1024);
868 if (right > table_len)
871 offset1 = aot_module->code_offsets [table [left]];
872 g_assert (offset1 <= offset);
874 //printf ("Found in index: 0x%x 0x%x 0x%x\n", offset, last_offset, new_offset);
877 //printf ("Not found in index: 0x%x\n", offset);
882 /* Binary search inside the method_order table to find the method */
884 pos = (left + right) / 2;
886 g_assert (table + pos <= aot_module->method_order_end);
888 //printf ("Pos: %5d < %5d < %5d Offset: 0x%05x < 0x%05x < 0x%05x\n", left, pos, right, aot_module->code_offsets [table [left]], offset, aot_module->code_offsets [table [right]]);
890 offset1 = aot_module->code_offsets [table [pos]];
891 if (table + pos + 1 >= aot_module->method_order_end)
892 offset2 = aot_module->code_end - aot_module->code;
894 offset2 = aot_module->code_offsets [table [pos + 1]];
896 if (offset < offset1)
898 else if (offset >= offset2)
904 method_index = table [pos];
906 token = mono_metadata_make_token (MONO_TABLE_METHOD, method_index + 1);
907 method = mono_get_method (image, token, NULL);
912 //printf ("F: %s\n", mono_method_full_name (method, TRUE));
914 code = &aot_module->code [aot_module->code_offsets [method_index]];
915 ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [method_index]];
917 jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
919 g_assert ((guint8*)addr >= (guint8*)jinfo->code_start);
920 g_assert ((guint8*)addr < (guint8*)jinfo->code_start + jinfo->code_size);
922 /* Add it to the normal JitInfo tables */
923 mono_jit_info_table_add (domain, jinfo);
929 load_patch_info (MonoAotModule *aot_module, MonoMemPool *mp, int n_patches,
930 guint32 got_index, guint32 **got_slots,
931 guint8 *buf, guint8 **endbuf)
933 MonoJumpInfo *patches;
934 MonoJumpInfo *patch_info;
943 /* First load the type + offset table */
945 patches = mono_mempool_alloc (mp, sizeof (MonoJumpInfo) * n_patches);
947 for (pindex = 0; pindex < n_patches; ++pindex) {
948 MonoJumpInfo *ji = &patches [pindex];
950 #if defined(MONO_ARCH_HAVE_PIC_AOT)
957 b2 = *((guint8*)p + 1);
962 if (((b1 & (1 + 2)) == 3) && (b2 == 255))
963 ji->ip.i = decode_value (p, &p);
965 ji->ip.i = (((guint32)(b1 & (1 + 2))) << 8) + b2;
967 ji->ip.i += last_offset;
968 last_offset = ji->ip.i;
970 //printf ("T: %d O: %d.\n", ji->type, ji->ip.i);
971 ji->next = patch_info;
975 *got_slots = g_malloc (sizeof (guint32) * n_patches);
976 memset (*got_slots, 0xff, sizeof (guint32) * n_patches);
978 /* Then load the other data */
979 for (pindex = 0; pindex < n_patches; ++pindex) {
980 MonoJumpInfo *ji = &patches [pindex];
983 case MONO_PATCH_INFO_CLASS:
984 case MONO_PATCH_INFO_IID:
985 case MONO_PATCH_INFO_VTABLE:
986 case MONO_PATCH_INFO_CLASS_INIT:
987 ji->data.klass = decode_klass_info (aot_module, p, &p);
991 case MONO_PATCH_INFO_IMAGE:
992 ji->data.image = load_image (aot_module, decode_value (p, &p));
996 case MONO_PATCH_INFO_METHOD:
997 case MONO_PATCH_INFO_METHODCONST:
998 case MONO_PATCH_INFO_METHOD_JUMP: {
999 guint32 image_index, token, value;
1001 value = decode_value (p, &p);
1002 image_index = value >> 24;
1003 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
1005 image = load_image (aot_module, image_index);
1009 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
1010 if (ji->type == MONO_PATCH_INFO_METHOD) {
1011 ji->data.target = mono_create_jit_trampoline_from_token (image, token);
1012 ji->type = MONO_PATCH_INFO_ABS;
1015 ji->data.method = mono_get_method (image, token, NULL);
1016 g_assert (ji->data.method);
1017 mono_class_init (ji->data.method->klass);
1020 ji->data.method = mono_get_method (image, token, NULL);
1021 g_assert (ji->data.method);
1022 mono_class_init (ji->data.method->klass);
1027 case MONO_PATCH_INFO_WRAPPER: {
1028 guint32 wrapper_type;
1030 wrapper_type = decode_value (p, &p);
1032 switch (wrapper_type) {
1033 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
1034 guint32 image_index, token, value;
1036 value = decode_value (p, &p);
1037 image_index = value >> 24;
1038 token = MONO_TOKEN_METHOD_DEF | (value & 0xffffff);
1040 image = load_image (aot_module, image_index);
1043 ji->data.method = mono_get_method (image, token, NULL);
1044 g_assert (ji->data.method);
1045 mono_class_init (ji->data.method->klass);
1047 ji->type = MONO_PATCH_INFO_METHOD;
1048 ji->data.method = mono_marshal_get_remoting_invoke_with_check (ji->data.method);
1051 case MONO_WRAPPER_PROXY_ISINST: {
1052 MonoClass *klass = decode_klass_info (aot_module, p, &p);
1055 ji->type = MONO_PATCH_INFO_METHOD;
1056 ji->data.method = mono_marshal_get_proxy_cancast (klass);
1059 case MONO_WRAPPER_LDFLD:
1060 case MONO_WRAPPER_LDFLDA:
1061 case MONO_WRAPPER_STFLD:
1062 case MONO_WRAPPER_LDFLD_REMOTE:
1063 case MONO_WRAPPER_STFLD_REMOTE:
1064 case MONO_WRAPPER_ISINST: {
1065 MonoClass *klass = decode_klass_info (aot_module, p, &p);
1068 ji->type = MONO_PATCH_INFO_METHOD;
1069 if (wrapper_type == MONO_WRAPPER_LDFLD)
1070 ji->data.method = mono_marshal_get_ldfld_wrapper (&klass->byval_arg);
1071 else if (wrapper_type == MONO_WRAPPER_LDFLDA)
1072 ji->data.method = mono_marshal_get_ldflda_wrapper (&klass->byval_arg);
1073 else if (wrapper_type == MONO_WRAPPER_STFLD)
1074 ji->data.method = mono_marshal_get_stfld_wrapper (&klass->byval_arg);
1075 else if (wrapper_type == MONO_WRAPPER_LDFLD_REMOTE)
1076 ji->data.method = mono_marshal_get_ldfld_remote_wrapper (klass);
1077 else if (wrapper_type == MONO_WRAPPER_STFLD_REMOTE)
1078 ji->data.method = mono_marshal_get_stfld_remote_wrapper (klass);
1079 else if (wrapper_type == MONO_WRAPPER_ISINST)
1080 ji->data.method = mono_marshal_get_isinst (klass);
1082 g_assert_not_reached ();
1085 case MONO_WRAPPER_STELEMREF:
1086 ji->type = MONO_PATCH_INFO_METHOD;
1087 ji->data.method = mono_marshal_get_stelemref ();
1090 g_assert_not_reached ();
1094 case MONO_PATCH_INFO_FIELD:
1095 case MONO_PATCH_INFO_SFLDA:
1096 ji->data.field = decode_field_info (aot_module, p, &p);
1097 if (!ji->data.field)
1100 case MONO_PATCH_INFO_INTERNAL_METHOD: {
1101 guint32 icall_index = decode_value (p, &p);
1103 ji->data.name = aot_module->icall_table [icall_index];
1104 g_assert (ji->data.name);
1106 #if MONO_ARCH_HAVE_PIC_AOT
1107 /* GOT entries for icalls are at the start of the got */
1108 (*got_slots) [pindex] = ICALL_GOT_SLOTS_START_INDEX + icall_index;
1112 case MONO_PATCH_INFO_SWITCH:
1113 ji->data.table = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoBBTable));
1114 ji->data.table->table_size = decode_value (p, &p);
1115 table = g_new (gpointer, ji->data.table->table_size);
1116 ji->data.table->table = (MonoBasicBlock**)table;
1117 for (i = 0; i < ji->data.table->table_size; i++)
1118 table [i] = (gpointer)(gssize)decode_value (p, &p);
1120 case MONO_PATCH_INFO_R4: {
1123 ji->data.target = mono_mempool_alloc0 (mp, sizeof (float));
1124 val = decode_value (p, &p);
1125 *(float*)ji->data.target = *(float*)&val;
1128 case MONO_PATCH_INFO_R8: {
1131 ji->data.target = mono_mempool_alloc0 (mp, sizeof (double));
1133 val [0] = decode_value (p, &p);
1134 val [1] = decode_value (p, &p);
1135 *(double*)ji->data.target = *(double*)val;
1138 case MONO_PATCH_INFO_LDSTR:
1139 image = load_image (aot_module, decode_value (p, &p));
1142 ji->data.token = mono_jump_info_token_new (mp, image, MONO_TOKEN_STRING + decode_value (p, &p));
1144 case MONO_PATCH_INFO_DECLSEC:
1145 case MONO_PATCH_INFO_LDTOKEN:
1146 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
1147 image = load_image (aot_module, decode_value (p, &p));
1150 ji->data.token = mono_jump_info_token_new (mp, image, decode_value (p, &p));
1152 case MONO_PATCH_INFO_EXC_NAME:
1153 ji->data.klass = decode_klass_info (aot_module, p, &p);
1154 if (!ji->data.klass)
1156 ji->data.name = ji->data.klass->name;
1158 case MONO_PATCH_INFO_METHOD_REL:
1159 ji->data.offset = decode_value (p, &p);
1162 g_warning ("unhandled type %d", ji->type);
1163 g_assert_not_reached ();
1166 #if MONO_ARCH_HAVE_PIC_AOT
1167 if ((*got_slots) [pindex] == 0xffffffff)
1168 (*got_slots) [pindex] = got_index ++;
1176 g_free (*got_slots);
1182 static MonoJitInfo *
1183 mono_aot_get_method_inner (MonoDomain *domain, MonoMethod *method)
1185 MonoClass *klass = method->klass;
1186 MonoAssembly *ass = klass->image->assembly;
1187 GModule *module = ass->aot_module;
1188 guint8 *code, *info, *ex_info;
1189 MonoAotModule *aot_module;
1197 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1200 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
1201 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
1202 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
1203 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
1206 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1208 g_assert (klass->inited);
1210 if ((domain != mono_get_root_domain ()) && (!(aot_module->opts & MONO_OPT_SHARED)))
1211 /* Non shared AOT code can't be used in other appdomains */
1214 if (aot_module->out_of_date)
1217 if (aot_module->code_offsets [mono_metadata_token_index (method->token) - 1] == 0xffffffff) {
1218 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1219 char *full_name = mono_method_full_name (method, TRUE);
1220 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT NOT FOUND: %s.\n", full_name);
1226 code = &aot_module->code [aot_module->code_offsets [mono_metadata_token_index (method->token) - 1]];
1227 info = &aot_module->method_infos [aot_module->method_info_offsets [mono_metadata_token_index (method->token) - 1]];
1228 ex_info = &aot_module->ex_infos [aot_module->ex_info_offsets [mono_metadata_token_index (method->token) - 1]];
1230 if (mono_last_aot_method != -1) {
1231 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1234 if (mono_jit_stats.methods_aot == mono_last_aot_method)
1235 printf ("LAST AOT METHOD: %s.%s.%s.\n", klass->name_space, klass->name, method->name);
1238 return mono_aot_load_method (domain, aot_module, method, code, info, ex_info);
1242 mono_aot_load_method (MonoDomain *domain, MonoAotModule *aot_module, MonoMethod *method, guint8 *code, guint8 *info, guint8* ex_info)
1244 MonoClass *klass = method->klass;
1245 MonoJumpInfo *patch_info = NULL;
1248 int i, pindex, got_index, n_patches, used_strings;
1249 gboolean non_got_patches, keep_patches = TRUE;
1252 jinfo = decode_exception_debug_info (aot_module, domain, method, ex_info, code);
1255 decode_klass_info (aot_module, p, &p);
1257 if (!use_loaded_code) {
1259 code2 = mono_code_manager_reserve (domain->code_mp, jinfo->code_size);
1260 memcpy (code2, code, jinfo->code_size);
1261 mono_arch_flush_icache (code2, jinfo->code_size);
1265 if (aot_module->opts & MONO_OPT_SHARED)
1266 used_strings = decode_value (p, &p);
1270 for (i = 0; i < used_strings; i++) {
1271 guint token = decode_value (p, &p);
1272 mono_ldstr (mono_get_root_domain (), klass->image, mono_metadata_token_index (token));
1275 if (aot_module->opts & MONO_OPT_SHARED)
1276 keep_patches = FALSE;
1278 #ifdef MONO_ARCH_HAVE_PIC_AOT
1279 got_index = decode_value (p, &p);
1280 keep_patches = FALSE;
1283 n_patches = decode_value (p, &p);
1286 MonoJumpInfo *patches;
1292 mp = mono_mempool_new ();
1294 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1295 if (patches == NULL)
1298 #if MONO_ARCH_HAVE_PIC_AOT
1299 /* Do this outside the lock to avoid deadlocks */
1301 non_got_patches = FALSE;
1302 for (pindex = 0; pindex < n_patches; ++pindex) {
1303 MonoJumpInfo *ji = &patches [pindex];
1305 if (is_got_patch (ji->type)) {
1306 if (!aot_module->got [got_slots [pindex]])
1307 aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (method, domain, code, ji, TRUE);
1308 ji->type = MONO_PATCH_INFO_NONE;
1311 non_got_patches = TRUE;
1313 if (non_got_patches) {
1314 mono_arch_flush_icache (code, jinfo->code_size);
1315 make_writable (code, jinfo->code_size);
1316 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1320 if (use_loaded_code)
1321 /* disable write protection */
1322 make_writable (code, jinfo->code_size);
1324 /* Do this outside the lock to avoid deadlocks */
1326 mono_arch_patch_code (method, domain, code, patch_info, TRUE);
1332 mono_mempool_destroy (mp);
1335 mono_jit_stats.methods_aot++;
1337 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1338 char *full_name = mono_method_full_name (method, TRUE);
1339 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);
1346 /* FIXME: The space in domain->mp is wasted */
1347 if (aot_module->opts & MONO_OPT_SHARED)
1348 /* No need to cache patches */
1349 mono_mempool_destroy (mp);
1355 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
1360 info = mono_aot_get_method_inner (domain, method);
1363 /* Do this outside the lock */
1365 mono_jit_info_table_add (domain, info);
1373 mono_aot_get_method_from_token_inner (MonoDomain *domain, MonoImage *image, guint32 token, MonoClass **klass)
1375 MonoAssembly *ass = image->assembly;
1377 int i, method_index, pindex, got_index, n_patches, used_strings;
1378 gboolean keep_patches = TRUE;
1380 GModule *module = ass->aot_module;
1381 guint8 *code = NULL;
1383 MonoAotModule *aot_module;
1390 if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE)
1393 aot_module = (MonoAotModule*) g_hash_table_lookup (aot_modules, ass);
1395 if (domain != mono_get_root_domain ())
1398 if (aot_module->out_of_date)
1401 if (aot_module->code_offsets [mono_metadata_token_index (token) - 1] == 0xffffffff) {
1405 method_index = mono_metadata_token_index (token) - 1;
1406 code = &aot_module->code [aot_module->code_offsets [method_index]];
1407 info = &aot_module->method_infos [aot_module->method_info_offsets [method_index]];
1409 if (mono_last_aot_method != -1) {
1410 if (mono_jit_stats.methods_aot > mono_last_aot_method)
1413 if (mono_jit_stats.methods_aot == mono_last_aot_method) {
1414 MonoMethod *method = mono_get_method (image, token, NULL);
1415 printf ("LAST AOT METHOD: %s.%s.%s.\n", method->klass->name_space, method->klass->name, method->name);
1419 if (!aot_module->methods_loaded)
1420 aot_module->methods_loaded = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 1);
1422 if ((aot_module->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
1425 aot_module->methods_loaded [method_index / 32] |= 1 << (method_index % 32);
1428 *klass = decode_klass_info (aot_module, p, &p);
1430 if (mono_trace_is_traced (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT)) {
1431 MonoMethod *method = mono_get_method (image, token, NULL);
1432 char *full_name = mono_method_full_name (method, TRUE);
1433 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_AOT, "AOT FOUND AOT compiled code for %s %p %p\n", full_name, code, info);
1437 if (aot_module->opts & MONO_OPT_SHARED)
1438 used_strings = decode_value (p, &p);
1442 for (i = 0; i < used_strings; i++) {
1443 guint string_token = decode_value (p, &p);
1444 mono_ldstr (mono_get_root_domain (), image, mono_metadata_token_index (string_token));
1447 if (aot_module->opts & MONO_OPT_SHARED)
1448 keep_patches = FALSE;
1450 got_index = decode_value (p, &p);
1451 keep_patches = FALSE;
1453 n_patches = decode_value (p, &p);
1456 MonoJumpInfo *patches;
1462 mp = mono_mempool_new ();
1464 patches = load_patch_info (aot_module, mp, n_patches, got_index, &got_slots, p, &p);
1465 if (patches == NULL)
1468 /* Do this outside the lock to avoid deadlocks */
1471 for (pindex = 0; pindex < n_patches; ++pindex) {
1472 MonoJumpInfo *ji = &patches [pindex];
1474 if (is_got_patch (ji->type)) {
1475 if (!aot_module->got [got_slots [pindex]])
1476 aot_module->got [got_slots [pindex]] = mono_resolve_patch_target (NULL, domain, code, ji, TRUE);
1477 ji->type = MONO_PATCH_INFO_NONE;
1486 mono_mempool_destroy (mp);
1489 mono_jit_stats.methods_aot++;
1494 /* FIXME: The space in domain->mp is wasted */
1495 if (aot_module->opts & MONO_OPT_SHARED)
1496 /* No need to cache patches */
1497 mono_mempool_destroy (mp);
1503 * Same as mono_aot_get_method, but we try to avoid loading any metadata from the
1507 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
1513 res = mono_aot_get_method_from_token_inner (domain, image, token, &klass);
1520 mono_runtime_class_init (mono_class_vtable (domain, klass));
1528 } IsGotEntryUserData;
1531 check_is_got_entry (gpointer key, gpointer value, gpointer user_data)
1533 IsGotEntryUserData *data = (IsGotEntryUserData*)user_data;
1534 MonoAotModule *aot_module = (MonoAotModule*)value;
1536 if (aot_module->got && (data->addr >= (guint8*)(aot_module->got)) && (data->addr < (guint8*)(aot_module->got + aot_module->got_size)))
1541 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
1543 IsGotEntryUserData user_data;
1548 user_data.addr = addr;
1549 user_data.res = FALSE;
1551 g_hash_table_foreach (aot_modules, check_is_got_entry, &user_data);
1554 return user_data.res;
1558 * mono_aot_set_make_unreadable:
1560 * Set whenever to make all mmaped memory unreadable. In conjuction with a
1561 * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
1564 mono_aot_set_make_unreadable (gboolean unreadable)
1566 make_unreadable = unreadable;
1570 MonoAotModule *module;
1575 find_map (gpointer key, gpointer value, gpointer user_data)
1577 MonoAotModule *module = (MonoAotModule*)value;
1578 FindMapUserData *data = (FindMapUserData*)user_data;
1581 if ((data->ptr >= module->mem_begin) && (data->ptr < module->mem_end))
1582 data->module = module;
1585 static MonoAotModule*
1586 find_module_for_addr (void *ptr)
1588 FindMapUserData data;
1590 if (!make_unreadable)
1594 data.ptr = (guint8*)ptr;
1597 g_hash_table_foreach (aot_modules, (GHFunc)find_map, &data);
1604 * mono_aot_is_pagefault:
1606 * Should be called from a SIGSEGV signal handler to find out whenever @ptr is
1607 * within memory allocated by this module.
1610 mono_aot_is_pagefault (void *ptr)
1612 if (!make_unreadable)
1615 return find_module_for_addr (ptr) != NULL;
1619 * mono_aot_handle_pagefault:
1621 * Handle a pagefault caused by an unreadable page by making it readable again.
1624 mono_aot_handle_pagefault (void *ptr)
1626 #ifndef PLATFORM_WIN32
1627 guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), PAGESIZE);
1631 res = mprotect (start, PAGESIZE, PROT_READ|PROT_WRITE|PROT_EXEC);
1632 g_assert (res == 0);
1640 * mono_aot_get_n_pagefaults:
1642 * Return the number of times handle_pagefault is called.
1645 mono_aot_get_n_pagefaults (void)
1647 return n_pagefaults;
1650 /*****************************************************/
1652 /*****************************************************/
1655 emit_section_change (FILE *fp, const char *section_name, int subsection_index)
1657 #if defined(PLATFORM_WIN32)
1658 fprintf (fp, ".section %s\n", section_name);
1659 #elif defined(sparc)
1660 /* For solaris as, GNU as should accept the same */
1661 fprintf (fp, ".section \"%s\"\n", section_name);
1662 #elif defined(__ppc__) && defined(__MACH__)
1663 /* This needs to be made more precise on mach. */
1664 fprintf (fp, "%s\n", subsection_index == 0 ? ".text" : ".data");
1666 fprintf (fp, "%s %d\n", section_name, subsection_index);
1671 emit_symbol_type (FILE *fp, const char *name, gboolean func)
1681 fprintf (fp, "\t.type %s,#%s\n", name, stype);
1682 #elif defined(PLATFORM_WIN32)
1684 #elif !(defined(__ppc__) && defined(__MACH__))
1685 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1686 #elif defined(__x86_64__) || defined(__i386__)
1687 fprintf (fp, "\t.type %s,@%s\n", name, stype);
1692 emit_global (FILE *fp, const char *name, gboolean func)
1694 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1695 // mach-o always uses a '_' prefix.
1696 fprintf (fp, "\t.globl _%s\n", name);
1698 fprintf (fp, "\t.globl %s\n", name);
1701 emit_symbol_type (fp, name, func);
1705 emit_label (FILE *fp, const char *name)
1707 #if (defined(__ppc__) && defined(__MACH__)) || defined(PLATFORM_WIN32)
1708 // mach-o always uses a '_' prefix.
1709 fprintf (fp, "_%s:\n", name);
1711 fprintf (fp, "%s:\n", name);
1714 #if defined(PLATFORM_WIN32)
1715 /* Emit a normal label too */
1716 fprintf (fp, "%s:\n", name);
1721 emit_string_symbol (FILE *fp, const char *name, const char *value)
1723 emit_section_change (fp, ".text", 1);
1724 emit_global(fp, name, FALSE);
1725 emit_label(fp, name);
1726 fprintf (fp, "\t%s \"%s\"\n", AS_STRING_DIRECTIVE, value);
1729 #if defined(__ppc__) && defined(__MACH__)
1731 ilog2(register int value)
1734 while (value & ~0xf) count += 4, value >>= 4;
1735 while (value) count++, value >>= 1;
1741 emit_alignment(FILE *fp, int size)
1743 #if defined(__ppc__) && defined(__MACH__)
1744 // the mach-o assembler specifies alignments as powers of 2.
1745 fprintf (fp, "\t.align %d\t; ilog2\n", ilog2(size));
1746 #elif defined(__powerpc__)
1747 /* ignore on linux/ppc */
1749 fprintf (fp, "\t.align %d\n", size);
1753 G_GNUC_UNUSED static void
1754 emit_pointer (FILE *fp, const char *target)
1756 emit_alignment (fp, sizeof (gpointer));
1757 #if defined(__x86_64__)
1758 fprintf (fp, "\t.quad %s\n", target);
1759 #elif defined(sparc) && SIZEOF_VOID_P == 8
1760 fprintf (fp, "\t.xword %s\n", target);
1762 fprintf (fp, "\t.long %s\n", target);
1767 mono_get_field_token (MonoClassField *field)
1769 MonoClass *klass = field->parent;
1772 for (i = 0; i < klass->field.count; ++i) {
1773 if (field == &klass->fields [i])
1774 return MONO_TOKEN_FIELD_DEF | (klass->field.first + 1 + i);
1777 g_assert_not_reached ();
1782 encode_value (gint32 value, guint8 *buf, guint8 **endbuf)
1786 //printf ("ENCODE: %d 0x%x.\n", value, value);
1789 * Same encoding as the one used in the metadata, extended to handle values
1790 * greater than 0x1fffffff.
1792 if ((value >= 0) && (value <= 127))
1794 else if ((value >= 0) && (value <= 16383)) {
1795 p [0] = 0x80 | (value >> 8);
1796 p [1] = value & 0xff;
1798 } else if ((value >= 0) && (value <= 0x1fffffff)) {
1799 p [0] = (value >> 24) | 0xc0;
1800 p [1] = (value >> 16) & 0xff;
1801 p [2] = (value >> 8) & 0xff;
1802 p [3] = value & 0xff;
1807 p [1] = (value >> 24) & 0xff;
1808 p [2] = (value >> 16) & 0xff;
1809 p [3] = (value >> 8) & 0xff;
1810 p [4] = value & 0xff;
1818 get_image_index (MonoAotCompile *cfg, MonoImage *image)
1822 index = GPOINTER_TO_UINT (g_hash_table_lookup (cfg->image_hash, image));
1826 index = g_hash_table_size (cfg->image_hash);
1827 g_hash_table_insert (cfg->image_hash, image, GUINT_TO_POINTER (index + 1));
1828 g_ptr_array_add (cfg->image_table, image);
1834 encode_klass_info (MonoAotCompile *cfg, MonoClass *klass, guint8 *buf, guint8 **endbuf)
1836 if (!klass->type_token) {
1838 g_assert (klass->rank > 0);
1839 g_assert (klass->element_class->type_token);
1840 encode_value (MONO_TOKEN_TYPE_DEF, buf, &buf);
1841 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1842 g_assert (mono_metadata_token_code (klass->element_class->type_token) == MONO_TOKEN_TYPE_DEF);
1843 encode_value (klass->element_class->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1844 encode_value (klass->rank, buf, &buf);
1847 g_assert (mono_metadata_token_code (klass->type_token) == MONO_TOKEN_TYPE_DEF);
1848 encode_value (klass->type_token - MONO_TOKEN_TYPE_DEF, buf, &buf);
1849 encode_value (get_image_index (cfg, klass->image), buf, &buf);
1855 encode_field_info (MonoAotCompile *cfg, MonoClassField *field, guint8 *buf, guint8 **endbuf)
1857 guint32 token = mono_get_field_token (field);
1859 encode_klass_info (cfg, field->parent, buf, &buf);
1860 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_FIELD_DEF);
1861 encode_value (token - MONO_TOKEN_FIELD_DEF, buf, &buf);
1866 encode_method_ref (MonoAotCompile *acfg, MonoMethod *method, guint8 *buf, guint8 **endbuf)
1868 guint32 image_index = get_image_index (acfg, method->klass->image);
1869 guint32 token = method->token;
1870 g_assert (image_index < 256);
1871 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
1873 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), buf, &buf);
1878 compare_patches (gconstpointer a, gconstpointer b)
1882 i = (*(MonoJumpInfo**)a)->ip.i;
1883 j = (*(MonoJumpInfo**)b)->ip.i;
1895 get_got_slot (MonoAotCompile *acfg, MonoJumpInfo *patch_info)
1899 switch (patch_info->type) {
1900 case MONO_PATCH_INFO_IMAGE:
1901 if (patch_info->data.image == acfg->image)
1904 res = acfg->got_offset;
1905 acfg->got_offset ++;
1908 case MONO_PATCH_INFO_INTERNAL_METHOD:
1909 res = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_to_got_offset_hash, patch_info->data.name));
1912 res = acfg->got_offset;
1913 acfg->got_offset ++;
1921 collect_icalls (MonoAotCompile *acfg)
1924 MonoJumpInfo *patch_info;
1926 for (mindex = 0; mindex < acfg->nmethods; ++mindex) {
1929 cfg = acfg->cfgs [mindex];
1933 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
1934 switch (patch_info->type) {
1935 case MONO_PATCH_INFO_INTERNAL_METHOD:
1936 index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
1938 index = g_hash_table_size (acfg->icall_hash) + 1;
1939 g_hash_table_insert (acfg->icall_hash, (gpointer)patch_info->data.name,
1940 GUINT_TO_POINTER (index));
1941 g_ptr_array_add (acfg->icall_table, (gpointer)patch_info->data.name);
1943 /* Allocate a GOT slot */
1944 g_hash_table_insert (acfg->icall_to_got_offset_hash, (gpointer)patch_info->data.name, GUINT_TO_POINTER (acfg->got_offset));
1945 acfg->got_offset ++;
1956 emit_method_code (MonoAotCompile *acfg, MonoCompile *cfg)
1960 int i, j, pindex, byte_index;
1963 int func_alignment = 16;
1965 MonoJumpInfo *patch_info;
1966 MonoMethodHeader *header;
1967 #ifdef MONO_ARCH_HAVE_PIC_AOT
1973 method = cfg->method;
1974 code = cfg->native_code;
1975 header = mono_method_get_header (method);
1977 /* Make the labels local */
1978 symbol = g_strdup_printf (".Lm_%x", mono_metadata_token_index (method->token));
1980 emit_alignment(tmpfp, func_alignment);
1981 emit_label(tmpfp, symbol);
1982 if (acfg->aot_opts.write_symbols)
1983 emit_global (tmpfp, symbol, TRUE);
1985 if (cfg->verbose_level > 0)
1986 g_print ("Method %s emitted as %s\n", mono_method_full_name (method, TRUE), symbol);
1988 acfg->code_size += cfg->code_len;
1990 /* Sort relocations */
1991 patches = g_ptr_array_new ();
1992 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
1993 g_ptr_array_add (patches, patch_info);
1994 g_ptr_array_sort (patches, compare_patches);
1996 #ifdef MONO_ARCH_HAVE_PIC_AOT
1997 acfg->method_got_offsets [mono_metadata_token_index (method->token)] = acfg->got_offset;
1999 for (i = 0; i < cfg->code_len; i++) {
2001 for (pindex = 0; pindex < patches->len; ++pindex) {
2002 patch_info = g_ptr_array_index (patches, pindex);
2003 if (patch_info->ip.i == i)
2008 if (patch_info && (pindex < patches->len)) {
2009 switch (patch_info->type) {
2010 case MONO_PATCH_INFO_LABEL:
2011 case MONO_PATCH_INFO_BB:
2012 case MONO_PATCH_INFO_NONE:
2014 case MONO_PATCH_INFO_GOT_OFFSET: {
2015 guint32 offset = mono_arch_get_patch_offset (code + i);
2016 fprintf (tmpfp, "\n.byte ");
2017 for (j = 0; j < offset; ++j)
2018 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
2019 fprintf (tmpfp, "\n.int got - . + %d", offset);
2021 i += offset + 4 - 1;
2026 if (!is_got_patch (patch_info->type))
2029 got_slot = get_got_slot (acfg, patch_info);
2030 fprintf (tmpfp, "\n.byte ");
2031 for (j = 0; j < mono_arch_get_patch_offset (code + i); ++j)
2032 fprintf (tmpfp, "%s0x%x", (j == 0) ? "" : ",", (unsigned int) code [i + j]);
2034 fprintf (tmpfp, "\n.int got - . + %d", (unsigned int) ((got_slot * sizeof (gpointer)) - 4));
2035 #elif defined(__i386__)
2036 fprintf (tmpfp, "\n.int %d\n", (unsigned int) ((got_slot * sizeof (gpointer))));
2039 i += mono_arch_get_patch_offset (code + i) + 4 - 1;
2045 if (byte_index == 0)
2046 fprintf (tmpfp, "\n.byte ");
2047 fprintf (tmpfp, "%s0x%x", (byte_index == 0) ? "" : ",", (unsigned int) code [i]);
2048 byte_index = (byte_index + 1) % 32;
2054 for (i = 0; i < cfg->code_len; i++) {
2055 fprintf (tmpfp, ".byte 0x%x\n", (unsigned int) code [i]);
2058 fprintf (tmpfp, "\n");
2062 emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
2067 int i, j, pindex, buf_size, n_patches;
2071 MonoJumpInfo *patch_info;
2072 MonoMethodHeader *header;
2073 guint32 last_offset;
2075 #ifdef MONO_ARCH_HAVE_PIC_AOT
2076 guint32 first_got_offset;
2080 method = cfg->method;
2081 code = cfg->native_code;
2082 header = mono_method_get_header (method);
2084 /* Make the labels local */
2085 symbol = g_strdup_printf (".Lm_%x_p", mono_metadata_token_index (method->token));
2087 /* Sort relocations */
2088 patches = g_ptr_array_new ();
2089 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next)
2090 g_ptr_array_add (patches, patch_info);
2091 g_ptr_array_sort (patches, compare_patches);
2093 #ifdef MONO_ARCH_HAVE_PIC_AOT
2094 first_got_offset = acfg->method_got_offsets [mono_metadata_token_index (cfg->method->token)];
2097 /**********************/
2098 /* Encode method info */
2099 /**********************/
2101 buf_size = (patches->len < 1000) ? 40960 : 40960 + (patches->len * 64);
2102 p = buf = g_malloc (buf_size);
2104 if (mono_class_get_cctor (method->klass))
2105 encode_klass_info (acfg, method->klass, p, &p);
2107 /* Not needed when loading the method */
2108 encode_value (0, p, &p);
2111 if (cfg->opt & MONO_OPT_SHARED) {
2112 encode_value (g_list_length (cfg->ldstr_list), p, &p);
2113 for (l = cfg->ldstr_list; l; l = l->next) {
2114 encode_value ((long)l->data, p, &p);
2118 /* Used only in shared mode */
2119 g_assert (!cfg->ldstr_list);
2121 #ifdef MONO_ARCH_HAVE_PIC_AOT
2122 encode_value (first_got_offset, p, &p);
2126 for (pindex = 0; pindex < patches->len; ++pindex) {
2127 patch_info = g_ptr_array_index (patches, pindex);
2129 if ((patch_info->type == MONO_PATCH_INFO_LABEL) ||
2130 (patch_info->type == MONO_PATCH_INFO_BB) ||
2131 (patch_info->type == MONO_PATCH_INFO_GOT_OFFSET) ||
2132 (patch_info->type == MONO_PATCH_INFO_NONE)) {
2133 patch_info->type = MONO_PATCH_INFO_NONE;
2138 if ((patch_info->type == MONO_PATCH_INFO_IMAGE) && (patch_info->data.image == acfg->image)) {
2139 /* Stored in GOT slot 0 */
2140 patch_info->type = MONO_PATCH_INFO_NONE;
2147 encode_value (n_patches, p, &p);
2149 /* First emit the type+position table */
2152 for (pindex = 0; pindex < patches->len; ++pindex) {
2154 patch_info = g_ptr_array_index (patches, pindex);
2156 if (patch_info->type == MONO_PATCH_INFO_NONE)
2161 //printf ("T: %d O: %d.\n", patch_info->type, patch_info->ip.i);
2162 offset = patch_info->ip.i - last_offset;
2163 last_offset = patch_info->ip.i;
2165 #if defined(MONO_ARCH_HAVE_PIC_AOT)
2166 /* Only the type is needed */
2167 *p = patch_info->type;
2170 /* Encode type+position compactly */
2171 g_assert (patch_info->type < 64);
2172 if (offset < 1024 - 1) {
2173 *p = (patch_info->type << 2) + (offset >> 8);
2175 *p = offset & ((1 << 8) - 1);
2179 *p = (patch_info->type << 2) + 3;
2183 encode_value (offset, p, &p);
2188 /* Then emit the other info */
2189 for (pindex = 0; pindex < patches->len; ++pindex) {
2190 patch_info = g_ptr_array_index (patches, pindex);
2192 switch (patch_info->type) {
2193 case MONO_PATCH_INFO_NONE:
2195 case MONO_PATCH_INFO_IMAGE:
2196 encode_value (get_image_index (acfg, patch_info->data.image), p, &p);
2198 case MONO_PATCH_INFO_METHOD_REL:
2199 encode_value ((gint)patch_info->data.offset, p, &p);
2201 case MONO_PATCH_INFO_SWITCH: {
2202 gpointer *table = (gpointer *)patch_info->data.table->table;
2205 encode_value (patch_info->data.table->table_size, p, &p);
2206 for (k = 0; k < patch_info->data.table->table_size; k++)
2207 encode_value ((int)(gssize)table [k], p, &p);
2210 case MONO_PATCH_INFO_METHODCONST:
2211 case MONO_PATCH_INFO_METHOD:
2212 case MONO_PATCH_INFO_METHOD_JUMP:
2213 encode_method_ref (acfg, patch_info->data.method, p, &p);
2215 case MONO_PATCH_INFO_INTERNAL_METHOD: {
2216 guint32 icall_index;
2218 icall_index = GPOINTER_TO_UINT (g_hash_table_lookup (acfg->icall_hash, patch_info->data.name));
2219 g_assert (icall_index);
2220 encode_value (icall_index - 1, p, &p);
2223 case MONO_PATCH_INFO_LDSTR: {
2224 guint32 image_index = get_image_index (acfg, patch_info->data.token->image);
2225 guint32 token = patch_info->data.token->token;
2226 g_assert (mono_metadata_token_code (token) == MONO_TOKEN_STRING);
2228 * An optimization would be to emit shared code for ldstr
2229 * statements followed by a throw.
2231 encode_value (image_index, p, &p);
2232 encode_value (patch_info->data.token->token - MONO_TOKEN_STRING, p, &p);
2235 case MONO_PATCH_INFO_DECLSEC:
2236 case MONO_PATCH_INFO_LDTOKEN:
2237 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2238 encode_value (get_image_index (acfg, patch_info->data.token->image), p, &p);
2239 encode_value (patch_info->data.token->token, p, &p);
2241 case MONO_PATCH_INFO_EXC_NAME: {
2242 MonoClass *ex_class;
2245 mono_class_from_name (mono_defaults.exception_class->image,
2246 "System", patch_info->data.target);
2247 g_assert (ex_class);
2248 encode_klass_info (acfg, ex_class, p, &p);
2251 case MONO_PATCH_INFO_R4:
2252 encode_value (*((guint32 *)patch_info->data.target), p, &p);
2254 case MONO_PATCH_INFO_R8:
2255 encode_value (*((guint32 *)patch_info->data.target), p, &p);
2256 encode_value (*(((guint32 *)patch_info->data.target) + 1), p, &p);
2258 case MONO_PATCH_INFO_VTABLE:
2259 case MONO_PATCH_INFO_CLASS_INIT:
2260 case MONO_PATCH_INFO_CLASS:
2261 case MONO_PATCH_INFO_IID:
2262 encode_klass_info (acfg, patch_info->data.klass, p, &p);
2264 case MONO_PATCH_INFO_FIELD:
2265 case MONO_PATCH_INFO_SFLDA:
2266 encode_field_info (acfg, patch_info->data.field, p, &p);
2268 case MONO_PATCH_INFO_WRAPPER: {
2269 encode_value (patch_info->data.method->wrapper_type, p, &p);
2271 switch (patch_info->data.method->wrapper_type) {
2272 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK: {
2274 guint32 image_index;
2277 m = mono_marshal_method_from_wrapper (patch_info->data.method);
2278 image_index = get_image_index (acfg, m->klass->image);
2280 g_assert (image_index < 256);
2281 g_assert (mono_metadata_token_table (token) == MONO_TABLE_METHOD);
2283 encode_value ((image_index << 24) + (mono_metadata_token_index (token)), p, &p);
2286 case MONO_WRAPPER_PROXY_ISINST:
2287 case MONO_WRAPPER_LDFLD:
2288 case MONO_WRAPPER_LDFLDA:
2289 case MONO_WRAPPER_STFLD:
2290 case MONO_WRAPPER_LDFLD_REMOTE:
2291 case MONO_WRAPPER_STFLD_REMOTE:
2292 case MONO_WRAPPER_ISINST: {
2293 MonoClass *proxy_class = (MonoClass*)mono_marshal_method_from_wrapper (patch_info->data.method);
2294 encode_klass_info (acfg, proxy_class, p, &p);
2297 case MONO_WRAPPER_STELEMREF:
2300 g_assert_not_reached ();
2305 g_warning ("unable to handle jump info %d", patch_info->type);
2306 g_assert_not_reached ();
2310 acfg->info_size += p - buf;
2312 /* Emit method info */
2314 emit_label (tmpfp, symbol);
2316 g_assert (p - buf < buf_size);
2317 for (i = 0; i < p - buf; ++i) {
2319 fprintf (tmpfp, "\n.byte ");
2320 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2322 fprintf (tmpfp, "\n");
2329 emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
2334 guint32 debug_info_size;
2337 MonoMethodHeader *header;
2338 guint8 *p, *buf, *debug_info;
2341 method = cfg->method;
2342 code = cfg->native_code;
2343 header = mono_method_get_header (method);
2345 /* Make the labels local */
2346 symbol = g_strdup_printf (".Le_%x_p", mono_metadata_token_index (method->token));
2348 buf_size = header->num_clauses * 256 + 128;
2349 p = buf = g_malloc (buf_size);
2351 encode_value (cfg->code_len, p, &p);
2352 encode_value (cfg->used_int_regs, p, &p);
2354 /* Exception table */
2355 if (header->num_clauses) {
2356 MonoJitInfo *jinfo = cfg->jit_info;
2358 for (k = 0; k < header->num_clauses; ++k) {
2359 MonoJitExceptionInfo *ei = &jinfo->clauses [k];
2361 encode_value (ei->exvar_offset, p, &p);
2363 if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER)
2364 encode_value ((gint)((guint8*)ei->data.filter - code), p, &p);
2366 encode_value ((gint)((guint8*)ei->try_start - code), p, &p);
2367 encode_value ((gint)((guint8*)ei->try_end - code), p, &p);
2368 encode_value ((gint)((guint8*)ei->handler_start - code), p, &p);
2372 mono_debug_serialize_debug_info (cfg, &debug_info, &debug_info_size);
2374 encode_value (debug_info_size, p, &p);
2375 if (debug_info_size) {
2376 memcpy (p, debug_info, debug_info_size);
2377 p += debug_info_size;
2378 g_free (debug_info);
2381 acfg->ex_info_size += p - buf;
2385 emit_label (tmpfp, symbol);
2387 g_assert (p - buf < buf_size);
2388 for (i = 0; i < p - buf; ++i) {
2390 fprintf (tmpfp, "\n.byte ");
2391 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2393 fprintf (tmpfp, "\n");
2400 emit_klass_info (MonoAotCompile *acfg, guint32 token)
2402 MonoClass *klass = mono_class_get (acfg->image, token);
2406 FILE *tmpfp = acfg->fp;
2407 gboolean no_special_static;
2410 p = buf = g_malloc (buf_size);
2414 mono_class_init (klass);
2417 * Emit all the information which is required for creating vtables so
2418 * the runtime does not need to create the MonoMethod structures which
2419 * take up a lot of space.
2422 no_special_static = !mono_class_has_special_static_fields (klass);
2425 encode_value (klass->vtable_size, p, &p);
2426 encode_value ((no_special_static << 7) | (klass->has_static_refs << 6) | (klass->has_references << 5) | ((klass->blittable << 4) | (klass->nested_classes ? 1 : 0) << 3) | (klass->has_cctor << 2) | (klass->has_finalize << 1) | klass->ghcimpl, p, &p);
2427 if (klass->has_cctor)
2428 encode_method_ref (acfg, mono_class_get_cctor (klass), p, &p);
2429 if (klass->has_finalize)
2430 encode_method_ref (acfg, mono_class_get_finalizer (klass), p, &p);
2432 encode_value (klass->instance_size, p, &p);
2433 encode_value (klass->class_size, p, &p);
2434 encode_value (klass->packing_size, p, &p);
2435 encode_value (klass->min_align, p, &p);
2437 for (i = 0; i < klass->vtable_size; ++i) {
2438 MonoMethod *cm = klass->vtable [i];
2441 encode_method_ref (acfg, cm, p, &p);
2443 encode_value (0, p, &p);
2447 acfg->class_info_size += p - buf;
2450 label = g_strdup_printf (".LK_I_%x", token - MONO_TOKEN_TYPE_DEF - 1);
2451 emit_label (tmpfp, label);
2453 g_assert (p - buf < buf_size);
2454 for (i = 0; i < p - buf; ++i) {
2456 fprintf (tmpfp, "\n.byte ");
2457 fprintf (tmpfp, "%s%d", ((i % 32) == 0) ? "" : ",", (unsigned int) buf [i]);
2459 fprintf (tmpfp, "\n");
2464 str_begins_with (const char *str1, const char *str2)
2466 int len = strlen (str2);
2467 return strncmp (str1, str2, len) == 0;
2471 mono_aot_parse_options (const char *aot_options, MonoAotOptions *opts)
2473 gchar **args, **ptr;
2475 memset (opts, 0, sizeof (*opts));
2477 args = g_strsplit (aot_options ? aot_options : "", ",", -1);
2478 for (ptr = args; ptr && *ptr; ptr ++) {
2479 const char *arg = *ptr;
2481 if (str_begins_with (arg, "outfile=")) {
2482 opts->outfile = g_strdup (arg + strlen ("outfile="));
2483 } else if (str_begins_with (arg, "save-temps")) {
2484 opts->save_temps = TRUE;
2485 } else if (str_begins_with (arg, "write-symbols")) {
2486 opts->write_symbols = TRUE;
2488 fprintf (stderr, "AOT : Unknown argument '%s'.\n", arg);
2495 compile_method (MonoAotCompile *acfg, int index)
2499 MonoJumpInfo *patch_info;
2501 guint32 token = MONO_TOKEN_METHOD_DEF | (index + 1);
2503 method = mono_get_method (acfg->image, token, NULL);
2505 /* fixme: maybe we can also precompile wrapper methods */
2506 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
2507 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
2508 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
2509 (method->flags & METHOD_ATTRIBUTE_ABSTRACT)) {
2510 //printf ("Skip (impossible): %s\n", mono_method_full_name (method, TRUE));
2516 /* fixme: we need to patch the IP for the LMF in that case */
2517 if (method->save_lmf) {
2518 //printf ("Skip (needs lmf): %s\n", mono_method_full_name (method, TRUE));
2524 * Since these methods are the only ones which are compiled with
2525 * AOT support, and they are not used by runtime startup/shutdown code,
2526 * the runtime will not see AOT methods during AOT compilation,so it
2527 * does not need to support them by creating a fake GOT etc.
2529 cfg = mini_method_compile (method, acfg->opts, mono_get_root_domain (), FALSE, TRUE, 0);
2532 if (cfg->disable_aot) {
2533 //printf ("Skip (other): %s\n", mono_method_full_name (method, TRUE));
2535 mono_destroy_compile (cfg);
2540 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2541 if (patch_info->type == MONO_PATCH_INFO_ABS) {
2542 /* unable to handle this */
2543 //printf ("Skip (abs addr): %s %d\n", mono_method_full_name (method, TRUE), patch_info->type);
2551 mono_destroy_compile (cfg);
2555 /* some wrappers are very common */
2556 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2557 if (patch_info->type == MONO_PATCH_INFO_METHODCONST) {
2558 switch (patch_info->data.method->wrapper_type) {
2559 case MONO_WRAPPER_PROXY_ISINST:
2560 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2564 if (patch_info->type == MONO_PATCH_INFO_METHOD) {
2565 switch (patch_info->data.method->wrapper_type) {
2566 case MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK:
2567 case MONO_WRAPPER_STFLD:
2568 case MONO_WRAPPER_LDFLD:
2569 case MONO_WRAPPER_LDFLDA:
2570 case MONO_WRAPPER_LDFLD_REMOTE:
2571 case MONO_WRAPPER_STFLD_REMOTE:
2572 case MONO_WRAPPER_STELEMREF:
2573 case MONO_WRAPPER_ISINST:
2574 case MONO_WRAPPER_PROXY_ISINST:
2575 patch_info->type = MONO_PATCH_INFO_WRAPPER;
2582 for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
2583 switch (patch_info->type) {
2584 case MONO_PATCH_INFO_METHOD:
2585 case MONO_PATCH_INFO_METHODCONST:
2586 if (patch_info->data.method->wrapper_type) {
2587 /* unable to handle this */
2588 //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));
2592 if (!patch_info->data.method->token)
2594 * The method is part of a constructed type like Int[,].Set (). It doesn't
2595 * have a token, and we can't make one, since the parent type is part of
2596 * assembly which contains the element type, and not the assembly which
2597 * referenced this type.
2601 case MONO_PATCH_INFO_VTABLE:
2602 case MONO_PATCH_INFO_CLASS_INIT:
2603 case MONO_PATCH_INFO_CLASS:
2604 case MONO_PATCH_INFO_IID:
2605 if (!patch_info->data.klass->type_token)
2606 if (!patch_info->data.klass->element_class->type_token)
2615 acfg->wrappercount++;
2616 mono_destroy_compile (cfg);
2620 //printf ("Compile: %s\n", mono_method_full_name (method, TRUE));
2622 acfg->cfgs [index] = cfg;
2628 load_profile_files (MonoAotCompile *acfg)
2632 int file_index, res, method_index, i;
2638 tmp = g_strdup_printf ("%s/.mono/aot-profile-data/%s-%s-%d", g_get_home_dir (), acfg->image->assembly_name, acfg->image->guid, file_index);
2640 if (!g_file_test (tmp, G_FILE_TEST_IS_REGULAR))
2643 infile = fopen (tmp, "r");
2646 printf ("Using profile data file '%s'\n", tmp);
2650 res = fscanf (infile, "%32s\n", ver);
2651 if ((res != 1) || strcmp (ver, "#VER:1") != 0) {
2652 printf ("Profile file has wrong version or invalid.\n");
2657 res = fscanf (infile, "%d\n", &token);
2661 method_index = mono_metadata_token_index (token) - 1;
2663 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (method_index)))
2664 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (method_index));
2668 /* Add missing methods */
2669 for (i = 0; i < acfg->image->tables [MONO_TABLE_METHOD].rows; ++i) {
2670 if (!g_list_find (acfg->method_order, GUINT_TO_POINTER (i)))
2671 acfg->method_order = g_list_append (acfg->method_order, GUINT_TO_POINTER (i));
2676 emit_method_order (MonoAotCompile *acfg)
2682 symbol = g_strdup_printf ("method_order");
2683 emit_section_change (acfg->fp, ".text", 1);
2684 emit_global (acfg->fp, symbol, FALSE);
2685 emit_alignment (acfg->fp, 8);
2686 emit_label(acfg->fp, symbol);
2688 /* First emit an index table */
2691 for (l = acfg->method_order; l != NULL; l = l->next) {
2692 i = GPOINTER_TO_UINT (l->data);
2694 if (acfg->cfgs [i]) {
2695 if ((index % 1024) == 0) {
2696 fprintf (acfg->fp, ".long %d\n", i);
2704 fprintf (acfg->fp, ".long 0xffffff\n");
2706 /* Then emit the whole method order */
2707 for (l = acfg->method_order; l != NULL; l = l->next) {
2708 i = GPOINTER_TO_UINT (l->data);
2710 if (acfg->cfgs [i]) {
2711 fprintf (acfg->fp, ".long %d\n", i);
2714 fprintf (acfg->fp, "\n");
2716 symbol = g_strdup_printf ("method_order_end");
2717 emit_section_change (acfg->fp, ".text", 1);
2718 emit_global (acfg->fp, symbol, FALSE);
2719 emit_alignment (acfg->fp, 8);
2720 emit_label(acfg->fp, symbol);
2724 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
2726 MonoImage *image = ass->image;
2727 char *com, *tmpfname, *opts_str, *symbol;
2730 MonoAotCompile *acfg;
2732 char *outfile_name, *tmp_outfile_name;
2735 printf ("Mono Ahead of Time compiler - compiling assembly %s\n", image->name);
2737 acfg = g_new0 (MonoAotCompile, 1);
2738 acfg->icall_hash = g_hash_table_new (NULL, NULL);
2739 acfg->icall_to_got_offset_hash = g_hash_table_new (NULL, NULL);
2740 acfg->icall_table = g_ptr_array_new ();
2741 acfg->image_hash = g_hash_table_new (NULL, NULL);
2742 acfg->image_table = g_ptr_array_new ();
2743 acfg->image = image;
2746 mono_aot_parse_options (aot_options, &acfg->aot_opts);
2748 load_profile_files (acfg);
2750 i = g_file_open_tmp ("mono_aot_XXXXXX", &tmpfname, NULL);
2751 tmpfp = fdopen (i, "w+");
2755 emit_string_symbol (tmpfp, "mono_assembly_guid" , image->guid);
2757 emit_string_symbol (tmpfp, "mono_aot_version", MONO_AOT_FILE_VERSION);
2759 opts_str = g_strdup_printf ("%d", opts);
2760 emit_string_symbol (tmpfp, "mono_aot_opt_flags", opts_str);
2763 cfgs = g_new0 (MonoCompile*, image->tables [MONO_TABLE_METHOD].rows + 32);
2765 acfg->nmethods = image->tables [MONO_TABLE_METHOD].rows;
2766 acfg->method_got_offsets = g_new0 (guint32, image->tables [MONO_TABLE_METHOD].rows + 32);
2768 /* Compile methods */
2769 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i)
2770 compile_method (acfg, i);
2772 /* Reserved slots */
2773 acfg->got_offset = N_RESERVED_GOT_SLOTS;
2775 collect_icalls (acfg);
2778 symbol = g_strdup_printf ("methods");
2779 emit_section_change (tmpfp, ".text", 0);
2780 emit_global (tmpfp, symbol, TRUE);
2781 emit_alignment (tmpfp, 8);
2782 emit_label (tmpfp, symbol);
2784 for (l = acfg->method_order; l != NULL; l = l->next) {
2785 i = GPOINTER_TO_UINT (l->data);
2788 emit_method_code (acfg, cfgs [i]);
2791 symbol = g_strdup_printf ("methods_end");
2792 emit_section_change (tmpfp, ".text", 0);
2793 emit_global (tmpfp, symbol, FALSE);
2794 emit_alignment (tmpfp, 8);
2795 emit_label (tmpfp, symbol);
2797 /* Emit method_offsets table */
2798 symbol = g_strdup_printf ("method_offsets");
2799 emit_section_change (tmpfp, ".text", 1);
2800 emit_global (tmpfp, symbol, FALSE);
2801 emit_alignment (tmpfp, 8);
2802 emit_label(tmpfp, symbol);
2804 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2806 if ((i % 32) == 0) {
2807 fprintf (tmpfp, "\n.long ");
2813 symbol = g_strdup_printf (".Lm_%x", i + 1);
2814 fprintf (tmpfp, "%s%s-methods", sep, symbol);
2817 fprintf (tmpfp, "%s0xffffffff", sep);
2819 fprintf (tmpfp, "\n");
2821 /* Emit method info */
2822 symbol = g_strdup_printf ("method_infos");
2823 emit_section_change (tmpfp, ".text", 1);
2824 emit_global (tmpfp, symbol, FALSE);
2825 emit_alignment (tmpfp, 8);
2826 emit_label (tmpfp, symbol);
2828 /* To reduce size of generated assembly code */
2829 symbol = g_strdup_printf ("mi");
2830 emit_label (tmpfp, symbol);
2832 for (l = acfg->method_order; l != NULL; l = l->next) {
2833 i = GPOINTER_TO_UINT (l->data);
2836 emit_method_info (acfg, cfgs [i]);
2839 symbol = g_strdup_printf ("method_info_offsets");
2840 emit_section_change (tmpfp, ".text", 1);
2841 emit_global (tmpfp, symbol, FALSE);
2842 emit_alignment (tmpfp, 8);
2843 emit_label(tmpfp, symbol);
2845 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2847 if ((i % 32) == 0) {
2848 fprintf (tmpfp, "\n.long ");
2854 symbol = g_strdup_printf (".Lm_%x_p", i + 1);
2855 fprintf (tmpfp, "%s%s - mi", sep, symbol);
2858 fprintf (tmpfp, "%s0", sep);
2860 fprintf (tmpfp, "\n");
2862 /* Emit exception info */
2863 symbol = g_strdup_printf ("ex_infos");
2864 emit_section_change (tmpfp, ".text", 1);
2865 emit_global (tmpfp, symbol, FALSE);
2866 emit_alignment (tmpfp, 8);
2867 emit_label (tmpfp, symbol);
2869 /* To reduce size of generate assembly */
2870 symbol = g_strdup_printf ("ex");
2871 emit_label (tmpfp, symbol);
2873 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2875 emit_exception_debug_info (acfg, cfgs [i]);
2878 symbol = g_strdup_printf ("ex_info_offsets");
2879 emit_section_change (tmpfp, ".text", 1);
2880 emit_global (tmpfp, symbol, FALSE);
2881 emit_alignment (tmpfp, 8);
2882 emit_label(tmpfp, symbol);
2884 for (i = 0; i < image->tables [MONO_TABLE_METHOD].rows; ++i) {
2886 if ((i % 32) == 0) {
2887 fprintf (tmpfp, "\n.long ");
2893 symbol = g_strdup_printf (".Le_%x_p", i + 1);
2894 fprintf (tmpfp, "%s%s - ex", sep, symbol);
2897 fprintf (tmpfp, "%s0", sep);
2899 fprintf (tmpfp, "\n");
2901 /* Emit method_order table */
2902 emit_method_order (acfg);
2904 /* Emit class info */
2905 symbol = g_strdup_printf ("class_infos");
2906 emit_section_change (tmpfp, ".text", 1);
2907 emit_global (tmpfp, symbol, FALSE);
2908 emit_alignment (tmpfp, 8);
2909 emit_label (tmpfp, symbol);
2911 for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i)
2912 emit_klass_info (acfg, MONO_TOKEN_TYPE_DEF | (i + 1));
2914 symbol = g_strdup_printf ("class_info_offsets");
2915 emit_section_change (tmpfp, ".text", 1);
2916 emit_global (tmpfp, symbol, FALSE);
2917 emit_alignment (tmpfp, 8);
2918 emit_label(tmpfp, symbol);
2920 for (i = 0; i < image->tables [MONO_TABLE_TYPEDEF].rows; ++i) {
2922 if ((i % 32) == 0) {
2923 fprintf (tmpfp, "\n.long ");
2929 symbol = g_strdup_printf (".LK_I_%x", i);
2930 fprintf (tmpfp, "%s%s - class_infos", sep, symbol);
2932 fprintf (tmpfp, "\n");
2935 * The icall and image tables are small but referenced in a lot of places.
2936 * So we emit them at once, and reference their elements by an index.
2939 /* Emit icall table */
2941 symbol = g_strdup_printf ("mono_icall_table");
2942 emit_section_change (tmpfp, ".text", 1);
2943 emit_global(tmpfp, symbol, FALSE);
2944 emit_alignment(tmpfp, 8);
2945 emit_label(tmpfp, symbol);
2946 fprintf (tmpfp, ".long %d\n", acfg->icall_table->len);
2947 for (i = 0; i < acfg->icall_table->len; i++)
2948 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, (char*)g_ptr_array_index (acfg->icall_table, i));
2950 /* Emit image table */
2952 symbol = g_strdup_printf ("mono_image_table");
2953 emit_section_change (tmpfp, ".text", 1);
2954 emit_global(tmpfp, symbol, FALSE);
2955 emit_alignment(tmpfp, 8);
2956 emit_label(tmpfp, symbol);
2957 fprintf (tmpfp, ".long %d\n", acfg->image_table->len);
2958 for (i = 0; i < acfg->image_table->len; i++) {
2959 MonoImage *image = (MonoImage*)g_ptr_array_index (acfg->image_table, i);
2960 MonoAssemblyName *aname = &image->assembly->aname;
2962 /* FIXME: Support multi-module assemblies */
2963 g_assert (image->assembly->image == image);
2965 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->assembly_name);
2966 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, image->guid);
2967 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->culture ? aname->culture : "");
2968 fprintf (tmpfp, "%s \"%s\"\n", AS_STRING_DIRECTIVE, aname->public_key_token);
2970 emit_alignment (tmpfp, 8);
2971 fprintf (tmpfp, ".long %d\n", aname->flags);
2972 fprintf (tmpfp, ".long %d\n", aname->major);
2973 fprintf (tmpfp, ".long %d\n", aname->minor);
2974 fprintf (tmpfp, ".long %d\n", aname->build);
2975 fprintf (tmpfp, ".long %d\n", aname->revision);
2978 #ifdef MONO_ARCH_HAVE_PIC_AOT
2981 /* Don't make GOT global so accesses to it don't need relocations */
2982 symbol = g_strdup_printf ("got");
2983 emit_section_change (tmpfp, ".bss", 1);
2984 emit_alignment (tmpfp, 8);
2985 emit_label(tmpfp, symbol);
2986 if (acfg->got_offset > 0)
2987 fprintf (tmpfp, ".skip %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
2989 printf ("Code: %d Info: %d Ex Info: %d Class Info: %d GOT: %d\n", acfg->code_size, acfg->info_size, acfg->ex_info_size, acfg->class_info_size, (int)(acfg->got_offset * sizeof (gpointer)));
2991 symbol = g_strdup_printf ("got_addr");
2992 emit_section_change (tmpfp, ".data", 1);
2993 emit_global (tmpfp, symbol, FALSE);
2994 emit_alignment (tmpfp, 8);
2995 emit_label(tmpfp, symbol);
2996 emit_pointer (tmpfp, "got");
2998 symbol = g_strdup_printf ("got_size");
2999 emit_section_change (tmpfp, ".data", 1);
3000 emit_global (tmpfp, symbol, FALSE);
3001 emit_alignment (tmpfp, 8);
3002 emit_label(tmpfp, symbol);
3003 fprintf (tmpfp, ".long %d\n", (int)(acfg->got_offset * sizeof (gpointer)));
3006 symbol = g_strdup_printf ("mem_end");
3007 emit_section_change (tmpfp, ".text", 1);
3008 emit_global (tmpfp, symbol, FALSE);
3009 emit_alignment (tmpfp, 8);
3010 emit_label(tmpfp, symbol);
3014 #if defined(__x86_64__)
3015 com = g_strdup_printf ("as --64 %s -o %s.o", tmpfname, tmpfname);
3016 #elif defined(sparc) && SIZEOF_VOID_P == 8
3017 com = g_strdup_printf ("as -xarch=v9 %s -o %s.o", tmpfname, tmpfname);
3019 com = g_strdup_printf ("as %s -o %s.o", tmpfname, tmpfname);
3022 printf ("Executing the native assembler: %s\n", com);
3023 if (system (com) != 0) {
3030 if (acfg->aot_opts.outfile)
3031 outfile_name = g_strdup_printf ("%s", acfg->aot_opts.outfile);
3033 outfile_name = g_strdup_printf ("%s%s", image->name, SHARED_EXT);
3035 tmp_outfile_name = g_strdup_printf ("%s.tmp", outfile_name);
3038 com = g_strdup_printf ("ld -shared -G -o %s %s.o", outfile_name, tmpfname);
3039 #elif defined(__ppc__) && defined(__MACH__)
3040 com = g_strdup_printf ("gcc -dynamiclib -o %s %s.o", outfile_name, tmpfname);
3041 #elif defined(PLATFORM_WIN32)
3042 com = g_strdup_printf ("gcc -shared --dll -mno-cygwin -o %s %s.o", outfile_name, tmpfname);
3044 com = g_strdup_printf ("ld -shared -o %s %s.o", outfile_name, tmpfname);
3046 printf ("Executing the native linker: %s\n", com);
3047 if (system (com) != 0) {
3048 g_free (tmp_outfile_name);
3049 g_free (outfile_name);
3055 com = g_strdup_printf ("%s.o", tmpfname);
3058 /*com = g_strdup_printf ("strip --strip-unneeded %s%s", image->name, SHARED_EXT);
3059 printf ("Stripping the binary: %s\n", com);
3063 rename (tmp_outfile_name, outfile_name);
3065 g_free (tmp_outfile_name);
3066 g_free (outfile_name);
3068 printf ("Compiled %d out of %d methods (%d%%)\n", acfg->ccount, acfg->mcount, acfg->mcount ? (acfg->ccount*100)/acfg->mcount : 100);
3069 printf ("%d methods contain absolute addresses (%d%%)\n", acfg->abscount, acfg->mcount ? (acfg->abscount*100)/acfg->mcount : 100);
3070 printf ("%d methods contain wrapper references (%d%%)\n", acfg->wrappercount, acfg->mcount ? (acfg->wrappercount*100)/acfg->mcount : 100);
3071 printf ("%d methods contain lmf pointers (%d%%)\n", acfg->lmfcount, acfg->mcount ? (acfg->lmfcount*100)/acfg->mcount : 100);
3072 printf ("%d methods have other problems (%d%%)\n", acfg->ocount, acfg->mcount ? (acfg->ocount*100)/acfg->mcount : 100);
3073 if (acfg->aot_opts.save_temps)
3074 printf ("Retained input file.\n");
3085 mono_aot_init (void)
3090 mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
3096 mono_aot_is_got_entry (guint8 *code, guint8 *addr)
3102 mono_compile_assembly (MonoAssembly *ass, guint32 opts, const char *aot_options)
3108 mono_aot_init_vtable (MonoVTable *vtable)
3114 mono_aot_get_cached_class_info (MonoClass *klass, MonoCachedClassInfo *res)
3120 mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
3126 mono_aot_get_method_from_token (MonoDomain *domain, MonoImage *image, guint32 token)
3132 mono_aot_is_pagefault (void *ptr)
3138 mono_aot_set_make_unreadable (gboolean unreadable)
3143 mono_aot_get_n_pagefaults (void)
3149 mono_aot_handle_pagefault (void *ptr)