Merge remote branch 'upstream/master'
[mono.git] / mono / mini / exceptions-x86.c
index 8b084386ad770d86d68e7554271f64474697cd8c..d3f09813c202f29cb035745f6decaa09f8302f80 100644 (file)
 #include "tasklets.h"
 #include "debug-mini.h"
 
-#ifdef PLATFORM_WIN32
+static gpointer signal_exception_trampoline;
+
+gpointer
+mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
+
+#ifdef TARGET_WIN32
 static void (*restore_stack) (void *);
 
 static MonoW32ExceptionHandler fpe_handler;
@@ -36,8 +41,12 @@ static MonoW32ExceptionHandler segv_handler;
 
 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
 
+#ifndef PROCESS_CALLBACK_FILTER_ENABLED
+#      define PROCESS_CALLBACK_FILTER_ENABLED 1
+#endif
+
 #define W32_SEH_HANDLE_EX(_ex) \
-       if (_ex##_handler) _ex##_handler((int)sctx)
+       if (_ex##_handler) _ex##_handler(0, er, sctx)
 
 /*
  * mono_win32_get_handle_stackoverflow (void):
@@ -103,21 +112,22 @@ mono_win32_get_handle_stackoverflow (void)
 static void 
 win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) 
 {
-    SYSTEM_INFO si;
-    DWORD page_size;
+       SYSTEM_INFO si;
+       DWORD page_size;
        MonoDomain *domain = mono_domain_get ();
-       MonoJitInfo *ji, rji;
+       MonoJitInfo rji;
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
        MonoLMF *lmf = jit_tls->lmf;            
        MonoContext initial_ctx;
        MonoContext ctx;
        guint32 free_stack = 0;
+       StackFrameInfo frame;
 
        /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */
        mono_arch_sigctx_to_monoctx (sctx, &ctx);
        
        /* get our os page size */
-    GetSystemInfo(&si);
+       GetSystemInfo(&si);
        page_size = si.dwPageSize;
 
        /* Let's walk the stack to recover
@@ -132,19 +142,19 @@ win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx)
        do {
                MonoContext new_ctx;
 
-               ji = mono_arch_find_jit_info (domain, jit_tls, &rji, &rji, &ctx, &new_ctx, &lmf, NULL);
-               if (!ji) {
+               mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, &lmf, NULL, &frame);
+               if (!frame.ji) {
                        g_warning ("Exception inside function without unwind info");
                        g_assert_not_reached ();
                }
 
-               if (ji != (gpointer)-1) {
+               if (frame.ji != (gpointer)-1) {
                        free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
                }
 
                /* todo: we should call abort if ji is -1 */
                ctx = new_ctx;
-       } while (free_stack < 64 * 1024 && ji != (gpointer) -1);
+       } while (free_stack < 64 * 1024 && frame.ji != (gpointer) -1);
 
        /* convert into sigcontext to be used in mono_arch_handle_exception */
        mono_arch_monoctx_to_sigctx (&ctx, sctx);
@@ -252,7 +262,7 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
        }
 }
 
-#endif /* PLATFORM_WIN32 */
+#endif /* TARGET_WIN32 */
 
 /*
  * mono_arch_get_restore_context:
@@ -260,24 +270,22 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
  * Returns a pointer to a method which restores a previously saved sigcontext.
  */
 gpointer
-mono_arch_get_restore_context (void)
+mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
 {
-       static guint8 *start = NULL;
+       guint8 *start = NULL;
        guint8 *code;
-
-       if (start)
-               return start;
+       MonoJumpInfo *ji = NULL;
+       GSList *unwind_ops = NULL;
 
        /* restore_contect (MonoContext *ctx) */
-       /* we do not restore X86_EAX, X86_EDX */
 
        start = code = mono_global_codeman_reserve (128);
        
        /* load ctx */
        x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
 
-       /* get return address, stored in EDX */
-       x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
+       /* get return address, stored in ECX */
+       x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
        /* restore EBX */
        x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
        /* restore EDI */
@@ -286,11 +294,31 @@ mono_arch_get_restore_context (void)
        x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
        /* restore ESP */
        x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esp), 4);
+       /* save the return addr to the restored stack */
+       x86_push_reg (code, X86_ECX);
        /* restore EBP */
        x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
