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