Merge pull request #2231 from ludovic-henry/coop-sync-friendliness
[mono.git] / mono / mini / mini-exceptions.c
index d5323d2a3bae65565e1b0dba00affd7927980fc9..26c9451330e2e6786e57841f94baed3ce723afc8 100644 (file)
 #include <sys/prctl.h>
 #endif
 
+#ifdef HAVE_UNWIND_H
+#include <unwind.h>
+#endif
+
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/threads.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/exception.h>
-#include <mono/metadata/gc-internal.h>
+#include <mono/metadata/object-internals.h>
+#include <mono/metadata/gc-internals.h>
 #include <mono/metadata/mono-debug.h>
 #include <mono/metadata/profiler.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/metadata/environment.h>
+#include <mono/metadata/mono-mlist.h>
 #include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-logger-internal.h>
+#include <mono/utils/mono-logger-internals.h>
 
 #include "mini.h"
 #include "trace.h"
 #include "debugger-agent.h"
 #include "seq-points.h"
+#include "llvm-runtime.h"
+#include "mini-llvm.h"
+
+#ifdef ENABLE_LLVM
+#include "mini-llvm-cpp.h"
+#endif
 
 #ifdef ENABLE_EXTENSION_MODULE
 #include "../../../mono-extensions/mono/mini/mini-exceptions.c"
