Merge branch 'master' of github.com:mono/mono
[mono.git] / mono / mini / exceptions-x86.c
1 /*
2  * exceptions-x86.c: exception support for x86
3  *
4  * Authors:
5  *   Dietmar Maurer (dietmar@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9
10 #include <config.h>
11 #include <glib.h>
12 #include <signal.h>
13 #include <string.h>
14
15 #include <mono/arch/x86/x86-codegen.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/tabledefs.h>
18 #include <mono/metadata/threads.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/exception.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/mono-debug.h>
23 #include <mono/utils/mono-mmap.h>
24
25 #include "mini.h"
26 #include "mini-x86.h"
27 #include "tasklets.h"
28 #include "debug-mini.h"
29
30 static gpointer signal_exception_trampoline;
31
32 gpointer
33 mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) MONO_INTERNAL;
34
35 #ifdef TARGET_WIN32
36 static void (*restore_stack) (void *);
37
38 static MonoW32ExceptionHandler fpe_handler;
39 static MonoW32ExceptionHandler ill_handler;
40 static MonoW32ExceptionHandler segv_handler;
41
42 LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter;
43 guint64 mono_win_chained_exception_filter_result;
44 gboolean mono_win_chained_exception_filter_didrun;
45
46 #ifndef PROCESS_CALLBACK_FILTER_ENABLED
47 #       define PROCESS_CALLBACK_FILTER_ENABLED 1
48 #endif
49
50 #define W32_SEH_HANDLE_EX(_ex) \
51         if (_ex##_handler) _ex##_handler(0, ep, sctx)
52
53 /*
54  * mono_win32_get_handle_stackoverflow (void):
55  *
56  * Returns a pointer to a method which restores the current context stack
57  * and calls handle_exceptions, when done restores the original stack.
58  */
59 static gpointer
60 mono_win32_get_handle_stackoverflow (void)
61 {
62         static guint8 *start = NULL;
63         guint8 *code;
64
65         if (start)
66                 return start;
67
68         /* restore_contect (void *sigctx) */
69         start = code = mono_global_codeman_reserve (128);
70
71         /* load context into ebx */
72         x86_mov_reg_membase (code, X86_EBX, X86_ESP, 4, 4);
73
74         /* move current stack into edi for later restore */
75         x86_mov_reg_reg (code, X86_EDI, X86_ESP, 4);
76
77         /* use the new freed stack from sigcontext */
78         x86_mov_reg_membase (code, X86_ESP, X86_EBX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);
79
80         /* get the current domain */
81         x86_call_code (code, mono_domain_get);
82
83         /* get stack overflow exception from domain object */
84         x86_mov_reg_membase (code, X86_EAX, X86_EAX, G_STRUCT_OFFSET (MonoDomain, stack_overflow_ex), 4);
85
86         /* call mono_arch_handle_exception (sctx, stack_overflow_exception_obj, FALSE) */
87         x86_push_imm (code, 0);
88         x86_push_reg (code, X86_EAX);
89         x86_push_reg (code, X86_EBX);
90         x86_call_code (code, mono_arch_handle_exception);
91
92         /* restore the SEH handler stack */
93         x86_mov_reg_reg (code, X86_ESP, X86_EDI, 4);
94
95         /* return */
96         x86_ret (code);
97
98         return start;
99 }
100
101 /* Special hack to workaround the fact that the
102  * when the SEH handler is called the stack is
103  * to small to recover.
104  *
105  * Stack walking part of this method is from mono_handle_exception
106  *
107  * The idea is simple; 
108  *  - walk the stack to free some space (64k)
109  *  - set esp to new stack location
110  *  - call mono_arch_handle_exception with stack overflow exception
111  *  - set esp to SEH handlers stack
112  *  - done
113  */
114 static void 
115 win32_handle_stack_overflow (EXCEPTION_POINTERS* ep, struct sigcontext *sctx) 
116 {
117         SYSTEM_INFO si;
118         DWORD page_size;
119         MonoDomain *domain = mono_domain_get ();
120         MonoJitInfo rji;
121         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
122         MonoLMF *lmf = jit_tls->lmf;            
123         MonoContext initial_ctx;
124         MonoContext ctx;
125         guint32 free_stack = 0;
126         StackFrameInfo frame;
127
128         /* convert sigcontext to MonoContext (due to reuse of stack walking helpers */
129         mono_arch_sigctx_to_monoctx (sctx, &ctx);
130         
131         /* get our os page size */
132         GetSystemInfo(&si);
133         page_size = si.dwPageSize;
134
135         /* Let's walk the stack to recover
136          * the needed stack space (if possible)
137          */
138         memset (&rji, 0, sizeof (rji));
139
140         initial_ctx = ctx;
141         free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
142
143         /* try to free 64kb from our stack */
144         do {
145                 MonoContext new_ctx;
146
147                 mono_arch_find_jit_info (domain, jit_tls, &rji, &ctx, &new_ctx, &lmf, NULL, &frame);
148                 if (!frame.ji) {
149                         g_warning ("Exception inside function without unwind info");
150                         g_assert_not_reached ();
151                 }
152
153                 if (frame.ji != (gpointer)-1) {
154                         free_stack = (guint8*)(MONO_CONTEXT_GET_BP (&ctx)) - (guint8*)(MONO_CONTEXT_GET_BP (&initial_ctx));
155                 }
156
157                 /* todo: we should call abort if ji is -1 */
158                 ctx = new_ctx;
159         } while (free_stack < 64 * 1024 && frame.ji != (gpointer) -1);
160
161         /* convert into sigcontext to be used in mono_arch_handle_exception */
162         mono_arch_monoctx_to_sigctx (&ctx, sctx);
163
164         /* todo: install new stack-guard page */
165
166         /* use the new stack and call mono_arch_handle_exception () */
167         restore_stack (sctx);
168 }
169
170 /*
171  * Unhandled Exception Filter
172  * Top-level per-process exception handler.
173  */
174 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
175 {
176         EXCEPTION_RECORD* er;
177         CONTEXT* ctx;
178         struct sigcontext* sctx;
179         LONG res;
180
181         mono_win_chained_exception_filter_didrun = FALSE;
182         res = EXCEPTION_CONTINUE_EXECUTION;
183
184         er = ep->ExceptionRecord;
185         ctx = ep->ContextRecord;
186         sctx = g_malloc(sizeof(struct sigcontext));
187
188         /* Copy Win32 context to UNIX style context */
189         sctx->eax = ctx->Eax;
190         sctx->ebx = ctx->Ebx;
191         sctx->ecx = ctx->Ecx;
192         sctx->edx = ctx->Edx;
193         sctx->ebp = ctx->Ebp;
194         sctx->esp = ctx->Esp;
195         sctx->esi = ctx->Esi;
196         sctx->edi = ctx->Edi;
197         sctx->eip = ctx->Eip;
198
199         switch (er->ExceptionCode) {
200         case EXCEPTION_STACK_OVERFLOW:
201                 win32_handle_stack_overflow (ep, sctx);
202                 break;
203         case EXCEPTION_ACCESS_VIOLATION:
204                 W32_SEH_HANDLE_EX(segv);
205                 break;
206         case EXCEPTION_ILLEGAL_INSTRUCTION:
207                 W32_SEH_HANDLE_EX(ill);
208                 break;
209         case EXCEPTION_INT_DIVIDE_BY_ZERO:
210         case EXCEPTION_INT_OVERFLOW:
211         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
212         case EXCEPTION_FLT_OVERFLOW:
213         case EXCEPTION_FLT_UNDERFLOW:
214         case EXCEPTION_FLT_INEXACT_RESULT:
215                 W32_SEH_HANDLE_EX(fpe);
216                 break;
217         default:
218                 break;
219         }
220
221         /* Copy context back */
222         ctx->Eax = sctx->eax;
223         ctx->Ebx = sctx->ebx;
224         ctx->Ecx = sctx->ecx;
225         ctx->Edx = sctx->edx;
226         ctx->Ebp = sctx->ebp;
227         ctx->Esp = sctx->esp;
228         ctx->Esi = sctx->esi;
229         ctx->Edi = sctx->edi;
230         ctx->Eip = sctx->eip;
231
232         g_free (sctx);
233
234         if (mono_win_chained_exception_filter_didrun)
235                 res = mono_win_chained_exception_filter_result;
236
237         return res;
238 }
239
240 void win32_seh_init()
241 {
242         /* install restore stack helper */
243         if (!restore_stack)
244                 restore_stack = mono_win32_get_handle_stackoverflow ();
245
246         mono_old_win_toplevel_exception_filter = SetUnhandledExceptionFilter(seh_handler);
247 }
248
249 void win32_seh_cleanup()
250 {
251         if (mono_old_win_toplevel_exception_filter) SetUnhandledExceptionFilter(mono_old_win_toplevel_exception_filter);
252 }
253
254 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
255 {
256         switch (type) {
257         case SIGFPE:
258                 fpe_handler = handler;
259                 break;
260         case SIGILL:
261                 ill_handler = handler;
262                 break;
263         case SIGSEGV:
264                 segv_handler = handler;
265                 break;
266         default:
267                 break;
268         }
269 }
270
271 #endif /* TARGET_WIN32 */
272
273 /*
274  * mono_arch_get_restore_context:
275  *
276  * Returns a pointer to a method which restores a previously saved sigcontext.
277  */
278 gpointer
279 mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot)
280 {
281         guint8 *start = NULL;
282         guint8 *code;
283         MonoJumpInfo *ji = NULL;
284         GSList *unwind_ops = NULL;
285
286         /* restore_contect (MonoContext *ctx) */
287
288         start = code = mono_global_codeman_reserve (128);
289         
290         /* load ctx */
291         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
292
293         /* get return address, stored in ECX */
294         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eip), 4);
295         /* restore EBX */
296         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
297         /* restore EDI */
298         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
299         /* restore ESI */
300         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
301         /* restore ESP */
302         x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esp), 4);
303         /* save the return addr to the restored stack */
304         x86_push_reg (code, X86_ECX);
305         /* restore EBP */
306         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
307         /* restore ECX */
308         x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ecx), 4);
309         /* restore EDX */
310         x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edx), 4);
311         /* restore EAX */
312         x86_mov_reg_membase (code, X86_EAX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, eax), 4);
313
314         /* jump to the saved IP */
315         x86_ret (code);
316
317         nacl_global_codeman_validate(&start, 128, &code);
318
319         if (info)
320                 *info = mono_tramp_info_create (g_strdup_printf ("restore_context"), start, code - start, ji, unwind_ops);
321         else {
322                 GSList *l;
323
324                 for (l = unwind_ops; l; l = l->next)
325                         g_free (l->data);
326                 g_slist_free (unwind_ops);
327         }
328
329         return start;
330 }
331
332 /*
333  * mono_arch_get_call_filter:
334  *
335  * Returns a pointer to a method which calls an exception filter. We
336  * also use this function to call finally handlers (we pass NULL as 
337  * @exc object in this case).
338  */
339 gpointer
340 mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot)
341 {
342         guint8* start;
343         guint8 *code;
344         MonoJumpInfo *ji = NULL;
345         GSList *unwind_ops = NULL;
346         guint kMaxCodeSize = NACL_SIZE (64, 128);
347
348         /* call_filter (MonoContext *ctx, unsigned long eip) */
349         start = code = mono_global_codeman_reserve (kMaxCodeSize);
350
351         x86_push_reg (code, X86_EBP);
352         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
353         x86_push_reg (code, X86_EBX);
354         x86_push_reg (code, X86_EDI);
355         x86_push_reg (code, X86_ESI);
356
357         /* load ctx */
358         x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
359         /* load eip */
360         x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
361         /* save EBP */
362         x86_push_reg (code, X86_EBP);
363
364         /* set new EBP */
365         x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebp), 4);
366         /* restore registers used by global register allocation (EBX & ESI) */
367         x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (MonoContext, ebx), 4);
368         x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, esi), 4);
369         x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (MonoContext, edi), 4);
370
371         /* align stack and save ESP */
372         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
373         x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
374         g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
375         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
376         x86_push_reg (code, X86_EDX);
377
378         /* call the handler */
379         x86_call_reg (code, X86_ECX);
380
381         /* restore ESP */
382         x86_pop_reg (code, X86_ESP);
383
384         /* restore EBP */
385         x86_pop_reg (code, X86_EBP);
386
387         /* restore saved regs */
388         x86_pop_reg (code, X86_ESI);
389         x86_pop_reg (code, X86_EDI);
390         x86_pop_reg (code, X86_EBX);
391         x86_leave (code);
392         x86_ret (code);
393
394         nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
395
396         if (info)
397                 *info = mono_tramp_info_create (g_strdup_printf ("call_filter"), start, code - start, ji, unwind_ops);
398         else {
399                 GSList *l;
400
401                 for (l = unwind_ops; l; l = l->next)
402                         g_free (l->data);
403                 g_slist_free (unwind_ops);
404         }
405
406         g_assert ((code - start) < kMaxCodeSize);
407         return start;
408 }
409
410 /*
411  * mono_x86_throw_exception:
412  *
413  *   C function called from the throw trampolines.
414  */
415 void
416 mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc, 
417                                                   mgreg_t eip, gboolean rethrow)
418 {
419         static void (*restore_context) (MonoContext *);
420         MonoContext ctx;
421
422         if (!restore_context)
423                 restore_context = mono_get_restore_context ();
424
425         ctx.esp = regs [X86_ESP];
426         ctx.eip = eip;
427         ctx.ebp = regs [X86_EBP];
428         ctx.edi = regs [X86_EDI];
429         ctx.esi = regs [X86_ESI];
430         ctx.ebx = regs [X86_EBX];
431         ctx.edx = regs [X86_EDX];
432         ctx.ecx = regs [X86_ECX];
433         ctx.eax = regs [X86_EAX];
434
435 #ifdef __APPLE__
436         /* The OSX ABI specifies 16 byte alignment at call sites */
437         g_assert ((ctx.esp % MONO_ARCH_FRAME_ALIGNMENT) == 0);
438 #endif
439
440         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
441                 MonoException *mono_ex = (MonoException*)exc;
442                 if (!rethrow)
443                         mono_ex->stack_trace = NULL;
444         }
445
446         if (mono_debug_using_mono_debugger ()) {
447                 guint8 buf [16], *code;
448
449                 mono_breakpoint_clean_code (NULL, (gpointer)eip, 8, buf, sizeof (buf));
450                 code = buf + 8;
451
452                 if (buf [3] == 0xe8) {
453                         MonoContext ctx_cp = ctx;
454                         ctx_cp.eip = eip - 5;
455
456                         if (mono_debugger_handle_exception (&ctx_cp, exc)) {
457                                 restore_context (&ctx_cp);
458                                 g_assert_not_reached ();
459                         }
460                 }
461         }
462
463         /* adjust eip so that it point into the call instruction */
464         ctx.eip -= 1;
465
466         mono_handle_exception (&ctx, exc, (gpointer)eip, FALSE);
467
468         restore_context (&ctx);
469
470         g_assert_not_reached ();
471 }
472
473 void
474 mono_x86_throw_corlib_exception (mgreg_t *regs, guint32 ex_token_index, 
475                                                                  mgreg_t eip, gint32 pc_offset)
476 {
477         guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
478         MonoException *ex;
479
480         ex = mono_exception_from_token (mono_defaults.exception_class->image, ex_token);
481
482         eip -= pc_offset;
483
484         /* Negate the ip adjustment done in mono_x86_throw_exception () */
485         eip += 1;
486
487         mono_x86_throw_exception (regs, (MonoObject*)ex, eip, FALSE);
488 }
489
490 static void
491 mono_x86_resume_unwind (mgreg_t *regs, MonoObject *exc, 
492                                                 mgreg_t eip, gboolean rethrow)
493 {
494         MonoContext ctx;
495
496         ctx.esp = regs [X86_ESP];
497         ctx.eip = eip;
498         ctx.ebp = regs [X86_EBP];
499         ctx.edi = regs [X86_EDI];
500         ctx.esi = regs [X86_ESI];
501         ctx.ebx = regs [X86_EBX];
502         ctx.edx = regs [X86_EDX];
503         ctx.ecx = regs [X86_ECX];
504         ctx.eax = regs [X86_EAX];
505
506         mono_resume_unwind (&ctx);
507 }
508
509 /*
510  * get_throw_trampoline:
511  *
512  *  Generate a call to mono_x86_throw_exception/
513  * mono_x86_throw_corlib_exception.
514  * If LLVM is true, generate code which assumes the caller is LLVM generated code, 
515  * which doesn't push the arguments.
516  */
517 static guint8*
518 get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolean corlib, gboolean llvm_abs, gboolean resume_unwind, MonoTrampInfo **info, gboolean aot)
519 {
520         guint8 *start, *code;
521         int i, stack_size, stack_offset, arg_offsets [5], regs_offset;
522         MonoJumpInfo *ji = NULL;
523         GSList *unwind_ops = NULL;
524         guint kMaxCodeSize = NACL_SIZE (128, 256);
525
526         start = code = mono_global_codeman_reserve (kMaxCodeSize);
527
528         stack_size = 128;
529
530         /* 
531          * On apple, the stack is misaligned by the pushing of the return address.
532          */
533         if (!llvm && corlib)
534                 /* On OSX, we don't generate alignment code to save space */
535                 stack_size += 4;
536         else
537                 stack_size += MONO_ARCH_FRAME_ALIGNMENT - 4;
538
539         /*
540          * The stack looks like this:
541          * <pc offset> (only if corlib is TRUE)
542          * <exception object>/<type token>
543          * <return addr> <- esp (unaligned on apple)
544          */
545
546         mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
547         mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
548
549         /* Alloc frame */
550         x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
551         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);
552
553         arg_offsets [0] = 0;
554         arg_offsets [1] = 4;
555         arg_offsets [2] = 8;
556         arg_offsets [3] = 12;
557         regs_offset = 16;
558
559         /* Save registers */
560         for (i = 0; i < X86_NREG; ++i)
561                 if (i != X86_ESP)
562                         x86_mov_membase_reg (code, X86_ESP, regs_offset + (i * 4), i, 4);
563         /* Calculate the offset between the current sp and the sp of the caller */
564         if (llvm) {
565                 /* LLVM doesn't push the arguments */
566                 stack_offset = stack_size + 4;
567         } else {
568                 if (corlib) {
569                         /* Two arguments */
570                         stack_offset = stack_size + 4 + 8;
571 #ifdef __APPLE__
572                         /* We don't generate stack alignment code on osx to save space */
573 #endif
574                 } else {
575                         /* One argument + stack alignment */
576                         stack_offset = stack_size + 4 + 4;
577 #ifdef __APPLE__
578                         /* Pop the alignment added by OP_THROW too */
579                         stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
580 #else
581                         if (mono_do_x86_stack_align)
582                                 stack_offset += MONO_ARCH_FRAME_ALIGNMENT - 4;
583 #endif
584                 }
585         }
586         /* Save ESP */
587         x86_lea_membase (code, X86_EAX, X86_ESP, stack_offset);
588         x86_mov_membase_reg (code, X86_ESP, regs_offset + (X86_ESP * 4), X86_EAX, 4);
589
590         /* Set arg1 == regs */
591         x86_lea_membase (code, X86_EAX, X86_ESP, regs_offset);
592         x86_mov_membase_reg (code, X86_ESP, arg_offsets [0], X86_EAX, 4);
593         /* Set arg2 == exc/ex_token_index */
594         if (resume_unwind)
595                 x86_mov_reg_imm (code, X86_EAX, 0);
596         else
597                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 4, 4);
598         x86_mov_membase_reg (code, X86_ESP, arg_offsets [1], X86_EAX, 4);
599         /* Set arg3 == eip */
600         if (llvm_abs)
601                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
602         else
603                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size, 4);
604         x86_mov_membase_reg (code, X86_ESP, arg_offsets [2], X86_EAX, 4);
605         /* Set arg4 == rethrow/pc_offset */
606         if (resume_unwind) {
607                 x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], 0, 4);
608         } else if (corlib) {
609                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, stack_size + 8, 4);
610                 if (llvm_abs) {
611                         /* 
612                          * The caller is LLVM code which passes the absolute address not a pc offset,
613                          * so compensate by passing 0 as 'ip' and passing the negated abs address as
614                          * the pc offset.
615                          */
616                         x86_neg_reg (code, X86_EAX);
617                 }
618                 x86_mov_membase_reg (code, X86_ESP, arg_offsets [3], X86_EAX, 4);
619         } else {
620                 x86_mov_membase_imm (code, X86_ESP, arg_offsets [3], rethrow, 4);
621         }
622         /* Make the call */
623         if (aot) {
624                 // This can be called from runtime code, which can't guarantee that
625                 // ebx contains the got address.
626                 // So emit the got address loading code too
627                 code = mono_arch_emit_load_got_addr (start, code, NULL, &ji);
628                 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");
629                 x86_call_reg (code, X86_EAX);
630         } else {
631                 x86_call_code (code, resume_unwind ? (mono_x86_resume_unwind) : (corlib ? (gpointer)mono_x86_throw_corlib_exception : (gpointer)mono_x86_throw_exception));
632         }
633         x86_breakpoint (code);
634
635         nacl_global_codeman_validate(&start, kMaxCodeSize, &code);
636
637         g_assert ((code - start) < kMaxCodeSize);
638
639         if (info)
640                 *info = mono_tramp_info_create (g_strdup (name), start, code - start, ji, unwind_ops);
641         else {
642                 GSList *l;
643
644                 for (l = unwind_ops; l; l = l->next)
645                         g_free (l->data);
646                 g_slist_free (unwind_ops);
647         }
648
649         return start;
650 }
651
652 /**
653  * mono_arch_get_throw_exception:
654  *
655  * Returns a function pointer which can be used to raise 
656  * exceptions. The returned function has the following 
657  * signature: void (*func) (MonoException *exc); 
658  * For example to raise an arithmetic exception you can use:
659  *
660  * x86_push_imm (code, mono_get_exception_arithmetic ()); 
661  * x86_call_code (code, arch_get_throw_exception ()); 
662  *
663  */
664 gpointer 
665 mono_arch_get_throw_exception (MonoTrampInfo **info, gboolean aot)
666 {
667         return get_throw_trampoline ("throw_exception", FALSE, FALSE, FALSE, FALSE, FALSE, info, aot);
668 }
669
670 gpointer 
671 mono_arch_get_rethrow_exception (MonoTrampInfo **info, gboolean aot)
672 {
673         return get_throw_trampoline ("rethrow_exception", TRUE, FALSE, FALSE, FALSE, FALSE, info, aot);
674 }
675
676 /**
677  * mono_arch_get_throw_corlib_exception:
678  *
679  * Returns a function pointer which can be used to raise 
680  * corlib exceptions. The returned function has the following 
681  * signature: void (*func) (guint32 ex_token, guint32 offset); 
682  * Here, offset is the offset which needs to be substracted from the caller IP 
683  * to get the IP of the throw. Passing the offset has the advantage that it 
684  * needs no relocations in the caller.
685  */
686 gpointer 
687 mono_arch_get_throw_corlib_exception (MonoTrampInfo **info, gboolean aot)
688 {
689         return get_throw_trampoline ("throw_corlib_exception", FALSE, FALSE, TRUE, FALSE, FALSE, info, aot);
690 }
691
692 void
693 mono_arch_exceptions_init (void)
694 {
695         guint8 *tramp;
696
697 /* 
698  * If we're running WoW64, we need to set the usermode exception policy 
699  * for SEHs to behave. This requires hotfix http://support.microsoft.com/kb/976038
700  * or (eventually) Windows 7 SP1.
701  */
702 #ifdef HOST_WIN32
703         DWORD flags;
704         FARPROC getter;
705         FARPROC setter;
706         HMODULE kernel32 = LoadLibraryW (L"kernel32.dll");
707
708         if (kernel32) {
709                 getter = GetProcAddress (kernel32, "GetProcessUserModeExceptionPolicy");
710                 setter = GetProcAddress (kernel32, "SetProcessUserModeExceptionPolicy");
711                 if (getter && setter) {
712                         if (getter (&flags))
713                                 setter (flags & ~PROCESS_CALLBACK_FILTER_ENABLED);
714                 }
715         }
716 #endif
717
718         if (mono_aot_only) {
719                 signal_exception_trampoline = mono_aot_get_trampoline ("x86_signal_exception_trampoline");
720                 return;
721         }
722
723         /* LLVM needs different throw trampolines */
724         tramp = get_throw_trampoline ("llvm_throw_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE);
725         mono_register_jit_icall (tramp, "llvm_throw_exception_trampoline", NULL, TRUE);
726
727         tramp = get_throw_trampoline ("llvm_rethrow_exception_trampoline", FALSE, TRUE, FALSE, FALSE, FALSE, NULL, FALSE);
728         mono_register_jit_icall (tramp, "llvm_rethrow_exception_trampoline", NULL, TRUE);
729
730         tramp = get_throw_trampoline ("llvm_throw_corlib_exception_trampoline", FALSE, TRUE, TRUE, FALSE, FALSE, NULL, FALSE);
731         mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_trampoline", NULL, TRUE);
732
733         tramp = get_throw_trampoline ("llvm_throw_corlib_exception_abs_trampoline", FALSE, TRUE, TRUE, TRUE, FALSE, NULL, FALSE);
734         mono_register_jit_icall (tramp, "llvm_throw_corlib_exception_abs_trampoline", NULL, TRUE);
735
736         tramp = get_throw_trampoline ("llvm_resume_unwind_trampoline", FALSE, FALSE, FALSE, FALSE, TRUE, NULL, FALSE);
737         mono_register_jit_icall (tramp, "llvm_resume_unwind_trampoline", NULL, TRUE);
738
739         signal_exception_trampoline = mono_x86_get_signal_exception_trampoline (NULL, FALSE);
740 }
741
742 /*
743  * mono_arch_find_jit_info:
744  *
745  * See exceptions-amd64.c for docs.
746  */
747 gboolean
748 mono_arch_find_jit_info (MonoDomain *domain, MonoJitTlsData *jit_tls, 
749                                                          MonoJitInfo *ji, MonoContext *ctx, 
750                                                          MonoContext *new_ctx, MonoLMF **lmf,
751                                                          mgreg_t **save_locations,
752                                                          StackFrameInfo *frame)
753 {
754         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
755
756         memset (frame, 0, sizeof (StackFrameInfo));
757         frame->ji = ji;
758
759         *new_ctx = *ctx;
760
761         if (ji != NULL) {
762                 gssize regs [MONO_MAX_IREGS + 1];
763                 guint8 *cfa;
764                 guint32 unwind_info_len;
765                 guint8 *unwind_info;
766
767                 frame->type = FRAME_TYPE_MANAGED;
768
769                 if (ji->from_aot)
770                         unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
771                 else
772                         unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
773
774                 regs [X86_EAX] = new_ctx->eax;
775                 regs [X86_EBX] = new_ctx->ebx;
776                 regs [X86_ECX] = new_ctx->ecx;
777                 regs [X86_EDX] = new_ctx->edx;
778                 regs [X86_ESP] = new_ctx->esp;
779                 regs [X86_EBP] = new_ctx->ebp;
780                 regs [X86_ESI] = new_ctx->esi;
781                 regs [X86_EDI] = new_ctx->edi;
782                 regs [X86_NREG] = new_ctx->eip;
783
784                 mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
785                                                    (guint8*)ji->code_start + ji->code_size,
786                                                    ip, regs, MONO_MAX_IREGS + 1,
787                                                    save_locations, MONO_MAX_IREGS, &cfa);
788
789                 new_ctx->eax = regs [X86_EAX];
790                 new_ctx->ebx = regs [X86_EBX];
791                 new_ctx->ecx = regs [X86_ECX];
792                 new_ctx->edx = regs [X86_EDX];
793                 new_ctx->esp = regs [X86_ESP];
794                 new_ctx->ebp = regs [X86_EBP];
795                 new_ctx->esi = regs [X86_ESI];
796                 new_ctx->edi = regs [X86_EDI];
797                 new_ctx->eip = regs [X86_NREG];
798
799                 /* The CFA becomes the new SP value */
800                 new_ctx->esp = (gssize)cfa;
801
802                 /* Adjust IP */
803                 new_ctx->eip --;
804
805                 if (*lmf && (MONO_CONTEXT_GET_BP (ctx) >= (gpointer)(*lmf)->ebp)) {
806                         /* remove any unused lmf */
807                         *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
808                 }
809
810                 /* Pop arguments off the stack */
811                 /* 
812                  * FIXME: LLVM doesn't push these, we can't use ji->from_llvm as it describes
813                  * the caller.
814                  */
815 #ifndef ENABLE_LLVM
816                 {
817                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
818
819                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
820                         new_ctx->esp += stack_to_pop;
821                 }
822 #endif
823
824                 return TRUE;
825         } else if (*lmf) {
826
827                 if (((guint64)(*lmf)->previous_lmf) & 2) {
828                         /* 
829                          * This LMF entry is created by the soft debug code to mark transitions to
830                          * managed code done during invokes.
831                          */
832                         MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
833
834                         g_assert (ext->debugger_invoke);
835
836                         memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
837
838                         *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
839
840                         frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
841
842                         return TRUE;
843                 }
844                 
845                 if ((ji = mini_jit_info_table_find (domain, (gpointer)(*lmf)->eip, NULL))) {
846                 } else {
847                         if (!((guint32)((*lmf)->previous_lmf) & 1))
848                                 /* Top LMF entry */
849                                 return FALSE;
850                         g_assert_not_reached ();
851                         /* Trampoline lmf frame */
852                         frame->method = (*lmf)->method;
853                 }
854
855                 new_ctx->esi = (*lmf)->esi;
856                 new_ctx->edi = (*lmf)->edi;
857                 new_ctx->ebx = (*lmf)->ebx;
858                 new_ctx->ebp = (*lmf)->ebp;
859                 new_ctx->eip = (*lmf)->eip;
860
861                 /* Adjust IP */
862                 new_ctx->eip --;
863
864                 frame->ji = ji;
865                 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
866
867                 /* Check if we are in a trampoline LMF frame */
868                 if ((guint32)((*lmf)->previous_lmf) & 1) {
869                         /* lmf->esp is set by the trampoline code */
870                         new_ctx->esp = (*lmf)->esp;
871
872                         /* Pop arguments off the stack */
873                         /* FIXME: Handle the delegate case too ((*lmf)->method == NULL) */
874                         /* FIXME: Handle the IMT/vtable case too */
875 #ifndef ENABLE_LLVM
876                         if ((*lmf)->method) {
877                                 MonoMethod *method = (*lmf)->method;
878                                 MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (method)->param_count + 1);
879
880                                 guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (method), mono_method_signature (method)->param_count, arg_info);
881                                 new_ctx->esp += stack_to_pop;
882                         }
883 #endif
884                 }
885                 else
886                         /* the lmf is always stored on the stack, so the following
887                          * expression points to a stack location which can be used as ESP */
888                         new_ctx->esp = (unsigned long)&((*lmf)->eip);
889
890                 *lmf = (gpointer)(((gsize)(*lmf)->previous_lmf) & ~3);
891
892                 return TRUE;
893         }
894
895         return FALSE;
896 }
897
898 void
899 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
900 {
901         mono_sigctx_to_monoctx (sigctx, mctx);
902 }
903
904 void
905 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
906 {
907         mono_monoctx_to_sigctx (mctx, sigctx);
908 }
909
910 gpointer
911 mono_arch_ip_from_context (void *sigctx)
912 {
913 #if defined(__native_client__)
914         printf("WARNING: mono_arch_ip_from_context() called!\n");
915         return (NULL);
916 #else
917 #ifdef MONO_ARCH_USE_SIGACTION
918         ucontext_t *ctx = (ucontext_t*)sigctx;
919         return (gpointer)UCONTEXT_REG_EIP (ctx);
920 #else
921         struct sigcontext *ctx = sigctx;
922         return (gpointer)ctx->SC_EIP;
923 #endif
924 #endif  /* __native_client__ */
925 }
926
927 /*
928  * handle_exception:
929  *
930  *   Called by resuming from a signal handler.
931  */
932 static void
933 handle_signal_exception (gpointer obj)
934 {
935         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
936         MonoContext ctx;
937         static void (*restore_context) (MonoContext *);
938
939         if (!restore_context)
940                 restore_context = mono_get_restore_context ();
941
942         memcpy (&ctx, &jit_tls->ex_ctx, sizeof (MonoContext));
943
944         if (mono_debugger_handle_exception (&ctx, (MonoObject *)obj))
945                 return;
946
947         mono_handle_exception (&ctx, obj, MONO_CONTEXT_GET_IP (&ctx), FALSE);
948
949         restore_context (&ctx);
950 }
951
952 /*
953  * mono_x86_get_signal_exception_trampoline:
954  *
955  *   This x86 specific trampoline is used to call handle_signal_exception.
956  */
957 gpointer
958 mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot)
959 {
960         guint8 *start, *code;
961         MonoJumpInfo *ji = NULL;
962         GSList *unwind_ops = NULL;
963         int stack_size;
964
965         start = code = mono_global_codeman_reserve (128);
966
967         /* Caller ip */
968         x86_push_reg (code, X86_ECX);
969
970         mono_add_unwind_op_def_cfa (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
971         mono_add_unwind_op_offset (unwind_ops, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
972
973         /* Fix the alignment to be what apple expects */
974         stack_size = 12;
975
976         x86_alu_reg_imm (code, X86_SUB, X86_ESP, stack_size);
977         mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, stack_size + 4);
978
979         /* Arg1 */
980         x86_mov_membase_reg (code, X86_ESP, 0, X86_EAX, 4);
981         /* Branch to target */
982         x86_call_reg (code, X86_EDX);
983
984         g_assert ((code - start) < 128);
985
986         if (info)
987                 *info = mono_tramp_info_create (g_strdup ("x86_signal_exception_trampoline"), start, code - start, ji, unwind_ops);
988         else {
989                 GSList *l;
990
991                 for (l = unwind_ops; l; l = l->next)
992                         g_free (l->data);
993                 g_slist_free (unwind_ops);
994         }
995
996         return start;
997 }
998
999 gboolean
1000 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
1001 {
1002 #if defined(MONO_ARCH_USE_SIGACTION)
1003         ucontext_t *ctx = (ucontext_t*)sigctx;
1004
1005         /*
1006          * Handling the exception in the signal handler is problematic, since the original
1007          * signal is disabled, and we could run arbitrary code though the debugger. So
1008          * resume into the normal stack and do most work there if possible.
1009          */
1010         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1011         guint64 sp = UCONTEXT_REG_ESP (ctx);
1012
1013         /* Pass the ctx parameter in TLS */
1014         mono_arch_sigctx_to_monoctx (ctx, &jit_tls->ex_ctx);
1015         /*
1016          * Can't pass the obj on the stack, since we are executing on the
1017          * same stack. Can't save it into MonoJitTlsData, since it needs GC tracking.
1018          * So put it into a register, and branch to a trampoline which
1019          * pushes it.
1020          */
1021         g_assert (!test_only);
1022         UCONTEXT_REG_EAX (ctx) = (gsize)obj;
1023         UCONTEXT_REG_ECX (ctx) = UCONTEXT_REG_EIP (ctx);
1024         UCONTEXT_REG_EDX (ctx) = (gsize)handle_signal_exception;
1025
1026         /* Allocate a stack frame, align it to 16 bytes which is needed on apple */
1027         sp -= 16;
1028         sp &= ~15;
1029         UCONTEXT_REG_ESP (ctx) = sp;
1030
1031         UCONTEXT_REG_EIP (ctx) = (gsize)signal_exception_trampoline;
1032
1033         return TRUE;
1034 #elif defined (TARGET_WIN32)
1035         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1036         struct sigcontext *ctx = (struct sigcontext *)sigctx;
1037         guint64 sp = ctx->SC_ESP;
1038
1039         mono_arch_sigctx_to_monoctx (sigctx, &jit_tls->ex_ctx);
1040
1041         /*
1042          * Can't pass the obj on the stack, since we are executing on the
1043          * same stack. Can't save it into MonoJitTlsData, since it needs GC tracking.
1044          * So put it into a register, and branch to a trampoline which
1045          * pushes it.
1046          */
1047         g_assert (!test_only);
1048         ctx->SC_EAX = (gsize)obj;
1049         ctx->SC_ECX = ctx->SC_EIP;
1050         ctx->SC_EDX = (gsize)handle_signal_exception;
1051
1052         /* Allocate a stack frame, align it to 16 bytes which is needed on apple */
1053         sp -= 16;
1054         sp &= ~15;
1055         ctx->SC_ESP = sp;
1056
1057         ctx->SC_EIP = (gsize)signal_exception_trampoline;
1058
1059         return TRUE;
1060 #else
1061         MonoContext mctx;
1062
1063         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
1064
1065         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj))
1066                 return TRUE;
1067
1068         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, test_only);
1069
1070         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
1071
1072         return TRUE;
1073 #endif
1074 }
1075
1076 static void
1077 restore_soft_guard_pages (void)
1078 {
1079         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
1080         if (jit_tls->stack_ovf_guard_base)
1081                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE);
1082 }
1083
1084 /* 
1085  * this function modifies mctx so that when it is restored, it
1086  * won't execcute starting at mctx.eip, but in a function that
1087  * will restore the protection on the soft-guard pages and return back to
1088  * continue at mctx.eip.
1089  */
1090 static void
1091 prepare_for_guard_pages (MonoContext *mctx)
1092 {
1093         gpointer *sp;
1094         sp = (gpointer)(mctx->esp);
1095         sp -= 1;
1096         /* the resturn addr */
1097         sp [0] = (gpointer)(mctx->eip);
1098         mctx->eip = (unsigned long)restore_soft_guard_pages;
1099         mctx->esp = (unsigned long)sp;
1100 }
1101
1102 static void
1103 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
1104 {
1105         void (*restore_context) (MonoContext *);
1106         MonoContext mctx;
1107
1108         restore_context = mono_get_restore_context ();
1109         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
1110
1111         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) {
1112                 if (stack_ovf)
1113                         prepare_for_guard_pages (&mctx);
1114                 restore_context (&mctx);
1115         }
1116
1117         mono_handle_exception (&mctx, obj, (gpointer)mctx.eip, FALSE);
1118         if (stack_ovf)
1119                 prepare_for_guard_pages (&mctx);
1120         restore_context (&mctx);
1121 }
1122
1123 void
1124 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
1125 {
1126 #ifdef MONO_ARCH_USE_SIGACTION
1127         MonoException *exc = NULL;
1128         ucontext_t *ctx = (ucontext_t*)sigctx;
1129         MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)UCONTEXT_REG_EIP (ctx), NULL);
1130         gpointer *sp;
1131         int frame_size;
1132
1133         /* if we didn't find a managed method for the ip address and it matches the fault
1134          * address, we assume we followed a broken pointer during an indirect call, so
1135          * we try the lookup again with the return address pushed on the stack
1136          */
1137         if (!ji && fault_addr == (gpointer)UCONTEXT_REG_EIP (ctx)) {
1138                 glong *sp = (gpointer)UCONTEXT_REG_ESP (ctx);
1139                 ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)sp [0], NULL);
1140                 if (ji)
1141                         UCONTEXT_REG_EIP (ctx) = sp [0];
1142         }
1143         if (stack_ovf)
1144                 exc = mono_domain_get ()->stack_overflow_ex;
1145         if (!ji)
1146                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
1147         /* setup a call frame on the real stack so that control is returned there
1148          * and exception handling can continue.
1149          * If this was a stack overflow the caller already ensured the stack pages
1150          * needed have been unprotected.
1151          * The frame looks like:
1152          *   ucontext struct
1153          *   test_only arg
1154          *   exception arg
1155          *   ctx arg
1156          *   return ip
1157          */
1158         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4;
1159         frame_size += 15;
1160         frame_size &= ~15;
1161         sp = (gpointer)(UCONTEXT_REG_ESP (ctx) & ~15);
1162         sp = (gpointer)((char*)sp - frame_size);
1163         /* the incoming arguments are aligned to 16 bytes boundaries, so the return address IP
1164          * goes at sp [-1]
1165          */
1166         sp [-1] = (gpointer)UCONTEXT_REG_EIP (ctx);
1167         sp [0] = sp + 4;
1168         sp [1] = exc;
1169         sp [2] = (gpointer)stack_ovf;
1170         /* may need to adjust pointers in the new struct copy, depending on the OS */
1171         memcpy (sp + 4, ctx, sizeof (ucontext_t));
1172         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
1173         UCONTEXT_REG_EIP (ctx) = (unsigned long)altstack_handle_and_restore;
1174         UCONTEXT_REG_ESP (ctx) = (unsigned long)(sp - 1);
1175 #endif
1176 }
1177
1178 #if MONO_SUPPORT_TASKLETS
1179 MonoContinuationRestore
1180 mono_tasklets_arch_restore (void)
1181 {
1182         static guint8* saved = NULL;
1183         guint8 *code, *start;
1184
1185 #ifdef __native_client_codegen__
1186         g_print("mono_tasklets_arch_restore needs to be aligned for Native Client\n");
1187 #endif
1188         if (saved)
1189                 return (MonoContinuationRestore)saved;
1190         code = start = mono_global_codeman_reserve (48);
1191         /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
1192         /* put cont in edx */
1193         x86_mov_reg_membase (code, X86_EDX, X86_ESP, 4, 4);
1194         /* setup the copy of the stack */
1195         x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), 4);
1196         x86_shift_reg_imm (code, X86_SHR, X86_ECX, 2);
1197         x86_cld (code);
1198         x86_mov_reg_membase (code, X86_ESI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, saved_stack), 4);
1199         x86_mov_reg_membase (code, X86_EDI, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_sp), 4);
1200         x86_prefix (code, X86_REP_PREFIX);
1201         x86_movsl (code);
1202
1203         /* now restore the registers from the LMF */
1204         x86_mov_reg_membase (code, X86_ECX, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, lmf), 4);
1205         x86_mov_reg_membase (code, X86_EBX, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebx), 4);
1206         x86_mov_reg_membase (code, X86_EBP, X86_ECX, G_STRUCT_OFFSET (MonoLMF, ebp), 4);
1207         x86_mov_reg_membase (code, X86_ESI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, esi), 4);
1208         x86_mov_reg_membase (code, X86_EDI, X86_ECX, G_STRUCT_OFFSET (MonoLMF, edi), 4);
1209
1210         /* restore the lmf chain */
1211         /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
1212         x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
1213
1214         /* state in eax, so it's setup as the return value */
1215         x86_mov_reg_membase (code, X86_EAX, X86_ESP, 8, 4);
1216         x86_jump_membase (code, X86_EDX, G_STRUCT_OFFSET (MonoContinuation, return_ip));
1217         g_assert ((code - start) <= 48);
1218         saved = start;
1219         return (MonoContinuationRestore)saved;
1220 }
1221 #endif
1222
1223 /*
1224  * mono_arch_setup_resume_sighandler_ctx:
1225  *
1226  *   Setup CTX so execution continues at FUNC.
1227  */
1228 void
1229 mono_arch_setup_resume_sighandler_ctx (MonoContext *ctx, gpointer func)
1230 {
1231         int align = (((gint32)MONO_CONTEXT_GET_SP (ctx)) % MONO_ARCH_FRAME_ALIGNMENT + 4);
1232
1233         if (align != 0)
1234                 MONO_CONTEXT_SET_SP (ctx, (gsize)MONO_CONTEXT_GET_SP (ctx) - align);
1235
1236         MONO_CONTEXT_SET_IP (ctx, func);
1237 }