Merge remote branch 'upstream/master'
[mono.git] / mono / mini / exceptions-x86.c
index 0384d6d97c11365ddf77ca30a800467df89c5dfd..d3f09813c202f29cb035745f6decaa09f8302f80 100644 (file)
 
 #include "mini.h"
 #include "mini-x86.h"
+#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;
@@ -34,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):
@@ -101,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
@@ -130,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);
@@ -250,7 +262,7 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
        }
 }
 
-#endif /* PLATFORM_WIN32 */
+#endif /* TARGET_WIN32 */
 
 /*
  * mono_arch_get_restore_context:
@@ -258,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 */
@@ -284,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;
 }
@@ -301,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);
@@ -334,9 +362,19 @@ mono_arch_get_call_filter (void)
        x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
        x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
 
+       /* align stack and save ESP */
+       x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
+       x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
+       g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
+       x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
+       x86_push_reg (code, X86_EDX);
+
        /* call the handler */
        x86_call_reg (code, X86_ECX);
 
+       /* restore ESP */
+       x86_pop_reg (code, X86_ESP);
+
        /* restore EBP */
        x86_pop_reg (code, X86_EBP);
 
@@ -347,166 +385,286 @@ 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;
-
-       if (mono_debugger_throw_exception ((gpointer)(eip - 5), (gpointer)esp, exc)) {
-               /*
-                * The debugger wants us to stop on the `throw' instruction.
-                * By the time we get here, it already inserted a breakpoint on
-                * eip - 5 (which is the address of the call).
-                */
-               ctx.eip = eip - 5;
-               ctx.esp = esp + sizeof (gpointer);
-               restore_context (&ctx);
-               g_assert_not_reached ();
-       }
-
-       /* adjust eip so that it point into the call instruction */
-       ctx.eip -= 1;
+       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;
                if (!rethrow)
                        mono_ex->stack_trace = NULL;
        }
+
+       if (mono_debug_using_mono_debugger ()) {
+               guint8 buf [16], *code;
+
+               mono_breakpoint_clean_code (NULL, (gpointer)eip, 8, buf, sizeof (buf));
+               code = buf + 8;
+
+               if (buf [3] == 0xe8) {
+                       MonoContext ctx_cp = ctx;
+                       ctx_cp.eip = eip - 5;
+
+                       if (mono_debugger_handle_exception (&ctx_cp, exc)) {
+                               restore_context (&ctx_cp);
+                               g_assert_not_reached ();
+                       }
+               }
+       }
+
+       /* adjust eip so that it point into the call instruction */
+       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);
 
-       x86_push_reg (code, X86_ESP);
-       x86_push_membase (code, X86_ESP, 4); /* IP */
-       x86_push_membase (code, X86_ESP, 12); /* 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);
 
-       start = get_throw_exception (TRUE);
+       g_assert ((code - start) < kMaxCodeSize);
 
-       inited = 1;
+       if (info)
+               *info = mono_tramp_info_create (g_strdup (name), 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;
 }
 
 /**
- * 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)
 {
-       static guint8* start;
-       static int inited = 0;
-       guint8 *code;
-
-       if (inited)
-               return start;
-
-       inited = 1;
-       code = start = mono_global_codeman_reserve (32);
-
-       x86_push_membase (code, X86_ESP, 4); /* exception name */
-       x86_push_imm (code, "System");
-       x86_push_imm (code, mono_defaults.exception_class->image);
-       x86_call_code (code, mono_exception_from_name);
-       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
-       /* save the newly create object (overwrite exception name)*/
-       x86_mov_membase_reg (code, X86_ESP, 4, X86_EAX, 4);
-       x86_jump_code (code, mono_arch_get_throw_exception ());
-
-       g_assert ((code - start) < 32);
+       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);
 }
 
 /**
@@ -520,139 +678,176 @@ 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;
+
+/* 
+ * 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
 
-       inited = 1;
-       code = start = mono_global_codeman_reserve (64);
+       if (mono_aot_only) {
+               signal_exception_trampoline = mono_aot_get_trampoline ("x86_signal_exception_trampoline");
+               return;
+       }
 
-       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 ());
+       /* 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);
 
-       g_assert ((code - start) < 64);
+       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);
 
-       return start;
+       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);
+       memset (frame, 0, sizeof (StackFrameInfo));
+       frame->ji = ji;
+       frame->managed = FALSE;
 
-       if (managed)
-               *managed = FALSE;
+       *new_ctx = *ctx;
 
        if (ji != NULL) {
-               int offset;
+               gssize regs [MONO_MAX_IREGS + 1];
+               guint8 *cfa;
+               guint32 unwind_info_len;
+               guint8 *unwind_info;
 
-               *new_ctx = *ctx;
+               frame->type = FRAME_TYPE_MANAGED;
 
-               if (managed)
-                       if (!ji->method->wrapper_type)
-                               *managed = TRUE;
+               if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
+                       frame->managed = TRUE;
 
-               /*
-                * Some managed methods like pinvoke wrappers might have save_lmf set.
-                * In this case, register save/restore code is not generated by the 
-                * JIT, so we have to restore callee saved registers from the lmf.
-                */
-               if (ji->method->save_lmf) {
-                       /* 
-                        * We only need to do this if the exception was raised in managed
-                        * code, since otherwise the lmf was already popped of the stack.
-                        */
-                       if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
-                               new_ctx->esi = (*lmf)->esi;
-                               new_ctx->edi = (*lmf)->edi;
-                               new_ctx->ebx = (*lmf)->ebx;
-                       }
-               }
-               else {
-                       offset = -1;
-                       /* restore caller saved registers */
-                       if (ji->used_regs & X86_EBX_MASK) {
-                               new_ctx->ebx = *((int *)ctx->ebp + offset);
-                               offset--;
-                       }
-                       if (ji->used_regs & X86_EDI_MASK) {
-                               new_ctx->edi = *((int *)ctx->ebp + offset);
-                               offset--;
-                       }
-                       if (ji->used_regs & X86_ESI_MASK) {
-                               new_ctx->esi = *((int *)ctx->ebp + offset);
-                       }
-               }
+               if (ji->from_aot)
+                       unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
+               else
+                       unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
+
+               regs [X86_EAX] = new_ctx->eax;
+               regs [X86_EBX] = new_ctx->ebx;
+               regs [X86_ECX] = new_ctx->ecx;
+               regs [X86_EDX] = new_ctx->edx;
+               regs [X86_ESP] = new_ctx->esp;
+               regs [X86_EBP] = new_ctx->ebp;
+               regs [X86_ESI] = new_ctx->esi;
+               regs [X86_EDI] = new_ctx->edi;
+               regs [X86_NREG] = new_ctx->eip;
+
+               mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
+                                                  (guint8*)ji->code_start + ji->code_size,
+                                                  ip, regs, MONO_MAX_IREGS + 1,
+                                                  save_locations, MONO_MAX_IREGS, &cfa);
+
+               new_ctx->eax = regs [X86_EAX];
+               new_ctx->ebx = regs [X86_EBX];
+               new_ctx->ecx = regs [X86_ECX];
+               new_ctx->edx = regs [X86_EDX];
+               new_ctx->esp = regs [X86_ESP];
+               new_ctx->ebp = regs [X86_EBP];
+               new_ctx->esi = regs [X86_ESI];
+               new_ctx->edi = regs [X86_EDI];
+               new_ctx->eip = regs [X86_NREG];
+
+               /* The CFA becomes the new SP value */
+               new_ctx->esp = (gssize)cfa;
+
+               /* Adjust IP */
+               new_ctx->eip --;
 
                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 EBP and the return address */
