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