2010-01-20 Zoltan Varga <vargaz@gmail.com>
[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->rsp == 0)
1023                 /* Initial LMF */
1024                 return;
1025
1026         if ((guint64)lmf->previous_lmf & 1)
1027                 /* Already hijacked or trampoline LMF entry */
1028                 return;
1029
1030         /* lmf->rsp is set just before making the call which transitions to unmanaged code */
1031         lmf->rip = *(guint64*)(lmf->rsp - 8);
1032         /* Signal that lmf->rip is set */
1033         lmf->previous_lmf = (gpointer)((guint64)lmf->previous_lmf | 1);
1034
1035         *(gpointer*)(lmf->rsp - 8) = throw_pending_exception;
1036 }
1037
1038 void
1039 mono_arch_exceptions_init (void)
1040 {
1041         guint32 code_size;
1042         MonoJumpInfo *ji;
1043
1044         if (mono_aot_only) {
1045                 throw_pending_exception = mono_aot_get_named_code ("throw_pending_exception");
1046         } else {
1047                 /* Call this to avoid initialization races */
1048                 throw_pending_exception = mono_arch_get_throw_pending_exception_full (&code_size, &ji, FALSE);
1049         }
1050 }
1051
1052 #ifdef TARGET_WIN32
1053
1054 /*
1055  * The mono_arch_unwindinfo* methods are used to build and add
1056  * function table info for each emitted method from mono.  On Winx64
1057  * the seh handler will not be called if the mono methods are not
1058  * added to the function table.  
1059  *
1060  * We should not need to add non-volatile register info to the 
1061  * table since mono stores that info elsewhere. (Except for the register 
1062  * used for the fp.)
1063  */
1064
1065 #define MONO_MAX_UNWIND_CODES 22
1066
1067 typedef union _UNWIND_CODE {
1068     struct {
1069         guchar CodeOffset;
1070         guchar UnwindOp : 4;
1071         guchar OpInfo   : 4;
1072     };
1073     gushort FrameOffset;
1074 } UNWIND_CODE, *PUNWIND_CODE;
1075
1076 typedef struct _UNWIND_INFO {
1077         guchar Version       : 3;
1078         guchar Flags         : 5;
1079         guchar SizeOfProlog;
1080         guchar CountOfCodes;
1081         guchar FrameRegister : 4;
1082         guchar FrameOffset   : 4;
1083         /* custom size for mono allowing for mono allowing for*/
1084         /*UWOP_PUSH_NONVOL ebp offset = 21*/
1085         /*UWOP_ALLOC_LARGE : requires 2 or 3 offset = 20*/
1086         /*UWOP_SET_FPREG : requires 2 offset = 17*/
1087         /*UWOP_PUSH_NONVOL offset = 15-0*/
1088         UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES]; 
1089
1090 /*      UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
1091  *      union {
1092  *          OPTIONAL ULONG ExceptionHandler;
1093  *          OPTIONAL ULONG FunctionEntry;
1094  *      };
1095  *      OPTIONAL ULONG ExceptionData[]; */
1096 } UNWIND_INFO, *PUNWIND_INFO;
1097
1098 typedef struct
1099 {
1100         RUNTIME_FUNCTION runtimeFunction;
1101         UNWIND_INFO unwindInfo;
1102 } MonoUnwindInfo, *PMonoUnwindInfo;
1103
1104 static void
1105 mono_arch_unwindinfo_create (gpointer* monoui)
1106 {
1107         PMonoUnwindInfo newunwindinfo;
1108         *monoui = newunwindinfo = g_new0 (MonoUnwindInfo, 1);
1109         newunwindinfo->unwindInfo.Version = 1;
1110 }
1111
1112 void
1113 mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
1114 {
1115         PMonoUnwindInfo unwindinfo;
1116         PUNWIND_CODE unwindcode;
1117         guchar codeindex;
1118         if (!*monoui)
1119                 mono_arch_unwindinfo_create (monoui);
1120         
1121         unwindinfo = (MonoUnwindInfo*)*monoui;
1122
1123         if (unwindinfo->unwindInfo.CountOfCodes >= MONO_MAX_UNWIND_CODES)
1124                 g_error ("Larger allocation needed for the unwind information.");
1125
1126         codeindex = MONO_MAX_UNWIND_CODES - (++unwindinfo->unwindInfo.CountOfCodes);
1127         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1128         unwindcode->UnwindOp = 0; /*UWOP_PUSH_NONVOL*/
1129         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1130         unwindcode->OpInfo = reg;
1131
1132         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1133                 g_error ("Adding unwind info in wrong order.");
1134         
1135         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1136 }
1137
1138 void
1139 mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg )
1140 {
1141         PMonoUnwindInfo unwindinfo;
1142         PUNWIND_CODE unwindcode;
1143         guchar codeindex;
1144         if (!*monoui)
1145                 mono_arch_unwindinfo_create (monoui);
1146         
1147         unwindinfo = (MonoUnwindInfo*)*monoui;
1148
1149         if (unwindinfo->unwindInfo.CountOfCodes + 1 >= MONO_MAX_UNWIND_CODES)
1150                 g_error ("Larger allocation needed for the unwind information.");
1151
1152         codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += 2);
1153         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1154         unwindcode->FrameOffset = 0; /*Assuming no frame pointer offset for mono*/
1155         unwindcode++;
1156         unwindcode->UnwindOp = 3; /*UWOP_SET_FPREG*/
1157         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1158         unwindcode->OpInfo = reg;
1159         
1160         unwindinfo->unwindInfo.FrameRegister = reg;
1161
1162         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1163                 g_error ("Adding unwind info in wrong order.");
1164         
1165         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1166 }
1167
1168 void
1169 mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size )
1170 {
1171         PMonoUnwindInfo unwindinfo;
1172         PUNWIND_CODE unwindcode;
1173         guchar codeindex;
1174         guchar codesneeded;
1175         if (!*monoui)
1176                 mono_arch_unwindinfo_create (monoui);
1177         
1178         unwindinfo = (MonoUnwindInfo*)*monoui;
1179
1180         if (size < 0x8)
1181                 g_error ("Stack allocation must be equal to or greater than 0x8.");
1182         
1183         if (size <= 0x80)
1184                 codesneeded = 1;
1185         else if (size <= 0x7FFF8)
1186                 codesneeded = 2;
1187         else
1188                 codesneeded = 3;
1189         
1190         if (unwindinfo->unwindInfo.CountOfCodes + codesneeded > MONO_MAX_UNWIND_CODES)
1191                 g_error ("Larger allocation needed for the unwind information.");
1192
1193         codeindex = MONO_MAX_UNWIND_CODES - (unwindinfo->unwindInfo.CountOfCodes += codesneeded);
1194         unwindcode = &unwindinfo->unwindInfo.UnwindCode[codeindex];
1195
1196         if (codesneeded == 1) {
1197                 /*The size of the allocation is 
1198                   (the number in the OpInfo member) times 8 plus 8*/
1199                 unwindcode->OpInfo = (size - 8)/8;
1200                 unwindcode->UnwindOp = 2; /*UWOP_ALLOC_SMALL*/
1201         }
1202         else {
1203                 if (codesneeded == 3) {
1204                         /*the unscaled size of the allocation is recorded
1205                           in the next two slots in little-endian format*/
1206                         *((unsigned int*)(&unwindcode->FrameOffset)) = size;
1207                         unwindcode += 2;
1208                         unwindcode->OpInfo = 1;
1209                 }
1210                 else {
1211                         /*the size of the allocation divided by 8
1212                           is recorded in the next slot*/
1213                         unwindcode->FrameOffset = size/8; 
1214                         unwindcode++;   
1215                         unwindcode->OpInfo = 0;
1216                         
1217                 }
1218                 unwindcode->UnwindOp = 1; /*UWOP_ALLOC_LARGE*/
1219         }
1220
1221         unwindcode->CodeOffset = (((guchar*)nextip)-((guchar*)codebegin));
1222
1223         if (unwindinfo->unwindInfo.SizeOfProlog >= unwindcode->CodeOffset)
1224                 g_error ("Adding unwind info in wrong order.");
1225         
1226         unwindinfo->unwindInfo.SizeOfProlog = unwindcode->CodeOffset;
1227 }
1228
1229 guint
1230 mono_arch_unwindinfo_get_size (gpointer monoui)
1231 {
1232         PMonoUnwindInfo unwindinfo;
1233         if (!monoui)
1234                 return 0;
1235         
1236         unwindinfo = (MonoUnwindInfo*)monoui;
1237         return (8 + sizeof (MonoUnwindInfo)) - 
1238                 (sizeof (UNWIND_CODE) * (MONO_MAX_UNWIND_CODES - unwindinfo->unwindInfo.CountOfCodes));
1239 }
1240
1241 PRUNTIME_FUNCTION
1242 MONO_GET_RUNTIME_FUNCTION_CALLBACK ( DWORD64 ControlPc, IN PVOID Context )
1243 {
1244         MonoJitInfo *ji;
1245         guint64 pos;
1246         PMonoUnwindInfo targetinfo;
1247         MonoDomain *domain = mono_domain_get ();
1248
1249         ji = mini_jit_info_table_find (domain, (char*)ControlPc, NULL);
1250         if (!ji)
1251                 return 0;
1252
1253         pos = (guint64)(((char*)ji->code_start) + ji->code_size);
1254         
1255         targetinfo = (PMonoUnwindInfo)ALIGN_TO (pos, 8);
1256
1257         targetinfo->runtimeFunction.UnwindData = ((DWORD64)&targetinfo->unwindInfo) - ((DWORD64)Context);
1258
1259         return &targetinfo->runtimeFunction;
1260 }
1261
1262 void
1263 mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size)
1264 {
1265         PMonoUnwindInfo unwindinfo, targetinfo;
1266         guchar codecount;
1267         guint64 targetlocation;
1268         if (!*monoui)
1269                 return;
1270
1271         unwindinfo = (MonoUnwindInfo*)*monoui;
1272         targetlocation = (guint64)&(((guchar*)code)[code_size]);
1273         targetinfo = (PMonoUnwindInfo) ALIGN_TO(targetlocation, 8);
1274
1275         unwindinfo->runtimeFunction.EndAddress = code_size;
1276         unwindinfo->runtimeFunction.UnwindData = ((guchar*)&targetinfo->unwindInfo) - ((guchar*)code);
1277         
1278         memcpy (targetinfo, unwindinfo, sizeof (MonoUnwindInfo) - (sizeof (UNWIND_CODE) * MONO_MAX_UNWIND_CODES));
1279         
1280         codecount = unwindinfo->unwindInfo.CountOfCodes;
1281         if (codecount) {
1282                 memcpy (&targetinfo->unwindInfo.UnwindCode[0], &unwindinfo->unwindInfo.UnwindCode[MONO_MAX_UNWIND_CODES-codecount], 
1283                         sizeof (UNWIND_CODE) * unwindinfo->unwindInfo.CountOfCodes);
1284         }
1285
1286         g_free (unwindinfo);
1287         *monoui = 0;
1288
1289         RtlInstallFunctionTableCallback (((DWORD64)code) | 0x3, (DWORD64)code, code_size, MONO_GET_RUNTIME_FUNCTION_CALLBACK, code, NULL);
1290 }
1291
1292 #endif
1293
1294 #if MONO_SUPPORT_TASKLETS
1295 MonoContinuationRestore
1296 mono_tasklets_arch_restore (void)
1297 {
1298         static guint8* saved = NULL;
1299         guint8 *code, *start;
1300         int cont_reg = AMD64_R9; /* register usable on both call conventions */
1301
1302         if (saved)
1303                 return (MonoContinuationRestore)saved;
1304         code = start = mono_global_codeman_reserve (64);
1305         /* the signature is: restore (MonoContinuation *cont, int state, MonoLMF **lmf_addr) */
1306         /* cont is in AMD64_ARG_REG1 ($rcx or $rdi)
1307          * state is in AMD64_ARG_REG2 ($rdx or $rsi)
1308          * lmf_addr is in AMD64_ARG_REG3 ($r8 or $rdx)
1309          * We move cont to cont_reg since we need both rcx and rdi for the copy
1310          * state is moved to $rax so it's setup as the return value and we can overwrite $rsi
1311          */
1312         amd64_mov_reg_reg (code, cont_reg, MONO_AMD64_ARG_REG1, 8);
1313         amd64_mov_reg_reg (code, AMD64_RAX, MONO_AMD64_ARG_REG2, 8);
1314         /* setup the copy of the stack */
1315         amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, G_STRUCT_OFFSET (MonoContinuation, stack_used_size), sizeof (int));
1316         amd64_shift_reg_imm (code, X86_SHR, AMD64_RCX, 3);
1317         x86_cld (code);
1318         amd64_mov_reg_membase (code, AMD64_RSI, cont_reg, G_STRUCT_OFFSET (MonoContinuation, saved_stack), sizeof (gpointer));
1319         amd64_mov_reg_membase (code, AMD64_RDI, cont_reg, G_STRUCT_OFFSET (MonoContinuation, return_sp), sizeof (gpointer));
1320         amd64_prefix (code, X86_REP_PREFIX);
1321         amd64_movsl (code);
1322
1323         /* now restore the registers from the LMF */
1324         amd64_mov_reg_membase (code, AMD64_RCX, cont_reg, G_STRUCT_OFFSET (MonoContinuation, lmf), 8);
1325         amd64_mov_reg_membase (code, AMD64_RBX, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rbx), 8);
1326         amd64_mov_reg_membase (code, AMD64_RBP, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rbp), 8);
1327         amd64_mov_reg_membase (code, AMD64_R12, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r12), 8);
1328         amd64_mov_reg_membase (code, AMD64_R13, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r13), 8);
1329         amd64_mov_reg_membase (code, AMD64_R14, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r14), 8);
1330         amd64_mov_reg_membase (code, AMD64_R15, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, r15), 8);
1331 #ifdef TARGET_WIN32
1332         amd64_mov_reg_membase (code, AMD64_RDI, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rdi), 8);
1333         amd64_mov_reg_membase (code, AMD64_RSI, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rsi), 8);
1334 #endif
1335         amd64_mov_reg_membase (code, AMD64_RSP, AMD64_RCX, G_STRUCT_OFFSET (MonoLMF, rsp), 8);
1336
1337         /* restore the lmf chain */
1338         /*x86_mov_reg_membase (code, X86_ECX, X86_ESP, 12, 4);
1339         x86_mov_membase_reg (code, X86_ECX, 0, X86_EDX, 4);*/
1340
1341         /* state is already in rax */
1342         amd64_jump_membase (code, cont_reg, G_STRUCT_OFFSET (MonoContinuation, return_ip));
1343         g_assert ((code - start) <= 64);
1344         saved = start;
1345         return (MonoContinuationRestore)saved;
1346 }
1347 #endif
1348