+       /* restore ECX */
+       x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ecx), 4);
+       /* restore EDX */
+       x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edx), 4);
+       /* restore EAX */
+       x86_mov_reg_membase (code, X86_EAX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eax), 4);
 
        /* jump to the saved IP */
-       x86_jump_reg (code, X86_EDX);
+       x86_ret (code);
+
+       nacl_global_codeman_validate(&start, 128, &code);
+
+       if (info)
+               *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops);
+       else {
+               GSList *l;
+
+               for (l = unwind_ops; l; l = l->next)
+                       g_free (l->data);
+               g_slist_free (unwind_ops);
+       }
 
        return start;
 }
@@ -303,18 +331,16 @@ mono_arch_get_restore_context (void)
  * @exc object in this case).
  */
 gpointer
-mono_arch_get_call_filter (void)
+mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
 {
-       static guint8* start;
-       static int inited = 0;
+       guint8* start;
        guint8 *code;
+       MonoJumpInfo *ji = NULL;
+       GSList *unwind_ops = NULL;
+       guint kMaxCodeSize = NACL_SIZE (64, 128);
 
-       if (inited)
-               return start;
-
-       inited = 1;
        /* call_filter (MonoContext *ctx, unsigned long eip) */
-       start = code = mono_global_codeman_reserve (64);
+       start = code = mono_global_codeman_reserve (kMaxCodeSize);
 
        x86_push_reg (code, X86_EBP);
        x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
@@ -359,31 +385,51 @@ mono_arch_get_call_filter (void)
        x86_leave (code);
        x86_ret (code);
 
-       g_assert ((code - start) < 64);
+       nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
+
+       if (info)
+               *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops);
+       else {
+               GSList *l;
+
+               for (l = unwind_ops; l; l = l->next)
+                       g_free (l->data);
+               g_slist_free (unwind_ops);
+       }
+
+       g_assert ((code - start) < kMaxCodeSize);
        return start;
 }
 
-static void
-throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsigned long ebx,
-                unsigned long esi, unsigned long edi, unsigned long ebp, MonoObject *exc,
-                unsigned long eip,  unsigned long esp, gboolean rethrow)
+/*
+ * mono_x86_throw_exception:
+ *
+ *   C function called from the throw trampolines.
+ */
+void
+mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc, 
+                                                 mgreg_t eip, gboolean rethrow)
 {
        static void (*restore_context) (MonoContext *);
        MonoContext ctx;
 
        if (!restore_context)
-               restore_context = mono_arch_get_restore_context ();
+               restore_context = mono_get_restore_context ();
 
-       /* Pop argument and return address */
-       ctx.esp = esp + (2 * sizeof (gpointer));
+       ctx.esp = regs [X86_ESP];
        ctx.eip = eip;
-       ctx.ebp = ebp;
-       ctx.edi = edi;
-       ctx.esi = esi;
-       ctx.ebx = ebx;
-       ctx.edx = edx;
-       ctx.ecx = ecx;
-       ctx.eax = eax;
+       ctx.ebp = regs [X86_EBP];
+       ctx.edi = regs [X86_EDI];
+       ctx.esi = regs [X86_ESI];
+       ctx.ebx = regs [X86_EBX];
+       ctx.edx = regs [X86_EDX];
+       ctx.ecx = regs [X86_ECX];
+       ctx.eax = regs [X86_EAX];
+
+#ifdef __APPLE__
+       /* The OSX ABI specifies 16 byte alignment at call sites */
+       g_assert ((ctx.esp % MONO_ARCH_FRAME_ALIGNMENT) == 0);
+#endif
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
@@ -412,110 +458,213 @@ throw_exception (unsigned long eax, unsigned long ecx, unsigned long edx, unsign
        ctx.eip -= 1;
 
        mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
+
        restore_context (&ctx);
 
        g_assert_not_reached ();
 }
 
-static guint8*
-get_throw_exception (gboolean rethrow)
+void
+mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, 
+                                                                mgreg_t eip, gint32 pc_offset)
 {
-       guint8 *start, *code;
+       guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
+       MonoException *ex;
 
-       start = code = mono_global_codeman_reserve (64);
+       ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
 
-       /* Align the stack on apple, since we push 10 args + the return address */
-       x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
-       x86_push_reg (code, X86_ESP);
-       x86_push_membase (code, X86_ESP, 8); /* IP */
-       x86_push_membase (code, X86_ESP, 16); /* exception */
-       x86_push_reg (code, X86_EBP);
-       x86_push_reg (code, X86_EDI);
-       x86_push_reg (code, X86_ESI);
-       x86_push_reg (code, X86_EBX);
-       x86_push_reg (code, X86_EDX);
-       x86_push_reg (code, X86_ECX);
-       x86_push_reg (code, X86_EAX);
-       x86_call_code (code, throw_exception);
-       /* we should never reach this breakpoint */
-       x86_breakpoint (code);
+       eip -= pc_offset;
 
-       g_assert ((code - start) < 64);
+       /* Negate the ip adjustment done in mono_x86_throw_exception () */
+       eip += 1;
 
-       return start;
+       mono_x86_throw_exception (regs, (MonoObject*)ex, eip, FALSE);
 }
 
