1 #ifndef __MONO_MINI_AMD64_H__
2 #define __MONO_MINI_AMD64_H__
4 #include <mono/arch/amd64/amd64-codegen.h>
5 #include <mono/utils/mono-sigcontext.h>
6 #include <mono/utils/mono-context.h>
11 /* use SIG* defines if possible */
16 #if !defined(_MSC_VER)
17 /* sigcontext surrogate */
31 typedef void (* MonoW32ExceptionHandler) (int _dummy, EXCEPTION_POINTERS *info, void *context);
32 void win32_seh_init(void);
33 void win32_seh_cleanup(void);
34 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
48 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
55 PRUNTIME_FUNCTION rt_funcs;
56 DWORD rt_funcs_current_count;
57 DWORD rt_funcs_max_count;
58 } DynamicFunctionTableEntry;
60 #define MONO_UNWIND_INFO_RT_FUNC_SIZE 128
62 // On Win8/Win2012Server and later we can use dynamic growable function tables
63 // instead of RtlInstallFunctionTableCallback. This gives us the benefit to
64 // include all needed unwind upon registration.
65 typedef DWORD (NTAPI* RtlAddGrowableFunctionTablePtr)(
67 PRUNTIME_FUNCTION FunctionTable,
69 DWORD MaximumEntryCount,
73 typedef VOID (NTAPI* RtlGrowFunctionTablePtr)(
77 typedef VOID (NTAPI* RtlDeleteGrowableFunctionTablePtr)(
80 #endif /* HOST_WIN32 */
82 #ifdef sun // Solaris x86
83 # undef SIGSEGV_ON_ALTSTACK
84 # define MONO_ARCH_NOMAP32BIT
87 unsigned short gs, __gsh;
88 unsigned short fs, __fsh;
89 unsigned short es, __esh;
90 unsigned short ds, __dsh;
102 unsigned short cs, __csh;
103 unsigned long eflags;
104 unsigned long esp_at_signal;
105 unsigned short ss, __ssh;
106 unsigned long fpstate[95];
107 unsigned long filler[5];
109 #endif // sun, Solaris x86
112 #define MONO_ARCH_SIMD_INTRINSICS 1
113 #define MONO_ARCH_NEED_SIMD_BANK 1
114 #define MONO_ARCH_USE_SHARED_FP_SIMD_BANK 1
119 #if defined(__APPLE__)
120 #define MONO_ARCH_SIGNAL_STACK_SIZE MINSIGSTKSZ
122 #define MONO_ARCH_SIGNAL_STACK_SIZE (16 * 1024)
125 #define MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT 1
127 #define MONO_ARCH_CPU_SPEC mono_amd64_desc
129 #define MONO_MAX_IREGS 16
131 #define MONO_MAX_FREGS AMD64_XMM_NREG
133 #define MONO_ARCH_FP_RETURN_REG AMD64_XMM0
136 /* xmm5 is used as a scratch register */
137 #define MONO_ARCH_CALLEE_FREGS 0x1f
139 #define MONO_ARCH_CALLEE_SAVED_FREGS (0xffff - 0x3f)
140 #define MONO_ARCH_FP_SCRATCH_REG AMD64_XMM5
142 /* xmm15 is used as a scratch register */
143 #define MONO_ARCH_CALLEE_FREGS 0x7fff
144 #define MONO_ARCH_CALLEE_SAVED_FREGS 0
145 #define MONO_ARCH_FP_SCRATCH_REG AMD64_XMM15
148 #define MONO_MAX_XREGS MONO_MAX_FREGS
150 #define MONO_ARCH_CALLEE_XREGS MONO_ARCH_CALLEE_FREGS
151 #define MONO_ARCH_CALLEE_SAVED_XREGS MONO_ARCH_CALLEE_SAVED_FREGS
154 #define MONO_ARCH_CALLEE_REGS AMD64_CALLEE_REGS
155 #define MONO_ARCH_CALLEE_SAVED_REGS AMD64_CALLEE_SAVED_REGS
157 #define MONO_ARCH_USE_FPSTACK FALSE
158 #define MONO_ARCH_FPSTACK_SIZE 0
160 #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)))))))
162 /* RDX is clobbered by the opcode implementation before accessing sreg2 */
163 #define MONO_ARCH_INST_SREG2_MASK(ins) (((ins [MONO_INST_CLOB] == 'a') || (ins [MONO_INST_CLOB] == 'd')) ? (1 << AMD64_RDX) : 0)
165 #define MONO_ARCH_INST_IS_REGPAIR(desc) FALSE
166 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (-1)
168 #define MONO_ARCH_FRAME_ALIGNMENT 16
170 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get
171 * reproduceable results for benchmarks */
172 #define MONO_ARCH_CODE_ALIGNMENT 32
174 /*This is the max size of the locals area of a given frame. I think 1MB is a safe default for now*/
175 #define MONO_ARCH_MAX_FRAME_SIZE 0x100000
179 * If the lowest bit is set, then this LMF has the rip field set. Otherwise,
180 * the rip field is not set, and the rsp field points to the stack location where
181 * the caller ip is saved.
182 * If the second lowest bit is set, then this is a MonoLMFExt structure, and
183 * the other fields are not valid.
184 * If the third lowest bit is set, then this is a MonoLMFTramp structure, and
185 * the 'rbp' field is not valid.
187 gpointer previous_lmf;
193 /* LMF structure used by the JIT trampolines */
200 typedef struct MonoCompileArch {
201 gint32 localloc_offset;
202 gint32 reg_save_area_offset;
203 gint32 stack_alloc_size;
206 gboolean omit_fp, omit_fp_computed;
208 gint32 async_point_count;
209 gpointer vret_addr_loc;
213 gpointer seq_point_info_var;
214 gpointer ss_trigger_page_var;
215 gpointer ss_tramp_var;
216 gpointer bp_tramp_var;
222 static AMD64_Reg_No param_regs [] = { AMD64_RCX, AMD64_RDX, AMD64_R8, AMD64_R9 };
224 static AMD64_XMM_Reg_No float_param_regs [] = { AMD64_XMM0, AMD64_XMM1, AMD64_XMM2, AMD64_XMM3 };
226 static AMD64_Reg_No return_regs [] = { AMD64_RAX };
228 static AMD64_XMM_Reg_No float_return_regs [] = { AMD64_XMM0 };
230 #define PARAM_REGS G_N_ELEMENTS(param_regs)
231 #define FLOAT_PARAM_REGS G_N_ELEMENTS(float_param_regs)
232 #define RETURN_REGS G_N_ELEMENTS(return_regs)
233 #define FLOAT_RETURN_REGS G_N_ELEMENTS(float_return_regs)
237 #define FLOAT_PARAM_REGS 8
239 static AMD64_Reg_No param_regs [] = { AMD64_RDI, AMD64_RSI, AMD64_RDX, AMD64_RCX, AMD64_R8, AMD64_R9 };
241 static AMD64_Reg_No return_regs [] = { AMD64_RAX, AMD64_RDX };
245 /* Method address to call */
247 /* The trampoline reads this, so keep the size explicit */
249 /* If ret_marshal != NONE, this is the reg of the vret arg, else -1 (used in out case) */
250 /* Equivalent of vret_arg_slot in the x86 implementation. */
252 /* The stack slot where the return value will be stored (used in in case) */
254 int stack_usage, map_count;
255 /* If not -1, then make a virtual call using this vtable offset */
257 /* If 1, make an indirect call to the address in the rgctx reg */
259 /* Whenever this is a in or an out call */
261 /* Maps stack slots/registers in the caller to the stack slots/registers in the callee */
262 int map [MONO_ZERO_LEN_ARRAY];
265 /* Structure used by the sequence points in AOTed code */
267 gpointer ss_tramp_addr;
268 gpointer bp_addrs [MONO_ZERO_LEN_ARRAY];
271 #define DYN_CALL_STACK_ARGS 6
274 mgreg_t regs [PARAM_REGS + DYN_CALL_STACK_ARGS];
288 ArgValuetypeAddrInIReg,
289 ArgValuetypeAddrOnStack,
290 /* gsharedvt argument passed by addr */
293 /* Variable sized gsharedvt argument passed/returned by addr */
294 ArgGsharedvtVariableInReg,
295 ArgNone /* only in pair_storage */
301 ArgStorage storage : 8;
303 /* Only if storage == ArgValuetypeInReg */
304 ArgStorage pair_storage [2];
306 /* The size of each pair (bytes) */
309 /* Only if storage == ArgOnStack */
310 int arg_size; // Bytes, will always be rounded up/aligned to 8 byte boundary
311 guint8 pass_empty_struct : 1; // Set in scenarios when empty structs needs to be represented as argument.
319 gboolean need_stack_align;
321 /* The index of the vret arg in the argument list */
329 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->gregs [AMD64_RAX] = (gsize)exc; } while (0)
330 #define MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG(ctx, sel) do { (ctx)->gregs [AMD64_RDX] = (gsize)(sel); } while (0)
332 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
336 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx, start_func) do { \
338 mono_arch_flush_register_windows (); \
339 stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));\
340 MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
341 MONO_CONTEXT_SET_BP ((ctx), stackptr); \
342 MONO_CONTEXT_SET_SP ((ctx), stackptr); \
348 * __builtin_frame_address () is broken on some older gcc versions in the presence of
349 * frame pointer elimination, see bug #82095.
351 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do { \
353 guint64 stackptr = (guint64)&tmp; \
354 mono_arch_flush_register_windows (); \
355 MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
356 MONO_CONTEXT_SET_BP ((ctx), stackptr); \
357 MONO_CONTEXT_SET_SP ((ctx), stackptr); \
363 * some icalls like mono_array_new_va needs to be called using a different
364 * calling convention.
366 #define MONO_ARCH_VARARG_ICALLS 1
368 #if !defined( HOST_WIN32 ) && defined (HAVE_SIGACTION)
370 #define MONO_ARCH_USE_SIGACTION 1
372 #ifdef HAVE_WORKING_SIGALTSTACK
374 #define MONO_ARCH_SIGSEGV_ON_ALTSTACK
378 #endif /* !HOST_WIN32 */
380 #if !defined(__linux__)
381 #define MONO_ARCH_NOMAP32BIT 1
385 #define MONO_AMD64_ARG_REG1 AMD64_RCX
386 #define MONO_AMD64_ARG_REG2 AMD64_RDX
387 #define MONO_AMD64_ARG_REG3 AMD64_R8
388 #define MONO_AMD64_ARG_REG4 AMD64_R9
390 #define MONO_AMD64_ARG_REG1 AMD64_RDI
391 #define MONO_AMD64_ARG_REG2 AMD64_RSI
392 #define MONO_AMD64_ARG_REG3 AMD64_RDX
393 #define MONO_AMD64_ARG_REG4 AMD64_RCX
396 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
397 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
399 #define MONO_ARCH_EMULATE_CONV_R8_UN 1
400 #define MONO_ARCH_EMULATE_FREM 1
401 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
402 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
403 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
404 #define MONO_ARCH_IMT_REG AMD64_R10
405 #define MONO_ARCH_IMT_SCRATCH_REG AMD64_R11
406 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
408 * We use r10 for the imt/rgctx register rather than r11 because r11 is
409 * used by the trampoline as a scratch register and hence might be
410 * clobbered across method call boundaries.
412 #define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG
413 #define MONO_ARCH_EXC_REG AMD64_RAX
414 #define MONO_ARCH_HAVE_CMOV_OPS 1
415 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
416 #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE 1
417 #define MONO_ARCH_HAVE_LIVERANGE_OPS 1
418 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
419 #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
421 #define MONO_ARCH_AOT_SUPPORTED 1
422 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
424 #define MONO_ARCH_SUPPORT_TASKLETS 1
426 #define MONO_ARCH_GSHARED_SUPPORTED 1
427 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
428 #define MONO_ARCH_DYN_CALL_PARAM_AREA (DYN_CALL_STACK_ARGS * 8)
430 #define MONO_ARCH_LLVM_SUPPORTED 1
431 #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD 1
432 #define MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD_AOT 1
433 #define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER 1
434 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
435 #define MONO_ARCH_GC_MAPS_SUPPORTED 1
436 #define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
437 #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
438 #define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1
439 #define MONO_ARCH_HAVE_OP_TAIL_CALL 1
440 #define MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET 1
441 #define MONO_ARCH_HAVE_DUMMY_INIT 1
442 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1
443 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
444 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
445 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
447 #if defined(TARGET_OSX) || defined(__linux__)
448 #define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1
451 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1
454 #if defined(TARGET_APPLETVOS)
456 #define MONO_ARCH_NEED_DIV_CHECK 1
459 /* Used for optimization, not complete */
460 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
462 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
464 MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
465 inst->inst_basereg = array_reg; \
466 inst->inst_offset = offset; \
467 inst->sreg2 = index_reg; \
468 MONO_ADD_INS ((cfg)->cbb, inst); \
469 MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
473 mono_amd64_patch (unsigned char* code, gpointer target);
476 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
477 guint64 dummy5, guint64 dummy6,
478 MonoContext *mctx, MonoObject *exc, gboolean rethrow);
481 mono_amd64_throw_corlib_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
482 guint64 dummy5, guint64 dummy6,
483 MonoContext *mctx, guint32 ex_token_index, gint64 pc_offset);
486 mono_amd64_resume_unwind (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
487 guint64 dummy5, guint64 dummy6,
488 MonoContext *mctx, guint32 dummy7, gint64 dummy8);
491 mono_amd64_start_gsharedvt_call (GSharedVtCallInfo *info, gpointer *caller, gpointer *callee, gpointer mrgctx_reg);
494 mono_amd64_get_original_ip (void);
497 mono_amd64_get_exception_trampolines (gboolean aot);
500 mono_amd64_get_tls_gs_offset (void) MONO_LLVM_INTERNAL;
503 mono_amd64_handler_block_trampoline_helper (void);
505 #if defined(TARGET_WIN32) && !defined(DISABLE_JIT)
507 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
508 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
509 #define MONO_ARCH_HAVE_CODE_CHUNK_TRACKING 1
511 #ifdef ENABLE_CHECKED_BUILD
512 #define ENABLE_CHECKED_BUILD_UNWINDINFO
515 #define MONO_MAX_UNWIND_CODES 22
517 typedef enum _UNWIND_OP_CODES {
518 UWOP_PUSH_NONVOL = 0, /* info == register number */
519 UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */
520 UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */
521 UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
522 UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */
523 UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */
524 UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */
525 UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */
526 UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */
529 typedef union _UNWIND_CODE {
536 } UNWIND_CODE, *PUNWIND_CODE;
538 typedef struct _UNWIND_INFO {
543 guchar FrameRegister : 4;
544 guchar FrameOffset : 4;
545 UNWIND_CODE UnwindCode[MONO_MAX_UNWIND_CODES];
546 /* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
548 * OPTIONAL ULONG ExceptionHandler;
549 * OPTIONAL ULONG FunctionEntry;
551 * OPTIONAL ULONG ExceptionData[]; */
552 } UNWIND_INFO, *PUNWIND_INFO;
555 mono_arch_unwindinfo_get_size (guchar code_count)
557 // Returned size will be used as the allocated size for unwind data trailing the memory used by compiled method.
558 // Windows x64 ABI have some requirements on the data written into this memory. Both the RUNTIME_FUNCTION
559 // and UNWIND_INFO struct needs to be DWORD aligned and the number of elements in unwind codes array
560 // should have an even number of entries, while the count stored in UNWIND_INFO struct should hold the real number
561 // of unwind codes. Adding extra bytes to the total size will make sure we can properly align the RUNTIME_FUNCTION
562 // struct. Since our UNWIND_INFO follows RUNTIME_FUNCTION struct in memory, it will automatically be DWORD aligned
563 // as well. Also make sure to allocate room for a padding UNWIND_CODE, if needed.
564 return (sizeof (mgreg_t) + sizeof (UNWIND_INFO)) -
565 (sizeof (UNWIND_CODE) * ((MONO_MAX_UNWIND_CODES - ((code_count + 1) & ~1))));
569 mono_arch_unwindinfo_get_code_count (GSList *unwind_ops);
572 mono_arch_unwindinfo_init_method_unwind_info (gpointer cfg);
575 mono_arch_unwindinfo_install_method_unwind_info (gpointer *monoui, gpointer code, guint code_size);
578 mono_arch_unwindinfo_install_tramp_unwind_info (GSList *unwind_ops, gpointer code, guint code_size);
581 mono_arch_code_chunk_new (void *chunk, int size);
584 mono_arch_code_chunk_destroy (void *chunk);
586 #endif /* G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) */
587 #endif /* defined(TARGET_WIN32) && !defined(DISABLE_JIT) */
589 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
590 // Allocate additional size for max 3 unwind ops (push + fp or sp small|large) + unwind info struct trailing code buffer.
591 #define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) (mono_arch_unwindinfo_get_size (max_code_count))
592 #define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE (MONO_TRAMPOLINE_UNWINDINFO_SIZE(3))
595 mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
597 guint current_size = mono_arch_unwindinfo_get_size (mono_arch_unwindinfo_get_code_count (unwind_ops));
598 return current_size <= max_size;
603 #define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) 0
604 #define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE 0
607 mono_arch_unwindinfo_validate_size (GSList *unwind_ops, guint max_size)
613 CallInfo* mono_arch_get_call_info (MonoMemPool *mp, MonoMethodSignature *sig);
615 #endif /* __MONO_MINI_AMD64_H__ */