Make the loading of llvm EH info async safe. (#4725)
authorZoltan Varga <vargaz@gmail.com>
Sun, 23 Apr 2017 23:16:49 +0000 (19:16 -0400)
committerGitHub <noreply@github.com>
Sun, 23 Apr 2017 23:16:49 +0000 (19:16 -0400)
* [aot] Emit class references in EH info in such as way that they can be skipped when reading them in async context.

* [aot] Rewrite the LLVM EH info loading code by moving allocations to callers so the lower level code is async safe.

* [aot] Make the memory allocation in the loading of llvm EH info async safe. Remove fields from MonoLLVMFDEInfo which are passed as parameters.

* [runtime] Add the ability to store the unwind info address/length in the MonoJitInfo structure instead of referencing it using the 'unwind_info' field.

* [aot] Make the loading of llvm EH information async safe.

mono/metadata/domain-internals.h
mono/metadata/jit-info.c
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/mini-exceptions.c
mono/mini/mini-llvm.c
mono/mini/mini-unwind.h
mono/mini/mini.h
mono/mini/unwind.c

index 6b3369fd2e4f42cae3920b040600dd7fff380fee..3cfa02246127b652ccfd974b097451047642283f 100644 (file)
@@ -184,12 +184,22 @@ typedef struct {
        int thunks_size;
 } MonoThunkJitInfo;
 
+typedef struct {
+       guint8 *unw_info;
+       int unw_info_len;
+} MonoUnwindJitInfo;
+
 typedef enum {
        JIT_INFO_NONE = 0,
        JIT_INFO_HAS_GENERIC_JIT_INFO = (1 << 0),
        JIT_INFO_HAS_TRY_BLOCK_HOLES = (1 << 1),
        JIT_INFO_HAS_ARCH_EH_INFO = (1 << 2),
-       JIT_INFO_HAS_THUNK_INFO = (1 << 3)
+       JIT_INFO_HAS_THUNK_INFO = (1 << 3),
+       /*
+        * If this is set, the unwind info is stored in the structure, instead of being pointed to by the
+        * 'unwind_info' field.
+        */
+       JIT_INFO_HAS_UNWIND_INFO = (1 << 4)
 } MonoJitInfoFlags;
 
 struct _MonoJitInfo {
@@ -217,6 +227,7 @@ struct _MonoJitInfo {
        gboolean    has_try_block_holes:1;
        gboolean    has_arch_eh_info:1;
        gboolean    has_thunk_info:1;
+       gboolean    has_unwind_info:1;
        gboolean    from_aot:1;
        gboolean    from_llvm:1;
        gboolean    dbg_attrs_inited:1;
@@ -536,6 +547,9 @@ mono_jit_info_get_arch_eh_info (MonoJitInfo *ji);
 MonoThunkJitInfo*
 mono_jit_info_get_thunk_info (MonoJitInfo *ji);
 
+MonoUnwindJitInfo*
+mono_jit_info_get_unwind_info (MonoJitInfo *ji);
+
 /* 
  * Installs a new function which is used to return a MonoJitInfo for a method inside
  * an AOT module.
index 50ca4e7e31daf8e432c9e05972421ab9a01ddf97..cf9992615e836ad1ce9f8c074b9dfef1f59d5d7f 100644 (file)
@@ -801,6 +801,8 @@ mono_jit_info_size (MonoJitInfoFlags flags, int num_clauses, int num_holes)
                size += sizeof (MonoArchEHJitInfo);
        if (flags & JIT_INFO_HAS_THUNK_INFO)
                size += sizeof (MonoThunkJitInfo);
+       if (flags & JIT_INFO_HAS_UNWIND_INFO)
+               size += sizeof (MonoUnwindJitInfo);
        return size;
 }
 
@@ -820,6 +822,8 @@ mono_jit_info_init (MonoJitInfo *ji, MonoMethod *method, guint8 *code, int code_
                ji->has_arch_eh_info = 1;
        if (flags & JIT_INFO_HAS_THUNK_INFO)
                ji->has_thunk_info = 1;
+       if (flags & JIT_INFO_HAS_UNWIND_INFO)
+               ji->has_unwind_info = 1;
 }
 
 /**
@@ -996,3 +1000,22 @@ mono_jit_info_get_thunk_info (MonoJitInfo *ji)
                return NULL;
        }
 }
+
+MonoUnwindJitInfo*
+mono_jit_info_get_unwind_info (MonoJitInfo *ji)
+{
+       if (ji->has_unwind_info) {
+               char *ptr = (char*)&ji->clauses [ji->num_clauses];
+               if (ji->has_generic_jit_info)
+                       ptr += sizeof (MonoGenericJitInfo);
+               if (ji->has_try_block_holes)
+                       ptr += try_block_hole_table_size (ji);
+               if (ji->has_arch_eh_info)
+                       ptr += sizeof (MonoArchEHJitInfo);
+               if (ji->has_thunk_info)
+                       ptr += sizeof (MonoThunkJitInfo);
+               return (MonoUnwindJitInfo*)ptr;
+       } else {
+               return NULL;
+       }
+}
index 4b94301b046b13444c0f7c7037b503687c9c7bfd..c18f91c9749b6f76e74396ae1d793ac381c416e6 100644 (file)
@@ -6134,11 +6134,23 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg, gboolean stor
                        clause = &header->clauses [k];
 
                        encode_value (clause->flags, p, &p);
-                       if (clause->data.catch_class) {
-                               encode_value (1, p, &p);
-                               encode_klass_ref (acfg, clause->data.catch_class, p, &p);
-                       } else {
-                               encode_value (0, p, &p);
+                       if (!(clause->flags == MONO_EXCEPTION_CLAUSE_FILTER || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
+                               if (clause->data.catch_class) {
+                                       guint8 *buf2, *p2;
+                                       int len;
+
+                                       buf2 = (guint8 *)g_malloc (4096);
+                                       p2 = buf2;
+                                       encode_klass_ref (acfg, clause->data.catch_class, p2, &p2);
+                                       len = p2 - buf2;
+                                       g_assert (len < 4096);
+                                       encode_value (len, p, &p);
+                                       memcpy (p, buf2, len);
+                                       p += p2 - buf2;
+                                       g_free (buf2);
+                               } else {
+                                       encode_value (0, p, &p);
+                               }
                        }
 
                        /* Emit the IL ranges too, since they might not be available at runtime */
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);
index cacc74c49bc360f876d124fc3fa8a851b479dea7..45ceb0d6629df7c7f288e115d55daf5bd90d3a30 100644 (file)
@@ -2995,7 +2995,12 @@ mono_restore_context (MonoContext *ctx)
 guint8*
 mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len)
 {
-       if (ji->from_aot)
+       if (ji->has_unwind_info) {
+               /* The address/length in the MonoJitInfo structure itself */
+               MonoUnwindJitInfo *info = mono_jit_info_get_unwind_info (ji);
+               *unwind_info_len = info->unw_info_len;
+               return info->unw_info;
+       } else if (ji->from_aot)
                return mono_aot_get_unwind_info (ji, unwind_info_len);
        else
                return mono_get_cached_unwind_info (ji->unwind_info, unwind_info_len);
index b53dafd323ea81108323fcb26d7cda53573525ae..c40b98b9f2dafc271e04046021c379099544c9da 100644 (file)
@@ -7719,6 +7719,7 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame)
        guint32 ei_len, i, nested_len;
        gpointer *type_info;
        gint32 *table;
+       guint8 *unw_info;
 
        /*
         * Decode the one element EH table emitted by the MonoException class
@@ -7751,9 +7752,16 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame)
        fde = (guint8*)eh_frame + fde_offset;
        cie = (guint8*)table;
 
-       mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info);
+       /* Compute lengths */
+       mono_unwind_decode_llvm_mono_fde (fde, fde_len, cie, cfg->native_code, &info, NULL, NULL, NULL);
 
-       cfg->encoded_unwind_ops = info.unw_info;
+       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, cfg->native_code, &info, ei, type_info, unw_info);
+
+       cfg->encoded_unwind_ops = unw_info;
        cfg->encoded_unwind_ops_len = info.unw_info_len;
        if (cfg->verbose_level > 1)
                mono_print_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len);