-/**
- * mono_arch_get_throw_exception:
- *
- * Returns a function pointer which can be used to raise 
- * exceptions. The returned function has the following 
- * signature: void (*func) (MonoException *exc); 
- * For example to raise an arithmetic exception you can use:
- *
- * x86_push_imm (code, mono_get_exception_arithmetic ()); 
- * x86_call_code (code, arch_get_throw_exception ()); 
+static void
+mono_x86_resume_unwind (mgreg_t *regs, MonoObject *exc, 
+                                               mgreg_t eip, gboolean rethrow)
+{
+       MonoContext ctx;
+
+       ctx.esp = regs [X86_ESP];
+       ctx.eip = eip;
+       ctx.ebp = regs [X86_EBP];
+       ctx.edi = regs [X86_EDI];
+       ctx.esi = regs [X86_ESI];
+       ctx.ebx = regs [X86_EBX];
+       ctx.edx = regs [X86_EDX];
+       ctx.ecx = regs [X86_ECX];
+       ctx.eax = regs [X86_EAX];
+
+       mono_resume_unwind (&ctx);
+}
+
+/*
+ * get_throw_trampoline:
  *
+ *  Generate a call to mono_x86_throw_exception/
+ * mono_x86_throw_corlib_exception.
+ * If LLVM is true, generate code which assumes the caller is LLVM generated code, 
+ * which doesn't push the arguments.
  */
-gpointer 
-mono_arch_get_throw_exception (void)
+static guint8*
+get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot)
 {
-       static guint8 *start;
-       static int inited = 0;
+       guint8 *start, *code;
+       int i, stack_size, stack_offset, arg_offsets [5], regs_offset;
+       MonoJumpInfo *ji = NULL;
+       GSList *unwind_ops = NULL;
+       guint kMaxCodeSize = NACL_SIZE (128, 256);
 
-       if (inited)
-               return start;
+       start = code = mono_global_codeman_reserve (kMaxCodeSize);
 
-       start = get_throw_exception (FALSE);
+       stack_size = 128;
 
-       inited = 1;
+       /* 
+        * On apple, the stack is misaligned by the pushing of the return address.
+        */
+       if (!llvm && corlib)
+               /* On OSX, we don't generate alignment code to save space */
+               stack_size += 4;
+       else
+               stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4;
 
-       return start;
-}
+       /*
+        * The stack looks like this:
+        * <pc offset> (only if corlib is TRUE)
+        * <exception object>/<type token>
+        * <return addr> <- esp (unaligned on apple)
+        */
 
