2009-12-13 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-amd64.h
1 #ifndef __MONO_MINI_AMD64_H__
2 #define __MONO_MINI_AMD64_H__
3
4 #include <mono/arch/amd64/amd64-codegen.h>
5 #include <mono/utils/mono-sigcontext.h>
6 #include <glib.h>
7
8 #ifdef HOST_WIN32
9 #include <windows.h>
10 /* use SIG* defines if possible */
11 #ifdef HAVE_SIGNAL_H
12 #include <signal.h>
13 #endif
14
15
16 /* sigcontext surrogate */
17 struct sigcontext {
18         guint64 eax;
19         guint64 ebx;
20         guint64 ecx;
21         guint64 edx;
22         guint64 ebp;
23         guint64 esp;
24     guint64 esi;
25         guint64 edi;
26         guint64 eip;
27 };
28
29 typedef void (* MonoW32ExceptionHandler) (int _dummy, EXCEPTION_RECORD *info, void *context);
30 void win32_seh_init(void);
31 void win32_seh_cleanup(void);
32 void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler);
33
34 #ifndef SIGFPE
35 #define SIGFPE 4
36 #endif
37
38 #ifndef SIGILL
39 #define SIGILL 8
40 #endif
41
42 #ifndef SIGSEGV
43 #define SIGSEGV 11
44 #endif
45
46 LONG CALLBACK seh_handler(EXCEPTION_POINTERS* ep);
47
48 #endif /* HOST_WIN32 */
49
50 #ifdef sun    // Solaris x86
51 #  undef SIGSEGV_ON_ALTSTACK
52 #  define MONO_ARCH_NOMAP32BIT
53
54 struct sigcontext {
55         unsigned short gs, __gsh;
56         unsigned short fs, __fsh;
57         unsigned short es, __esh;
58         unsigned short ds, __dsh;
59         unsigned long edi;
60         unsigned long esi;
61         unsigned long ebp;
62         unsigned long esp;
63         unsigned long ebx;
64         unsigned long edx;
65         unsigned long ecx;
66         unsigned long eax;
67         unsigned long trapno;
68         unsigned long err;
69         unsigned long eip;
70         unsigned short cs, __csh;
71         unsigned long eflags;
72         unsigned long esp_at_signal;
73         unsigned short ss, __ssh;
74         unsigned long fpstate[95];
75       unsigned long filler[5];
76 };
77 #endif  // sun, Solaris x86
78
79 #define MONO_ARCH_SUPPORT_SIMD_INTRINSICS 1
80
81 #ifndef DISABLE_SIMD
82 #define MONO_ARCH_SIMD_INTRINSICS 1
83 #define MONO_ARCH_NEED_SIMD_BANK 1
84 #define MONO_ARCH_USE_SHARED_FP_SIMD_BANK 1
85 #endif
86
87
88
89 #define MONO_ARCH_SIGNAL_STACK_SIZE (16 * 1024)
90
91 #define MONO_ARCH_HAVE_RESTORE_STACK_SUPPORT 1
92
93 #define MONO_ARCH_CPU_SPEC amd64_desc
94
95 #define MONO_MAX_IREGS 16
96
97 #define MONO_MAX_FREGS AMD64_XMM_NREG
98
99 #define MONO_ARCH_FP_RETURN_REG AMD64_XMM0
100
101 /* xmm15 is reserved for use by some opcodes */
102 #define MONO_ARCH_CALLEE_FREGS 0x7fff
103 #define MONO_ARCH_CALLEE_SAVED_FREGS 0
104
105 #define MONO_MAX_XREGS MONO_MAX_FREGS
106
107 #define MONO_ARCH_CALLEE_XREGS 0x7fff
108 #define MONO_ARCH_CALLEE_SAVED_XREGS 0
109
110
111 #define MONO_ARCH_CALLEE_REGS AMD64_CALLEE_REGS
112 #define MONO_ARCH_CALLEE_SAVED_REGS AMD64_CALLEE_SAVED_REGS
113
114 #define MONO_ARCH_USE_FPSTACK FALSE
115 #define MONO_ARCH_FPSTACK_SIZE 0
116
117 #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 : -1))))))
118
119 /* RDX is clobbered by the opcode implementation before accessing sreg2 */
120 #define MONO_ARCH_INST_SREG2_MASK(ins) (((ins [MONO_INST_CLOB] == 'a') || (ins [MONO_INST_CLOB] == 'd')) ? (1 << AMD64_RDX) : 0)
121
122 #define MONO_ARCH_INST_IS_REGPAIR(desc) FALSE
123 #define MONO_ARCH_INST_REGPAIR_REG2(desc,hreg1) (-1)
124
125 #define MONO_ARCH_FRAME_ALIGNMENT 16
126
127 /* fixme: align to 16byte instead of 32byte (we align to 32byte to get 
128  * reproduceable results for benchmarks */
129 #define MONO_ARCH_CODE_ALIGNMENT 32
130
131 #define MONO_ARCH_RETREG1 X86_EAX
132 #define MONO_ARCH_RETREG2 X86_EDX
133
134 struct MonoLMF {
135         /* 
136          * If the lowest bit is set to 1, then this LMF has the rip field set. Otherwise,
137          * the rip field is not set, and the rsp field points to the stack location where
138          * the caller ip is saved.
139          * If the second lowest bit is set to 1, then this is a MonoLMFExt structure, and
140          * the other fields are not valid.
141          */
142         gpointer    previous_lmf;
143         gpointer    lmf_addr;
144         /* This is only set in trampoline LMF frames */
145         MonoMethod *method;
146         guint64     rip;
147         guint64     rbx;
148         guint64     rbp;
149         guint64     rsp;
150         guint64     r12;
151         guint64     r13;
152         guint64     r14;
153         guint64     r15;
154 #ifdef PLATFORM_WIN32
155         guint64     rdi;
156         guint64     rsi;
157 #endif
158 };
159
160 typedef struct MonoCompileArch {
161         gint32 lmf_offset;
162         gint32 localloc_offset;
163         gint32 reg_save_area_offset;
164         gint32 stack_alloc_size;
165         gboolean omit_fp, omit_fp_computed, no_pushes;
166         gpointer cinfo;
167         gint32 async_point_count;
168         gpointer vret_addr_loc;
169 #ifdef PLATFORM_WIN32
170         gpointer        unwindinfo;
171 #endif
172 } MonoCompileArch;
173
174 typedef struct {
175         guint64 rax;
176         guint64 rbx;
177         guint64 rcx;
178         guint64 rdx;
179         guint64 rbp;
180         guint64 rsp;
181     guint64 rsi;
182         guint64 rdi;
183         guint64 rip;
184         guint64 r12;
185         guint64 r13;
186         guint64 r14;
187         guint64 r15;
188 } MonoContext;
189
190 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->rip = (guint64)(ip); } while (0); 
191 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->rbp = (guint64)(bp); } while (0); 
192 #define MONO_CONTEXT_SET_SP(ctx,esp) do { (ctx)->rsp = (guint64)(esp); } while (0); 
193
194 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->rip))
195 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->rbp))
196 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->rsp))
197
198 #define MONO_CONTEXT_SET_LLVM_EXC_REG(ctx, exc) do { (ctx)->rax = (gsize)exc; } while (0)
199
200 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
201
202 #ifdef _MSC_VER
203
204 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx, start_func) do { \
205     guint64 stackptr; \
206         mono_arch_flush_register_windows (); \
207         stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));\
208         MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
209         MONO_CONTEXT_SET_BP ((ctx), stackptr); \
210         MONO_CONTEXT_SET_SP ((ctx), stackptr); \
211 } while (0)
212
213 #else
214
215 /* 
216  * __builtin_frame_address () is broken on some older gcc versions in the presence of
217  * frame pointer elimination, see bug #82095.
218  */
219 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do {        \
220         int tmp; \
221         guint64 stackptr = (guint64)&tmp; \
222                 mono_arch_flush_register_windows ();    \
223                 MONO_CONTEXT_SET_IP ((ctx), (start_func));      \
224                 MONO_CONTEXT_SET_BP ((ctx), stackptr);  \
225                 MONO_CONTEXT_SET_SP ((ctx), stackptr);  \
226         } while (0)
227
228 #endif
229
230 /*
231  * This structure is an extension of MonoLMF and contains extra information.
232  */
233 typedef struct {
234         struct MonoLMF lmf;
235         gboolean debugger_invoke;
236         MonoContext ctx; /* if debugger_invoke is TRUE */
237 } MonoLMFExt;
238
239 /*
240  * some icalls like mono_array_new_va needs to be called using a different 
241  * calling convention.
242  */
243 #define MONO_ARCH_VARARG_ICALLS 1
244
245 #ifndef PLATFORM_WIN32
246
247 #define MONO_ARCH_USE_SIGACTION 1
248
249 #ifdef HAVE_WORKING_SIGALTSTACK
250
251 #define MONO_ARCH_SIGSEGV_ON_ALTSTACK
252
253 #endif
254
255 #ifdef __OpenBSD__
256 #undef MONO_ARCH_USE_SIGACTION
257 #endif
258
259 #endif /* PLATFORM_WIN32 */
260
261 #if defined (__NetBSD__)
262
263 #define REG_RAX 14
264 #define REG_RCX 3
265 #define REG_RDX 2
266 #define REG_RBX 13
267 #define REG_RSP 24
268 #define REG_RBP 12
269 #define REG_RSI 1
270 #define REG_RDI 0
271 #define REG_R8 4
272 #define REG_R9 5
273 #define REG_R10 6
274 #define REG_R11 7
275 #define REG_R12 8
276 #define REG_R13 9
277 #define REG_R14 10
278 #define REG_R15 11
279 #define REG_RIP 21
280
281 #define MONO_ARCH_NOMAP32BIT
282
283 #elif defined (__FreeBSD__) || defined (__OpenBSD__)
284
285 #define REG_RAX 7
286 #define REG_RCX 4
287 #define REG_RDX 3
288 #define REG_RBX 8
289 #define REG_RSP 23
290 #define REG_RBP 9
291 #define REG_RSI 2
292 #define REG_RDI 1
293 #define REG_R8  5
294 #define REG_R9  6
295 #define REG_R10 10
296 #define REG_R11 11
297 #define REG_R12 12
298 #define REG_R13 13
299 #define REG_R14 14
300 #define REG_R15 15
301 #define REG_RIP 20
302
303 /* 
304  * FreeBSD does not have MAP_32BIT, so code allocated by the code manager might not have a
305  * 32 bit address.
306  */
307 #define MONO_ARCH_NOMAP32BIT
308
309 #endif /* __FreeBSD__ */
310
311 #ifdef PLATFORM_WIN32
312 #define MONO_AMD64_ARG_REG1 AMD64_RCX
313 #define MONO_AMD64_ARG_REG2 AMD64_RDX
314 #else
315 #define MONO_AMD64_ARG_REG1 AMD64_RDI
316 #define MONO_AMD64_ARG_REG2 AMD64_RSI
317 #endif
318
319 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
320 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
321
322 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
323 #define MONO_ARCH_EMULATE_FREM 1
324 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
325
326 #define MONO_ARCH_ENABLE_REGALLOC_IN_EH_BLOCKS 1
327 #define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
328 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
329 #define MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION 1
330 #define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
331 #define MONO_ARCH_HAVE_ATOMIC_ADD 1
332 #define MONO_ARCH_HAVE_ATOMIC_EXCHANGE 1
333 #define MONO_ARCH_HAVE_ATOMIC_CAS 1
334 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
335 #define MONO_ARCH_HAVE_IMT 1
336 #define MONO_ARCH_HAVE_TLS_GET 1
337 #define MONO_ARCH_IMT_REG AMD64_R11
338 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
339 /*
340  * We use r10 for the rgctx register rather than r11 because r11 is
341  * used by the trampoline as a scratch register and hence might be
342  * clobbered across method call boundaries.
343  */
344 #define MONO_ARCH_RGCTX_REG AMD64_R10
345 #define MONO_ARCH_HAVE_CMOV_OPS 1
346 #define MONO_ARCH_HAVE_NOTIFY_PENDING_EXC 1
347 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
348 #define MONO_ARCH_ENABLE_GLOBAL_RA 1
349 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
350 #define MONO_ARCH_HAVE_LIVERANGE_OPS 1
351 #define MONO_ARCH_HAVE_XP_UNWIND 1
352 #define MONO_ARCH_HAVE_SIGCTX_TO_MONOCTX 1
353 #if !defined(PLATFORM_WIN32) && !defined(HAVE_MOVING_COLLECTOR)
354 #define MONO_ARCH_MONITOR_OBJECT_REG MONO_AMD64_ARG_REG1
355 #endif
356 #define MONO_ARCH_HAVE_STATIC_RGCTX_TRAMPOLINE 1
357
358 #define MONO_ARCH_AOT_SUPPORTED 1
359 #ifndef PLATFORM_WIN32
360 #define MONO_ARCH_SOFT_DEBUG_SUPPORTED 1
361 #else
362 #define DISABLE_DEBUGGER_AGENT 1
363 #endif
364 #define MONO_ARCH_HAVE_FIND_JIT_INFO_EXT 1
365
366 #if !defined(PLATFORM_WIN32) || defined(__sun)
367 #define MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH 1
368 #endif
369
370 #define MONO_ARCH_SUPPORT_TASKLETS 1
371
372 #ifndef PLATFORM_WIN32
373 #define MONO_AMD64_NO_PUSHES 1
374 #endif
375
376 #define MONO_ARCH_GSHARED_SUPPORTED 1
377 #define MONO_ARCH_DYN_CALL_SUPPORTED 1
378 #define MONO_ARCH_DYN_CALL_PARAM_AREA 0
379
380 #define MONO_ARCH_HAVE_LLVM_IMT_TRAMPOLINE 1
381 #define MONO_ARCH_LLVM_SUPPORTED 1
382
383 #define MONO_ARCH_USE_OP_TAIL_CALL(caller_sig, callee_sig) mono_metadata_signature_equal ((caller_sig), (callee_sig))
384
385 /* Used for optimization, not complete */
386 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
387
388 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
389             MonoInst *inst; \
390             MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
391             inst->inst_basereg = array_reg; \
392             inst->inst_offset = offset; \
393             inst->sreg2 = index_reg; \
394             MONO_ADD_INS ((cfg)->cbb, inst); \
395             MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
396        } while (0)
397
398 void 
399 mono_amd64_patch (unsigned char* code, gpointer target) MONO_INTERNAL;
400
401 void
402 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
403                                                         guint64 dummy5, guint64 dummy6,
404                                                         MonoObject *exc, guint64 rip, guint64 rsp,
405                                                         guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
406                                                         guint64 r14, guint64 r15, guint64 rdi, guint64 rsi, 
407                                                         guint64 rax, guint64 rcx, guint64 rdx,
408                                                         guint64 rethrow);
409
410 guint64
411 mono_amd64_get_original_ip (void) MONO_INTERNAL;
412
413 guint8*
414 mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset) MONO_INTERNAL;
415
416 typedef struct {
417         guint8 *address;
418         guint8 saved_byte;
419 } MonoBreakpointInfo;
420
421 extern MonoBreakpointInfo mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
422
423 #ifdef PLATFORM_WIN32
424
425 void mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
426 void mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
427 void mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size );
428 guint mono_arch_unwindinfo_get_size (gpointer monoui);
429 void mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size);
430
431 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
432 #endif
433
434 #endif /* __MONO_MINI_AMD64_H__ */  
435