@@ -7762,9 +7770,7 @@ decode_llvm_eh_info (EmitContext *ctx, gpointer eh_frame)
                cfg->llvm_this_offset = info.this_offset;
        }
 
-       ei = info.ex_info;
        ei_len = info.ex_info_len;
-       type_info = info.type_info;
 
        // Nested clauses are currently disabled
        nested_len = 0;
index 26c7ada5df39c91beb747816bf8ebbb8e4557ec2..cdcebec8214328b7437a6fa587cbb0d00377bea2 100644 (file)
@@ -196,18 +196,15 @@ guint8* mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len
 
 /* Data retrieved from an LLVM Mono FDE entry */
 typedef struct {
-       /* Malloc'ed */
-       guint8 *unw_info;
        guint32 unw_info_len;
-       MonoJitExceptionInfo *ex_info;
        guint32 ex_info_len;
-       gpointer *type_info;
+       int type_info_len;
        int this_reg;
        int this_offset;
 } MonoLLVMFDEInfo;
 
 void
-mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res) MONO_LLVM_INTERNAL;
+mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res, MonoJitExceptionInfo *ei, gpointer *type_info, guint8 *unw_info) MONO_LLVM_INTERNAL;
 
 GSList* mono_unwind_get_cie_program (void);
 
index 191386a06bb5032ddeeb6e57b40e2fc81763080a..98714bd220097cd5d8fc5c8f008c8b665e1cca7d 100644 (file)
 #endif
 
 /* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION 139
+#define MONO_AOT_FILE_VERSION 140
 
 //TODO: This is x86/amd64 specific.
 #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
index 2dc04322dc6b22a1f64feac6342fa85d39e5f334..72f5d0d59e0b959373fcb1cb00dee5b86b4b601d 100644 (file)
@@ -867,9 +867,10 @@ read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
  * decode_lsda:
  *
  *   Decode the Mono specific Language Specific Data Area generated by LLVM.
+ * This function is async safe.
  */
 static void
-decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
+decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo *ex_info, gpointer *type_info, guint32 *ex_info_len, int *this_reg, int *this_offset)
 {
        guint8 *p;
        int i, ncall_sites, this_encoding;
@@ -905,12 +906,8 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
        ncall_sites = decode_uleb128 (p, &p);
        p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
 
-       if (ex_info) {
-               *ex_info = (MonoJitExceptionInfo *)g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
+       if (ex_info_len)
                *ex_info_len = ncall_sites;
-       }
-       if (type_info)
-               *type_info = (gpointer *)g_malloc0 (ncall_sites * sizeof (gpointer));
 
        for (i = 0; i < ncall_sites; ++i) {
                int block_start_offset, block_size, landing_pad;
@@ -930,11 +927,11 @@ decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32
                //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
 
                if (ex_info) {
-                       if (*type_info)
-                               (*type_info) [i] = tinfo;
-                       (*ex_info)[i].try_start = code + block_start_offset;
-                       (*ex_info)[i].try_end = code + block_start_offset + block_size;
-                       (*ex_info)[i].handler_start = code + landing_pad;
+                       if (type_info)
+                               type_info [i] = tinfo;
+                       ex_info[i].try_start = code + block_start_offset;
+                       ex_info[i].try_end = code + block_start_offset + block_size;
+                       ex_info[i].handler_start = code + landing_pad;
                }
        }
 }
@@ -1073,7 +1070,16 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi
                if (lsda_offset != 0) {
                        lsda = fde_aug + lsda_offset;
 
-                       decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
+                       /* Get the lengths first */
+                       guint32 len;
+                       decode_lsda (lsda, code, NULL, NULL, &len, this_reg, this_offset);
+
+                       if (ex_info)
+                               *ex_info = (MonoJitExceptionInfo *)g_malloc0 (len * sizeof (MonoJitExceptionInfo));
+                       if (type_info)
+                               *type_info = (gpointer *)g_malloc0 (len * sizeof (gpointer));
+
+                       decode_lsda (lsda, code, ex_info ? *ex_info : NULL, type_info ? *type_info : NULL, ex_info_len, this_reg, this_offset);
                }
        }
 
@@ -1116,13 +1122,15 @@ mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJi
  * mono_unwind_decode_mono_fde:
  *
  *   Decode an FDE entry in the LLVM emitted mono EH frame.
- * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
- * only try_start, try_end and handler_start is set.
- * info->type_info is set to a malloc-ed array containing the ttype table from the
- * LSDA.
+ * If EI/TYPE_INFO/UNW_INFO are NULL, compute only the value of the scalar fields in INFO.
+ * Otherwise:
+ * - Fill out EX_INFO with try_start, try_end and handler_start.
+ * - Fill out TYPE_INFO with the ttype table from the LSDA.
+ * - Fill out UNW_INFO with the unwind info.
+ * This function is async safe.
  */
 void
-mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
+mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res, MonoJitExceptionInfo *ex_info, gpointer *type_info, guint8 *unw_info)
 {
        guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
        int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
@@ -1152,7 +1160,10 @@ mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8
                /* The LSDA is embedded directly into the FDE */
                lsda = fde_aug;
 
-               decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
+               /* Get the lengths first */
+               decode_lsda (lsda, code, NULL, NULL, &res->ex_info_len, &res->this_reg, &res->this_offset);
+
+               decode_lsda (lsda, code, ex_info, type_info, NULL, &res->this_reg, &res->this_offset);
        }
 
        /* Decode CIE */
@@ -1183,12 +1194,13 @@ mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8
        cie_cfi_len = p - cie_cfi;
        fde_cfi_len = (fde + fde_len - fde_cfi);
 
-       buf = (guint8 *)g_malloc0 (cie_cfi_len + fde_cfi_len);
-       memcpy (buf, cie_cfi, cie_cfi_len);
-       memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
+       buf = unw_info;
+       if (buf) {
+               memcpy (buf, cie_cfi, cie_cfi_len);
+               memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
+       }
 
        res->unw_info_len = cie_cfi_len + fde_cfi_len;
-       res->unw_info = buf;
 }
 
 /*