-gpointer 
-mono_arch_get_rethrow_exception (void)
-{
-       static guint8 *start;
-       static int inited = 0;
+       mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
+       mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
+
+       /* Alloc frame */
+       x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
+       mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);
+
+       arg_offsets [0] = 0;
+       arg_offsets [1] = 4;
+       arg_offsets [2] = 8;
+       arg_offsets [3] = 12;
+       regs_offset = 16;
+
+       /* Save registers */
+       for (i = 0; i < X86_NREG; ++i)
+               if (i != X86_ESP)
+                       x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4);
+       /* Calculate the offset between the current sp and the sp of the caller */
+       if (llvm) {
+               /* LLVM doesn't push the arguments */
+               stack_offset = stack_size + 4;
+       } else {
+               if (corlib) {
+                       /* Two arguments */
+                       stack_offset = stack_size + 4 + 8;
+#ifdef __APPLE__
+                       /* We don't generate stack alignment code on osx to save space */
+#endif
+               } else {
+                       /* One argument + stack alignment */
+                       stack_offset = stack_size + 4 + 4;
+#ifdef __APPLE__
+                       /* Pop the alignment added by OP_THROW too */
+                       stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
+#else
+                       if (mono_do_x86_stack_align)
+                               stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
+#endif
+               }
+       }
+       /* Save ESP */
+       x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset);
+       x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4);
+
+       /* Set arg1 == regs */
+       x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset);
+       x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4);
+       /* Set arg2 == exc/ex_token_index */
+       if (resume_unwind)
+               x86_mov_reg_imm (code, X86_EAX, 0);
+       else
+               x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4);
+       x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4);
+       /* Set arg3 == eip */
+       if (llvm_abs)
+               x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
+       else
+               x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4);
+       x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4);
+       /* Set arg4 == rethrow/pc_offset */
+       if (resume_unwind) {
+               x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], 0, 4);
+       } else if (corlib) {
+               x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4);
+               if (llvm_abs) {
+                       /* 
+                        * The caller is LLVM code which passes the absolute address not a pc offset,
+                        * so compensate by passing 0 as 'ip' and passing the negated abs address as
+                        * the pc offset.
+                        */
+                       x86_neg_reg (code, X86_EAX);
+               }
+               x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4);
+       } else {
+               x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4);
+       }
+       /* Make the call */
+       if (aot) {
+               // This can be called from runtime code, which can't guarantee that
+               // ebx contains the got address.
+               // So emit the got address loading code too
+               code = mono_arch_emit_load_got_addr (start, code, NULL, &ji);
+               code = mono_arch_emit_load_aotconst (start, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, corlib ? "mono_x86_throw_corlib_exception" : "mono_x86_throw_exception");
+               x86_call_reg (code, X86_EAX);
+       } else {
+               x86_call_code (code, resume_unwind ? (mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception));
+       }
+       x86_breakpoint (code);
 
-       if (inited)
-               return start;
+       nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
+
+       g_assert ((code - start) < kMaxCodeSize);
 
-       start = get_throw_exception (TRUE);
+       if (info)
+               *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops);
+       else {
+               GSList *l;
 
-       inited = 1;
+               for (l = unwind_ops; l; l = l->next)
+                       g_free (l->data);
+               g_slist_free (unwind_ops);
+       }
 
        return start;
 }
 
 /**
- * mono_arch_get_throw_exception_by_name:
+ * mono_arch_get_throw_exception:
  *
  * Returns a function pointer which can be used to raise 
- * corlib exceptions. The returned function has the following 
- * signature: void (*func) (gpointer ip, char *exc_name); 
+ * exceptions. The returned function has the following 
+ * signature: void (*func) (MonoException *exc); 
  * For example to raise an arithmetic exception you can use:
  *
- * x86_push_imm (code, "ArithmeticException"); 
- * x86_push_imm (code, <IP>)
- * x86_jump_code (code, arch_get_throw_exception_by_name ()); 
+ * x86_push_imm (code, mono_get_exception_arithmetic ()); 
+ * x86_call_code (code, arch_get_throw_exception ()); 
  *
  */
 gpointer 
-mono_arch_get_throw_exception_by_name (void)
+mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
 {
-       guint8* start;
-       guint8 *code;
-
-       start = code = mono_global_codeman_reserve (32);
-
-       /* Not used */
-       x86_breakpoint (code);
-
-       mono_arch_flush_icache (start, code - start);
+       return get_throw_trampoline ("throw_exception", FALSE, FALSE, FALSE, FALSE, FALSE, info, aot);
+}
 
