Add support for precise unwind info in epilogs on amd64:
[mono.git] / mono / mini / aot-runtime.c
index 3cbc3cb6a8e5c94000aed77fa3a8d02235140737..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;
@@ -1763,7 +1781,7 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
                        /* method_addresses () contains a table of branches, since the ios linker can update those correctly */
                        void *addr = NULL;
 
-#ifdef TARGET_ARM
+#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);
@@ -2068,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;
 
@@ -2079,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;
                }
        }
@@ -2119,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;
                        }
@@ -2144,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;
 }
@@ -2488,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);
@@ -2508,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);
@@ -2526,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);
@@ -2671,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;
 }
@@ -2754,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;
@@ -2762,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;
@@ -2854,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;
                }
@@ -3311,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;
@@ -3327,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);
                        }
                }
        }
@@ -3411,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);
 
@@ -3422,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;
@@ -3487,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) {
@@ -3636,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;
 
@@ -3757,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;
@@ -3858,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);
+       }
 }
 
 /*
@@ -3946,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
@@ -3960,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)
@@ -4356,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;
        }
@@ -4857,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)
 {
 }