@@ -98,17 +110,19 @@ mono_exceptions_init (void)
                MonoTrampInfo *info;
 
                restore_context_func = mono_arch_get_restore_context (&info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
                call_filter_func = mono_arch_get_call_filter (&info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
                throw_exception_func = mono_arch_get_throw_exception (&info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
                rethrow_exception_func = mono_arch_get_rethrow_exception (&info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
        }
 #ifdef MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT
-       try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
-       restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
+       if (!mono_llvm_only) {
+               try_more_restore_tramp = mono_create_specific_trampoline (try_more_restore, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
+               restore_stack_protection_tramp = mono_create_specific_trampoline (restore_stack_protection, MONO_TRAMPOLINE_RESTORE_STACK_PROT, mono_domain_get (), NULL);
+       }
 #endif
 
 #ifdef MONO_ARCH_HAVE_EXCEPTIONS_INIT
@@ -116,7 +130,11 @@ mono_exceptions_init (void)
 #endif
        cbs.mono_walk_stack_with_ctx = mono_runtime_walk_stack_with_ctx;
        cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
-       cbs.mono_raise_exception = mono_get_throw_exception ();
+
+       if (mono_llvm_only)
+               cbs.mono_raise_exception = mono_llvm_raise_exception;
+       else
+               cbs.mono_raise_exception = mono_get_throw_exception ();
        cbs.mono_raise_exception_with_ctx = mono_raise_exception_with_ctx;
        cbs.mono_exception_walk_trace = mono_exception_walk_trace;
        cbs.mono_install_handler_block_guard = mono_install_handler_block_guard;
@@ -165,7 +183,7 @@ mono_get_throw_corlib_exception (void)
                code = mono_aot_get_trampoline ("throw_corlib_exception");
        else {
                code = mono_arch_get_throw_corlib_exception (&info, FALSE);
-               mono_tramp_info_register (info);
+               mono_tramp_info_register (info, NULL);
        }
 
        mono_memory_barrier ();
@@ -243,6 +261,8 @@ find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, Mo
                if (managed)
                        *managed = TRUE;
                return frame.ji;
+       case FRAME_TYPE_TRAMPOLINE:
+               return frame.ji;
        case FRAME_TYPE_MANAGED_TO_NATIVE:
                if (frame.ji)
                        return frame.ji;
@@ -301,10 +321,10 @@ mono_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *re
        if (ji == (gpointer)-1)
                return ji;
 
-       if (ji)
+       if (ji && !ji->is_trampoline)
                method = jinfo_get_method (ji);
 
-       if (managed2 || (ji && method->wrapper_type)) {
+       if (managed2 || (method && method->wrapper_type)) {
                const char *real_ip, *start;
                gint32 offset;
 
@@ -397,7 +417,7 @@ mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
                *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~(SIZEOF_VOID_P -1));
        }
 
-       if (frame->ji && !frame->ji->async)
+       if (frame->ji && !frame->ji->is_trampoline && !frame->ji->async)
                method = jinfo_get_method (frame->ji);
 
        if (frame->type == FRAME_TYPE_MANAGED && method) {
@@ -451,6 +471,9 @@ mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls,
        return TRUE;
 }
 
+/*
+ * This function is async-safe.
+ */
 static gpointer
 get_generic_info_from_stack_frame (MonoJitInfo *ji, MonoContext *ctx)
 {
@@ -511,7 +534,7 @@ static MonoGenericContext
 get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
 {
        MonoGenericContext context = { NULL, NULL };
-       MonoClass *class, *method_container_class;
+       MonoClass *klass, *method_container_class;
        MonoMethod *method;
 
        g_assert (generic_info);
@@ -521,15 +544,15 @@ get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
        if (mono_method_get_context (method)->method_inst) {
                MonoMethodRuntimeGenericContext *mrgctx = generic_info;
 
-               class = mrgctx->class_vtable->klass;
+               klass = mrgctx->class_vtable->klass;
                context.method_inst = mrgctx->method_inst;
                g_assert (context.method_inst);
        } else if ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype) {
                MonoVTable *vtable = generic_info;
 
-               class = vtable->klass;
+               klass = vtable->klass;
        } else {
-               class = generic_info;
+               klass = generic_info;
        }
 
        //g_assert (!method->klass->generic_container);
@@ -539,18 +562,18 @@ get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_info)
                method_container_class = method->klass;
 
        /* class might refer to a subclass of method's class */
-       while (!(class == method->klass || (class->generic_class && class->generic_class->container_class == method_container_class))) {
-               class = class->parent;
-               g_assert (class);
+       while (!(klass == method->klass || (klass->generic_class && klass->generic_class->container_class == method_container_class))) {
+               klass = klass->parent;
+               g_assert (klass);
        }
 
-       if (class->generic_class || class->generic_container)
-               context.class_inst = mini_class_get_context (class)->class_inst;
+       if (klass->generic_class || klass->generic_container)
+               context.class_inst = mini_class_get_context (klass)->class_inst;
 
-       if (class->generic_class)
-               g_assert (mono_class_has_parent_and_ignore_generics (class->generic_class->container_class, method_container_class));
+       if (klass->generic_class)
+               g_assert (mono_class_has_parent_and_ignore_generics (klass->generic_class->container_class, method_container_class));
        else
-               g_assert (mono_class_has_parent_and_ignore_generics (class, method_container_class));
+               g_assert (mono_class_has_parent_and_ignore_generics (klass, method_container_class));
 
        return context;
 }
@@ -615,50 +638,6 @@ mono_exception_walk_trace (MonoException *ex, MonoExceptionFrameWalk func, gpoin
        return len > 0;
 }
 
-MonoString *
-ves_icall_System_Exception_get_trace (MonoException *ex)
-{
-       MonoDomain *domain = mono_domain_get ();
-       MonoString *res;
-       MonoArray *ta = ex->trace_ips;
-       int i, len;
-       GString *trace_str;
-
-       if (ta == NULL)
-               /* Exception is not thrown yet */
-               return NULL;
-
-       len = mono_array_length (ta) >> 1;
-       trace_str = g_string_new ("");
-       for (i = 0; i < len; i++) {
-               MonoJitInfo *ji;
-               gpointer ip = mono_array_get (ta, gpointer, i * 2 + 0);
-               gpointer generic_info = mono_array_get (ta, gpointer, i * 2 + 1);
-
-               ji = mono_jit_info_table_find (domain, ip);
-               if (ji == NULL) {
-                       /* Unmanaged frame */
-                       g_string_append_printf (trace_str, "in (unmanaged) %p\n", ip);
-               } else {
-                       gchar *location;
-                       gint32 address;
-                       MonoMethod *method = get_method_from_stack_frame (ji, generic_info);
-
-                       address = (char *)ip - (char *)ji->code_start;
-                       location = mono_debug_print_stack_frame (
-                               method, address, ex->object.vtable->domain);
-
-                       g_string_append_printf (trace_str, "%s\n", location);
-                       g_free (location);
-               }
-       }
-
-       res = mono_string_new (ex->object.vtable->domain, trace_str->str);
-       g_string_free (trace_str, TRUE);
-
-       return res;
-}
-
 MonoArray *
 ves_icall_get_trace (MonoException *exc, gint32 skip, MonoBoolean need_file_info)
 {
@@ -808,6 +787,10 @@ mono_walk_stack_with_state (MonoJitStackWalk func, MonoThreadUnwindState *state,
 
        g_assert (state->valid);
 
+       if (!state->unwind_data [MONO_UNWIND_DATA_DOMAIN])
+               /* Not attached */
+               return;
+
        mono_walk_stack_full (func,
                &state->ctx, 
                state->unwind_data [MONO_UNWIND_DATA_DOMAIN],
@@ -870,7 +853,7 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain
                if (!res)
                        return;
 
-               if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji) {
+               if ((unwind_options & MONO_UNWIND_LOOKUP_IL_OFFSET) && frame.ji && !frame.ji->is_trampoline) {
                        MonoDebugSourceLocation *source;
 
                        source = mono_debug_lookup_source_location (jinfo_get_method (frame.ji), frame.native_offset, domain);
@@ -889,7 +872,7 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain
 
                frame.il_offset = il_offset;
 
-               if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji) {
+               if ((unwind_options & MONO_UNWIND_LOOKUP_ACTUAL_METHOD) && frame.ji && !frame.ji->is_trampoline) {
                        frame.actual_method = get_method_from_stack_frame (frame.ji, get_generic_info_from_stack_frame (frame.ji, &ctx));
                } else {
                        frame.actual_method = frame.method;
@@ -944,7 +927,9 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
                if (!res)
                        return FALSE;
 
-               if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || frame.type == FRAME_TYPE_DEBUGGER_INVOKE)
+               if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+                               frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
+                               frame.type == FRAME_TYPE_TRAMPOLINE)
                        continue;
 
                ji = frame.ji;
@@ -983,25 +968,6 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
        return TRUE;
 }
 
-static MonoArray *
-glist_to_array (GList *list, MonoClass *eclass) 
-{
-       MonoDomain *domain = mono_domain_get ();
-       MonoArray *res;
-       int len, i;
-
-       if (!list)
-               return NULL;
-
-       len = g_list_length (list);
-       res = mono_array_new (domain, eclass, len);
-
-       for (i = 0; list; list = list->next, i++)
-               mono_array_set (res, gpointer, i, list->data);
-
-       return res;
-}
-
 static MonoClass*
 get_exception_catch_class (MonoJitExceptionInfo *ei, MonoJitInfo *ji, MonoContext *ctx)
 {
@@ -1085,7 +1051,7 @@ mini_jit_info_table_find_ext (MonoDomain *domain, char *addr, gboolean allow_tra
 MonoJitInfo*
 mini_jit_info_table_find (MonoDomain *domain, char *addr, MonoDomain **out_domain)
 {
-       return mini_jit_info_table_find_ext (domain, addr, FALSE, out_domain);
+       return mini_jit_info_table_find_ext (domain, addr, TRUE, out_domain);
 }
 
 /*
@@ -1183,18 +1149,42 @@ build_native_trace (void)
 #endif
 }
 
-#define setup_managed_stacktrace_information() do {    \
-       if (mono_ex && !initial_trace_ips) {    \
-               trace_ips = g_list_reverse (trace_ips); \
-               MONO_OBJECT_SETREF (mono_ex, trace_ips, glist_to_array (trace_ips, mono_defaults.int_class));   \
-               MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ());  \
-               if (has_dynamic_methods)        \
-                       /* These methods could go away anytime, so compute the stack trace now */       \
-                       MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));      \
-       }       \
-       g_list_free (trace_ips);        \
-       trace_ips = NULL;       \
-} while (0)
+static void
+setup_stack_trace (MonoException *mono_ex, GSList *dynamic_methods, MonoArray *initial_trace_ips, GList **trace_ips)
+{
+       if (mono_ex && !initial_trace_ips) {
+               *trace_ips = g_list_reverse (*trace_ips);
+               MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (*trace_ips, mono_defaults.int_class));
+               MONO_OBJECT_SETREF (mono_ex, native_trace_ips, build_native_trace ());
+               if (dynamic_methods) {
+                       /* These methods could go away anytime, so save a reference to them in the exception object */
+                       GSList *l;
+                       MonoMList *list = NULL;
+
+                       for (l = dynamic_methods; l; l = l->next) {
+                               guint32 dis_link;
+                               MonoDomain *domain = mono_domain_get ();
+
+                               if (domain->method_to_dyn_method) {
+                                       mono_domain_lock (domain);
+                                       dis_link = (guint32)(size_t)g_hash_table_lookup (domain->method_to_dyn_method, l->data);
+                                       mono_domain_unlock (domain);
+                                       if (dis_link) {
+                                               MonoObject *o = mono_gchandle_get_target (dis_link);
+                                               if (o) {
+                                                       list = mono_mlist_prepend (list, o);
+                                               }
+                                       }
+                               }
+                       }
+
+                       MONO_OBJECT_SETREF (mono_ex, dynamic_methods, list);
+               }
+       }
+       g_list_free (*trace_ips);
+       *trace_ips = NULL;
+}
+
 /*
  * mono_handle_exception_internal_first_pass:
  *
@@ -1212,12 +1202,12 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
        MonoLMF *lmf = mono_get_lmf ();
        MonoArray *initial_trace_ips = NULL;
        GList *trace_ips = NULL;
+       GSList *dynamic_methods = NULL;
        MonoException *mono_ex;
        gboolean stack_overflow = FALSE;
        MonoContext initial_ctx;
        MonoMethod *method;
        int frame_count = 0;
-       gboolean has_dynamic_methods = FALSE;
        gint32 filter_idx;
        int i;
        MonoObject *ex_obj;
@@ -1265,7 +1255,9 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
 
                unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
                if (unwind_res) {
-                       if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
+                       if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
+                                       frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+                                       frame.type == FRAME_TYPE_TRAMPOLINE) {
                                *ctx = new_ctx;
                                continue;
                        }
@@ -1274,7 +1266,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
                }
 
                if (!unwind_res) {
-                       setup_managed_stacktrace_information ();
+                       setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+                       g_slist_free (dynamic_methods);
                        return FALSE;
                }
 
@@ -1302,7 +1295,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
                }
 
                if (method->dynamic)
-                       has_dynamic_methods = TRUE;
+                       dynamic_methods = g_slist_prepend (dynamic_methods, method);
 
                if (stack_overflow) {
                        if (DOES_STACK_GROWS_UP)
@@ -1349,7 +1342,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
                                        FIXME Not 100% sure if it's a good idea even with user clauses.
                                        */
                                        if (is_user_frame)
-                                               setup_managed_stacktrace_information ();
+                                               setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
 
 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
                                        if (ji->from_llvm)
@@ -1385,7 +1378,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
 
                                        if (filtered) {
                                                if (!is_user_frame)
-                                                       setup_managed_stacktrace_information ();
+                                                       setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+                                               g_slist_free (dynamic_methods);
                                                /* mono_debugger_agent_handle_exception () needs this */
                                                MONO_CONTEXT_SET_IP (ctx, ei->handler_start);
                                                return TRUE;
@@ -1393,7 +1387,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, gpointer obj, gint3
                                }
 
                                if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (ex_obj, catch_class)) {
-                                       setup_managed_stacktrace_information ();
+                                       setup_stack_trace (mono_ex, dynamic_methods, initial_trace_ips, &trace_ips);
+                                       g_slist_free (dynamic_methods);
 
                                        if (out_ji)
                                                *out_ji = ji;
@@ -1531,7 +1526,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gboolean resume,
                        if (msg == NULL) {
                                msg = message ? mono_string_to_utf8 ((MonoString *) message) : g_strdup ("(System.Exception.Message property not available)");
                        }
-                       g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)GetCurrentThreadId (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
+                       g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)mono_native_thread_id_get (), mono_object_class (obj)->name_space, mono_object_class (obj)->name, msg);
                        g_free (msg);
                        if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
                                mono_print_thread_dump_from_ctx (ctx);
@@ -1602,7 +1597,9 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gboolean resume,
 
                        unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame);
                        if (unwind_res) {
-                               if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || frame.type == FRAME_TYPE_MANAGED_TO_NATIVE) {
+                               if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE ||
+                                               frame.type == FRAME_TYPE_MANAGED_TO_NATIVE ||
+                                               frame.type == FRAME_TYPE_TRAMPOLINE) {
                                        *ctx = new_ctx;
                                        continue;
                                }
