Add support for precise unwind info in epilogs on amd64:
[mono.git] / mono / mini / aot-runtime.c
index 51577f520cea1f45e4df06e12f873e1f19dd5dd0..3c9064b885d26a203dc19b01836b11e696780383 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/wait.h>  /* for WIFEXITED, WEXITSTATUS */
 #endif
 
+#include <mono/metadata/abi-details.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
 #include <mono/metadata/object.h>
@@ -138,6 +139,7 @@ typedef struct MonoAotModule {
        MonoDl *sofile;
 
        JitInfoMap *async_jit_info_table;
+       CRITICAL_SECTION mutex;
 } MonoAotModule;
 
 typedef struct {
@@ -208,6 +210,18 @@ init_plt (MonoAotModule *info);
 /*                 AOT RUNTIME                       */
 /*****************************************************/
 
+static inline void
+amodule_lock (MonoAotModule *amodule)
+{
+       EnterCriticalSection (&amodule->mutex);
+}
+
+static inline void
+amodule_unlock (MonoAotModule *amodule)
+{
+       LeaveCriticalSection (&amodule->mutex);
+}
+
 /*
  * load_image:
  *
@@ -1536,6 +1550,8 @@ get_arm_bl_target (guint32 *ins_addr)
                offset = (((int)ins & 0xffffff) << 8) >> 8;
                return (char*)ins_addr + (offset * 4) + 8;
        }
+#elif defined(TARGET_ARM64)
+       return mono_arch_get_call_target (((guint8*)ins_addr) + 4);
 #else
        g_assert_not_reached ();
        return NULL;
@@ -1662,8 +1678,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                align_int64 = align;
        }
 #else
-       align_double = __alignof__ (double);
-       align_int64 = __alignof__ (gint64);
+       align_double = MONO_ABI_ALIGNOF (double);
+       align_int64 = MONO_ABI_ALIGNOF (gint64);
 #endif
 
        /* Sanity check */
@@ -1686,6 +1702,8 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        amodule->method_to_code = g_hash_table_new (mono_aligned_addr_hash, NULL);
        amodule->blob = blob;
 
+       InitializeCriticalSection (&amodule->mutex);
+
        /* Read image table */
        {
                guint32 table_len, i;
@@ -1756,21 +1774,27 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        amodule->trampolines [MONO_AOT_TRAMP_GSHAREDVT_ARG] = info->gsharedvt_arg_trampolines;
        amodule->thumb_end = info->thumb_end;
 
-#ifdef MONOTOUCH
        if (info->flags & MONO_AOT_FILE_FLAG_DIRECT_METHOD_ADDRESSES) {
                /* Compute code_offsets from the method addresses */
                amodule->code_offsets = g_malloc0 (amodule->info.nmethods * sizeof (gint32));
                for (i = 0; i < amodule->info.nmethods; ++i) {
                        /* method_addresses () contains a table of branches, since the ios linker can update those correctly */
-                       void *addr = get_arm_bl_target ((guint32*)amodule->method_addresses + i);
+                       void *addr = NULL;
 
+#if defined(TARGET_ARM) || defined(TARGET_ARM64)
+                       addr = get_arm_bl_target ((guint32*)amodule->method_addresses + i);
+#elif defined(TARGET_X86) || defined(TARGET_AMD64)
+                       addr = mono_arch_get_call_target ((guint8*)amodule->method_addresses + (i * 5) + 5);
+#else
+                       g_assert_not_reached ();
+#endif
+                       g_assert (addr);
                        if (addr == amodule->method_addresses)
                                amodule->code_offsets [i] = 0xffffffff;
                        else
                                amodule->code_offsets [i] = (char*)addr - (char*)amodule->code;
                }
        }
-#endif
 
        if (make_unreadable) {
 #ifndef TARGET_WIN32
@@ -2062,7 +2086,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
        if (!amodule || !amodule->class_name_table)
                return FALSE;
 
-       mono_aot_lock ();
+       amodule_lock (amodule);
 
        *klass = NULL;
 
@@ -2073,7 +2097,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
        if (nspace_table) {
                *klass = g_hash_table_lookup (nspace_table, name);
                if (*klass) {
-                       mono_aot_unlock ();
+                       amodule_unlock (amodule);
                        return TRUE;
                }
        }
@@ -2113,19 +2137,19 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
                        name_space2 = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
 
                        if (!strcmp (name, name2) && !strcmp (name_space, name_space2)) {
-                               mono_aot_unlock ();
+                               amodule_unlock (amodule);
                                *klass = mono_class_get (image, token);
 
                                /* Add to cache */
                                if (*klass) {
-                                       mono_aot_lock ();
+                                       amodule_lock (amodule);
                                        nspace_table = g_hash_table_lookup (amodule->name_cache, name_space);
                                        if (!nspace_table) {
                                                nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
                                                g_hash_table_insert (amodule->name_cache, (char*)name_space2, nspace_table);
                                        }
                                        g_hash_table_insert (nspace_table, (char*)name2, *klass);
-                                       mono_aot_unlock ();
+                                       amodule_unlock (amodule);
                                }
                                return TRUE;
                        }
@@ -2138,7 +2162,7 @@ mono_aot_get_class_from_name (MonoImage *image, const char *name_space, const ch
                }
        }
 
-       mono_aot_unlock ();
+       amodule_unlock (amodule);
        
        return TRUE;
 }
@@ -2482,10 +2506,21 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                jinfo->from_aot = 1;
        }
 