-       return start;
+gpointer 
+mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
+{
+       return get_throw_trampoline ("rethrow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot);
 }
 
 /**
@@ -529,65 +678,78 @@ mono_arch_get_throw_exception_by_name (void)
  * needs no relocations in the caller.
  */
 gpointer 
-mono_arch_get_throw_corlib_exception (void)
+mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
 {
-       static guint8* start;
-       static int inited = 0;
-       guint8 *code;
+       return get_throw_trampoline ("throw_corlib_exception", FALSE, FALSE, TRUE, FALSE, FALSE, info, aot);
+}
 
-       if (inited)
-               return start;
+void
+mono_arch_exceptions_init (void)
+{
+       guint8 *tramp;
 
-       inited = 1;
-       code = start = mono_global_codeman_reserve (64);
+/* 
+ * If we're running WoW64, we need to set the usermode exception policy 
+ * for SEHs to behave. This requires hotfix http://support.microsoft.com/kb/976038
+ * or (eventually) Windows 7 SP1.
+ */
+#ifdef HOST_WIN32
+       DWORD flags;
+       FARPROC getter;
+       FARPROC setter;
+       HMODULE kernel32 = LoadLibraryW (L"kernel32.dll");
+
+       if (kernel32) {
+               getter = GetProcAddress (kernel32, "GetProcessUserModeExceptionPolicy");
+               setter = GetProcAddress (kernel32, "SetProcessUserModeExceptionPolicy");
+               if (getter && setter) {
+                       if (getter (&flags))
+                               setter (flags & ~PROCESS_CALLBACK_FILTER_ENABLED);
+               }
+       }
+#endif
 
-       x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4); /* token */
-       x86_alu_reg_imm (code, X86_ADD, X86_EAX, MONO_TOKEN_TYPE_DEF);
-       x86_push_reg (code, X86_EAX);
-       x86_push_imm (code, mono_defaults.exception_class->image);
-       x86_call_code (code, mono_exception_from_token);
-       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
-       /* Compute caller ip */
-       x86_pop_reg (code, X86_ECX);
-       /* Pop token */
-       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
-       x86_pop_reg (code, X86_EDX);
-       x86_alu_reg_reg (code, X86_SUB, X86_ECX, X86_EDX);
-       /* Push exception object */
-       x86_push_reg (code, X86_EAX);
-       /* Push throw IP */
-       x86_push_reg (code, X86_ECX);
-       x86_jump_code (code, mono_arch_get_throw_exception ());
+       if (mono_aot_only) {
+               signal_exception_trampoline = mono_aot_get_trampoline ("x86_signal_exception_trampoline");
+               return;
+       }
 
-       g_assert ((code - start) < 64);
+       /* LLVM needs different throw trampolines */
+       tramp = get_throw_trampoline ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE);
+       mono_register_jit_icall (tramp, "llvm_throw_exception_trampoline", NULL, TRUE);
 
-       return start;
+       tramp = get_throw_trampoline ("llvm_rethrow_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE);
+       mono_register_jit_icall (tramp, "llvm_rethrow_exception_trampoline", NULL, TRUE);
+
+       tramp = get_throw_trampoline ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, FALSE, FALSE, NULL, FALSE);
+       mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE);
+
+       tramp = get_throw_trampoline ("llvm_throw_corlib_exception_abs_trampoline", FALSE, TRUE, TRUE, TRUE, FALSE, NULL, FALSE);
+       mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE);
+
+       tramp = get_throw_trampoline ("llvm_resume_unwind_trampoline", FALSE, FALSE, FALSE, FALSE, TRUE, NULL, FALSE);
+       mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE);
+
+       signal_exception_trampoline = mono_x86_get_signal_exception_trampoline (NULL, FALSE);
 }
 
-/* mono_arch_find_jit_info:
+/*
+ * mono_arch_find_jit_info:
  *
- * This function is used to gather information from @ctx. It return the 
- * MonoJitInfo of the corresponding function, unwinds one stack frame and
- * stores the resulting context into @new_ctx. It also stores a string 
- * describing the stack location into @trace (if not NULL), and modifies
- * the @lmf if necessary. @native_offset return the IP offset from the 
- * start of the function or -1 if that info is not available.
+ * See exceptions-amd64.c for docs.
  */
