5 #ifndef __MONO_MINI_AMD64_H__
6 #define __MONO_MINI_AMD64_H__
8 #include <mono/arch/amd64/amd64-codegen.h>
9 #include <mono/utils/mono-sigcontext.h>
10 #include <mono/utils/mono-context.h>
15 /* use SIG* defines if possible */
20 #if !defined(_MSC_VER)
21 /* sigcontext surrogate */
35 typedef void MONO_SIG_HANDLER_SIGNATURE ((*MonoW32ExceptionHandler
));
36 void win32_seh_init(void);
37 void win32_seh_cleanup(void);
38 void win32_seh_set_handler(int type
, MonoW32ExceptionHandler handler
);
52 LONG CALLBACK
seh_handler(EXCEPTION_POINTERS
* ep
);
59 PRUNTIME_FUNCTION rt_funcs
;
60 DWORD rt_funcs_current_count
;
61 DWORD rt_funcs_max_count
;
62 } DynamicFunctionTableEntry
;
64 #define MONO_UNWIND_INFO_RT_FUNC_SIZE 128
66 typedef BOOLEAN (WINAPI
* RtlInstallFunctionTableCallbackPtr
)(
67 DWORD64 TableIdentifier
,
70 PGET_RUNTIME_FUNCTION_CALLBACK Callback
,
72 PCWSTR OutOfProcessCallbackDll
);
74 typedef BOOLEAN (WINAPI
* RtlDeleteFunctionTablePtr
)(
75 PRUNTIME_FUNCTION FunctionTable
);
77 // On Win8/Win2012Server and later we can use dynamic growable function tables
78 // instead of RtlInstallFunctionTableCallback. This gives us the benefit to
79 // include all needed unwind upon registration.
80 typedef DWORD (NTAPI
* RtlAddGrowableFunctionTablePtr
)(
82 PRUNTIME_FUNCTION FunctionTable
,
84 DWORD MaximumEntryCount
,
88 typedef VOID (NTAPI
* RtlGrowFunctionTablePtr
)(
92 typedef VOID (NTAPI
* RtlDeleteGrowableFunctionTablePtr
)(
95 #endif /* HOST_WIN32 */
97 #ifdef sun // Solaris x86
98 # undef SIGSEGV_ON_ALTSTACK
99 # define MONO_ARCH_NOMAP32BIT
102 unsigned short gs
, __gsh
;
103 unsigned short fs
, __fsh
;
104 unsigned short es
, __esh
;
105 unsigned short ds
, __dsh
;
114 unsigned long trapno
;
117 unsigned short cs
, __csh
;
118 unsigned long eflags
;
119 unsigned long esp_at_signal
;
120 unsigned short ss
, __ssh
;
121 unsigned long fpstate
[95];
122 unsigned long filler
[5];
124 #endif // sun, Solaris x86
127 #define MONO_ARCH_SIMD_INTRINSICS 1
128 #define MONO_ARCH_NEED_SIMD_BANK 1
129 #define MONO_ARCH_USE_SHARED_FP_SIMD_BANK 1
134 #if defined(__APPLE__)
135 #define MONO_ARCH_SIGNAL_STACK_SIZE MINSIGSTKSZ
137 #define MONO_ARCH_SIGNAL_STACK_SIZE (16 * 1024)
140 #define MONO_ARCH_CPU_SPEC mono_amd64_desc
142 #define MONO_MAX_IREGS 16
144 #define MONO_MAX_FREGS AMD64_XMM_NREG
146 #define MONO_ARCH_FP_RETURN_REG AMD64_XMM0
149 /* xmm5 is used as a scratch register */
150 #define MONO_ARCH_CALLEE_FREGS 0x1f
152 #define MONO_ARCH_CALLEE_SAVED_FREGS (0xffff - 0x3f)
153 #define MONO_ARCH_FP_SCRATCH_REG AMD64_XMM5
155 /* xmm15 is used as a scratch register */
156 #define MONO_ARCH_CALLEE_FREGS 0x7fff
157 #define MONO_ARCH_CALLEE_SAVED_FREGS 0
158 #define MONO_ARCH_FP_SCRATCH_REG AMD64_XMM15
161 #define MONO_MAX_XREGS MONO_MAX_FREGS
163 #define MONO_ARCH_CALLEE_XREGS MONO_ARCH_CALLEE_FREGS
164 #define MONO_ARCH_CALLEE_SAVED_XREGS MONO_ARCH_CALLEE_SAVED_FREGS
167 #define MONO_ARCH_CALLEE_REGS AMD64_CALLEE_REGS
168 #define MONO_ARCH_CALLEE_SAVED_REGS AMD64_CALLEE_SAVED_REGS
170 #define MONO_ARCH_USE_FPSTACK FALSE
172 #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)))))))
174 /* RDX is clobbered by the opcode implementation before accessing sreg2 */
175 #define MONO_ARCH_INST_SREG2_MASK(ins) (((ins [MONO_INST_CLOB] == 'a') || (ins [MONO_INST_CLOB] == 'd')) ? (1 << AMD64_RDX) : 0)
177 #define MONO_ARCH_INST_IS_REGPAIR(desc) FALSE
178 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (-1)
180 #define MONO_ARCH_FRAME_ALIGNMENT 16
182 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get
183 * reproduceable results for benchmarks */
184 #define MONO_ARCH_CODE_ALIGNMENT 32
188 * The rsp field points to the stack location where the caller ip is saved.
189 * If the second lowest bit is set, then this is a MonoLMFExt structure, and
190 * the other fields are not valid.
191 * If the third lowest bit is set, then this is a MonoLMFTramp structure, and
192 * the 'rbp' field is not valid.
194 gpointer previous_lmf
;
199 /* LMF structure used by the JIT trampolines */
206 typedef struct MonoCompileArch
{
207 gint32 localloc_offset
;
208 gint32 reg_save_area_offset
;
209 gint32 stack_alloc_size
;
213 gboolean omit_fp_computed
;
215 gint32 async_point_count
;
216 MonoInst
*vret_addr_loc
;
217 MonoInst
*seq_point_info_var
;
218 MonoInst
*ss_tramp_var
;
219 MonoInst
*bp_tramp_var
;
222 struct _UNWIND_INFO
* unwindinfo
;
228 static const AMD64_Reg_No param_regs
[] = { AMD64_RCX
, AMD64_RDX
, AMD64_R8
, AMD64_R9
};
230 static const AMD64_XMM_Reg_No float_param_regs
[] = { AMD64_XMM0
, AMD64_XMM1
, AMD64_XMM2
, AMD64_XMM3
};
232 static const AMD64_Reg_No return_regs
[] = { AMD64_RAX
};
234 static const AMD64_XMM_Reg_No float_return_regs
[] = { AMD64_XMM0
};
236 #define PARAM_REGS G_N_ELEMENTS(param_regs)
237 #define FLOAT_PARAM_REGS G_N_ELEMENTS(float_param_regs)
238 #define RETURN_REGS G_N_ELEMENTS(return_regs)
239 #define FLOAT_RETURN_REGS G_N_ELEMENTS(float_return_regs)
243 #define FLOAT_PARAM_REGS 8
244 #define RETURN_REGS 2
245 #define FLOAT_RETURN_REGS 2
247 static const AMD64_Reg_No param_regs
[] = {AMD64_RDI
, AMD64_RSI
, AMD64_RDX
,
248 AMD64_RCX
, AMD64_R8
, AMD64_R9
};
250 static const AMD64_XMM_Reg_No float_param_regs
[] = {AMD64_XMM0
, AMD64_XMM1
, AMD64_XMM2
,
251 AMD64_XMM3
, AMD64_XMM4
, AMD64_XMM5
,
252 AMD64_XMM6
, AMD64_XMM7
};
254 static const AMD64_Reg_No return_regs
[] = {AMD64_RAX
, AMD64_RDX
};
258 /* Method address to call */
260 /* The trampoline reads this, so keep the size explicit */
262 /* If ret_marshal != NONE, this is the reg of the vret arg, else -1 (used in out case) */
263 /* Equivalent of vret_arg_slot in the x86 implementation. */
265 /* The stack slot where the return value will be stored (used in in case) */
267 int stack_usage
, map_count
;
268 /* If not -1, then make a virtual call using this vtable offset */
270 /* If 1, make an indirect call to the address in the rgctx reg */
272 /* Whenever this is a in or an out call */
274 /* Maps stack slots/registers in the caller to the stack slots/registers in the callee */
275 int map
[MONO_ZERO_LEN_ARRAY
];
278 /* Structure used by the sequence points in AOTed code */
279 struct SeqPointInfo
{
280 gpointer ss_tramp_addr
;
281 gpointer bp_addrs
[MONO_ZERO_LEN_ARRAY
];
289 host_mgreg_t nstack_args
;
290 /* This should come last as the structure is dynamically extended */
291 host_mgreg_t regs
[PARAM_REGS
];
300 ArgValuetypeAddrInIReg
,
301 ArgValuetypeAddrOnStack
,
302 /* gsharedvt argument passed by addr */
305 /* Variable sized gsharedvt argument passed/returned by addr */
306 ArgGsharedvtVariableInReg
,
307 ArgNone
/* only in pair_storage */
313 ArgStorage storage
: 8;
315 /* Only if storage == ArgValuetypeInReg */
316 ArgStorage pair_storage
[2];
318 /* The size of each pair (bytes) */
321 /* Only if storage == ArgOnStack */
322 int arg_size
; // Bytes, will always be rounded up/aligned to 8 byte boundary
323 // Size in bytes for small arguments
325 guint8 pass_empty_struct
: 1; // Set in scenarios when empty structs needs to be represented as argument.
333 gboolean need_stack_align
;
335 /* The index of the vret arg in the argument list */
343 /* General registers */
344 host_mgreg_t gregs
[AMD64_NREG
];
345 /* Floating registers */
346 double fregs
[AMD64_XMM_NREG
];
347 /* Stack usage, used for passing params on stack */
352 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->gregs [AMD64_RAX] = (gsize)exc; } while (0)
353 #define MONO_CONTEXT_SET_LLVM_EH_SELECTOR_REG(ctx, sel) do { (ctx)->gregs [AMD64_RDX] = (gsize)(sel); } while (0)
355 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
359 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx, start_func) do { \
361 stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));\
362 MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
363 MONO_CONTEXT_SET_BP ((ctx), stackptr); \
364 MONO_CONTEXT_SET_SP ((ctx), stackptr); \
370 * __builtin_frame_address () is broken on some older gcc versions in the presence of
371 * frame pointer elimination, see bug #82095.
373 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do { \
375 guint64 stackptr = (guint64)&tmp; \
376 MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
377 MONO_CONTEXT_SET_BP ((ctx), stackptr); \
378 MONO_CONTEXT_SET_SP ((ctx), stackptr); \
383 #if !defined( HOST_WIN32 ) && !defined(__HAIKU__) && defined (HAVE_SIGACTION)
385 #define MONO_ARCH_USE_SIGACTION 1
387 #ifdef HAVE_WORKING_SIGALTSTACK
389 #define MONO_ARCH_SIGSEGV_ON_ALTSTACK
393 #endif /* !HOST_WIN32 */
395 #if !defined(__linux__)
396 #define MONO_ARCH_NOMAP32BIT 1
400 #define MONO_AMD64_ARG_REG1 AMD64_RCX
401 #define MONO_AMD64_ARG_REG2 AMD64_RDX
402 #define MONO_AMD64_ARG_REG3 AMD64_R8
403 #define MONO_AMD64_ARG_REG4 AMD64_R9
405 #define MONO_AMD64_ARG_REG1 AMD64_RDI
406 #define MONO_AMD64_ARG_REG2 AMD64_RSI
407 #define MONO_AMD64_ARG_REG3 AMD64_RDX
408 #define MONO_AMD64_ARG_REG4 AMD64_RCX
411 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
412 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
414 #define MONO_ARCH_EMULATE_CONV_R8_UN 1
415 #define MONO_ARCH_EMULATE_FREM 1
416 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
417 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
418 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
419 #define MONO_ARCH_IMT_REG AMD64_R10
420 #define MONO_ARCH_IMT_SCRATCH_REG AMD64_R11
421 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
423 * We use r10 for the imt/rgctx register rather than r11 because r11 is
424 * used by the trampoline as a scratch register and hence might be
425 * clobbered across method call boundaries.
427 #define MONO_ARCH_RGCTX_REG MONO_ARCH_IMT_REG
428 #define MONO_ARCH_HAVE_CMOV_OPS 1
429 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
430 #define MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE 1
431 #define MONO_ARCH_HAVE_GET_TRAMPOLINES 1
433 #define MONO_ARCH_INTERPRETER_SUPPORTED 1
434 #define MONO_ARCH_AOT_SUPPORTED 1
435 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
437 #define MONO_ARCH_SUPPORT_TASKLETS 1
439 #define MONO_ARCH_GSHARED_SUPPORTED 1
440 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
441 #define MONO_ARCH_DYN_CALL_PARAM_AREA 0
443 #define MONO_ARCH_LLVM_SUPPORTED 1
444 #if defined(HOST_WIN32) && defined(TARGET_WIN32) && !defined(_MSC_VER)
445 // Only supported for Windows cross compiler builds, host == Win32, target != Win32
446 // and only using MSVC for none cross compiler builds.
447 #undef MONO_ARCH_LLVM_SUPPORTED
450 #define MONO_ARCH_HAVE_CARD_TABLE_WBARRIER 1
451 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1
452 #define MONO_ARCH_GC_MAPS_SUPPORTED 1
453 #define MONO_ARCH_HAVE_CONTEXT_SET_INT_REG 1
454 #define MONO_ARCH_HAVE_SETUP_ASYNC_CALLBACK 1
455 #define MONO_ARCH_HAVE_CREATE_LLVM_NATIVE_THUNK 1
456 #define MONO_ARCH_HAVE_OP_TAILCALL_MEMBASE 1
457 #define MONO_ARCH_HAVE_OP_TAILCALL_REG 1
458 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1
459 #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1
460 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1
461 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1
462 #define MONO_ARCH_FLOAT32_SUPPORTED 1
463 #define MONO_ARCH_LLVM_TARGET_LAYOUT "e-i64:64-i128:128-n8:16:32:64-S128"
465 #define MONO_ARCH_HAVE_INTERP_PINVOKE_TRAMP
466 #define MONO_ARCH_HAVE_INTERP_ENTRY_TRAMPOLINE 1
467 #define MONO_ARCH_HAVE_INTERP_NATIVE_TO_MANAGED 1
469 #if defined(TARGET_OSX) || defined(__linux__)
470 #define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1
473 #define MONO_ARCH_GSHAREDVT_SUPPORTED 1
476 #if defined(HOST_TVOS)
478 #define MONO_ARCH_NEED_DIV_CHECK 1
481 /* Used for optimization, not complete */
482 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
484 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
486 MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
487 inst->inst_basereg = array_reg; \
488 inst->inst_offset = offset; \
489 inst->sreg2 = index_reg; \
490 MONO_ADD_INS ((cfg)->cbb, inst); \
491 MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
494 // Does the ABI have a volatile non-parameter register, so tailcall
495 // can pass context to generics or interfaces?
496 #define MONO_ARCH_HAVE_VOLATILE_NON_PARAM_REGISTER 1
499 mono_amd64_patch (unsigned char* code
, gpointer target
);
502 mono_amd64_throw_exception (guint64 dummy1
, guint64 dummy2
, guint64 dummy3
, guint64 dummy4
,
503 guint64 dummy5
, guint64 dummy6
,
504 MonoContext
*mctx
, MonoObject
*exc
, gboolean rethrow
, gboolean preserve_ips
);
507 mono_amd64_throw_corlib_exception (guint64 dummy1
, guint64 dummy2
, guint64 dummy3
, guint64 dummy4
,
508 guint64 dummy5
, guint64 dummy6
,
509 MonoContext
*mctx
, guint32 ex_token_index
, gint64 pc_offset
);
512 mono_amd64_resume_unwind (guint64 dummy1
, guint64 dummy2
, guint64 dummy3
, guint64 dummy4
,
513 guint64 dummy5
, guint64 dummy6
,
514 MonoContext
*mctx
, guint32 dummy7
, gint64 dummy8
);
517 mono_amd64_start_gsharedvt_call (GSharedVtCallInfo
*info
, gpointer
*caller
, gpointer
*callee
, gpointer mrgctx_reg
);
520 mono_amd64_get_exception_trampolines (gboolean aot
);
523 mono_amd64_get_tls_gs_offset (void) MONO_LLVM_INTERNAL
;
525 #if defined(TARGET_WIN32) && !defined(DISABLE_JIT)
527 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
528 #define MONO_ARCH_HAVE_CODE_CHUNK_TRACKING 1
530 #ifdef ENABLE_CHECKED_BUILD
531 #define ENABLE_CHECKED_BUILD_UNWINDINFO
534 #define MONO_MAX_UNWIND_CODES 22
536 typedef enum _UNWIND_OP_CODES
{
537 UWOP_PUSH_NONVOL
= 0, /* info == register number */
538 UWOP_ALLOC_LARGE
, /* no info, alloc size in next 2 slots */
539 UWOP_ALLOC_SMALL
, /* info == size of allocation / 8 - 1 */
540 UWOP_SET_FPREG
, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
541 UWOP_SAVE_NONVOL
, /* info == register number, offset in next slot */
542 UWOP_SAVE_NONVOL_FAR
, /* info == register number, offset in next 2 slots */
543 UWOP_SAVE_XMM128
, /* info == XMM reg number, offset in next slot */
544 UWOP_SAVE_XMM128_FAR
, /* info == XMM reg number, offset in next 2 slots */
545 UWOP_PUSH_MACHFRAME
/* info == 0: no error-code, 1: error-code */
548 typedef union _UNWIND_CODE
{
555 } UNWIND_CODE
, *PUNWIND_CODE
;
557 typedef struct _UNWIND_INFO
{
562 guchar FrameRegister
: 4;
563 guchar FrameOffset
: 4;
564 UNWIND_CODE UnwindCode
[MONO_MAX_UNWIND_CODES
];
565 /* UNWIND_CODE MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
567 * OPTIONAL ULONG ExceptionHandler;
568 * OPTIONAL ULONG FunctionEntry;
570 * OPTIONAL ULONG ExceptionData[]; */
571 } UNWIND_INFO
, *PUNWIND_INFO
;
574 mono_arch_unwindinfo_get_size (guchar code_count
)
576 // Returned size will be used as the allocated size for unwind data trailing the memory used by compiled method.
577 // Windows x64 ABI have some requirements on the data written into this memory. Both the RUNTIME_FUNCTION
578 // and UNWIND_INFO struct needs to be DWORD aligned and the number of elements in unwind codes array
579 // should have an even number of entries, while the count stored in UNWIND_INFO struct should hold the real number
580 // of unwind codes. Adding extra bytes to the total size will make sure we can properly align the RUNTIME_FUNCTION
581 // struct. Since our UNWIND_INFO follows RUNTIME_FUNCTION struct in memory, it will automatically be DWORD aligned
582 // as well. Also make sure to allocate room for a padding UNWIND_CODE, if needed.
583 return (sizeof (target_mgreg_t
) + sizeof (UNWIND_INFO
)) -
584 (sizeof (UNWIND_CODE
) * ((MONO_MAX_UNWIND_CODES
- ((code_count
+ 1) & ~1))));
585 /* FIXME Something simpler should work:
586 return sizeof (UNWIND_INFO) + sizeof (UNWIND_CODE) * (code_count + (code_count & 1));
591 mono_arch_unwindinfo_get_code_count (GSList
*unwind_ops
);
594 mono_arch_unwindinfo_alloc_unwind_info (GSList
*unwind_ops
);
597 mono_arch_unwindinfo_free_unwind_info (PUNWIND_INFO unwind_info
);
600 mono_arch_unwindinfo_init_method_unwind_info (gpointer cfg
);
603 mono_arch_unwindinfo_install_method_unwind_info (PUNWIND_INFO
*monoui
, gpointer code
, guint code_size
);
606 mono_arch_unwindinfo_install_tramp_unwind_info (GSList
*unwind_ops
, gpointer code
, guint code_size
);
609 mono_arch_code_chunk_new (void *chunk
, int size
);
612 mono_arch_code_chunk_destroy (void *chunk
);
614 #endif /* defined(TARGET_WIN32) && !defined(DISABLE_JIT) */
616 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
617 // Allocate additional size for max 3 unwind ops (push + fp or sp small|large) + unwind info struct trailing code buffer.
618 #define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) (mono_arch_unwindinfo_get_size (max_code_count))
619 #define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE (MONO_TRAMPOLINE_UNWINDINFO_SIZE(3))
621 static inline gboolean
622 mono_arch_unwindinfo_validate_size (GSList
*unwind_ops
, guint max_size
)
624 guint current_size
= mono_arch_unwindinfo_get_size (mono_arch_unwindinfo_get_code_count (unwind_ops
));
625 return current_size
<= max_size
;
630 #define MONO_TRAMPOLINE_UNWINDINFO_SIZE(max_code_count) 0
631 #define MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE 0
633 static inline gboolean
634 mono_arch_unwindinfo_validate_size (GSList
*unwind_ops
, guint max_size
)
640 CallInfo
* mono_arch_get_call_info (MonoMemPool
*mp
, MonoMethodSignature
*sig
);
642 #endif /* __MONO_MINI_AMD64_H__ */