b0db85e087dd74160f5843c28673c356cd0bbe61
[mono.git] / mono / mini / exceptions-amd64.c
1 /*
2  * exceptions-amd64.c: exception support for AMD64
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 #ifdef HAVE_UCONTEXT_H
15 #include <ucontext.h>
16 #endif
17
18 #include <mono/arch/amd64/amd64-codegen.h>
19 #include <mono/metadata/appdomain.h>
20 #include <mono/metadata/tabledefs.h>
21 #include <mono/metadata/threads.h>
22 #include <mono/metadata/threads-types.h>
23 #include <mono/metadata/debug-helpers.h>
24 #include <mono/metadata/exception.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/metadata/mono-debug.h>
27 #include <mono/utils/mono-mmap.h>
28
29 #include "mini.h"
30 #include "mini-amd64.h"
31 #include "tasklets.h"
32 #include "debug-mini.h"
33
34 #define ALIGN_TO(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
35
36 #ifdef TARGET_WIN32
37 static MonoW32ExceptionHandler fpe_handler;
38 static MonoW32ExceptionHandler ill_handler;
39 static MonoW32ExceptionHandler segv_handler;
40
41 static LPTOP_LEVEL_EXCEPTION_FILTER old_handler;
42
43 #define W32_SEH_HANDLE_EX(_ex) \
44         if (_ex##_handler) _ex##_handler(0, er, sctx)
45
46 /*
47  * Unhandled Exception Filter
48  * Top-level per-process exception handler.
49  */
50 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep)
51 {
52         EXCEPTION_RECORD* er;
53         CONTEXT* ctx;
54         MonoContext* sctx;
55         LONG res;
56
57         res = EXCEPTION_CONTINUE_EXECUTION;
58
59         er = ep->ExceptionRecord;
60         ctx = ep->ContextRecord;
61         sctx = g_malloc(sizeof(MonoContext));
62
63         /* Copy Win32 context to UNIX style context */
64         sctx->rax = ctx->Rax;
65         sctx->rbx = ctx->Rbx;
66         sctx->rcx = ctx->Rcx;
67         sctx->rdx = ctx->Rdx;
68         sctx->rbp = ctx->Rbp;
69         sctx->rsp = ctx->Rsp;
70         sctx->rsi = ctx->Rsi;
71         sctx->rdi = ctx->Rdi;
72         sctx->rip = ctx->Rip;
73         sctx->r12 = ctx->R12;
74         sctx->r13 = ctx->R13;
75         sctx->r14 = ctx->R14;
76         sctx->r15 = ctx->R15;
77
78         switch (er->ExceptionCode) {
79         case EXCEPTION_ACCESS_VIOLATION:
80                 W32_SEH_HANDLE_EX(segv);
81                 break;
82         case EXCEPTION_ILLEGAL_INSTRUCTION:
83                 W32_SEH_HANDLE_EX(ill);
84                 break;
85         case EXCEPTION_INT_DIVIDE_BY_ZERO:
86         case EXCEPTION_INT_OVERFLOW:
87         case EXCEPTION_FLT_DIVIDE_BY_ZERO:
88         case EXCEPTION_FLT_OVERFLOW:
89         case EXCEPTION_FLT_UNDERFLOW:
90         case EXCEPTION_FLT_INEXACT_RESULT:
91                 W32_SEH_HANDLE_EX(fpe);
92                 break;
93         default:
94                 break;
95         }
96
97         /* Copy context back */
98         /* Nonvolatile */
99         ctx->Rsp = sctx->rsp; 
100         ctx->Rdi = sctx->rdi; 
101         ctx->Rsi = sctx->rsi; 
102         ctx->Rbx = sctx->rbx; 
103         ctx->Rbp = sctx->rbp;
104         ctx->R12 = sctx->r12; 
105         ctx->R13 = sctx->r13; 
106         ctx->R14 = sctx->r14;
107         ctx->R15 = sctx->r15;
108         ctx->Rip = sctx->rip; 
109
110         /* Volatile But should not matter?*/
111         ctx->Rax = sctx->rax; 
112         ctx->Rcx = sctx->rcx; 
113         ctx->Rdx = sctx->rdx;
114
115         g_free (sctx);
116
117         return res;
118 }
119
120 void win32_seh_init()
121 {
122         old_handler = SetUnhandledExceptionFilter(seh_handler);
123 }
124
125 void win32_seh_cleanup()
126 {
127         if (old_handler) SetUnhandledExceptionFilter(old_handler);
128 }
129
130 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
131 {
132         switch (type) {
133         case SIGFPE:
134                 fpe_handler = handler;
135                 break;
136         case SIGILL:
137                 ill_handler = handler;
138                 break;
139         case SIGSEGV:
140                 segv_handler = handler;
141                 break;
142         default:
143                 break;
144         }
145 }
146
147 #endif /* TARGET_WIN32 */
148
149 /*
150  * mono_arch_get_restore_context:
151  *
152  * Returns a pointer to a method which restores a previously saved sigcontext.
153  */
154 gpointer
155 mono_arch_get_restore_context_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
156 {
157         guint8 *start = NULL;
158         guint8 *code;
159
160         /* restore_contect (MonoContext *ctx) */
161
162         *ji = NULL;
163
164         start = code = mono_global_codeman_reserve (256);
165
166         amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG1, 8);
167
168         /* Restore all registers except %rip and %r11 */
169         amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rax), 8);
170         amd64_mov_reg_membase (code, AMD64_RCX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rcx), 8);
171         amd64_mov_reg_membase (code, AMD64_RDX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rdx), 8);
172         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rbx), 8);
173         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rbp), 8);
174         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rsi), 8);
175         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rdi), 8);
176         //amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r8), 8);
177         //amd64_mov_reg_membase (code, AMD64_R9, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r9), 8);
178         //amd64_mov_reg_membase (code, AMD64_R10, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r10), 8);
179         amd64_mov_reg_membase (code, AMD64_R12, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r12), 8);
180         amd64_mov_reg_membase (code, AMD64_R13, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r13), 8);
181         amd64_mov_reg_membase (code, AMD64_R14, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r14), 8);
182         amd64_mov_reg_membase (code, AMD64_R15, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, r15), 8);
183
184         if (mono_running_on_valgrind ()) {
185                 /* Prevent 'Address 0x... is just below the stack ptr.' errors */
186                 amd64_mov_reg_membase (code, AMD64_R8, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rsp), 8);
187                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rip), 8);
188                 amd64_mov_reg_reg (code, AMD64_RSP, AMD64_R8, 8);
189         } else {
190                 amd64_mov_reg_membase (code, AMD64_RSP, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rsp), 8);
191                 /* get return address */
192                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11,  G_STRUCT_OFFSET (MonoContext, rip), 8);
193         }
194
195         /* jump to the saved IP */
196         amd64_jump_reg (code, AMD64_R11);
197
198         mono_arch_flush_icache (start, code - start);
199
200         *code_size = code - start;
201
202         return start;
203 }
204
205 /*
206  * mono_arch_get_call_filter:
207  *
208  * Returns a pointer to a method which calls an exception filter. We
209  * also use this function to call finally handlers (we pass NULL as 
210  * @exc object in this case).
211  */
212 gpointer
213 mono_arch_get_call_filter_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
214 {
215         guint8 *start;
216         int i;
217         guint8 *code;
218         guint32 pos;
219
220         *ji = NULL;
221
222         start = code = mono_global_codeman_reserve (128);
223
224         /* call_filter (MonoContext *ctx, unsigned long eip) */
225         code = start;
226
227         /* Alloc new frame */
228         amd64_push_reg (code, AMD64_RBP);
229         amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, 8);
230
231         /* Save callee saved regs */
232         pos = 0;
233         for (i = 0; i < AMD64_NREG; ++i)
234                 if (AMD64_IS_CALLEE_SAVED_REG (i)) {
235                         amd64_push_reg (code, i);
236                         pos += 8;
237                 }
238
239         /* Save EBP */
240         pos += 8;
241         amd64_push_reg (code, AMD64_RBP);
242
243         /* Make stack misaligned, the call will make it aligned again */
244         if (! (pos & 8))
245                 amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
246
247         /* set new EBP */
248         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, rbp), 8);
249         /* load callee saved regs */
250         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, rbx), 8);
251         amd64_mov_reg_membase (code, AMD64_R12, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r12), 8);
252         amd64_mov_reg_membase (code, AMD64_R13, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r13), 8);
253         amd64_mov_reg_membase (code, AMD64_R14, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r14), 8);
254         amd64_mov_reg_membase (code, AMD64_R15, AMD64_ARG_REG1, G_STRUCT_OFFSET (MonoContext, r15), 8);
255 #ifdef TARGET_WIN32
256         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_ARG_REG1,  G_STRUCT_OFFSET (MonoContext, rdi), 8);
257         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_ARG_REG1,  G_STRUCT_OFFSET (MonoContext, rsi), 8);
258 #endif
259
260         /* call the handler */
261         amd64_call_reg (code, AMD64_ARG_REG2);
262
263         if (! (pos & 8))
264                 amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
265
266         /* restore RBP */
267         amd64_pop_reg (code, AMD64_RBP);
268
269         /* Restore callee saved regs */
270         for (i = AMD64_NREG; i >= 0; --i)
271                 if (AMD64_IS_CALLEE_SAVED_REG (i))
272                         amd64_pop_reg (code, i);
273
274         amd64_leave (code);
275         amd64_ret (code);
276
277         g_assert ((code - start) < 128);
278
279         mono_arch_flush_icache (start, code - start);
280
281         *code_size = code - start;
282
283         return start;
284 }
285
286 /* 
287  * The first few arguments are dummy, to force the other arguments to be passed on
288  * the stack, this avoids overwriting the argument registers in the throw trampoline.
289  */
290 void
291 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
292                                                         guint64 dummy5, guint64 dummy6,
293                                                         MonoObject *exc, guint64 rip, guint64 rsp,
294                                                         guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
295                                                         guint64 r14, guint64 r15, guint64 rdi, guint64 rsi, 
296                                                         guint64 rax, guint64 rcx, guint64 rdx,
297                                                         guint64 rethrow)
298 {
299         static void (*restore_context) (MonoContext *);
300         MonoContext ctx;
301
302         if (!restore_context)
303                 restore_context = mono_get_restore_context ();
304
305         ctx.rsp = rsp;
306         ctx.rip = rip;
307         ctx.rbx = rbx;
308         ctx.rbp = rbp;
309         ctx.r12 = r12;
310         ctx.r13 = r13;
311         ctx.r14 = r14;
312         ctx.r15 = r15;
313         ctx.rdi = rdi;
314         ctx.rsi = rsi;
315         ctx.rax = rax;
316         ctx.rcx = rcx;
317         ctx.rdx = rdx;
318
319         if (mono_object_isinst (exc, mono_defaults.exception_class)) {
320                 MonoException *mono_ex = (MonoException*)exc;
321                 if (!rethrow)
322                         mono_ex->stack_trace = NULL;
323         }
324
325         if (mono_debug_using_mono_debugger ()) {
326                 guint8 buf [16], *code;
327
328                 mono_breakpoint_clean_code (NULL, (gpointer)rip, 8, buf, sizeof (buf));
329                 code = buf + 8;
330
331                 if (buf [3] == 0xe8) {
332                         MonoContext ctx_cp = ctx;
333                         ctx_cp.rip = rip - 5;
334
335                         if (mono_debugger_handle_exception (&ctx_cp, exc)) {
336                                 restore_context (&ctx_cp);
337                                 g_assert_not_reached ();
338                         }
339                 }
340         }
341
342         /* adjust eip so that it point into the call instruction */
343         ctx.rip -= 1;
344
345         mono_handle_exception (&ctx, exc, (gpointer)rip, FALSE);
346         restore_context (&ctx);
347
348         g_assert_not_reached ();
349 }
350
351 static gpointer
352 get_throw_trampoline (gboolean rethrow, guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
353 {
354         guint8* start;
355         guint8 *code;
356
357         start = code = mono_global_codeman_reserve (64);
358
359         code = start;
360
361         *ji = NULL;
362
363         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, 8);
364
365         /* reverse order */
366         amd64_push_imm (code, rethrow);
367         amd64_push_reg (code, AMD64_RDX);
368         amd64_push_reg (code, AMD64_RCX);
369         amd64_push_reg (code, AMD64_RAX);
370         amd64_push_reg (code, AMD64_RSI);
371         amd64_push_reg (code, AMD64_RDI);
372         amd64_push_reg (code, AMD64_R15);
373         amd64_push_reg (code, AMD64_R14);
374         amd64_push_reg (code, AMD64_R13);
375         amd64_push_reg (code, AMD64_R12);
376         amd64_push_reg (code, AMD64_RBP);
377         amd64_push_reg (code, AMD64_RBX);
378
379         /* SP */
380         amd64_lea_membase (code, AMD64_RAX, AMD64_R11, 8);
381         amd64_push_reg (code, AMD64_RAX);
382
383         /* IP */
384         amd64_push_membase (code, AMD64_R11, 0);
385
386         /* Exception */
387         amd64_push_reg (code, AMD64_ARG_REG1);
388
389 #ifdef TARGET_WIN32
390         /* align stack */
391         amd64_push_imm (code, 0);
392         amd64_push_imm (code, 0);
393         amd64_push_imm (code, 0);
394         amd64_push_imm (code, 0);
395         amd64_push_imm (code, 0);
396         amd64_push_imm (code, 0);
397 #endif
398
399         if (aot) {
400                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_throw_exception");
401                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
402         } else {
403                 amd64_mov_reg_imm (code, AMD64_R11, mono_amd64_throw_exception);
404         }
405         amd64_call_reg (code, AMD64_R11);
406         amd64_breakpoint (code);
407
408         mono_arch_flush_icache (start, code - start);
409
410         g_assert ((code - start) < 64);
411
412         *code_size = code - start;
413
414         return start;
415 }
416
417 /**
418  * mono_arch_get_throw_exception:
419  *
420  * Returns a function pointer which can be used to raise 
421  * exceptions. The returned function has the following 
422  * signature: void (*func) (MonoException *exc); 
423  *
424  */
425 gpointer 
426 mono_arch_get_throw_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
427 {
428         return get_throw_trampoline (FALSE, code_size, ji, aot);
429 }
430
431 gpointer 
432 mono_arch_get_rethrow_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
433 {
434         return get_throw_trampoline (TRUE, code_size, ji, aot);
435 }
436
437 /**
438  * mono_arch_get_throw_corlib_exception:
439  *
440  * Returns a function pointer which can be used to raise 
441  * corlib exceptions. The returned function has the following 
442  * signature: void (*func) (guint32 ex_token, guint32 offset); 
443  * Here, offset is the offset which needs to be substracted from the caller IP 
444  * to get the IP of the throw. Passing the offset has the advantage that it 
445  * needs no relocations in the caller.
446  */
447 gpointer 
448 mono_arch_get_throw_corlib_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
449 {
450         static guint8* start;
451         guint8 *code;
452         guint64 throw_ex;
453
454         start = code = mono_global_codeman_reserve (64);
455
456         *ji = NULL;
457
458         /* Push throw_ip */
459         amd64_push_reg (code, AMD64_ARG_REG2);
460
461         /* Call exception_from_token */
462         amd64_mov_reg_reg (code, AMD64_ARG_REG2, AMD64_ARG_REG1, 8);
463         if (aot) {
464                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_IMAGE, mono_defaults.exception_class->image);
465                 amd64_mov_reg_membase (code, AMD64_ARG_REG1, AMD64_RIP, 0, 8);
466                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_exception_from_token");
467                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
468         } else {
469                 amd64_mov_reg_imm (code, AMD64_ARG_REG1, mono_defaults.exception_class->image);
470                 amd64_mov_reg_imm (code, AMD64_R11, mono_exception_from_token);
471         }
472 #ifdef TARGET_WIN32
473         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 32);
474 #endif
475         amd64_call_reg (code, AMD64_R11);
476 #ifdef TARGET_WIN32
477         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 32);
478 #endif
479
480         /* Compute throw_ip */
481         amd64_pop_reg (code, AMD64_ARG_REG2);
482         /* return addr */
483         amd64_pop_reg (code, AMD64_ARG_REG3);
484         amd64_alu_reg_reg (code, X86_SUB, AMD64_ARG_REG3, AMD64_ARG_REG2);
485
486         /* Put the throw_ip at the top of the misaligned stack */
487         amd64_push_reg (code, AMD64_ARG_REG3);
488
489         throw_ex = (guint64)mono_get_throw_exception ();
490
491         /* Call throw_exception */
492         amd64_mov_reg_reg (code, AMD64_ARG_REG1, AMD64_RAX, 8);
493         if (aot) {
494                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_throw_exception");
495                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
496         } else {
497                 amd64_mov_reg_imm (code, AMD64_R11, throw_ex);
498         }
499         /* The original IP is on the stack */
500         amd64_jump_reg (code, AMD64_R11);
501
502         g_assert ((code - start) < 64);
503
504         mono_arch_flush_icache (start, code - start);
505
506         *code_size = code - start;
507
508         return start;
509 }
510
511 /*
512  * mono_arch_find_jit_info_ext:
513  *
514  * This function is used to gather information from @ctx, and store it in @frame_info.
515  * It unwinds one stack frame, and stores the resulting context into @new_ctx. @lmf
516  * is modified if needed.
517  * Returns TRUE on success, FALSE otherwise.
518  * This function is a version of mono_arch_find_jit_info () where all the results are
519  * returned in a StackFrameInfo structure.
520  */
521 gboolean
522 mono_arch_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, 
523                                                          MonoJitInfo *ji, MonoContext *ctx, 
524                                                          MonoContext *new_ctx, MonoLMF **lmf, 
525                                                          StackFrameInfo *frame)
526 {
527         gpointer ip = MONO_CONTEXT_GET_IP (ctx);
528
529         memset (frame, 0, sizeof (StackFrameInfo));
530         frame->ji = ji;
531         frame->managed = FALSE;
532
533         *new_ctx = *ctx;
534
535         if (ji != NULL) {
536                 gssize regs [MONO_MAX_IREGS + 1];
537                 guint8 *cfa;
538                 guint32 unwind_info_len;
539                 guint8 *unwind_info;
540
541                 frame->type = FRAME_TYPE_MANAGED;
542
543                 if (!ji->method->wrapper_type || ji->method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD)
544                         frame->managed = TRUE;
545
546                 if (ji->from_aot)
547                         unwind_info = mono_aot_get_unwind_info (ji, &unwind_info_len);
548                 else
549                         unwind_info = mono_get_cached_unwind_info (ji->used_regs, &unwind_info_len);
550  
551                 regs [AMD64_RAX] = new_ctx->rax;
552                 regs [AMD64_RBX] = new_ctx->rbx;
553                 regs [AMD64_RCX] = new_ctx->rcx;
554                 regs [AMD64_RDX] = new_ctx->rdx;
555                 regs [AMD64_RBP] = new_ctx->rbp;
556                 regs [AMD64_RSP] = new_ctx->rsp;
557                 regs [AMD64_RSI] = new_ctx->rsi;
558                 regs [AMD64_RDI] = new_ctx->rdi;
559                 regs [AMD64_RIP] = new_ctx->rip;
560                 regs [AMD64_R12] = new_ctx->r12;
561                 regs [AMD64_R13] = new_ctx->r13;
562                 regs [AMD64_R14] = new_ctx->r14;
563                 regs [AMD64_R15] = new_ctx->r15;
564
565                 mono_unwind_frame (unwind_info, unwind_info_len, ji->code_start, 
566                                                    (guint8*)ji->code_start + ji->code_size,
567                                                    ip, regs, MONO_MAX_IREGS + 1, &cfa);
568
569                 new_ctx->rax = regs [AMD64_RAX];
570                 new_ctx->rbx = regs [AMD64_RBX];
571                 new_ctx->rcx = regs [AMD64_RCX];
572                 new_ctx->rdx = regs [AMD64_RDX];
573                 new_ctx->rbp = regs [AMD64_RBP];
574                 new_ctx->rsp = regs [AMD64_RSP];
575                 new_ctx->rsi = regs [AMD64_RSI];
576                 new_ctx->rdi = regs [AMD64_RDI];
577                 new_ctx->rip = regs [AMD64_RIP];
578                 new_ctx->r12 = regs [AMD64_R12];
579                 new_ctx->r13 = regs [AMD64_R13];
580                 new_ctx->r14 = regs [AMD64_R14];
581                 new_ctx->r15 = regs [AMD64_R15];
582  
583                 /* The CFA becomes the new SP value */
584                 new_ctx->rsp = (gssize)cfa;
585
586                 /* Adjust IP */
587                 new_ctx->rip --;
588
589                 if (*lmf && ((*lmf) != jit_tls->first_lmf) && (MONO_CONTEXT_GET_SP (ctx) >= (gpointer)(*lmf)->rsp)) {
590                         /* remove any unused lmf */
591                         *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);
592                 }
593
594 #ifndef MONO_AMD64_NO_PUSHES
595                 /* Pop arguments off the stack */
596                 {
597                         MonoJitArgumentInfo *arg_info = g_newa (MonoJitArgumentInfo, mono_method_signature (ji->method)->param_count + 1);
598
599                         guint32 stack_to_pop = mono_arch_get_argument_info (mono_method_signature (ji->method), mono_method_signature (ji->method)->param_count, arg_info);
600                         new_ctx->rsp += stack_to_pop;
601                 }
602 #endif
603
604                 return TRUE;
605         } else if (*lmf) {
606                 guint64 rip;
607
608                 if (((guint64)(*lmf)->previous_lmf) & 2) {
609                         /* 
610                          * This LMF entry is created by the soft debug code to mark transitions to
611                          * managed code done during invokes.
612                          */
613                         MonoLMFExt *ext = (MonoLMFExt*)(*lmf);
614
615                         g_assert (ext->debugger_invoke);
616
617                         memcpy (new_ctx, &ext->ctx, sizeof (MonoContext));
618
619                         *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);
620
621                         frame->type = FRAME_TYPE_DEBUGGER_INVOKE;
622
623                         return TRUE;
624                 }
625
626                 if (((guint64)(*lmf)->previous_lmf) & 1) {
627                         /* This LMF has the rip field set */
628                         rip = (*lmf)->rip;
629                 } else if ((*lmf)->rsp == 0) {
630                         /* Top LMF entry */
631                         return FALSE;
632                 } else {
633                         /* 
634                          * The rsp field is set just before the call which transitioned to native 
635                          * code. Obtain the rip from the stack.
636                          */
637                         rip = *(guint64*)((*lmf)->rsp - sizeof (gpointer));
638                 }
639
640                 ji = mini_jit_info_table_find (domain, (gpointer)rip, NULL);
641                 if (!ji) {
642                         // FIXME: This can happen with multiple appdomains (bug #444383)
643                         return FALSE;
644                 }
645
646                 frame->ji = ji;
647                 frame->type = FRAME_TYPE_MANAGED_TO_NATIVE;
648
649                 new_ctx->rip = rip;
650                 new_ctx->rbp = (*lmf)->rbp;
651                 new_ctx->rsp = (*lmf)->rsp;
652
653                 new_ctx->rbx = (*lmf)->rbx;
654                 new_ctx->r12 = (*lmf)->r12;
655                 new_ctx->r13 = (*lmf)->r13;
656                 new_ctx->r14 = (*lmf)->r14;
657                 new_ctx->r15 = (*lmf)->r15;
658 #ifdef TARGET_WIN32
659                 new_ctx->rdi = (*lmf)->rdi;
660                 new_ctx->rsi = (*lmf)->rsi;
661 #endif
662
663                 *lmf = (gpointer)(((guint64)(*lmf)->previous_lmf) & ~3);
664
665                 return TRUE;
666         }
667
668         return FALSE;
669 }
670
671 /**
672  * mono_arch_handle_exception:
673  *
674  * @ctx: saved processor state
675  * @obj: the exception object
676  */
677 gboolean
678 mono_arch_handle_exception (void *sigctx, gpointer obj, gboolean test_only)
679 {
680         MonoContext mctx;
681
682         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
683
684         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj))
685                 return TRUE;
686
687         mono_handle_exception (&mctx, obj, MONO_CONTEXT_GET_IP (&mctx), test_only);
688
689         mono_arch_monoctx_to_sigctx (&mctx, sigctx);
690
691         return TRUE;
692 }
693
694 #ifdef MONO_ARCH_USE_SIGACTION
695 static inline guint64*
696 gregs_from_ucontext (ucontext_t *ctx)
697 {
698         return (guint64 *) UCONTEXT_GREGS (ctx);
699 }
700 #endif
701 void
702 mono_arch_sigctx_to_monoctx (void *sigctx, MonoContext *mctx)
703 {
704 #ifdef MONO_ARCH_USE_SIGACTION
705         ucontext_t *ctx = (ucontext_t*)sigctx;
706
707     guint64 *gregs = gregs_from_ucontext (ctx);
708
709         mctx->rax = gregs [REG_RAX];
710         mctx->rbx = gregs [REG_RBX];
711         mctx->rcx = gregs [REG_RCX];
712         mctx->rdx = gregs [REG_RDX];
713         mctx->rbp = gregs [REG_RBP];
714         mctx->rsp = gregs [REG_RSP];
715         mctx->rsi = gregs [REG_RSI];
716         mctx->rdi = gregs [REG_RDI];
717         mctx->rip = gregs [REG_RIP];
718         mctx->r12 = gregs [REG_R12];
719         mctx->r13 = gregs [REG_R13];
720         mctx->r14 = gregs [REG_R14];
721         mctx->r15 = gregs [REG_R15];
722 #else
723         MonoContext *ctx = (MonoContext *)sigctx;
724
725         mctx->rax = ctx->rax;
726         mctx->rbx = ctx->rbx;
727         mctx->rcx = ctx->rcx;
728         mctx->rdx = ctx->rdx;
729         mctx->rbp = ctx->rbp;
730         mctx->rsp = ctx->rsp;
731         mctx->rsi = ctx->rsi;
732         mctx->rdi = ctx->rdi;
733         mctx->rip = ctx->rip;
734         mctx->r12 = ctx->r12;
735         mctx->r13 = ctx->r13;
736         mctx->r14 = ctx->r14;
737         mctx->r15 = ctx->r15;
738 #endif
739 }
740
741 void
742 mono_arch_monoctx_to_sigctx (MonoContext *mctx, void *sigctx)
743 {
744 #ifdef MONO_ARCH_USE_SIGACTION
745         ucontext_t *ctx = (ucontext_t*)sigctx;
746
747     guint64 *gregs = gregs_from_ucontext (ctx);
748
749         gregs [REG_RAX] = mctx->rax;
750         gregs [REG_RBX] = mctx->rbx;
751         gregs [REG_RCX] = mctx->rcx;
752         gregs [REG_RDX] = mctx->rdx;
753         gregs [REG_RBP] = mctx->rbp;
754         gregs [REG_RSP] = mctx->rsp;
755         gregs [REG_RSI] = mctx->rsi;
756         gregs [REG_RDI] = mctx->rdi;
757         gregs [REG_RIP] = mctx->rip;
758         gregs [REG_R12] = mctx->r12;
759         gregs [REG_R13] = mctx->r13;
760         gregs [REG_R14] = mctx->r14;
761         gregs [REG_R15] = mctx->r15;
762 #else
763         MonoContext *ctx = (MonoContext *)sigctx;
764
765         ctx->rax = mctx->rax;
766         ctx->rbx = mctx->rbx;
767         ctx->rcx = mctx->rcx;
768         ctx->rdx = mctx->rdx;
769         ctx->rbp = mctx->rbp;
770         ctx->rsp = mctx->rsp;
771         ctx->rsi = mctx->rsi;
772         ctx->rdi = mctx->rdi;
773         ctx->rip = mctx->rip;
774         ctx->r12 = mctx->r12;
775         ctx->r13 = mctx->r13;
776         ctx->r14 = mctx->r14;
777         ctx->r15 = mctx->r15;
778 #endif
779 }
780
781 gpointer
782 mono_arch_ip_from_context (void *sigctx)
783 {
784         
785 #ifdef MONO_ARCH_USE_SIGACTION
786
787         ucontext_t *ctx = (ucontext_t*)sigctx;
788
789     guint64 *gregs = gregs_from_ucontext (ctx);
790
791         return (gpointer)gregs [REG_RIP];
792 #else
793         MonoContext *ctx = sigctx;
794         return (gpointer)ctx->rip;
795 #endif  
796 }
797
798 static void
799 restore_soft_guard_pages (void)
800 {
801         MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
802         if (jit_tls->stack_ovf_guard_base)
803                 mono_mprotect (jit_tls->stack_ovf_guard_base, jit_tls->stack_ovf_guard_size, MONO_MMAP_NONE);
804 }
805
806 /* 
807  * this function modifies mctx so that when it is restored, it
808  * won't execcute starting at mctx.eip, but in a function that
809  * will restore the protection on the soft-guard pages and return back to
810  * continue at mctx.eip.
811  */
812 static void
813 prepare_for_guard_pages (MonoContext *mctx)
814 {
815         gpointer *sp;
816         sp = (gpointer)(mctx->rsp);
817         sp -= 1;
818         /* the return addr */
819         sp [0] = (gpointer)(mctx->rip);
820         mctx->rip = (guint64)restore_soft_guard_pages;
821         mctx->rsp = (guint64)sp;
822 }
823
824 static void
825 altstack_handle_and_restore (void *sigctx, gpointer obj, gboolean stack_ovf)
826 {
827         void (*restore_context) (MonoContext *);
828         MonoContext mctx;
829
830         restore_context = mono_get_restore_context ();
831         mono_arch_sigctx_to_monoctx (sigctx, &mctx);
832
833         if (mono_debugger_handle_exception (&mctx, (MonoObject *)obj)) {
834                 if (stack_ovf)
835                         prepare_for_guard_pages (&mctx);
836                 restore_context (&mctx);
837         }
838
839         mono_handle_exception (&mctx, obj, MONO_CONTEXT_GET_IP (&mctx), FALSE);
840         if (stack_ovf)
841                 prepare_for_guard_pages (&mctx);
842         restore_context (&mctx);
843 }
844
845 void
846 mono_arch_handle_altstack_exception (void *sigctx, gpointer fault_addr, gboolean stack_ovf)
847 {
848 #ifdef MONO_ARCH_USE_SIGACTION
849         MonoException *exc = NULL;
850         ucontext_t *ctx = (ucontext_t*)sigctx;
851         guint64 *gregs = gregs_from_ucontext (ctx);
852         MonoJitInfo *ji = mini_jit_info_table_find (mono_domain_get (), (gpointer)gregs [REG_RIP], NULL);
853         gpointer *sp;
854         int frame_size;
855
856         if (stack_ovf)
857                 exc = mono_domain_get ()->stack_overflow_ex;
858         if (!ji)
859                 mono_handle_native_sigsegv (SIGSEGV, sigctx);
860
861         /* setup a call frame on the real stack so that control is returned there
862          * and exception handling can continue.
863          * The frame looks like:
864          *   ucontext struct
865          *   ...
866          *   return ip
867          * 128 is the size of the red zone
868          */
869         frame_size = sizeof (ucontext_t) + sizeof (gpointer) * 4 + 128;
870         frame_size += 15;
871         frame_size &= ~15;
872         sp = (gpointer)(gregs [REG_RSP] & ~15);
873         sp = (gpointer)((char*)sp - frame_size);
874         /* the arguments must be aligned */
875         sp [-1] = (gpointer)gregs [REG_RIP];
876         /* may need to adjust pointers in the new struct copy, depending on the OS */
877         memcpy (sp + 4, ctx, sizeof (ucontext_t));
878         /* at the return form the signal handler execution starts in altstack_handle_and_restore() */
879         gregs [REG_RIP] = (unsigned long)altstack_handle_and_restore;
880         gregs [REG_RSP] = (unsigned long)(sp - 1);
881         gregs [REG_RDI] = (unsigned long)(sp + 4);
882         gregs [REG_RSI] = (guint64)exc;
883         gregs [REG_RDX] = stack_ovf;
884 #endif
885 }
886
887 guint64
888 mono_amd64_get_original_ip (void)
889 {
890         MonoLMF *lmf = mono_get_lmf ();
891
892         g_assert (lmf);
893
894         /* Reset the change to previous_lmf */
895         lmf->previous_lmf = (gpointer)((guint64)lmf->previous_lmf & ~1);
896
897         return lmf->rip;
898 }
899
900 gpointer
901 mono_arch_get_throw_pending_exception_full (guint32 *code_size, MonoJumpInfo **ji, gboolean aot)
902 {
903         guint8 *code, *start;
904         guint8 *br[1];
905         gpointer throw_trampoline;
906
907         *ji = NULL;
908
909         start = code = mono_global_codeman_reserve (128);
910
911         /* We are in the frame of a managed method after a call */
912         /* 
913          * We would like to throw the pending exception in such a way that it looks to
914          * be thrown from the managed method.
915          */
916
917         /* Save registers which might contain the return value of the call */
918         amd64_push_reg (code, AMD64_RAX);
919         amd64_push_reg (code, AMD64_RDX);
920
921         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
922         amd64_movsd_membase_reg (code, AMD64_RSP, 0, AMD64_XMM0);
923
924         /* Align stack */
925         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
926
927         /* Obtain the pending exception */
928         if (aot) {
929                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_get_and_clear_pending_exception");
930                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
931         } else {
932                 amd64_mov_reg_imm (code, AMD64_R11, mono_thread_get_and_clear_pending_exception);
933         }
934         amd64_call_reg (code, AMD64_R11);
935
936         /* Check if it is NULL, and branch */
937         amd64_alu_reg_imm (code, X86_CMP, AMD64_RAX, 0);
938         br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
939
940         /* exc != NULL branch */
941
942         /* Save the exc on the stack */
943         amd64_push_reg (code, AMD64_RAX);
944         /* Align stack */
945         amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, 8);
946
947         /* Obtain the original ip and clear the flag in previous_lmf */
948         if (aot) {
949                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_get_original_ip");
950                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
951         } else {
952                 amd64_mov_reg_imm (code, AMD64_R11, mono_amd64_get_original_ip);
953         }
954         amd64_call_reg (code, AMD64_R11);       
955
956         /* Load exc */
957         amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, 8, 8);
958
959         /* Pop saved stuff from the stack */
960         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 6 * 8);
961
962         /* Setup arguments for the throw trampoline */
963         /* Exception */
964         amd64_mov_reg_reg (code, AMD64_ARG_REG1, AMD64_R11, 8);
965         /* The trampoline expects the caller ip to be pushed on the stack */
966         amd64_push_reg (code, AMD64_RAX);
967
968         /* Call the throw trampoline */
969         if (aot) {
970                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_throw_exception");
971                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
972         } else {
973                 throw_trampoline = mono_get_throw_exception ();
974                 amd64_mov_reg_imm (code, AMD64_R11, throw_trampoline);
975         }
976         /* We use a jump instead of a call so we can push the original ip on the stack */
977         amd64_jump_reg (code, AMD64_R11);
978
979         /* ex == NULL branch */
980         mono_amd64_patch (br [0], code);
981
982         /* Obtain the original ip and clear the flag in previous_lmf */
983         if (aot) {
984                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_amd64_get_original_ip");
985                 amd64_mov_reg_membase (code, AMD64_R11, AMD64_RIP, 0, 8);
986         } else {
987                 amd64_mov_reg_imm (code, AMD64_R11, mono_amd64_get_original_ip);
988         }
989         amd64_call_reg (code, AMD64_R11);       
990         amd64_mov_reg_reg (code, AMD64_R11, AMD64_RAX, 8);
991
992         /* Restore registers */
993         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
994         amd64_movsd_reg_membase (code, AMD64_XMM0, AMD64_RSP, 0);
995         amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
996         amd64_pop_reg (code, AMD64_RDX);
997         amd64_pop_reg (code, AMD64_RAX);
998
999         /* Return to original code */
1000         amd64_jump_reg (code, AMD64_R11);
1001
1002         g_assert ((code - start) < 128);
1003
1004         *code_size = code - start;
1005
1006         return start;
1007 }
1008
1009 static gpointer throw_pending_exception;
1010
1011 /*
1012  * Called when a thread receives an async exception while executing unmanaged code.
1013  * Instead of checking for this exception in the managed-to-native wrapper, we hijack 
1014  * the return address on the stack to point to a helper routine which throws the
1015  * exception.
1016  */
1017 void
1018 mono_arch_notify_pending_exc (void)
1019 {
1020         MonoLMF *lmf = mono_get_lmf ();
1021
1022         if (!lmf)
1023                 /* Not yet started */
1024                 return;
1025
1026         if (lmf->rsp == 0)
1027                 /* Initial LMF */
1028                 return;
1029
1030         if ((guint64)lmf->previous_lmf & 1)
1031                 /* Already hijacked or trampoline LMF entry */
1032                 return;
1033
1034         /* lmf->rsp is set just before making the call which transitions to unmanaged code */
1035         lmf->rip = *(guint64*)(lmf->rsp - 8);
1036         /* Signal that lmf->rip is set */
1037         lmf->previous_lmf = (gpointer)((guint64)lmf->previous_lmf | 1);
1038
1039         *(gpointer*)(lmf->rsp - 8) = throw_pending_exception;
1040 }
1041
1042 void
1043 mono_arch_exceptions_init (void)
1044 {
1045         guint32 code_size;
1046         MonoJumpInfo *ji;
1047
1048         if (mono_aot_only) {
1049                 throw_pending_exception = mono_aot_get_named_code ("throw_pending_exception");
1050         } else {
1051                 /* Call this to avoid initialization races */
1052                 throw_pending_exception = mono_arch_get_throw_pending_exception_full (&code_size, &ji, FALSE);
1053         }
1054 }
1055
1056 #ifdef TARGET_WIN32
1057
1058 /*
1059  * The mono_arch_unwindinfo* methods are used to build and add
1060  * function table info for each emitted method from mono.  On Winx64
1061  * the seh handler will not be called if the mono methods are not
1062  * added to the function table.  
1063  *
1064  * We should not need to add non-volatile register info to the 
1065  * table since mono stores that info elsewhere. (Except for the register 
1066  * used for the fp.)
1067  */
1068
1069 #define MONO_MAX_UNWIND_CODES 22
1070
1071 typedef union _UNWIND_CODE {
1072     struct {
1073         guchar CodeOffset;
1074         guchar UnwindOp : 4;
1075         guchar OpInfo   : 4;
1076     };
1077     gushort FrameOffset;
1078 } UNWIND_CODE, *PUNWIND_CODE;
1079
1080 typedef struct _UNWIND_INFO {
1081         guchar Version       : 3;
1082         guchar Flags         : 5;
1083         guchar SizeOfProlog;
1084         guchar CountOfCodes;
1085         guchar FrameRegister : 4;
1086         guchar FrameOffset   : 4;
1087         /* custom size for mono allowing for mono allowing for*/
1088         /*UWOP_PUSH_NONVOL ebp offset = 21*/
1089         /*UWOP_ALLOC_LARGE : requires 2 or 3 offset = 20*/
1090         /*UWOP_SET_FPREG : requires 2 offset = 17*/
1091         /*UWOP_PUSH_NONVOL offset = 15-0*/
1092         UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES]; 
1093
1094 /*      UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
1095  *      union {
1096  *          OPTIONAL ULONG ExceptionHandler;
1097  *          OPTIONAL ULONG FunctionEntry;
1098  *      };
1099  *      OPTIONAL ULONG ExceptionData[]; */
1100 } UNWIND_INFO, *PUNWIND_INFO;
1101
1102 typedef struct
1103 {
1104         RUNTIME_FUNCTION runtimeFunction;
1105         UNWIND_INFO unwindInfo;
1106 } MonoUnwindInfo, *PMonoUnwindInfo;
1107
1108 static void
1109 mono_arch_unwindinfo_create (gpointer* monoui)
1110 {
1111         PMonoUnwindInfo newunwindinfo;
1112         *monoui = newunwindinfo = g_new0 (MonoUnwindInfo, 1);
1113         newunwindinfo->unwindInfo.Version = 1;
1114 }
1115
1116 void
1117 mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
1118 {
1119         PMonoUnwindInfo unwindinfo;
1120         PUNWIND_CODE unwindcode;
1121         guchar codeindex;
1122         if (!*monoui)
1123                 mono_arch_unwindinfo_create (monoui);
1124         
1125         unwindinfo = (MonoUnwindInfo*)*monoui;
1126
1127         if (unwindinfo->unwindInfo.CountOfCodes >= MONO_MAX_UNWIND_CODES)
1128                 g_error ("Larger allocation needed for the unwind information.");
1129
1130         codeindex = MONO_MAX_UNWIND_CODES - (++unwindinfo->unwindInfo.CountOfCodes);
1131         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1132         unwindcode->UnwindOp = 0; /*UWOP_PUSH_NONVOL*/
1133         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1134         unwindcode->OpInfo = reg;
1135
1136         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1137                 g_error ("Adding unwind info in wrong order.");
1138         
1139         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1140 }
1141
1142 void
1143 mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
1144 {
1145         PMonoUnwindInfo unwindinfo;
1146         PUNWIND_CODE unwindcode;
1147         guchar codeindex;
1148         if (!*monoui)
1149                 mono_arch_unwindinfo_create (monoui);
1150         
1151         unwindinfo = (MonoUnwindInfo*)*monoui;
1152
1153         if (unwindinfo->unwindInfo.CountOfCodes + 1 >= MONO_MAX_UNWIND_CODES)
1154                 g_error ("Larger allocation needed for the unwind information.");
1155
1156         codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += 2);
1157         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1158         unwindcode->FrameOffset = 0; /*Assuming no frame pointer offset for mono*/
1159         unwindcode++;
1160         unwindcode->UnwindOp = 3; /*UWOP_SET_FPREG*/
1161         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1162         unwindcode->OpInfo = reg;
1163         
1164         unwindinfo->unwindInfo.FrameRegister = reg;
1165
1166         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1167                 g_error ("Adding unwind info in wrong order.");
1168         
1169         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1170 }
1171
1172 void
1173 mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size )
1174 {
1175         PMonoUnwindInfo unwindinfo;
1176         PUNWIND_CODE unwindcode;
1177         guchar codeindex;
1178         guchar codesneeded;
1179         if (!*monoui)
1180                 mono_arch_unwindinfo_create (monoui);
1181         
1182         unwindinfo = (MonoUnwindInfo*)*monoui;
1183
1184         if (size < 0x8)
1185                 g_error ("Stack allocation must be equal to or greater than 0x8.");
1186         
1187         if (size <= 0x80)
1188                 codesneeded = 1;
1189         else if (size <= 0x7FFF8)
1190                 codesneeded = 2;
1191         else
1192                 codesneeded = 3;
1193         
1194         if (unwindinfo->unwindInfo.CountOfCodes + codesneeded > MONO_MAX_UNWIND_CODES)
1195                 g_error ("Larger allocation needed for the unwind information.");
1196
1197         codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += codesneeded);
1198         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1199
1200         if (codesneeded == 1) {
1201                 /*The size of the allocation is 
1202                   (the number in the OpInfo member) times 8 plus 8*/
1203                 unwindcode->OpInfo = (size - 8)/8;
1204                 unwindcode->UnwindOp = 2; /*UWOP_ALLOC_SMALL*/
1205         }
1206         else {
1207                 if (codesneeded == 3) {
1208                         /*the unscaled size of the allocation is recorded
1209                           in the next two slots in little-endian format*/
1210                         *((unsigned int*)(&unwindcode->FrameOffset)) = size;
1211                         unwindcode += 2;
1212                         unwindcode->OpInfo = 1;
1213                 }
1214                 else {
1215                         /*the size of the allocation divided by 8
1216                           is recorded in the next slot*/
1217                         unwindcode->FrameOffset = size/8; 
1218                         unwindcode++;   
1219                         unwindcode->OpInfo = 0;
1220                         
1221                 }
1222                 unwindcode->UnwindOp = 1; /*UWOP_ALLOC_LARGE*/
1223         }
1224
1225         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1226
1227         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1228                 g_error ("Adding unwind info in wrong order.");
1229         
1230         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1231 }
1232
1233 guint
1234 mono_arch_unwindinfo_get_size (gpointer monoui)
1235 {
1236         PMonoUnwindInfo unwindinfo;
1237         if (!monoui)
1238                 return 0;
1239         
1240         unwindinfo = (MonoUnwindInfo*)monoui;
1241         return (8 + sizeof (MonoUnwindInfo)) - 
1242                 (sizeof (UNWIND_CODE) * (MONO_MAX_UNWIND_CODES - unwindinfo->unwindInfo.CountOfCodes));
1243 }
1244
1245 PRUNTIME_FUNCTION
1246 MONO_GET_RUNTIME_FUNCTION_CALLBACK ( DWORD64 ControlPc, IN PVOID Context )
1247 {
1248         MonoJitInfo *ji;
1249         guint64 pos;
1250         PMonoUnwindInfo targetinfo;
1251         MonoDomain *domain = mono_domain_get ();
1252
1253         ji = mini_jit_info_table_find (domain, (char*)ControlPc, NULL);
1254         if (!ji)
1255                 return 0;
1256
1257         pos = (guint64)(((char*)ji->code_start) + ji->code_size);
1258         
1259         targetinfo = (PMonoUnwindInfo)ALIGN_TO (pos, 8);
1260
1261         targetinfo->runtimeFunction.UnwindData = ((DWORD64)&targetinfo->unwindInfo) - ((DWORD64)Context);
1262
1263         return &targetinfo->runtimeFunction;
1264 }
1265
1266 void
1267 mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size)
1268 {
1269         PMonoUnwindInfo unwindinfo, targetinfo;
1270         guchar codecount;
1271         guint64 targetlocation;
1272         if (!*monoui)
1273                 return;
1274
1275         unwindinfo = (MonoUnwindInfo*)*monoui;
1276         targetlocation = (guint64)&(((guchar*)code)[code_size]);
1277         targetinfo = (PMonoUnwindInfo) ALIGN_TO(targetlocation, 8);
1278
1279         unwindinfo->runtimeFunction.EndAddress = code_size;
1280         unwindinfo->runtimeFunction.UnwindData = ((guchar*)&targetinfo->unwindInfo) - ((guchar*)code);
1281         
1282         memcpy (targetinfo, unwindinfo, sizeof (MonoUnwindInfo) - (sizeof (UNWIND_CODE) * MONO_MAX_UNWIND_CODES));
1283         
1284         codecount = unwindinfo->unwindInfo.CountOfCodes;
1285         if (codecount) {
1286                 memcpy (&targetinfo->unwindInfo.UnwindCode[0], &unwindinfo->unwindInfo.UnwindCode[MONO_MAX_UNWIND_CODES-codecount], 
1287                         sizeof (UNWIND_CODE) * unwindinfo->unwindInfo.CountOfCodes);
1288         }
1289
1290         g_free (unwindinfo);
1291         *monoui = 0;
1292
1293         RtlInstallFunctionTableCallback (((DWORD64)code) | 0x3, (DWORD64)code, code_size, MONO_GET_RUNTIME_FUNCTION_CALLBACK, code, NULL);
1294 }
1295
1296 #endif
1297
1298 #if MONO_SUPPORT_TASKLETS
1299 MonoContinuationRestore
1300 mono_tasklets_arch_restore (void)
1301 {
1302         static guint8* saved = NULL;
1303         guint8 *code, *start;
1304         int cont_reg = AMD64_R9; /* register usable on both call conventions */
1305
1306         if (saved)
1307                 return (MonoContinuationRestore)saved;
1308         code = start = mono_global_codeman_reserve (64);
1309         /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
1310         /* cont is in AMD64_ARG_REG1 ($rcx or $rdi)
1311          * state is in AMD64_ARG_REG2 ($rdx or $rsi)
1312          * lmf_addr is in AMD64_ARG_REG3 ($r8 or $rdx)
1313          * We move cont to cont_reg since we need both rcx and rdi for the copy
1314          * state is moved to $rax so it's setup as the return value and we can overwrite $rsi
1315          */
1316         amd64_mov_reg_reg (code, cont_reg, MONO_AMD64_ARG_REG1, 8);
1317         amd64_mov_reg_reg (code, AMD64_RAX, MONO_AMD64_ARG_REG2, 8);
1318         /* setup the copy of the stack */
1319         amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), sizeof (int));
1320         amd64_shift_reg_imm (code, X86_SHR, AMD64_RCX, 3);
1321         x86_cld (code);
1322         amd64_mov_reg_membase (code, AMD64_RSI, cont_reg, G_STRUCT_OFFSET (MonoContinuation, saved_stack), sizeof (gpointer));
1323         amd64_mov_reg_membase (code, AMD64_RDI, cont_reg, G_STRUCT_OFFSET (MonoContinuation, return_sp), sizeof (gpointer));
1324         amd64_prefix (code, X86_REP_PREFIX);
1325         amd64_movsl (code);
1326
1327         /* now restore the registers from the LMF */
1328         amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, G_STRUCT_OFFSET (MonoContinuation, lmf), 8);
1329         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rbx), 8);
1330         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rbp), 8);
1331         amd64_mov_reg_membase (code, AMD64_R12, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r12), 8);
1332         amd64_mov_reg_membase (code, AMD64_R13, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r13), 8);
1333         amd64_mov_reg_membase (code, AMD64_R14, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r14), 8);
1334         amd64_mov_reg_membase (code, AMD64_R15, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r15), 8);
1335 #ifdef TARGET_WIN32
1336         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rdi), 8);
1337         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rsi), 8);
1338 #endif
1339         amd64_mov_reg_membase (code, AMD64_RSP, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rsp), 8);
1340
1341         /* restore the lmf chain */
1342         /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
1343         x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
1344
1345         /* state is already in rax */
1346         amd64_jump_membase (code, cont_reg, G_STRUCT_OFFSET (MonoContinuation, return_ip));
1347         g_assert ((code - start) <= 64);
1348         saved = start;
1349         return (MonoContinuationRestore)saved;
1350 }
1351 #endif
1352