+       /*
+        * Set all the 'has' flags, the mono_jit_info_get () functions depends on this to
+        * compute the addresses of data blocks.
+        */
+       if (has_generic_jit_info)
+               jinfo->has_generic_jit_info = 1;
+       if (has_arch_eh_jit_info)
+               jinfo->has_arch_eh_info = 1;
+       if (has_try_block_holes)
+               jinfo->has_try_block_holes = 1;
+
        if (has_try_block_holes) {
                MonoTryBlockHoleTableJitInfo *table;
 
-               jinfo->has_try_block_holes = 1;
+               g_assert (jinfo->has_try_block_holes);
 
                table = mono_jit_info_get_try_block_hole_table_info (jinfo);
                g_assert (table);
@@ -2502,7 +2537,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
        if (has_arch_eh_jit_info) {
                MonoArchEHJitInfo *eh_info;
 
-               jinfo->has_arch_eh_info = 1;
+               g_assert (jinfo->has_arch_eh_info);
 
                eh_info = mono_jit_info_get_arch_eh_info (jinfo);
                eh_info->stack_size = decode_value (p, &p);
@@ -2520,7 +2555,7 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                MonoGenericJitInfo *gi;
                int len;
 
-               jinfo->has_generic_jit_info = 1;
+               g_assert (jinfo->has_generic_jit_info);
 
                gi = mono_jit_info_get_generic_jit_info (jinfo);
                g_assert (gi);
@@ -2665,7 +2700,8 @@ mono_aot_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
                mono_aot_unlock ();
        }
 
-       p = amodule->unwind_info + ji->used_regs;
+       /* The upper 16 bits of ji->used_regs might contain the epilog offset */
+       p = amodule->unwind_info + (ji->used_regs & 0xffff);
        *unwind_info_len = decode_value (p, &p);
        return p;
 }
@@ -2748,7 +2784,7 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
        MonoJitInfo *jinfo;
        guint8 *code, *ex_info, *p;
        guint32 *table;
-       int nmethods = amodule->info.nmethods;
+       int nmethods;
        gint32 *code_offsets;
        int offsets_len, i;
        gboolean async;
@@ -2756,6 +2792,8 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
        if (!amodule)
                return NULL;
 
+       nmethods = amodule->info.nmethods;
+
        if (domain != mono_get_root_domain ())
                /* FIXME: */
                return NULL;
