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