2008-11-17 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 #endif /* PLATFORM_WIN32 */
225
226 #ifdef __FreeBSD__
227
228 #define REG_RAX 7
229 #define REG_RCX 4
230 #define REG_RDX 3
231 #define REG_RBX 8
232 #define REG_RSP 23
233 #define REG_RBP 9
234 #define REG_RSI 2
235 #define REG_RDI 1
236 #define REG_R8  5
237 #define REG_R9  6
238 #define REG_R10 10
239 #define REG_R11 11
240 #define REG_R12 12
241 #define REG_R13 13
242 #define REG_R14 14
243 #define REG_R15 15
244 #define REG_RIP 20
245
246 /* 
247  * FreeBSD does not have MAP_32BIT, so code allocated by the code manager might not have a
248  * 32 bit address.
249  */
250 #define MONO_ARCH_NOMAP32BIT
251
252 #endif /* __FreeBSD__ */
253
254 #ifdef PLATFORM_WIN32
255 #define MONO_AMD64_ARG_REG1 AMD64_RCX
256 #define MONO_AMD64_ARG_REG2 AMD64_RDX
257 #else
258 #define MONO_AMD64_ARG_REG1 AMD64_RDI
259 #define MONO_AMD64_ARG_REG2 AMD64_RSI
260 #endif
261
262 #define MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS
263 #define MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
264
265 #define MONO_ARCH_EMULATE_CONV_R8_UN    1
266 #define MONO_ARCH_EMULATE_FREM 1
267 #define MONO_ARCH_HAVE_IS_INT_OVERFLOW 1
268
269 #define MONO_ARCH_ENABLE_EMIT_STATE_OPT 1
270 #define MONO_ARCH_ENABLE_REGALLOC_IN_EH_BLOCKS 1
271 #define MONO_ARCH_ENABLE_MONO_LMF_VAR 1
272 #define MONO_ARCH_HAVE_INVALIDATE_METHOD 1
273 #define MONO_ARCH_HAVE_THROW_CORLIB_EXCEPTION 1
274 #define MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN 1
275 #define MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE 1
276 #define MONO_ARCH_HAVE_ATOMIC_ADD 1
277 #define MONO_ARCH_HAVE_ATOMIC_EXCHANGE 1
278 #define MONO_ARCH_HAVE_ATOMIC_CAS_IMM 1
279 #define MONO_ARCH_HAVE_FULL_AOT_TRAMPOLINES 1
280 #define MONO_ARCH_HAVE_IMT 1
281 #define MONO_ARCH_HAVE_TLS_GET 1
282 #define MONO_ARCH_IMT_REG AMD64_R11
283 #define MONO_ARCH_VTABLE_REG MONO_AMD64_ARG_REG1
284 /*
285  * We use r10 for the rgctx register rather than r11 because r11 is
286  * used by the trampoline as a scratch register and hence might be
287  * clobbered across method call boundaries.
288  */
289 #define MONO_ARCH_RGCTX_REG AMD64_R10
290 #define MONO_ARCH_COMMON_VTABLE_TRAMPOLINE 1
291 #define MONO_ARCH_HAVE_CMOV_OPS 1
292 #define MONO_ARCH_HAVE_NOTIFY_PENDING_EXC 1
293 #define MONO_ARCH_ENABLE_NORMALIZE_OPCODES 1
294 #define MONO_ARCH_ENABLE_GLOBAL_RA 1
295 #define MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK 1
296 #if !defined(PLATFORM_WIN32) && !defined(HAVE_MOVING_COLLECTOR)
297 #define MONO_ARCH_MONITOR_OBJECT_REG AMD64_RDI
298 #endif
299
300 #define MONO_ARCH_AOT_SUPPORTED 1
301
302 #if !defined(PLATFORM_WIN32) || defined(__sun)
303 #define MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH 1
304 #endif
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 guint8*
332 mono_amd64_emit_tls_get (guint8* code, int dreg, int tls_offset) MONO_INTERNAL;
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