@@ -2848,9 +2886,9 @@ mono_aot_find_jit_info (MonoDomain *domain, MonoImage *image, gpointer addr)
        /* Might be a wrapper/extra method */
        if (!async) {
                if (amodule->extra_methods) {
-                       mono_aot_lock ();
+                       amodule_lock (amodule);
                        method = g_hash_table_lookup (amodule->extra_methods, GUINT_TO_POINTER (method_index));
-                       mono_aot_unlock ();
+                       amodule_unlock (amodule);
                } else {
                        method = NULL;
                }
@@ -2989,16 +3027,22 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
        case MONO_PATCH_INFO_CLASS:
        case MONO_PATCH_INFO_IID:
        case MONO_PATCH_INFO_ADJUSTED_IID:
+       case MONO_PATCH_INFO_CLASS_INIT:
                /* Shared */
                ji->data.klass = decode_klass_ref (aot_module, p, &p);
                if (!ji->data.klass)
                        goto cleanup;
                break;
-       case MONO_PATCH_INFO_CLASS_INIT:
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
-               ji->data.klass = decode_klass_ref (aot_module, p, &p);
-               if (!ji->data.klass)
+               ji->data.del_tramp = mono_mempool_alloc0 (mp, sizeof (MonoClassMethodPair));
+               ji->data.del_tramp->klass = decode_klass_ref (aot_module, p, &p);
+               if (!ji->data.del_tramp->klass)
                        goto cleanup;
+               if (decode_value (p, &p)) {
+                       ji->data.del_tramp->method = decode_resolve_method_ref (aot_module, p, &p);
+                       if (!ji->data.del_tramp->method)
+                               goto cleanup;
+               }
                break;
        case MONO_PATCH_INFO_IMAGE:
                ji->data.image = load_image (aot_module, decode_value (p, &p), TRUE);
@@ -3299,10 +3343,17 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                code = &amodule->code [amodule->code_offsets [method_index] + 1];
        }
 
-       mono_aot_lock ();
-       if (!amodule->methods_loaded)
-               amodule->methods_loaded = g_new0 (guint32, amodule->info.nmethods / 32 + 1);
-       mono_aot_unlock ();
+       if (!amodule->methods_loaded) {
+               amodule_lock (amodule);
+               if (!amodule->methods_loaded) {
+                       guint32 *loaded;
+
+                       loaded = g_new0 (guint32, amodule->info.nmethods / 32 + 1);
+                       mono_memory_barrier ();
+                       amodule->methods_loaded = loaded;
+               }
+               amodule_unlock (amodule);
+       }
 
        if ((amodule->methods_loaded [method_index / 32] >> (method_index % 32)) & 0x1)
                return code;
@@ -3315,10 +3366,10 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                                method = mono_get_method (image, token, NULL);
                        if (method) {
                                char *name = mono_method_full_name (method, TRUE);
-                               printf ("LAST AOT METHOD: %s.\n", name);
+                               g_print ("LAST AOT METHOD: %s.\n", name);
                                g_free (name);
                        } else {
-                               printf ("LAST AOT METHOD: %p %d\n", code, method_index);
+                               g_print ("LAST AOT METHOD: %p %d\n", code, method_index);
                        }
                }
        }
@@ -3399,7 +3450,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
                g_free (full_name);
        }
 
-       mono_aot_lock ();
+       amodule_lock (amodule);
 
        InterlockedIncrement (&mono_jit_stats.methods_aot);
 
@@ -3410,7 +3461,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM
        if (method && method->wrapper_type)
                g_hash_table_insert (amodule->method_to_code, method, code);
 
