Make the loading of llvm EH info async safe. (#4725)
[mono.git] / mono / mini / aot-runtime.c
index 3a5b1813ee10d15c65a0bbe8fb65624fd411ae25..d5ae8dbeece97b2fb080d546eaa4abcf04698354 100644 (file)
@@ -2665,15 +2665,15 @@ is_thumb_code (MonoAotModule *amodule, guint8 *code)
  *
  *   Decode the EH information emitted by our modified LLVM compiler and construct a
  * MonoJitInfo structure from it.
- * LOCKING: Acquires the domain lock.
+ * If JINFO is NULL, set OUT_LLVM_CLAUSES to the number of llvm level clauses.
+ * This function is async safe when called in async context.
  */
-static MonoJitInfo*
-decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, 
-                                                  MonoMethod *method, guint8 *code, guint32 code_len,
+static void
+decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain, MonoJitInfo *jinfo,
+                                                  guint8 *code, guint32 code_len,
                                                   MonoJitExceptionInfo *clauses, int num_clauses,
-                                                  MonoJitInfoFlags flags,
                                                   GSList **nesting,
-                                                  int *this_reg, int *this_offset)
+                                                  int *this_reg, int *this_offset, int *out_llvm_clauses)
 {
        guint8 *p, *code1, *code2;
        guint8 *fde, *cie, *code_start, *code_end;
@@ -2683,14 +2683,19 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
        MonoJitExceptionInfo *ei;
        guint32 fde_len, ei_len, nested_len, nindex;
        gpointer *type_info;
-       MonoJitInfo *jinfo;
        MonoLLVMFDEInfo info;
+       guint8 *unw_info;
+       gboolean async;
+
+       async = mono_thread_info_is_async_context ();
 
        if (!amodule->mono_eh_frame) {
-               jinfo = (MonoJitInfo *)mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, num_clauses, 0));
-               mono_jit_info_init (jinfo, method, code, code_len, flags, num_clauses, 0);
+               if (!jinfo) {
+                       *out_llvm_clauses = num_clauses;
+                       return;
+               }
                memcpy (jinfo->clauses, clauses, num_clauses * sizeof (MonoJitExceptionInfo));
-               return jinfo;
+               return;
        }
 
        g_assert (amodule->mono_eh_frame && code);
@@ -2759,13 +2764,29 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
        /* This won't overflow because there is +1 entry in the table */
        fde_len = table [(pos * 2) + 2 + 1] - table [(pos * 2) + 1];
 
-       mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info);
-       ei = info.ex_info;
+       /* Compute lengths */
+       mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info, NULL, NULL, NULL);
+
+       if (async) {
+               /* These are leaked, but the leak is bounded */
+               ei = mono_domain_alloc0_lock_free (domain, info.ex_info_len * sizeof (MonoJitExceptionInfo));
+               type_info = mono_domain_alloc0_lock_free (domain, info.ex_info_len * sizeof (gpointer));
+               unw_info = mono_domain_alloc0_lock_free (domain, info.unw_info_len);
+       } else {
+               ei = (MonoJitExceptionInfo *)g_malloc0 (info.ex_info_len * sizeof (MonoJitExceptionInfo));
+               type_info = (gpointer *)g_malloc0 (info.ex_info_len * sizeof (gpointer));
+               unw_info = (guint8*)g_malloc0 (info.unw_info_len);
+       }
+       mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, code_start, &info, ei, type_info, unw_info);
+
        ei_len = info.ex_info_len;
-       type_info = info.type_info;
        *this_reg = info.this_reg;
        *this_offset = info.this_offset;
 
+       /*
+        * LLVM might represent one IL region with multiple regions.
+        */
+
        /* Count number of nested clauses */
        nested_len = 0;
        for (i = 0; i < ei_len; ++i) {
@@ -2777,18 +2798,16 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
                        nested_len ++;
        }
 
-       /*
-        * LLVM might represent one IL region with multiple regions, so have to
-        * allocate a new JI.
-        */
-       jinfo = 
-               (MonoJitInfo *)mono_domain_alloc0_lock_free (domain, mono_jit_info_size (flags, ei_len + nested_len, 0));
-       mono_jit_info_init (jinfo, method, code, code_len, flags, ei_len + nested_len, 0);
+       if (!jinfo) {
+               *out_llvm_clauses = ei_len + nested_len;
+               return;
+       }
 
