[amd64] Make inline function in header static
[mono.git] / mono / mini / mini-amd64.h
1 /**
2  * \file
3  */
4
5 #ifndef __MONO_MINI_AMD64_H__
6 #define __MONO_MINI_AMD64_H__
7
8 #include <mono/arch/amd64/amd64-codegen.h>
9 #include <mono/utils/mono-sigcontext.h>
10 #include <mono/utils/mono-context.h>
11 #include <glib.h>
12
13 #ifdef HOST_WIN32
14 #include <windows.h>
15 /* use SIG* defines if possible */
16 #ifdef HAVE_SIGNAL_H
17 #include <signal.h>
18 #endif
19
20 #if !defined(_MSC_VER)
21 /* sigcontext surrogate */
22 struct sigcontext {
23         guint64 eax;
24         guint64 ebx;
25         guint64 ecx;
26         guint64 edx;
27         guint64 ebp;
28         guint64 esp;
29     guint64 esi;
30         guint64 edi;
31         guint64 eip;
32 };
33 #endif
34
35 typedef void (* MonoW32ExceptionHandler) (int _dummy, EXCEPTION_POINTERS *info, void *context);
36 void win32_seh_init(void);
37 void win32_seh_cleanup(void);
38 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
39
40 #ifndef SIGFPE
41 #define SIGFPE 4
42 #endif
43
44 #ifndef SIGILL
45 #define SIGILL 8
46 #endif
47
48 #ifndef SIGSEGV
49 #define SIGSEGV 11
50 #endif
51
52 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
53
54 typedef struct {
55         SRWLOCK lock;
56         PVOID handle;
57         gsize begin_range;
58         gsize end_range;
59         PRUNTIME_FUNCTION rt_funcs;
60         DWORD rt_funcs_current_count;
61         DWORD rt_funcs_max_count;
62 } DynamicFunctionTableEntry;
63
64 #define MONO_UNWIND_INFO_RT_FUNC_SIZE 128
65
66 // On Win8/Win2012Server and later we can use dynamic growable function tables
67 // instead of RtlInstallFunctionTableCallback. This gives us the benefit to
68 // include all needed unwind upon registration.
69 typedef DWORD (NTAPI* RtlAddGrowableFunctionTablePtr)(
70     PVOID * DynamicTable,
71     PRUNTIME_FUNCTION FunctionTable,
72     DWORD EntryCount,
73     DWORD MaximumEntryCount,
74     ULONG_PTR RangeBase,
75     ULONG_PTR RangeEnd);
76
77 typedef VOID (NTAPI* RtlGrowFunctionTablePtr)(
78     PVOID DynamicTable,
79     DWORD NewEntryCount);
80
81 typedef VOID (NTAPI* RtlDeleteGrowableFunctionTablePtr)(
82     PVOID DynamicTable);
83
84 #endif /* HOST_WIN32 */
85
86 #ifdef sun    // Solaris x86
87 #  undef SIGSEGV_ON_ALTSTACK
88 #  define MONO_ARCH_NOMAP32BIT
89
90 struct sigcontext {
91         unsigned short gs, __gsh;
92         unsigned short fs, __fsh;
93         unsigned short es, __esh;
94         unsigned short ds, __dsh;
95         unsigned long edi;
96         unsigned long esi;
97         unsigned long ebp;
98         unsigned long esp;
99         unsigned long ebx;
100         unsigned long edx;
101         unsigned long ecx;
102         unsigned long eax;
103         unsigned long trapno;
104         unsigned long err;
105         unsigned long eip;
106         unsigned short cs, __csh;
107         unsigned long eflags;
108         unsigned long esp_at_signal;
109         unsigned short ss, __ssh;
110         unsigned long fpstate[95];
111       unsigned long filler[5];
112 };
113 #endif  // sun, Solaris x86
114
115 #ifndef DISABLE_SIMD
116 #define MONO_ARCH_SIMD_INTRINSICS 1
117 #define MONO_ARCH_NEED_SIMD_BANK 1
118 #define MONO_ARCH_USE_SHARED_FP_SIMD_BANK 1
119 #endif
120
121
122
123 #if defined(__APPLE__)
124 #define MONO_ARCH_SIGNAL_STACK_SIZE MINSIGSTKSZ
125 #else
126 #define MONO_ARCH_SIGNAL_STACK_SIZE (16 * 1024)
127 #endif
128
129 #define MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT 1
130
131 #define MONO_ARCH_CPU_SPEC mono_amd64_desc
132
133 #define MONO_MAX_IREGS 16
134
135 #define MONO_MAX_FREGS AMD64_XMM_NREG
136
137 #define MONO_ARCH_FP_RETURN_REG AMD64_XMM0
138
139 #ifdef TARGET_WIN32
140 /* xmm5 is used as a scratch register */
141 #define MONO_ARCH_CALLEE_FREGS 0x1f
142 /* xmm6:xmm15 */
143 #define MONO_ARCH_CALLEE_SAVED_FREGS (0xffff - 0x3f)
144 #define MONO_ARCH_FP_SCRATCH_REG AMD64_XMM5
145 #else
146 /* xmm15 is used as a scratch register */
147 #define MONO_ARCH_CALLEE_FREGS 0x7fff
148 #define MONO_ARCH_CALLEE_SAVED_FREGS 0
149 #define MONO_ARCH_FP_SCRATCH_REG AMD64_XMM15
150 #endif
151
152 #define MONO_MAX_XREGS MONO_MAX_FREGS
153
154 #define MONO_ARCH_CALLEE_XREGS MONO_ARCH_CALLEE_FREGS
155 #define MONO_ARCH_CALLEE_SAVED_XREGS MONO_ARCH_CALLEE_SAVED_FREGS
156
157
158 #define MONO_ARCH_CALLEE_REGS AMD64_CALLEE_REGS
159 #define MONO_ARCH_CALLEE_SAVED_REGS AMD64_CALLEE_SAVED_REGS
160
161 #define MONO_ARCH_USE_FPSTACK FALSE
162 #define MONO_ARCH_FPSTACK_SIZE 0
163
164 #define MONO_ARCH_INST_FIXED_REG(desc) ((desc == '\0') ? -1 : ((desc == 'i' ? -1 : ((desc == 'a') ? AMD64_RAX : ((desc == 's') ? AMD64_RCX : ((desc == 'd') ? AMD64_RDX : ((desc == 'A') ? MONO_AMD64_ARG_REG1 : -1)))))))
165
166 /* RDX is clobbered by the opcode implementation before accessing sreg2 */
167 #define MONO_ARCH_INST_SREG2_MASK(ins) (((ins [MONO_INST_CLOB] == 'a') || (ins [MONO_INST_CLOB] == 'd')) ? (1 << AMD64_RDX) : 0)
168
169 #define MONO_ARCH_INST_IS_REGPAIR(desc) FALSE
170 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (-1)
171
172 #define MONO_ARCH_FRAME_ALIGNMENT 16
173
174 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get 
175  * reproduceable results for benchmarks */
176 #define MONO_ARCH_CODE_ALIGNMENT 32
177
178 /*This is the max size of the locals area of a given frame. I think 1MB is a safe default for now*/
179 #define MONO_ARCH_MAX_FRAME_SIZE 0x100000
180
181 struct MonoLMF {
182         /* 
183          * If the lowest bit is set, then this LMF has the rip field set. Otherwise,
184          * the rip field is not set, and the rsp field points to the stack location where
185          * the caller ip is saved.
186          * If the second lowest bit is set, then this is a MonoLMFExt structure, and
187          * the other fields are not valid.
188          * If the third lowest bit is set, then this is a MonoLMFTramp structure, and
189          * the 'rbp' field is not valid.
190          */
191         gpointer    previous_lmf;
192         guint64     rip;
193         guint64     rbp;
194         guint64     rsp;
195 };
196
197 /* LMF structure used by the JIT trampolines */
198 typedef struct {
199         struct MonoLMF lmf;
200         MonoContext *ctx;
201         gpointer lmf_addr;
202 } MonoLMFTramp;
203
204 typedef struct MonoCompileArch {
205         gint32 localloc_offset;
206         gint32 reg_save_area_offset;
207         gint32 stack_alloc_size;
208         gint32 sp_fp_offset;
209         guint32 saved_iregs;
210         gboolean omit_fp, omit_fp_computed;
211         gpointer cinfo;
212         gint32 async_point_count;
213         gpointer vret_addr_loc;
214 #ifdef HOST_WIN32
215         gpointer unwindinfo;
216 #endif
217         gpointer seq_point_info_var;
218         gpointer ss_trigger_page_var;
219         gpointer ss_tramp_var;
220         gpointer bp_tramp_var;
221         gpointer lmf_var;
222 } MonoCompileArch;
223
224 #ifdef TARGET_WIN32
225
226 static AMD64_Reg_No param_regs [] = { AMD64_RCX, AMD64_RDX, AMD64_R8, AMD64_R9 };
227
228 static AMD64_XMM_Reg_No float_param_regs [] = { AMD64_XMM0, AMD64_XMM1, AMD64_XMM2, AMD64_XMM3 };
229
230 static AMD64_Reg_No return_regs [] = { AMD64_RAX };
231
232 static AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 };
233
234 #define PARAM_REGS G_N_ELEMENTS(param_regs)
235 #define FLOAT_PARAM_REGS G_N_ELEMENTS(float_param_regs)
236 #define RETURN_REGS G_N_ELEMENTS(return_regs)
237 #define FLOAT_RETURN_REGS G_N_ELEMENTS(float_return_regs)
238
239 #else
240 #define PARAM_REGS 6
241 #define FLOAT_PARAM_REGS 8
242
243 static AMD64_Reg_No param_regs [] = { AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9 };
244
245 static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
246 #endif
247
248 typedef struct {
249         /* Method address to call */
250         gpointer addr;
251         /* The trampoline reads this, so keep the size explicit */
252         int ret_marshal;
253         /* If ret_marshal != NONE, this is the reg of the vret arg, else -1 (used in out case) */
254         /* Equivalent of vret_arg_slot in the x86 implementation. */
255         int vret_arg_reg;
256         /* The stack slot where the return value will be stored (used in in case) */
257         int vret_slot;
258         int stack_usage, map_count;
259         /* If not -1, then make a virtual call using this vtable offset */
260         int vcall_offset;
261         /* If 1, make an indirect call to the address in the rgctx reg */
262         int calli;
263         /* Whenever this is a in or an out call */
264         int gsharedvt_in;
265         /* Maps stack slots/registers in the caller to the stack slots/registers in the callee */
266         int map [MONO_ZERO_LEN_ARRAY];
267 } GSharedVtCallInfo;
268
269 /* Structure used by the sequence points in AOTed code */
270 typedef struct {
271         gpointer ss_tramp_addr;
272         gpointer bp_addrs [MONO_ZERO_LEN_ARRAY];
273 } SeqPointInfo;
274
275 #define DYN_CALL_STACK_ARGS 6
276
277 typedef struct {
278         mgreg_t regs [PARAM_REGS + DYN_CALL_STACK_ARGS];
279         mgreg_t res;
280         guint8 *ret;
281         double fregs [8];
282         mgreg_t has_fp;
283         guint8 buffer [256];
284 } DynCallArgs;
285
286 typedef enum {
287         ArgInIReg,
288         ArgInFloatSSEReg,
289         ArgInDoubleSSEReg,
290         ArgOnStack,
291         ArgValuetypeInReg,
292         ArgValuetypeAddrInIReg,
293         ArgValuetypeAddrOnStack,
294         /* gsharedvt argument passed by addr */
295         ArgGSharedVtInReg,
296         ArgGSharedVtOnStack,
297         /* Variable sized gsharedvt argument passed/returned by addr */
298         ArgGsharedvtVariableInReg,
299         ArgNone /* only in pair_storage */
300 } ArgStorage;
301
302 typedef struct {
303         gint16 offset;
304         gint8  reg;
305         ArgStorage storage : 8;
306
307         /* Only if storage == ArgValuetypeInReg */
308         ArgStorage pair_storage [2];
309         gint8 pair_regs [2];
310         /* The size of each pair (bytes) */
311         int pair_size [2];
312         int nregs;
313         /* Only if storage == ArgOnStack */
314         int arg_size; // Bytes, will always be rounded up/aligned to 8 byte boundary
315         guint8 pass_empty_struct : 1; // Set in scenarios when empty structs needs to be represented as argument.
316 } ArgInfo;
317
318 typedef struct {
319         int nargs;
320         guint32 stack_usage;
321         guint32 reg_usage;
322         guint32 freg_usage;
323         gboolean need_stack_align;
324         gboolean gsharedvt;
325         /* The index of the vret arg in the argument list */
326         int vret_arg_index;
327         ArgInfo ret;
328         ArgInfo sig_cookie;
329         ArgInfo args [1];
330 } CallInfo;
331
332
333 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->gregs [AMD64_RAX] = (gsize)exc; } while (0)
334 #define MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG(ctx, sel) do { (ctx)->gregs [AMD64_RDX] = (gsize)(sel); } while (0)
335
336 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
337
338 #ifdef _MSC_VER
339
340 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx, start_func) do { \
341     guint64 stackptr; \
342         mono_arch_flush_register_windows (); \
343         stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));\
344         MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
345         MONO_CONTEXT_SET_BP ((ctx), stackptr); \
346         MONO_CONTEXT_SET_SP ((ctx), stackptr); \
347 } while (0)
348
349 #else
350
351 /* 
352  * __builtin_frame_address () is broken on some older gcc versions in the presence of
353  * frame pointer elimination, see bug #82095.
354  */
355 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do {        \
356         int tmp; \
357         guint64 stackptr = (guint64)&tmp; \
358                 mono_arch_flush_register_windows ();    \
359                 MONO_CONTEXT_SET_IP ((ctx), (start_func));      \
360                 MONO_CONTEXT_SET_BP ((ctx), stackptr);  \
361                 MONO_CONTEXT_SET_SP ((ctx), stackptr);  \
362         } while (0)
363
364 #endif
365
366 /*
367  * some icalls like mono_array_new_va needs to be called using a different 
368  * calling convention.
369  */
370 #define MONO_ARCH_VARARG_ICALLS 1
371
372 #if !defined( HOST_WIN32 ) && defined (HAVE_SIGACTION)
373
374 #define MONO_ARCH_USE_SIGACTION 1
375
376 #ifdef HAVE_WORKING_SIGALTSTACK
377
378 #define MONO_ARCH_SIGSEGV_ON_ALTSTACK
379
380 #endif
381
382 #endif /* !HOST_WIN32 */
383
384 #if !defined(__linux__)
385 #define MONO_ARCH_NOMAP32BIT 1
386 #endif
387
388 #ifdef TARGET_WIN32
389 #define MONO_AMD64_ARG_REG1 AMD64_RCX
390 #define MONO_AMD64_ARG_REG2 AMD64_RDX
391 #define MONO_AMD64_ARG_REG3 AMD64_R8
392 #define MONO_AMD64_ARG_REG4 AMD64_R9
393 #else
394 #define MONO_AMD64_ARG_REG1 AMD64_RDI
395 #define MONO_AMD64_ARG_REG2 AMD64_RSI
396 #define MONO_AMD64_ARG_REG3 AMD64_RDX
397 #define MONO_AMD64_ARG_REG4 AMD64_RCX
398 #endif
399
400 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
401 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
402
403 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
404 #define MONO_ARCH_EMULATE_FREM 1
405 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
406 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
407 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
408 #define MONO_ARCH_IMT_REG AMD64_R10
409 #define MONO_ARCH_IMT_SCRATCH_REG AMD64_R11
410 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
411 /*
412  * We use r10 for the imt/rgctx register rather than r11 because r11 is
413  * used by the trampoline as a scratch register and hence might be
414  * clobbered across method call boundaries.
415  */
416 #define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG
417 #define MONO_ARCH_EXC_REG AMD64_RAX
418 #define MONO_ARCH_HAVE_CMOV_OPS 1
419 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
420 #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE 1
421 #define MONO_ARCH_HAVE_LIVERANGE_OPS 1
422 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
423 #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
424
425 #define MONO_ARCH_AOT_SUPPORTED 1
426 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
427
428 #define MONO_ARCH_SUPPORT_TASKLETS 1
429
430 #define MONO_ARCH_GSHARED_SUPPORTED 1
431 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
432 #define MONO_ARCH_DYN_CALL_PARAM_AREA (DYN_CALL_STACK_ARGS * 8)
433
434 #define MONO_ARCH_LLVM_SUPPORTED 1
435 #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
436 #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD_AOT 1
437 #define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER 1
438 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
439 #define MONO_ARCH_GC_MAPS_SUPPORTED 1
440 #define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
441 #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
442 #define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1
443 #define MONO_ARCH_HAVE_OP_TAIL_CALL 1
444 #define MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET 1
445 #define MONO_ARCH_HAVE_DUMMY_INIT 1
446 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1
447 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
448 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
449 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
450
451 #if defined(TARGET_OSX) || defined(__linux__)
452 #define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1
453 #endif
454
455 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1
456
457
458 #if defined(TARGET_APPLETVOS)
459 /* No signals */
460 #define MONO_ARCH_NEED_DIV_CHECK 1
461 #endif
462
463 /* Used for optimization, not complete */
464 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
465
466 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
467             MonoInst *inst; \
468             MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
469             inst->inst_basereg = array_reg; \
470             inst->inst_offset = offset; \
471             inst->sreg2 = index_reg; \
472             MONO_ADD_INS ((cfg)->cbb, inst); \
473             MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
474        } while (0)
475
476 void 
477 mono_amd64_patch (unsigned char* code, gpointer target);
478
479 void
480 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
481                                                         guint64 dummy5, guint64 dummy6,
482                                                         MonoContext *mctx, MonoObject *exc, gboolean rethrow);
483
484 void
485 mono_amd64_throw_corlib_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
486                                                                    guint64 dummy5, guint64 dummy6,
487                                                                    MonoContext *mctx, guint32 ex_token_index, gint64 pc_offset);
488
489 void
490 mono_amd64_resume_unwind (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
491                                                   guint64 dummy5, guint64 dummy6,
492                                                   MonoContext *mctx, guint32 dummy7, gint64 dummy8);
493
494 gpointer
495 mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg);
496
497 guint64
498 mono_amd64_get_original_ip (void);
499
500 GSList*
501 mono_amd64_get_exception_trampolines (gboolean aot);
502
503 int
504 mono_amd64_get_tls_gs_offset (void) MONO_LLVM_INTERNAL;
505
506 gpointer
507 mono_amd64_handler_block_trampoline_helper (void);
508
509 #if defined(TARGET_WIN32) && !defined(DISABLE_JIT)
510
511 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
512 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
513 #define MONO_ARCH_HAVE_CODE_CHUNK_TRACKING 1
514
515 #ifdef ENABLE_CHECKED_BUILD
516 #define ENABLE_CHECKED_BUILD_UNWINDINFO
517 #endif
518
519 #define MONO_MAX_UNWIND_CODES 22
520
521 typedef enum _UNWIND_OP_CODES {
522     UWOP_PUSH_NONVOL = 0, /* info == register number */
523     UWOP_ALLOC_LARGE,     /* no info, alloc size in next 2 slots */
524     UWOP_ALLOC_SMALL,     /* info == size of allocation / 8 - 1 */
525     UWOP_SET_FPREG,       /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
526     UWOP_SAVE_NONVOL,     /* info == register number, offset in next slot */
527     UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
528     UWOP_SAVE_XMM128,     /* info == XMM reg number, offset in next slot */
529     UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
530     UWOP_PUSH_MACHFRAME   /* info == 0: no error-code, 1: error-code */
531 } UNWIND_CODE_OPS;
532
533 typedef union _UNWIND_CODE {
534     struct {
535         guchar CodeOffset;
536         guchar UnwindOp : 4;
537         guchar OpInfo   : 4;
538     };
539     gushort FrameOffset;
540 } UNWIND_CODE, *PUNWIND_CODE;
541
542 typedef struct _UNWIND_INFO {
543         guchar Version       : 3;
544         guchar Flags         : 5;
545         guchar SizeOfProlog;
546         guchar CountOfCodes;
547         guchar FrameRegister : 4;
548         guchar FrameOffset   : 4;
549         UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES];
550 /*      UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
551  *      union {
552  *              OPTIONAL ULONG ExceptionHandler;
553  *              OPTIONAL ULONG FunctionEntry;
554  *      };
555  *      OPTIONAL ULONG ExceptionData[]; */
556 } UNWIND_INFO, *PUNWIND_INFO;
557
558 inline guint
559 mono_arch_unwindinfo_get_size (guchar code_count)
560 {
561         // Returned size will be used as the allocated size for unwind data trailing the memory used by compiled method.
562         // Windows x64 ABI have some requirements on the data written into this memory. Both the RUNTIME_FUNCTION
563         // and UNWIND_INFO struct needs to be DWORD aligned and the number of elements in unwind codes array
564         // should have an even number of entries, while the count stored in UNWIND_INFO struct should hold the real number
565         // of unwind codes. Adding extra bytes to the total size will make sure we can properly align the RUNTIME_FUNCTION
566         // struct. Since our UNWIND_INFO follows RUNTIME_FUNCTION struct in memory, it will automatically be DWORD aligned
567         // as well. Also make sure to allocate room for a padding UNWIND_CODE, if needed.
568         return (sizeof (mgreg_t) + sizeof (UNWIND_INFO)) -
569                 (sizeof (UNWIND_CODE) * ((MONO_MAX_UNWIND_CODES - ((code_count + 1) & ~1))));
570 }
571
572 guchar
573 mono_arch_unwindinfo_get_code_count (GSList *unwind_ops);
574
575 guint
576 mono_arch_unwindinfo_init_method_unwind_info (gpointer cfg);
577
578 void
579 mono_arch_unwindinfo_install_method_unwind_info (gpointer *monoui, gpointer code, guint code_size);
580
581 void
582 mono_arch_unwindinfo_install_tramp_unwind_info (GSList *unwind_ops, gpointer code, guint code_size);
583
584 void
585 mono_arch_code_chunk_new (void *chunk, int size);
586
587 void
588 mono_arch_code_chunk_destroy (void *chunk);
589
590 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
591 #endif /* defined(TARGET_WIN32) && !defined(DISABLE_JIT) */
592
593 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
594 // Allocate additional size for max 3 unwind ops (push + fp or sp small|large) + unwind info struct trailing code buffer.
595 #define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) (mono_arch_unwindinfo_get_size (max_code_count))
596 #define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE (MONO_TRAMPOLINE_UNWINDINFO_SIZE(3))
597
598 static inline gboolean
599 mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
600 {
601         guint current_size = mono_arch_unwindinfo_get_size (mono_arch_unwindinfo_get_code_count (unwind_ops));
602         return current_size <= max_size;
603 }
604
605 #else
606
607 #define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) 0
608 #define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE 0
609
610 static inline gboolean
611 mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
612 {
613         return TRUE;
614 }
615 #endif
616
617 CallInfo* mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
618
619 #endif /* __MONO_MINI_AMD64_H__ */  
620