Merge pull request #642 from Ventero/CleanCopyLocal
[mono.git] / mono / mini / mini-x86.c
1 /*
2  * mini-x86.c: x86 backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Patrik Torstensson
8  *
9  * Copyright 2003 Ximian, Inc.
10  * Copyright 2003-2011 Novell Inc.
11  * Copyright 2011 Xamarin Inc.
12  */
13 #include "mini.h"
14 #include <string.h>
15 #include <math.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/debug-helpers.h>
22 #include <mono/metadata/threads.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/mono-debug.h>
25 #include <mono/metadata/gc-internal.h>
26 #include <mono/utils/mono-math.h>
27 #include <mono/utils/mono-counters.h>
28 #include <mono/utils/mono-mmap.h>
29 #include <mono/utils/mono-memory-model.h>
30
31 #include "trace.h"
32 #include "mini-x86.h"
33 #include "cpu-x86.h"
34 #include "ir-emit.h"
35 #include "mini-gc.h"
36
37 /* On windows, these hold the key returned by TlsAlloc () */
38 static gint lmf_tls_offset = -1;
39 static gint lmf_addr_tls_offset = -1;
40 static gint appdomain_tls_offset = -1;
41
42 #ifdef MONO_XEN_OPT
43 static gboolean optimize_for_xen = TRUE;
44 #else
45 #define optimize_for_xen 0
46 #endif
47
48 #ifdef TARGET_WIN32
49 static gboolean is_win32 = TRUE;
50 #else
51 static gboolean is_win32 = FALSE;
52 #endif
53
54 /* This mutex protects architecture specific caches */
55 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
56 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
57 static CRITICAL_SECTION mini_arch_mutex;
58
59 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
60
61 #define ARGS_OFFSET 8
62
63 #ifdef TARGET_WIN32
64 /* Under windows, the default pinvoke calling convention is stdcall */
65 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
66 #else
67 #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL)
68 #endif
69
70 #define X86_IS_CALLEE_SAVED_REG(reg) (((reg) == X86_EBX) || ((reg) == X86_EDI) || ((reg) == X86_ESI))
71
72 MonoBreakpointInfo
73 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
74
75
76 #ifdef __native_client_codegen__
77
78 /* Default alignment for Native Client is 32-byte. */
79 gint8 nacl_align_byte = -32; /* signed version of 0xe0 */
80
81 /* mono_arch_nacl_pad: Add pad bytes of alignment instructions at code,       */
82 /* Check that alignment doesn't cross an alignment boundary.        */
83 guint8 *
84 mono_arch_nacl_pad (guint8 *code, int pad)
85 {
86         const int kMaxPadding = 7;    /* see x86-codegen.h: x86_padding() */
87
88         if (pad == 0) return code;
89         /* assertion: alignment cannot cross a block boundary */
90         g_assert(((uintptr_t)code & (~kNaClAlignmentMask)) ==
91                          (((uintptr_t)code + pad - 1) & (~kNaClAlignmentMask)));
92         while (pad >= kMaxPadding) {
93                 x86_padding (code, kMaxPadding);
94                 pad -= kMaxPadding;
95         }
96         if (pad != 0) x86_padding (code, pad);
97         return code;
98 }
99
100 guint8 *
101 mono_arch_nacl_skip_nops (guint8 *code)
102 {
103         x86_skip_nops (code);
104         return code;
105 }
106
107 #endif /* __native_client_codegen__ */
108
109 /*
110  * The code generated for sequence points reads from this location, which is
111  * made read-only when single stepping is enabled.
112  */
113 static gpointer ss_trigger_page;
114
115 /* Enabled breakpoints read from this trigger page */
116 static gpointer bp_trigger_page;
117
118 const char*
119 mono_arch_regname (int reg)
120 {
121         switch (reg) {
122         case X86_EAX: return "%eax";
123         case X86_EBX: return "%ebx";
124         case X86_ECX: return "%ecx";
125         case X86_EDX: return "%edx";
126         case X86_ESP: return "%esp";    
127         case X86_EBP: return "%ebp";
128         case X86_EDI: return "%edi";
129         case X86_ESI: return "%esi";
130         }
131         return "unknown";
132 }
133
134 const char*
135 mono_arch_fregname (int reg)
136 {
137         switch (reg) {
138         case 0:
139                 return "%fr0";
140         case 1:
141                 return "%fr1";
142         case 2:
143                 return "%fr2";
144         case 3:
145                 return "%fr3";
146         case 4:
147                 return "%fr4";
148         case 5:
149                 return "%fr5";
150         case 6:
151                 return "%fr6";
152         case 7:
153                 return "%fr7";
154         default:
155                 return "unknown";
156         }
157 }
158
159 const char *
160 mono_arch_xregname (int reg)
161 {
162         switch (reg) {
163         case 0:
164                 return "%xmm0";
165         case 1:
166                 return "%xmm1";
167         case 2:
168                 return "%xmm2";
169         case 3:
170                 return "%xmm3";
171         case 4:
172                 return "%xmm4";
173         case 5:
174                 return "%xmm5";
175         case 6:
176                 return "%xmm6";
177         case 7:
178                 return "%xmm7";
179         default:
180                 return "unknown";
181         }
182 }
183
184 void 
185 mono_x86_patch (unsigned char* code, gpointer target)
186 {
187         x86_patch (code, (unsigned char*)target);
188 }
189
190 typedef enum {
191         ArgInIReg,
192         ArgInFloatSSEReg,
193         ArgInDoubleSSEReg,
194         ArgOnStack,
195         ArgValuetypeInReg,
196         ArgOnFloatFpStack,
197         ArgOnDoubleFpStack,
198         /* gsharedvt argument passed by addr */
199         ArgGSharedVt,
200         ArgNone
201 } ArgStorage;
202
203 typedef struct {
204         gint16 offset;
205         gint8  reg;
206         ArgStorage storage;
207         int nslots;
208         gboolean is_pair;
209
210         /* Only if storage == ArgValuetypeInReg */
211         ArgStorage pair_storage [2];
212         gint8 pair_regs [2];
213 } ArgInfo;
214
215 typedef struct {
216         int nargs;
217         guint32 stack_usage;
218         guint32 reg_usage;
219         guint32 freg_usage;
220         gboolean need_stack_align;
221         guint32 stack_align_amount;
222         gboolean vtype_retaddr;
223         /* The index of the vret arg in the argument list */
224         int vret_arg_index;
225         int vret_arg_offset;
226         ArgInfo ret;
227         ArgInfo sig_cookie;
228         ArgInfo args [1];
229 } CallInfo;
230
231 #define PARAM_REGS 0
232
233 #define FLOAT_PARAM_REGS 0
234
235 static X86_Reg_No param_regs [] = { 0 };
236
237 #if defined(TARGET_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
238 #define SMALL_STRUCTS_IN_REGS
239 static X86_Reg_No return_regs [] = { X86_EAX, X86_EDX };
240 #endif
241
242 static void inline
243 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
244 {
245     ainfo->offset = *stack_size;
246
247     if (*gr >= PARAM_REGS) {
248                 ainfo->storage = ArgOnStack;
249                 ainfo->nslots = 1;
250                 (*stack_size) += sizeof (gpointer);
251     }
252     else {
253                 ainfo->storage = ArgInIReg;
254                 ainfo->reg = param_regs [*gr];
255                 (*gr) ++;
256     }
257 }
258
259 static void inline
260 add_general_pair (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
261 {
262         ainfo->offset = *stack_size;
263
264         g_assert (PARAM_REGS == 0);
265         
266         ainfo->storage = ArgOnStack;
267         (*stack_size) += sizeof (gpointer) * 2;
268         ainfo->nslots = 2;
269 }
270
271 static void inline
272 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
273 {
274     ainfo->offset = *stack_size;
275
276     if (*gr >= FLOAT_PARAM_REGS) {
277                 ainfo->storage = ArgOnStack;
278                 (*stack_size) += is_double ? 8 : 4;
279                 ainfo->nslots = is_double ? 2 : 1;
280     }
281     else {
282                 /* A double register */
283                 if (is_double)
284                         ainfo->storage = ArgInDoubleSSEReg;
285                 else
286                         ainfo->storage = ArgInFloatSSEReg;
287                 ainfo->reg = *gr;
288                 (*gr) += 1;
289     }
290 }
291
292
293 static void
294 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
295                gboolean is_return,
296                guint32 *gr, guint32 *fr, guint32 *stack_size)
297 {
298         guint32 size;
299         MonoClass *klass;
300
301         klass = mono_class_from_mono_type (type);
302         size = mini_type_stack_size_full (gsctx, &klass->byval_arg, NULL, sig->pinvoke);
303
304 #ifdef SMALL_STRUCTS_IN_REGS
305         if (sig->pinvoke && is_return) {
306                 MonoMarshalType *info;
307
308                 /*
309                  * the exact rules are not very well documented, the code below seems to work with the 
310                  * code generated by gcc 3.3.3 -mno-cygwin.
311                  */
312                 info = mono_marshal_load_type_info (klass);
313                 g_assert (info);
314
315                 ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
316
317                 /* Special case structs with only a float member */
318                 if ((info->native_size == 8) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R8)) {
319                         ainfo->storage = ArgValuetypeInReg;
320                         ainfo->pair_storage [0] = ArgOnDoubleFpStack;
321                         return;
322                 }
323                 if ((info->native_size == 4) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R4)) {
324                         ainfo->storage = ArgValuetypeInReg;
325                         ainfo->pair_storage [0] = ArgOnFloatFpStack;
326                         return;
327                 }               
328                 if ((info->native_size == 1) || (info->native_size == 2) || (info->native_size == 4) || (info->native_size == 8)) {
329                         ainfo->storage = ArgValuetypeInReg;
330                         ainfo->pair_storage [0] = ArgInIReg;
331                         ainfo->pair_regs [0] = return_regs [0];
332                         if (info->native_size > 4) {
333                                 ainfo->pair_storage [1] = ArgInIReg;
334                                 ainfo->pair_regs [1] = return_regs [1];
335                         }
336                         return;
337                 }
338         }
339 #endif
340
341         ainfo->offset = *stack_size;
342         ainfo->storage = ArgOnStack;
343         *stack_size += ALIGN_TO (size, sizeof (gpointer));
344         ainfo->nslots = ALIGN_TO (size, sizeof (gpointer)) / sizeof (gpointer);
345 }
346
347 /*
348  * get_call_info:
349  *
350  *  Obtain information about a call according to the calling convention.
351  * For x86 ELF, see the "System V Application Binary Interface Intel386 
352  * Architecture Processor Supplment, Fourth Edition" document for more
353  * information.
354  * For x86 win32, see ???.
355  */
356 static CallInfo*
357 get_call_info_internal (MonoGenericSharingContext *gsctx, CallInfo *cinfo, MonoMethodSignature *sig)
358 {
359         guint32 i, gr, fr, pstart;
360         MonoType *ret_type;
361         int n = sig->hasthis + sig->param_count;
362         guint32 stack_size = 0;
363         gboolean is_pinvoke = sig->pinvoke;
364
365         gr = 0;
366         fr = 0;
367         cinfo->nargs = n;
368
369         /* return value */
370         {
371                 ret_type = mini_type_get_underlying_type (gsctx, sig->ret);
372                 switch (ret_type->type) {
373                 case MONO_TYPE_BOOLEAN:
374                 case MONO_TYPE_I1:
375                 case MONO_TYPE_U1:
376                 case MONO_TYPE_I2:
377                 case MONO_TYPE_U2:
378                 case MONO_TYPE_CHAR:
379                 case MONO_TYPE_I4:
380                 case MONO_TYPE_U4:
381                 case MONO_TYPE_I:
382                 case MONO_TYPE_U:
383                 case MONO_TYPE_PTR:
384                 case MONO_TYPE_FNPTR:
385                 case MONO_TYPE_CLASS:
386                 case MONO_TYPE_OBJECT:
387                 case MONO_TYPE_SZARRAY:
388                 case MONO_TYPE_ARRAY:
389                 case MONO_TYPE_STRING:
390                         cinfo->ret.storage = ArgInIReg;
391                         cinfo->ret.reg = X86_EAX;
392                         break;
393                 case MONO_TYPE_U8:
394                 case MONO_TYPE_I8:
395                         cinfo->ret.storage = ArgInIReg;
396                         cinfo->ret.reg = X86_EAX;
397                         cinfo->ret.is_pair = TRUE;
398                         break;
399                 case MONO_TYPE_R4:
400                         cinfo->ret.storage = ArgOnFloatFpStack;
401                         break;
402                 case MONO_TYPE_R8:
403                         cinfo->ret.storage = ArgOnDoubleFpStack;
404                         break;
405                 case MONO_TYPE_GENERICINST:
406                         if (!mono_type_generic_inst_is_valuetype (ret_type)) {
407                                 cinfo->ret.storage = ArgInIReg;
408                                 cinfo->ret.reg = X86_EAX;
409                                 break;
410                         }
411                         if (mini_is_gsharedvt_type_gsctx (gsctx, ret_type)) {
412                                 cinfo->ret.storage = ArgOnStack;
413                                 cinfo->vtype_retaddr = TRUE;
414                                 break;
415                         }
416                         /* Fall through */
417                 case MONO_TYPE_VALUETYPE:
418                 case MONO_TYPE_TYPEDBYREF: {
419                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
420
421                         add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
422                         if (cinfo->ret.storage == ArgOnStack) {
423                                 cinfo->vtype_retaddr = TRUE;
424                                 /* The caller passes the address where the value is stored */
425                         }
426                         break;
427                 }
428                 case MONO_TYPE_VAR:
429                 case MONO_TYPE_MVAR:
430                         g_assert (mini_is_gsharedvt_type_gsctx (gsctx, ret_type));
431                         cinfo->ret.storage = ArgOnStack;
432                         cinfo->vtype_retaddr = TRUE;
433                         break;
434                 case MONO_TYPE_VOID:
435                         cinfo->ret.storage = ArgNone;
436                         break;
437                 default:
438                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
439                 }
440         }
441
442         pstart = 0;
443         /*
444          * To simplify get_this_arg_reg () and LLVM integration, emit the vret arg after
445          * the first argument, allowing 'this' to be always passed in the first arg reg.
446          * Also do this if the first argument is a reference type, since virtual calls
447          * are sometimes made using calli without sig->hasthis set, like in the delegate
448          * invoke wrappers.
449          */
450         if (cinfo->vtype_retaddr && !is_pinvoke && (sig->hasthis || (sig->param_count > 0 && MONO_TYPE_IS_REFERENCE (mini_type_get_underlying_type (gsctx, sig->params [0]))))) {
451                 if (sig->hasthis) {
452                         add_general (&gr, &stack_size, cinfo->args + 0);
453                 } else {
454                         add_general (&gr, &stack_size, &cinfo->args [sig->hasthis + 0]);
455                         pstart = 1;
456                 }
457                 cinfo->vret_arg_offset = stack_size;
458                 add_general (&gr, &stack_size, &cinfo->ret);
459                 cinfo->vret_arg_index = 1;
460         } else {
461                 /* this */
462                 if (sig->hasthis)
463                         add_general (&gr, &stack_size, cinfo->args + 0);
464
465                 if (cinfo->vtype_retaddr)
466                         add_general (&gr, &stack_size, &cinfo->ret);
467         }
468
469         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
470                 gr = PARAM_REGS;
471                 fr = FLOAT_PARAM_REGS;
472                 
473                 /* Emit the signature cookie just before the implicit arguments */
474                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
475         }
476
477         for (i = pstart; i < sig->param_count; ++i) {
478                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
479                 MonoType *ptype;
480
481                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
482                         /* We allways pass the sig cookie on the stack for simplicity */
483                         /* 
484                          * Prevent implicit arguments + the sig cookie from being passed 
485                          * in registers.
486                          */
487                         gr = PARAM_REGS;
488                         fr = FLOAT_PARAM_REGS;
489
490                         /* Emit the signature cookie just before the implicit arguments */
491                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
492                 }
493
494                 if (sig->params [i]->byref) {
495                         add_general (&gr, &stack_size, ainfo);
496                         continue;
497                 }
498                 ptype = mini_type_get_underlying_type (gsctx, sig->params [i]);
499                 switch (ptype->type) {
500                 case MONO_TYPE_BOOLEAN:
501                 case MONO_TYPE_I1:
502                 case MONO_TYPE_U1:
503                         add_general (&gr, &stack_size, ainfo);
504                         break;
505                 case MONO_TYPE_I2:
506                 case MONO_TYPE_U2:
507                 case MONO_TYPE_CHAR:
508                         add_general (&gr, &stack_size, ainfo);
509                         break;
510                 case MONO_TYPE_I4:
511                 case MONO_TYPE_U4:
512                         add_general (&gr, &stack_size, ainfo);
513                         break;
514                 case MONO_TYPE_I:
515                 case MONO_TYPE_U:
516                 case MONO_TYPE_PTR:
517                 case MONO_TYPE_FNPTR:
518                 case MONO_TYPE_CLASS:
519                 case MONO_TYPE_OBJECT:
520                 case MONO_TYPE_STRING:
521                 case MONO_TYPE_SZARRAY:
522                 case MONO_TYPE_ARRAY:
523                         add_general (&gr, &stack_size, ainfo);
524                         break;
525                 case MONO_TYPE_GENERICINST:
526                         if (!mono_type_generic_inst_is_valuetype (ptype)) {
527                                 add_general (&gr, &stack_size, ainfo);
528                                 break;
529                         }
530                         if (mini_is_gsharedvt_type_gsctx (gsctx, ptype)) {
531                                 /* gsharedvt arguments are passed by ref */
532                                 add_general (&gr, &stack_size, ainfo);
533                                 g_assert (ainfo->storage == ArgOnStack);
534                                 ainfo->storage = ArgGSharedVt;
535                                 break;
536                         }
537                         /* Fall through */
538                 case MONO_TYPE_VALUETYPE:
539                 case MONO_TYPE_TYPEDBYREF:
540                         add_valuetype (gsctx, sig, ainfo, ptype, FALSE, &gr, &fr, &stack_size);
541                         break;
542                 case MONO_TYPE_U8:
543                 case MONO_TYPE_I8:
544                         add_general_pair (&gr, &stack_size, ainfo);
545                         break;
546                 case MONO_TYPE_R4:
547                         add_float (&fr, &stack_size, ainfo, FALSE);
548                         break;
549                 case MONO_TYPE_R8:
550                         add_float (&fr, &stack_size, ainfo, TRUE);
551                         break;
552                 case MONO_TYPE_VAR:
553                 case MONO_TYPE_MVAR:
554                         /* gsharedvt arguments are passed by ref */
555                         g_assert (mini_is_gsharedvt_type_gsctx (gsctx, ptype));
556                         add_general (&gr, &stack_size, ainfo);
557                         g_assert (ainfo->storage == ArgOnStack);
558                         ainfo->storage = ArgGSharedVt;
559                         break;
560                 default:
561                         g_error ("unexpected type 0x%x", ptype->type);
562                         g_assert_not_reached ();
563                 }
564         }
565
566         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
567                 gr = PARAM_REGS;
568                 fr = FLOAT_PARAM_REGS;
569                 
570                 /* Emit the signature cookie just before the implicit arguments */
571                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
572         }
573
574         if (mono_do_x86_stack_align && (stack_size % MONO_ARCH_FRAME_ALIGNMENT) != 0) {
575                 cinfo->need_stack_align = TRUE;
576                 cinfo->stack_align_amount = MONO_ARCH_FRAME_ALIGNMENT - (stack_size % MONO_ARCH_FRAME_ALIGNMENT);
577                 stack_size += cinfo->stack_align_amount;
578         }
579
580         cinfo->stack_usage = stack_size;
581         cinfo->reg_usage = gr;
582         cinfo->freg_usage = fr;
583         return cinfo;
584 }
585
586 static CallInfo*
587 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig)
588 {
589         int n = sig->hasthis + sig->param_count;
590         CallInfo *cinfo;
591
592         if (mp)
593                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
594         else
595                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
596
597         return get_call_info_internal (gsctx, cinfo, sig);
598 }
599
600 /*
601  * mono_arch_get_argument_info:
602  * @csig:  a method signature
603  * @param_count: the number of parameters to consider
604  * @arg_info: an array to store the result infos
605  *
606  * Gathers information on parameters such as size, alignment and
607  * padding. arg_info should be large enought to hold param_count + 1 entries. 
608  *
609  * Returns the size of the argument area on the stack.
610  * This should be signal safe, since it is called from
611  * mono_arch_find_jit_info ().
612  * FIXME: The metadata calls might not be signal safe.
613  */
614 int
615 mono_arch_get_argument_info (MonoGenericSharingContext *gsctx, MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
616 {
617         int len, k, args_size = 0;
618         int size, pad;
619         guint32 align;
620         int offset = 8;
621         CallInfo *cinfo;
622
623         /* Avoid g_malloc as it is not signal safe */
624         len = sizeof (CallInfo) + (sizeof (ArgInfo) * (csig->param_count + 1));
625         cinfo = (CallInfo*)g_newa (guint8*, len);
626         memset (cinfo, 0, len);
627
628         cinfo = get_call_info_internal (gsctx, cinfo, csig);
629
630         arg_info [0].offset = offset;
631
632         if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) {
633                 args_size += sizeof (gpointer);
634                 offset += 4;
635         }
636
637         if (csig->hasthis) {
638                 args_size += sizeof (gpointer);
639                 offset += 4;
640         }
641
642         if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && csig->hasthis) {
643                 /* Emitted after this */
644                 args_size += sizeof (gpointer);
645                 offset += 4;
646         }
647
648         arg_info [0].size = args_size;
649
650         for (k = 0; k < param_count; k++) {
651                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
652
653                 /* ignore alignment for now */
654                 align = 1;
655
656                 args_size += pad = (align - (args_size & (align - 1))) & (align - 1);   
657                 arg_info [k].pad = pad;
658                 args_size += size;
659                 arg_info [k + 1].pad = 0;
660                 arg_info [k + 1].size = size;
661                 offset += pad;
662                 arg_info [k + 1].offset = offset;
663                 offset += size;
664
665                 if (k == 0 && cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && !csig->hasthis) {
666                         /* Emitted after the first arg */
667                         args_size += sizeof (gpointer);
668                         offset += 4;
669                 }
670         }
671
672         if (mono_do_x86_stack_align && !CALLCONV_IS_STDCALL (csig))
673                 align = MONO_ARCH_FRAME_ALIGNMENT;
674         else
675                 align = 4;
676         args_size += pad = (align - (args_size & (align - 1))) & (align - 1);
677         arg_info [k].pad = pad;
678
679         return args_size;
680 }
681
682 gboolean
683 mono_x86_tail_call_supported (MonoMethodSignature *caller_sig, MonoMethodSignature *callee_sig)
684 {
685         CallInfo *c1, *c2;
686         gboolean res;
687
688         c1 = get_call_info (NULL, NULL, caller_sig);
689         c2 = get_call_info (NULL, NULL, callee_sig);
690         res = c1->stack_usage >= c2->stack_usage;
691         if (callee_sig->ret && MONO_TYPE_ISSTRUCT (callee_sig->ret) && c2->ret.storage != ArgValuetypeInReg)
692                 /* An address on the callee's stack is passed as the first argument */
693                 res = FALSE;
694
695         g_free (c1);
696         g_free (c2);
697
698         return res;
699 }
700
701 #if !defined(__native_client__)
702 static const guchar cpuid_impl [] = {
703         0x55,                           /* push   %ebp */
704         0x89, 0xe5,                     /* mov    %esp,%ebp */
705         0x53,                           /* push   %ebx */
706         0x8b, 0x45, 0x08,               /* mov    0x8(%ebp),%eax */
707         0x0f, 0xa2,                     /* cpuid   */
708         0x50,                           /* push   %eax */
709         0x8b, 0x45, 0x10,               /* mov    0x10(%ebp),%eax */
710         0x89, 0x18,                     /* mov    %ebx,(%eax) */
711         0x8b, 0x45, 0x14,               /* mov    0x14(%ebp),%eax */
712         0x89, 0x08,                     /* mov    %ecx,(%eax) */
713         0x8b, 0x45, 0x18,               /* mov    0x18(%ebp),%eax */
714         0x89, 0x10,                     /* mov    %edx,(%eax) */
715         0x58,                           /* pop    %eax */
716         0x8b, 0x55, 0x0c,               /* mov    0xc(%ebp),%edx */
717         0x89, 0x02,                     /* mov    %eax,(%edx) */
718         0x5b,                           /* pop    %ebx */
719         0xc9,                           /* leave   */
720         0xc3,                           /* ret     */
721 };
722 #else
723 static const guchar cpuid_impl [] = {
724         0x55,                                   /* push   %ebp */
725         0x89, 0xe5,                             /* mov    %esp,%ebp */
726         0x53,                                   /* push   %ebx */
727         0x8b, 0x45, 0x08,                       /* mov    0x8(%ebp),%eax */
728         0x0f, 0xa2,                             /* cpuid   */
729         0x50,                                   /* push   %eax */
730         0x8b, 0x45, 0x10,                       /* mov    0x10(%ebp),%eax */
731         0x89, 0x18,                             /* mov    %ebx,(%eax) */
732         0x8b, 0x45, 0x14,                       /* mov    0x14(%ebp),%eax */
733         0x89, 0x08,                             /* mov    %ecx,(%eax) */
734         0x8b, 0x45, 0x18,                       /* mov    0x18(%ebp),%eax */
735         0x89, 0x10,                             /* mov    %edx,(%eax) */
736         0x58,                                   /* pop    %eax */
737         0x8b, 0x55, 0x0c,                       /* mov    0xc(%ebp),%edx */
738         0x89, 0x02,                             /* mov    %eax,(%edx) */
739         0x5b,                                   /* pop    %ebx */
740         0xc9,                                   /* leave   */
741         0x59, 0x83, 0xe1, 0xe0, 0xff, 0xe1,     /* naclret */
742         0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,     /* padding, to provide bundle aligned version */
743         0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
744         0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
745         0xf4, 0xf4, 0xf4, 0xf4, 0xf4, 0xf4,
746         0xf4
747 };
748 #endif
749
750 typedef void (*CpuidFunc) (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx);
751
752 static int 
753 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
754 {
755 #if defined(__native_client__)
756         static CpuidFunc func = NULL;
757         void *ptr, *end_ptr;
758         if (!func) {
759                 ptr = mono_global_codeman_reserve (sizeof (cpuid_impl));
760                 memcpy(ptr, cpuid_impl, sizeof(cpuid_impl));
761                 end_ptr = ptr + sizeof(cpuid_impl);
762                 nacl_global_codeman_validate (&ptr, sizeof(cpuid_impl), &end_ptr);
763                 func = (CpuidFunc)ptr;
764         }
765         func (id, p_eax, p_ebx, p_ecx, p_edx);
766 #else
767         int have_cpuid = 0;
768 #ifndef _MSC_VER
769         __asm__  __volatile__ (
770                 "pushfl\n"
771                 "popl %%eax\n"
772                 "movl %%eax, %%edx\n"
773                 "xorl $0x200000, %%eax\n"
774                 "pushl %%eax\n"
775                 "popfl\n"
776                 "pushfl\n"
777                 "popl %%eax\n"
778                 "xorl %%edx, %%eax\n"
779                 "andl $0x200000, %%eax\n"
780                 "movl %%eax, %0"
781                 : "=r" (have_cpuid)
782                 :
783                 : "%eax", "%edx"
784         );
785 #else
786         __asm {
787                 pushfd
788                 pop eax
789                 mov edx, eax
790                 xor eax, 0x200000
791                 push eax
792                 popfd
793                 pushfd
794                 pop eax
795                 xor eax, edx
796                 and eax, 0x200000
797                 mov have_cpuid, eax
798         }
799 #endif
800         if (have_cpuid) {
801                 /* Have to use the code manager to get around WinXP DEP */
802                 static CpuidFunc func = NULL;
803                 void *ptr;
804                 if (!func) {
805                         ptr = mono_global_codeman_reserve (sizeof (cpuid_impl));
806                         memcpy (ptr, cpuid_impl, sizeof (cpuid_impl));
807                         func = (CpuidFunc)ptr;
808                 }
809                 func (id, p_eax, p_ebx, p_ecx, p_edx);
810
811                 /*
812                  * We use this approach because of issues with gcc and pic code, see:
813                  * http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=7329
814                 __asm__ __volatile__ ("cpuid"
815                         : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
816                         : "a" (id));
817                 */
818                 return 1;
819         }
820         return 0;
821 #endif
822 }
823
824 /*
825  * Initialize the cpu to execute managed code.
826  */
827 void
828 mono_arch_cpu_init (void)
829 {
830         /* spec compliance requires running with double precision */
831 #ifndef _MSC_VER
832         guint16 fpcw;
833
834         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
835         fpcw &= ~X86_FPCW_PRECC_MASK;
836         fpcw |= X86_FPCW_PREC_DOUBLE;
837         __asm__  __volatile__ ("fldcw %0\n": : "m" (fpcw));
838         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
839 #else
840         _control87 (_PC_53, MCW_PC);
841 #endif
842 }
843
844 /*
845  * Initialize architecture specific code.
846  */
847 void
848 mono_arch_init (void)
849 {
850         InitializeCriticalSection (&mini_arch_mutex);
851
852         ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ);
853         bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
854         mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
855
856         mono_aot_register_jit_icall ("mono_x86_throw_exception", mono_x86_throw_exception);
857         mono_aot_register_jit_icall ("mono_x86_throw_corlib_exception", mono_x86_throw_corlib_exception);
858 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
859         mono_aot_register_jit_icall ("mono_x86_start_gsharedvt_call", mono_x86_start_gsharedvt_call);
860 #endif
861 }
862
863 /*
864  * Cleanup architecture specific code.
865  */
866 void
867 mono_arch_cleanup (void)
868 {
869         if (ss_trigger_page)
870                 mono_vfree (ss_trigger_page, mono_pagesize ());
871         if (bp_trigger_page)
872                 mono_vfree (bp_trigger_page, mono_pagesize ());
873         DeleteCriticalSection (&mini_arch_mutex);
874 }
875
876 /*
877  * This function returns the optimizations supported on this cpu.
878  */
879 guint32
880 mono_arch_cpu_optimizations (guint32 *exclude_mask)
881 {
882 #if !defined(__native_client__)
883         int eax, ebx, ecx, edx;
884         guint32 opts = 0;
885         
886         *exclude_mask = 0;
887
888         if (mono_aot_only)
889                 /* The cpuid function allocates from the global codeman */
890                 return opts;
891
892         /* Feature Flags function, flags returned in EDX. */
893         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
894                 if (edx & (1 << 15)) {
895                         opts |= MONO_OPT_CMOV;
896                         if (edx & 1)
897                                 opts |= MONO_OPT_FCMOV;
898                         else
899                                 *exclude_mask |= MONO_OPT_FCMOV;
900                 } else
901                         *exclude_mask |= MONO_OPT_CMOV;
902                 if (edx & (1 << 26))
903                         opts |= MONO_OPT_SSE2;
904                 else
905                         *exclude_mask |= MONO_OPT_SSE2;
906
907 #ifdef MONO_ARCH_SIMD_INTRINSICS
908                 /*SIMD intrinsics require at least SSE2.*/
909                 if (!(opts & MONO_OPT_SSE2))
910                         *exclude_mask |= MONO_OPT_SIMD;
911 #endif
912         }
913         return opts;
914 #else
915         return MONO_OPT_CMOV | MONO_OPT_FCMOV | MONO_OPT_SSE2;
916 #endif
917 }
918
919 /*
920  * This function test for all SSE functions supported.
921  *
922  * Returns a bitmask corresponding to all supported versions.
923  * 
924  */
925 guint32
926 mono_arch_cpu_enumerate_simd_versions (void)
927 {
928         int eax, ebx, ecx, edx;
929         guint32 sse_opts = 0;
930
931         if (mono_aot_only)
932                 /* The cpuid function allocates from the global codeman */
933                 return sse_opts;
934
935         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
936                 if (edx & (1 << 25))
937                         sse_opts |= SIMD_VERSION_SSE1;
938                 if (edx & (1 << 26))
939                         sse_opts |= SIMD_VERSION_SSE2;
940                 if (ecx & (1 << 0))
941                         sse_opts |= SIMD_VERSION_SSE3;
942                 if (ecx & (1 << 9))
943                         sse_opts |= SIMD_VERSION_SSSE3;
944                 if (ecx & (1 << 19))
945                         sse_opts |= SIMD_VERSION_SSE41;
946                 if (ecx & (1 << 20))
947                         sse_opts |= SIMD_VERSION_SSE42;
948         }
949
950         /* Yes, all this needs to be done to check for sse4a.
951            See: "Amd: CPUID Specification"
952          */
953         if (cpuid (0x80000000, &eax, &ebx, &ecx, &edx)) {
954                 /* eax greater or equal than 0x80000001, ebx = 'htuA', ecx = DMAc', edx = 'itne'*/
955                 if ((((unsigned int) eax) >= 0x80000001) && (ebx == 0x68747541) && (ecx == 0x444D4163) && (edx == 0x69746E65)) {
956                         cpuid (0x80000001, &eax, &ebx, &ecx, &edx);
957                         if (ecx & (1 << 6))
958                                 sse_opts |= SIMD_VERSION_SSE4a;
959                 }
960         }
961
962
963         return sse_opts;        
964 }
965
966 /*
967  * Determine whenever the trap whose info is in SIGINFO is caused by
968  * integer overflow.
969  */
970 gboolean
971 mono_arch_is_int_overflow (void *sigctx, void *info)
972 {
973         MonoContext ctx;
974         guint8* ip;
975
976         mono_arch_sigctx_to_monoctx (sigctx, &ctx);
977
978         ip = (guint8*)ctx.eip;
979
980         if ((ip [0] == 0xf7) && (x86_modrm_mod (ip [1]) == 0x3) && (x86_modrm_reg (ip [1]) == 0x7)) {
981                 gint32 reg;
982
983                 /* idiv REG */
984                 switch (x86_modrm_rm (ip [1])) {
985                 case X86_EAX:
986                         reg = ctx.eax;
987                         break;
988                 case X86_ECX:
989                         reg = ctx.ecx;
990                         break;
991                 case X86_EDX:
992                         reg = ctx.edx;
993                         break;
994                 case X86_EBX:
995                         reg = ctx.ebx;
996                         break;
997                 case X86_ESI:
998                         reg = ctx.esi;
999                         break;
1000                 case X86_EDI:
1001                         reg = ctx.edi;
1002                         break;
1003                 default:
1004                         g_assert_not_reached ();
1005                         reg = -1;
1006                 }
1007
1008                 if (reg == -1)
1009                         return TRUE;
1010         }
1011                         
1012         return FALSE;
1013 }
1014
1015 GList *
1016 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
1017 {
1018         GList *vars = NULL;
1019         int i;
1020
1021         for (i = 0; i < cfg->num_varinfo; i++) {
1022                 MonoInst *ins = cfg->varinfo [i];
1023                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
1024
1025                 /* unused vars */
1026                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
1027                         continue;
1028
1029                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
1030                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
1031                         continue;
1032
1033                 /* we dont allocate I1 to registers because there is no simply way to sign extend 
1034                  * 8bit quantities in caller saved registers on x86 */
1035                 if (mono_is_regsize_var (ins->inst_vtype) && (ins->inst_vtype->type != MONO_TYPE_I1)) {
1036                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
1037                         g_assert (i == vmv->idx);
1038                         vars = g_list_prepend (vars, vmv);
1039                 }
1040         }
1041
1042         vars = mono_varlist_sort (cfg, vars, 0);
1043
1044         return vars;
1045 }
1046
1047 GList *
1048 mono_arch_get_global_int_regs (MonoCompile *cfg)
1049 {
1050         GList *regs = NULL;
1051
1052         /* we can use 3 registers for global allocation */
1053         regs = g_list_prepend (regs, (gpointer)X86_EBX);
1054         regs = g_list_prepend (regs, (gpointer)X86_ESI);
1055         regs = g_list_prepend (regs, (gpointer)X86_EDI);
1056
1057         return regs;
1058 }
1059
1060 /*
1061  * mono_arch_regalloc_cost:
1062  *
1063  *  Return the cost, in number of memory references, of the action of 
1064  * allocating the variable VMV into a register during global register
1065  * allocation.
1066  */
1067 guint32
1068 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
1069 {
1070         MonoInst *ins = cfg->varinfo [vmv->idx];
1071
1072         if (cfg->method->save_lmf)
1073                 /* The register is already saved */
1074                 return (ins->opcode == OP_ARG) ? 1 : 0;
1075         else
1076                 /* push+pop+possible load if it is an argument */
1077                 return (ins->opcode == OP_ARG) ? 3 : 2;
1078 }
1079
1080 static void
1081 set_needs_stack_frame (MonoCompile *cfg, gboolean flag)
1082 {
1083         static int inited = FALSE;
1084         static int count = 0;
1085
1086         if (cfg->arch.need_stack_frame_inited) {
1087                 g_assert (cfg->arch.need_stack_frame == flag);
1088                 return;
1089         }
1090
1091         cfg->arch.need_stack_frame = flag;
1092         cfg->arch.need_stack_frame_inited = TRUE;
1093
1094         if (flag)
1095                 return;
1096
1097         if (!inited) {
1098                 mono_counters_register ("Could eliminate stack frame", MONO_COUNTER_INT|MONO_COUNTER_JIT, &count);
1099                 inited = TRUE;
1100         }
1101         ++count;
1102
1103         //g_print ("will eliminate %s.%s.%s\n", cfg->method->klass->name_space, cfg->method->klass->name, cfg->method->name);
1104 }
1105
1106 static gboolean
1107 needs_stack_frame (MonoCompile *cfg)
1108 {
1109         MonoMethodSignature *sig;
1110         MonoMethodHeader *header;
1111         gboolean result = FALSE;
1112
1113 #if defined(__APPLE__)
1114         /*OSX requires stack frame code to have the correct alignment. */
1115         return TRUE;
1116 #endif
1117
1118         if (cfg->arch.need_stack_frame_inited)
1119                 return cfg->arch.need_stack_frame;
1120
1121         header = cfg->header;
1122         sig = mono_method_signature (cfg->method);
1123
1124         if (cfg->disable_omit_fp)
1125                 result = TRUE;
1126         else if (cfg->flags & MONO_CFG_HAS_ALLOCA)
1127                 result = TRUE;
1128         else if (cfg->method->save_lmf)
1129                 result = TRUE;
1130         else if (cfg->stack_offset)
1131                 result = TRUE;
1132         else if (cfg->param_area)
1133                 result = TRUE;
1134         else if (cfg->flags & (MONO_CFG_HAS_CALLS | MONO_CFG_HAS_ALLOCA | MONO_CFG_HAS_TAIL))
1135                 result = TRUE;
1136         else if (header->num_clauses)
1137                 result = TRUE;
1138         else if (sig->param_count + sig->hasthis)
1139                 result = TRUE;
1140         else if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1141                 result = TRUE;
1142         else if ((mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method)) ||
1143                 (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE))
1144                 result = TRUE;
1145
1146         set_needs_stack_frame (cfg, result);
1147
1148         return cfg->arch.need_stack_frame;
1149 }
1150
1151 /*
1152  * Set var information according to the calling convention. X86 version.
1153  * The locals var stuff should most likely be split in another method.
1154  */
1155 void
1156 mono_arch_allocate_vars (MonoCompile *cfg)
1157 {
1158         MonoMethodSignature *sig;
1159         MonoMethodHeader *header;
1160         MonoInst *inst;
1161         guint32 locals_stack_size, locals_stack_align;
1162         int i, offset;
1163         gint32 *offsets;
1164         CallInfo *cinfo;
1165
1166         header = cfg->header;
1167         sig = mono_method_signature (cfg->method);
1168
1169         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1170
1171         cfg->frame_reg = X86_EBP;
1172         offset = 0;
1173
1174         /* Reserve space to save LMF and caller saved registers */
1175
1176         if (cfg->method->save_lmf) {
1177                 offset += sizeof (MonoLMF);
1178         } else {
1179                 if (cfg->used_int_regs & (1 << X86_EBX)) {
1180                         offset += 4;
1181                 }
1182
1183                 if (cfg->used_int_regs & (1 << X86_EDI)) {
1184                         offset += 4;
1185                 }
1186
1187                 if (cfg->used_int_regs & (1 << X86_ESI)) {
1188                         offset += 4;
1189                 }
1190         }
1191
1192         switch (cinfo->ret.storage) {
1193         case ArgValuetypeInReg:
1194                 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
1195                 offset += 8;
1196                 cfg->ret->opcode = OP_REGOFFSET;
1197                 cfg->ret->inst_basereg = X86_EBP;
1198                 cfg->ret->inst_offset = - offset;
1199                 break;
1200         default:
1201                 break;
1202         }
1203
1204         /* Allocate locals */
1205         offsets = mono_allocate_stack_slots (cfg, TRUE, &locals_stack_size, &locals_stack_align);
1206         if (locals_stack_size > MONO_ARCH_MAX_FRAME_SIZE) {
1207                 char *mname = mono_method_full_name (cfg->method, TRUE);
1208                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
1209                 cfg->exception_message = g_strdup_printf ("Method %s stack is too big.", mname);
1210                 g_free (mname);
1211                 return;
1212         }
1213         if (locals_stack_align) {
1214                 int prev_offset = offset;
1215
1216                 offset += (locals_stack_align - 1);
1217                 offset &= ~(locals_stack_align - 1);
1218
1219                 while (prev_offset < offset) {
1220                         prev_offset += 4;
1221                         mini_gc_set_slot_type_from_fp (cfg, - prev_offset, SLOT_NOREF);
1222                 }
1223         }
1224         cfg->locals_min_stack_offset = - (offset + locals_stack_size);
1225         cfg->locals_max_stack_offset = - offset;
1226         /*
1227          * EBP is at alignment 8 % MONO_ARCH_FRAME_ALIGNMENT, so if we
1228          * have locals larger than 8 bytes we need to make sure that
1229          * they have the appropriate offset.
1230          */
1231         if (MONO_ARCH_FRAME_ALIGNMENT > 8 && locals_stack_align > 8)
1232                 offset += MONO_ARCH_FRAME_ALIGNMENT - sizeof (gpointer) * 2;
1233         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
1234                 if (offsets [i] != -1) {
1235                         MonoInst *inst = cfg->varinfo [i];
1236                         inst->opcode = OP_REGOFFSET;
1237                         inst->inst_basereg = X86_EBP;
1238                         inst->inst_offset = - (offset + offsets [i]);
1239                         //printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
1240                 }
1241         }
1242         offset += locals_stack_size;
1243
1244
1245         /*
1246          * Allocate arguments+return value
1247          */
1248
1249         switch (cinfo->ret.storage) {
1250         case ArgOnStack:
1251                 if (cfg->vret_addr) {
1252                         /* 
1253                          * In the new IR, the cfg->vret_addr variable represents the
1254                          * vtype return value.
1255                          */
1256                         cfg->vret_addr->opcode = OP_REGOFFSET;
1257                         cfg->vret_addr->inst_basereg = cfg->frame_reg;
1258                         cfg->vret_addr->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
1259                         if (G_UNLIKELY (cfg->verbose_level > 1)) {
1260                                 printf ("vret_addr =");
1261                                 mono_print_ins (cfg->vret_addr);
1262                         }
1263                 } else {
1264                         cfg->ret->opcode = OP_REGOFFSET;
1265                         cfg->ret->inst_basereg = X86_EBP;
1266                         cfg->ret->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
1267                 }
1268                 break;
1269         case ArgValuetypeInReg:
1270                 break;
1271         case ArgInIReg:
1272                 cfg->ret->opcode = OP_REGVAR;
1273                 cfg->ret->inst_c0 = cinfo->ret.reg;
1274                 cfg->ret->dreg = cinfo->ret.reg;
1275                 break;
1276         case ArgNone:
1277         case ArgOnFloatFpStack:
1278         case ArgOnDoubleFpStack:
1279                 break;
1280         default:
1281                 g_assert_not_reached ();
1282         }
1283
1284         if (sig->call_convention == MONO_CALL_VARARG) {
1285                 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
1286                 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
1287         }
1288
1289         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
1290                 ArgInfo *ainfo = &cinfo->args [i];
1291                 inst = cfg->args [i];
1292                 if (inst->opcode != OP_REGVAR) {
1293                         inst->opcode = OP_REGOFFSET;
1294                         inst->inst_basereg = X86_EBP;
1295                 }
1296                 inst->inst_offset = ainfo->offset + ARGS_OFFSET;
1297         }
1298
1299         cfg->stack_offset = offset;
1300 }
1301
1302 void
1303 mono_arch_create_vars (MonoCompile *cfg)
1304 {
1305         MonoMethodSignature *sig;
1306         CallInfo *cinfo;
1307
1308         sig = mono_method_signature (cfg->method);
1309
1310         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1311
1312         if (cinfo->ret.storage == ArgValuetypeInReg)
1313                 cfg->ret_var_is_local = TRUE;
1314         if ((cinfo->ret.storage != ArgValuetypeInReg) && (MONO_TYPE_ISSTRUCT (sig->ret) || mini_is_gsharedvt_variable_type (cfg, sig->ret))) {
1315                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1316         }
1317
1318         cfg->arch_eh_jit_info = 1;
1319 }
1320
1321 /*
1322  * It is expensive to adjust esp for each individual fp argument pushed on the stack
1323  * so we try to do it just once when we have multiple fp arguments in a row.
1324  * We don't use this mechanism generally because for int arguments the generated code
1325  * is slightly bigger and new generation cpus optimize away the dependency chains
1326  * created by push instructions on the esp value.
1327  * fp_arg_setup is the first argument in the execution sequence where the esp register
1328  * is modified.
1329  */
1330 static G_GNUC_UNUSED int
1331 collect_fp_stack_space (MonoMethodSignature *sig, int start_arg, int *fp_arg_setup)
1332 {
1333         int fp_space = 0;
1334         MonoType *t;
1335
1336         for (; start_arg < sig->param_count; ++start_arg) {
1337                 t = mini_type_get_underlying_type (NULL, sig->params [start_arg]);
1338                 if (!t->byref && t->type == MONO_TYPE_R8) {
1339                         fp_space += sizeof (double);
1340                         *fp_arg_setup = start_arg;
1341                 } else {
1342                         break;
1343                 }
1344         }
1345         return fp_space;
1346 }
1347
1348 static void
1349 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1350 {
1351         MonoMethodSignature *tmp_sig;
1352         int sig_reg;
1353
1354         /*
1355          * mono_ArgIterator_Setup assumes the signature cookie is 
1356          * passed first and all the arguments which were before it are
1357          * passed on the stack after the signature. So compensate by 
1358          * passing a different signature.
1359          */
1360         tmp_sig = mono_metadata_signature_dup (call->signature);
1361         tmp_sig->param_count -= call->signature->sentinelpos;
1362         tmp_sig->sentinelpos = 0;
1363         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1364
1365         if (cfg->compile_aot) {
1366                 sig_reg = mono_alloc_ireg (cfg);
1367                 MONO_EMIT_NEW_SIGNATURECONST (cfg, sig_reg, tmp_sig);
1368                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, sig_reg);
1369         } else {
1370                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_X86_PUSH_IMM, -1, -1, tmp_sig);
1371         }
1372 }
1373
1374 #ifdef ENABLE_LLVM
1375 LLVMCallInfo*
1376 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
1377 {
1378         int i, n;
1379         CallInfo *cinfo;
1380         ArgInfo *ainfo;
1381         LLVMCallInfo *linfo;
1382         MonoType *t;
1383
1384         n = sig->param_count + sig->hasthis;
1385
1386         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1387
1388         linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
1389
1390         /*
1391          * LLVM always uses the native ABI while we use our own ABI, the
1392          * only difference is the handling of vtypes:
1393          * - we only pass/receive them in registers in some cases, and only 
1394          *   in 1 or 2 integer registers.
1395          */
1396         if (cinfo->ret.storage == ArgValuetypeInReg) {
1397                 if (sig->pinvoke) {
1398                         cfg->exception_message = g_strdup ("pinvoke + vtypes");
1399                         cfg->disable_llvm = TRUE;
1400                         return linfo;
1401                 }
1402
1403                 cfg->exception_message = g_strdup ("vtype ret in call");
1404                 cfg->disable_llvm = TRUE;
1405                 /*
1406                 linfo->ret.storage = LLVMArgVtypeInReg;
1407                 for (j = 0; j < 2; ++j)
1408                         linfo->ret.pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, cinfo->ret.pair_storage [j]);
1409                 */
1410         }
1411
1412         if (mini_type_is_vtype (cfg, sig->ret) && cinfo->ret.storage == ArgInIReg) {
1413                 /* Vtype returned using a hidden argument */
1414                 linfo->ret.storage = LLVMArgVtypeRetAddr;
1415                 linfo->vret_arg_index = cinfo->vret_arg_index;
1416         }
1417
1418         if (mini_type_is_vtype (cfg, sig->ret) && cinfo->ret.storage != ArgInIReg) {
1419                 // FIXME:
1420                 cfg->exception_message = g_strdup ("vtype ret in call");
1421                 cfg->disable_llvm = TRUE;
1422         }
1423
1424         for (i = 0; i < n; ++i) {
1425                 ainfo = cinfo->args + i;
1426
1427                 if (i >= sig->hasthis)
1428                         t = sig->params [i - sig->hasthis];
1429                 else
1430                         t = &mono_defaults.int_class->byval_arg;
1431
1432                 linfo->args [i].storage = LLVMArgNone;
1433
1434                 switch (ainfo->storage) {
1435                 case ArgInIReg:
1436                         linfo->args [i].storage = LLVMArgInIReg;
1437                         break;
1438                 case ArgInDoubleSSEReg:
1439                 case ArgInFloatSSEReg:
1440                         linfo->args [i].storage = LLVMArgInFPReg;
1441                         break;
1442                 case ArgOnStack:
1443                         if (mini_type_is_vtype (cfg, t)) {
1444                                 if (mono_class_value_size (mono_class_from_mono_type (t), NULL) == 0)
1445                                 /* LLVM seems to allocate argument space for empty structures too */
1446                                         linfo->args [i].storage = LLVMArgNone;
1447                                 else
1448                                         linfo->args [i].storage = LLVMArgVtypeByVal;
1449                         } else {
1450                                 linfo->args [i].storage = LLVMArgInIReg;
1451                                 if (t->byref) {
1452                                         if (t->type == MONO_TYPE_R4)
1453                                                 linfo->args [i].storage = LLVMArgInFPReg;
1454                                         else if (t->type == MONO_TYPE_R8)
1455                                                 linfo->args [i].storage = LLVMArgInFPReg;
1456                                 }
1457                         }
1458                         break;
1459                 case ArgValuetypeInReg:
1460                         if (sig->pinvoke) {
1461                                 cfg->exception_message = g_strdup ("pinvoke + vtypes");
1462                                 cfg->disable_llvm = TRUE;
1463                                 return linfo;
1464                         }
1465
1466                         cfg->exception_message = g_strdup ("vtype arg");
1467                         cfg->disable_llvm = TRUE;
1468                         /*
1469                         linfo->args [i].storage = LLVMArgVtypeInReg;
1470                         for (j = 0; j < 2; ++j)
1471                                 linfo->args [i].pair_storage [j] = arg_storage_to_llvm_arg_storage (cfg, ainfo->pair_storage [j]);
1472                         */
1473                         break;
1474                 case ArgGSharedVt:
1475                         linfo->args [i].storage = LLVMArgGSharedVt;
1476                         break;
1477                 default:
1478                         cfg->exception_message = g_strdup ("ainfo->storage");
1479                         cfg->disable_llvm = TRUE;
1480                         break;
1481                 }
1482         }
1483
1484         return linfo;
1485 }
1486 #endif
1487
1488 static void
1489 emit_gc_param_slot_def (MonoCompile *cfg, int sp_offset, MonoType *t)
1490 {
1491         if (cfg->compute_gc_maps) {
1492                 MonoInst *def;
1493
1494                 /* On x86, the offsets are from the sp value before the start of the call sequence */
1495                 if (t == NULL)
1496                         t = &mono_defaults.int_class->byval_arg;
1497                 EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, sp_offset, t);
1498         }
1499 }
1500
1501 void
1502 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1503 {
1504         MonoInst *arg, *in;
1505         MonoMethodSignature *sig;
1506         int i, j, n;
1507         CallInfo *cinfo;
1508         int sentinelpos = 0, sp_offset = 0;
1509
1510         sig = call->signature;
1511         n = sig->param_count + sig->hasthis;
1512
1513         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1514
1515         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1516                 sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0);
1517
1518         if (cinfo->need_stack_align) {
1519                 MONO_INST_NEW (cfg, arg, OP_SUB_IMM);
1520                 arg->dreg = X86_ESP;
1521                 arg->sreg1 = X86_ESP;
1522                 arg->inst_imm = cinfo->stack_align_amount;
1523                 MONO_ADD_INS (cfg->cbb, arg);
1524                 for (i = 0; i < cinfo->stack_align_amount; i += sizeof (mgreg_t)) {
1525                         sp_offset += 4;
1526
1527                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1528                 }
1529         }
1530
1531         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1532                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1533                         /*
1534                          * Tell the JIT to use a more efficient calling convention: call using
1535                          * OP_CALL, compute the result location after the call, and save the 
1536                          * result there.
1537                          */
1538                         call->vret_in_reg = TRUE;
1539                         if (call->vret_var)
1540                                 NULLIFY_INS (call->vret_var);
1541                 }
1542         }
1543
1544         // FIXME: Emit EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF everywhere 
1545
1546         /* Handle the case where there are no implicit arguments */
1547         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) {
1548                 emit_sig_cookie (cfg, call, cinfo);
1549                 sp_offset += 4;
1550                 emit_gc_param_slot_def (cfg, sp_offset, NULL);
1551         }
1552
1553         /* Arguments are pushed in the reverse order */
1554         for (i = n - 1; i >= 0; i --) {
1555                 ArgInfo *ainfo = cinfo->args + i;
1556                 MonoType *orig_type, *t;
1557                 int argsize;
1558
1559                 if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && i == 0) {
1560                         /* Push the vret arg before the first argument */
1561                         MonoInst *vtarg;
1562                         MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1563                         vtarg->type = STACK_MP;
1564                         vtarg->sreg1 = call->vret_var->dreg;
1565                         MONO_ADD_INS (cfg->cbb, vtarg);
1566                         sp_offset += 4;
1567                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1568                 }
1569
1570                 if (i >= sig->hasthis)
1571                         t = sig->params [i - sig->hasthis];
1572                 else
1573                         t = &mono_defaults.int_class->byval_arg;
1574                 orig_type = t;
1575                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1576
1577                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
1578
1579                 in = call->args [i];
1580                 arg->cil_code = in->cil_code;
1581                 arg->sreg1 = in->dreg;
1582                 arg->type = in->type;
1583
1584                 g_assert (in->dreg != -1);
1585
1586                 if (ainfo->storage == ArgGSharedVt) {
1587                         arg->opcode = OP_OUTARG_VT;
1588                         arg->sreg1 = in->dreg;
1589                         arg->klass = in->klass;
1590                         sp_offset += 4;
1591                         MONO_ADD_INS (cfg->cbb, arg);
1592                 } else if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
1593                         guint32 align;
1594                         guint32 size;
1595
1596                         g_assert (in->klass);
1597
1598                         if (t->type == MONO_TYPE_TYPEDBYREF) {
1599                                 size = sizeof (MonoTypedRef);
1600                                 align = sizeof (gpointer);
1601                         }
1602                         else {
1603                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, &in->klass->byval_arg, &align, sig->pinvoke);
1604                         }
1605
1606                         if (size > 0) {
1607                                 arg->opcode = OP_OUTARG_VT;
1608                                 arg->sreg1 = in->dreg;
1609                                 arg->klass = in->klass;
1610                                 arg->backend.size = size;
1611
1612                                 MONO_ADD_INS (cfg->cbb, arg);
1613                                 sp_offset += size;
1614                                 emit_gc_param_slot_def (cfg, sp_offset, orig_type);
1615                         }
1616                 } else {
1617                         argsize = 4;
1618
1619                         switch (ainfo->storage) {
1620                         case ArgOnStack:
1621                                 arg->opcode = OP_X86_PUSH;
1622                                 if (!t->byref) {
1623                                         if (t->type == MONO_TYPE_R4) {
1624                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
1625                                                 arg->opcode = OP_STORER4_MEMBASE_REG;
1626                                                 arg->inst_destbasereg = X86_ESP;
1627                                                 arg->inst_offset = 0;
1628                                                 argsize = 4;
1629                                         } else if (t->type == MONO_TYPE_R8) {
1630                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
1631                                                 arg->opcode = OP_STORER8_MEMBASE_REG;
1632                                                 arg->inst_destbasereg = X86_ESP;
1633                                                 arg->inst_offset = 0;
1634                                                 argsize = 8;
1635                                         } else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8) {
1636                                                 arg->sreg1 ++;
1637                                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 2);
1638                                                 sp_offset += 4;
1639                                         }
1640                                 }
1641                                 break;
1642                         default:
1643                                 g_assert_not_reached ();
1644                         }
1645                         
1646                         MONO_ADD_INS (cfg->cbb, arg);
1647
1648                         sp_offset += argsize;
1649
1650                         if (cfg->compute_gc_maps) {
1651                                 if (argsize == 4) {
1652                                         /* FIXME: The == STACK_OBJ check might be fragile ? */
1653                                         if (sig->hasthis && i == 0 && call->args [i]->type == STACK_OBJ) {
1654                                                 /* this */
1655                                                 if (call->need_unbox_trampoline)
1656                                                         /* The unbox trampoline transforms this into a managed pointer */
1657                                                         emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.int_class->this_arg);
1658                                                 else
1659                                                         emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.object_class->byval_arg);
1660                                         } else {
1661                                                 emit_gc_param_slot_def (cfg, sp_offset, orig_type);
1662                                         }
1663                                 } else {
1664                                         /* i8/r8 */
1665                                         for (j = 0; j < argsize; j += 4)
1666                                                 emit_gc_param_slot_def (cfg, sp_offset - j, NULL);
1667                                 }
1668                         }
1669                 }
1670
1671                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) {
1672                         /* Emit the signature cookie just before the implicit arguments */
1673                         emit_sig_cookie (cfg, call, cinfo);
1674                         sp_offset += 4;
1675                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1676                 }
1677         }
1678
1679         if (sig->ret && (MONO_TYPE_ISSTRUCT (sig->ret) || cinfo->vtype_retaddr)) {
1680                 MonoInst *vtarg;
1681
1682                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1683                         /* Already done */
1684                 }
1685                 else if (cinfo->ret.storage == ArgInIReg) {
1686                         NOT_IMPLEMENTED;
1687                         /* The return address is passed in a register */
1688                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1689                         vtarg->sreg1 = call->inst.dreg;
1690                         vtarg->dreg = mono_alloc_ireg (cfg);
1691                         MONO_ADD_INS (cfg->cbb, vtarg);
1692                                 
1693                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
1694                 } else if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) {
1695                         MonoInst *vtarg;
1696                         MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1697                         vtarg->type = STACK_MP;
1698                         vtarg->sreg1 = call->vret_var->dreg;
1699                         MONO_ADD_INS (cfg->cbb, vtarg);
1700                         sp_offset += 4;
1701                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1702                 }
1703
1704                 /* if the function returns a struct on stack, the called method already does a ret $0x4 */
1705                 if (cinfo->ret.storage != ArgValuetypeInReg)
1706                         cinfo->stack_usage -= 4;
1707         }
1708
1709         call->stack_usage = cinfo->stack_usage;
1710         call->stack_align_amount = cinfo->stack_align_amount;
1711         cfg->arch.param_area_size = MAX (cfg->arch.param_area_size, sp_offset);
1712 }
1713
1714 void
1715 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1716 {
1717         MonoInst *arg;
1718         int size = ins->backend.size;
1719
1720         if (cfg->gsharedvt && mini_is_gsharedvt_klass (cfg, ins->klass)) {
1721                 /* Pass by addr */
1722                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
1723                 arg->sreg1 = src->dreg;
1724                 MONO_ADD_INS (cfg->cbb, arg);
1725         } else if (size <= 4) {
1726                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_MEMBASE);
1727                 arg->sreg1 = src->dreg;
1728
1729                 MONO_ADD_INS (cfg->cbb, arg);
1730         } else if (size <= 20) {        
1731                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, ALIGN_TO (size, 4));
1732                 mini_emit_memcpy (cfg, X86_ESP, 0, src->dreg, 0, size, 4);
1733         } else {
1734                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_OBJ);
1735                 arg->inst_basereg = src->dreg;
1736                 arg->inst_offset = 0;
1737                 arg->inst_imm = size;
1738                                         
1739                 MONO_ADD_INS (cfg->cbb, arg);
1740         }
1741 }
1742
1743 void
1744 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1745 {
1746         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1747
1748         if (!ret->byref) {
1749                 if (ret->type == MONO_TYPE_R4) {
1750                         if (COMPILE_LLVM (cfg))
1751                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1752                         /* Nothing to do */
1753                         return;
1754                 } else if (ret->type == MONO_TYPE_R8) {
1755                         if (COMPILE_LLVM (cfg))
1756                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1757                         /* Nothing to do */
1758                         return;
1759                 } else if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1760                         if (COMPILE_LLVM (cfg))
1761                                 MONO_EMIT_NEW_UNALU (cfg, OP_LMOVE, cfg->ret->dreg, val->dreg);
1762                         else {
1763                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EAX, val->dreg + 1);
1764                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EDX, val->dreg + 2);
1765                         }
1766                         return;
1767                 }
1768         }
1769                         
1770         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1771 }
1772
1773 /*
1774  * Allow tracing to work with this interface (with an optional argument)
1775  */
1776 void*
1777 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1778 {
1779         guchar *code = p;
1780
1781         g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
1782         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
1783
1784         /* if some args are passed in registers, we need to save them here */
1785         x86_push_reg (code, X86_EBP);
1786
1787         if (cfg->compile_aot) {
1788                 x86_push_imm (code, cfg->method);
1789                 x86_mov_reg_imm (code, X86_EAX, func);
1790                 x86_call_reg (code, X86_EAX);
1791         } else {
1792                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, cfg->method);
1793                 x86_push_imm (code, cfg->method);
1794                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1795                 x86_call_code (code, 0);
1796         }
1797         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT);
1798
1799         return code;
1800 }
1801
1802 enum {
1803         SAVE_NONE,
1804         SAVE_STRUCT,
1805         SAVE_EAX,
1806         SAVE_EAX_EDX,
1807         SAVE_FP
1808 };
1809
1810 void*
1811 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1812 {
1813         guchar *code = p;
1814         int arg_size = 0, stack_usage = 0, save_mode = SAVE_NONE;
1815         MonoMethod *method = cfg->method;
1816         MonoType *ret_type = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1817
1818         switch (ret_type->type) {
1819         case MONO_TYPE_VOID:
1820                 /* special case string .ctor icall */
1821                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class) {
1822                         save_mode = SAVE_EAX;
1823                         stack_usage = enable_arguments ? 8 : 4;
1824                 } else
1825                         save_mode = SAVE_NONE;
1826                 break;
1827         case MONO_TYPE_I8:
1828         case MONO_TYPE_U8:
1829                 save_mode = SAVE_EAX_EDX;
1830                 stack_usage = enable_arguments ? 16 : 8;
1831                 break;
1832         case MONO_TYPE_R4:
1833         case MONO_TYPE_R8:
1834                 save_mode = SAVE_FP;
1835                 stack_usage = enable_arguments ? 16 : 8;
1836                 break;
1837         case MONO_TYPE_GENERICINST:
1838                 if (!mono_type_generic_inst_is_valuetype (ret_type)) {
1839                         save_mode = SAVE_EAX;
1840                         stack_usage = enable_arguments ? 8 : 4;
1841                         break;
1842                 }
1843                 /* Fall through */
1844         case MONO_TYPE_VALUETYPE:
1845                 // FIXME: Handle SMALL_STRUCT_IN_REG here for proper alignment on darwin-x86
1846                 save_mode = SAVE_STRUCT;
1847                 stack_usage = enable_arguments ? 4 : 0;
1848                 break;
1849         default:
1850                 save_mode = SAVE_EAX;
1851                 stack_usage = enable_arguments ? 8 : 4;
1852                 break;
1853         }
1854
1855         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - stack_usage - 4);
1856
1857         switch (save_mode) {
1858         case SAVE_EAX_EDX:
1859                 x86_push_reg (code, X86_EDX);
1860                 x86_push_reg (code, X86_EAX);
1861                 if (enable_arguments) {
1862                         x86_push_reg (code, X86_EDX);
1863                         x86_push_reg (code, X86_EAX);
1864                         arg_size = 8;
1865                 }
1866                 break;
1867         case SAVE_EAX:
1868                 x86_push_reg (code, X86_EAX);
1869                 if (enable_arguments) {
1870                         x86_push_reg (code, X86_EAX);
1871                         arg_size = 4;
1872                 }
1873                 break;
1874         case SAVE_FP:
1875                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1876                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1877                 if (enable_arguments) {
1878                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1879                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1880                         arg_size = 8;
1881                 }
1882                 break;
1883         case SAVE_STRUCT:
1884                 if (enable_arguments) {
1885                         x86_push_membase (code, X86_EBP, 8);
1886                         arg_size = 4;
1887                 }
1888                 break;
1889         case SAVE_NONE:
1890         default:
1891                 break;
1892         }
1893
1894         if (cfg->compile_aot) {
1895                 x86_push_imm (code, method);
1896                 x86_mov_reg_imm (code, X86_EAX, func);
1897                 x86_call_reg (code, X86_EAX);
1898         } else {
1899                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method);
1900                 x86_push_imm (code, method);
1901                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1902                 x86_call_code (code, 0);
1903         }
1904
1905         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
1906
1907         switch (save_mode) {
1908         case SAVE_EAX_EDX:
1909                 x86_pop_reg (code, X86_EAX);
1910                 x86_pop_reg (code, X86_EDX);
1911                 break;
1912         case SAVE_EAX:
1913                 x86_pop_reg (code, X86_EAX);
1914                 break;
1915         case SAVE_FP:
1916                 x86_fld_membase (code, X86_ESP, 0, TRUE);
1917                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1918                 break;
1919         case SAVE_NONE:
1920         default:
1921                 break;
1922         }
1923         
1924         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - stack_usage);
1925
1926         return code;
1927 }
1928
1929 #define EMIT_COND_BRANCH(ins,cond,sign) \
1930 if (ins->inst_true_bb->native_offset) { \
1931         x86_branch (code, cond, cfg->native_code + ins->inst_true_bb->native_offset, sign); \
1932 } else { \
1933         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1934         if ((cfg->opt & MONO_OPT_BRANCH) && \
1935             x86_is_imm8 (ins->inst_true_bb->max_offset - cpos)) \
1936                 x86_branch8 (code, cond, 0, sign); \
1937         else \
1938                 x86_branch32 (code, cond, 0, sign); \
1939 }
1940
1941 /*  
1942  *      Emit an exception if condition is fail and
1943  *  if possible do a directly branch to target 
1944  */
1945 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
1946         do {                                                        \
1947                 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1948                 if (tins == NULL) {                                                                             \
1949                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1950                                         MONO_PATCH_INFO_EXC, exc_name);  \
1951                         x86_branch32 (code, cond, 0, signed);               \
1952                 } else {        \
1953                         EMIT_COND_BRANCH (tins, cond, signed);  \
1954                 }                       \
1955         } while (0); 
1956
1957 #define EMIT_FPCOMPARE(code) do { \
1958         x86_fcompp (code); \
1959         x86_fnstsw (code); \
1960 } while (0); 
1961
1962
1963 static guint8*
1964 emit_call (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointer data)
1965 {
1966         gboolean needs_paddings = TRUE;
1967         guint32 pad_size;
1968         MonoJumpInfo *jinfo = NULL;
1969
1970         if (cfg->abs_patches) {
1971                 jinfo = g_hash_table_lookup (cfg->abs_patches, data);
1972                 if (jinfo && jinfo->type == MONO_PATCH_INFO_JIT_ICALL_ADDR)
1973                         needs_paddings = FALSE;
1974         }
1975
1976         if (cfg->compile_aot)
1977                 needs_paddings = FALSE;
1978         /*The address must be 4 bytes aligned to avoid spanning multiple cache lines.
1979         This is required for code patching to be safe on SMP machines.
1980         */
1981         pad_size = (guint32)(code + 1 - cfg->native_code) & 0x3;
1982 #ifndef __native_client_codegen__
1983         if (needs_paddings && pad_size)
1984                 x86_padding (code, 4 - pad_size);
1985 #endif
1986
1987         mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
1988         x86_call_code (code, 0);
1989
1990         return code;
1991 }
1992
1993 #define INST_IGNORES_CFLAGS(opcode) (!(((opcode) == OP_ADC) || ((opcode) == OP_IADC) || ((opcode) == OP_ADC_IMM) || ((opcode) == OP_IADC_IMM) || ((opcode) == OP_SBB) || ((opcode) == OP_ISBB) || ((opcode) == OP_SBB_IMM) || ((opcode) == OP_ISBB_IMM)))
1994
1995 /*
1996  * mono_peephole_pass_1:
1997  *
1998  *   Perform peephole opts which should/can be performed before local regalloc
1999  */
2000 void
2001 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2002 {
2003         MonoInst *ins, *n;
2004
2005         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2006                 MonoInst *last_ins = ins->prev;
2007
2008                 switch (ins->opcode) {
2009                 case OP_IADD_IMM:
2010                 case OP_ADD_IMM:
2011                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
2012                                 /* 
2013                                  * X86_LEA is like ADD, but doesn't have the
2014                                  * sreg1==dreg restriction.
2015                                  */
2016                                 ins->opcode = OP_X86_LEA_MEMBASE;
2017                                 ins->inst_basereg = ins->sreg1;
2018                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2019                                 ins->opcode = OP_X86_INC_REG;
2020                         break;
2021                 case OP_SUB_IMM:
2022                 case OP_ISUB_IMM:
2023                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
2024                                 ins->opcode = OP_X86_LEA_MEMBASE;
2025                                 ins->inst_basereg = ins->sreg1;
2026                                 ins->inst_imm = -ins->inst_imm;
2027                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2028                                 ins->opcode = OP_X86_DEC_REG;
2029                         break;
2030                 case OP_COMPARE_IMM:
2031                 case OP_ICOMPARE_IMM:
2032                         /* OP_COMPARE_IMM (reg, 0) 
2033                          * --> 
2034                          * OP_X86_TEST_NULL (reg) 
2035                          */
2036                         if (!ins->inst_imm)
2037                                 ins->opcode = OP_X86_TEST_NULL;
2038                         break;
2039                 case OP_X86_COMPARE_MEMBASE_IMM:
2040                         /* 
2041                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
2042                          * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm
2043                          * -->
2044                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
2045                          * OP_COMPARE_IMM reg, imm
2046                          *
2047                          * Note: if imm = 0 then OP_COMPARE_IMM replaced with OP_X86_TEST_NULL
2048                          */
2049                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2050                             ins->inst_basereg == last_ins->inst_destbasereg &&
2051                             ins->inst_offset == last_ins->inst_offset) {
2052                                         ins->opcode = OP_COMPARE_IMM;
2053                                         ins->sreg1 = last_ins->sreg1;
2054
2055                                         /* check if we can remove cmp reg,0 with test null */
2056                                         if (!ins->inst_imm)
2057                                                 ins->opcode = OP_X86_TEST_NULL;
2058                                 }
2059
2060                         break;                  
2061                 case OP_X86_PUSH_MEMBASE:
2062                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG ||
2063                                          last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2064                             ins->inst_basereg == last_ins->inst_destbasereg &&
2065                             ins->inst_offset == last_ins->inst_offset) {
2066                                     ins->opcode = OP_X86_PUSH;
2067                                     ins->sreg1 = last_ins->sreg1;
2068                         }
2069                         break;
2070                 }
2071
2072                 mono_peephole_ins (bb, ins);
2073         }
2074 }
2075
2076 void
2077 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2078 {
2079         MonoInst *ins, *n;
2080
2081         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2082                 switch (ins->opcode) {
2083                 case OP_ICONST:
2084                         /* reg = 0 -> XOR (reg, reg) */
2085                         /* XOR sets cflags on x86, so we cant do it always */
2086                         if (ins->inst_c0 == 0 && (!ins->next || (ins->next && INST_IGNORES_CFLAGS (ins->next->opcode)))) {
2087                                 MonoInst *ins2;
2088
2089                                 ins->opcode = OP_IXOR;
2090                                 ins->sreg1 = ins->dreg;
2091                                 ins->sreg2 = ins->dreg;
2092
2093                                 /* 
2094                                  * Convert succeeding STORE_MEMBASE_IMM 0 ins to STORE_MEMBASE_REG 
2095                                  * since it takes 3 bytes instead of 7.
2096                                  */
2097                                 for (ins2 = ins->next; ins2; ins2 = ins2->next) {
2098                                         if ((ins2->opcode == OP_STORE_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
2099                                                 ins2->opcode = OP_STORE_MEMBASE_REG;
2100                                                 ins2->sreg1 = ins->dreg;
2101                                         }
2102                                         else if ((ins2->opcode == OP_STOREI4_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
2103                                                 ins2->opcode = OP_STOREI4_MEMBASE_REG;
2104                                                 ins2->sreg1 = ins->dreg;
2105                                         }
2106                                         else if ((ins2->opcode == OP_STOREI1_MEMBASE_IMM) || (ins2->opcode == OP_STOREI2_MEMBASE_IMM)) {
2107                                                 /* Continue iteration */
2108                                         }
2109                                         else
2110                                                 break;
2111                                 }
2112                         }
2113                         break;
2114                 case OP_IADD_IMM:
2115                 case OP_ADD_IMM:
2116                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2117                                 ins->opcode = OP_X86_INC_REG;
2118                         break;
2119                 case OP_ISUB_IMM:
2120                 case OP_SUB_IMM:
2121                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2122                                 ins->opcode = OP_X86_DEC_REG;
2123                         break;
2124                 }
2125
2126                 mono_peephole_ins (bb, ins);
2127         }
2128 }
2129
2130 /*
2131  * mono_arch_lowering_pass:
2132  *
2133  *  Converts complex opcodes into simpler ones so that each IR instruction
2134  * corresponds to one machine instruction.
2135  */
2136 void
2137 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2138 {
2139         MonoInst *ins, *next;
2140
2141         /*
2142          * FIXME: Need to add more instructions, but the current machine 
2143          * description can't model some parts of the composite instructions like
2144          * cdq.
2145          */
2146         MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) {
2147                 switch (ins->opcode) {
2148                 case OP_IREM_IMM:
2149                 case OP_IDIV_IMM:
2150                 case OP_IDIV_UN_IMM:
2151                 case OP_IREM_UN_IMM:
2152                         /* 
2153                          * Keep the cases where we could generated optimized code, otherwise convert
2154                          * to the non-imm variant.
2155                          */
2156                         if ((ins->opcode == OP_IREM_IMM) && mono_is_power_of_two (ins->inst_imm) >= 0)
2157                                 break;
2158                         mono_decompose_op_imm (cfg, bb, ins);
2159                         break;
2160                 default:
2161                         break;
2162                 }
2163         }
2164
2165         bb->max_vreg = cfg->next_vreg;
2166 }
2167
2168 static const int 
2169 branch_cc_table [] = {
2170         X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
2171         X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
2172         X86_CC_O, X86_CC_NO, X86_CC_C, X86_CC_NC
2173 };
2174
2175 /* Maps CMP_... constants to X86_CC_... constants */
2176 static const int
2177 cc_table [] = {
2178         X86_CC_EQ, X86_CC_NE, X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT,
2179         X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT
2180 };
2181
2182 static const int
2183 cc_signed_table [] = {
2184         TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
2185         FALSE, FALSE, FALSE, FALSE
2186 };
2187
2188 static unsigned char*
2189 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
2190 {
2191 #define XMM_TEMP_REG 0
2192         /*This SSE2 optimization must not be done which OPT_SIMD in place as it clobbers xmm0.*/
2193         /*The xmm pass decomposes OP_FCONV_ ops anyway anyway.*/
2194         if (cfg->opt & MONO_OPT_SSE2 && size < 8 && !(cfg->opt & MONO_OPT_SIMD)) {
2195                 /* optimize by assigning a local var for this use so we avoid
2196                  * the stack manipulations */
2197                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2198                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
2199                 x86_movsd_reg_membase (code, XMM_TEMP_REG, X86_ESP, 0);
2200                 x86_cvttsd2si (code, dreg, XMM_TEMP_REG);
2201                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
2202                 if (size == 1)
2203                         x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
2204                 else if (size == 2)
2205                         x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
2206                 return code;
2207         }
2208         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
2209         x86_fnstcw_membase(code, X86_ESP, 0);
2210         x86_mov_reg_membase (code, dreg, X86_ESP, 0, 2);
2211         x86_alu_reg_imm (code, X86_OR, dreg, 0xc00);
2212         x86_mov_membase_reg (code, X86_ESP, 2, dreg, 2);
2213         x86_fldcw_membase (code, X86_ESP, 2);
2214         if (size == 8) {
2215                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2216                 x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
2217                 x86_pop_reg (code, dreg);
2218                 /* FIXME: need the high register 
2219                  * x86_pop_reg (code, dreg_high);
2220                  */
2221         } else {
2222                 x86_push_reg (code, X86_EAX); // SP = SP - 4
2223                 x86_fist_pop_membase (code, X86_ESP, 0, FALSE);
2224                 x86_pop_reg (code, dreg);
2225         }
2226         x86_fldcw_membase (code, X86_ESP, 0);
2227         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2228
2229         if (size == 1)
2230                 x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
2231         else if (size == 2)
2232                 x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
2233         return code;
2234 }
2235
2236 static unsigned char*
2237 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2238 {
2239         int sreg = tree->sreg1;
2240         int need_touch = FALSE;
2241
2242 #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
2243         need_touch = TRUE;
2244 #endif
2245
2246         if (need_touch) {
2247                 guint8* br[5];
2248
2249                 /*
2250                  * Under Windows:
2251                  * If requested stack size is larger than one page,
2252                  * perform stack-touch operation
2253                  */
2254                 /*
2255                  * Generate stack probe code.
2256                  * Under Windows, it is necessary to allocate one page at a time,
2257                  * "touching" stack after each successful sub-allocation. This is
2258                  * because of the way stack growth is implemented - there is a
2259                  * guard page before the lowest stack page that is currently commited.
2260                  * Stack normally grows sequentially so OS traps access to the
2261                  * guard page and commits more pages when needed.
2262                  */
2263                 x86_test_reg_imm (code, sreg, ~0xFFF);
2264                 br[0] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2265
2266                 br[2] = code; /* loop */
2267                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
2268                 x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
2269
2270                 /* 
2271                  * By the end of the loop, sreg2 is smaller than 0x1000, so the init routine
2272                  * that follows only initializes the last part of the area.
2273                  */
2274                 /* Same as the init code below with size==0x1000 */
2275                 if (tree->flags & MONO_INST_INIT) {
2276                         x86_push_reg (code, X86_EAX);
2277                         x86_push_reg (code, X86_ECX);
2278                         x86_push_reg (code, X86_EDI);
2279                         x86_mov_reg_imm (code, X86_ECX, (0x1000 >> 2));
2280                         x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);                              
2281                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2282                         x86_cld (code);
2283                         x86_prefix (code, X86_REP_PREFIX);
2284                         x86_stosl (code);
2285                         x86_pop_reg (code, X86_EDI);
2286                         x86_pop_reg (code, X86_ECX);
2287                         x86_pop_reg (code, X86_EAX);
2288                 }
2289
2290                 x86_alu_reg_imm (code, X86_SUB, sreg, 0x1000);
2291                 x86_alu_reg_imm (code, X86_CMP, sreg, 0x1000);
2292                 br[3] = code; x86_branch8 (code, X86_CC_AE, 0, FALSE);
2293                 x86_patch (br[3], br[2]);
2294                 x86_test_reg_reg (code, sreg, sreg);
2295                 br[4] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2296                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2297
2298                 br[1] = code; x86_jump8 (code, 0);
2299
2300                 x86_patch (br[0], code);
2301                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2302                 x86_patch (br[1], code);
2303                 x86_patch (br[4], code);
2304         }
2305         else
2306                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2307
2308         if (tree->flags & MONO_INST_INIT) {
2309                 int offset = 0;
2310                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2311                         x86_push_reg (code, X86_EAX);
2312                         offset += 4;
2313                 }
2314                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2315                         x86_push_reg (code, X86_ECX);
2316                         offset += 4;
2317                 }
2318                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2319                         x86_push_reg (code, X86_EDI);
2320                         offset += 4;
2321                 }
2322                 
2323                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2324                 if (sreg != X86_ECX)
2325                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2326                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2327                                 
2328                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2329                 x86_cld (code);
2330                 x86_prefix (code, X86_REP_PREFIX);
2331                 x86_stosl (code);
2332                 
2333                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2334                         x86_pop_reg (code, X86_EDI);
2335                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2336                         x86_pop_reg (code, X86_ECX);
2337                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2338                         x86_pop_reg (code, X86_EAX);
2339         }
2340         return code;
2341 }
2342
2343
2344 static guint8*
2345 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2346 {
2347         /* Move return value to the target register */
2348         switch (ins->opcode) {
2349         case OP_CALL:
2350         case OP_CALL_REG:
2351         case OP_CALL_MEMBASE:
2352                 if (ins->dreg != X86_EAX)
2353                         x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2354                 break;
2355         default:
2356                 break;
2357         }
2358
2359         return code;
2360 }
2361
2362 #ifdef __APPLE__
2363 static int tls_gs_offset;
2364 #endif
2365
2366 gboolean
2367 mono_x86_have_tls_get (void)
2368 {
2369 #ifdef __APPLE__
2370         static gboolean have_tls_get = FALSE;
2371         static gboolean inited = FALSE;
2372         guint32 *ins;
2373
2374         if (inited)
2375                 return have_tls_get;
2376
2377         ins = (guint32*)pthread_getspecific;
2378         /*
2379          * We're looking for these two instructions:
2380          *
2381          * mov    0x4(%esp),%eax
2382          * mov    %gs:[offset](,%eax,4),%eax
2383          */
2384         have_tls_get = ins [0] == 0x0424448b && ins [1] == 0x85048b65;
2385         tls_gs_offset = ins [2];
2386
2387         inited = TRUE;
2388
2389         return have_tls_get;
2390 #elif defined(TARGET_ANDROID)
2391         return FALSE;
2392 #else
2393         return TRUE;
2394 #endif
2395 }
2396
2397 static guint8*
2398 mono_x86_emit_tls_set (guint8* code, int sreg, int tls_offset)
2399 {
2400 #if defined(__APPLE__)
2401         x86_prefix (code, X86_GS_PREFIX);
2402         x86_mov_mem_reg (code, tls_gs_offset + (tls_offset * 4), sreg, 4);
2403 #elif defined(TARGET_WIN32)
2404         g_assert_not_reached ();
2405 #else
2406         x86_prefix (code, X86_GS_PREFIX);
2407         x86_mov_mem_reg (code, tls_offset, sreg, 4);
2408 #endif
2409         return code;
2410 }
2411
2412 /*
2413  * mono_x86_emit_tls_get:
2414  * @code: buffer to store code to
2415  * @dreg: hard register where to place the result
2416  * @tls_offset: offset info
2417  *
2418  * mono_x86_emit_tls_get emits in @code the native code that puts in
2419  * the dreg register the item in the thread local storage identified
2420  * by tls_offset.
2421  *
2422  * Returns: a pointer to the end of the stored code
2423  */
2424 guint8*
2425 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset)
2426 {
2427 #if defined(__APPLE__)
2428         x86_prefix (code, X86_GS_PREFIX);
2429         x86_mov_reg_mem (code, dreg, tls_gs_offset + (tls_offset * 4), 4);
2430 #elif defined(TARGET_WIN32)
2431         /* 
2432          * See the Under the Hood article in the May 1996 issue of Microsoft Systems 
2433          * Journal and/or a disassembly of the TlsGet () function.
2434          */
2435         g_assert (tls_offset < 64);
2436         x86_prefix (code, X86_FS_PREFIX);
2437         x86_mov_reg_mem (code, dreg, 0x18, 4);
2438         /* Dunno what this does but TlsGetValue () contains it */
2439         x86_alu_membase_imm (code, X86_AND, dreg, 0x34, 0);
2440         x86_mov_reg_membase (code, dreg, dreg, 3600 + (tls_offset * 4), 4);
2441 #else
2442         if (optimize_for_xen) {
2443                 x86_prefix (code, X86_GS_PREFIX);
2444                 x86_mov_reg_mem (code, dreg, 0, 4);
2445                 x86_mov_reg_membase (code, dreg, dreg, tls_offset, 4);
2446         } else {
2447                 x86_prefix (code, X86_GS_PREFIX);
2448                 x86_mov_reg_mem (code, dreg, tls_offset, 4);
2449         }
2450 #endif
2451         return code;
2452 }
2453
2454 /*
2455  * emit_load_volatile_arguments:
2456  *
2457  *  Load volatile arguments from the stack to the original input registers.
2458  * Required before a tail call.
2459  */
2460 static guint8*
2461 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2462 {
2463         MonoMethod *method = cfg->method;
2464         MonoMethodSignature *sig;
2465         MonoInst *inst;
2466         CallInfo *cinfo;
2467         guint32 i;
2468
2469         /* FIXME: Generate intermediate code instead */
2470
2471         sig = mono_method_signature (method);
2472
2473         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2474         
2475         /* This is the opposite of the code in emit_prolog */
2476
2477         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2478                 ArgInfo *ainfo = cinfo->args + i;
2479                 MonoType *arg_type;
2480                 inst = cfg->args [i];
2481
2482                 if (sig->hasthis && (i == 0))
2483                         arg_type = &mono_defaults.object_class->byval_arg;
2484                 else
2485                         arg_type = sig->params [i - sig->hasthis];
2486
2487                 /*
2488                  * On x86, the arguments are either in their original stack locations, or in
2489                  * global regs.
2490                  */
2491                 if (inst->opcode == OP_REGVAR) {
2492                         g_assert (ainfo->storage == ArgOnStack);
2493                         
2494                         x86_mov_membase_reg (code, X86_EBP, inst->inst_offset, inst->dreg, 4);
2495                 }
2496         }
2497
2498         return code;
2499 }
2500
2501 #define REAL_PRINT_REG(text,reg) \
2502 mono_assert (reg >= 0); \
2503 x86_push_reg (code, X86_EAX); \
2504 x86_push_reg (code, X86_EDX); \
2505 x86_push_reg (code, X86_ECX); \
2506 x86_push_reg (code, reg); \
2507 x86_push_imm (code, reg); \
2508 x86_push_imm (code, text " %d %p\n"); \
2509 x86_mov_reg_imm (code, X86_EAX, printf); \
2510 x86_call_reg (code, X86_EAX); \
2511 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
2512 x86_pop_reg (code, X86_ECX); \
2513 x86_pop_reg (code, X86_EDX); \
2514 x86_pop_reg (code, X86_EAX);
2515
2516 /* REAL_PRINT_REG does not appear to be used, and was not adapted to work with Native Client. */
2517 #ifdef __native__client_codegen__
2518 #define REAL_PRINT_REG(text, reg) g_assert_not_reached()
2519 #endif
2520
2521 /* benchmark and set based on cpu */
2522 #define LOOP_ALIGNMENT 8
2523 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2524
2525 #ifndef DISABLE_JIT
2526 void
2527 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2528 {
2529         MonoInst *ins;
2530         MonoCallInst *call;
2531         guint offset;
2532         guint8 *code = cfg->native_code + cfg->code_len;
2533         int max_len, cpos;
2534
2535         if (cfg->opt & MONO_OPT_LOOP) {
2536                 int pad, align = LOOP_ALIGNMENT;
2537                 /* set alignment depending on cpu */
2538                 if (bb_is_loop_start (bb) && (pad = (cfg->code_len & (align - 1)))) {
2539                         pad = align - pad;
2540                         /*g_print ("adding %d pad at %x to loop in %s\n", pad, cfg->code_len, cfg->method->name);*/
2541                         x86_padding (code, pad);
2542                         cfg->code_len += pad;
2543                         bb->native_offset = cfg->code_len;
2544                 }
2545         }
2546 #ifdef __native_client_codegen__
2547         {
2548                 /* For Native Client, all indirect call/jump targets must be   */
2549                 /* 32-byte aligned.  Exception handler blocks are jumped to    */
2550                 /* indirectly as well.                                         */
2551                 gboolean bb_needs_alignment = (bb->flags & BB_INDIRECT_JUMP_TARGET) ||
2552                         (bb->flags & BB_EXCEPTION_HANDLER);
2553
2554                 /* if ((cfg->code_len & kNaClAlignmentMask) != 0) { */
2555                 if ( bb_needs_alignment && ((cfg->code_len & kNaClAlignmentMask) != 0)) {
2556             int pad = kNaClAlignment - (cfg->code_len & kNaClAlignmentMask);
2557             if (pad != kNaClAlignment) code = mono_arch_nacl_pad(code, pad);
2558             cfg->code_len += pad;
2559             bb->native_offset = cfg->code_len;
2560                 }
2561         }
2562 #endif  /* __native_client_codegen__ */
2563         if (cfg->verbose_level > 2)
2564                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2565
2566         cpos = bb->max_offset;
2567
2568         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2569                 MonoProfileCoverageInfo *cov = cfg->coverage_info;
2570                 g_assert (!cfg->compile_aot);
2571                 cpos += 6;
2572
2573                 cov->data [bb->dfn].cil_code = bb->cil_code;
2574                 /* this is not thread save, but good enough */
2575                 x86_inc_mem (code, &cov->data [bb->dfn].count); 
2576         }
2577
2578         offset = code - cfg->native_code;
2579
2580         mono_debug_open_block (cfg, bb, offset);
2581
2582     if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num)
2583                 x86_breakpoint (code);
2584
2585         MONO_BB_FOR_EACH_INS (bb, ins) {
2586                 offset = code - cfg->native_code;
2587
2588                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2589
2590 #define EXTRA_CODE_SPACE (NACL_SIZE (16, 16 + kNaClAlignment))
2591
2592                 if (G_UNLIKELY (offset > (cfg->code_size - max_len - EXTRA_CODE_SPACE))) {
2593                         cfg->code_size *= 2;
2594                         cfg->native_code = mono_realloc_native_code(cfg);
2595                         code = cfg->native_code + offset;
2596                         cfg->stat_code_reallocs++;
2597                 }
2598
2599                 if (cfg->debug_info)
2600                         mono_debug_record_line_number (cfg, ins, offset);
2601
2602                 switch (ins->opcode) {
2603                 case OP_BIGMUL:
2604                         x86_mul_reg (code, ins->sreg2, TRUE);
2605                         break;
2606                 case OP_BIGMUL_UN:
2607                         x86_mul_reg (code, ins->sreg2, FALSE);
2608                         break;
2609                 case OP_X86_SETEQ_MEMBASE:
2610                 case OP_X86_SETNE_MEMBASE:
2611                         x86_set_membase (code, ins->opcode == OP_X86_SETEQ_MEMBASE ? X86_CC_EQ : X86_CC_NE,
2612                                          ins->inst_basereg, ins->inst_offset, TRUE);
2613                         break;
2614                 case OP_STOREI1_MEMBASE_IMM:
2615                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 1);
2616                         break;
2617                 case OP_STOREI2_MEMBASE_IMM:
2618                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 2);
2619                         break;
2620                 case OP_STORE_MEMBASE_IMM:
2621                 case OP_STOREI4_MEMBASE_IMM:
2622                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 4);
2623                         break;
2624                 case OP_STOREI1_MEMBASE_REG:
2625                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 1);
2626                         break;
2627                 case OP_STOREI2_MEMBASE_REG:
2628                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
2629                         break;
2630                 case OP_STORE_MEMBASE_REG:
2631                 case OP_STOREI4_MEMBASE_REG:
2632                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
2633                         break;
2634                 case OP_STORE_MEM_IMM:
2635                         x86_mov_mem_imm (code, ins->inst_p0, ins->inst_c0, 4);
2636                         break;
2637                 case OP_LOADU4_MEM:
2638                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2639                         break;
2640                 case OP_LOAD_MEM:
2641                 case OP_LOADI4_MEM:
2642                         /* These are created by the cprop pass so they use inst_imm as the source */
2643                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2644                         break;
2645                 case OP_LOADU1_MEM:
2646                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, FALSE);
2647                         break;
2648                 case OP_LOADU2_MEM:
2649                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, TRUE);
2650                         break;
2651                 case OP_LOAD_MEMBASE:
2652                 case OP_LOADI4_MEMBASE:
2653                 case OP_LOADU4_MEMBASE:
2654                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 4);
2655                         break;
2656                 case OP_LOADU1_MEMBASE:
2657                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, FALSE);
2658                         break;
2659                 case OP_LOADI1_MEMBASE:
2660                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, FALSE);
2661                         break;
2662                 case OP_LOADU2_MEMBASE:
2663                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, TRUE);
2664                         break;
2665                 case OP_LOADI2_MEMBASE:
2666                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
2667                         break;
2668                 case OP_ICONV_TO_I1:
2669                 case OP_SEXT_I1:
2670                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2671                         break;
2672                 case OP_ICONV_TO_I2:
2673                 case OP_SEXT_I2:
2674                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2675                         break;
2676                 case OP_ICONV_TO_U1:
2677                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, FALSE);
2678                         break;
2679                 case OP_ICONV_TO_U2:
2680                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, TRUE);
2681                         break;
2682                 case OP_COMPARE:
2683                 case OP_ICOMPARE:
2684                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2685                         break;
2686                 case OP_COMPARE_IMM:
2687                 case OP_ICOMPARE_IMM:
2688                         x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
2689                         break;
2690                 case OP_X86_COMPARE_MEMBASE_REG:
2691                         x86_alu_membase_reg (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2692                         break;
2693                 case OP_X86_COMPARE_MEMBASE_IMM:
2694                         x86_alu_membase_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2695                         break;
2696                 case OP_X86_COMPARE_MEMBASE8_IMM:
2697                         x86_alu_membase8_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2698                         break;
2699                 case OP_X86_COMPARE_REG_MEMBASE:
2700                         x86_alu_reg_membase (code, X86_CMP, ins->sreg1, ins->sreg2, ins->inst_offset);
2701                         break;
2702                 case OP_X86_COMPARE_MEM_IMM:
2703                         x86_alu_mem_imm (code, X86_CMP, ins->inst_offset, ins->inst_imm);
2704                         break;
2705                 case OP_X86_TEST_NULL:
2706                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2707                         break;
2708                 case OP_X86_ADD_MEMBASE_IMM:
2709                         x86_alu_membase_imm (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2710                         break;
2711                 case OP_X86_ADD_REG_MEMBASE:
2712                         x86_alu_reg_membase (code, X86_ADD, ins->sreg1, ins->sreg2, ins->inst_offset);
2713                         break;
2714                 case OP_X86_SUB_MEMBASE_IMM:
2715                         x86_alu_membase_imm (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2716                         break;
2717                 case OP_X86_SUB_REG_MEMBASE:
2718                         x86_alu_reg_membase (code, X86_SUB, ins->sreg1, ins->sreg2, ins->inst_offset);
2719                         break;
2720                 case OP_X86_AND_MEMBASE_IMM:
2721                         x86_alu_membase_imm (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2722                         break;
2723                 case OP_X86_OR_MEMBASE_IMM:
2724                         x86_alu_membase_imm (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2725                         break;
2726                 case OP_X86_XOR_MEMBASE_IMM:
2727                         x86_alu_membase_imm (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2728                         break;
2729                 case OP_X86_ADD_MEMBASE_REG:
2730                         x86_alu_membase_reg (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2731                         break;
2732                 case OP_X86_SUB_MEMBASE_REG:
2733                         x86_alu_membase_reg (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2734                         break;
2735                 case OP_X86_AND_MEMBASE_REG:
2736                         x86_alu_membase_reg (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2737                         break;
2738                 case OP_X86_OR_MEMBASE_REG:
2739                         x86_alu_membase_reg (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2740                         break;
2741                 case OP_X86_XOR_MEMBASE_REG:
2742                         x86_alu_membase_reg (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2743                         break;
2744                 case OP_X86_INC_MEMBASE:
2745                         x86_inc_membase (code, ins->inst_basereg, ins->inst_offset);
2746                         break;
2747                 case OP_X86_INC_REG:
2748                         x86_inc_reg (code, ins->dreg);
2749                         break;
2750                 case OP_X86_DEC_MEMBASE:
2751                         x86_dec_membase (code, ins->inst_basereg, ins->inst_offset);
2752                         break;
2753                 case OP_X86_DEC_REG:
2754                         x86_dec_reg (code, ins->dreg);
2755                         break;
2756                 case OP_X86_MUL_REG_MEMBASE:
2757                         x86_imul_reg_membase (code, ins->sreg1, ins->sreg2, ins->inst_offset);
2758                         break;
2759                 case OP_X86_AND_REG_MEMBASE:
2760                         x86_alu_reg_membase (code, X86_AND, ins->sreg1, ins->sreg2, ins->inst_offset);
2761                         break;
2762                 case OP_X86_OR_REG_MEMBASE:
2763                         x86_alu_reg_membase (code, X86_OR, ins->sreg1, ins->sreg2, ins->inst_offset);
2764                         break;
2765                 case OP_X86_XOR_REG_MEMBASE:
2766                         x86_alu_reg_membase (code, X86_XOR, ins->sreg1, ins->sreg2, ins->inst_offset);
2767                         break;
2768                 case OP_BREAK:
2769                         x86_breakpoint (code);
2770                         break;
2771                 case OP_RELAXED_NOP:
2772                         x86_prefix (code, X86_REP_PREFIX);
2773                         x86_nop (code);
2774                         break;
2775                 case OP_HARD_NOP:
2776                         x86_nop (code);
2777                         break;
2778                 case OP_NOP:
2779                 case OP_DUMMY_USE:
2780                 case OP_DUMMY_STORE:
2781                 case OP_NOT_REACHED:
2782                 case OP_NOT_NULL:
2783                         break;
2784                 case OP_SEQ_POINT: {
2785                         int i;
2786
2787                         if (cfg->compile_aot)
2788                                 NOT_IMPLEMENTED;
2789
2790                         /* 
2791                          * Read from the single stepping trigger page. This will cause a
2792                          * SIGSEGV when single stepping is enabled.
2793                          * We do this _before_ the breakpoint, so single stepping after
2794                          * a breakpoint is hit will step to the next IL offset.
2795                          */
2796                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
2797                                 x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
2798
2799                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
2800
2801                         /* 
2802                          * A placeholder for a possible breakpoint inserted by
2803                          * mono_arch_set_breakpoint ().
2804                          */
2805                         for (i = 0; i < 6; ++i)
2806                                 x86_nop (code);
2807                         /*
2808                          * Add an additional nop so skipping the bp doesn't cause the ip to point
2809                          * to another IL offset.
2810                          */
2811                         x86_nop (code);
2812                         break;
2813                 }
2814                 case OP_ADDCC:
2815                 case OP_IADDCC:
2816                 case OP_IADD:
2817                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2818                         break;
2819                 case OP_ADC:
2820                 case OP_IADC:
2821                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2822                         break;
2823                 case OP_ADDCC_IMM:
2824                 case OP_ADD_IMM:
2825                 case OP_IADD_IMM:
2826                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2827                         break;
2828                 case OP_ADC_IMM:
2829                 case OP_IADC_IMM:
2830                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2831                         break;
2832                 case OP_SUBCC:
2833                 case OP_ISUBCC:
2834                 case OP_ISUB:
2835                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2836                         break;
2837                 case OP_SBB:
2838                 case OP_ISBB:
2839                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2840                         break;
2841                 case OP_SUBCC_IMM:
2842                 case OP_SUB_IMM:
2843                 case OP_ISUB_IMM:
2844                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2845                         break;
2846                 case OP_SBB_IMM:
2847                 case OP_ISBB_IMM:
2848                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2849                         break;
2850                 case OP_IAND:
2851                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2852                         break;
2853                 case OP_AND_IMM:
2854                 case OP_IAND_IMM:
2855                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2856                         break;
2857                 case OP_IDIV:
2858                 case OP_IREM:
2859 #if defined( __native_client_codegen__ )
2860                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0);
2861                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "DivideByZeroException");
2862 #endif
2863                         /* 
2864                          * The code is the same for div/rem, the allocator will allocate dreg
2865                          * to RAX/RDX as appropriate.
2866                          */
2867                         if (ins->sreg2 == X86_EDX) {
2868                                 /* cdq clobbers this */
2869                                 x86_push_reg (code, ins->sreg2);
2870                                 x86_cdq (code);
2871                                 x86_div_membase (code, X86_ESP, 0, TRUE);
2872                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2873                         } else {
2874                                 x86_cdq (code);
2875                                 x86_div_reg (code, ins->sreg2, TRUE);
2876                         }
2877                         break;
2878                 case OP_IDIV_UN:
2879                 case OP_IREM_UN:
2880 #if defined( __native_client_codegen__ )
2881                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0);
2882                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "DivideByZeroException");
2883 #endif
2884                         if (ins->sreg2 == X86_EDX) {
2885                                 x86_push_reg (code, ins->sreg2);
2886                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2887                                 x86_div_membase (code, X86_ESP, 0, FALSE);
2888                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2889                         } else {
2890                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2891                                 x86_div_reg (code, ins->sreg2, FALSE);
2892                         }
2893                         break;
2894                 case OP_DIV_IMM:
2895 #if defined( __native_client_codegen__ )
2896                         if (ins->inst_imm == 0) {
2897                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "DivideByZeroException");
2898                                 x86_jump32 (code, 0);
2899                                 break;
2900                         }
2901 #endif
2902                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2903                         x86_cdq (code);
2904                         x86_div_reg (code, ins->sreg2, TRUE);
2905                         break;
2906                 case OP_IREM_IMM: {
2907                         int power = mono_is_power_of_two (ins->inst_imm);
2908
2909                         g_assert (ins->sreg1 == X86_EAX);
2910                         g_assert (ins->dreg == X86_EAX);
2911                         g_assert (power >= 0);
2912
2913                         if (power == 1) {
2914                                 /* Based on http://compilers.iecc.com/comparch/article/93-04-079 */
2915                                 x86_cdq (code);
2916                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, 1);
2917                                 /* 
2918                                  * If the divident is >= 0, this does not nothing. If it is positive, it
2919                                  * it transforms %eax=0 into %eax=0, and %eax=1 into %eax=-1.
2920                                  */
2921                                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EDX);
2922                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2923                         } else if (power == 0) {
2924                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
2925                         } else {
2926                                 /* Based on gcc code */
2927
2928                                 /* Add compensation for negative dividents */
2929                                 x86_cdq (code);
2930                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, 32 - power);
2931                                 x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EDX);
2932                                 /* Compute remainder */
2933                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, (1 << power) - 1);
2934                                 /* Remove compensation */
2935                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2936                         }
2937                         break;
2938                 }
2939                 case OP_IOR:
2940                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2941                         break;
2942                 case OP_OR_IMM:
2943                 case OP_IOR_IMM:
2944                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2945                         break;
2946                 case OP_IXOR:
2947                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2948                         break;
2949                 case OP_XOR_IMM:
2950                 case OP_IXOR_IMM:
2951                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2952                         break;
2953                 case OP_ISHL:
2954                         g_assert (ins->sreg2 == X86_ECX);
2955                         x86_shift_reg (code, X86_SHL, ins->dreg);
2956                         break;
2957                 case OP_ISHR:
2958                         g_assert (ins->sreg2 == X86_ECX);
2959                         x86_shift_reg (code, X86_SAR, ins->dreg);
2960                         break;
2961                 case OP_SHR_IMM:
2962                 case OP_ISHR_IMM:
2963                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2964                         break;
2965                 case OP_SHR_UN_IMM:
2966                 case OP_ISHR_UN_IMM:
2967                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2968                         break;
2969                 case OP_ISHR_UN:
2970                         g_assert (ins->sreg2 == X86_ECX);
2971                         x86_shift_reg (code, X86_SHR, ins->dreg);
2972                         break;
2973                 case OP_SHL_IMM:
2974                 case OP_ISHL_IMM:
2975                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2976                         break;
2977                 case OP_LSHL: {
2978                         guint8 *jump_to_end;
2979
2980                         /* handle shifts below 32 bits */
2981                         x86_shld_reg (code, ins->backend.reg3, ins->sreg1);
2982                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2983
2984                         x86_test_reg_imm (code, X86_ECX, 32);
2985                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2986
2987                         /* handle shift over 32 bit */
2988                         x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2989                         x86_clear_reg (code, ins->sreg1);
2990                         
2991                         x86_patch (jump_to_end, code);
2992                         }
2993                         break;
2994                 case OP_LSHR: {
2995                         guint8 *jump_to_end;
2996
2997                         /* handle shifts below 32 bits */
2998                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2999                         x86_shift_reg (code, X86_SAR, ins->backend.reg3);
3000
3001                         x86_test_reg_imm (code, X86_ECX, 32);
3002                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
3003
3004                         /* handle shifts over 31 bits */
3005                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
3006                         x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 31);
3007                         
3008                         x86_patch (jump_to_end, code);
3009                         }
3010                         break;
3011                 case OP_LSHR_UN: {
3012                         guint8 *jump_to_end;
3013
3014                         /* handle shifts below 32 bits */
3015                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
3016                         x86_shift_reg (code, X86_SHR, ins->backend.reg3);
3017
3018                         x86_test_reg_imm (code, X86_ECX, 32);
3019                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
3020
3021                         /* handle shifts over 31 bits */
3022                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
3023                         x86_clear_reg (code, ins->backend.reg3);
3024                         
3025                         x86_patch (jump_to_end, code);
3026                         }
3027                         break;
3028                 case OP_LSHL_IMM:
3029                         if (ins->inst_imm >= 32) {
3030                                 x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
3031                                 x86_clear_reg (code, ins->sreg1);
3032                                 x86_shift_reg_imm (code, X86_SHL, ins->backend.reg3, ins->inst_imm - 32);
3033                         } else {
3034                                 x86_shld_reg_imm (code, ins->backend.reg3, ins->sreg1, ins->inst_imm);
3035                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
3036                         }
3037                         break;
3038                 case OP_LSHR_IMM:
3039                         if (ins->inst_imm >= 32) {
3040                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3,  4);
3041                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 0x1f);
3042                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
3043                         } else {
3044                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
3045                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, ins->inst_imm);
3046                         }
3047                         break;
3048                 case OP_LSHR_UN_IMM:
3049                         if (ins->inst_imm >= 32) {
3050                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
3051                                 x86_clear_reg (code, ins->backend.reg3);
3052                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
3053                         } else {
3054                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
3055                                 x86_shift_reg_imm (code, X86_SHR, ins->backend.reg3, ins->inst_imm);
3056                         }
3057                         break;
3058                 case OP_INOT:
3059                         x86_not_reg (code, ins->sreg1);
3060                         break;
3061                 case OP_INEG:
3062                         x86_neg_reg (code, ins->sreg1);
3063                         break;
3064
3065                 case OP_IMUL:
3066                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
3067                         break;
3068                 case OP_MUL_IMM:
3069                 case OP_IMUL_IMM:
3070                         switch (ins->inst_imm) {
3071                         case 2:
3072                                 /* MOV r1, r2 */
3073                                 /* ADD r1, r1 */
3074                                 if (ins->dreg != ins->sreg1)
3075                                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3076                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
3077                                 break;
3078                         case 3:
3079                                 /* LEA r1, [r2 + r2*2] */
3080                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
3081                                 break;
3082                         case 5:
3083                                 /* LEA r1, [r2 + r2*4] */
3084                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3085                                 break;
3086                         case 6:
3087                                 /* LEA r1, [r2 + r2*2] */
3088                                 /* ADD r1, r1          */
3089                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
3090                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
3091                                 break;
3092                         case 9:
3093                                 /* LEA r1, [r2 + r2*8] */
3094                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 3);
3095                                 break;
3096                         case 10:
3097                                 /* LEA r1, [r2 + r2*4] */
3098                                 /* ADD r1, r1          */
3099                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3100                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
3101                                 break;
3102                         case 12:
3103                                 /* LEA r1, [r2 + r2*2] */
3104                                 /* SHL r1, 2           */
3105                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
3106                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
3107                                 break;
3108                         case 25:
3109                                 /* LEA r1, [r2 + r2*4] */
3110                                 /* LEA r1, [r1 + r1*4] */
3111                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3112                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
3113                                 break;
3114                         case 100:
3115                                 /* LEA r1, [r2 + r2*4] */
3116                                 /* SHL r1, 2           */
3117                                 /* LEA r1, [r1 + r1*4] */
3118                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3119                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
3120                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
3121                                 break;
3122                         default:
3123                                 x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
3124                                 break;
3125                         }
3126                         break;
3127                 case OP_IMUL_OVF:
3128                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
3129                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
3130                         break;
3131                 case OP_IMUL_OVF_UN: {
3132                         /* the mul operation and the exception check should most likely be split */
3133                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
3134                         /*g_assert (ins->sreg2 == X86_EAX);
3135                         g_assert (ins->dreg == X86_EAX);*/
3136                         if (ins->sreg2 == X86_EAX) {
3137                                 non_eax_reg = ins->sreg1;
3138                         } else if (ins->sreg1 == X86_EAX) {
3139                                 non_eax_reg = ins->sreg2;
3140                         } else {
3141                                 /* no need to save since we're going to store to it anyway */
3142                                 if (ins->dreg != X86_EAX) {
3143                                         saved_eax = TRUE;
3144                                         x86_push_reg (code, X86_EAX);
3145                                 }
3146                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
3147                                 non_eax_reg = ins->sreg2;
3148                         }
3149                         if (ins->dreg == X86_EDX) {
3150                                 if (!saved_eax) {
3151                                         saved_eax = TRUE;
3152                                         x86_push_reg (code, X86_EAX);
3153                                 }
3154                         } else if (ins->dreg != X86_EAX) {
3155                                 saved_edx = TRUE;
3156                                 x86_push_reg (code, X86_EDX);
3157                         }
3158                         x86_mul_reg (code, non_eax_reg, FALSE);
3159                         /* save before the check since pop and mov don't change the flags */
3160                         if (ins->dreg != X86_EAX)
3161                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
3162                         if (saved_edx)
3163                                 x86_pop_reg (code, X86_EDX);
3164                         if (saved_eax)
3165                                 x86_pop_reg (code, X86_EAX);
3166                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
3167                         break;
3168                 }
3169                 case OP_ICONST:
3170                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
3171                         break;
3172                 case OP_AOTCONST:
3173                         g_assert_not_reached ();
3174                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3175                         x86_mov_reg_imm (code, ins->dreg, 0);
3176                         break;
3177                 case OP_JUMP_TABLE:
3178                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3179                         x86_mov_reg_imm (code, ins->dreg, 0);
3180                         break;
3181                 case OP_LOAD_GOTADDR:
3182                         g_assert (ins->dreg == MONO_ARCH_GOT_REG);
3183                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3184                         break;
3185                 case OP_GOT_ENTRY:
3186                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3187                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, 0xf0f0f0f0, 4);
3188                         break;
3189                 case OP_X86_PUSH_GOT_ENTRY:
3190                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3191                         x86_push_membase (code, ins->inst_basereg, 0xf0f0f0f0);
3192                         break;
3193                 case OP_MOVE:
3194                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3195                         break;
3196                 case OP_JMP: {
3197                         /*
3198                          * Note: this 'frame destruction' logic is useful for tail calls, too.
3199                          * Keep in sync with the code in emit_epilog.
3200                          */
3201                         int pos = 0;
3202
3203                         /* FIXME: no tracing support... */
3204                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3205                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
3206                         /* reset offset to make max_len work */
3207                         offset = code - cfg->native_code;
3208
3209                         g_assert (!cfg->method->save_lmf);
3210
3211                         code = emit_load_volatile_arguments (cfg, code);
3212
3213                         if (cfg->used_int_regs & (1 << X86_EBX))
3214                                 pos -= 4;
3215                         if (cfg->used_int_regs & (1 << X86_EDI))
3216                                 pos -= 4;
3217                         if (cfg->used_int_regs & (1 << X86_ESI))
3218                                 pos -= 4;
3219                         if (pos)
3220                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
3221         
3222                         if (cfg->used_int_regs & (1 << X86_ESI))
3223                                 x86_pop_reg (code, X86_ESI);
3224                         if (cfg->used_int_regs & (1 << X86_EDI))
3225                                 x86_pop_reg (code, X86_EDI);
3226                         if (cfg->used_int_regs & (1 << X86_EBX))
3227                                 x86_pop_reg (code, X86_EBX);
3228         
3229                         /* restore ESP/EBP */
3230                         x86_leave (code);
3231                         offset = code - cfg->native_code;
3232                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3233                         x86_jump32 (code, 0);
3234
3235                         cfg->disable_aot = TRUE;
3236                         break;
3237                 }
3238                 case OP_TAILCALL: {
3239                         MonoCallInst *call = (MonoCallInst*)ins;
3240                         int pos = 0, i;
3241
3242                         ins->flags |= MONO_INST_GC_CALLSITE;
3243                         ins->backend.pc_offset = code - cfg->native_code;
3244
3245                         /* FIXME: no tracing support... */
3246                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3247                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
3248                         /* reset offset to make max_len work */
3249                         offset = code - cfg->native_code;
3250
3251                         g_assert (!cfg->method->save_lmf);
3252
3253                         //code = emit_load_volatile_arguments (cfg, code);
3254
3255                         /* restore callee saved registers */
3256                         for (i = 0; i < X86_NREG; ++i)
3257                                 if (X86_IS_CALLEE_SAVED_REG (i) && cfg->used_int_regs & (1 << i))
3258                                         pos -= 4;
3259                         if (cfg->used_int_regs & (1 << X86_ESI)) {
3260                                 x86_mov_reg_membase (code, X86_ESI, X86_EBP, pos, 4);
3261                                 pos += 4;
3262                         }
3263                         if (cfg->used_int_regs & (1 << X86_EDI)) {
3264                                 x86_mov_reg_membase (code, X86_EDI, X86_EBP, pos, 4);
3265                                 pos += 4;
3266                         }
3267                         if (cfg->used_int_regs & (1 << X86_EBX)) {
3268                                 x86_mov_reg_membase (code, X86_EBX, X86_EBP, pos, 4);
3269                                 pos += 4;
3270                         }
3271
3272                         /* Copy arguments on the stack to our argument area */
3273                         for (i = 0; i < call->stack_usage - call->stack_align_amount; i += 4) {
3274                                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, i, 4);
3275                                 x86_mov_membase_reg (code, X86_EBP, 8 + i, X86_EAX, 4);
3276                         }
3277         
3278                         /* restore ESP/EBP */
3279                         x86_leave (code);
3280                         offset = code - cfg->native_code;
3281                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, call->method);
3282                         x86_jump32 (code, 0);
3283
3284                         ins->flags |= MONO_INST_GC_CALLSITE;
3285                         cfg->disable_aot = TRUE;
3286                         break;
3287                 }
3288                 case OP_CHECK_THIS:
3289                         /* ensure ins->sreg1 is not NULL
3290                          * note that cmp DWORD PTR [eax], eax is one byte shorter than
3291                          * cmp DWORD PTR [eax], 0
3292                          */
3293                         x86_alu_membase_reg (code, X86_CMP, ins->sreg1, 0, ins->sreg1);
3294                         break;
3295                 case OP_ARGLIST: {
3296                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
3297                         x86_push_reg (code, hreg);
3298                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
3299                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
3300                         x86_pop_reg (code, hreg);
3301                         break;
3302                 }
3303                 case OP_FCALL:
3304                 case OP_LCALL:
3305                 case OP_VCALL:
3306                 case OP_VCALL2:
3307                 case OP_VOIDCALL:
3308                 case OP_CALL:
3309                         call = (MonoCallInst*)ins;
3310                         if (ins->flags & MONO_INST_HAS_METHOD)
3311                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
3312                         else
3313                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
3314                         ins->flags |= MONO_INST_GC_CALLSITE;
3315                         ins->backend.pc_offset = code - cfg->native_code;
3316                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
3317                                 /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8
3318                                  * bytes to pop, we want to use pops. GCC does this (note it won't happen
3319                                  * for P4 or i686 because gcc will avoid using pop push at all. But we aren't
3320                                  * smart enough to do that optimization yet
3321                                  *
3322                                  * It turns out that on my P4, doing two pops for 8 bytes on the stack makes
3323                                  * mcs botstrap slow down. However, doing 1 pop for 4 bytes creates a small,
3324                                  * (most likely from locality benefits). People with other processors should
3325                                  * check on theirs to see what happens.
3326                                  */
3327                                 if (call->stack_usage == 4) {
3328                                         /* we want to use registers that won't get used soon, so use
3329                                          * ecx, as eax will get allocated first. edx is used by long calls,
3330                                          * so we can't use that.
3331                                          */
3332                                         
3333                                         x86_pop_reg (code, X86_ECX);
3334                                 } else {
3335                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
3336                                 }
3337                         }
3338                         code = emit_move_return_value (cfg, ins, code);
3339                         break;
3340                 case OP_FCALL_REG:
3341                 case OP_LCALL_REG:
3342                 case OP_VCALL_REG:
3343                 case OP_VCALL2_REG:
3344                 case OP_VOIDCALL_REG:
3345                 case OP_CALL_REG:
3346                         call = (MonoCallInst*)ins;
3347                         x86_call_reg (code, ins->sreg1);
3348                         ins->flags |= MONO_INST_GC_CALLSITE;
3349                         ins->backend.pc_offset = code - cfg->native_code;
3350                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
3351                                 if (call->stack_usage == 4)
3352                                         x86_pop_reg (code, X86_ECX);
3353                                 else
3354                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
3355                         }
3356                         code = emit_move_return_value (cfg, ins, code);
3357                         break;
3358                 case OP_FCALL_MEMBASE:
3359                 case OP_LCALL_MEMBASE:
3360                 case OP_VCALL_MEMBASE:
3361                 case OP_VCALL2_MEMBASE:
3362                 case OP_VOIDCALL_MEMBASE:
3363                 case OP_CALL_MEMBASE:
3364                         call = (MonoCallInst*)ins;
3365
3366                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
3367                         ins->flags |= MONO_INST_GC_CALLSITE;
3368                         ins->backend.pc_offset = code - cfg->native_code;
3369                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
3370                                 if (call->stack_usage == 4)
3371                                         x86_pop_reg (code, X86_ECX);
3372                                 else
3373                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
3374                         }
3375                         code = emit_move_return_value (cfg, ins, code);
3376                         break;
3377                 case OP_X86_PUSH:
3378                         x86_push_reg (code, ins->sreg1);
3379                         break;
3380                 case OP_X86_PUSH_IMM:
3381                         x86_push_imm (code, ins->inst_imm);
3382                         break;
3383                 case OP_X86_PUSH_MEMBASE:
3384                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
3385                         break;
3386                 case OP_X86_PUSH_OBJ: 
3387                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
3388                         x86_push_reg (code, X86_EDI);
3389                         x86_push_reg (code, X86_ESI);
3390                         x86_push_reg (code, X86_ECX);
3391                         if (ins->inst_offset)
3392                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
3393                         else
3394                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
3395                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
3396                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
3397                         x86_cld (code);
3398                         x86_prefix (code, X86_REP_PREFIX);
3399                         x86_movsd (code);
3400                         x86_pop_reg (code, X86_ECX);
3401                         x86_pop_reg (code, X86_ESI);
3402                         x86_pop_reg (code, X86_EDI);
3403                         break;
3404                 case OP_X86_LEA:
3405                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
3406                         break;
3407                 case OP_X86_LEA_MEMBASE:
3408                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
3409                         break;
3410                 case OP_X86_XCHG:
3411                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
3412                         break;
3413                 case OP_LOCALLOC:
3414                         /* keep alignment */
3415                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_LOCALLOC_ALIGNMENT - 1);
3416                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
3417                         code = mono_emit_stack_alloc (code, ins);
3418                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
3419                         break;
3420                 case OP_LOCALLOC_IMM: {
3421                         guint32 size = ins->inst_imm;
3422                         size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
3423
3424                         if (ins->flags & MONO_INST_INIT) {
3425                                 /* FIXME: Optimize this */
3426                                 x86_mov_reg_imm (code, ins->dreg, size);
3427                                 ins->sreg1 = ins->dreg;
3428
3429                                 code = mono_emit_stack_alloc (code, ins);
3430                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
3431                         } else {
3432                                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, size);
3433                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
3434                         }
3435                         break;
3436                 }
3437                 case OP_THROW: {
3438                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3439                         x86_push_reg (code, ins->sreg1);
3440                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3441                                                           (gpointer)"mono_arch_throw_exception");
3442                         ins->flags |= MONO_INST_GC_CALLSITE;
3443                         ins->backend.pc_offset = code - cfg->native_code;
3444                         break;
3445                 }
3446                 case OP_RETHROW: {
3447                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3448                         x86_push_reg (code, ins->sreg1);
3449                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3450                                                           (gpointer)"mono_arch_rethrow_exception");
3451                         ins->flags |= MONO_INST_GC_CALLSITE;
3452                         ins->backend.pc_offset = code - cfg->native_code;
3453                         break;
3454                 }
3455                 case OP_CALL_HANDLER:
3456                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3457                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3458                         x86_call_imm (code, 0);
3459                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3460                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3461                         break;
3462                 case OP_START_HANDLER: {
3463                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3464                         x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4);
3465                         break;
3466                 }
3467                 case OP_ENDFINALLY: {
3468                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3469                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
3470                         x86_ret (code);
3471                         break;
3472                 }
3473                 case OP_ENDFILTER: {
3474                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3475                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
3476                         /* The local allocator will put the result into EAX */
3477                         x86_ret (code);
3478                         break;
3479                 }
3480
3481                 case OP_LABEL:
3482                         ins->inst_c0 = code - cfg->native_code;
3483                         break;
3484                 case OP_BR:
3485                         if (ins->inst_target_bb->native_offset) {
3486                                 x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
3487                         } else {
3488                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3489                                 if ((cfg->opt & MONO_OPT_BRANCH) &&
3490                                     x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
3491                                         x86_jump8 (code, 0);
3492                                 else 
3493                                         x86_jump32 (code, 0);
3494                         }
3495                         break;
3496                 case OP_BR_REG:
3497                         x86_jump_reg (code, ins->sreg1);
3498                         break;
3499                 case OP_CEQ:
3500                 case OP_CLT:
3501                 case OP_CLT_UN:
3502                 case OP_CGT:
3503                 case OP_CGT_UN:
3504                 case OP_CNE:
3505                 case OP_ICEQ:
3506                 case OP_ICLT:
3507                 case OP_ICLT_UN:
3508                 case OP_ICGT:
3509                 case OP_ICGT_UN:
3510                         x86_set_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3511                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3512                         break;
3513                 case OP_COND_EXC_EQ:
3514                 case OP_COND_EXC_NE_UN:
3515                 case OP_COND_EXC_LT:
3516                 case OP_COND_EXC_LT_UN:
3517                 case OP_COND_EXC_GT:
3518                 case OP_COND_EXC_GT_UN:
3519                 case OP_COND_EXC_GE:
3520                 case OP_COND_EXC_GE_UN:
3521                 case OP_COND_EXC_LE:
3522                 case OP_COND_EXC_LE_UN:
3523                 case OP_COND_EXC_IEQ:
3524                 case OP_COND_EXC_INE_UN:
3525                 case OP_COND_EXC_ILT:
3526                 case OP_COND_EXC_ILT_UN:
3527                 case OP_COND_EXC_IGT:
3528                 case OP_COND_EXC_IGT_UN:
3529                 case OP_COND_EXC_IGE:
3530                 case OP_COND_EXC_IGE_UN:
3531                 case OP_COND_EXC_ILE:
3532                 case OP_COND_EXC_ILE_UN:
3533                         EMIT_COND_SYSTEM_EXCEPTION (cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->inst_p1);
3534                         break;
3535                 case OP_COND_EXC_OV:
3536                 case OP_COND_EXC_NO:
3537                 case OP_COND_EXC_C:
3538                 case OP_COND_EXC_NC:
3539                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
3540                         break;
3541                 case OP_COND_EXC_IOV:
3542                 case OP_COND_EXC_INO:
3543                 case OP_COND_EXC_IC:
3544                 case OP_COND_EXC_INC:
3545                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], (ins->opcode < OP_COND_EXC_INE_UN), ins->inst_p1);
3546                         break;
3547                 case OP_IBEQ:
3548                 case OP_IBNE_UN:
3549                 case OP_IBLT:
3550                 case OP_IBLT_UN:
3551                 case OP_IBGT:
3552                 case OP_IBGT_UN:
3553                 case OP_IBGE:
3554                 case OP_IBGE_UN:
3555                 case OP_IBLE:
3556                 case OP_IBLE_UN:
3557                         EMIT_COND_BRANCH (ins, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3558                         break;
3559
3560                 case OP_CMOV_IEQ:
3561                 case OP_CMOV_IGE:
3562                 case OP_CMOV_IGT:
3563                 case OP_CMOV_ILE:
3564                 case OP_CMOV_ILT:
3565                 case OP_CMOV_INE_UN:
3566                 case OP_CMOV_IGE_UN:
3567                 case OP_CMOV_IGT_UN:
3568                 case OP_CMOV_ILE_UN:
3569                 case OP_CMOV_ILT_UN:
3570                         g_assert (ins->dreg == ins->sreg1);
3571                         x86_cmov_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, ins->sreg2);
3572                         break;
3573
3574                 /* floating point opcodes */
3575                 case OP_R8CONST: {
3576                         double d = *(double *)ins->inst_p0;
3577
3578                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
3579                                 x86_fldz (code);
3580                         } else if (d == 1.0) {
3581                                 x86_fld1 (code);
3582                         } else {
3583                                 if (cfg->compile_aot) {
3584                                         guint32 *val = (guint32*)&d;
3585                                         x86_push_imm (code, val [1]);
3586                                         x86_push_imm (code, val [0]);
3587                                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3588                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3589                                 }
3590                                 else {
3591                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R8, ins->inst_p0);
3592                                         x86_fld (code, NULL, TRUE);
3593                                 }
3594                         }
3595                         break;
3596                 }
3597                 case OP_R4CONST: {
3598                         float f = *(float *)ins->inst_p0;
3599
3600                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
3601                                 x86_fldz (code);
3602                         } else if (f == 1.0) {
3603                                 x86_fld1 (code);
3604                         } else {
3605                                 if (cfg->compile_aot) {
3606                                         guint32 val = *(guint32*)&f;
3607                                         x86_push_imm (code, val);
3608                                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3609                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3610                                 }
3611                                 else {
3612                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R4, ins->inst_p0);
3613                                         x86_fld (code, NULL, FALSE);
3614                                 }
3615                         }
3616                         break;
3617                 }
3618                 case OP_STORER8_MEMBASE_REG:
3619                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
3620                         break;
3621                 case OP_LOADR8_MEMBASE:
3622                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3623                         break;
3624                 case OP_STORER4_MEMBASE_REG:
3625                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
3626                         break;
3627                 case OP_LOADR4_MEMBASE:
3628                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3629                         break;
3630                 case OP_ICONV_TO_R4:
3631                         x86_push_reg (code, ins->sreg1);
3632                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3633                         /* Change precision */
3634                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3635                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3636                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3637                         break;
3638                 case OP_ICONV_TO_R8:
3639                         x86_push_reg (code, ins->sreg1);
3640                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3641                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3642                         break;
3643                 case OP_ICONV_TO_R_UN:
3644                         x86_push_imm (code, 0);
3645                         x86_push_reg (code, ins->sreg1);
3646                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3647                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3648                         break;
3649                 case OP_X86_FP_LOAD_I8:
3650                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3651                         break;
3652                 case OP_X86_FP_LOAD_I4:
3653                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3654                         break;
3655                 case OP_FCONV_TO_R4:
3656                         /* Change precision */
3657                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3658                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3659                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3660                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3661                         break;
3662                 case OP_FCONV_TO_I1:
3663                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
3664                         break;
3665                 case OP_FCONV_TO_U1:
3666                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
3667                         break;
3668                 case OP_FCONV_TO_I2:
3669                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
3670                         break;
3671                 case OP_FCONV_TO_U2:
3672                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
3673                         break;
3674                 case OP_FCONV_TO_I4:
3675                 case OP_FCONV_TO_I:
3676                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
3677                         break;
3678                 case OP_FCONV_TO_I8:
3679                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3680                         x86_fnstcw_membase(code, X86_ESP, 0);
3681                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
3682                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
3683                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
3684                         x86_fldcw_membase (code, X86_ESP, 2);
3685                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3686                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
3687                         x86_pop_reg (code, ins->dreg);
3688                         x86_pop_reg (code, ins->backend.reg3);
3689                         x86_fldcw_membase (code, X86_ESP, 0);
3690                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3691                         break;
3692                 case OP_LCONV_TO_R8_2:
3693                         x86_push_reg (code, ins->sreg2);
3694                         x86_push_reg (code, ins->sreg1);
3695                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3696                         /* Change precision */
3697                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3698                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3699                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3700                         break;
3701                 case OP_LCONV_TO_R4_2:
3702                         x86_push_reg (code, ins->sreg2);
3703                         x86_push_reg (code, ins->sreg1);
3704                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3705                         /* Change precision */
3706                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3707                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3708                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3709                         break;
3710                 case OP_LCONV_TO_R_UN_2: { 
3711                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
3712                         guint8 *br;
3713
3714                         /* load 64bit integer to FP stack */
3715                         x86_push_reg (code, ins->sreg2);
3716                         x86_push_reg (code, ins->sreg1);
3717                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3718                         
3719                         /* test if lreg is negative */
3720                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3721                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
3722         
3723                         /* add correction constant mn */
3724                         if (cfg->compile_aot) {
3725                                 x86_push_imm (code, (((guint32)mn [9]) << 24) | ((guint32)mn [8] << 16) | ((guint32)mn [7] << 8) | ((guint32)mn [6]));
3726                                 x86_push_imm (code, (((guint32)mn [5]) << 24) | ((guint32)mn [4] << 16) | ((guint32)mn [3] << 8) | ((guint32)mn [2]));
3727                                 x86_push_imm (code, (((guint32)mn [1]) << 24) | ((guint32)mn [0] << 16));
3728                                 x86_fld80_membase (code, X86_ESP, 2);
3729                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
3730                         } else {
3731                                 x86_fld80_mem (code, mn);
3732                         }
3733                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3734
3735                         x86_patch (br, code);
3736
3737                         /* Change precision */
3738                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3739                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3740
3741                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3742
3743                         break;
3744                 }
3745                 case OP_LCONV_TO_OVF_I:
3746                 case OP_LCONV_TO_OVF_I4_2: {
3747                         guint8 *br [3], *label [1];
3748                         MonoInst *tins;
3749
3750                         /* 
3751                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3752                          */
3753                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
3754
3755                         /* If the low word top bit is set, see if we are negative */
3756                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
3757                         /* We are not negative (no top bit set, check for our top word to be zero */
3758                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3759                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
3760                         label [0] = code;
3761
3762                         /* throw exception */
3763                         tins = mono_branch_optimize_exception_target (cfg, bb, "OverflowException");
3764                         if (tins) {
3765                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, tins->inst_true_bb);
3766                                 if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (tins->inst_true_bb->max_offset - cpos))
3767                                         x86_jump8 (code, 0);
3768                                 else
3769                                         x86_jump32 (code, 0);
3770                         } else {
3771                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
3772                                 x86_jump32 (code, 0);
3773                         }
3774         
3775         
3776                         x86_patch (br [0], code);
3777                         /* our top bit is set, check that top word is 0xfffffff */
3778                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
3779                 
3780                         x86_patch (br [1], code);
3781                         /* nope, emit exception */
3782                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
3783                         x86_patch (br [2], label [0]);
3784
3785                         if (ins->dreg != ins->sreg1)
3786                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3787                         break;
3788                 }
3789                 case OP_FMOVE:
3790                         /* Not needed on the fp stack */
3791                         break;
3792                 case OP_FADD:
3793                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3794                         break;
3795                 case OP_FSUB:
3796                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
3797                         break;          
3798                 case OP_FMUL:
3799                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
3800                         break;          
3801                 case OP_FDIV:
3802                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
3803                         break;          
3804                 case OP_FNEG:
3805                         x86_fchs (code);
3806                         break;          
3807                 case OP_SIN:
3808                         x86_fsin (code);
3809                         x86_fldz (code);
3810                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3811                         break;          
3812                 case OP_COS:
3813                         x86_fcos (code);
3814                         x86_fldz (code);
3815                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3816                         break;          
3817                 case OP_ABS:
3818                         x86_fabs (code);
3819                         break;          
3820                 case OP_TAN: {
3821                         /* 
3822                          * it really doesn't make sense to inline all this code,
3823                          * it's here just to show that things may not be as simple 
3824                          * as they appear.
3825                          */
3826                         guchar *check_pos, *end_tan, *pop_jump;
3827                         x86_push_reg (code, X86_EAX);
3828                         x86_fptan (code);
3829                         x86_fnstsw (code);
3830                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3831                         check_pos = code;
3832                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3833                         x86_fstp (code, 0); /* pop the 1.0 */
3834                         end_tan = code;
3835                         x86_jump8 (code, 0);
3836                         x86_fldpi (code);
3837                         x86_fp_op (code, X86_FADD, 0);
3838                         x86_fxch (code, 1);
3839                         x86_fprem1 (code);
3840                         x86_fstsw (code);
3841                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3842                         pop_jump = code;
3843                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3844                         x86_fstp (code, 1);
3845                         x86_fptan (code);
3846                         x86_patch (pop_jump, code);
3847                         x86_fstp (code, 0); /* pop the 1.0 */
3848                         x86_patch (check_pos, code);
3849                         x86_patch (end_tan, code);
3850                         x86_fldz (code);
3851                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3852                         x86_pop_reg (code, X86_EAX);
3853                         break;
3854                 }
3855                 case OP_ATAN:
3856                         x86_fld1 (code);
3857                         x86_fpatan (code);
3858                         x86_fldz (code);
3859                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3860                         break;          
3861                 case OP_SQRT:
3862                         x86_fsqrt (code);
3863                         break;
3864                 case OP_ROUND:
3865                         x86_frndint (code);
3866                         break;
3867                 case OP_IMIN:
3868                         g_assert (cfg->opt & MONO_OPT_CMOV);
3869                         g_assert (ins->dreg == ins->sreg1);
3870                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3871                         x86_cmov_reg (code, X86_CC_GT, TRUE, ins->dreg, ins->sreg2);
3872                         break;
3873                 case OP_IMIN_UN:
3874                         g_assert (cfg->opt & MONO_OPT_CMOV);
3875                         g_assert (ins->dreg == ins->sreg1);
3876                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3877                         x86_cmov_reg (code, X86_CC_GT, FALSE, ins->dreg, ins->sreg2);
3878                         break;
3879                 case OP_IMAX:
3880                         g_assert (cfg->opt & MONO_OPT_CMOV);
3881                         g_assert (ins->dreg == ins->sreg1);
3882                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3883                         x86_cmov_reg (code, X86_CC_LT, TRUE, ins->dreg, ins->sreg2);
3884                         break;
3885                 case OP_IMAX_UN:
3886                         g_assert (cfg->opt & MONO_OPT_CMOV);
3887                         g_assert (ins->dreg == ins->sreg1);
3888                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3889                         x86_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2);
3890                         break;
3891                 case OP_X86_FPOP:
3892                         x86_fstp (code, 0);
3893                         break;
3894                 case OP_X86_FXCH:
3895                         x86_fxch (code, ins->inst_imm);
3896                         break;
3897                 case OP_FREM: {
3898                         guint8 *l1, *l2;
3899
3900                         x86_push_reg (code, X86_EAX);
3901                         /* we need to exchange ST(0) with ST(1) */
3902                         x86_fxch (code, 1);
3903
3904                         /* this requires a loop, because fprem somtimes 
3905                          * returns a partial remainder */
3906                         l1 = code;
3907                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3908                         /* x86_fprem1 (code); */
3909                         x86_fprem (code);
3910                         x86_fnstsw (code);
3911                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3912                         l2 = code;
3913                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3914                         x86_patch (l2, l1);
3915
3916                         /* pop result */
3917                         x86_fstp (code, 1);
3918
3919                         x86_pop_reg (code, X86_EAX);
3920                         break;
3921                 }
3922                 case OP_FCOMPARE:
3923                         if (cfg->opt & MONO_OPT_FCMOV) {
3924                                 x86_fcomip (code, 1);
3925                                 x86_fstp (code, 0);
3926                                 break;
3927                         }
3928                         /* this overwrites EAX */
3929                         EMIT_FPCOMPARE(code);
3930                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3931                         break;
3932                 case OP_FCEQ:
3933                         if (cfg->opt & MONO_OPT_FCMOV) {
3934                                 /* zeroing the register at the start results in 
3935                                  * shorter and faster code (we can also remove the widening op)
3936                                  */
3937                                 guchar *unordered_check;
3938                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3939                                 x86_fcomip (code, 1);
3940                                 x86_fstp (code, 0);
3941                                 unordered_check = code;
3942                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3943                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3944                                 x86_patch (unordered_check, code);
3945                                 break;
3946                         }
3947                         if (ins->dreg != X86_EAX) 
3948                                 x86_push_reg (code, X86_EAX);
3949
3950                         EMIT_FPCOMPARE(code);
3951                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3952                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3953                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3954                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3955
3956                         if (ins->dreg != X86_EAX) 
3957                                 x86_pop_reg (code, X86_EAX);
3958                         break;
3959                 case OP_FCLT:
3960                 case OP_FCLT_UN:
3961                         if (cfg->opt & MONO_OPT_FCMOV) {
3962                                 /* zeroing the register at the start results in 
3963                                  * shorter and faster code (we can also remove the widening op)
3964                                  */
3965                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3966                                 x86_fcomip (code, 1);
3967                                 x86_fstp (code, 0);
3968                                 if (ins->opcode == OP_FCLT_UN) {
3969                                         guchar *unordered_check = code;
3970                                         guchar *jump_to_end;
3971                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3972                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3973                                         jump_to_end = code;
3974                                         x86_jump8 (code, 0);
3975                                         x86_patch (unordered_check, code);
3976                                         x86_inc_reg (code, ins->dreg);
3977                                         x86_patch (jump_to_end, code);
3978                                 } else {
3979                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3980                                 }
3981                                 break;
3982                         }
3983                         if (ins->dreg != X86_EAX) 
3984                                 x86_push_reg (code, X86_EAX);
3985
3986                         EMIT_FPCOMPARE(code);
3987                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3988                         if (ins->opcode == OP_FCLT_UN) {
3989                                 guchar *is_not_zero_check, *end_jump;
3990                                 is_not_zero_check = code;
3991                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3992                                 end_jump = code;
3993                                 x86_jump8 (code, 0);
3994                                 x86_patch (is_not_zero_check, code);
3995                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3996
3997                                 x86_patch (end_jump, code);
3998                         }
3999                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
4000                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4001
4002                         if (ins->dreg != X86_EAX) 
4003                                 x86_pop_reg (code, X86_EAX);
4004                         break;
4005                 case OP_FCGT:
4006                 case OP_FCGT_UN:
4007                         if (cfg->opt & MONO_OPT_FCMOV) {
4008                                 /* zeroing the register at the start results in 
4009                                  * shorter and faster code (we can also remove the widening op)
4010                                  */
4011                                 guchar *unordered_check;
4012                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
4013                                 x86_fcomip (code, 1);
4014                                 x86_fstp (code, 0);
4015                                 if (ins->opcode == OP_FCGT) {
4016                                         unordered_check = code;
4017                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
4018                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
4019                                         x86_patch (unordered_check, code);
4020                                 } else {
4021                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
4022                                 }
4023                                 break;
4024                         }
4025                         if (ins->dreg != X86_EAX) 
4026                                 x86_push_reg (code, X86_EAX);
4027
4028                         EMIT_FPCOMPARE(code);
4029                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
4030                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4031                         if (ins->opcode == OP_FCGT_UN) {
4032                                 guchar *is_not_zero_check, *end_jump;
4033                                 is_not_zero_check = code;
4034                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
4035                                 end_jump = code;
4036                                 x86_jump8 (code, 0);
4037                                 x86_patch (is_not_zero_check, code);
4038                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
4039         
4040                                 x86_patch (end_jump, code);
4041                         }
4042                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
4043                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4044
4045                         if (ins->dreg != X86_EAX) 
4046                                 x86_pop_reg (code, X86_EAX);
4047                         break;
4048                 case OP_FBEQ:
4049                         if (cfg->opt & MONO_OPT_FCMOV) {
4050                                 guchar *jump = code;
4051                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
4052                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4053                                 x86_patch (jump, code);
4054                                 break;
4055                         }
4056                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
4057                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
4058                         break;
4059                 case OP_FBNE_UN:
4060                         /* Branch if C013 != 100 */
4061                         if (cfg->opt & MONO_OPT_FCMOV) {
4062                                 /* branch if !ZF or (PF|CF) */
4063                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4064                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
4065                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
4066                                 break;
4067                         }
4068                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
4069                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4070                         break;
4071                 case OP_FBLT:
4072                         if (cfg->opt & MONO_OPT_FCMOV) {
4073                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
4074                                 break;
4075                         }
4076                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4077                         break;
4078                 case OP_FBLT_UN:
4079                         if (cfg->opt & MONO_OPT_FCMOV) {
4080                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
4081                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
4082                                 break;
4083                         }
4084                         if (ins->opcode == OP_FBLT_UN) {
4085                                 guchar *is_not_zero_check, *end_jump;
4086                                 is_not_zero_check = code;
4087                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
4088                                 end_jump = code;
4089                                 x86_jump8 (code, 0);
4090                                 x86_patch (is_not_zero_check, code);
4091                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
4092
4093                                 x86_patch (end_jump, code);
4094                         }
4095                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4096                         break;
4097                 case OP_FBGT:
4098                 case OP_FBGT_UN:
4099                         if (cfg->opt & MONO_OPT_FCMOV) {
4100                                 if (ins->opcode == OP_FBGT) {
4101                                         guchar *br1;
4102
4103                                         /* skip branch if C1=1 */
4104                                         br1 = code;
4105                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
4106                                         /* branch if (C0 | C3) = 1 */
4107                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
4108                                         x86_patch (br1, code);
4109                                 } else {
4110                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
4111                                 }
4112                                 break;
4113                         }
4114                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4115                         if (ins->opcode == OP_FBGT_UN) {
4116                                 guchar *is_not_zero_check, *end_jump;
4117                                 is_not_zero_check = code;
4118                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
4119                                 end_jump = code;
4120                                 x86_jump8 (code, 0);
4121                                 x86_patch (is_not_zero_check, code);
4122                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
4123
4124                                 x86_patch (end_jump, code);
4125                         }
4126                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4127                         break;
4128                 case OP_FBGE:
4129                         /* Branch if C013 == 100 or 001 */
4130                         if (cfg->opt & MONO_OPT_FCMOV) {
4131                                 guchar *br1;
4132
4133                                 /* skip branch if C1=1 */
4134                                 br1 = code;
4135                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
4136                                 /* branch if (C0 | C3) = 1 */
4137                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
4138                                 x86_patch (br1, code);
4139                                 break;
4140                         }
4141                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4142                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4143                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
4144                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4145                         break;
4146                 case OP_FBGE_UN:
4147                         /* Branch if C013 == 000 */
4148                         if (cfg->opt & MONO_OPT_FCMOV) {
4149                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
4150                                 break;
4151                         }
4152                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4153                         break;
4154                 case OP_FBLE:
4155                         /* Branch if C013=000 or 100 */
4156                         if (cfg->opt & MONO_OPT_FCMOV) {
4157                                 guchar *br1;
4158
4159                                 /* skip branch if C1=1 */
4160                                 br1 = code;
4161                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
4162                                 /* branch if C0=0 */
4163                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
4164                                 x86_patch (br1, code);
4165                                 break;
4166                         }
4167                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
4168                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
4169                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4170                         break;
4171                 case OP_FBLE_UN:
4172                         /* Branch if C013 != 001 */
4173                         if (cfg->opt & MONO_OPT_FCMOV) {
4174                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
4175                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
4176                                 break;
4177                         }
4178                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4179                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4180                         break;
4181                 case OP_CKFINITE: {
4182                         guchar *br1;
4183                         x86_push_reg (code, X86_EAX);
4184                         x86_fxam (code);
4185                         x86_fnstsw (code);
4186                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
4187                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4188                         x86_pop_reg (code, X86_EAX);
4189
4190                         /* Have to clean up the fp stack before throwing the exception */
4191                         br1 = code;
4192                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
4193
4194                         x86_fstp (code, 0);                     
4195                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
4196
4197                         x86_patch (br1, code);
4198                         break;
4199                 }
4200                 case OP_TLS_GET: {
4201                         code = mono_x86_emit_tls_get (code, ins->dreg, ins->inst_offset);
4202                         break;
4203                 }
4204                 case OP_TLS_GET_REG: {
4205 #ifdef __APPLE__
4206                         // FIXME: tls_gs_offset can change too, do these when calculating the tls offset
4207                         if (ins->dreg != ins->sreg1)
4208                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, sizeof (gpointer));
4209                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
4210                         if (tls_gs_offset)
4211                                 x86_alu_reg_imm (code, X86_ADD, ins->dreg, tls_gs_offset);
4212                         x86_prefix (code, X86_GS_PREFIX);
4213                         x86_mov_reg_membase (code, ins->dreg, ins->dreg, 0, sizeof (gpointer));
4214 #else
4215                         g_assert_not_reached ();
4216 #endif
4217                         break;
4218                 }
4219                 case OP_MEMORY_BARRIER: {
4220                         /* x86 only needs barrier for StoreLoad and FullBarrier */
4221                         switch (ins->backend.memory_barrier_kind) {
4222                         case StoreLoadBarrier:
4223                         case FullBarrier:
4224                                 /* http://blogs.sun.com/dave/resource/NHM-Pipeline-Blog-V2.txt */
4225                                 x86_prefix (code, X86_LOCK_PREFIX);
4226                                 x86_alu_membase_imm (code, X86_ADD, X86_ESP, 0, 0);
4227                                 break;
4228                         }
4229                         break;
4230                 }
4231                 case OP_ATOMIC_ADD_I4: {
4232                         int dreg = ins->dreg;
4233
4234                         if (dreg == ins->inst_basereg) {
4235                                 x86_push_reg (code, ins->sreg2);
4236                                 dreg = ins->sreg2;
4237                         } 
4238                         
4239                         if (dreg != ins->sreg2)
4240                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
4241
4242                         x86_prefix (code, X86_LOCK_PREFIX);
4243                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
4244
4245                         if (dreg != ins->dreg) {
4246                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
4247                                 x86_pop_reg (code, dreg);
4248                         }
4249
4250                         break;
4251                 }
4252                 case OP_ATOMIC_ADD_NEW_I4: {
4253                         int dreg = ins->dreg;
4254
4255                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
4256                         if (ins->sreg2 == dreg) {
4257                                 if (dreg == X86_EBX) {
4258                                         dreg = X86_EDI;
4259                                         if (ins->inst_basereg == X86_EDI)
4260                                                 dreg = X86_ESI;
4261                                 } else {
4262                                         dreg = X86_EBX;
4263                                         if (ins->inst_basereg == X86_EBX)
4264                                                 dreg = X86_EDI;
4265                                 }
4266                         } else if (ins->inst_basereg == dreg) {
4267                                 if (dreg == X86_EBX) {
4268                                         dreg = X86_EDI;
4269                                         if (ins->sreg2 == X86_EDI)
4270                                                 dreg = X86_ESI;
4271                                 } else {
4272                                         dreg = X86_EBX;
4273                                         if (ins->sreg2 == X86_EBX)
4274                                                 dreg = X86_EDI;
4275                                 }
4276                         }
4277
4278                         if (dreg != ins->dreg) {
4279                                 x86_push_reg (code, dreg);
4280                         }
4281
4282                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
4283                         x86_prefix (code, X86_LOCK_PREFIX);
4284                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
4285                         /* dreg contains the old value, add with sreg2 value */
4286                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
4287                         
4288                         if (ins->dreg != dreg) {
4289                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
4290                                 x86_pop_reg (code, dreg);
4291                         }
4292
4293                         break;
4294                 }
4295                 case OP_ATOMIC_EXCHANGE_I4: {
4296                         guchar *br[2];
4297                         int sreg2 = ins->sreg2;
4298                         int breg = ins->inst_basereg;
4299
4300                         /* cmpxchg uses eax as comperand, need to make sure we can use it
4301                          * hack to overcome limits in x86 reg allocator 
4302                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
4303                          */
4304                         g_assert (ins->dreg == X86_EAX);
4305                         
4306                         /* We need the EAX reg for the cmpxchg */
4307                         if (ins->sreg2 == X86_EAX) {
4308                                 sreg2 = (breg == X86_EDX) ? X86_EBX : X86_EDX;
4309                                 x86_push_reg (code, sreg2);
4310                                 x86_mov_reg_reg (code, sreg2, X86_EAX, 4);
4311                         }
4312
4313                         if (breg == X86_EAX) {
4314                                 breg = (sreg2 == X86_ESI) ? X86_EDI : X86_ESI;
4315                                 x86_push_reg (code, breg);
4316                                 x86_mov_reg_reg (code, breg, X86_EAX, 4);
4317                         }
4318
4319                         x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
4320
4321                         br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
4322                         x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
4323                         br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
4324                         x86_patch (br [1], br [0]);
4325
4326                         if (breg != ins->inst_basereg)
4327                                 x86_pop_reg (code, breg);
4328
4329                         if (ins->sreg2 != sreg2)
4330                                 x86_pop_reg (code, sreg2);
4331
4332                         break;
4333                 }
4334                 case OP_ATOMIC_CAS_I4: {
4335                         g_assert (ins->dreg == X86_EAX);
4336                         g_assert (ins->sreg3 == X86_EAX);
4337                         g_assert (ins->sreg1 != X86_EAX);
4338                         g_assert (ins->sreg1 != ins->sreg2);
4339
4340                         x86_prefix (code, X86_LOCK_PREFIX);
4341                         x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2);
4342                         break;
4343                 }
4344                 case OP_CARD_TABLE_WBARRIER: {
4345                         int ptr = ins->sreg1;
4346                         int value = ins->sreg2;
4347                         guchar *br;
4348                         int nursery_shift, card_table_shift;
4349                         gpointer card_table_mask;
4350                         size_t nursery_size;
4351                         gulong card_table = (gulong)mono_gc_get_card_table (&card_table_shift, &card_table_mask);
4352                         gulong nursery_start = (gulong)mono_gc_get_nursery (&nursery_shift, &nursery_size);
4353                         gboolean card_table_nursery_check = mono_gc_card_table_nursery_check ();
4354
4355                         /*
4356                          * We need one register we can clobber, we choose EDX and make sreg1
4357                          * fixed EAX to work around limitations in the local register allocator.
4358                          * sreg2 might get allocated to EDX, but that is not a problem since
4359                          * we use it before clobbering EDX.
4360                          */
4361                         g_assert (ins->sreg1 == X86_EAX);
4362
4363                         /*
4364                          * This is the code we produce:
4365                          *
4366                          *   edx = value
4367                          *   edx >>= nursery_shift
4368                          *   cmp edx, (nursery_start >> nursery_shift)
4369                          *   jne done
4370                          *   edx = ptr
4371                          *   edx >>= card_table_shift
4372                          *   card_table[edx] = 1
4373                          * done:
4374                          */
4375
4376                         if (card_table_nursery_check) {
4377                                 if (value != X86_EDX)
4378                                         x86_mov_reg_reg (code, X86_EDX, value, 4);
4379                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, nursery_shift);
4380                                 x86_alu_reg_imm (code, X86_CMP, X86_EDX, nursery_start >> nursery_shift);
4381                                 br = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
4382                         }
4383                         x86_mov_reg_reg (code, X86_EDX, ptr, 4);
4384                         x86_shift_reg_imm (code, X86_SHR, X86_EDX, card_table_shift);
4385                         if (card_table_mask)
4386                                 x86_alu_reg_imm (code, X86_AND, X86_EDX, (int)card_table_mask);
4387                         x86_mov_membase_imm (code, X86_EDX, card_table, 1, 1);
4388                         if (card_table_nursery_check)
4389                                 x86_patch (br, code);
4390                         break;
4391                 }
4392 #ifdef MONO_ARCH_SIMD_INTRINSICS
4393                 case OP_ADDPS:
4394                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4395                         break;
4396                 case OP_DIVPS:
4397                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4398                         break;
4399                 case OP_MULPS:
4400                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4401                         break;
4402                 case OP_SUBPS:
4403                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4404                         break;
4405                 case OP_MAXPS:
4406                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4407                         break;
4408                 case OP_MINPS:
4409                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4410                         break;
4411                 case OP_COMPPS:
4412                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4413                         x86_sse_alu_ps_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4414                         break;
4415                 case OP_ANDPS:
4416                         x86_sse_alu_ps_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4417                         break;
4418                 case OP_ANDNPS:
4419                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4420                         break;
4421                 case OP_ORPS:
4422                         x86_sse_alu_ps_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4423                         break;
4424                 case OP_XORPS:
4425                         x86_sse_alu_ps_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4426                         break;
4427                 case OP_SQRTPS:
4428                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4429                         break;
4430                 case OP_RSQRTPS:
4431                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
4432                         break;
4433                 case OP_RCPPS:
4434                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RCP, ins->dreg, ins->sreg1);
4435                         break;
4436                 case OP_ADDSUBPS:
4437                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4438                         break;
4439                 case OP_HADDPS:
4440                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4441                         break;
4442                 case OP_HSUBPS:
4443                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4444                         break;
4445                 case OP_DUPPS_HIGH:
4446                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSHDUP, ins->dreg, ins->sreg1);
4447                         break;
4448                 case OP_DUPPS_LOW:
4449                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSLDUP, ins->dreg, ins->sreg1);
4450                         break;
4451
4452                 case OP_PSHUFLEW_HIGH:
4453                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4454                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 1);
4455                         break;
4456                 case OP_PSHUFLEW_LOW:
4457                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4458                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 0);
4459                         break;
4460                 case OP_PSHUFLED:
4461                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4462                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0);
4463                         break;
4464                 case OP_SHUFPS:
4465                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4466                         x86_sse_alu_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0);
4467                         break; 
4468                 case OP_SHUFPD:
4469                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3);
4470                         x86_sse_alu_pd_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0);
4471                         break; 
4472
4473                 case OP_ADDPD:
4474                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4475                         break;
4476                 case OP_DIVPD:
4477                         x86_sse_alu_pd_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4478                         break;
4479                 case OP_MULPD:
4480                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4481                         break;
4482                 case OP_SUBPD:
4483                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4484                         break;
4485                 case OP_MAXPD:
4486                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4487                         break;
4488                 case OP_MINPD:
4489                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4490                         break;
4491                 case OP_COMPPD:
4492                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4493                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4494                         break;
4495                 case OP_ANDPD:
4496                         x86_sse_alu_pd_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4497                         break;
4498                 case OP_ANDNPD:
4499                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4500                         break;
4501                 case OP_ORPD:
4502                         x86_sse_alu_pd_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4503                         break;
4504                 case OP_XORPD:
4505                         x86_sse_alu_pd_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4506                         break;
4507                 case OP_SQRTPD:
4508                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4509                         break;
4510                 case OP_ADDSUBPD:
4511                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4512                         break;
4513                 case OP_HADDPD:
4514                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4515                         break;
4516                 case OP_HSUBPD:
4517                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4518                         break;
4519                 case OP_DUPPD:
4520                         x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1);
4521                         break;
4522                         
4523                 case OP_EXTRACT_MASK:
4524                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1);
4525                         break;
4526         
4527                 case OP_PAND:
4528                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
4529                         break;
4530                 case OP_POR:
4531                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
4532                         break;
4533                 case OP_PXOR:
4534                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
4535                         break;
4536
4537                 case OP_PADDB:
4538                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDB, ins->sreg1, ins->sreg2);
4539                         break;
4540                 case OP_PADDW:
4541                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDW, ins->sreg1, ins->sreg2);
4542                         break;
4543                 case OP_PADDD:
4544                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDD, ins->sreg1, ins->sreg2);
4545                         break;
4546                 case OP_PADDQ:
4547                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDQ, ins->sreg1, ins->sreg2);
4548                         break;
4549
4550                 case OP_PSUBB:
4551                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBB, ins->sreg1, ins->sreg2);
4552                         break;
4553                 case OP_PSUBW:
4554                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBW, ins->sreg1, ins->sreg2);
4555                         break;
4556                 case OP_PSUBD:
4557                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBD, ins->sreg1, ins->sreg2);
4558                         break;
4559                 case OP_PSUBQ:
4560                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBQ, ins->sreg1, ins->sreg2);
4561                         break;
4562
4563                 case OP_PMAXB_UN:
4564                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXUB, ins->sreg1, ins->sreg2);
4565                         break;
4566                 case OP_PMAXW_UN:
4567                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUW, ins->sreg1, ins->sreg2);
4568                         break;
4569                 case OP_PMAXD_UN:
4570                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2);
4571                         break;
4572                 
4573                 case OP_PMAXB:
4574                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2);
4575                         break;
4576                 case OP_PMAXW:
4577                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXSW, ins->sreg1, ins->sreg2);
4578                         break;
4579                 case OP_PMAXD:
4580                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSD, ins->sreg1, ins->sreg2);
4581                         break;
4582
4583                 case OP_PAVGB_UN:
4584                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGB, ins->sreg1, ins->sreg2);
4585                         break;
4586                 case OP_PAVGW_UN:
4587                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGW, ins->sreg1, ins->sreg2);
4588                         break;
4589
4590                 case OP_PMINB_UN:
4591                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINUB, ins->sreg1, ins->sreg2);
4592                         break;
4593                 case OP_PMINW_UN:
4594                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUW, ins->sreg1, ins->sreg2);
4595                         break;
4596                 case OP_PMIND_UN:
4597                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUD, ins->sreg1, ins->sreg2);
4598                         break;
4599
4600                 case OP_PMINB:
4601                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSB, ins->sreg1, ins->sreg2);
4602                         break;
4603                 case OP_PMINW:
4604                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINSW, ins->sreg1, ins->sreg2);
4605                         break;
4606                 case OP_PMIND:
4607                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSD, ins->sreg1, ins->sreg2);
4608                         break;
4609
4610                 case OP_PCMPEQB:
4611                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->sreg1, ins->sreg2);
4612                         break;
4613                 case OP_PCMPEQW:
4614                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQW, ins->sreg1, ins->sreg2);
4615                         break;
4616                 case OP_PCMPEQD:
4617                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQD, ins->sreg1, ins->sreg2);
4618                         break;
4619                 case OP_PCMPEQQ:
4620                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPEQQ, ins->sreg1, ins->sreg2);
4621                         break;
4622
4623                 case OP_PCMPGTB:
4624                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTB, ins->sreg1, ins->sreg2);
4625                         break;
4626                 case OP_PCMPGTW:
4627                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTW, ins->sreg1, ins->sreg2);
4628                         break;
4629                 case OP_PCMPGTD:
4630                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTD, ins->sreg1, ins->sreg2);
4631                         break;
4632                 case OP_PCMPGTQ:
4633                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPGTQ, ins->sreg1, ins->sreg2);
4634                         break;
4635
4636                 case OP_PSUM_ABS_DIFF:
4637                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSADBW, ins->sreg1, ins->sreg2);
4638                         break;
4639
4640                 case OP_UNPACK_LOWB:
4641                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLBW, ins->sreg1, ins->sreg2);
4642                         break;
4643                 case OP_UNPACK_LOWW:
4644                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLWD, ins->sreg1, ins->sreg2);
4645                         break;
4646                 case OP_UNPACK_LOWD:
4647                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLDQ, ins->sreg1, ins->sreg2);
4648                         break;
4649                 case OP_UNPACK_LOWQ:
4650                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLQDQ, ins->sreg1, ins->sreg2);
4651                         break;
4652                 case OP_UNPACK_LOWPS:
4653                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4654                         break;
4655                 case OP_UNPACK_LOWPD:
4656                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4657                         break;
4658
4659                 case OP_UNPACK_HIGHB:
4660                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHBW, ins->sreg1, ins->sreg2);
4661                         break;
4662                 case OP_UNPACK_HIGHW:
4663                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHWD, ins->sreg1, ins->sreg2);
4664                         break;
4665                 case OP_UNPACK_HIGHD:
4666                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHDQ, ins->sreg1, ins->sreg2);
4667                         break;
4668                 case OP_UNPACK_HIGHQ:
4669                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHQDQ, ins->sreg1, ins->sreg2);
4670                         break;
4671                 case OP_UNPACK_HIGHPS:
4672                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4673                         break;
4674                 case OP_UNPACK_HIGHPD:
4675                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4676                         break;
4677
4678                 case OP_PACKW:
4679                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSWB, ins->sreg1, ins->sreg2);
4680                         break;
4681                 case OP_PACKD:
4682                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSDW, ins->sreg1, ins->sreg2);
4683                         break;
4684                 case OP_PACKW_UN:
4685                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKUSWB, ins->sreg1, ins->sreg2);
4686                         break;
4687                 case OP_PACKD_UN:
4688                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PACKUSDW, ins->sreg1, ins->sreg2);
4689                         break;
4690
4691                 case OP_PADDB_SAT_UN:
4692                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSB, ins->sreg1, ins->sreg2);
4693                         break;
4694                 case OP_PSUBB_SAT_UN:
4695                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSB, ins->sreg1, ins->sreg2);
4696                         break;
4697                 case OP_PADDW_SAT_UN:
4698                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSW, ins->sreg1, ins->sreg2);
4699                         break;
4700                 case OP_PSUBW_SAT_UN:
4701                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSW, ins->sreg1, ins->sreg2);
4702                         break;
4703
4704                 case OP_PADDB_SAT:
4705                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSB, ins->sreg1, ins->sreg2);
4706                         break;
4707                 case OP_PSUBB_SAT:
4708                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSB, ins->sreg1, ins->sreg2);
4709                         break;
4710                 case OP_PADDW_SAT:
4711                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSW, ins->sreg1, ins->sreg2);
4712                         break;
4713                 case OP_PSUBW_SAT:
4714                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2);
4715                         break;
4716                         
4717                 case OP_PMULW:
4718                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2);
4719                         break;
4720                 case OP_PMULD:
4721                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMULLD, ins->sreg1, ins->sreg2);
4722                         break;
4723                 case OP_PMULQ:
4724                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULUDQ, ins->sreg1, ins->sreg2);
4725                         break;
4726                 case OP_PMULW_HIGH_UN:
4727                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHUW, ins->sreg1, ins->sreg2);
4728                         break;
4729                 case OP_PMULW_HIGH:
4730                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHW, ins->sreg1, ins->sreg2);
4731                         break;
4732
4733                 case OP_PSHRW:
4734                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4735                         break;
4736                 case OP_PSHRW_REG:
4737                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLW_REG, ins->dreg, ins->sreg2);
4738                         break;
4739
4740                 case OP_PSARW:
4741                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4742                         break;
4743                 case OP_PSARW_REG:
4744                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAW_REG, ins->dreg, ins->sreg2);
4745                         break;
4746
4747                 case OP_PSHLW:
4748                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4749                         break;
4750                 case OP_PSHLW_REG:
4751                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLW_REG, ins->dreg, ins->sreg2);
4752                         break;
4753
4754                 case OP_PSHRD:
4755                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4756                         break;
4757                 case OP_PSHRD_REG:
4758                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLD_REG, ins->dreg, ins->sreg2);
4759                         break;
4760
4761                 case OP_PSARD:
4762                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4763                         break;
4764                 case OP_PSARD_REG:
4765                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAD_REG, ins->dreg, ins->sreg2);
4766                         break;
4767
4768                 case OP_PSHLD:
4769                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4770                         break;
4771                 case OP_PSHLD_REG:
4772                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLD_REG, ins->dreg, ins->sreg2);
4773                         break;
4774
4775                 case OP_PSHRQ:
4776                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4777                         break;
4778                 case OP_PSHRQ_REG:
4779                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLQ_REG, ins->dreg, ins->sreg2);
4780                         break;
4781
4782                 case OP_PSHLQ:
4783                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4784                         break;
4785                 case OP_PSHLQ_REG:
4786                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2);
4787                         break;          
4788                         
4789                 case OP_ICONV_TO_X:
4790                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4791                         break;
4792                 case OP_EXTRACT_I4:
4793                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4794                         break;
4795                 case OP_EXTRACT_I1:
4796                 case OP_EXTRACT_U1:
4797                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4798                         if (ins->inst_c0)
4799                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
4800                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
4801                         break;
4802                 case OP_EXTRACT_I2:
4803                 case OP_EXTRACT_U2:
4804                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4805                         if (ins->inst_c0)
4806                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, 16);
4807                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE);
4808                         break;
4809                 case OP_EXTRACT_R8:
4810                         if (ins->inst_c0)
4811                                 x86_sse_alu_pd_membase_reg (code, X86_SSE_MOVHPD_MEMBASE_REG, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1);
4812                         else
4813                                 x86_sse_alu_sd_membase_reg (code, X86_SSE_MOVSD_MEMBASE_REG, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1);
4814                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE);
4815                         break;
4816
4817                 case OP_INSERT_I2:
4818                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->sreg1, ins->sreg2, ins->inst_c0);
4819                         break;
4820                 case OP_EXTRACTX_U2:
4821                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PEXTRW, ins->dreg, ins->sreg1, ins->inst_c0);
4822                         break;
4823                 case OP_INSERTX_U1_SLOW:
4824                         /*sreg1 is the extracted ireg (scratch)
4825                         /sreg2 is the to be inserted ireg (scratch)
4826                         /dreg is the xreg to receive the value*/
4827
4828                         /*clear the bits from the extracted word*/
4829                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
4830                         /*shift the value to insert if needed*/
4831                         if (ins->inst_c0 & 1)
4832                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg2, 8);
4833                         /*join them together*/
4834                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
4835                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
4836                         break;
4837                 case OP_INSERTX_I4_SLOW:
4838                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
4839                         x86_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
4840                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
4841                         break;
4842
4843                 case OP_INSERTX_R4_SLOW:
4844                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4845                         /*TODO if inst_c0 == 0 use movss*/
4846                         x86_sse_alu_pd_reg_membase_imm (code, X86_SSE_PINSRW, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset + 0, ins->inst_c0 * 2);
4847                         x86_sse_alu_pd_reg_membase_imm (code, X86_SSE_PINSRW, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset + 2, ins->inst_c0 * 2 + 1);
4848                         break;
4849                 case OP_INSERTX_R8_SLOW:
4850                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4851                         if (cfg->verbose_level)
4852                                 printf ("CONVERTING a OP_INSERTX_R8_SLOW %d offset %x\n", ins->inst_c0, offset);
4853                         if (ins->inst_c0)
4854                                 x86_sse_alu_pd_reg_membase (code, X86_SSE_MOVHPD_REG_MEMBASE, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4855                         else
4856                                 x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4857                         break;
4858
4859                 case OP_STOREX_MEMBASE_REG:
4860                 case OP_STOREX_MEMBASE:
4861                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4862                         break;
4863                 case OP_LOADX_MEMBASE:
4864                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4865                         break;
4866                 case OP_LOADX_ALIGNED_MEMBASE:
4867                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4868                         break;
4869                 case OP_STOREX_ALIGNED_MEMBASE_REG:
4870                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4871                         break;
4872                 case OP_STOREX_NTA_MEMBASE_REG:
4873                         x86_sse_alu_reg_membase (code, X86_SSE_MOVNTPS, ins->dreg, ins->sreg1, ins->inst_offset);
4874                         break;
4875                 case OP_PREFETCH_MEMBASE:
4876                         x86_sse_alu_reg_membase (code, X86_SSE_PREFETCH, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
4877
4878                         break;
4879                 case OP_XMOVE:
4880                         /*FIXME the peephole pass should have killed this*/
4881                         if (ins->dreg != ins->sreg1)
4882                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
4883                         break;          
4884                 case OP_XZERO:
4885                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
4886                         break;
4887                 case OP_ICONV_TO_R8_RAW:
4888                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
4889                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
4890                         break;
4891
4892                 case OP_FCONV_TO_R8_X:
4893                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4894                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4895                         break;
4896
4897                 case OP_XCONV_R8_TO_I4:
4898                         x86_cvttsd2si (code, ins->dreg, ins->sreg1);
4899                         switch (ins->backend.source_opcode) {
4900                         case OP_FCONV_TO_I1:
4901                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
4902                                 break;
4903                         case OP_FCONV_TO_U1:
4904                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4905                                 break;
4906                         case OP_FCONV_TO_I2:
4907                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
4908                                 break;
4909                         case OP_FCONV_TO_U2:
4910                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
4911                                 break;
4912                         }                       
4913                         break;
4914
4915                 case OP_EXPAND_I1:
4916                         /*FIXME this causes a partial register stall, maybe it would not be that bad to use shift + mask + or*/
4917                         /*The +4 is to get a mov ?h, ?l over the same reg.*/
4918                         x86_mov_reg_reg (code, ins->dreg + 4, ins->dreg, 1);
4919                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4920                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4921                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4922                         break;
4923                 case OP_EXPAND_I2:
4924                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4925                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4926                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4927                         break;
4928                 case OP_EXPAND_I4:
4929                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4930                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4931                         break;
4932                 case OP_EXPAND_R4:
4933                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4934                         x86_movd_xreg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4935                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4936                         break;
4937                 case OP_EXPAND_R8:
4938                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4939                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4940                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44);
4941                         break;
4942
4943                 case OP_CVTDQ2PD:
4944                         x86_sse_alu_ss_reg_reg (code, X86_SSE_CVTDQ2PD, ins->dreg, ins->sreg1);
4945                         break;
4946                 case OP_CVTDQ2PS:
4947                         x86_sse_alu_ps_reg_reg (code, X86_SSE_CVTDQ2PS, ins->dreg, ins->sreg1);
4948                         break;
4949                 case OP_CVTPD2DQ:
4950                         x86_sse_alu_sd_reg_reg (code, X86_SSE_CVTPD2DQ, ins->dreg, ins->sreg1);
4951                         break;
4952                 case OP_CVTPD2PS:
4953                         x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTPD2PS, ins->dreg, ins->sreg1);
4954                         break;
4955                 case OP_CVTPS2DQ:
4956                         x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTPS2DQ, ins->dreg, ins->sreg1);
4957                         break;
4958                 case OP_CVTPS2PD:
4959                         x86_sse_alu_ps_reg_reg (code, X86_SSE_CVTPS2PD, ins->dreg, ins->sreg1);
4960                         break;
4961                 case OP_CVTTPD2DQ:
4962                         x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTTPD2DQ, ins->dreg, ins->sreg1);
4963                         break;
4964                 case OP_CVTTPS2DQ:
4965                         x86_sse_alu_ss_reg_reg (code, X86_SSE_CVTTPS2DQ, ins->dreg, ins->sreg1);
4966                         break;
4967
4968 #endif
4969                 case OP_LIVERANGE_START: {
4970                         if (cfg->verbose_level > 1)
4971                                 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4972                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4973                         break;
4974                 }
4975                 case OP_LIVERANGE_END: {
4976                         if (cfg->verbose_level > 1)
4977                                 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4978                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4979                         break;
4980                 }
4981                 case OP_NACL_GC_SAFE_POINT: {
4982 #if defined(__native_client_codegen__) && defined(__native_client_gc__)
4983                         if (cfg->compile_aot)
4984                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc);
4985                         else {
4986                                 guint8 *br [1];
4987
4988                                 x86_test_mem_imm8 (code, (gpointer)&__nacl_thread_suspension_needed, 0xFFFFFFFF);
4989                                 br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
4990                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc);
4991                                 x86_patch (br[0], code);
4992                         }
4993 #endif
4994                         break;
4995                 }
4996                 case OP_GC_LIVENESS_DEF:
4997                 case OP_GC_LIVENESS_USE:
4998                 case OP_GC_PARAM_SLOT_LIVENESS_DEF:
4999                         ins->backend.pc_offset = code - cfg->native_code;
5000                         break;
5001                 case OP_GC_SPILL_SLOT_LIVENESS_DEF:
5002                         ins->backend.pc_offset = code - cfg->native_code;
5003                         bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
5004                         break;
5005                 default:
5006                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
5007                         g_assert_not_reached ();
5008                 }
5009
5010                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
5011 #ifndef __native_client_codegen__
5012                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
5013                                            mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
5014                         g_assert_not_reached ();
5015 #endif  /* __native_client_codegen__ */
5016                 }
5017                
5018                 cpos += max_len;
5019         }
5020
5021         cfg->code_len = code - cfg->native_code;
5022 }
5023
5024 #endif /* DISABLE_JIT */
5025
5026 void
5027 mono_arch_register_lowlevel_calls (void)
5028 {
5029 }
5030
5031 void
5032 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
5033 {
5034         MonoJumpInfo *patch_info;
5035         gboolean compile_aot = !run_cctors;
5036
5037         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
5038                 unsigned char *ip = patch_info->ip.i + code;
5039                 const unsigned char *target;
5040
5041                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
5042
5043                 if (compile_aot) {
5044                         switch (patch_info->type) {
5045                         case MONO_PATCH_INFO_BB:
5046                         case MONO_PATCH_INFO_LABEL:
5047                                 break;
5048                         default:
5049                                 /* No need to patch these */
5050                                 continue;
5051                         }
5052                 }
5053
5054                 switch (patch_info->type) {
5055                 case MONO_PATCH_INFO_IP:
5056                         *((gconstpointer *)(ip)) = target;
5057                         break;
5058                 case MONO_PATCH_INFO_CLASS_INIT: {
5059                         guint8 *code = ip;
5060                         /* Might already been changed to a nop */
5061                         x86_call_code (code, 0);
5062                         x86_patch (ip, target);
5063                         break;
5064                 }
5065                 case MONO_PATCH_INFO_ABS:
5066                 case MONO_PATCH_INFO_METHOD:
5067                 case MONO_PATCH_INFO_METHOD_JUMP:
5068                 case MONO_PATCH_INFO_INTERNAL_METHOD:
5069                 case MONO_PATCH_INFO_BB:
5070                 case MONO_PATCH_INFO_LABEL:
5071                 case MONO_PATCH_INFO_RGCTX_FETCH:
5072                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
5073                 case MONO_PATCH_INFO_MONITOR_ENTER:
5074                 case MONO_PATCH_INFO_MONITOR_EXIT:
5075                 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
5076 #if defined(__native_client_codegen__) && defined(__native_client__)
5077                         if (nacl_is_code_address (code)) {
5078                                 /* For tail calls, code is patched after being installed */
5079                                 /* but not through the normal "patch callsite" method.   */
5080                                 unsigned char buf[kNaClAlignment];
5081                                 unsigned char *aligned_code = (uintptr_t)code & ~kNaClAlignmentMask;
5082                                 unsigned char *_target = target;
5083                                 int ret;
5084                                 /* All patch targets modified in x86_patch */
5085                                 /* are IP relative.                        */
5086                                 _target = _target + (uintptr_t)buf - (uintptr_t)aligned_code;
5087                                 memcpy (buf, aligned_code, kNaClAlignment);
5088                                 /* Patch a temp buffer of bundle size, */
5089                                 /* then install to actual location.    */
5090                                 x86_patch (buf + ((uintptr_t)code - (uintptr_t)aligned_code), _target);
5091                                 ret = nacl_dyncode_modify (aligned_code, buf, kNaClAlignment);
5092                                 g_assert (ret == 0);
5093                         }
5094                         else {
5095                                 x86_patch (ip, target);
5096                         }
5097 #else
5098                         x86_patch (ip, target);
5099 #endif
5100                         break;
5101                 case MONO_PATCH_INFO_NONE:
5102                         break;
5103                 case MONO_PATCH_INFO_R4:
5104                 case MONO_PATCH_INFO_R8: {
5105                         guint32 offset = mono_arch_get_patch_offset (ip);
5106                         *((gconstpointer *)(ip + offset)) = target;
5107                         break;
5108                 }
5109                 default: {
5110                         guint32 offset = mono_arch_get_patch_offset (ip);
5111 #if !defined(__native_client__)
5112                         *((gconstpointer *)(ip + offset)) = target;
5113 #else
5114                         *((gconstpointer *)(ip + offset)) = nacl_modify_patch_target (target);
5115 #endif
5116                         break;
5117                 }
5118                 }
5119         }
5120 }
5121
5122 static G_GNUC_UNUSED void
5123 stack_unaligned (MonoMethod *m, gpointer caller)
5124 {
5125         printf ("%s\n", mono_method_full_name (m, TRUE));
5126         g_assert_not_reached ();
5127 }
5128
5129 guint8 *
5130 mono_arch_emit_prolog (MonoCompile *cfg)
5131 {
5132         MonoMethod *method = cfg->method;
5133         MonoBasicBlock *bb;
5134         MonoMethodSignature *sig;
5135         MonoInst *inst;
5136         int alloc_size, pos, max_offset, i, cfa_offset;
5137         guint8 *code;
5138         gboolean need_stack_frame;
5139 #ifdef __native_client_codegen__
5140         guint alignment_check;
5141 #endif
5142
5143         cfg->code_size = MAX (cfg->header->code_size * 4, 10240);
5144
5145         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5146                 cfg->code_size += 512;
5147
5148 #if defined(__default_codegen__)
5149         code = cfg->native_code = g_malloc (cfg->code_size);
5150 #elif defined(__native_client_codegen__)
5151         /* native_code_alloc is not 32-byte aligned, native_code is. */
5152         cfg->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size);
5153         cfg->native_code_alloc = g_malloc (cfg->code_size + kNaClAlignment);
5154
5155         /* Align native_code to next nearest kNaclAlignment byte. */
5156         cfg->native_code = (guint)cfg->native_code_alloc + kNaClAlignment; 
5157         cfg->native_code = (guint)cfg->native_code & ~kNaClAlignmentMask;
5158         
5159         code = cfg->native_code;
5160
5161         alignment_check = (guint)cfg->native_code & kNaClAlignmentMask;
5162         g_assert(alignment_check == 0);
5163 #endif
5164
5165 #if 0
5166         {
5167                 guint8 *br [16];
5168
5169         /* Check that the stack is aligned on osx */
5170         x86_mov_reg_reg (code, X86_EAX, X86_ESP, sizeof (mgreg_t));
5171         x86_alu_reg_imm (code, X86_AND, X86_EAX, 15);
5172         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0xc);
5173         br [0] = code;
5174         x86_branch_disp (code, X86_CC_Z, 0, FALSE);
5175         x86_push_membase (code, X86_ESP, 0);
5176         x86_push_imm (code, cfg->method);
5177         x86_mov_reg_imm (code, X86_EAX, stack_unaligned);
5178         x86_call_reg (code, X86_EAX);
5179         x86_patch (br [0], code);
5180         }
5181 #endif
5182
5183         /* Offset between RSP and the CFA */
5184         cfa_offset = 0;
5185
5186         // CFA = sp + 4
5187         cfa_offset = sizeof (gpointer);
5188         mono_emit_unwind_op_def_cfa (cfg, code, X86_ESP, sizeof (gpointer));
5189         // IP saved at CFA - 4
5190         /* There is no IP reg on x86 */
5191         mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset);
5192         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5193
5194         need_stack_frame = needs_stack_frame (cfg);
5195
5196         if (need_stack_frame) {
5197                 x86_push_reg (code, X86_EBP);
5198                 cfa_offset += sizeof (gpointer);
5199                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5200                 mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset);
5201                 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
5202                 mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP);
5203                 /* These are handled automatically by the stack marking code */
5204                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5205         } else {
5206                 cfg->frame_reg = X86_ESP;
5207         }
5208
5209         alloc_size = cfg->stack_offset;
5210         pos = 0;
5211
5212         if (method->save_lmf) {
5213                 pos += sizeof (MonoLMF);
5214
5215                 /* save the current IP */
5216                 if (cfg->compile_aot) {
5217                         /* This pushes the current ip */
5218                         x86_call_imm (code, 0);
5219                 } else {
5220                         mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5221                         x86_push_imm_template (code);
5222                 }
5223                 cfa_offset += sizeof (gpointer);
5224                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5225
5226                 /* save all caller saved regs */
5227                 x86_push_reg (code, X86_EBP);
5228                 cfa_offset += sizeof (gpointer);
5229                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5230                 x86_push_reg (code, X86_ESI);
5231                 cfa_offset += sizeof (gpointer);
5232                 mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
5233                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5234                 x86_push_reg (code, X86_EDI);
5235                 cfa_offset += sizeof (gpointer);
5236                 mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
5237                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5238                 x86_push_reg (code, X86_EBX);
5239                 cfa_offset += sizeof (gpointer);
5240                 mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
5241                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5242
5243                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
5244                         /*
5245                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
5246                          * through the mono_lmf_addr TLS variable.
5247                          */
5248                         /* %eax = previous_lmf */
5249                         code = mono_x86_emit_tls_get (code, X86_EAX, lmf_tls_offset);
5250                         /* skip esp + method_info + lmf */
5251                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
5252                         cfa_offset += 12;
5253                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5254                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 4, SLOT_NOREF);
5255                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 8, SLOT_NOREF);
5256                         /* push previous_lmf */
5257                         x86_push_reg (code, X86_EAX);
5258                         cfa_offset += 4;
5259                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5260                         /* new lmf = ESP */
5261                         code = mono_x86_emit_tls_set (code, X86_ESP, lmf_tls_offset);
5262                 } else {
5263                         /* get the address of lmf for the current thread */
5264                         /* 
5265                          * This is performance critical so we try to use some tricks to make
5266                          * it fast.
5267                          */                                                                        
5268
5269                         if (lmf_addr_tls_offset != -1) {
5270                                 /* Load lmf quicky using the GS register */
5271                                 code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
5272 #ifdef TARGET_WIN32
5273                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
5274                                 /* FIXME: Add a separate key for LMF to avoid this */
5275                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5276 #endif
5277                         } else {
5278                                 if (cfg->compile_aot)
5279                                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5280                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
5281                         }
5282
5283                         /* Skip esp + method info */
5284                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
5285
5286                         /* push lmf */
5287                         x86_push_reg (code, X86_EAX); 
5288                         /* push *lfm (previous_lmf) */
5289                         x86_push_membase (code, X86_EAX, 0);
5290                         /* *(lmf) = ESP */
5291                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
5292                 }
5293         } else {
5294
5295                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5296                         x86_push_reg (code, X86_EBX);
5297                         pos += 4;
5298                         cfa_offset += sizeof (gpointer);
5299                         mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
5300                         /* These are handled automatically by the stack marking code */
5301                         mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF);
5302                 }
5303
5304                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5305                         x86_push_reg (code, X86_EDI);
5306                         pos += 4;
5307                         cfa_offset += sizeof (gpointer);
5308                         mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
5309                         mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF);
5310                 }
5311
5312                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5313                         x86_push_reg (code, X86_ESI);
5314                         pos += 4;
5315                         cfa_offset += sizeof (gpointer);
5316                         mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
5317                         mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF);
5318                 }
5319         }
5320
5321         alloc_size -= pos;
5322
5323         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
5324         if (mono_do_x86_stack_align && need_stack_frame) {
5325                 int tot = alloc_size + pos + 4; /* ret ip */
5326                 if (need_stack_frame)
5327                         tot += 4; /* ebp */
5328                 tot &= MONO_ARCH_FRAME_ALIGNMENT - 1;
5329                 if (tot) {
5330                         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot;
5331                         for (i = 0; i < MONO_ARCH_FRAME_ALIGNMENT - tot; i += sizeof (mgreg_t))
5332                                 mini_gc_set_slot_type_from_fp (cfg, - (alloc_size + pos - i), SLOT_NOREF);
5333                 }
5334         }
5335
5336         cfg->arch.sp_fp_offset = alloc_size + pos;
5337
5338         if (alloc_size) {
5339                 /* See mono_emit_stack_alloc */
5340 #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
5341                 guint32 remaining_size = alloc_size;
5342                 /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/
5343                 guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 8; /*8 is the max size of x86_alu_reg_imm + x86_test_membase_reg*/
5344                 guint32 offset = code - cfg->native_code;
5345                 if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) {
5346                         while (required_code_size >= (cfg->code_size - offset))
5347                                 cfg->code_size *= 2;
5348                         cfg->native_code = mono_realloc_native_code(cfg);
5349                         code = cfg->native_code + offset;
5350                         cfg->stat_code_reallocs++;
5351                 }
5352                 while (remaining_size >= 0x1000) {
5353                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
5354                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
5355                         remaining_size -= 0x1000;
5356                 }
5357                 if (remaining_size)
5358                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
5359 #else
5360                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
5361 #endif
5362
5363                 g_assert (need_stack_frame);
5364         }
5365
5366         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED ||
5367                         cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
5368                 x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
5369         }
5370
5371 #if DEBUG_STACK_ALIGNMENT
5372         /* check the stack is aligned */
5373         if (need_stack_frame && method->wrapper_type == MONO_WRAPPER_NONE) {
5374                 x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
5375                 x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
5376                 x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
5377                 x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
5378                 x86_breakpoint (code);
5379         }
5380 #endif
5381
5382         /* compute max_offset in order to use short forward jumps */
5383         max_offset = 0;
5384         if (cfg->opt & MONO_OPT_BRANCH) {
5385                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5386                         MonoInst *ins;
5387                         bb->max_offset = max_offset;
5388
5389                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
5390                                 max_offset += 6;
5391                         /* max alignment for loops */
5392                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
5393                                 max_offset += LOOP_ALIGNMENT;
5394 #ifdef __native_client_codegen__
5395                         /* max alignment for native client */
5396                         if (bb->flags & BB_INDIRECT_JUMP_TARGET || bb->flags & BB_EXCEPTION_HANDLER)
5397                                 max_offset += kNaClAlignment;
5398 #endif
5399                         MONO_BB_FOR_EACH_INS (bb, ins) {
5400                                 if (ins->opcode == OP_LABEL)
5401                                         ins->inst_c1 = max_offset;
5402 #ifdef __native_client_codegen__
5403                                 switch (ins->opcode)
5404                                 {
5405                                         case OP_FCALL:
5406                                         case OP_LCALL:
5407                                         case OP_VCALL:
5408                                         case OP_VCALL2:
5409                                         case OP_VOIDCALL:
5410                                         case OP_CALL:
5411                                         case OP_FCALL_REG:
5412                                         case OP_LCALL_REG:
5413                                         case OP_VCALL_REG:
5414                                         case OP_VCALL2_REG:
5415                                         case OP_VOIDCALL_REG:
5416                                         case OP_CALL_REG:
5417                                         case OP_FCALL_MEMBASE:
5418                                         case OP_LCALL_MEMBASE:
5419                                         case OP_VCALL_MEMBASE:
5420                                         case OP_VCALL2_MEMBASE:
5421                                         case OP_VOIDCALL_MEMBASE:
5422                                         case OP_CALL_MEMBASE:
5423                                                 max_offset += kNaClAlignment;
5424                                                 break;
5425                                         default:
5426                                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN] - 1;
5427                                                 break;
5428                                 }
5429 #endif  /* __native_client_codegen__ */
5430                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
5431                         }
5432                 }
5433         }
5434
5435         /* store runtime generic context */
5436         if (cfg->rgctx_var) {
5437                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
5438
5439                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
5440         }
5441
5442         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5443                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5444
5445         /* load arguments allocated to register from the stack */
5446         sig = mono_method_signature (method);
5447         pos = 0;
5448
5449         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5450                 inst = cfg->args [pos];
5451                 if (inst->opcode == OP_REGVAR) {
5452                         g_assert (need_stack_frame);
5453                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
5454                         if (cfg->verbose_level > 2)
5455                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5456                 }
5457                 pos++;
5458         }
5459
5460         cfg->code_len = code - cfg->native_code;
5461
5462         g_assert (cfg->code_len < cfg->code_size);
5463
5464         return code;
5465 }
5466
5467 void
5468 mono_arch_emit_epilog (MonoCompile *cfg)
5469 {
5470         MonoMethod *method = cfg->method;
5471         MonoMethodSignature *sig = mono_method_signature (method);
5472         int quad, pos;
5473         guint32 stack_to_pop;
5474         guint8 *code;
5475         int max_epilog_size = 16;
5476         CallInfo *cinfo;
5477         gboolean need_stack_frame = needs_stack_frame (cfg);
5478
5479         if (cfg->method->save_lmf)
5480                 max_epilog_size += 128;
5481
5482         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5483                 cfg->code_size *= 2;
5484                 cfg->native_code = mono_realloc_native_code(cfg);
5485                 cfg->stat_code_reallocs++;
5486         }
5487
5488         code = cfg->native_code + cfg->code_len;
5489
5490         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5491                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5492
5493         /* the code restoring the registers must be kept in sync with OP_JMP */
5494         pos = 0;
5495         
5496         if (method->save_lmf) {
5497                 gint32 prev_lmf_reg;
5498                 gint32 lmf_offset = -sizeof (MonoLMF);
5499
5500                 /* check if we need to restore protection of the stack after a stack overflow */
5501                 if (mono_get_jit_tls_offset () != -1) {
5502                         guint8 *patch;
5503                         code = mono_x86_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
5504                         /* we load the value in a separate instruction: this mechanism may be
5505                          * used later as a safer way to do thread interruption
5506                          */
5507                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
5508                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
5509                         patch = code;
5510                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
5511                         /* note that the call trampoline will preserve eax/edx */
5512                         x86_call_reg (code, X86_ECX);
5513                         x86_patch (patch, code);
5514                 } else {
5515                         /* FIXME: maybe save the jit tls in the prolog */
5516                 }
5517                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
5518                         /*
5519                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
5520                          * through the mono_lmf_addr TLS variable.
5521                          */
5522                         /* reg = previous_lmf */
5523                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5524
5525                         /* lmf = previous_lmf */
5526                         code = mono_x86_emit_tls_set (code, X86_ECX, lmf_tls_offset);
5527                 } else {
5528                         /* Find a spare register */
5529                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
5530                         case MONO_TYPE_I8:
5531                         case MONO_TYPE_U8:
5532                                 prev_lmf_reg = X86_EDI;
5533                                 cfg->used_int_regs |= (1 << X86_EDI);
5534                                 break;
5535                         default:
5536                                 prev_lmf_reg = X86_EDX;
5537                                 break;
5538                         }
5539
5540                         /* reg = previous_lmf */
5541                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5542
5543                         /* ecx = lmf */
5544                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
5545
5546                         /* *(lmf) = previous_lmf */
5547                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
5548                 }
5549
5550                 /* restore caller saved regs */
5551                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5552                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
5553                 }
5554
5555                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5556                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
5557                 }
5558                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5559                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
5560                 }
5561
5562                 /* EBP is restored by LEAVE */
5563         } else {
5564                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5565                         pos -= 4;
5566                 }
5567                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5568                         pos -= 4;
5569                 }
5570                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5571                         pos -= 4;
5572                 }
5573
5574                 if (pos) {
5575                         g_assert (need_stack_frame);
5576                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
5577                 }
5578
5579                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5580                         x86_pop_reg (code, X86_ESI);
5581                 }
5582                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5583                         x86_pop_reg (code, X86_EDI);
5584                 }
5585                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5586                         x86_pop_reg (code, X86_EBX);
5587                 }
5588         }
5589
5590         /* Load returned vtypes into registers if needed */
5591         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5592         if (cinfo->ret.storage == ArgValuetypeInReg) {
5593                 for (quad = 0; quad < 2; quad ++) {
5594                         switch (cinfo->ret.pair_storage [quad]) {
5595                         case ArgInIReg:
5596                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
5597                                 break;
5598                         case ArgOnFloatFpStack:
5599                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
5600                                 break;
5601                         case ArgOnDoubleFpStack:
5602                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
5603                                 break;
5604                         case ArgNone:
5605                                 break;
5606                         default:
5607                                 g_assert_not_reached ();
5608                         }
5609                 }
5610         }
5611
5612         if (need_stack_frame)
5613                 x86_leave (code);
5614
5615         if (CALLCONV_IS_STDCALL (sig)) {
5616                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
5617
5618                 stack_to_pop = mono_arch_get_argument_info (NULL, sig, sig->param_count, arg_info);
5619         } else if (cinfo->vtype_retaddr)
5620                 stack_to_pop = 4;
5621         else
5622                 stack_to_pop = 0;
5623
5624         if (stack_to_pop) {
5625                 g_assert (need_stack_frame);
5626                 x86_ret_imm (code, stack_to_pop);
5627         } else {
5628                 x86_ret (code);
5629         }
5630
5631         cfg->code_len = code - cfg->native_code;
5632
5633         g_assert (cfg->code_len < cfg->code_size);
5634 }
5635
5636 void
5637 mono_arch_emit_exceptions (MonoCompile *cfg)
5638 {
5639         MonoJumpInfo *patch_info;
5640         int nthrows, i;
5641         guint8 *code;
5642         MonoClass *exc_classes [16];
5643         guint8 *exc_throw_start [16], *exc_throw_end [16];
5644         guint32 code_size;
5645         int exc_count = 0;
5646
5647         /* Compute needed space */
5648         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5649                 if (patch_info->type == MONO_PATCH_INFO_EXC)
5650                         exc_count++;
5651         }
5652
5653         /* 
5654          * make sure we have enough space for exceptions
5655          * 16 is the size of two push_imm instructions and a call
5656          */
5657         if (cfg->compile_aot)
5658                 code_size = exc_count * 32;
5659         else
5660                 code_size = exc_count * 16;
5661
5662         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
5663                 cfg->code_size *= 2;
5664                 cfg->native_code = mono_realloc_native_code(cfg);
5665                 cfg->stat_code_reallocs++;
5666         }
5667
5668         code = cfg->native_code + cfg->code_len;
5669
5670         nthrows = 0;
5671         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5672                 switch (patch_info->type) {
5673                 case MONO_PATCH_INFO_EXC: {
5674                         MonoClass *exc_class;
5675                         guint8 *buf, *buf2;
5676                         guint32 throw_ip;
5677
5678                         x86_patch (patch_info->ip.i + cfg->native_code, code);
5679
5680                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5681                         g_assert (exc_class);
5682                         throw_ip = patch_info->ip.i;
5683
5684                         /* Find a throw sequence for the same exception class */
5685                         for (i = 0; i < nthrows; ++i)
5686                                 if (exc_classes [i] == exc_class)
5687                                         break;
5688                         if (i < nthrows) {
5689                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
5690                                 x86_jump_code (code, exc_throw_start [i]);
5691                                 patch_info->type = MONO_PATCH_INFO_NONE;
5692                         }
5693                         else {
5694                                 guint32 size;
5695
5696                                 /* Compute size of code following the push <OFFSET> */
5697 #if defined(__default_codegen__)
5698                                 size = 5 + 5;
5699 #elif defined(__native_client_codegen__)
5700                                 code = mono_nacl_align (code);
5701                                 size = kNaClAlignment;
5702 #endif
5703                                 /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
5704
5705                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
5706                                         /* Use the shorter form */
5707                                         buf = buf2 = code;
5708                                         x86_push_imm (code, 0);
5709                                 }
5710                                 else {
5711                                         buf = code;
5712                                         x86_push_imm (code, 0xf0f0f0f0);
5713                                         buf2 = code;
5714                                 }
5715
5716                                 if (nthrows < 16) {
5717                                         exc_classes [nthrows] = exc_class;
5718                                         exc_throw_start [nthrows] = code;
5719                                 }
5720
5721                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
5722                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
5723                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5724                                 patch_info->ip.i = code - cfg->native_code;
5725                                 x86_call_code (code, 0);
5726                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
5727                                 while (buf < buf2)
5728                                         x86_nop (buf);
5729
5730                                 if (nthrows < 16) {
5731                                         exc_throw_end [nthrows] = code;
5732                                         nthrows ++;
5733                                 }
5734                         }
5735                         break;
5736                 }
5737                 default:
5738                         /* do nothing */
5739                         break;
5740                 }
5741         }
5742
5743         cfg->code_len = code - cfg->native_code;
5744
5745         g_assert (cfg->code_len < cfg->code_size);
5746 }
5747
5748 void
5749 mono_arch_flush_icache (guint8 *code, gint size)
5750 {
5751         /* not needed */
5752 }
5753
5754 void
5755 mono_arch_flush_register_windows (void)
5756 {
5757 }
5758
5759 gboolean 
5760 mono_arch_is_inst_imm (gint64 imm)
5761 {
5762         return TRUE;
5763 }
5764
5765 void
5766 mono_arch_finish_init (void)
5767 {
5768         if (!getenv ("MONO_NO_TLS")) {
5769 #ifdef TARGET_WIN32
5770                 /* 
5771                  * We need to init this multiple times, since when we are first called, the key might not
5772                  * be initialized yet.
5773                  */
5774                 appdomain_tls_offset = mono_domain_get_tls_key ();
5775                 lmf_tls_offset = mono_get_jit_tls_key ();
5776
5777                 /* Only 64 tls entries can be accessed using inline code */
5778                 if (appdomain_tls_offset >= 64)
5779                         appdomain_tls_offset = -1;
5780                 if (lmf_tls_offset >= 64)
5781                         lmf_tls_offset = -1;
5782 #else
5783 #if MONO_XEN_OPT
5784                 optimize_for_xen = access ("/proc/xen", F_OK) == 0;
5785 #endif
5786                 appdomain_tls_offset = mono_domain_get_tls_offset ();
5787                 lmf_tls_offset = mono_get_lmf_tls_offset ();
5788                 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5789 #endif
5790         }               
5791 }
5792
5793 void
5794 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5795 {
5796 }
5797
5798 #ifdef MONO_ARCH_HAVE_IMT
5799
5800 // Linear handler, the bsearch head compare is shorter
5801 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
5802 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
5803 //        x86_patch(ins,target)
5804 //[1 + 5] x86_jump_mem(inst,mem)
5805
5806 #define CMP_SIZE 6
5807 #if defined(__default_codegen__)
5808 #define BR_SMALL_SIZE 2
5809 #define BR_LARGE_SIZE 5
5810 #elif defined(__native_client_codegen__)
5811 /* I suspect the size calculation below is actually incorrect. */
5812 /* TODO: fix the calculation that uses these sizes.  */
5813 #define BR_SMALL_SIZE 16
5814 #define BR_LARGE_SIZE 12
5815 #endif  /*__native_client_codegen__*/
5816 #define JUMP_IMM_SIZE 6
5817 #define ENABLE_WRONG_METHOD_CHECK 0
5818 #define DEBUG_IMT 0
5819
5820 static int
5821 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
5822 {
5823         int i, distance = 0;
5824         for (i = start; i < target; ++i)
5825                 distance += imt_entries [i]->chunk_size;
5826         return distance;
5827 }
5828
5829 /*
5830  * LOCKING: called with the domain lock held
5831  */
5832 gpointer
5833 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5834         gpointer fail_tramp)
5835 {
5836         int i;
5837         int size = 0;
5838         guint8 *code, *start;
5839
5840         for (i = 0; i < count; ++i) {
5841                 MonoIMTCheckItem *item = imt_entries [i];
5842                 if (item->is_equals) {
5843                         if (item->check_target_idx) {
5844                                 if (!item->compare_done)
5845                                         item->chunk_size += CMP_SIZE;
5846                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
5847                         } else {
5848                                 if (fail_tramp) {
5849                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
5850                                 } else {
5851                                         item->chunk_size += JUMP_IMM_SIZE;
5852 #if ENABLE_WRONG_METHOD_CHECK
5853                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
5854 #endif
5855                                 }
5856                         }
5857                 } else {
5858                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
5859                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5860                 }
5861                 size += item->chunk_size;
5862         }
5863 #if defined(__native_client__) && defined(__native_client_codegen__)
5864         /* In Native Client, we don't re-use thunks, allocate from the */
5865         /* normal code manager paths. */
5866         size = NACL_BUNDLE_ALIGN_UP (size);
5867         code = mono_domain_code_reserve (domain, size);
5868 #else
5869         if (fail_tramp)
5870                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5871         else
5872                 code = mono_domain_code_reserve (domain, size);
5873 #endif
5874         start = code;
5875         for (i = 0; i < count; ++i) {
5876                 MonoIMTCheckItem *item = imt_entries [i];
5877                 item->code_target = code;
5878                 if (item->is_equals) {
5879                         if (item->check_target_idx) {
5880                                 if (!item->compare_done)
5881                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5882                                 item->jmp_code = code;
5883                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
5884                                 if (item->has_target_code)
5885                                         x86_jump_code (code, item->value.target_code);
5886                                 else
5887                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5888                         } else {
5889                                 if (fail_tramp) {
5890                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5891                                         item->jmp_code = code;
5892                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5893                                         if (item->has_target_code)
5894                                                 x86_jump_code (code, item->value.target_code);
5895                                         else
5896                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5897                                         x86_patch (item->jmp_code, code);
5898                                         x86_jump_code (code, fail_tramp);
5899                                         item->jmp_code = NULL;
5900                                 } else {
5901                                         /* enable the commented code to assert on wrong method */
5902 #if ENABLE_WRONG_METHOD_CHECK
5903                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5904                                         item->jmp_code = code;
5905                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5906 #endif
5907                                         if (item->has_target_code)
5908                                                 x86_jump_code (code, item->value.target_code);
5909                                         else
5910                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5911 #if ENABLE_WRONG_METHOD_CHECK
5912                                         x86_patch (item->jmp_code, code);
5913                                         x86_breakpoint (code);
5914                                         item->jmp_code = NULL;
5915 #endif
5916                                 }
5917                         }
5918                 } else {
5919                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5920                         item->jmp_code = code;
5921                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
5922                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
5923                         else
5924                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
5925                 }
5926         }
5927         /* patch the branches to get to the target items */
5928         for (i = 0; i < count; ++i) {
5929                 MonoIMTCheckItem *item = imt_entries [i];
5930                 if (item->jmp_code) {
5931                         if (item->check_target_idx) {
5932                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5933                         }
5934                 }
5935         }
5936
5937         if (!fail_tramp)
5938                 mono_stats.imt_thunks_size += code - start;
5939         g_assert (code - start <= size);
5940
5941 #if DEBUG_IMT
5942         {
5943                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5944                 mono_disassemble_code (NULL, (guint8*)start, code - start, buff);
5945                 g_free (buff);
5946         }
5947 #endif
5948         if (mono_jit_map_is_enabled ()) {
5949                 char *buff;
5950                 if (vtable)
5951                         buff = g_strdup_printf ("imt_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5952                 else
5953                         buff = g_strdup_printf ("imt_thunk_entries_%d", count);
5954                 mono_emit_jit_tramp (start, code - start, buff);
5955                 g_free (buff);
5956         }
5957
5958         nacl_domain_code_validate (domain, &start, size, &code);
5959
5960         return start;
5961 }
5962
5963 MonoMethod*
5964 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5965 {
5966         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5967 }
5968 #endif
5969
5970 MonoVTable*
5971 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5972 {
5973         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5974 }
5975
5976 GSList*
5977 mono_arch_get_cie_program (void)
5978 {
5979         GSList *l = NULL;
5980
5981         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
5982         mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
5983
5984         return l;
5985 }
5986
5987 MonoInst*
5988 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5989 {
5990         MonoInst *ins = NULL;
5991         int opcode = 0;
5992
5993         if (cmethod->klass == mono_defaults.math_class) {
5994                 if (strcmp (cmethod->name, "Sin") == 0) {
5995                         opcode = OP_SIN;
5996                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5997                         opcode = OP_COS;
5998                 } else if (strcmp (cmethod->name, "Tan") == 0) {
5999                         opcode = OP_TAN;
6000                 } else if (strcmp (cmethod->name, "Atan") == 0) {
6001                         opcode = OP_ATAN;
6002                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
6003                         opcode = OP_SQRT;
6004                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
6005                         opcode = OP_ABS;
6006                 } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
6007                         opcode = OP_ROUND;
6008                 }
6009                 
6010                 if (opcode) {
6011                         MONO_INST_NEW (cfg, ins, opcode);
6012                         ins->type = STACK_R8;
6013                         ins->dreg = mono_alloc_freg (cfg);
6014                         ins->sreg1 = args [0]->dreg;
6015                         MONO_ADD_INS (cfg->cbb, ins);
6016                 }
6017
6018                 if (cfg->opt & MONO_OPT_CMOV) {
6019                         int opcode = 0;
6020
6021                         if (strcmp (cmethod->name, "Min") == 0) {
6022                                 if (fsig->params [0]->type == MONO_TYPE_I4)
6023                                         opcode = OP_IMIN;
6024                         } else if (strcmp (cmethod->name, "Max") == 0) {
6025                                 if (fsig->params [0]->type == MONO_TYPE_I4)
6026                                         opcode = OP_IMAX;
6027                         }               
6028
6029                         if (opcode) {
6030                                 MONO_INST_NEW (cfg, ins, opcode);
6031                                 ins->type = STACK_I4;
6032                                 ins->dreg = mono_alloc_ireg (cfg);
6033                                 ins->sreg1 = args [0]->dreg;
6034                                 ins->sreg2 = args [1]->dreg;
6035                                 MONO_ADD_INS (cfg->cbb, ins);
6036                         }
6037                 }
6038
6039 #if 0
6040                 /* OP_FREM is not IEEE compatible */
6041                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
6042                         MONO_INST_NEW (cfg, ins, OP_FREM);
6043                         ins->inst_i0 = args [0];
6044                         ins->inst_i1 = args [1];
6045                 }
6046 #endif
6047         }
6048
6049         return ins;
6050 }
6051
6052 gboolean
6053 mono_arch_print_tree (MonoInst *tree, int arity)
6054 {
6055         return 0;
6056 }
6057
6058 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
6059 {
6060         MonoInst* ins;
6061
6062         return NULL;
6063
6064         if (appdomain_tls_offset == -1)
6065                 return NULL;
6066
6067         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
6068         ins->inst_offset = appdomain_tls_offset;
6069         return ins;
6070 }
6071
6072 guint32
6073 mono_arch_get_patch_offset (guint8 *code)
6074 {
6075         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
6076                 return 2;
6077         else if (code [0] == 0xba)
6078                 return 1;
6079         else if (code [0] == 0x68)
6080                 /* push IMM */
6081                 return 1;
6082         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
6083                 /* push <OFFSET>(<REG>) */
6084                 return 2;
6085         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
6086                 /* call *<OFFSET>(<REG>) */
6087                 return 2;
6088         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
6089                 /* fldl <ADDR> */
6090                 return 2;
6091         else if ((code [0] == 0x58) && (code [1] == 0x05))
6092                 /* pop %eax; add <OFFSET>, %eax */
6093                 return 2;
6094         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
6095                 /* pop <REG>; add <OFFSET>, <REG> */
6096                 return 3;
6097         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
6098                 /* mov <REG>, imm */
6099                 return 1;
6100         else {
6101                 g_assert_not_reached ();
6102                 return -1;
6103         }
6104 }
6105
6106 /**
6107  * mono_breakpoint_clean_code:
6108  *
6109  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
6110  * breakpoints in the original code, they are removed in the copy.
6111  *
6112  * Returns TRUE if no sw breakpoint was present.
6113  */
6114 gboolean
6115 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
6116 {
6117         int i;
6118         gboolean can_write = TRUE;
6119         /*
6120          * If method_start is non-NULL we need to perform bound checks, since we access memory
6121          * at code - offset we could go before the start of the method and end up in a different
6122          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
6123          * instead.
6124          */
6125         if (!method_start || code - offset >= method_start) {
6126                 memcpy (buf, code - offset, size);
6127         } else {
6128                 int diff = code - method_start;
6129                 memset (buf, 0, size);
6130                 memcpy (buf + offset - diff, method_start, diff + size - offset);
6131         }
6132         code -= offset;
6133         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
6134                 int idx = mono_breakpoint_info_index [i];
6135                 guint8 *ptr;
6136                 if (idx < 1)
6137                         continue;
6138                 ptr = mono_breakpoint_info [idx].address;
6139                 if (ptr >= code && ptr < code + size) {
6140                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
6141                         can_write = FALSE;
6142                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
6143                         buf [ptr - code] = saved_byte;
6144                 }
6145         }
6146         return can_write;
6147 }
6148
6149 /*
6150  * mono_x86_get_this_arg_offset:
6151  *
6152  *   Return the offset of the stack location where this is passed during a virtual
6153  * call.
6154  */
6155 guint32
6156 mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
6157 {
6158         return 0;
6159 }
6160
6161 gpointer
6162 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
6163 {
6164         guint32 esp = regs [X86_ESP];
6165         CallInfo *cinfo = NULL;
6166         gpointer res;
6167         int offset;
6168
6169         offset = 0;
6170
6171         /*
6172          * The stack looks like:
6173          * <other args>
6174          * <this=delegate>
6175          * <return addr>
6176          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
6177          */
6178         res = (((MonoObject**)esp) [5 + (offset / 4)]);
6179         if (cinfo)
6180                 g_free (cinfo);
6181         return res;
6182 }
6183
6184 #define MAX_ARCH_DELEGATE_PARAMS 10
6185
6186 static gpointer
6187 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
6188 {
6189         guint8 *code, *start;
6190         int code_reserve = 64;
6191
6192         /*
6193          * The stack contains:
6194          * <delegate>
6195          * <return addr>
6196          */
6197
6198         if (has_target) {
6199                 start = code = mono_global_codeman_reserve (code_reserve);
6200
6201                 /* Replace the this argument with the target */
6202                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
6203                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
6204                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
6205                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
6206
6207                 g_assert ((code - start) < code_reserve);
6208         } else {
6209                 int i = 0;
6210                 /* 8 for mov_reg and jump, plus 8 for each parameter */
6211 #ifdef __native_client_codegen__
6212                 /* TODO: calculate this size correctly */
6213                 code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment;
6214 #else
6215                 code_reserve = 8 + (param_count * 8);
6216 #endif  /* __native_client_codegen__ */
6217                 /*
6218                  * The stack contains:
6219                  * <args in reverse order>
6220                  * <delegate>
6221                  * <return addr>
6222                  *
6223                  * and we need:
6224                  * <args in reverse order>
6225                  * <return addr>
6226                  * 
6227                  * without unbalancing the stack.
6228                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
6229                  * and leaving original spot of first arg as placeholder in stack so
6230                  * when callee pops stack everything works.
6231                  */
6232
6233                 start = code = mono_global_codeman_reserve (code_reserve);
6234
6235                 /* store delegate for access to method_ptr */
6236                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
6237
6238                 /* move args up */
6239                 for (i = 0; i < param_count; ++i) {
6240                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
6241                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
6242                 }
6243
6244                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
6245
6246                 g_assert ((code - start) < code_reserve);
6247         }
6248
6249         nacl_global_codeman_validate(&start, code_reserve, &code);
6250         mono_debug_add_delegate_trampoline (start, code - start);
6251
6252         if (code_len)
6253                 *code_len = code - start;
6254
6255         if (mono_jit_map_is_enabled ()) {
6256                 char *buff;
6257                 if (has_target)
6258                         buff = (char*)"delegate_invoke_has_target";
6259                 else
6260                         buff = g_strdup_printf ("delegate_invoke_no_target_%d", param_count);
6261                 mono_emit_jit_tramp (start, code - start, buff);
6262                 if (!has_target)
6263                         g_free (buff);
6264         }
6265
6266         return start;
6267 }
6268
6269 GSList*
6270 mono_arch_get_delegate_invoke_impls (void)
6271 {
6272         GSList *res = NULL;
6273         guint8 *code;
6274         guint32 code_len;
6275         int i;
6276
6277         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
6278         res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
6279
6280         for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
6281                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
6282                 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
6283         }
6284
6285         return res;
6286 }
6287
6288 gpointer
6289 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
6290 {
6291         guint8 *code, *start;
6292
6293         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
6294                 return NULL;
6295
6296         /* FIXME: Support more cases */
6297         if (MONO_TYPE_ISSTRUCT (sig->ret))
6298                 return NULL;
6299
6300         /*
6301          * The stack contains:
6302          * <delegate>
6303          * <return addr>
6304          */
6305
6306         if (has_target) {
6307                 static guint8* cached = NULL;
6308                 if (cached)
6309                         return cached;
6310
6311                 if (mono_aot_only)
6312                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
6313                 else
6314                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
6315
6316                 mono_memory_barrier ();
6317
6318                 cached = start;
6319         } else {
6320                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
6321                 int i = 0;
6322
6323                 for (i = 0; i < sig->param_count; ++i)
6324                         if (!mono_is_regsize_var (sig->params [i]))
6325                                 return NULL;
6326
6327                 code = cache [sig->param_count];
6328                 if (code)
6329                         return code;
6330
6331                 if (mono_aot_only) {
6332                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
6333                         start = mono_aot_get_trampoline (name);
6334                         g_free (name);
6335                 } else {
6336                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
6337                 }
6338
6339                 mono_memory_barrier ();
6340
6341                 cache [sig->param_count] = start;
6342         }
6343
6344         return start;
6345 }
6346
6347 mgreg_t
6348 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6349 {
6350         switch (reg) {
6351         case X86_EAX: return ctx->eax;
6352         case X86_EBX: return ctx->ebx;
6353         case X86_ECX: return ctx->ecx;
6354         case X86_EDX: return ctx->edx;
6355         case X86_ESP: return ctx->esp;
6356         case X86_EBP: return ctx->ebp;
6357         case X86_ESI: return ctx->esi;
6358         case X86_EDI: return ctx->edi;
6359         default:
6360                 g_assert_not_reached ();
6361                 return 0;
6362         }
6363 }
6364
6365 void
6366 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
6367 {
6368         switch (reg) {
6369         case X86_EAX:
6370                 ctx->eax = val;
6371                 break;
6372         case X86_EBX:
6373                 ctx->ebx = val;
6374                 break;
6375         case X86_ECX:
6376                 ctx->ecx = val;
6377                 break;
6378         case X86_EDX:
6379                 ctx->edx = val;
6380                 break;
6381         case X86_ESP:
6382                 ctx->esp = val;
6383                 break;
6384         case X86_EBP:
6385                 ctx->ebp = val;
6386                 break;
6387         case X86_ESI:
6388                 ctx->esi = val;
6389                 break;
6390         case X86_EDI:
6391                 ctx->edi = val;
6392                 break;
6393         default:
6394                 g_assert_not_reached ();
6395         }
6396 }
6397
6398 #ifdef MONO_ARCH_SIMD_INTRINSICS
6399
6400 static MonoInst*
6401 get_float_to_x_spill_area (MonoCompile *cfg)
6402 {
6403         if (!cfg->fconv_to_r8_x_var) {
6404                 cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
6405                 cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
6406         }       
6407         return cfg->fconv_to_r8_x_var;
6408 }
6409
6410 /*
6411  * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. 
6412  */
6413 void
6414 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
6415 {
6416         MonoInst *fconv;
6417         int dreg, src_opcode;
6418
6419         if (!(cfg->opt & MONO_OPT_SSE2) || !(cfg->opt & MONO_OPT_SIMD) || COMPILE_LLVM (cfg))
6420                 return;
6421
6422         switch (src_opcode = ins->opcode) {
6423         case OP_FCONV_TO_I1:
6424         case OP_FCONV_TO_U1:
6425         case OP_FCONV_TO_I2:
6426         case OP_FCONV_TO_U2:
6427         case OP_FCONV_TO_I4:
6428         case OP_FCONV_TO_I:
6429                 break;
6430         default:
6431                 return;
6432         }
6433
6434         /* dreg is the IREG and sreg1 is the FREG */
6435         MONO_INST_NEW (cfg, fconv, OP_FCONV_TO_R8_X);
6436         fconv->klass = NULL; /*FIXME, what can I use here as the Mono.Simd lib might not be loaded yet*/
6437         fconv->sreg1 = ins->sreg1;
6438         fconv->dreg = mono_alloc_ireg (cfg);
6439         fconv->type = STACK_VTYPE;
6440         fconv->backend.spill_var = get_float_to_x_spill_area (cfg);
6441
6442         mono_bblock_insert_before_ins (cfg->cbb, ins, fconv);
6443
6444         dreg = ins->dreg;
6445         NULLIFY_INS (ins);
6446         ins->opcode = OP_XCONV_R8_TO_I4;
6447
6448         ins->klass = mono_defaults.int32_class;
6449         ins->sreg1 = fconv->dreg;
6450         ins->dreg = dreg;
6451         ins->type = STACK_I4;
6452         ins->backend.source_opcode = src_opcode;
6453 }
6454
6455 #endif /* #ifdef MONO_ARCH_SIMD_INTRINSICS */
6456
6457 void
6458 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
6459 {
6460         MonoInst *ins;
6461         int vreg;
6462
6463         if (long_ins->opcode == OP_LNEG) {
6464                 ins = long_ins;
6465                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 1, ins->sreg1 + 1);
6466                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
6467                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 2, ins->dreg + 2);
6468                 NULLIFY_INS (ins);
6469                 return;
6470         }
6471
6472 #ifdef MONO_ARCH_SIMD_INTRINSICS
6473
6474         if (!(cfg->opt & MONO_OPT_SIMD))
6475                 return;
6476         
6477         /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ 
6478         switch (long_ins->opcode) {
6479         case OP_EXTRACT_I8:
6480                 vreg = long_ins->sreg1;
6481         
6482                 if (long_ins->inst_c0) {
6483                         MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6484                         ins->klass = long_ins->klass;
6485                         ins->sreg1 = long_ins->sreg1;
6486                         ins->inst_c0 = 2;
6487                         ins->type = STACK_VTYPE;
6488                         ins->dreg = vreg = alloc_ireg (cfg);
6489                         MONO_ADD_INS (cfg->cbb, ins);
6490                 }
6491         
6492                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6493                 ins->klass = mono_defaults.int32_class;
6494                 ins->sreg1 = vreg;
6495                 ins->type = STACK_I4;
6496                 ins->dreg = long_ins->dreg + 1;
6497                 MONO_ADD_INS (cfg->cbb, ins);
6498         
6499                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6500                 ins->klass = long_ins->klass;
6501                 ins->sreg1 = long_ins->sreg1;
6502                 ins->inst_c0 = long_ins->inst_c0 ? 3 : 1;
6503                 ins->type = STACK_VTYPE;
6504                 ins->dreg = vreg = alloc_ireg (cfg);
6505                 MONO_ADD_INS (cfg->cbb, ins);
6506         
6507                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6508                 ins->klass = mono_defaults.int32_class;
6509                 ins->sreg1 = vreg;
6510                 ins->type = STACK_I4;
6511                 ins->dreg = long_ins->dreg + 2;
6512                 MONO_ADD_INS (cfg->cbb, ins);
6513         
6514                 long_ins->opcode = OP_NOP;
6515                 break;
6516         case OP_INSERTX_I8_SLOW:
6517                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6518                 ins->dreg = long_ins->dreg;
6519                 ins->sreg1 = long_ins->dreg;
6520                 ins->sreg2 = long_ins->sreg2 + 1;
6521                 ins->inst_c0 = long_ins->inst_c0 * 2;
6522                 MONO_ADD_INS (cfg->cbb, ins);
6523
6524                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6525                 ins->dreg = long_ins->dreg;
6526                 ins->sreg1 = long_ins->dreg;
6527                 ins->sreg2 = long_ins->sreg2 + 2;
6528                 ins->inst_c0 = long_ins->inst_c0 * 2 + 1;
6529                 MONO_ADD_INS (cfg->cbb, ins);
6530
6531                 long_ins->opcode = OP_NOP;
6532                 break;
6533         case OP_EXPAND_I8:
6534                 MONO_INST_NEW (cfg, ins, OP_ICONV_TO_X);
6535                 ins->dreg = long_ins->dreg;
6536                 ins->sreg1 = long_ins->sreg1 + 1;
6537                 ins->klass = long_ins->klass;
6538                 ins->type = STACK_VTYPE;
6539                 MONO_ADD_INS (cfg->cbb, ins);
6540
6541                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6542                 ins->dreg = long_ins->dreg;
6543                 ins->sreg1 = long_ins->dreg;
6544                 ins->sreg2 = long_ins->sreg1 + 2;
6545                 ins->inst_c0 = 1;
6546                 ins->klass = long_ins->klass;
6547                 ins->type = STACK_VTYPE;
6548                 MONO_ADD_INS (cfg->cbb, ins);
6549
6550                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6551                 ins->dreg = long_ins->dreg;
6552                 ins->sreg1 = long_ins->dreg;;
6553                 ins->inst_c0 = 0x44; /*Magic number for swizzling (X,Y,X,Y)*/
6554                 ins->klass = long_ins->klass;
6555                 ins->type = STACK_VTYPE;
6556                 MONO_ADD_INS (cfg->cbb, ins);
6557
6558                 long_ins->opcode = OP_NOP;
6559                 break;
6560         }
6561 #endif /* MONO_ARCH_SIMD_INTRINSICS */
6562 }
6563
6564 /*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
6565 gpointer
6566 mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
6567 {
6568         int offset;
6569         gpointer *sp, old_value;
6570         char *bp;
6571         const unsigned char *handler;
6572
6573         /*Decode the first instruction to figure out where did we store the spvar*/
6574         /*Our jit MUST generate the following:
6575          mov %esp, -?(%ebp)
6576          Which is encoded as: 0x89 mod_rm.
6577          mod_rm (esp, ebp, imm) which can be: (imm will never be zero)
6578                 mod (reg + imm8):  01 reg(esp): 100 rm(ebp): 101 -> 01100101 (0x65)
6579                 mod (reg + imm32): 10 reg(esp): 100 rm(ebp): 101 -> 10100101 (0xA5)
6580         */
6581         handler = clause->handler_start;
6582
6583         if (*handler != 0x89)
6584                 return NULL;
6585
6586         ++handler;
6587
6588         if (*handler == 0x65)
6589                 offset = *(signed char*)(handler + 1);
6590         else if (*handler == 0xA5)
6591                 offset = *(int*)(handler + 1);
6592         else
6593                 return NULL;
6594
6595         /*Load the spvar*/
6596         bp = MONO_CONTEXT_GET_BP (ctx);
6597         sp = *(gpointer*)(bp + offset);
6598
6599         old_value = *sp;
6600         if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
6601                 return old_value;
6602
6603         *sp = new_value;
6604
6605         return old_value;
6606 }
6607
6608 /*
6609  * mono_aot_emit_load_got_addr:
6610  *
6611  *   Emit code to load the got address.
6612  * On x86, the result is placed into EBX.
6613  */
6614 guint8*
6615 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6616 {
6617         x86_call_imm (code, 0);
6618         /* 
6619          * The patch needs to point to the pop, since the GOT offset needs 
6620          * to be added to that address.
6621          */
6622         if (cfg)
6623                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6624         else
6625                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6626         x86_pop_reg (code, MONO_ARCH_GOT_REG);
6627         x86_alu_reg_imm (code, X86_ADD, MONO_ARCH_GOT_REG, 0xf0f0f0f0);
6628
6629         return code;
6630 }
6631
6632 /*
6633  * mono_ppc_emit_load_aotconst:
6634  *
6635  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6636  * TARGET from the mscorlib GOT in full-aot code.
6637  * On x86, the GOT address is assumed to be in EBX, and the result is placed into 
6638  * EAX.
6639  */
6640 guint8*
6641 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6642 {
6643         /* Load the mscorlib got address */
6644         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
6645         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6646         /* arch_emit_got_access () patches this */
6647         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0xf0f0f0f0, 4);
6648
6649         return code;
6650 }
6651
6652 /* Can't put this into mini-x86.h */
6653 gpointer
6654 mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot);
6655
6656 GSList *
6657 mono_arch_get_trampolines (gboolean aot)
6658 {
6659         MonoTrampInfo *info;
6660         GSList *tramps = NULL;
6661
6662         mono_x86_get_signal_exception_trampoline (&info, aot);
6663
6664         tramps = g_slist_append (tramps, info);
6665
6666         return tramps;
6667 }
6668
6669
6670 #if __APPLE__
6671 #define DBG_SIGNAL SIGBUS
6672 #else
6673 #define DBG_SIGNAL SIGSEGV
6674 #endif
6675
6676 /* Soft Debug support */
6677 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6678
6679 /*
6680  * mono_arch_set_breakpoint:
6681  *
6682  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
6683  * The location should contain code emitted by OP_SEQ_POINT.
6684  */
6685 void
6686 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6687 {
6688         guint8 *code = ip;
6689
6690         /* 
6691          * In production, we will use int3 (has to fix the size in the md 
6692          * file). But that could confuse gdb, so during development, we emit a SIGSEGV
6693          * instead.
6694          */
6695         g_assert (code [0] == 0x90);
6696         x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
6697 }
6698
6699 /*
6700  * mono_arch_clear_breakpoint:
6701  *
6702  *   Clear the breakpoint at IP.
6703  */
6704 void
6705 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6706 {
6707         guint8 *code = ip;
6708         int i;
6709
6710         for (i = 0; i < 6; ++i)
6711                 x86_nop (code);
6712 }
6713         
6714 /*
6715  * mono_arch_start_single_stepping:
6716  *
6717  *   Start single stepping.
6718  */
6719 void
6720 mono_arch_start_single_stepping (void)
6721 {
6722         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6723 }
6724         
6725 /*
6726  * mono_arch_stop_single_stepping:
6727  *
6728  *   Stop single stepping.
6729  */
6730 void
6731 mono_arch_stop_single_stepping (void)
6732 {
6733         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6734 }
6735
6736 /*
6737  * mono_arch_is_single_step_event:
6738  *
6739  *   Return whenever the machine state in SIGCTX corresponds to a single
6740  * step event.
6741  */
6742 gboolean
6743 mono_arch_is_single_step_event (void *info, void *sigctx)
6744 {
6745 #ifdef TARGET_WIN32
6746         EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* Sometimes the address is off by 4 */
6747
6748         if ((einfo->ExceptionInformation[1] >= ss_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)ss_trigger_page + 128))
6749                 return TRUE;
6750         else
6751                 return FALSE;
6752 #else
6753         siginfo_t* sinfo = (siginfo_t*) info;
6754         /* Sometimes the address is off by 4 */
6755         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
6756                 return TRUE;
6757         else
6758                 return FALSE;
6759 #endif
6760 }
6761
6762 gboolean
6763 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6764 {
6765 #ifdef TARGET_WIN32
6766         EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* Sometimes the address is off by 4 */
6767         if ((einfo->ExceptionInformation[1] >= bp_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)bp_trigger_page + 128))
6768                 return TRUE;
6769         else
6770                 return FALSE;
6771 #else
6772         siginfo_t* sinfo = (siginfo_t*)info;
6773         /* Sometimes the address is off by 4 */
6774         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
6775                 return TRUE;
6776         else
6777                 return FALSE;
6778 #endif
6779 }
6780
6781 #define BREAKPOINT_SIZE 6
6782
6783 /*
6784  * mono_arch_skip_breakpoint:
6785  *
6786  *   See mini-amd64.c for docs.
6787  */
6788 void
6789 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6790 {
6791         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
6792 }
6793
6794 /*
6795  * mono_arch_skip_single_step:
6796  *
6797  *   See mini-amd64.c for docs.
6798  */
6799 void
6800 mono_arch_skip_single_step (MonoContext *ctx)
6801 {
6802         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
6803 }
6804
6805 /*
6806  * mono_arch_get_seq_point_info:
6807  *
6808  *   See mini-amd64.c for docs.
6809  */
6810 gpointer
6811 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6812 {
6813         NOT_IMPLEMENTED;
6814         return NULL;
6815 }
6816
6817 #endif
6818
6819 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
6820
6821 #include "../../../mono-extensions/mono/mini/mini-x86-gsharedvt.c"
6822
6823 #endif /* !MONOTOUCH */