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