-       mono_aot_unlock ();
+       amodule_unlock (amodule);
 
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) {
                MonoJitInfo *jinfo;
@@ -3475,17 +3526,17 @@ find_extra_method_in_amodule (MonoAotModule *amodule, MonoMethod *method)
                p = amodule->blob + key;
                orig_p = p;
 
-               mono_aot_lock ();
+               amodule_lock (amodule);
                if (!amodule->method_ref_to_method)
                        amodule->method_ref_to_method = g_hash_table_new (NULL, NULL);
                m = g_hash_table_lookup (amodule->method_ref_to_method, p);
-               mono_aot_unlock ();
+               amodule_unlock (amodule);
                if (!m) {
                        m = decode_resolve_method_ref_with_target (amodule, method, p, &p);
                        if (m) {
-                               mono_aot_lock ();
+                               amodule_lock (amodule);
                                g_hash_table_insert (amodule->method_ref_to_method, orig_p, m);
-                               mono_aot_unlock ();
+                               amodule_unlock (amodule);
                        }
                }
                if (m == method) {
@@ -3624,9 +3675,9 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                method_index = mono_metadata_token_index (method->token) - 1;
        } else if (method->is_inflated || !method->token) {
                /* This hash table is used to avoid the slower search in the extra_method_table in the AOT image */
-               mono_aot_lock ();
+               amodule_lock (amodule);
                code = g_hash_table_lookup (amodule->method_to_code, method);
-               mono_aot_unlock ();
+               amodule_unlock (amodule);
                if (code)
                        return code;
 
@@ -3745,11 +3796,11 @@ mono_aot_get_method (MonoDomain *domain, MonoMethod *method)
                        return NULL;
 
                /* Needed by find_jit_info */
-               mono_aot_lock ();
+               amodule_lock (amodule);
                if (!amodule->extra_methods)
                        amodule->extra_methods = g_hash_table_new (NULL, NULL);
                g_hash_table_insert (amodule->extra_methods, GUINT_TO_POINTER (method_index), method);
-               mono_aot_unlock ();
+               amodule_unlock (amodule);
        } else {
                /* Common case */
                method_index = mono_metadata_token_index (method->token) - 1;
@@ -3846,16 +3897,24 @@ find_aot_module (guint8 *code)
 }
 
 void
-mono_aot_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
+mono_aot_patch_plt_entry (guint8 *code, guint8 *plt_entry, gpointer *got, mgreg_t *regs, guint8 *addr)
 {
+       MonoAotModule *amodule;
+
        /*
         * Since AOT code is only used in the root domain, 
         * mono_domain_get () != mono_get_root_domain () means the calling method
         * is AppDomain:InvokeInDomain, so this is the same check as in 
         * mono_method_same_domain () but without loading the metadata for the method.
         */
-       if (mono_domain_get () == mono_get_root_domain ())
-               mono_arch_patch_plt_entry (code, got, regs, addr);
+       if (mono_domain_get () == mono_get_root_domain ()) {
+               if (!got) {
+                       amodule = find_aot_module (code);
+                       if (amodule)
+                               got = amodule->got;
+               }
+               mono_arch_patch_plt_entry (plt_entry, got, regs, addr);
+       }
 }
 
 /*
@@ -3934,7 +3993,7 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code
        /* Patch the PLT entry with target which might be the actual method not a trampoline */
        plt_entry = mono_aot_get_plt_entry (code);
        g_assert (plt_entry);
-       mono_aot_patch_plt_entry (plt_entry, module->got, NULL, target);
+       mono_aot_patch_plt_entry (code, plt_entry, module->got, NULL, target);
 
        return target;
 #else
@@ -3948,7 +4007,7 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code
  *
  *   Initialize the PLT table of the AOT module. Called lazily when the first AOT
  * method in the module is loaded to avoid committing memory by writing to it.
- * LOCKING: Assumes the AOT lock is held.
+ * LOCKING: Assumes the AMODULE lock is held.
  */
 static void
 init_plt (MonoAotModule *amodule)
@@ -4344,10 +4403,14 @@ get_new_trampoline_from_page (int tramp_type)
                page = (TrampolinePage*)addr;
                page->next = trampoline_pages [tramp_type];
                trampoline_pages [tramp_type] = page;
+#ifdef TARGET_ARM64
+               page->trampolines = (void*)(taddr + amodule->info.tramp_page_code_offsets [tramp_type]);
+#else
                page->trampolines = (void*)(taddr + trampolines_pages_code_offsets [tramp_type]);
-               page->trampolines_end = (void*)(taddr + psize);
+#endif
+               page->trampolines_end = (void*)(taddr + psize - 64);
                code = page->trampolines;
-               page->trampolines += 8;
+               page->trampolines += specific_trampoline_size;
                mono_aot_page_unlock ();
                return code;
        }
@@ -4845,7 +4908,7 @@ mono_aot_plt_resolve (gpointer aot_module, guint32 plt_info_offset, guint8 *code
 }
 
 void
-mono_aot_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
+mono_aot_patch_plt_entry (guint8 *code, guint8 *plt_entry, gpointer *got, mgreg_t *regs, guint8 *addr)
 {
 }