-       jinfo->unwind_info = mono_cache_unwind_info (info.unw_info, info.unw_info_len);
-       /* This signals that unwind_info points to a normal cached unwind info */
-       jinfo->from_aot = 0;
-       jinfo->from_llvm = 1;
+       /* Store the unwind info addr/length in the MonoJitInfo structure itself so its async safe */
+       MonoUnwindJitInfo *jinfo_unwind = mono_jit_info_get_unwind_info (jinfo);
+       g_assert (jinfo_unwind);
+       jinfo_unwind->unw_info = unw_info;
+       jinfo_unwind->unw_info_len = info.unw_info_len;
 
        for (i = 0; i < ei_len; ++i) {
                /*
@@ -2838,8 +2857,6 @@ decode_llvm_mono_eh_frame (MonoAotModule *amodule, MonoDomain *domain,
                }
        }
        g_assert (nindex == ei_len + nested_len);
-
-       return jinfo;
 }
 
 static gpointer
@@ -2924,24 +2941,41 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                MonoJitExceptionInfo *clauses;
                GSList **nesting;
 
-               // FIXME: async
-               g_assert (!async);
-
                /*
                 * Part of the info is encoded by the AOT compiler, the rest is in the .eh_frame
                 * section.
                 */
-               clauses = g_new0 (MonoJitExceptionInfo, num_clauses);
-               nesting = g_new0 (GSList*, num_clauses);
+               if (async) {
+                       if (num_clauses < 16) {
+                               clauses = g_newa (MonoJitExceptionInfo, num_clauses);
+                               nesting = g_newa (GSList*, num_clauses);
+                       } else {
+                               clauses = alloc0_jit_info_data (domain, sizeof (MonoJitExceptionInfo) * num_clauses, TRUE);
+                               nesting = alloc0_jit_info_data (domain, sizeof (GSList*) * num_clauses, TRUE);
+                       }
+                       memset (clauses, 0, sizeof (MonoJitExceptionInfo) * num_clauses);
+                       memset (nesting, 0, sizeof (GSList*) * num_clauses);
+               } else {
+                       clauses = g_new0 (MonoJitExceptionInfo, num_clauses);
+                       nesting = g_new0 (GSList*, num_clauses);
+               }
 
                for (i = 0; i < num_clauses; ++i) {
                        MonoJitExceptionInfo *ei = &clauses [i];
 
                        ei->flags = decode_value (p, &p);
 
-                       if (decode_value (p, &p)) {
-                               ei->data.catch_class = decode_klass_ref (amodule, p, &p, &error);
-                               mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                       if (!(ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
+                               int len = decode_value (p, &p);
+
+                               if (len > 0) {
+                                       if (async) {
+                                               p += len;
+                                       } else {
+                                               ei->data.catch_class = decode_klass_ref (amodule, p, &p, &error);
+                                               mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                                       }
+                               }
                        }
 
                        ei->clause_index = i;
@@ -2956,16 +2990,29 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
                                int nesting_index = decode_value (p, &p);
                                if (nesting_index == -1)
                                        break;
+                               // FIXME: async
+                               g_assert (!async);
                                nesting [i] = g_slist_prepend (nesting [i], GINT_TO_POINTER (nesting_index));
                        }
                }
 
-               jinfo = decode_llvm_mono_eh_frame (amodule, domain, method, code, code_len, clauses, num_clauses, flags, nesting, &this_reg, &this_offset);
+               flags |= JIT_INFO_HAS_UNWIND_INFO;
+
+               int num_llvm_clauses;
+               /* Get the length first */
+               decode_llvm_mono_eh_frame (amodule, domain, NULL, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, &num_llvm_clauses);
+               len = mono_jit_info_size (flags, num_llvm_clauses, num_holes);
+               jinfo = (MonoJitInfo *)alloc0_jit_info_data (domain, len, async);
+               mono_jit_info_init (jinfo, method, code, code_len, flags, num_llvm_clauses, num_holes);
 
-               g_free (clauses);
-               for (i = 0; i < num_clauses; ++i)
-                       g_slist_free (nesting [i]);
-               g_free (nesting);
+               decode_llvm_mono_eh_frame (amodule, domain, jinfo, code, code_len, clauses, num_clauses, nesting, &this_reg, &this_offset, NULL);
+
+               if (!async) {
+                       g_free (clauses);
+                       for (i = 0; i < num_clauses; ++i)
+                               g_slist_free (nesting [i]);
+                       g_free (nesting);
+               }
        } else {
                len = mono_jit_info_size (flags, num_clauses, num_holes);
                jinfo = (MonoJitInfo *)alloc0_jit_info_data (domain, len, async);