-               new_ctx->esp = ctx->ebp + (2 * sizeof (gpointer));
-               /* we substract 1, so that the IP points into the call instruction */
-               new_ctx->eip = *((int *)ctx->ebp + 1) - 1;
-               new_ctx->ebp = *((int *)ctx->ebp);
-
                /* 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 (!(*lmf)->method)
+                       if (!((guint32)((*lmf)->previous_lmf) & 1))
                                /* Top LMF entry */
-                               return (gpointer)-1;
+                               return FALSE;
+                       g_assert_not_reached ();
                        /* Trampoline lmf frame */
-                       memset (res, 0, sizeof (MonoJitInfo));
-                       res->method = (*lmf)->method;
+                       frame->method = (*lmf)->method;
                }
 
                new_ctx->esi = (*lmf)->esi;
@@ -661,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 */
@@ -669,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
@@ -705,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;
        
@@ -730,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;
 
@@ -760,32 +979,173 @@ 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);
 
+       if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj))
+               return TRUE;
+
        mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
 
        mono_arch_monoctx_to_sigctx (&mctx, sigctx);
 
        return TRUE;
+#endif
 }
 
 static void
@@ -820,8 +1180,15 @@ 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)) {
+               if (stack_ovf)
+                       prepare_for_guard_pages (&mctx);
+               restore_context (&mctx);
+       }
+
        mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, FALSE);
        if (stack_ovf)
                prepare_for_guard_pages (&mctx);
@@ -834,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;
 
@@ -844,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];
        }
@@ -883,3 +1250,48 @@ mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean
 #endif
 }
 
+#if MONO_SUPPORT_TASKLETS
+MonoContinuationRestore
+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);
+       /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
+       /* put cont in edx */
+       x86_mov_reg_membase (code, X86_EDX, X86_ESP, 4, 4);
+       /* setup the copy of the stack */
+       x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), 4);
+       x86_shift_reg_imm (code, X86_SHR, X86_ECX, 2);
+       x86_cld (code);
+       x86_mov_reg_membase (code, X86_ESI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, saved_stack), 4);
+       x86_mov_reg_membase (code, X86_EDI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_sp), 4);
+       x86_prefix (code, X86_REP_PREFIX);
+       x86_movsl (code);
+
+       /* now restore the registers from the LMF */
+       x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, lmf), 4);
+       x86_mov_reg_membase (code, X86_EBX, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebx), 4);
+       x86_mov_reg_membase (code, X86_EBP, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebp), 4);
+       x86_mov_reg_membase (code, X86_ESI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, esi), 4);
+       x86_mov_reg_membase (code, X86_EDI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, edi), 4);
+
+       /* restore the lmf chain */
+       /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
+       x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
+
+       /* state in eax, so it's setup as the return value */
+       x86_mov_reg_membase (code, X86_EAX, X86_ESP, 8, 4);
+       x86_jump_membase (code, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_ip));
+       g_assert ((code - start) <= 48);
+       saved = start;
+       return (MonoContinuationRestore)saved;
+}
+#endif
+