2009-02-04 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_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_RETREG1 X86_EAX
114 #define MONO_ARCH_RETREG2 X86_EDX
115
116 struct MonoLMF {
117         /* 
118          * If the lowest bit is set to 1, then this LMF has the rip field set. Otherwise,
119          * the rip field is not set, and the rsp field points to the stack location where
120          * the caller ip is saved.
121          */
122         gpointer    previous_lmf;
123         gpointer    lmf_addr;
124         /* This is only set in trampoline LMF frames */
125         MonoMethod *method;
126         guint64     rip;
127         guint64     rbx;
128         guint64     rbp;
129         guint64     rsp;
130         guint64     r12;
131         guint64     r13;
132         guint64     r14;
133         guint64     r15;
134 #ifdef PLATFORM_WIN32
135         guint64     rdi;
136         guint64     rsi;
137 #endif
138 };
139
140 typedef struct MonoCompileArch {
141         gint32 lmf_offset;
142         gint32 localloc_offset;
143         gint32 reg_save_area_offset;
144         gint32 stack_alloc_size;
145         gboolean omit_fp, omit_fp_computed;
146         gpointer cinfo;
147         gint32 async_point_count;
148         gpointer vret_addr_loc;
149 #ifdef PLATFORM_WIN32
150         gpointer        unwindinfo;
151 #endif
152 } MonoCompileArch;
153
154 typedef struct {
155         guint64 rax;
156         guint64 rbx;
157         guint64 rcx;
158         guint64 rdx;
159         guint64 rbp;
160         guint64 rsp;
161     guint64 rsi;
162         guint64 rdi;
163         guint64 rip;
164         guint64 r12;
165         guint64 r13;
166         guint64 r14;
167         guint64 r15;
168 } MonoContext;
169
170 #define MONO_CONTEXT_SET_IP(ctx,ip) do { (ctx)->rip = (guint64)(ip); } while (0); 
171 #define MONO_CONTEXT_SET_BP(ctx,bp) do { (ctx)->rbp = (guint64)(bp); } while (0); 
172 #define MONO_CONTEXT_SET_SP(ctx,esp) do { (ctx)->rsp = (guint64)(esp); } while (0); 
173
174 #define MONO_CONTEXT_GET_IP(ctx) ((gpointer)((ctx)->rip))
175 #define MONO_CONTEXT_GET_BP(ctx) ((gpointer)((ctx)->rbp))
176 #define MONO_CONTEXT_GET_SP(ctx) ((gpointer)((ctx)->rsp))
177
178 #define MONO_ARCH_INIT_TOP_LMF_ENTRY(lmf)
179
180 #ifdef _MSC_VER
181
182 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx, start_func) do { \
183     guint64 stackptr; \
184         mono_arch_flush_register_windows (); \
185         stackptr = ((guint64)_AddressOfReturnAddress () - sizeof (void*));\
186         MONO_CONTEXT_SET_IP ((ctx), (start_func)); \
187         MONO_CONTEXT_SET_BP ((ctx), stackptr); \
188         MONO_CONTEXT_SET_SP ((ctx), stackptr); \
189 } while (0)
190
191 #else
192
193 /* 
194  * __builtin_frame_address () is broken on some older gcc versions in the presence of
195  * frame pointer elimination, see bug #82095.
196  */
197 #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,start_func) do {        \
198         int tmp; \
199         guint64 stackptr = (guint64)&tmp; \
200                 mono_arch_flush_register_windows ();    \
201                 MONO_CONTEXT_SET_IP ((ctx), (start_func));      \
202                 MONO_CONTEXT_SET_BP ((ctx), stackptr);  \
203                 MONO_CONTEXT_SET_SP ((ctx), stackptr);  \
204         } while (0)
205
206 #endif
207
208 /*
209  * some icalls like mono_array_new_va needs to be called using a different 
210  * calling convention.
211  */
212 #define MONO_ARCH_VARARG_ICALLS 1
213
214 #ifndef PLATFORM_WIN32
215
216 #define MONO_ARCH_USE_SIGACTION 1
217
218 #ifdef HAVE_WORKING_SIGALTSTACK
219
220 #define MONO_ARCH_SIGSEGV_ON_ALTSTACK
221
222 #endif
223
224 #ifdef __OpenBSD__
225 #undef MONO_ARCH_USE_SIGACTION
226 #endif
227
228 #endif /* PLATFORM_WIN32 */
229
230 #if defined (__NetBSD__)
231
232 #define REG_RAX 14
233 #define REG_RCX 3
234 #define REG_RDX 2
235 #define REG_RBX 13
236 #define REG_RSP 24
237 #define REG_RBP 12
238 #define REG_RSI 1
239 #define REG_RDI 0
240 #define REG_R8 4
241 #define REG_R9 5
242 #define REG_R10 6
243 #define REG_R11 7
244 #define REG_R12 8
245 #define REG_R13 9
246 #define REG_R14 10
247 #define REG_R15 11
248 #define REG_RIP 21
249
250 #define MONO_ARCH_NOMAP32BIT
251
252 #elif defined (__FreeBSD__) || defined (__OpenBSD__)
253
254 #define REG_RAX 7
255 #define REG_RCX 4
256 #define REG_RDX 3
257 #define REG_RBX 8
258 #define REG_RSP 23
259 #define REG_RBP 9
260 #define REG_RSI 2
261 #define REG_RDI 1
262 #define REG_R8  5
263 #define REG_R9  6
264 #define REG_R10 10
265 #define REG_R11 11
266 #define REG_R12 12
267 #define REG_R13 13
268 #define REG_R14 14
269 #define REG_R15 15
270 #define REG_RIP 20
271
272 /* 
273  * FreeBSD does not have MAP_32BIT, so code allocated by the code manager might not have a
274  * 32 bit address.
275  */
276 #define MONO_ARCH_NOMAP32BIT
277
278 #endif /* __FreeBSD__ */
279
280 #ifdef PLATFORM_WIN32
281 #define MONO_AMD64_ARG_REG1 AMD64_RCX
282 #define MONO_AMD64_ARG_REG2 AMD64_RDX
283 #else
284 #define MONO_AMD64_ARG_REG1 AMD64_RDI
285 #define MONO_AMD64_ARG_REG2 AMD64_RSI
286 #endif
287
288 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
289 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
290
291 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
292 #define MONO_ARCH_EMULATE_FREM 1
293 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
294
295 #define MONO_ARCH_ENABLE_EMIT_STATE_OPT 1
296 #define MONO_ARCH_ENABLE_REGALLOC_IN_EH_BLOCKS 1
297 #define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
298 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
299 #define MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION 1
300 #define MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN 1
301 #define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
302 #define MONO_ARCH_HAVE_ATOMIC_ADD 1
303 #define MONO_ARCH_HAVE_ATOMIC_EXCHANGE 1
304 #define MONO_ARCH_HAVE_ATOMIC_CAS_IMM 1
305 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
306 #define MONO_ARCH_HAVE_IMT 1
307 #define MONO_ARCH_HAVE_TLS_GET 1
308 #define MONO_ARCH_IMT_REG AMD64_R11
309 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
310 /*
311  * We use r10 for the rgctx register rather than r11 because r11 is
312  * used by the trampoline as a scratch register and hence might be
313  * clobbered across method call boundaries.
314  */
315 #define MONO_ARCH_RGCTX_REG AMD64_R10
316 #define MONO_ARCH_COMMON_VTABLE_TRAMPOLINE 1
317 #define MONO_ARCH_HAVE_CMOV_OPS 1
318 #define MONO_ARCH_HAVE_NOTIFY_PENDING_EXC 1
319 #define MONO_ARCH_HAVE_EXCEPTIONS_INIT 1
320 #define MONO_ARCH_ENABLE_GLOBAL_RA 1
321 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
322 #define MONO_ARCH_HAVE_LIVERANGE_OPS 1
323 #define MONO_ARCH_HAVE_XP_UNWIND 1
324 #if !defined(PLATFORM_WIN32) && !defined(HAVE_MOVING_COLLECTOR)
325 #define MONO_ARCH_MONITOR_OBJECT_REG AMD64_RDI
326 #endif
327
328 #define MONO_ARCH_AOT_SUPPORTED 1
329
330 #if !defined(PLATFORM_WIN32) || defined(__sun)
331 #define MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH 1
332 #endif
333
334 /* Used for optimization, not complete */
335 #define MONO_ARCH_IS_OP_MEMBASE(opcode) ((opcode) == OP_X86_PUSH_MEMBASE)
336
337 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
338             MonoInst *inst; \
339             MONO_INST_NEW ((cfg), inst, OP_AMD64_ICOMPARE_MEMBASE_REG); \
340             inst->inst_basereg = array_reg; \
341             inst->inst_offset = offset; \
342             inst->sreg2 = index_reg; \
343             MONO_ADD_INS ((cfg)->cbb, inst); \
344             MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
345        } while (0)
346
347 void 
348 mono_amd64_patch (unsigned char* code, gpointer target) MONO_INTERNAL;
349
350 void
351 mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guint64 dummy4,
352                                                         guint64 dummy5, guint64 dummy6,
353                                                         MonoObject *exc, guint64 rip, guint64 rsp,
354                                                         guint64 rbx, guint64 rbp, guint64 r12, guint64 r13, 
355                                                         guint64 r14, guint64 r15, guint64 rdi, guint64 rsi, 
356                                                         guint64 rax, guint64 rcx, guint64 rdx,
357                                                         guint64 rethrow);
358
359 guint8*
360 mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset) MONO_INTERNAL;
361
362 typedef struct {
363         guint8 *address;
364         guint8 saved_byte;
365 } MonoBreakpointInfo;
366
367 extern MonoBreakpointInfo mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
368
369 #ifdef PLATFORM_WIN32
370
371 void mono_arch_unwindinfo_add_push_nonvol (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
372 void mono_arch_unwindinfo_add_set_fpreg (gpointer* monoui, gpointer codebegin, gpointer nextip, guchar reg );
373 void mono_arch_unwindinfo_add_alloc_stack (gpointer* monoui, gpointer codebegin, gpointer nextip, guint size );
374 guint mono_arch_unwindinfo_get_size (gpointer monoui);
375 void mono_arch_unwindinfo_install_unwind_info (gpointer* monoui, gpointer code, guint code_size);
376
377 #define MONO_ARCH_HAVE_UNWIND_TABLE 1
378 #endif
379
380 #endif /* __MONO_MINI_AMD64_H__ */  
381