-MonoJitInfo *
-mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInfo *res, MonoJitInfo *prev_ji, MonoContext *ctx, 
-                        MonoContext *new_ctx, MonoLMF **lmf, gboolean *managed)
+gboolean
+mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
+                                                        MonoJitInfo *ji, MonoContext *ctx, 
+                                                        MonoContext *new_ctx, MonoLMF **lmf,
+                                                        mgreg_t **save_locations,
+                                                        StackFrameInfo *frame)
 {
-       MonoJitInfo *ji;
        gpointer ip = MONO_CONTEXT_GET_IP (ctx);
 
-       /* Avoid costly table lookup during stack overflow */
-       if (prev_ji && (ip > prev_ji->code_start && ((guint8*)ip < ((guint8*)prev_ji->code_start) + prev_ji->code_size)))
-               ji = prev_ji;
-       else
-               ji = mono_jit_info_table_find (domain, ip);
-
-       if (managed)
-               *managed = FALSE;
+       memset (frame, 0, sizeof (StackFrameInfo));
+       frame->ji = ji;
+       frame->managed = FALSE;
 
        *new_ctx = *ctx;
 
@@ -597,9 +759,10 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                guint32 unwind_info_len;
                guint8 *unwind_info;
 
-               if (managed)
-                       if (!ji->method->wrapper_type)
-                               *managed = TRUE;
+               frame->type = FRAME_TYPE_MANAGED;
+
+               if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+                       frame->managed = TRUE;
 
                if (ji->from_aot)
                        unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
@@ -618,7 +781,8 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
 
                mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
                                                   (guint8*)ji->code_start + ji->code_size,
-                                                  ip, regs, MONO_MAX_IREGS + 1, &cfa);
+                                                  ip, regs, MONO_MAX_IREGS + 1,
+                                                  save_locations, MONO_MAX_IREGS, &cfa);
 
                new_ctx->eax = regs [X86_EAX];
                new_ctx->ebx = regs [X86_EBX];
@@ -638,30 +802,52 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
 
                if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
                        /* remove any unused lmf */
-                       *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
+                       *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
                }
 
                /* Pop arguments off the stack */
+               /* 
+                * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes
+                * the caller.
+                */
+#ifndef ENABLE_LLVM
                {
                        MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
 
                        guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
                        new_ctx->esp += stack_to_pop;
                }
+#endif
 
-               return ji;
+               return TRUE;
        } else if (*lmf) {
-               
-               *new_ctx = *ctx;
 
-               if ((ji = mono_jit_info_table_find (domain, (gpointer)(*lmf)->eip))) {
+               if (((guint64)(*lmf)->previous_lmf) & 2) {
+                       /* 
+                        * This LMF entry is created by the soft debug code to mark transitions to
+                        * managed code done during invokes.
+                        */
+                       MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
+
+                       g_assert (ext->debugger_invoke);
+
+                       memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
+
+                       *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
+
+                       frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
+
+                       return TRUE;
+               }
+               
+               if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
                } else {
                        if (!((guint32)((*lmf)->previous_lmf) & 1))
                                /* Top LMF entry */
-                               return (gpointer)-1;
+                               return FALSE;
+                       g_assert_not_reached ();
                        /* Trampoline lmf frame */
-                       memset (res, 0, MONO_SIZEOF_JIT_INFO);
-                       res->method = (*lmf)->method;
+                       frame->method = (*lmf)->method;
                }
 
                new_ctx->esi = (*lmf)->esi;
@@ -670,6 +856,12 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                new_ctx->ebp = (*lmf)->ebp;
                new_ctx->eip = (*lmf)->eip;
 
+               /* Adjust IP */
+               new_ctx->eip --;
+
+               frame->ji = ji;
+               frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
+
                /* Check if we are in a trampoline LMF frame */
                if ((guint32)((*lmf)->previous_lmf) & 1) {
                        /* lmf->esp is set by the trampoline code */
@@ -678,25 +870,27 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
                        /* Pop arguments off the stack */
                        /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */
                        /* FIXME: Handle the IMT/vtable case too */
-                       if ((*lmf)->method && (*lmf)->method != MONO_FAKE_IMT_METHOD && (*lmf)->method != MONO_FAKE_VTABLE_METHOD) {
+#ifndef ENABLE_LLVM
+                       if ((*lmf)->method) {
                                MonoMethod *method = (*lmf)->method;
                                MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1);
 
                                guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
                                new_ctx->esp += stack_to_pop;
                        }
+#endif
                }
                else
                        /* the lmf is always stored on the stack, so the following
                         * expression points to a stack location which can be used as ESP */
                        new_ctx->esp = (unsigned long)&((*lmf)->eip);
 
-               *lmf = (gpointer)(((guint32)(*lmf)->previous_lmf) & ~1);
+               *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
 
-               return ji ? ji : res;
+               return TRUE;
        }
 