@@ -1731,8 +1728,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gboolean resume,
 
                                        return 0;
                                }
-                               if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
-                                       (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT)) {
+                               if (ei->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
                                        if (mono_trace_is_enabled () && mono_trace_eval (method))
                                                g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE));
                                        jit_tls->orig_ex_ctx_set = TRUE;
@@ -1740,8 +1736,7 @@ mono_handle_exception_internal (MonoContext *ctx, gpointer obj, gboolean resume,
                                        jit_tls->orig_ex_ctx_set = FALSE;
                                        call_filter (ctx, ei->handler_start);
                                }
-                               if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx)) &&
-                                       (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY)) {
+                               if (ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) {
                                        if (mono_trace_is_enabled () && mono_trace_eval (method))
                                                g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE));
                                        jit_tls->orig_ex_ctx_set = TRUE;
@@ -1984,6 +1979,9 @@ mono_altstack_restore_prot (mgreg_t *regs, guint8 *code, gpointer *tramp_data, g
 gboolean
 mono_handle_soft_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx, MONO_SIG_HANDLER_INFO_TYPE *siginfo, guint8* fault_addr)
 {
+       if (mono_llvm_only)
+               return FALSE;
+
        /* we got a stack overflow in the soft-guard pages
         * There are two cases:
         * 1) managed code caused the overflow: we unprotect the soft-guard page
@@ -2044,7 +2042,7 @@ print_overflow_stack_frame (StackFrameInfo *frame, MonoContext *ctx, gpointer da
        PrintOverflowUserData *user_data = data;
        gchar *location;
 
-       if (frame->ji)
+       if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
                method = jinfo_get_method (frame->ji);
 
        if (method) {
@@ -2097,7 +2095,7 @@ mono_handle_hard_stack_ovf (MonoJitTlsData *jit_tls, MonoJitInfo *ji, void *ctx,
 
        mono_walk_stack_with_ctx (print_overflow_stack_frame, &mctx, MONO_UNWIND_LOOKUP_ACTUAL_METHOD, &ud);
 #else
-       if (ji && jinfo_get_method (ji))
+       if (ji && !ji->is_trampoline && jinfo_get_method (ji))
                mono_runtime_printf_err ("At %s", mono_method_full_name (jinfo_get_method (ji), TRUE));
        else
                mono_runtime_printf_err ("At <unmanaged>.");
@@ -2111,7 +2109,7 @@ print_stack_frame_to_stderr (StackFrameInfo *frame, MonoContext *ctx, gpointer d
 {
        MonoMethod *method = NULL;
 
-       if (frame->ji)
+       if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
                method = jinfo_get_method (frame->ji);
 
        if (method) {
@@ -2130,7 +2128,7 @@ print_stack_frame_to_string (StackFrameInfo *frame, MonoContext *ctx, gpointer d
        GString *p = (GString*)data;
        MonoMethod *method = NULL;
 
-       if (frame->ji)
+       if (frame->ji && frame->type != FRAME_TYPE_TRAMPOLINE)
                method = jinfo_get_method (frame->ji);
 
        if (method && frame->domain) {
@@ -2526,20 +2524,16 @@ mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
                return FALSE;
        }
 
-       if (sigctx)
+       if (sigctx) {
                mono_sigctx_to_monoctx (sigctx, &ctx->ctx);
-       else
-#if defined(MONO_CROSS_COMPILE)
-               ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
-#elif MONO_ARCH_HAS_MONO_CONTEXT
-               MONO_CONTEXT_GET_CURRENT (ctx->ctx);
-#else
-               g_error ("Use a null sigctx requires a working mono-context");
-#endif
 
-       ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
-       ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
-       ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
+               ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
+               ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
+               ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread->jit_data;
+       }
+       else {
+               mono_thread_state_init (ctx);
+       }
 
        if (!ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] || !ctx->unwind_data [MONO_UNWIND_DATA_LMF])
                return FALSE;
@@ -2552,6 +2546,26 @@ mono_thread_state_init_from_sigctx (MonoThreadUnwindState *ctx, void *sigctx)
 #endif
 }
 
+void
+mono_thread_state_init (MonoThreadUnwindState *ctx)
+{
+       MonoThreadInfo *thread = mono_thread_info_current_unchecked ();
+
+#if defined(MONO_CROSS_COMPILE)
+       ctx->valid = FALSE; //A cross compiler doesn't need to suspend.
+#elif MONO_ARCH_HAS_MONO_CONTEXT
+       MONO_CONTEXT_GET_CURRENT (ctx->ctx);
+#else
+       g_error ("Use a null sigctx requires a working mono-context");
+#endif
+
+       ctx->unwind_data [MONO_UNWIND_DATA_DOMAIN] = mono_domain_get ();
+       ctx->unwind_data [MONO_UNWIND_DATA_LMF] = mono_get_lmf ();
+       ctx->unwind_data [MONO_UNWIND_DATA_JIT_TLS] = thread ? thread->jit_data : NULL;
+       ctx->valid = TRUE;
+}
+
+
 gboolean
 mono_thread_state_init_from_monoctx (MonoThreadUnwindState *ctx, MonoContext *mctx)
 {
@@ -2699,3 +2713,212 @@ mono_jinfo_get_epilog_size (MonoJitInfo *ji)
 
        return info->epilog_size;
 }
+
+/*
+ * LLVM/Bitcode exception handling.
+ */
+
+#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
+
+#if 0
+static gboolean show_native_addresses = TRUE;
+#else
+static gboolean show_native_addresses = FALSE;
+#endif
+
+static _Unwind_Reason_Code
+build_stack_trace (struct _Unwind_Context *frame_ctx, void *state)
+{
+       MonoDomain *domain = mono_domain_get ();
+       uintptr_t ip = _Unwind_GetIP (frame_ctx);
+
+       if (show_native_addresses || mono_jit_info_table_find (domain, (char*)ip)) {
+               GList **trace_ips = (GList **)state;
+               *trace_ips = g_list_prepend (*trace_ips, (gpointer)ip);
+       }
+
+       return _URC_NO_REASON;
+}
+
+#endif
+
+static void
+throw_exception (MonoObject *ex, gboolean rethrow)
+{
+       MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+       MonoException *mono_ex;
+
+       if (!mono_object_isinst (ex, mono_defaults.exception_class))
+               mono_ex = mono_get_exception_runtime_wrapped (ex);
+       else
+               mono_ex = (MonoException*)ex;
+
+       // Note: Not pinned
+       jit_tls->thrown_exc = mono_gchandle_new ((MonoObject*)mono_ex, FALSE);
+
+       if (!rethrow) {
+#ifdef MONO_ARCH_HAVE_UNWIND_BACKTRACE
+               GList *l, *ips = NULL;
+               GList *trace;
+
+               _Unwind_Backtrace (build_stack_trace, &ips);
+               /* The list contains gshared info-ip pairs */
+               trace = NULL;
+               ips = g_list_reverse (ips);
+               for (l = ips; l; l = l->next) {
+                       // FIXME:
+                       trace = g_list_append (trace, l->data);
+                       trace = g_list_append (trace, NULL);
+               }
+               MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace, mono_defaults.int_class));
+               g_list_free (l);
+               g_list_free (trace);
+#endif
+       }
+
+       mono_llvm_cpp_throw_exception ();
+}
+
+void
+mono_llvm_throw_exception (MonoObject *ex)
+{
+       throw_exception (ex, FALSE);
+}
+
+void
+mono_llvm_rethrow_exception (MonoObject *ex)
+{
+       throw_exception (ex, TRUE);
+}
+
+void
+mono_llvm_raise_exception (MonoException *e)
+{
+       mono_llvm_throw_exception ((MonoObject*)e);
+}
+
+void
+mono_llvm_throw_corlib_exception (guint32 ex_token_index)
+{
+       guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
+       MonoException *ex;
+
+       ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
+
+       mono_llvm_throw_exception ((MonoObject*)ex);
+}
+
+/*
+ * mono_llvm_resume_exception:
+ *
+ *   Resume exception propagation.
+ */
+void
+mono_llvm_resume_exception (void)
+{
+       mono_llvm_cpp_throw_exception ();
+}
+
+/*
+ * mono_llvm_load_exception:
+ *
+ *   Return the currently thrown exception.
+ */
+MonoObject *
+mono_llvm_load_exception (void)
+{
+       MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+
+       MonoException *mono_ex = (MonoException*)mono_gchandle_get_target (jit_tls->thrown_exc);
+       g_assert (mono_ex->trace_ips);
+
+       GList *trace_ips = NULL;
+       gpointer ip = __builtin_return_address (0);
+
+       size_t upper = mono_array_length (mono_ex->trace_ips);
+
+       for (int i = 0; i < upper; i++) {
+               gpointer curr_ip = mono_array_get (mono_ex->trace_ips, gpointer, i);
+               trace_ips = g_list_prepend (trace_ips, curr_ip);
+
+               if (ip == curr_ip)
+                       break;
+       }
+
+       // FIXME: Does this work correctly for rethrows?
+       // We may be discarding useful information
+       // when this gets GC'ed
+       MONO_OBJECT_SETREF (mono_ex, trace_ips, mono_glist_to_array (trace_ips, mono_defaults.int_class));
+       g_list_free (trace_ips);
+
+       // FIXME:
+       //MONO_OBJECT_SETREF (mono_ex, stack_trace, ves_icall_System_Exception_get_trace (mono_ex));
+
+       return &mono_ex->object;
+}
+
+/*
+ * mono_llvm_clear_exception:
+ *
+ *   Mark the currently thrown exception as handled.
+ */
+void
+mono_llvm_clear_exception (void)
+{
+       MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+       mono_gchandle_free (jit_tls->thrown_exc);
+       jit_tls->thrown_exc = 0;
+
+       mono_memory_barrier ();
+}
+
+/*
+ * mono_llvm_match_exception:
+ *
+ *   Return the innermost clause containing REGION_START-REGION_END which can handle
+ * the current exception.
+ */
+gint32
+mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end)
+{
+       MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+       MonoObject *exc;
+       gint32 index = -1;
+
+       g_assert (jit_tls->thrown_exc);
+       exc = mono_gchandle_get_target (jit_tls->thrown_exc);
+       for (int i = 0; i < jinfo->num_clauses; i++) {
+               MonoJitExceptionInfo *ei = &jinfo->clauses [i];
+
+               if (! (ei->try_offset == region_start && ei->try_offset + ei->try_len == region_end) )
+                       continue;
+
+               // FIXME: Handle edge cases handled in get_exception_catch_class
+               if (ei->flags == MONO_EXCEPTION_CLAUSE_NONE && mono_object_isinst (exc, ei->data.catch_class)) {
+                       index = ei->clause_index;
+                       break;
+               } else if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                       g_assert_not_reached ();
+               }
+       }
+
+       return index;
+}
+
+#ifdef ENABLE_LLVM
+_Unwind_Reason_Code 
+mono_debug_personality (int a, _Unwind_Action b,
+uint64_t c, struct _Unwind_Exception *d, struct _Unwind_Context *e)
+{
+       g_assert_not_reached ();
+}
+#else
+void
+mono_debug_personality (void);
+
+void
+mono_debug_personality (void)
+{
+       g_assert_not_reached ();
+}
+#endif