-       return NULL;
+       return FALSE;
 }
 
 #ifdef __sun
@@ -714,6 +908,18 @@ mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, MonoJitInf
 void
 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
 {
+#if defined (__native_client__)
+       printf("WARNING: mono_arch_sigctx_to_monoctx() called!\n");
+       mctx->eax = 0xDEADBEEF;
+       mctx->ebx = 0xDEADBEEF;
+       mctx->ecx = 0xDEADBEEF;
+       mctx->edx = 0xDEADBEEF;
+       mctx->ebp = 0xDEADBEEF;
+       mctx->esp = 0xDEADBEEF;
+       mctx->esi = 0xDEADBEEF;
+       mctx->edi = 0xDEADBEEF;
+       mctx->eip = 0xDEADBEEF;
+#else
 #ifdef MONO_ARCH_USE_SIGACTION
        ucontext_t *ctx = (ucontext_t*)sigctx;
        
@@ -739,11 +945,15 @@ mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
        mctx->edi = ctx->SC_EDI;
        mctx->eip = ctx->SC_EIP;
 #endif
+#endif /* if defined(__native_client__) */
 }
 
 void
 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
 {
+#if defined(__native_client__)
+       printf("WARNING: mono_arch_monoctx_to_sigctx() called!\n");
+#else
 #ifdef MONO_ARCH_USE_SIGACTION
        ucontext_t *ctx = (ucontext_t*)sigctx;
 
@@ -769,23 +979,160 @@ mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
        ctx->SC_EDI = mctx->edi;
        ctx->SC_EIP = mctx->eip;
 #endif
+#endif /* __native_client__ */
 }      
 
 gpointer
 mono_arch_ip_from_context (void *sigctx)
 {
+#if defined(__native_client__)
+       printf("WARNING: mono_arch_ip_from_context() called!\n");
+       return (NULL);
+#else
 #ifdef MONO_ARCH_USE_SIGACTION
        ucontext_t *ctx = (ucontext_t*)sigctx;
        return (gpointer)UCONTEXT_REG_EIP (ctx);
 #else
        struct sigcontext *ctx = sigctx;
        return (gpointer)ctx->SC_EIP;
-#endif 
+#endif
+#endif /* __native_client__ */
+}
+
+/*
+ * handle_exception:
+ *
+ *   Called by resuming from a signal handler.
+ */
+static void
+handle_signal_exception (gpointer obj)
+{
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       MonoContext ctx;
+       static void (*restore_context) (MonoContext *);
+
+       if (!restore_context)
+               restore_context = mono_get_restore_context ();
+
+       memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
+
+       if (mono_debugger_handle_exception (&ctx, (MonoObject *)obj))
+               return;
+
+       mono_handle_exception (&ctx, obj, MONO_CONTEXT_GET_IP (&ctx), FALSE);
+
+       restore_context (&ctx);
+}
+
+/*
+ * mono_x86_get_signal_exception_trampoline:
+ *
+ *   This x86 specific trampoline is used to call handle_signal_exception.
+ */
+gpointer
+mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot)
+{
+       guint8 *start, *code;
+       MonoJumpInfo *ji = NULL;
+       GSList *unwind_ops = NULL;
+       int stack_size;
+
+       start = code = mono_global_codeman_reserve (128);
+
+       /* Caller ip */
+       x86_push_reg (code, X86_ECX);
+
+       mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
+       mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
+
+       /* Fix the alignment to be what apple expects */
+       stack_size = 12;
+
+       x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
+       mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);
+
+       /* Arg1 */
+       x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4);
+       /* Branch to target */
+       x86_call_reg (code, X86_EDX);
+
+       g_assert ((code - start) < 128);
+
+       if (info)
+               *info = mono_tramp_info_create (g_strdup ("x86_signal_exception_trampoline"), start, code - start, ji, unwind_ops);
+       else {
+               GSList *l;
+
+               for (l = unwind_ops; l; l = l->next)
+                       g_free (l->data);
+               g_slist_free (unwind_ops);
+       }
+
+       return start;
 }
 
 gboolean
 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
 {
+#if defined(MONO_ARCH_USE_SIGACTION)
+       ucontext_t *ctx = (ucontext_t*)sigctx;
+
+       /*
+        * Handling the exception in the signal handler is problematic, since the original
+        * signal is disabled, and we could run arbitrary code though the debugger. So
+        * resume into the normal stack and do most work there if possible.
+        */
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       guint64 sp = UCONTEXT_REG_ESP (ctx);
+
+       /* Pass the ctx parameter in TLS */
+       mono_arch_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx);
+       /*
+        * Can't pass the obj on the stack, since we are executing on the
+        * same stack. Can't save it into MonoJitTlsData, since it needs GC tracking.
+        * So put it into a register, and branch to a trampoline which
+        * pushes it.
+        */
+       g_assert (!test_only);
+       UCONTEXT_REG_EAX (ctx) = (gsize)obj;
+       UCONTEXT_REG_ECX (ctx) = UCONTEXT_REG_EIP (ctx);
+       UCONTEXT_REG_EDX (ctx) = (gsize)handle_signal_exception;
+
+       /* Allocate a stack frame, align it to 16 bytes which is needed on apple */
+       sp -= 16;
+       sp &= ~15;
+       UCONTEXT_REG_ESP (ctx) = sp;
+
+       UCONTEXT_REG_EIP (ctx) = (gsize)signal_exception_trampoline;
+
+       return TRUE;
+#elif defined (TARGET_WIN32)
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       struct sigcontext *ctx = (struct sigcontext *)sigctx;
+       guint64 sp = ctx->SC_ESP;
+
+       mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
+
+       /*
+        * Can't pass the obj on the stack, since we are executing on the
+        * same stack. Can't save it into MonoJitTlsData, since it needs GC tracking.
+        * So put it into a register, and branch to a trampoline which
+        * pushes it.
+        */
+       g_assert (!test_only);
+       ctx->SC_EAX = (gsize)obj;
+       ctx->SC_ECX = ctx->SC_EIP;
+       ctx->SC_EDX = (gsize)handle_signal_exception;
+
+       /* Allocate a stack frame, align it to 16 bytes which is needed on apple */
+       sp -= 16;
+       sp &= ~15;
+       ctx->SC_ESP = sp;
+
+       ctx->SC_EIP = (gsize)signal_exception_trampoline;
+
+       return TRUE;
+#else
        MonoContext mctx;
 
        mono_arch_sigctx_to_monoctx (sigctx, &mctx);
@@ -798,6 +1145,7 @@ mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
        mono_arch_monoctx_to_sigctx (&mctx, sigctx);
 
        return TRUE;
+#endif
 }
 
 static void
@@ -832,7 +1180,7 @@ altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
        void (*restore_context) (MonoContext *);
        MonoContext mctx;
 
-       restore_context = mono_arch_get_restore_context ();
+       restore_context = mono_get_restore_context ();
        mono_arch_sigctx_to_monoctx (sigctx, &mctx);
 
        if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) {
@@ -853,7 +1201,7 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean
 #ifdef MONO_ARCH_USE_SIGACTION
        MonoException *exc = NULL;
        ucontext_t *ctx = (ucontext_t*)sigctx;
-       MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx));
+       MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx), NULL);
        gpointer *sp;
        int frame_size;
 
@@ -863,7 +1211,7 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean
         */
        if (!ji && fault_addr == (gpointer)UCONTEXT_REG_EIP (ctx)) {
                glong *sp = (gpointer)UCONTEXT_REG_ESP (ctx);
-               ji = mono_jit_info_table_find (mono_domain_get (), (gpointer)sp [0]);
+               ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)sp [0], NULL);
                if (ji)
                        UCONTEXT_REG_EIP (ctx) = sp [0];
        }
@@ -909,6 +1257,9 @@ mono_tasklets_arch_restore (void)
        static guint8* saved = NULL;
        guint8 *code, *start;
 
+#ifdef __native_client_codegen__
+       g_print("mono_tasklets_arch_restore needs to be aligned for Native Client\n");
+#endif
        if (saved)
                return (MonoContinuationRestore)saved;
        code = start = mono_global_codeman_reserve (48);