Rework the gsharedvt code to add support for vtypes with arbitrary size.
[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                 default:
1475                         cfg->exception_message = g_strdup ("ainfo->storage");
1476                         cfg->disable_llvm = TRUE;
1477                         break;
1478                 }
1479         }
1480
1481         return linfo;
1482 }
1483 #endif
1484
1485 static void
1486 emit_gc_param_slot_def (MonoCompile *cfg, int sp_offset, MonoType *t)
1487 {
1488         if (cfg->compute_gc_maps) {
1489                 MonoInst *def;
1490
1491                 /* On x86, the offsets are from the sp value before the start of the call sequence */
1492                 if (t == NULL)
1493                         t = &mono_defaults.int_class->byval_arg;
1494                 EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF (cfg, def, sp_offset, t);
1495         }
1496 }
1497
1498 void
1499 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1500 {
1501         MonoInst *arg, *in;
1502         MonoMethodSignature *sig;
1503         int i, j, n;
1504         CallInfo *cinfo;
1505         int sentinelpos = 0, sp_offset = 0;
1506
1507         sig = call->signature;
1508         n = sig->param_count + sig->hasthis;
1509
1510         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
1511
1512         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1513                 sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0);
1514
1515         if (cinfo->need_stack_align) {
1516                 MONO_INST_NEW (cfg, arg, OP_SUB_IMM);
1517                 arg->dreg = X86_ESP;
1518                 arg->sreg1 = X86_ESP;
1519                 arg->inst_imm = cinfo->stack_align_amount;
1520                 MONO_ADD_INS (cfg->cbb, arg);
1521                 for (i = 0; i < cinfo->stack_align_amount; i += sizeof (mgreg_t)) {
1522                         sp_offset += 4;
1523
1524                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1525                 }
1526         }
1527
1528         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1529                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1530                         /*
1531                          * Tell the JIT to use a more efficient calling convention: call using
1532                          * OP_CALL, compute the result location after the call, and save the 
1533                          * result there.
1534                          */
1535                         call->vret_in_reg = TRUE;
1536                         if (call->vret_var)
1537                                 NULLIFY_INS (call->vret_var);
1538                 }
1539         }
1540
1541         // FIXME: Emit EMIT_NEW_GC_PARAM_SLOT_LIVENESS_DEF everywhere 
1542
1543         /* Handle the case where there are no implicit arguments */
1544         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) {
1545                 emit_sig_cookie (cfg, call, cinfo);
1546                 sp_offset += 4;
1547                 emit_gc_param_slot_def (cfg, sp_offset, NULL);
1548         }
1549
1550         /* Arguments are pushed in the reverse order */
1551         for (i = n - 1; i >= 0; i --) {
1552                 ArgInfo *ainfo = cinfo->args + i;
1553                 MonoType *orig_type, *t;
1554                 int argsize;
1555
1556                 if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 1 && i == 0) {
1557                         /* Push the vret arg before the first argument */
1558                         MonoInst *vtarg;
1559                         MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1560                         vtarg->type = STACK_MP;
1561                         vtarg->sreg1 = call->vret_var->dreg;
1562                         MONO_ADD_INS (cfg->cbb, vtarg);
1563                         sp_offset += 4;
1564                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1565                 }
1566
1567                 if (i >= sig->hasthis)
1568                         t = sig->params [i - sig->hasthis];
1569                 else
1570                         t = &mono_defaults.int_class->byval_arg;
1571                 orig_type = t;
1572                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1573
1574                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
1575
1576                 in = call->args [i];
1577                 arg->cil_code = in->cil_code;
1578                 arg->sreg1 = in->dreg;
1579                 arg->type = in->type;
1580
1581                 g_assert (in->dreg != -1);
1582
1583                 if (ainfo->storage == ArgGSharedVt) {
1584                         arg->opcode = OP_OUTARG_VT;
1585                         arg->sreg1 = in->dreg;
1586                         arg->klass = in->klass;
1587                         sp_offset += 4;
1588                         MONO_ADD_INS (cfg->cbb, arg);
1589                 } else if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
1590                         guint32 align;
1591                         guint32 size;
1592
1593                         g_assert (in->klass);
1594
1595                         if (t->type == MONO_TYPE_TYPEDBYREF) {
1596                                 size = sizeof (MonoTypedRef);
1597                                 align = sizeof (gpointer);
1598                         }
1599                         else {
1600                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, &in->klass->byval_arg, &align, sig->pinvoke);
1601                         }
1602
1603                         if (size > 0) {
1604                                 arg->opcode = OP_OUTARG_VT;
1605                                 arg->sreg1 = in->dreg;
1606                                 arg->klass = in->klass;
1607                                 arg->backend.size = size;
1608
1609                                 MONO_ADD_INS (cfg->cbb, arg);
1610                                 sp_offset += size;
1611                                 emit_gc_param_slot_def (cfg, sp_offset, orig_type);
1612                         }
1613                 } else {
1614                         argsize = 4;
1615
1616                         switch (ainfo->storage) {
1617                         case ArgOnStack:
1618                                 arg->opcode = OP_X86_PUSH;
1619                                 if (!t->byref) {
1620                                         if (t->type == MONO_TYPE_R4) {
1621                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
1622                                                 arg->opcode = OP_STORER4_MEMBASE_REG;
1623                                                 arg->inst_destbasereg = X86_ESP;
1624                                                 arg->inst_offset = 0;
1625                                                 argsize = 4;
1626                                         } else if (t->type == MONO_TYPE_R8) {
1627                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
1628                                                 arg->opcode = OP_STORER8_MEMBASE_REG;
1629                                                 arg->inst_destbasereg = X86_ESP;
1630                                                 arg->inst_offset = 0;
1631                                                 argsize = 8;
1632                                         } else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8) {
1633                                                 arg->sreg1 ++;
1634                                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 2);
1635                                                 sp_offset += 4;
1636                                         }
1637                                 }
1638                                 break;
1639                         default:
1640                                 g_assert_not_reached ();
1641                         }
1642                         
1643                         MONO_ADD_INS (cfg->cbb, arg);
1644
1645                         sp_offset += argsize;
1646
1647                         if (cfg->compute_gc_maps) {
1648                                 if (argsize == 4) {
1649                                         /* FIXME: The == STACK_OBJ check might be fragile ? */
1650                                         if (sig->hasthis && i == 0 && call->args [i]->type == STACK_OBJ) {
1651                                                 /* this */
1652                                                 if (call->need_unbox_trampoline)
1653                                                         /* The unbox trampoline transforms this into a managed pointer */
1654                                                         emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.int_class->this_arg);
1655                                                 else
1656                                                         emit_gc_param_slot_def (cfg, sp_offset, &mono_defaults.object_class->byval_arg);
1657                                         } else {
1658                                                 emit_gc_param_slot_def (cfg, sp_offset, orig_type);
1659                                         }
1660                                 } else {
1661                                         /* i8/r8 */
1662                                         for (j = 0; j < argsize; j += 4)
1663                                                 emit_gc_param_slot_def (cfg, sp_offset - j, NULL);
1664                                 }
1665                         }
1666                 }
1667
1668                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) {
1669                         /* Emit the signature cookie just before the implicit arguments */
1670                         emit_sig_cookie (cfg, call, cinfo);
1671                         sp_offset += 4;
1672                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1673                 }
1674         }
1675
1676         if (sig->ret && (MONO_TYPE_ISSTRUCT (sig->ret) || cinfo->vtype_retaddr)) {
1677                 MonoInst *vtarg;
1678
1679                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1680                         /* Already done */
1681                 }
1682                 else if (cinfo->ret.storage == ArgInIReg) {
1683                         NOT_IMPLEMENTED;
1684                         /* The return address is passed in a register */
1685                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1686                         vtarg->sreg1 = call->inst.dreg;
1687                         vtarg->dreg = mono_alloc_ireg (cfg);
1688                         MONO_ADD_INS (cfg->cbb, vtarg);
1689                                 
1690                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
1691                 } else if (cinfo->vtype_retaddr && cinfo->vret_arg_index == 0) {
1692                         MonoInst *vtarg;
1693                         MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1694                         vtarg->type = STACK_MP;
1695                         vtarg->sreg1 = call->vret_var->dreg;
1696                         MONO_ADD_INS (cfg->cbb, vtarg);
1697                         sp_offset += 4;
1698                         emit_gc_param_slot_def (cfg, sp_offset, NULL);
1699                 }
1700
1701                 /* if the function returns a struct on stack, the called method already does a ret $0x4 */
1702                 if (cinfo->ret.storage != ArgValuetypeInReg)
1703                         cinfo->stack_usage -= 4;
1704         }
1705
1706         call->stack_usage = cinfo->stack_usage;
1707         call->stack_align_amount = cinfo->stack_align_amount;
1708         cfg->arch.param_area_size = MAX (cfg->arch.param_area_size, sp_offset);
1709 }
1710
1711 void
1712 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1713 {
1714         MonoInst *arg;
1715         int size = ins->backend.size;
1716
1717         if (cfg->gsharedvt && mini_is_gsharedvt_klass (cfg, ins->klass)) {
1718                 /* Pass by addr */
1719                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
1720                 arg->sreg1 = src->dreg;
1721                 MONO_ADD_INS (cfg->cbb, arg);
1722         } else if (size <= 4) {
1723                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_MEMBASE);
1724                 arg->sreg1 = src->dreg;
1725
1726                 MONO_ADD_INS (cfg->cbb, arg);
1727         } else if (size <= 20) {        
1728                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, ALIGN_TO (size, 4));
1729                 mini_emit_memcpy (cfg, X86_ESP, 0, src->dreg, 0, size, 4);
1730         } else {
1731                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_OBJ);
1732                 arg->inst_basereg = src->dreg;
1733                 arg->inst_offset = 0;
1734                 arg->inst_imm = size;
1735                                         
1736                 MONO_ADD_INS (cfg->cbb, arg);
1737         }
1738 }
1739
1740 void
1741 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1742 {
1743         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1744
1745         if (!ret->byref) {
1746                 if (ret->type == MONO_TYPE_R4) {
1747                         if (COMPILE_LLVM (cfg))
1748                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1749                         /* Nothing to do */
1750                         return;
1751                 } else if (ret->type == MONO_TYPE_R8) {
1752                         if (COMPILE_LLVM (cfg))
1753                                 MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1754                         /* Nothing to do */
1755                         return;
1756                 } else if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1757                         if (COMPILE_LLVM (cfg))
1758                                 MONO_EMIT_NEW_UNALU (cfg, OP_LMOVE, cfg->ret->dreg, val->dreg);
1759                         else {
1760                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EAX, val->dreg + 1);
1761                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EDX, val->dreg + 2);
1762                         }
1763                         return;
1764                 }
1765         }
1766                         
1767         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1768 }
1769
1770 /*
1771  * Allow tracing to work with this interface (with an optional argument)
1772  */
1773 void*
1774 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1775 {
1776         guchar *code = p;
1777
1778         g_assert (MONO_ARCH_FRAME_ALIGNMENT >= 8);
1779         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 8);
1780
1781         /* if some args are passed in registers, we need to save them here */
1782         x86_push_reg (code, X86_EBP);
1783
1784         if (cfg->compile_aot) {
1785                 x86_push_imm (code, cfg->method);
1786                 x86_mov_reg_imm (code, X86_EAX, func);
1787                 x86_call_reg (code, X86_EAX);
1788         } else {
1789                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, cfg->method);
1790                 x86_push_imm (code, cfg->method);
1791                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1792                 x86_call_code (code, 0);
1793         }
1794         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT);
1795
1796         return code;
1797 }
1798
1799 enum {
1800         SAVE_NONE,
1801         SAVE_STRUCT,
1802         SAVE_EAX,
1803         SAVE_EAX_EDX,
1804         SAVE_FP
1805 };
1806
1807 void*
1808 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1809 {
1810         guchar *code = p;
1811         int arg_size = 0, stack_usage = 0, save_mode = SAVE_NONE;
1812         MonoMethod *method = cfg->method;
1813         MonoType *ret_type = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1814
1815         switch (ret_type->type) {
1816         case MONO_TYPE_VOID:
1817                 /* special case string .ctor icall */
1818                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class) {
1819                         save_mode = SAVE_EAX;
1820                         stack_usage = enable_arguments ? 8 : 4;
1821                 } else
1822                         save_mode = SAVE_NONE;
1823                 break;
1824         case MONO_TYPE_I8:
1825         case MONO_TYPE_U8:
1826                 save_mode = SAVE_EAX_EDX;
1827                 stack_usage = enable_arguments ? 16 : 8;
1828                 break;
1829         case MONO_TYPE_R4:
1830         case MONO_TYPE_R8:
1831                 save_mode = SAVE_FP;
1832                 stack_usage = enable_arguments ? 16 : 8;
1833                 break;
1834         case MONO_TYPE_GENERICINST:
1835                 if (!mono_type_generic_inst_is_valuetype (ret_type)) {
1836                         save_mode = SAVE_EAX;
1837                         stack_usage = enable_arguments ? 8 : 4;
1838                         break;
1839                 }
1840                 /* Fall through */
1841         case MONO_TYPE_VALUETYPE:
1842                 // FIXME: Handle SMALL_STRUCT_IN_REG here for proper alignment on darwin-x86
1843                 save_mode = SAVE_STRUCT;
1844                 stack_usage = enable_arguments ? 4 : 0;
1845                 break;
1846         default:
1847                 save_mode = SAVE_EAX;
1848                 stack_usage = enable_arguments ? 8 : 4;
1849                 break;
1850         }
1851
1852         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - stack_usage - 4);
1853
1854         switch (save_mode) {
1855         case SAVE_EAX_EDX:
1856                 x86_push_reg (code, X86_EDX);
1857                 x86_push_reg (code, X86_EAX);
1858                 if (enable_arguments) {
1859                         x86_push_reg (code, X86_EDX);
1860                         x86_push_reg (code, X86_EAX);
1861                         arg_size = 8;
1862                 }
1863                 break;
1864         case SAVE_EAX:
1865                 x86_push_reg (code, X86_EAX);
1866                 if (enable_arguments) {
1867                         x86_push_reg (code, X86_EAX);
1868                         arg_size = 4;
1869                 }
1870                 break;
1871         case SAVE_FP:
1872                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1873                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1874                 if (enable_arguments) {
1875                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1876                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1877                         arg_size = 8;
1878                 }
1879                 break;
1880         case SAVE_STRUCT:
1881                 if (enable_arguments) {
1882                         x86_push_membase (code, X86_EBP, 8);
1883                         arg_size = 4;
1884                 }
1885                 break;
1886         case SAVE_NONE:
1887         default:
1888                 break;
1889         }
1890
1891         if (cfg->compile_aot) {
1892                 x86_push_imm (code, method);
1893                 x86_mov_reg_imm (code, X86_EAX, func);
1894                 x86_call_reg (code, X86_EAX);
1895         } else {
1896                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method);
1897                 x86_push_imm (code, method);
1898                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1899                 x86_call_code (code, 0);
1900         }
1901
1902         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
1903
1904         switch (save_mode) {
1905         case SAVE_EAX_EDX:
1906                 x86_pop_reg (code, X86_EAX);
1907                 x86_pop_reg (code, X86_EDX);
1908                 break;
1909         case SAVE_EAX:
1910                 x86_pop_reg (code, X86_EAX);
1911                 break;
1912         case SAVE_FP:
1913                 x86_fld_membase (code, X86_ESP, 0, TRUE);
1914                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1915                 break;
1916         case SAVE_NONE:
1917         default:
1918                 break;
1919         }
1920         
1921         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - stack_usage);
1922
1923         return code;
1924 }
1925
1926 #define EMIT_COND_BRANCH(ins,cond,sign) \
1927 if (ins->inst_true_bb->native_offset) { \
1928         x86_branch (code, cond, cfg->native_code + ins->inst_true_bb->native_offset, sign); \
1929 } else { \
1930         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1931         if ((cfg->opt & MONO_OPT_BRANCH) && \
1932             x86_is_imm8 (ins->inst_true_bb->max_offset - cpos)) \
1933                 x86_branch8 (code, cond, 0, sign); \
1934         else \
1935                 x86_branch32 (code, cond, 0, sign); \
1936 }
1937
1938 /*  
1939  *      Emit an exception if condition is fail and
1940  *  if possible do a directly branch to target 
1941  */
1942 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
1943         do {                                                        \
1944                 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1945                 if (tins == NULL) {                                                                             \
1946                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1947                                         MONO_PATCH_INFO_EXC, exc_name);  \
1948                         x86_branch32 (code, cond, 0, signed);               \
1949                 } else {        \
1950                         EMIT_COND_BRANCH (tins, cond, signed);  \
1951                 }                       \
1952         } while (0); 
1953
1954 #define EMIT_FPCOMPARE(code) do { \
1955         x86_fcompp (code); \
1956         x86_fnstsw (code); \
1957 } while (0); 
1958
1959
1960 static guint8*
1961 emit_call (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointer data)
1962 {
1963         gboolean needs_paddings = TRUE;
1964         guint32 pad_size;
1965         MonoJumpInfo *jinfo = NULL;
1966
1967         if (cfg->abs_patches) {
1968                 jinfo = g_hash_table_lookup (cfg->abs_patches, data);
1969                 if (jinfo && jinfo->type == MONO_PATCH_INFO_JIT_ICALL_ADDR)
1970                         needs_paddings = FALSE;
1971         }
1972
1973         if (cfg->compile_aot)
1974                 needs_paddings = FALSE;
1975         /*The address must be 4 bytes aligned to avoid spanning multiple cache lines.
1976         This is required for code patching to be safe on SMP machines.
1977         */
1978         pad_size = (guint32)(code + 1 - cfg->native_code) & 0x3;
1979 #ifndef __native_client_codegen__
1980         if (needs_paddings && pad_size)
1981                 x86_padding (code, 4 - pad_size);
1982 #endif
1983
1984         mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
1985         x86_call_code (code, 0);
1986
1987         return code;
1988 }
1989
1990 #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)))
1991
1992 /*
1993  * mono_peephole_pass_1:
1994  *
1995  *   Perform peephole opts which should/can be performed before local regalloc
1996  */
1997 void
1998 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1999 {
2000         MonoInst *ins, *n;
2001
2002         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2003                 MonoInst *last_ins = ins->prev;
2004
2005                 switch (ins->opcode) {
2006                 case OP_IADD_IMM:
2007                 case OP_ADD_IMM:
2008                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
2009                                 /* 
2010                                  * X86_LEA is like ADD, but doesn't have the
2011                                  * sreg1==dreg restriction.
2012                                  */
2013                                 ins->opcode = OP_X86_LEA_MEMBASE;
2014                                 ins->inst_basereg = ins->sreg1;
2015                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2016                                 ins->opcode = OP_X86_INC_REG;
2017                         break;
2018                 case OP_SUB_IMM:
2019                 case OP_ISUB_IMM:
2020                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
2021                                 ins->opcode = OP_X86_LEA_MEMBASE;
2022                                 ins->inst_basereg = ins->sreg1;
2023                                 ins->inst_imm = -ins->inst_imm;
2024                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2025                                 ins->opcode = OP_X86_DEC_REG;
2026                         break;
2027                 case OP_COMPARE_IMM:
2028                 case OP_ICOMPARE_IMM:
2029                         /* OP_COMPARE_IMM (reg, 0) 
2030                          * --> 
2031                          * OP_X86_TEST_NULL (reg) 
2032                          */
2033                         if (!ins->inst_imm)
2034                                 ins->opcode = OP_X86_TEST_NULL;
2035                         break;
2036                 case OP_X86_COMPARE_MEMBASE_IMM:
2037                         /* 
2038                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
2039                          * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm
2040                          * -->
2041                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
2042                          * OP_COMPARE_IMM reg, imm
2043                          *
2044                          * Note: if imm = 0 then OP_COMPARE_IMM replaced with OP_X86_TEST_NULL
2045                          */
2046                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
2047                             ins->inst_basereg == last_ins->inst_destbasereg &&
2048                             ins->inst_offset == last_ins->inst_offset) {
2049                                         ins->opcode = OP_COMPARE_IMM;
2050                                         ins->sreg1 = last_ins->sreg1;
2051
2052                                         /* check if we can remove cmp reg,0 with test null */
2053                                         if (!ins->inst_imm)
2054                                                 ins->opcode = OP_X86_TEST_NULL;
2055                                 }
2056
2057                         break;                  
2058                 case OP_X86_PUSH_MEMBASE:
2059                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG ||
2060                                          last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2061                             ins->inst_basereg == last_ins->inst_destbasereg &&
2062                             ins->inst_offset == last_ins->inst_offset) {
2063                                     ins->opcode = OP_X86_PUSH;
2064                                     ins->sreg1 = last_ins->sreg1;
2065                         }
2066                         break;
2067                 }
2068
2069                 mono_peephole_ins (bb, ins);
2070         }
2071 }
2072
2073 void
2074 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2075 {
2076         MonoInst *ins, *n;
2077
2078         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2079                 switch (ins->opcode) {
2080                 case OP_ICONST:
2081                         /* reg = 0 -> XOR (reg, reg) */
2082                         /* XOR sets cflags on x86, so we cant do it always */
2083                         if (ins->inst_c0 == 0 && (!ins->next || (ins->next && INST_IGNORES_CFLAGS (ins->next->opcode)))) {
2084                                 MonoInst *ins2;
2085
2086                                 ins->opcode = OP_IXOR;
2087                                 ins->sreg1 = ins->dreg;
2088                                 ins->sreg2 = ins->dreg;
2089
2090                                 /* 
2091                                  * Convert succeeding STORE_MEMBASE_IMM 0 ins to STORE_MEMBASE_REG 
2092                                  * since it takes 3 bytes instead of 7.
2093                                  */
2094                                 for (ins2 = ins->next; ins2; ins2 = ins2->next) {
2095                                         if ((ins2->opcode == OP_STORE_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
2096                                                 ins2->opcode = OP_STORE_MEMBASE_REG;
2097                                                 ins2->sreg1 = ins->dreg;
2098                                         }
2099                                         else if ((ins2->opcode == OP_STOREI4_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
2100                                                 ins2->opcode = OP_STOREI4_MEMBASE_REG;
2101                                                 ins2->sreg1 = ins->dreg;
2102                                         }
2103                                         else if ((ins2->opcode == OP_STOREI1_MEMBASE_IMM) || (ins2->opcode == OP_STOREI2_MEMBASE_IMM)) {
2104                                                 /* Continue iteration */
2105                                         }
2106                                         else
2107                                                 break;
2108                                 }
2109                         }
2110                         break;
2111                 case OP_IADD_IMM:
2112                 case OP_ADD_IMM:
2113                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2114                                 ins->opcode = OP_X86_INC_REG;
2115                         break;
2116                 case OP_ISUB_IMM:
2117                 case OP_SUB_IMM:
2118                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
2119                                 ins->opcode = OP_X86_DEC_REG;
2120                         break;
2121                 }
2122
2123                 mono_peephole_ins (bb, ins);
2124         }
2125 }
2126
2127 /*
2128  * mono_arch_lowering_pass:
2129  *
2130  *  Converts complex opcodes into simpler ones so that each IR instruction
2131  * corresponds to one machine instruction.
2132  */
2133 void
2134 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2135 {
2136         MonoInst *ins, *next;
2137
2138         /*
2139          * FIXME: Need to add more instructions, but the current machine 
2140          * description can't model some parts of the composite instructions like
2141          * cdq.
2142          */
2143         MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) {
2144                 switch (ins->opcode) {
2145                 case OP_IREM_IMM:
2146                 case OP_IDIV_IMM:
2147                 case OP_IDIV_UN_IMM:
2148                 case OP_IREM_UN_IMM:
2149                         /* 
2150                          * Keep the cases where we could generated optimized code, otherwise convert
2151                          * to the non-imm variant.
2152                          */
2153                         if ((ins->opcode == OP_IREM_IMM) && mono_is_power_of_two (ins->inst_imm) >= 0)
2154                                 break;
2155                         mono_decompose_op_imm (cfg, bb, ins);
2156                         break;
2157                 default:
2158                         break;
2159                 }
2160         }
2161
2162         bb->max_vreg = cfg->next_vreg;
2163 }
2164
2165 static const int 
2166 branch_cc_table [] = {
2167         X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
2168         X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
2169         X86_CC_O, X86_CC_NO, X86_CC_C, X86_CC_NC
2170 };
2171
2172 /* Maps CMP_... constants to X86_CC_... constants */
2173 static const int
2174 cc_table [] = {
2175         X86_CC_EQ, X86_CC_NE, X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT,
2176         X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT
2177 };
2178
2179 static const int
2180 cc_signed_table [] = {
2181         TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
2182         FALSE, FALSE, FALSE, FALSE
2183 };
2184
2185 static unsigned char*
2186 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
2187 {
2188 #define XMM_TEMP_REG 0
2189         /*This SSE2 optimization must not be done which OPT_SIMD in place as it clobbers xmm0.*/
2190         /*The xmm pass decomposes OP_FCONV_ ops anyway anyway.*/
2191         if (cfg->opt & MONO_OPT_SSE2 && size < 8 && !(cfg->opt & MONO_OPT_SIMD)) {
2192                 /* optimize by assigning a local var for this use so we avoid
2193                  * the stack manipulations */
2194                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2195                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
2196                 x86_movsd_reg_membase (code, XMM_TEMP_REG, X86_ESP, 0);
2197                 x86_cvttsd2si (code, dreg, XMM_TEMP_REG);
2198                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
2199                 if (size == 1)
2200                         x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
2201                 else if (size == 2)
2202                         x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
2203                 return code;
2204         }
2205         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
2206         x86_fnstcw_membase(code, X86_ESP, 0);
2207         x86_mov_reg_membase (code, dreg, X86_ESP, 0, 2);
2208         x86_alu_reg_imm (code, X86_OR, dreg, 0xc00);
2209         x86_mov_membase_reg (code, X86_ESP, 2, dreg, 2);
2210         x86_fldcw_membase (code, X86_ESP, 2);
2211         if (size == 8) {
2212                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
2213                 x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
2214                 x86_pop_reg (code, dreg);
2215                 /* FIXME: need the high register 
2216                  * x86_pop_reg (code, dreg_high);
2217                  */
2218         } else {
2219                 x86_push_reg (code, X86_EAX); // SP = SP - 4
2220                 x86_fist_pop_membase (code, X86_ESP, 0, FALSE);
2221                 x86_pop_reg (code, dreg);
2222         }
2223         x86_fldcw_membase (code, X86_ESP, 0);
2224         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
2225
2226         if (size == 1)
2227                 x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
2228         else if (size == 2)
2229                 x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
2230         return code;
2231 }
2232
2233 static unsigned char*
2234 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
2235 {
2236         int sreg = tree->sreg1;
2237         int need_touch = FALSE;
2238
2239 #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
2240         need_touch = TRUE;
2241 #endif
2242
2243         if (need_touch) {
2244                 guint8* br[5];
2245
2246                 /*
2247                  * Under Windows:
2248                  * If requested stack size is larger than one page,
2249                  * perform stack-touch operation
2250                  */
2251                 /*
2252                  * Generate stack probe code.
2253                  * Under Windows, it is necessary to allocate one page at a time,
2254                  * "touching" stack after each successful sub-allocation. This is
2255                  * because of the way stack growth is implemented - there is a
2256                  * guard page before the lowest stack page that is currently commited.
2257                  * Stack normally grows sequentially so OS traps access to the
2258                  * guard page and commits more pages when needed.
2259                  */
2260                 x86_test_reg_imm (code, sreg, ~0xFFF);
2261                 br[0] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2262
2263                 br[2] = code; /* loop */
2264                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
2265                 x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
2266
2267                 /* 
2268                  * By the end of the loop, sreg2 is smaller than 0x1000, so the init routine
2269                  * that follows only initializes the last part of the area.
2270                  */
2271                 /* Same as the init code below with size==0x1000 */
2272                 if (tree->flags & MONO_INST_INIT) {
2273                         x86_push_reg (code, X86_EAX);
2274                         x86_push_reg (code, X86_ECX);
2275                         x86_push_reg (code, X86_EDI);
2276                         x86_mov_reg_imm (code, X86_ECX, (0x1000 >> 2));
2277                         x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);                              
2278                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2279                         x86_cld (code);
2280                         x86_prefix (code, X86_REP_PREFIX);
2281                         x86_stosl (code);
2282                         x86_pop_reg (code, X86_EDI);
2283                         x86_pop_reg (code, X86_ECX);
2284                         x86_pop_reg (code, X86_EAX);
2285                 }
2286
2287                 x86_alu_reg_imm (code, X86_SUB, sreg, 0x1000);
2288                 x86_alu_reg_imm (code, X86_CMP, sreg, 0x1000);
2289                 br[3] = code; x86_branch8 (code, X86_CC_AE, 0, FALSE);
2290                 x86_patch (br[3], br[2]);
2291                 x86_test_reg_reg (code, sreg, sreg);
2292                 br[4] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
2293                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2294
2295                 br[1] = code; x86_jump8 (code, 0);
2296
2297                 x86_patch (br[0], code);
2298                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
2299                 x86_patch (br[1], code);
2300                 x86_patch (br[4], code);
2301         }
2302         else
2303                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
2304
2305         if (tree->flags & MONO_INST_INIT) {
2306                 int offset = 0;
2307                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
2308                         x86_push_reg (code, X86_EAX);
2309                         offset += 4;
2310                 }
2311                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
2312                         x86_push_reg (code, X86_ECX);
2313                         offset += 4;
2314                 }
2315                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
2316                         x86_push_reg (code, X86_EDI);
2317                         offset += 4;
2318                 }
2319                 
2320                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
2321                 if (sreg != X86_ECX)
2322                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
2323                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
2324                                 
2325                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
2326                 x86_cld (code);
2327                 x86_prefix (code, X86_REP_PREFIX);
2328                 x86_stosl (code);
2329                 
2330                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
2331                         x86_pop_reg (code, X86_EDI);
2332                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
2333                         x86_pop_reg (code, X86_ECX);
2334                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
2335                         x86_pop_reg (code, X86_EAX);
2336         }
2337         return code;
2338 }
2339
2340
2341 static guint8*
2342 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
2343 {
2344         /* Move return value to the target register */
2345         switch (ins->opcode) {
2346         case OP_CALL:
2347         case OP_CALL_REG:
2348         case OP_CALL_MEMBASE:
2349                 if (ins->dreg != X86_EAX)
2350                         x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2351                 break;
2352         default:
2353                 break;
2354         }
2355
2356         return code;
2357 }
2358
2359 #ifdef __APPLE__
2360 static int tls_gs_offset;
2361 #endif
2362
2363 gboolean
2364 mono_x86_have_tls_get (void)
2365 {
2366 #ifdef __APPLE__
2367         static gboolean have_tls_get = FALSE;
2368         static gboolean inited = FALSE;
2369         guint32 *ins;
2370
2371         if (inited)
2372                 return have_tls_get;
2373
2374         ins = (guint32*)pthread_getspecific;
2375         /*
2376          * We're looking for these two instructions:
2377          *
2378          * mov    0x4(%esp),%eax
2379          * mov    %gs:[offset](,%eax,4),%eax
2380          */
2381         have_tls_get = ins [0] == 0x0424448b && ins [1] == 0x85048b65;
2382         tls_gs_offset = ins [2];
2383
2384         inited = TRUE;
2385
2386         return have_tls_get;
2387 #elif defined(TARGET_ANDROID)
2388         return FALSE;
2389 #else
2390         return TRUE;
2391 #endif
2392 }
2393
2394 static guint8*
2395 mono_x86_emit_tls_set (guint8* code, int sreg, int tls_offset)
2396 {
2397 #if defined(__APPLE__)
2398         x86_prefix (code, X86_GS_PREFIX);
2399         x86_mov_mem_reg (code, tls_gs_offset + (tls_offset * 4), sreg, 4);
2400 #elif defined(TARGET_WIN32)
2401         g_assert_not_reached ();
2402 #else
2403         x86_prefix (code, X86_GS_PREFIX);
2404         x86_mov_mem_reg (code, tls_offset, sreg, 4);
2405 #endif
2406         return code;
2407 }
2408
2409 /*
2410  * mono_x86_emit_tls_get:
2411  * @code: buffer to store code to
2412  * @dreg: hard register where to place the result
2413  * @tls_offset: offset info
2414  *
2415  * mono_x86_emit_tls_get emits in @code the native code that puts in
2416  * the dreg register the item in the thread local storage identified
2417  * by tls_offset.
2418  *
2419  * Returns: a pointer to the end of the stored code
2420  */
2421 guint8*
2422 mono_x86_emit_tls_get (guint8* code, int dreg, int tls_offset)
2423 {
2424 #if defined(__APPLE__)
2425         x86_prefix (code, X86_GS_PREFIX);
2426         x86_mov_reg_mem (code, dreg, tls_gs_offset + (tls_offset * 4), 4);
2427 #elif defined(TARGET_WIN32)
2428         /* 
2429          * See the Under the Hood article in the May 1996 issue of Microsoft Systems 
2430          * Journal and/or a disassembly of the TlsGet () function.
2431          */
2432         g_assert (tls_offset < 64);
2433         x86_prefix (code, X86_FS_PREFIX);
2434         x86_mov_reg_mem (code, dreg, 0x18, 4);
2435         /* Dunno what this does but TlsGetValue () contains it */
2436         x86_alu_membase_imm (code, X86_AND, dreg, 0x34, 0);
2437         x86_mov_reg_membase (code, dreg, dreg, 3600 + (tls_offset * 4), 4);
2438 #else
2439         if (optimize_for_xen) {
2440                 x86_prefix (code, X86_GS_PREFIX);
2441                 x86_mov_reg_mem (code, dreg, 0, 4);
2442                 x86_mov_reg_membase (code, dreg, dreg, tls_offset, 4);
2443         } else {
2444                 x86_prefix (code, X86_GS_PREFIX);
2445                 x86_mov_reg_mem (code, dreg, tls_offset, 4);
2446         }
2447 #endif
2448         return code;
2449 }
2450
2451 /*
2452  * emit_load_volatile_arguments:
2453  *
2454  *  Load volatile arguments from the stack to the original input registers.
2455  * Required before a tail call.
2456  */
2457 static guint8*
2458 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2459 {
2460         MonoMethod *method = cfg->method;
2461         MonoMethodSignature *sig;
2462         MonoInst *inst;
2463         CallInfo *cinfo;
2464         guint32 i;
2465
2466         /* FIXME: Generate intermediate code instead */
2467
2468         sig = mono_method_signature (method);
2469
2470         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
2471         
2472         /* This is the opposite of the code in emit_prolog */
2473
2474         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2475                 ArgInfo *ainfo = cinfo->args + i;
2476                 MonoType *arg_type;
2477                 inst = cfg->args [i];
2478
2479                 if (sig->hasthis && (i == 0))
2480                         arg_type = &mono_defaults.object_class->byval_arg;
2481                 else
2482                         arg_type = sig->params [i - sig->hasthis];
2483
2484                 /*
2485                  * On x86, the arguments are either in their original stack locations, or in
2486                  * global regs.
2487                  */
2488                 if (inst->opcode == OP_REGVAR) {
2489                         g_assert (ainfo->storage == ArgOnStack);
2490                         
2491                         x86_mov_membase_reg (code, X86_EBP, inst->inst_offset, inst->dreg, 4);
2492                 }
2493         }
2494
2495         return code;
2496 }
2497
2498 #define REAL_PRINT_REG(text,reg) \
2499 mono_assert (reg >= 0); \
2500 x86_push_reg (code, X86_EAX); \
2501 x86_push_reg (code, X86_EDX); \
2502 x86_push_reg (code, X86_ECX); \
2503 x86_push_reg (code, reg); \
2504 x86_push_imm (code, reg); \
2505 x86_push_imm (code, text " %d %p\n"); \
2506 x86_mov_reg_imm (code, X86_EAX, printf); \
2507 x86_call_reg (code, X86_EAX); \
2508 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
2509 x86_pop_reg (code, X86_ECX); \
2510 x86_pop_reg (code, X86_EDX); \
2511 x86_pop_reg (code, X86_EAX);
2512
2513 /* REAL_PRINT_REG does not appear to be used, and was not adapted to work with Native Client. */
2514 #ifdef __native__client_codegen__
2515 #define REAL_PRINT_REG(text, reg) g_assert_not_reached()
2516 #endif
2517
2518 /* benchmark and set based on cpu */
2519 #define LOOP_ALIGNMENT 8
2520 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2521
2522 #ifndef DISABLE_JIT
2523 void
2524 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2525 {
2526         MonoInst *ins;
2527         MonoCallInst *call;
2528         guint offset;
2529         guint8 *code = cfg->native_code + cfg->code_len;
2530         int max_len, cpos;
2531
2532         if (cfg->opt & MONO_OPT_LOOP) {
2533                 int pad, align = LOOP_ALIGNMENT;
2534                 /* set alignment depending on cpu */
2535                 if (bb_is_loop_start (bb) && (pad = (cfg->code_len & (align - 1)))) {
2536                         pad = align - pad;
2537                         /*g_print ("adding %d pad at %x to loop in %s\n", pad, cfg->code_len, cfg->method->name);*/
2538                         x86_padding (code, pad);
2539                         cfg->code_len += pad;
2540                         bb->native_offset = cfg->code_len;
2541                 }
2542         }
2543 #ifdef __native_client_codegen__
2544         {
2545                 /* For Native Client, all indirect call/jump targets must be   */
2546                 /* 32-byte aligned.  Exception handler blocks are jumped to    */
2547                 /* indirectly as well.                                         */
2548                 gboolean bb_needs_alignment = (bb->flags & BB_INDIRECT_JUMP_TARGET) ||
2549                         (bb->flags & BB_EXCEPTION_HANDLER);
2550
2551                 /* if ((cfg->code_len & kNaClAlignmentMask) != 0) { */
2552                 if ( bb_needs_alignment && ((cfg->code_len & kNaClAlignmentMask) != 0)) {
2553             int pad = kNaClAlignment - (cfg->code_len & kNaClAlignmentMask);
2554             if (pad != kNaClAlignment) code = mono_arch_nacl_pad(code, pad);
2555             cfg->code_len += pad;
2556             bb->native_offset = cfg->code_len;
2557                 }
2558         }
2559 #endif  /* __native_client_codegen__ */
2560         if (cfg->verbose_level > 2)
2561                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2562
2563         cpos = bb->max_offset;
2564
2565         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2566                 MonoProfileCoverageInfo *cov = cfg->coverage_info;
2567                 g_assert (!cfg->compile_aot);
2568                 cpos += 6;
2569
2570                 cov->data [bb->dfn].cil_code = bb->cil_code;
2571                 /* this is not thread save, but good enough */
2572                 x86_inc_mem (code, &cov->data [bb->dfn].count); 
2573         }
2574
2575         offset = code - cfg->native_code;
2576
2577         mono_debug_open_block (cfg, bb, offset);
2578
2579     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)
2580                 x86_breakpoint (code);
2581
2582         MONO_BB_FOR_EACH_INS (bb, ins) {
2583                 offset = code - cfg->native_code;
2584
2585                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2586
2587 #define EXTRA_CODE_SPACE (NACL_SIZE (16, 16 + kNaClAlignment))
2588
2589                 if (G_UNLIKELY (offset > (cfg->code_size - max_len - EXTRA_CODE_SPACE))) {
2590                         cfg->code_size *= 2;
2591                         cfg->native_code = mono_realloc_native_code(cfg);
2592                         code = cfg->native_code + offset;
2593                         cfg->stat_code_reallocs++;
2594                 }
2595
2596                 if (cfg->debug_info)
2597                         mono_debug_record_line_number (cfg, ins, offset);
2598
2599                 switch (ins->opcode) {
2600                 case OP_BIGMUL:
2601                         x86_mul_reg (code, ins->sreg2, TRUE);
2602                         break;
2603                 case OP_BIGMUL_UN:
2604                         x86_mul_reg (code, ins->sreg2, FALSE);
2605                         break;
2606                 case OP_X86_SETEQ_MEMBASE:
2607                 case OP_X86_SETNE_MEMBASE:
2608                         x86_set_membase (code, ins->opcode == OP_X86_SETEQ_MEMBASE ? X86_CC_EQ : X86_CC_NE,
2609                                          ins->inst_basereg, ins->inst_offset, TRUE);
2610                         break;
2611                 case OP_STOREI1_MEMBASE_IMM:
2612                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 1);
2613                         break;
2614                 case OP_STOREI2_MEMBASE_IMM:
2615                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 2);
2616                         break;
2617                 case OP_STORE_MEMBASE_IMM:
2618                 case OP_STOREI4_MEMBASE_IMM:
2619                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 4);
2620                         break;
2621                 case OP_STOREI1_MEMBASE_REG:
2622                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 1);
2623                         break;
2624                 case OP_STOREI2_MEMBASE_REG:
2625                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
2626                         break;
2627                 case OP_STORE_MEMBASE_REG:
2628                 case OP_STOREI4_MEMBASE_REG:
2629                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
2630                         break;
2631                 case OP_STORE_MEM_IMM:
2632                         x86_mov_mem_imm (code, ins->inst_p0, ins->inst_c0, 4);
2633                         break;
2634                 case OP_LOADU4_MEM:
2635                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2636                         break;
2637                 case OP_LOAD_MEM:
2638                 case OP_LOADI4_MEM:
2639                         /* These are created by the cprop pass so they use inst_imm as the source */
2640                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2641                         break;
2642                 case OP_LOADU1_MEM:
2643                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, FALSE);
2644                         break;
2645                 case OP_LOADU2_MEM:
2646                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, TRUE);
2647                         break;
2648                 case OP_LOAD_MEMBASE:
2649                 case OP_LOADI4_MEMBASE:
2650                 case OP_LOADU4_MEMBASE:
2651                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 4);
2652                         break;
2653                 case OP_LOADU1_MEMBASE:
2654                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, FALSE);
2655                         break;
2656                 case OP_LOADI1_MEMBASE:
2657                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, FALSE);
2658                         break;
2659                 case OP_LOADU2_MEMBASE:
2660                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, TRUE);
2661                         break;
2662                 case OP_LOADI2_MEMBASE:
2663                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
2664                         break;
2665                 case OP_ICONV_TO_I1:
2666                 case OP_SEXT_I1:
2667                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2668                         break;
2669                 case OP_ICONV_TO_I2:
2670                 case OP_SEXT_I2:
2671                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2672                         break;
2673                 case OP_ICONV_TO_U1:
2674                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, FALSE);
2675                         break;
2676                 case OP_ICONV_TO_U2:
2677                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, TRUE);
2678                         break;
2679                 case OP_COMPARE:
2680                 case OP_ICOMPARE:
2681                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2682                         break;
2683                 case OP_COMPARE_IMM:
2684                 case OP_ICOMPARE_IMM:
2685                         x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
2686                         break;
2687                 case OP_X86_COMPARE_MEMBASE_REG:
2688                         x86_alu_membase_reg (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2689                         break;
2690                 case OP_X86_COMPARE_MEMBASE_IMM:
2691                         x86_alu_membase_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2692                         break;
2693                 case OP_X86_COMPARE_MEMBASE8_IMM:
2694                         x86_alu_membase8_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2695                         break;
2696                 case OP_X86_COMPARE_REG_MEMBASE:
2697                         x86_alu_reg_membase (code, X86_CMP, ins->sreg1, ins->sreg2, ins->inst_offset);
2698                         break;
2699                 case OP_X86_COMPARE_MEM_IMM:
2700                         x86_alu_mem_imm (code, X86_CMP, ins->inst_offset, ins->inst_imm);
2701                         break;
2702                 case OP_X86_TEST_NULL:
2703                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2704                         break;
2705                 case OP_X86_ADD_MEMBASE_IMM:
2706                         x86_alu_membase_imm (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2707                         break;
2708                 case OP_X86_ADD_REG_MEMBASE:
2709                         x86_alu_reg_membase (code, X86_ADD, ins->sreg1, ins->sreg2, ins->inst_offset);
2710                         break;
2711                 case OP_X86_SUB_MEMBASE_IMM:
2712                         x86_alu_membase_imm (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2713                         break;
2714                 case OP_X86_SUB_REG_MEMBASE:
2715                         x86_alu_reg_membase (code, X86_SUB, ins->sreg1, ins->sreg2, ins->inst_offset);
2716                         break;
2717                 case OP_X86_AND_MEMBASE_IMM:
2718                         x86_alu_membase_imm (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2719                         break;
2720                 case OP_X86_OR_MEMBASE_IMM:
2721                         x86_alu_membase_imm (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2722                         break;
2723                 case OP_X86_XOR_MEMBASE_IMM:
2724                         x86_alu_membase_imm (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2725                         break;
2726                 case OP_X86_ADD_MEMBASE_REG:
2727                         x86_alu_membase_reg (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2728                         break;
2729                 case OP_X86_SUB_MEMBASE_REG:
2730                         x86_alu_membase_reg (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2731                         break;
2732                 case OP_X86_AND_MEMBASE_REG:
2733                         x86_alu_membase_reg (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2734                         break;
2735                 case OP_X86_OR_MEMBASE_REG:
2736                         x86_alu_membase_reg (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2737                         break;
2738                 case OP_X86_XOR_MEMBASE_REG:
2739                         x86_alu_membase_reg (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2740                         break;
2741                 case OP_X86_INC_MEMBASE:
2742                         x86_inc_membase (code, ins->inst_basereg, ins->inst_offset);
2743                         break;
2744                 case OP_X86_INC_REG:
2745                         x86_inc_reg (code, ins->dreg);
2746                         break;
2747                 case OP_X86_DEC_MEMBASE:
2748                         x86_dec_membase (code, ins->inst_basereg, ins->inst_offset);
2749                         break;
2750                 case OP_X86_DEC_REG:
2751                         x86_dec_reg (code, ins->dreg);
2752                         break;
2753                 case OP_X86_MUL_REG_MEMBASE:
2754                         x86_imul_reg_membase (code, ins->sreg1, ins->sreg2, ins->inst_offset);
2755                         break;
2756                 case OP_X86_AND_REG_MEMBASE:
2757                         x86_alu_reg_membase (code, X86_AND, ins->sreg1, ins->sreg2, ins->inst_offset);
2758                         break;
2759                 case OP_X86_OR_REG_MEMBASE:
2760                         x86_alu_reg_membase (code, X86_OR, ins->sreg1, ins->sreg2, ins->inst_offset);
2761                         break;
2762                 case OP_X86_XOR_REG_MEMBASE:
2763                         x86_alu_reg_membase (code, X86_XOR, ins->sreg1, ins->sreg2, ins->inst_offset);
2764                         break;
2765                 case OP_BREAK:
2766                         x86_breakpoint (code);
2767                         break;
2768                 case OP_RELAXED_NOP:
2769                         x86_prefix (code, X86_REP_PREFIX);
2770                         x86_nop (code);
2771                         break;
2772                 case OP_HARD_NOP:
2773                         x86_nop (code);
2774                         break;
2775                 case OP_NOP:
2776                 case OP_DUMMY_USE:
2777                 case OP_DUMMY_STORE:
2778                 case OP_NOT_REACHED:
2779                 case OP_NOT_NULL:
2780                         break;
2781                 case OP_SEQ_POINT: {
2782                         int i;
2783
2784                         if (cfg->compile_aot)
2785                                 NOT_IMPLEMENTED;
2786
2787                         /* 
2788                          * Read from the single stepping trigger page. This will cause a
2789                          * SIGSEGV when single stepping is enabled.
2790                          * We do this _before_ the breakpoint, so single stepping after
2791                          * a breakpoint is hit will step to the next IL offset.
2792                          */
2793                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
2794                                 x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
2795
2796                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
2797
2798                         /* 
2799                          * A placeholder for a possible breakpoint inserted by
2800                          * mono_arch_set_breakpoint ().
2801                          */
2802                         for (i = 0; i < 6; ++i)
2803                                 x86_nop (code);
2804                         /*
2805                          * Add an additional nop so skipping the bp doesn't cause the ip to point
2806                          * to another IL offset.
2807                          */
2808                         x86_nop (code);
2809                         break;
2810                 }
2811                 case OP_ADDCC:
2812                 case OP_IADDCC:
2813                 case OP_IADD:
2814                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2815                         break;
2816                 case OP_ADC:
2817                 case OP_IADC:
2818                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2819                         break;
2820                 case OP_ADDCC_IMM:
2821                 case OP_ADD_IMM:
2822                 case OP_IADD_IMM:
2823                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2824                         break;
2825                 case OP_ADC_IMM:
2826                 case OP_IADC_IMM:
2827                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2828                         break;
2829                 case OP_SUBCC:
2830                 case OP_ISUBCC:
2831                 case OP_ISUB:
2832                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2833                         break;
2834                 case OP_SBB:
2835                 case OP_ISBB:
2836                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2837                         break;
2838                 case OP_SUBCC_IMM:
2839                 case OP_SUB_IMM:
2840                 case OP_ISUB_IMM:
2841                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2842                         break;
2843                 case OP_SBB_IMM:
2844                 case OP_ISBB_IMM:
2845                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2846                         break;
2847                 case OP_IAND:
2848                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2849                         break;
2850                 case OP_AND_IMM:
2851                 case OP_IAND_IMM:
2852                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2853                         break;
2854                 case OP_IDIV:
2855                 case OP_IREM:
2856 #if defined( __native_client_codegen__ )
2857                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0);
2858                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "DivideByZeroException");
2859 #endif
2860                         /* 
2861                          * The code is the same for div/rem, the allocator will allocate dreg
2862                          * to RAX/RDX as appropriate.
2863                          */
2864                         if (ins->sreg2 == X86_EDX) {
2865                                 /* cdq clobbers this */
2866                                 x86_push_reg (code, ins->sreg2);
2867                                 x86_cdq (code);
2868                                 x86_div_membase (code, X86_ESP, 0, TRUE);
2869                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2870                         } else {
2871                                 x86_cdq (code);
2872                                 x86_div_reg (code, ins->sreg2, TRUE);
2873                         }
2874                         break;
2875                 case OP_IDIV_UN:
2876                 case OP_IREM_UN:
2877 #if defined( __native_client_codegen__ )
2878                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0);
2879                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, TRUE, "DivideByZeroException");
2880 #endif
2881                         if (ins->sreg2 == X86_EDX) {
2882                                 x86_push_reg (code, ins->sreg2);
2883                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2884                                 x86_div_membase (code, X86_ESP, 0, FALSE);
2885                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2886                         } else {
2887                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2888                                 x86_div_reg (code, ins->sreg2, FALSE);
2889                         }
2890                         break;
2891                 case OP_DIV_IMM:
2892 #if defined( __native_client_codegen__ )
2893                         if (ins->inst_imm == 0) {
2894                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "DivideByZeroException");
2895                                 x86_jump32 (code, 0);
2896                                 break;
2897                         }
2898 #endif
2899                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2900                         x86_cdq (code);
2901                         x86_div_reg (code, ins->sreg2, TRUE);
2902                         break;
2903                 case OP_IREM_IMM: {
2904                         int power = mono_is_power_of_two (ins->inst_imm);
2905
2906                         g_assert (ins->sreg1 == X86_EAX);
2907                         g_assert (ins->dreg == X86_EAX);
2908                         g_assert (power >= 0);
2909
2910                         if (power == 1) {
2911                                 /* Based on http://compilers.iecc.com/comparch/article/93-04-079 */
2912                                 x86_cdq (code);
2913                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, 1);
2914                                 /* 
2915                                  * If the divident is >= 0, this does not nothing. If it is positive, it
2916                                  * it transforms %eax=0 into %eax=0, and %eax=1 into %eax=-1.
2917                                  */
2918                                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EDX);
2919                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2920                         } else if (power == 0) {
2921                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
2922                         } else {
2923                                 /* Based on gcc code */
2924
2925                                 /* Add compensation for negative dividents */
2926                                 x86_cdq (code);
2927                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, 32 - power);
2928                                 x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EDX);
2929                                 /* Compute remainder */
2930                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, (1 << power) - 1);
2931                                 /* Remove compensation */
2932                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2933                         }
2934                         break;
2935                 }
2936                 case OP_IOR:
2937                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2938                         break;
2939                 case OP_OR_IMM:
2940                 case OP_IOR_IMM:
2941                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2942                         break;
2943                 case OP_IXOR:
2944                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2945                         break;
2946                 case OP_XOR_IMM:
2947                 case OP_IXOR_IMM:
2948                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2949                         break;
2950                 case OP_ISHL:
2951                         g_assert (ins->sreg2 == X86_ECX);
2952                         x86_shift_reg (code, X86_SHL, ins->dreg);
2953                         break;
2954                 case OP_ISHR:
2955                         g_assert (ins->sreg2 == X86_ECX);
2956                         x86_shift_reg (code, X86_SAR, ins->dreg);
2957                         break;
2958                 case OP_SHR_IMM:
2959                 case OP_ISHR_IMM:
2960                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2961                         break;
2962                 case OP_SHR_UN_IMM:
2963                 case OP_ISHR_UN_IMM:
2964                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2965                         break;
2966                 case OP_ISHR_UN:
2967                         g_assert (ins->sreg2 == X86_ECX);
2968                         x86_shift_reg (code, X86_SHR, ins->dreg);
2969                         break;
2970                 case OP_SHL_IMM:
2971                 case OP_ISHL_IMM:
2972                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2973                         break;
2974                 case OP_LSHL: {
2975                         guint8 *jump_to_end;
2976
2977                         /* handle shifts below 32 bits */
2978                         x86_shld_reg (code, ins->backend.reg3, ins->sreg1);
2979                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2980
2981                         x86_test_reg_imm (code, X86_ECX, 32);
2982                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2983
2984                         /* handle shift over 32 bit */
2985                         x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2986                         x86_clear_reg (code, ins->sreg1);
2987                         
2988                         x86_patch (jump_to_end, code);
2989                         }
2990                         break;
2991                 case OP_LSHR: {
2992                         guint8 *jump_to_end;
2993
2994                         /* handle shifts below 32 bits */
2995                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2996                         x86_shift_reg (code, X86_SAR, ins->backend.reg3);
2997
2998                         x86_test_reg_imm (code, X86_ECX, 32);
2999                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
3000
3001                         /* handle shifts over 31 bits */
3002                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
3003                         x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 31);
3004                         
3005                         x86_patch (jump_to_end, code);
3006                         }
3007                         break;
3008                 case OP_LSHR_UN: {
3009                         guint8 *jump_to_end;
3010
3011                         /* handle shifts below 32 bits */
3012                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
3013                         x86_shift_reg (code, X86_SHR, ins->backend.reg3);
3014
3015                         x86_test_reg_imm (code, X86_ECX, 32);
3016                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
3017
3018                         /* handle shifts over 31 bits */
3019                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
3020                         x86_clear_reg (code, ins->backend.reg3);
3021                         
3022                         x86_patch (jump_to_end, code);
3023                         }
3024                         break;
3025                 case OP_LSHL_IMM:
3026                         if (ins->inst_imm >= 32) {
3027                                 x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
3028                                 x86_clear_reg (code, ins->sreg1);
3029                                 x86_shift_reg_imm (code, X86_SHL, ins->backend.reg3, ins->inst_imm - 32);
3030                         } else {
3031                                 x86_shld_reg_imm (code, ins->backend.reg3, ins->sreg1, ins->inst_imm);
3032                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
3033                         }
3034                         break;
3035                 case OP_LSHR_IMM:
3036                         if (ins->inst_imm >= 32) {
3037                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3,  4);
3038                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 0x1f);
3039                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
3040                         } else {
3041                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
3042                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, ins->inst_imm);
3043                         }
3044                         break;
3045                 case OP_LSHR_UN_IMM:
3046                         if (ins->inst_imm >= 32) {
3047                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
3048                                 x86_clear_reg (code, ins->backend.reg3);
3049                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
3050                         } else {
3051                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
3052                                 x86_shift_reg_imm (code, X86_SHR, ins->backend.reg3, ins->inst_imm);
3053                         }
3054                         break;
3055                 case OP_INOT:
3056                         x86_not_reg (code, ins->sreg1);
3057                         break;
3058                 case OP_INEG:
3059                         x86_neg_reg (code, ins->sreg1);
3060                         break;
3061
3062                 case OP_IMUL:
3063                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
3064                         break;
3065                 case OP_MUL_IMM:
3066                 case OP_IMUL_IMM:
3067                         switch (ins->inst_imm) {
3068                         case 2:
3069                                 /* MOV r1, r2 */
3070                                 /* ADD r1, r1 */
3071                                 if (ins->dreg != ins->sreg1)
3072                                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3073                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
3074                                 break;
3075                         case 3:
3076                                 /* LEA r1, [r2 + r2*2] */
3077                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
3078                                 break;
3079                         case 5:
3080                                 /* LEA r1, [r2 + r2*4] */
3081                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3082                                 break;
3083                         case 6:
3084                                 /* LEA r1, [r2 + r2*2] */
3085                                 /* ADD r1, r1          */
3086                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
3087                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
3088                                 break;
3089                         case 9:
3090                                 /* LEA r1, [r2 + r2*8] */
3091                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 3);
3092                                 break;
3093                         case 10:
3094                                 /* LEA r1, [r2 + r2*4] */
3095                                 /* ADD r1, r1          */
3096                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3097                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
3098                                 break;
3099                         case 12:
3100                                 /* LEA r1, [r2 + r2*2] */
3101                                 /* SHL r1, 2           */
3102                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
3103                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
3104                                 break;
3105                         case 25:
3106                                 /* LEA r1, [r2 + r2*4] */
3107                                 /* LEA r1, [r1 + r1*4] */
3108                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3109                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
3110                                 break;
3111                         case 100:
3112                                 /* LEA r1, [r2 + r2*4] */
3113                                 /* SHL r1, 2           */
3114                                 /* LEA r1, [r1 + r1*4] */
3115                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
3116                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
3117                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
3118                                 break;
3119                         default:
3120                                 x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
3121                                 break;
3122                         }
3123                         break;
3124                 case OP_IMUL_OVF:
3125                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
3126                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
3127                         break;
3128                 case OP_IMUL_OVF_UN: {
3129                         /* the mul operation and the exception check should most likely be split */
3130                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
3131                         /*g_assert (ins->sreg2 == X86_EAX);
3132                         g_assert (ins->dreg == X86_EAX);*/
3133                         if (ins->sreg2 == X86_EAX) {
3134                                 non_eax_reg = ins->sreg1;
3135                         } else if (ins->sreg1 == X86_EAX) {
3136                                 non_eax_reg = ins->sreg2;
3137                         } else {
3138                                 /* no need to save since we're going to store to it anyway */
3139                                 if (ins->dreg != X86_EAX) {
3140                                         saved_eax = TRUE;
3141                                         x86_push_reg (code, X86_EAX);
3142                                 }
3143                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
3144                                 non_eax_reg = ins->sreg2;
3145                         }
3146                         if (ins->dreg == X86_EDX) {
3147                                 if (!saved_eax) {
3148                                         saved_eax = TRUE;
3149                                         x86_push_reg (code, X86_EAX);
3150                                 }
3151                         } else if (ins->dreg != X86_EAX) {
3152                                 saved_edx = TRUE;
3153                                 x86_push_reg (code, X86_EDX);
3154                         }
3155                         x86_mul_reg (code, non_eax_reg, FALSE);
3156                         /* save before the check since pop and mov don't change the flags */
3157                         if (ins->dreg != X86_EAX)
3158                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
3159                         if (saved_edx)
3160                                 x86_pop_reg (code, X86_EDX);
3161                         if (saved_eax)
3162                                 x86_pop_reg (code, X86_EAX);
3163                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
3164                         break;
3165                 }
3166                 case OP_ICONST:
3167                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
3168                         break;
3169                 case OP_AOTCONST:
3170                         g_assert_not_reached ();
3171                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3172                         x86_mov_reg_imm (code, ins->dreg, 0);
3173                         break;
3174                 case OP_JUMP_TABLE:
3175                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3176                         x86_mov_reg_imm (code, ins->dreg, 0);
3177                         break;
3178                 case OP_LOAD_GOTADDR:
3179                         g_assert (ins->dreg == MONO_ARCH_GOT_REG);
3180                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
3181                         break;
3182                 case OP_GOT_ENTRY:
3183                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3184                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, 0xf0f0f0f0, 4);
3185                         break;
3186                 case OP_X86_PUSH_GOT_ENTRY:
3187                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
3188                         x86_push_membase (code, ins->inst_basereg, 0xf0f0f0f0);
3189                         break;
3190                 case OP_MOVE:
3191                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3192                         break;
3193                 case OP_JMP: {
3194                         /*
3195                          * Note: this 'frame destruction' logic is useful for tail calls, too.
3196                          * Keep in sync with the code in emit_epilog.
3197                          */
3198                         int pos = 0;
3199
3200                         /* FIXME: no tracing support... */
3201                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3202                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
3203                         /* reset offset to make max_len work */
3204                         offset = code - cfg->native_code;
3205
3206                         g_assert (!cfg->method->save_lmf);
3207
3208                         code = emit_load_volatile_arguments (cfg, code);
3209
3210                         if (cfg->used_int_regs & (1 << X86_EBX))
3211                                 pos -= 4;
3212                         if (cfg->used_int_regs & (1 << X86_EDI))
3213                                 pos -= 4;
3214                         if (cfg->used_int_regs & (1 << X86_ESI))
3215                                 pos -= 4;
3216                         if (pos)
3217                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
3218         
3219                         if (cfg->used_int_regs & (1 << X86_ESI))
3220                                 x86_pop_reg (code, X86_ESI);
3221                         if (cfg->used_int_regs & (1 << X86_EDI))
3222                                 x86_pop_reg (code, X86_EDI);
3223                         if (cfg->used_int_regs & (1 << X86_EBX))
3224                                 x86_pop_reg (code, X86_EBX);
3225         
3226                         /* restore ESP/EBP */
3227                         x86_leave (code);
3228                         offset = code - cfg->native_code;
3229                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3230                         x86_jump32 (code, 0);
3231
3232                         cfg->disable_aot = TRUE;
3233                         break;
3234                 }
3235                 case OP_TAILCALL: {
3236                         MonoCallInst *call = (MonoCallInst*)ins;
3237                         int pos = 0, i;
3238
3239                         ins->flags |= MONO_INST_GC_CALLSITE;
3240                         ins->backend.pc_offset = code - cfg->native_code;
3241
3242                         /* FIXME: no tracing support... */
3243                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3244                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
3245                         /* reset offset to make max_len work */
3246                         offset = code - cfg->native_code;
3247
3248                         g_assert (!cfg->method->save_lmf);
3249
3250                         //code = emit_load_volatile_arguments (cfg, code);
3251
3252                         /* restore callee saved registers */
3253                         for (i = 0; i < X86_NREG; ++i)
3254                                 if (X86_IS_CALLEE_SAVED_REG (i) && cfg->used_int_regs & (1 << i))
3255                                         pos -= 4;
3256                         if (cfg->used_int_regs & (1 << X86_ESI)) {
3257                                 x86_mov_reg_membase (code, X86_ESI, X86_EBP, pos, 4);
3258                                 pos += 4;
3259                         }
3260                         if (cfg->used_int_regs & (1 << X86_EDI)) {
3261                                 x86_mov_reg_membase (code, X86_EDI, X86_EBP, pos, 4);
3262                                 pos += 4;
3263                         }
3264                         if (cfg->used_int_regs & (1 << X86_EBX)) {
3265                                 x86_mov_reg_membase (code, X86_EBX, X86_EBP, pos, 4);
3266                                 pos += 4;
3267                         }
3268
3269                         /* Copy arguments on the stack to our argument area */
3270                         for (i = 0; i < call->stack_usage - call->stack_align_amount; i += 4) {
3271                                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, i, 4);
3272                                 x86_mov_membase_reg (code, X86_EBP, 8 + i, X86_EAX, 4);
3273                         }
3274         
3275                         /* restore ESP/EBP */
3276                         x86_leave (code);
3277                         offset = code - cfg->native_code;
3278                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3279                         x86_jump32 (code, 0);
3280
3281                         ins->flags |= MONO_INST_GC_CALLSITE;
3282                         cfg->disable_aot = TRUE;
3283                         break;
3284                 }
3285                 case OP_CHECK_THIS:
3286                         /* ensure ins->sreg1 is not NULL
3287                          * note that cmp DWORD PTR [eax], eax is one byte shorter than
3288                          * cmp DWORD PTR [eax], 0
3289                          */
3290                         x86_alu_membase_reg (code, X86_CMP, ins->sreg1, 0, ins->sreg1);
3291                         break;
3292                 case OP_ARGLIST: {
3293                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
3294                         x86_push_reg (code, hreg);
3295                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
3296                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
3297                         x86_pop_reg (code, hreg);
3298                         break;
3299                 }
3300                 case OP_FCALL:
3301                 case OP_LCALL:
3302                 case OP_VCALL:
3303                 case OP_VCALL2:
3304                 case OP_VOIDCALL:
3305                 case OP_CALL:
3306                         call = (MonoCallInst*)ins;
3307                         if (ins->flags & MONO_INST_HAS_METHOD)
3308                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
3309                         else
3310                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
3311                         ins->flags |= MONO_INST_GC_CALLSITE;
3312                         ins->backend.pc_offset = code - cfg->native_code;
3313                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
3314                                 /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8
3315                                  * bytes to pop, we want to use pops. GCC does this (note it won't happen
3316                                  * for P4 or i686 because gcc will avoid using pop push at all. But we aren't
3317                                  * smart enough to do that optimization yet
3318                                  *
3319                                  * It turns out that on my P4, doing two pops for 8 bytes on the stack makes
3320                                  * mcs botstrap slow down. However, doing 1 pop for 4 bytes creates a small,
3321                                  * (most likely from locality benefits). People with other processors should
3322                                  * check on theirs to see what happens.
3323                                  */
3324                                 if (call->stack_usage == 4) {
3325                                         /* we want to use registers that won't get used soon, so use
3326                                          * ecx, as eax will get allocated first. edx is used by long calls,
3327                                          * so we can't use that.
3328                                          */
3329                                         
3330                                         x86_pop_reg (code, X86_ECX);
3331                                 } else {
3332                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
3333                                 }
3334                         }
3335                         code = emit_move_return_value (cfg, ins, code);
3336                         break;
3337                 case OP_FCALL_REG:
3338                 case OP_LCALL_REG:
3339                 case OP_VCALL_REG:
3340                 case OP_VCALL2_REG:
3341                 case OP_VOIDCALL_REG:
3342                 case OP_CALL_REG:
3343                         call = (MonoCallInst*)ins;
3344                         x86_call_reg (code, ins->sreg1);
3345                         ins->flags |= MONO_INST_GC_CALLSITE;
3346                         ins->backend.pc_offset = code - cfg->native_code;
3347                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
3348                                 if (call->stack_usage == 4)
3349                                         x86_pop_reg (code, X86_ECX);
3350                                 else
3351                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
3352                         }
3353                         code = emit_move_return_value (cfg, ins, code);
3354                         break;
3355                 case OP_FCALL_MEMBASE:
3356                 case OP_LCALL_MEMBASE:
3357                 case OP_VCALL_MEMBASE:
3358                 case OP_VCALL2_MEMBASE:
3359                 case OP_VOIDCALL_MEMBASE:
3360                 case OP_CALL_MEMBASE:
3361                         call = (MonoCallInst*)ins;
3362
3363                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
3364                         ins->flags |= MONO_INST_GC_CALLSITE;
3365                         ins->backend.pc_offset = code - cfg->native_code;
3366                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
3367                                 if (call->stack_usage == 4)
3368                                         x86_pop_reg (code, X86_ECX);
3369                                 else
3370                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
3371                         }
3372                         code = emit_move_return_value (cfg, ins, code);
3373                         break;
3374                 case OP_X86_PUSH:
3375                         x86_push_reg (code, ins->sreg1);
3376                         break;
3377                 case OP_X86_PUSH_IMM:
3378                         x86_push_imm (code, ins->inst_imm);
3379                         break;
3380                 case OP_X86_PUSH_MEMBASE:
3381                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
3382                         break;
3383                 case OP_X86_PUSH_OBJ: 
3384                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
3385                         x86_push_reg (code, X86_EDI);
3386                         x86_push_reg (code, X86_ESI);
3387                         x86_push_reg (code, X86_ECX);
3388                         if (ins->inst_offset)
3389                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
3390                         else
3391                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
3392                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
3393                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
3394                         x86_cld (code);
3395                         x86_prefix (code, X86_REP_PREFIX);
3396                         x86_movsd (code);
3397                         x86_pop_reg (code, X86_ECX);
3398                         x86_pop_reg (code, X86_ESI);
3399                         x86_pop_reg (code, X86_EDI);
3400                         break;
3401                 case OP_X86_LEA:
3402                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
3403                         break;
3404                 case OP_X86_LEA_MEMBASE:
3405                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
3406                         break;
3407                 case OP_X86_XCHG:
3408                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
3409                         break;
3410                 case OP_LOCALLOC:
3411                         /* keep alignment */
3412                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_LOCALLOC_ALIGNMENT - 1);
3413                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
3414                         code = mono_emit_stack_alloc (code, ins);
3415                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
3416                         break;
3417                 case OP_LOCALLOC_IMM: {
3418                         guint32 size = ins->inst_imm;
3419                         size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
3420
3421                         if (ins->flags & MONO_INST_INIT) {
3422                                 /* FIXME: Optimize this */
3423                                 x86_mov_reg_imm (code, ins->dreg, size);
3424                                 ins->sreg1 = ins->dreg;
3425
3426                                 code = mono_emit_stack_alloc (code, ins);
3427                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
3428                         } else {
3429                                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, size);
3430                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
3431                         }
3432                         break;
3433                 }
3434                 case OP_THROW: {
3435                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3436                         x86_push_reg (code, ins->sreg1);
3437                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3438                                                           (gpointer)"mono_arch_throw_exception");
3439                         ins->flags |= MONO_INST_GC_CALLSITE;
3440                         ins->backend.pc_offset = code - cfg->native_code;
3441                         break;
3442                 }
3443                 case OP_RETHROW: {
3444                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3445                         x86_push_reg (code, ins->sreg1);
3446                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3447                                                           (gpointer)"mono_arch_rethrow_exception");
3448                         ins->flags |= MONO_INST_GC_CALLSITE;
3449                         ins->backend.pc_offset = code - cfg->native_code;
3450                         break;
3451                 }
3452                 case OP_CALL_HANDLER:
3453                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3454                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3455                         x86_call_imm (code, 0);
3456                         mono_cfg_add_try_hole (cfg, ins->inst_eh_block, code, bb);
3457                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, MONO_ARCH_FRAME_ALIGNMENT - 4);
3458                         break;
3459                 case OP_START_HANDLER: {
3460                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3461                         x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4);
3462                         break;
3463                 }
3464                 case OP_ENDFINALLY: {
3465                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3466                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
3467                         x86_ret (code);
3468                         break;
3469                 }
3470                 case OP_ENDFILTER: {
3471                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3472                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
3473                         /* The local allocator will put the result into EAX */
3474                         x86_ret (code);
3475                         break;
3476                 }
3477
3478                 case OP_LABEL:
3479                         ins->inst_c0 = code - cfg->native_code;
3480                         break;
3481                 case OP_BR:
3482                         if (ins->inst_target_bb->native_offset) {
3483                                 x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
3484                         } else {
3485                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3486                                 if ((cfg->opt & MONO_OPT_BRANCH) &&
3487                                     x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
3488                                         x86_jump8 (code, 0);
3489                                 else 
3490                                         x86_jump32 (code, 0);
3491                         }
3492                         break;
3493                 case OP_BR_REG:
3494                         x86_jump_reg (code, ins->sreg1);
3495                         break;
3496                 case OP_CEQ:
3497                 case OP_CLT:
3498                 case OP_CLT_UN:
3499                 case OP_CGT:
3500                 case OP_CGT_UN:
3501                 case OP_CNE:
3502                 case OP_ICEQ:
3503                 case OP_ICLT:
3504                 case OP_ICLT_UN:
3505                 case OP_ICGT:
3506                 case OP_ICGT_UN:
3507                         x86_set_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3508                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3509                         break;
3510                 case OP_COND_EXC_EQ:
3511                 case OP_COND_EXC_NE_UN:
3512                 case OP_COND_EXC_LT:
3513                 case OP_COND_EXC_LT_UN:
3514                 case OP_COND_EXC_GT:
3515                 case OP_COND_EXC_GT_UN:
3516                 case OP_COND_EXC_GE:
3517                 case OP_COND_EXC_GE_UN:
3518                 case OP_COND_EXC_LE:
3519                 case OP_COND_EXC_LE_UN:
3520                 case OP_COND_EXC_IEQ:
3521                 case OP_COND_EXC_INE_UN:
3522                 case OP_COND_EXC_ILT:
3523                 case OP_COND_EXC_ILT_UN:
3524                 case OP_COND_EXC_IGT:
3525                 case OP_COND_EXC_IGT_UN:
3526                 case OP_COND_EXC_IGE:
3527                 case OP_COND_EXC_IGE_UN:
3528                 case OP_COND_EXC_ILE:
3529                 case OP_COND_EXC_ILE_UN:
3530                         EMIT_COND_SYSTEM_EXCEPTION (cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->inst_p1);
3531                         break;
3532                 case OP_COND_EXC_OV:
3533                 case OP_COND_EXC_NO:
3534                 case OP_COND_EXC_C:
3535                 case OP_COND_EXC_NC:
3536                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
3537                         break;
3538                 case OP_COND_EXC_IOV:
3539                 case OP_COND_EXC_INO:
3540                 case OP_COND_EXC_IC:
3541                 case OP_COND_EXC_INC:
3542                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], (ins->opcode < OP_COND_EXC_INE_UN), ins->inst_p1);
3543                         break;
3544                 case OP_IBEQ:
3545                 case OP_IBNE_UN:
3546                 case OP_IBLT:
3547                 case OP_IBLT_UN:
3548                 case OP_IBGT:
3549                 case OP_IBGT_UN:
3550                 case OP_IBGE:
3551                 case OP_IBGE_UN:
3552                 case OP_IBLE:
3553                 case OP_IBLE_UN:
3554                         EMIT_COND_BRANCH (ins, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3555                         break;
3556
3557                 case OP_CMOV_IEQ:
3558                 case OP_CMOV_IGE:
3559                 case OP_CMOV_IGT:
3560                 case OP_CMOV_ILE:
3561                 case OP_CMOV_ILT:
3562                 case OP_CMOV_INE_UN:
3563                 case OP_CMOV_IGE_UN:
3564                 case OP_CMOV_IGT_UN:
3565                 case OP_CMOV_ILE_UN:
3566                 case OP_CMOV_ILT_UN:
3567                         g_assert (ins->dreg == ins->sreg1);
3568                         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);
3569                         break;
3570
3571                 /* floating point opcodes */
3572                 case OP_R8CONST: {
3573                         double d = *(double *)ins->inst_p0;
3574
3575                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
3576                                 x86_fldz (code);
3577                         } else if (d == 1.0) {
3578                                 x86_fld1 (code);
3579                         } else {
3580                                 if (cfg->compile_aot) {
3581                                         guint32 *val = (guint32*)&d;
3582                                         x86_push_imm (code, val [1]);
3583                                         x86_push_imm (code, val [0]);
3584                                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3585                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3586                                 }
3587                                 else {
3588                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R8, ins->inst_p0);
3589                                         x86_fld (code, NULL, TRUE);
3590                                 }
3591                         }
3592                         break;
3593                 }
3594                 case OP_R4CONST: {
3595                         float f = *(float *)ins->inst_p0;
3596
3597                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
3598                                 x86_fldz (code);
3599                         } else if (f == 1.0) {
3600                                 x86_fld1 (code);
3601                         } else {
3602                                 if (cfg->compile_aot) {
3603                                         guint32 val = *(guint32*)&f;
3604                                         x86_push_imm (code, val);
3605                                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3606                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3607                                 }
3608                                 else {
3609                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R4, ins->inst_p0);
3610                                         x86_fld (code, NULL, FALSE);
3611                                 }
3612                         }
3613                         break;
3614                 }
3615                 case OP_STORER8_MEMBASE_REG:
3616                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
3617                         break;
3618                 case OP_LOADR8_MEMBASE:
3619                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3620                         break;
3621                 case OP_STORER4_MEMBASE_REG:
3622                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
3623                         break;
3624                 case OP_LOADR4_MEMBASE:
3625                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3626                         break;
3627                 case OP_ICONV_TO_R4:
3628                         x86_push_reg (code, ins->sreg1);
3629                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3630                         /* Change precision */
3631                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3632                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3633                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3634                         break;
3635                 case OP_ICONV_TO_R8:
3636                         x86_push_reg (code, ins->sreg1);
3637                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3638                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3639                         break;
3640                 case OP_ICONV_TO_R_UN:
3641                         x86_push_imm (code, 0);
3642                         x86_push_reg (code, ins->sreg1);
3643                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3644                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3645                         break;
3646                 case OP_X86_FP_LOAD_I8:
3647                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3648                         break;
3649                 case OP_X86_FP_LOAD_I4:
3650                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3651                         break;
3652                 case OP_FCONV_TO_R4:
3653                         /* Change precision */
3654                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3655                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3656                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3657                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3658                         break;
3659                 case OP_FCONV_TO_I1:
3660                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
3661                         break;
3662                 case OP_FCONV_TO_U1:
3663                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
3664                         break;
3665                 case OP_FCONV_TO_I2:
3666                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
3667                         break;
3668                 case OP_FCONV_TO_U2:
3669                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
3670                         break;
3671                 case OP_FCONV_TO_I4:
3672                 case OP_FCONV_TO_I:
3673                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
3674                         break;
3675                 case OP_FCONV_TO_I8:
3676                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3677                         x86_fnstcw_membase(code, X86_ESP, 0);
3678                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
3679                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
3680                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
3681                         x86_fldcw_membase (code, X86_ESP, 2);
3682                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3683                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
3684                         x86_pop_reg (code, ins->dreg);
3685                         x86_pop_reg (code, ins->backend.reg3);
3686                         x86_fldcw_membase (code, X86_ESP, 0);
3687                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3688                         break;
3689                 case OP_LCONV_TO_R8_2:
3690                         x86_push_reg (code, ins->sreg2);
3691                         x86_push_reg (code, ins->sreg1);
3692                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3693                         /* Change precision */
3694                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3695                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3696                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3697                         break;
3698                 case OP_LCONV_TO_R4_2:
3699                         x86_push_reg (code, ins->sreg2);
3700                         x86_push_reg (code, ins->sreg1);
3701                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3702                         /* Change precision */
3703                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3704                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3705                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3706                         break;
3707                 case OP_LCONV_TO_R_UN_2: { 
3708                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
3709                         guint8 *br;
3710
3711                         /* load 64bit integer to FP stack */
3712                         x86_push_reg (code, ins->sreg2);
3713                         x86_push_reg (code, ins->sreg1);
3714                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3715                         
3716                         /* test if lreg is negative */
3717                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3718                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
3719         
3720                         /* add correction constant mn */
3721                         if (cfg->compile_aot) {
3722                                 x86_push_imm (code, (((guint32)mn [9]) << 24) | ((guint32)mn [8] << 16) | ((guint32)mn [7] << 8) | ((guint32)mn [6]));
3723                                 x86_push_imm (code, (((guint32)mn [5]) << 24) | ((guint32)mn [4] << 16) | ((guint32)mn [3] << 8) | ((guint32)mn [2]));
3724                                 x86_push_imm (code, (((guint32)mn [1]) << 24) | ((guint32)mn [0] << 16));
3725                                 x86_fld80_membase (code, X86_ESP, 2);
3726                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
3727                         } else {
3728                                 x86_fld80_mem (code, mn);
3729                         }
3730                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3731
3732                         x86_patch (br, code);
3733
3734                         /* Change precision */
3735                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
3736                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3737
3738                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3739
3740                         break;
3741                 }
3742                 case OP_LCONV_TO_OVF_I:
3743                 case OP_LCONV_TO_OVF_I4_2: {
3744                         guint8 *br [3], *label [1];
3745                         MonoInst *tins;
3746
3747                         /* 
3748                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3749                          */
3750                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
3751
3752                         /* If the low word top bit is set, see if we are negative */
3753                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
3754                         /* We are not negative (no top bit set, check for our top word to be zero */
3755                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3756                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
3757                         label [0] = code;
3758
3759                         /* throw exception */
3760                         tins = mono_branch_optimize_exception_target (cfg, bb, "OverflowException");
3761                         if (tins) {
3762                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, tins->inst_true_bb);
3763                                 if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (tins->inst_true_bb->max_offset - cpos))
3764                                         x86_jump8 (code, 0);
3765                                 else
3766                                         x86_jump32 (code, 0);
3767                         } else {
3768                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
3769                                 x86_jump32 (code, 0);
3770                         }
3771         
3772         
3773                         x86_patch (br [0], code);
3774                         /* our top bit is set, check that top word is 0xfffffff */
3775                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
3776                 
3777                         x86_patch (br [1], code);
3778                         /* nope, emit exception */
3779                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
3780                         x86_patch (br [2], label [0]);
3781
3782                         if (ins->dreg != ins->sreg1)
3783                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3784                         break;
3785                 }
3786                 case OP_FMOVE:
3787                         /* Not needed on the fp stack */
3788                         break;
3789                 case OP_FADD:
3790                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3791                         break;
3792                 case OP_FSUB:
3793                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
3794                         break;          
3795                 case OP_FMUL:
3796                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
3797                         break;          
3798                 case OP_FDIV:
3799                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
3800                         break;          
3801                 case OP_FNEG:
3802                         x86_fchs (code);
3803                         break;          
3804                 case OP_SIN:
3805                         x86_fsin (code);
3806                         x86_fldz (code);
3807                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3808                         break;          
3809                 case OP_COS:
3810                         x86_fcos (code);
3811                         x86_fldz (code);
3812                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3813                         break;          
3814                 case OP_ABS:
3815                         x86_fabs (code);
3816                         break;          
3817                 case OP_TAN: {
3818                         /* 
3819                          * it really doesn't make sense to inline all this code,
3820                          * it's here just to show that things may not be as simple 
3821                          * as they appear.
3822                          */
3823                         guchar *check_pos, *end_tan, *pop_jump;
3824                         x86_push_reg (code, X86_EAX);
3825                         x86_fptan (code);
3826                         x86_fnstsw (code);
3827                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3828                         check_pos = code;
3829                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3830                         x86_fstp (code, 0); /* pop the 1.0 */
3831                         end_tan = code;
3832                         x86_jump8 (code, 0);
3833                         x86_fldpi (code);
3834                         x86_fp_op (code, X86_FADD, 0);
3835                         x86_fxch (code, 1);
3836                         x86_fprem1 (code);
3837                         x86_fstsw (code);
3838                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3839                         pop_jump = code;
3840                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3841                         x86_fstp (code, 1);
3842                         x86_fptan (code);
3843                         x86_patch (pop_jump, code);
3844                         x86_fstp (code, 0); /* pop the 1.0 */
3845                         x86_patch (check_pos, code);
3846                         x86_patch (end_tan, code);
3847                         x86_fldz (code);
3848                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3849                         x86_pop_reg (code, X86_EAX);
3850                         break;
3851                 }
3852                 case OP_ATAN:
3853                         x86_fld1 (code);
3854                         x86_fpatan (code);
3855                         x86_fldz (code);
3856                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3857                         break;          
3858                 case OP_SQRT:
3859                         x86_fsqrt (code);
3860                         break;
3861                 case OP_ROUND:
3862                         x86_frndint (code);
3863                         break;
3864                 case OP_IMIN:
3865                         g_assert (cfg->opt & MONO_OPT_CMOV);
3866                         g_assert (ins->dreg == ins->sreg1);
3867                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3868                         x86_cmov_reg (code, X86_CC_GT, TRUE, ins->dreg, ins->sreg2);
3869                         break;
3870                 case OP_IMIN_UN:
3871                         g_assert (cfg->opt & MONO_OPT_CMOV);
3872                         g_assert (ins->dreg == ins->sreg1);
3873                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3874                         x86_cmov_reg (code, X86_CC_GT, FALSE, ins->dreg, ins->sreg2);
3875                         break;
3876                 case OP_IMAX:
3877                         g_assert (cfg->opt & MONO_OPT_CMOV);
3878                         g_assert (ins->dreg == ins->sreg1);
3879                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3880                         x86_cmov_reg (code, X86_CC_LT, TRUE, ins->dreg, ins->sreg2);
3881                         break;
3882                 case OP_IMAX_UN:
3883                         g_assert (cfg->opt & MONO_OPT_CMOV);
3884                         g_assert (ins->dreg == ins->sreg1);
3885                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3886                         x86_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2);
3887                         break;
3888                 case OP_X86_FPOP:
3889                         x86_fstp (code, 0);
3890                         break;
3891                 case OP_X86_FXCH:
3892                         x86_fxch (code, ins->inst_imm);
3893                         break;
3894                 case OP_FREM: {
3895                         guint8 *l1, *l2;
3896
3897                         x86_push_reg (code, X86_EAX);
3898                         /* we need to exchange ST(0) with ST(1) */
3899                         x86_fxch (code, 1);
3900
3901                         /* this requires a loop, because fprem somtimes 
3902                          * returns a partial remainder */
3903                         l1 = code;
3904                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3905                         /* x86_fprem1 (code); */
3906                         x86_fprem (code);
3907                         x86_fnstsw (code);
3908                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3909                         l2 = code;
3910                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3911                         x86_patch (l2, l1);
3912
3913                         /* pop result */
3914                         x86_fstp (code, 1);
3915
3916                         x86_pop_reg (code, X86_EAX);
3917                         break;
3918                 }
3919                 case OP_FCOMPARE:
3920                         if (cfg->opt & MONO_OPT_FCMOV) {
3921                                 x86_fcomip (code, 1);
3922                                 x86_fstp (code, 0);
3923                                 break;
3924                         }
3925                         /* this overwrites EAX */
3926                         EMIT_FPCOMPARE(code);
3927                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3928                         break;
3929                 case OP_FCEQ:
3930                         if (cfg->opt & MONO_OPT_FCMOV) {
3931                                 /* zeroing the register at the start results in 
3932                                  * shorter and faster code (we can also remove the widening op)
3933                                  */
3934                                 guchar *unordered_check;
3935                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3936                                 x86_fcomip (code, 1);
3937                                 x86_fstp (code, 0);
3938                                 unordered_check = code;
3939                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3940                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3941                                 x86_patch (unordered_check, code);
3942                                 break;
3943                         }
3944                         if (ins->dreg != X86_EAX) 
3945                                 x86_push_reg (code, X86_EAX);
3946
3947                         EMIT_FPCOMPARE(code);
3948                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3949                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3950                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3951                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3952
3953                         if (ins->dreg != X86_EAX) 
3954                                 x86_pop_reg (code, X86_EAX);
3955                         break;
3956                 case OP_FCLT:
3957                 case OP_FCLT_UN:
3958                         if (cfg->opt & MONO_OPT_FCMOV) {
3959                                 /* zeroing the register at the start results in 
3960                                  * shorter and faster code (we can also remove the widening op)
3961                                  */
3962                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3963                                 x86_fcomip (code, 1);
3964                                 x86_fstp (code, 0);
3965                                 if (ins->opcode == OP_FCLT_UN) {
3966                                         guchar *unordered_check = code;
3967                                         guchar *jump_to_end;
3968                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3969                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3970                                         jump_to_end = code;
3971                                         x86_jump8 (code, 0);
3972                                         x86_patch (unordered_check, code);
3973                                         x86_inc_reg (code, ins->dreg);
3974                                         x86_patch (jump_to_end, code);
3975                                 } else {
3976                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3977                                 }
3978                                 break;
3979                         }
3980                         if (ins->dreg != X86_EAX) 
3981                                 x86_push_reg (code, X86_EAX);
3982
3983                         EMIT_FPCOMPARE(code);
3984                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3985                         if (ins->opcode == OP_FCLT_UN) {
3986                                 guchar *is_not_zero_check, *end_jump;
3987                                 is_not_zero_check = code;
3988                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3989                                 end_jump = code;
3990                                 x86_jump8 (code, 0);
3991                                 x86_patch (is_not_zero_check, code);
3992                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3993
3994                                 x86_patch (end_jump, code);
3995                         }
3996                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3997                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3998
3999                         if (ins->dreg != X86_EAX) 
4000                                 x86_pop_reg (code, X86_EAX);
4001                         break;
4002                 case OP_FCGT:
4003                 case OP_FCGT_UN:
4004                         if (cfg->opt & MONO_OPT_FCMOV) {
4005                                 /* zeroing the register at the start results in 
4006                                  * shorter and faster code (we can also remove the widening op)
4007                                  */
4008                                 guchar *unordered_check;
4009                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
4010                                 x86_fcomip (code, 1);
4011                                 x86_fstp (code, 0);
4012                                 if (ins->opcode == OP_FCGT) {
4013                                         unordered_check = code;
4014                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
4015                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
4016                                         x86_patch (unordered_check, code);
4017                                 } else {
4018                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
4019                                 }
4020                                 break;
4021                         }
4022                         if (ins->dreg != X86_EAX) 
4023                                 x86_push_reg (code, X86_EAX);
4024
4025                         EMIT_FPCOMPARE(code);
4026                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
4027                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4028                         if (ins->opcode == OP_FCGT_UN) {
4029                                 guchar *is_not_zero_check, *end_jump;
4030                                 is_not_zero_check = code;
4031                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
4032                                 end_jump = code;
4033                                 x86_jump8 (code, 0);
4034                                 x86_patch (is_not_zero_check, code);
4035                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
4036         
4037                                 x86_patch (end_jump, code);
4038                         }
4039                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
4040                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4041
4042                         if (ins->dreg != X86_EAX) 
4043                                 x86_pop_reg (code, X86_EAX);
4044                         break;
4045                 case OP_FBEQ:
4046                         if (cfg->opt & MONO_OPT_FCMOV) {
4047                                 guchar *jump = code;
4048                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
4049                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4050                                 x86_patch (jump, code);
4051                                 break;
4052                         }
4053                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
4054                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
4055                         break;
4056                 case OP_FBNE_UN:
4057                         /* Branch if C013 != 100 */
4058                         if (cfg->opt & MONO_OPT_FCMOV) {
4059                                 /* branch if !ZF or (PF|CF) */
4060                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4061                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
4062                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
4063                                 break;
4064                         }
4065                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
4066                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4067                         break;
4068                 case OP_FBLT:
4069                         if (cfg->opt & MONO_OPT_FCMOV) {
4070                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
4071                                 break;
4072                         }
4073                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4074                         break;
4075                 case OP_FBLT_UN:
4076                         if (cfg->opt & MONO_OPT_FCMOV) {
4077                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
4078                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
4079                                 break;
4080                         }
4081                         if (ins->opcode == OP_FBLT_UN) {
4082                                 guchar *is_not_zero_check, *end_jump;
4083                                 is_not_zero_check = code;
4084                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
4085                                 end_jump = code;
4086                                 x86_jump8 (code, 0);
4087                                 x86_patch (is_not_zero_check, code);
4088                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
4089
4090                                 x86_patch (end_jump, code);
4091                         }
4092                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4093                         break;
4094                 case OP_FBGT:
4095                 case OP_FBGT_UN:
4096                         if (cfg->opt & MONO_OPT_FCMOV) {
4097                                 if (ins->opcode == OP_FBGT) {
4098                                         guchar *br1;
4099
4100                                         /* skip branch if C1=1 */
4101                                         br1 = code;
4102                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
4103                                         /* branch if (C0 | C3) = 1 */
4104                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
4105                                         x86_patch (br1, code);
4106                                 } else {
4107                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
4108                                 }
4109                                 break;
4110                         }
4111                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4112                         if (ins->opcode == OP_FBGT_UN) {
4113                                 guchar *is_not_zero_check, *end_jump;
4114                                 is_not_zero_check = code;
4115                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
4116                                 end_jump = code;
4117                                 x86_jump8 (code, 0);
4118                                 x86_patch (is_not_zero_check, code);
4119                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
4120
4121                                 x86_patch (end_jump, code);
4122                         }
4123                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4124                         break;
4125                 case OP_FBGE:
4126                         /* Branch if C013 == 100 or 001 */
4127                         if (cfg->opt & MONO_OPT_FCMOV) {
4128                                 guchar *br1;
4129
4130                                 /* skip branch if C1=1 */
4131                                 br1 = code;
4132                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
4133                                 /* branch if (C0 | C3) = 1 */
4134                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
4135                                 x86_patch (br1, code);
4136                                 break;
4137                         }
4138                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4139                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4140                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
4141                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4142                         break;
4143                 case OP_FBGE_UN:
4144                         /* Branch if C013 == 000 */
4145                         if (cfg->opt & MONO_OPT_FCMOV) {
4146                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
4147                                 break;
4148                         }
4149                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4150                         break;
4151                 case OP_FBLE:
4152                         /* Branch if C013=000 or 100 */
4153                         if (cfg->opt & MONO_OPT_FCMOV) {
4154                                 guchar *br1;
4155
4156                                 /* skip branch if C1=1 */
4157                                 br1 = code;
4158                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
4159                                 /* branch if C0=0 */
4160                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
4161                                 x86_patch (br1, code);
4162                                 break;
4163                         }
4164                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
4165                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
4166                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
4167                         break;
4168                 case OP_FBLE_UN:
4169                         /* Branch if C013 != 001 */
4170                         if (cfg->opt & MONO_OPT_FCMOV) {
4171                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
4172                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
4173                                 break;
4174                         }
4175                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4176                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
4177                         break;
4178                 case OP_CKFINITE: {
4179                         guchar *br1;
4180                         x86_push_reg (code, X86_EAX);
4181                         x86_fxam (code);
4182                         x86_fnstsw (code);
4183                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
4184                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
4185                         x86_pop_reg (code, X86_EAX);
4186
4187                         /* Have to clean up the fp stack before throwing the exception */
4188                         br1 = code;
4189                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
4190
4191                         x86_fstp (code, 0);                     
4192                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
4193
4194                         x86_patch (br1, code);
4195                         break;
4196                 }
4197                 case OP_TLS_GET: {
4198                         code = mono_x86_emit_tls_get (code, ins->dreg, ins->inst_offset);
4199                         break;
4200                 }
4201                 case OP_MEMORY_BARRIER: {
4202                         /* x86 only needs barrier for StoreLoad and FullBarrier */
4203                         switch (ins->backend.memory_barrier_kind) {
4204                         case StoreLoadBarrier:
4205                         case FullBarrier:
4206                                 /* http://blogs.sun.com/dave/resource/NHM-Pipeline-Blog-V2.txt */
4207                                 x86_prefix (code, X86_LOCK_PREFIX);
4208                                 x86_alu_membase_imm (code, X86_ADD, X86_ESP, 0, 0);
4209                                 break;
4210                         }
4211                         break;
4212                 }
4213                 case OP_ATOMIC_ADD_I4: {
4214                         int dreg = ins->dreg;
4215
4216                         if (dreg == ins->inst_basereg) {
4217                                 x86_push_reg (code, ins->sreg2);
4218                                 dreg = ins->sreg2;
4219                         } 
4220                         
4221                         if (dreg != ins->sreg2)
4222                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
4223
4224                         x86_prefix (code, X86_LOCK_PREFIX);
4225                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
4226
4227                         if (dreg != ins->dreg) {
4228                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
4229                                 x86_pop_reg (code, dreg);
4230                         }
4231
4232                         break;
4233                 }
4234                 case OP_ATOMIC_ADD_NEW_I4: {
4235                         int dreg = ins->dreg;
4236
4237                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
4238                         if (ins->sreg2 == dreg) {
4239                                 if (dreg == X86_EBX) {
4240                                         dreg = X86_EDI;
4241                                         if (ins->inst_basereg == X86_EDI)
4242                                                 dreg = X86_ESI;
4243                                 } else {
4244                                         dreg = X86_EBX;
4245                                         if (ins->inst_basereg == X86_EBX)
4246                                                 dreg = X86_EDI;
4247                                 }
4248                         } else if (ins->inst_basereg == dreg) {
4249                                 if (dreg == X86_EBX) {
4250                                         dreg = X86_EDI;
4251                                         if (ins->sreg2 == X86_EDI)
4252                                                 dreg = X86_ESI;
4253                                 } else {
4254                                         dreg = X86_EBX;
4255                                         if (ins->sreg2 == X86_EBX)
4256                                                 dreg = X86_EDI;
4257                                 }
4258                         }
4259
4260                         if (dreg != ins->dreg) {
4261                                 x86_push_reg (code, dreg);
4262                         }
4263
4264                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
4265                         x86_prefix (code, X86_LOCK_PREFIX);
4266                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
4267                         /* dreg contains the old value, add with sreg2 value */
4268                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
4269                         
4270                         if (ins->dreg != dreg) {
4271                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
4272                                 x86_pop_reg (code, dreg);
4273                         }
4274
4275                         break;
4276                 }
4277                 case OP_ATOMIC_EXCHANGE_I4: {
4278                         guchar *br[2];
4279                         int sreg2 = ins->sreg2;
4280                         int breg = ins->inst_basereg;
4281
4282                         /* cmpxchg uses eax as comperand, need to make sure we can use it
4283                          * hack to overcome limits in x86 reg allocator 
4284                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
4285                          */
4286                         g_assert (ins->dreg == X86_EAX);
4287                         
4288                         /* We need the EAX reg for the cmpxchg */
4289                         if (ins->sreg2 == X86_EAX) {
4290                                 sreg2 = (breg == X86_EDX) ? X86_EBX : X86_EDX;
4291                                 x86_push_reg (code, sreg2);
4292                                 x86_mov_reg_reg (code, sreg2, X86_EAX, 4);
4293                         }
4294
4295                         if (breg == X86_EAX) {
4296                                 breg = (sreg2 == X86_ESI) ? X86_EDI : X86_ESI;
4297                                 x86_push_reg (code, breg);
4298                                 x86_mov_reg_reg (code, breg, X86_EAX, 4);
4299                         }
4300
4301                         x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
4302
4303                         br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
4304                         x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
4305                         br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
4306                         x86_patch (br [1], br [0]);
4307
4308                         if (breg != ins->inst_basereg)
4309                                 x86_pop_reg (code, breg);
4310
4311                         if (ins->sreg2 != sreg2)
4312                                 x86_pop_reg (code, sreg2);
4313
4314                         break;
4315                 }
4316                 case OP_ATOMIC_CAS_I4: {
4317                         g_assert (ins->dreg == X86_EAX);
4318                         g_assert (ins->sreg3 == X86_EAX);
4319                         g_assert (ins->sreg1 != X86_EAX);
4320                         g_assert (ins->sreg1 != ins->sreg2);
4321
4322                         x86_prefix (code, X86_LOCK_PREFIX);
4323                         x86_cmpxchg_membase_reg (code, ins->sreg1, ins->inst_offset, ins->sreg2);
4324                         break;
4325                 }
4326                 case OP_CARD_TABLE_WBARRIER: {
4327                         int ptr = ins->sreg1;
4328                         int value = ins->sreg2;
4329                         guchar *br;
4330                         int nursery_shift, card_table_shift;
4331                         gpointer card_table_mask;
4332                         size_t nursery_size;
4333                         gulong card_table = (gulong)mono_gc_get_card_table (&card_table_shift, &card_table_mask);
4334                         gulong nursery_start = (gulong)mono_gc_get_nursery (&nursery_shift, &nursery_size);
4335                         gboolean card_table_nursery_check = mono_gc_card_table_nursery_check ();
4336
4337                         /*
4338                          * We need one register we can clobber, we choose EDX and make sreg1
4339                          * fixed EAX to work around limitations in the local register allocator.
4340                          * sreg2 might get allocated to EDX, but that is not a problem since
4341                          * we use it before clobbering EDX.
4342                          */
4343                         g_assert (ins->sreg1 == X86_EAX);
4344
4345                         /*
4346                          * This is the code we produce:
4347                          *
4348                          *   edx = value
4349                          *   edx >>= nursery_shift
4350                          *   cmp edx, (nursery_start >> nursery_shift)
4351                          *   jne done
4352                          *   edx = ptr
4353                          *   edx >>= card_table_shift
4354                          *   card_table[edx] = 1
4355                          * done:
4356                          */
4357
4358                         if (card_table_nursery_check) {
4359                                 if (value != X86_EDX)
4360                                         x86_mov_reg_reg (code, X86_EDX, value, 4);
4361                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, nursery_shift);
4362                                 x86_alu_reg_imm (code, X86_CMP, X86_EDX, nursery_start >> nursery_shift);
4363                                 br = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
4364                         }
4365                         x86_mov_reg_reg (code, X86_EDX, ptr, 4);
4366                         x86_shift_reg_imm (code, X86_SHR, X86_EDX, card_table_shift);
4367                         if (card_table_mask)
4368                                 x86_alu_reg_imm (code, X86_AND, X86_EDX, (int)card_table_mask);
4369                         x86_mov_membase_imm (code, X86_EDX, card_table, 1, 1);
4370                         if (card_table_nursery_check)
4371                                 x86_patch (br, code);
4372                         break;
4373                 }
4374 #ifdef MONO_ARCH_SIMD_INTRINSICS
4375                 case OP_ADDPS:
4376                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4377                         break;
4378                 case OP_DIVPS:
4379                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4380                         break;
4381                 case OP_MULPS:
4382                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4383                         break;
4384                 case OP_SUBPS:
4385                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4386                         break;
4387                 case OP_MAXPS:
4388                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4389                         break;
4390                 case OP_MINPS:
4391                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4392                         break;
4393                 case OP_COMPPS:
4394                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4395                         x86_sse_alu_ps_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4396                         break;
4397                 case OP_ANDPS:
4398                         x86_sse_alu_ps_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4399                         break;
4400                 case OP_ANDNPS:
4401                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4402                         break;
4403                 case OP_ORPS:
4404                         x86_sse_alu_ps_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4405                         break;
4406                 case OP_XORPS:
4407                         x86_sse_alu_ps_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4408                         break;
4409                 case OP_SQRTPS:
4410                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4411                         break;
4412                 case OP_RSQRTPS:
4413                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
4414                         break;
4415                 case OP_RCPPS:
4416                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RCP, ins->dreg, ins->sreg1);
4417                         break;
4418                 case OP_ADDSUBPS:
4419                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4420                         break;
4421                 case OP_HADDPS:
4422                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4423                         break;
4424                 case OP_HSUBPS:
4425                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4426                         break;
4427                 case OP_DUPPS_HIGH:
4428                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSHDUP, ins->dreg, ins->sreg1);
4429                         break;
4430                 case OP_DUPPS_LOW:
4431                         x86_sse_alu_ss_reg_reg (code, X86_SSE_MOVSLDUP, ins->dreg, ins->sreg1);
4432                         break;
4433
4434                 case OP_PSHUFLEW_HIGH:
4435                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4436                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 1);
4437                         break;
4438                 case OP_PSHUFLEW_LOW:
4439                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4440                         x86_pshufw_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0, 0);
4441                         break;
4442                 case OP_PSHUFLED:
4443                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4444                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->sreg1, ins->inst_c0);
4445                         break;
4446                 case OP_SHUFPS:
4447                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
4448                         x86_sse_alu_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0);
4449                         break; 
4450                 case OP_SHUFPD:
4451                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0x3);
4452                         x86_sse_alu_pd_reg_reg_imm8 (code, X86_SSE_SHUFP, ins->sreg1, ins->sreg2, ins->inst_c0);
4453                         break; 
4454
4455                 case OP_ADDPD:
4456                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
4457                         break;
4458                 case OP_DIVPD:
4459                         x86_sse_alu_pd_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
4460                         break;
4461                 case OP_MULPD:
4462                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
4463                         break;
4464                 case OP_SUBPD:
4465                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
4466                         break;
4467                 case OP_MAXPD:
4468                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
4469                         break;
4470                 case OP_MINPD:
4471                         x86_sse_alu_pd_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
4472                         break;
4473                 case OP_COMPPD:
4474                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 7);
4475                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_COMP, ins->sreg1, ins->sreg2, ins->inst_c0);
4476                         break;
4477                 case OP_ANDPD:
4478                         x86_sse_alu_pd_reg_reg (code, X86_SSE_AND, ins->sreg1, ins->sreg2);
4479                         break;
4480                 case OP_ANDNPD:
4481                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ANDN, ins->sreg1, ins->sreg2);
4482                         break;
4483                 case OP_ORPD:
4484                         x86_sse_alu_pd_reg_reg (code, X86_SSE_OR, ins->sreg1, ins->sreg2);
4485                         break;
4486                 case OP_XORPD:
4487                         x86_sse_alu_pd_reg_reg (code, X86_SSE_XOR, ins->sreg1, ins->sreg2);
4488                         break;
4489                 case OP_SQRTPD:
4490                         x86_sse_alu_pd_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
4491                         break;
4492                 case OP_ADDSUBPD:
4493                         x86_sse_alu_pd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
4494                         break;
4495                 case OP_HADDPD:
4496                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
4497                         break;
4498                 case OP_HSUBPD:
4499                         x86_sse_alu_pd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
4500                         break;
4501                 case OP_DUPPD:
4502                         x86_sse_alu_sd_reg_reg (code, X86_SSE_MOVDDUP, ins->dreg, ins->sreg1);
4503                         break;
4504                         
4505                 case OP_EXTRACT_MASK:
4506                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMOVMSKB, ins->dreg, ins->sreg1);
4507                         break;
4508         
4509                 case OP_PAND:
4510                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
4511                         break;
4512                 case OP_POR:
4513                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
4514                         break;
4515                 case OP_PXOR:
4516                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
4517                         break;
4518
4519                 case OP_PADDB:
4520                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDB, ins->sreg1, ins->sreg2);
4521                         break;
4522                 case OP_PADDW:
4523                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDW, ins->sreg1, ins->sreg2);
4524                         break;
4525                 case OP_PADDD:
4526                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDD, ins->sreg1, ins->sreg2);
4527                         break;
4528                 case OP_PADDQ:
4529                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDQ, ins->sreg1, ins->sreg2);
4530                         break;
4531
4532                 case OP_PSUBB:
4533                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBB, ins->sreg1, ins->sreg2);
4534                         break;
4535                 case OP_PSUBW:
4536                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBW, ins->sreg1, ins->sreg2);
4537                         break;
4538                 case OP_PSUBD:
4539                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBD, ins->sreg1, ins->sreg2);
4540                         break;
4541                 case OP_PSUBQ:
4542                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBQ, ins->sreg1, ins->sreg2);
4543                         break;
4544
4545                 case OP_PMAXB_UN:
4546                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXUB, ins->sreg1, ins->sreg2);
4547                         break;
4548                 case OP_PMAXW_UN:
4549                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUW, ins->sreg1, ins->sreg2);
4550                         break;
4551                 case OP_PMAXD_UN:
4552                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXUD, ins->sreg1, ins->sreg2);
4553                         break;
4554                 
4555                 case OP_PMAXB:
4556                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSB, ins->sreg1, ins->sreg2);
4557                         break;
4558                 case OP_PMAXW:
4559                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMAXSW, ins->sreg1, ins->sreg2);
4560                         break;
4561                 case OP_PMAXD:
4562                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMAXSD, ins->sreg1, ins->sreg2);
4563                         break;
4564
4565                 case OP_PAVGB_UN:
4566                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGB, ins->sreg1, ins->sreg2);
4567                         break;
4568                 case OP_PAVGW_UN:
4569                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAVGW, ins->sreg1, ins->sreg2);
4570                         break;
4571
4572                 case OP_PMINB_UN:
4573                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINUB, ins->sreg1, ins->sreg2);
4574                         break;
4575                 case OP_PMINW_UN:
4576                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUW, ins->sreg1, ins->sreg2);
4577                         break;
4578                 case OP_PMIND_UN:
4579                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINUD, ins->sreg1, ins->sreg2);
4580                         break;
4581
4582                 case OP_PMINB:
4583                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSB, ins->sreg1, ins->sreg2);
4584                         break;
4585                 case OP_PMINW:
4586                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMINSW, ins->sreg1, ins->sreg2);
4587                         break;
4588                 case OP_PMIND:
4589                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMINSD, ins->sreg1, ins->sreg2);
4590                         break;
4591
4592                 case OP_PCMPEQB:
4593                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQB, ins->sreg1, ins->sreg2);
4594                         break;
4595                 case OP_PCMPEQW:
4596                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQW, ins->sreg1, ins->sreg2);
4597                         break;
4598                 case OP_PCMPEQD:
4599                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPEQD, ins->sreg1, ins->sreg2);
4600                         break;
4601                 case OP_PCMPEQQ:
4602                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPEQQ, ins->sreg1, ins->sreg2);
4603                         break;
4604
4605                 case OP_PCMPGTB:
4606                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTB, ins->sreg1, ins->sreg2);
4607                         break;
4608                 case OP_PCMPGTW:
4609                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTW, ins->sreg1, ins->sreg2);
4610                         break;
4611                 case OP_PCMPGTD:
4612                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PCMPGTD, ins->sreg1, ins->sreg2);
4613                         break;
4614                 case OP_PCMPGTQ:
4615                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PCMPGTQ, ins->sreg1, ins->sreg2);
4616                         break;
4617
4618                 case OP_PSUM_ABS_DIFF:
4619                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSADBW, ins->sreg1, ins->sreg2);
4620                         break;
4621
4622                 case OP_UNPACK_LOWB:
4623                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLBW, ins->sreg1, ins->sreg2);
4624                         break;
4625                 case OP_UNPACK_LOWW:
4626                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLWD, ins->sreg1, ins->sreg2);
4627                         break;
4628                 case OP_UNPACK_LOWD:
4629                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLDQ, ins->sreg1, ins->sreg2);
4630                         break;
4631                 case OP_UNPACK_LOWQ:
4632                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKLQDQ, ins->sreg1, ins->sreg2);
4633                         break;
4634                 case OP_UNPACK_LOWPS:
4635                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4636                         break;
4637                 case OP_UNPACK_LOWPD:
4638                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKL, ins->sreg1, ins->sreg2);
4639                         break;
4640
4641                 case OP_UNPACK_HIGHB:
4642                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHBW, ins->sreg1, ins->sreg2);
4643                         break;
4644                 case OP_UNPACK_HIGHW:
4645                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHWD, ins->sreg1, ins->sreg2);
4646                         break;
4647                 case OP_UNPACK_HIGHD:
4648                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHDQ, ins->sreg1, ins->sreg2);
4649                         break;
4650                 case OP_UNPACK_HIGHQ:
4651                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PUNPCKHQDQ, ins->sreg1, ins->sreg2);
4652                         break;
4653                 case OP_UNPACK_HIGHPS:
4654                         x86_sse_alu_ps_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4655                         break;
4656                 case OP_UNPACK_HIGHPD:
4657                         x86_sse_alu_pd_reg_reg (code, X86_SSE_UNPCKH, ins->sreg1, ins->sreg2);
4658                         break;
4659
4660                 case OP_PACKW:
4661                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSWB, ins->sreg1, ins->sreg2);
4662                         break;
4663                 case OP_PACKD:
4664                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKSSDW, ins->sreg1, ins->sreg2);
4665                         break;
4666                 case OP_PACKW_UN:
4667                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PACKUSWB, ins->sreg1, ins->sreg2);
4668                         break;
4669                 case OP_PACKD_UN:
4670                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PACKUSDW, ins->sreg1, ins->sreg2);
4671                         break;
4672
4673                 case OP_PADDB_SAT_UN:
4674                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSB, ins->sreg1, ins->sreg2);
4675                         break;
4676                 case OP_PSUBB_SAT_UN:
4677                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSB, ins->sreg1, ins->sreg2);
4678                         break;
4679                 case OP_PADDW_SAT_UN:
4680                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDUSW, ins->sreg1, ins->sreg2);
4681                         break;
4682                 case OP_PSUBW_SAT_UN:
4683                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBUSW, ins->sreg1, ins->sreg2);
4684                         break;
4685
4686                 case OP_PADDB_SAT:
4687                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSB, ins->sreg1, ins->sreg2);
4688                         break;
4689                 case OP_PSUBB_SAT:
4690                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSB, ins->sreg1, ins->sreg2);
4691                         break;
4692                 case OP_PADDW_SAT:
4693                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PADDSW, ins->sreg1, ins->sreg2);
4694                         break;
4695                 case OP_PSUBW_SAT:
4696                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PSUBSW, ins->sreg1, ins->sreg2);
4697                         break;
4698                         
4699                 case OP_PMULW:
4700                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULLW, ins->sreg1, ins->sreg2);
4701                         break;
4702                 case OP_PMULD:
4703                         x86_sse_alu_sse41_reg_reg (code, X86_SSE_PMULLD, ins->sreg1, ins->sreg2);
4704                         break;
4705                 case OP_PMULQ:
4706                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULUDQ, ins->sreg1, ins->sreg2);
4707                         break;
4708                 case OP_PMULW_HIGH_UN:
4709                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHUW, ins->sreg1, ins->sreg2);
4710                         break;
4711                 case OP_PMULW_HIGH:
4712                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PMULHW, ins->sreg1, ins->sreg2);
4713                         break;
4714
4715                 case OP_PSHRW:
4716                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4717                         break;
4718                 case OP_PSHRW_REG:
4719                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLW_REG, ins->dreg, ins->sreg2);
4720                         break;
4721
4722                 case OP_PSARW:
4723                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4724                         break;
4725                 case OP_PSARW_REG:
4726                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAW_REG, ins->dreg, ins->sreg2);
4727                         break;
4728
4729                 case OP_PSHLW:
4730                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTW, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4731                         break;
4732                 case OP_PSHLW_REG:
4733                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLW_REG, ins->dreg, ins->sreg2);
4734                         break;
4735
4736                 case OP_PSHRD:
4737                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4738                         break;
4739                 case OP_PSHRD_REG:
4740                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLD_REG, ins->dreg, ins->sreg2);
4741                         break;
4742
4743                 case OP_PSARD:
4744                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SAR, ins->dreg, ins->inst_imm);
4745                         break;
4746                 case OP_PSARD_REG:
4747                         x86_sse_shift_reg_reg (code, X86_SSE_PSRAD_REG, ins->dreg, ins->sreg2);
4748                         break;
4749
4750                 case OP_PSHLD:
4751                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTD, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4752                         break;
4753                 case OP_PSHLD_REG:
4754                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLD_REG, ins->dreg, ins->sreg2);
4755                         break;
4756
4757                 case OP_PSHRQ:
4758                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHR, ins->dreg, ins->inst_imm);
4759                         break;
4760                 case OP_PSHRQ_REG:
4761                         x86_sse_shift_reg_reg (code, X86_SSE_PSRLQ_REG, ins->dreg, ins->sreg2);
4762                         break;
4763
4764                 case OP_PSHLQ:
4765                         x86_sse_shift_reg_imm (code, X86_SSE_PSHIFTQ, X86_SSE_SHL, ins->dreg, ins->inst_imm);
4766                         break;
4767                 case OP_PSHLQ_REG:
4768                         x86_sse_shift_reg_reg (code, X86_SSE_PSLLQ_REG, ins->dreg, ins->sreg2);
4769                         break;          
4770                         
4771                 case OP_ICONV_TO_X:
4772                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4773                         break;
4774                 case OP_EXTRACT_I4:
4775                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4776                         break;
4777                 case OP_EXTRACT_I1:
4778                 case OP_EXTRACT_U1:
4779                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4780                         if (ins->inst_c0)
4781                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_c0 * 8);
4782                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I1, FALSE);
4783                         break;
4784                 case OP_EXTRACT_I2:
4785                 case OP_EXTRACT_U2:
4786                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
4787                         if (ins->inst_c0)
4788                                 x86_shift_reg_imm (code, X86_SHR, ins->dreg, 16);
4789                         x86_widen_reg (code, ins->dreg, ins->dreg, ins->opcode == OP_EXTRACT_I2, TRUE);
4790                         break;
4791                 case OP_EXTRACT_R8:
4792                         if (ins->inst_c0)
4793                                 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);
4794                         else
4795                                 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);
4796                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE);
4797                         break;
4798
4799                 case OP_INSERT_I2:
4800                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->sreg1, ins->sreg2, ins->inst_c0);
4801                         break;
4802                 case OP_EXTRACTX_U2:
4803                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PEXTRW, ins->dreg, ins->sreg1, ins->inst_c0);
4804                         break;
4805                 case OP_INSERTX_U1_SLOW:
4806                         /*sreg1 is the extracted ireg (scratch)
4807                         /sreg2 is the to be inserted ireg (scratch)
4808                         /dreg is the xreg to receive the value*/
4809
4810                         /*clear the bits from the extracted word*/
4811                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_c0 & 1 ? 0x00FF : 0xFF00);
4812                         /*shift the value to insert if needed*/
4813                         if (ins->inst_c0 & 1)
4814                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg2, 8);
4815                         /*join them together*/
4816                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
4817                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, ins->inst_c0 / 2);
4818                         break;
4819                 case OP_INSERTX_I4_SLOW:
4820                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2);
4821                         x86_shift_reg_imm (code, X86_SHR, ins->sreg2, 16);
4822                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg2, ins->inst_c0 * 2 + 1);
4823                         break;
4824
4825                 case OP_INSERTX_R4_SLOW:
4826                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4827                         /*TODO if inst_c0 == 0 use movss*/
4828                         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);
4829                         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);
4830                         break;
4831                 case OP_INSERTX_R8_SLOW:
4832                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4833                         if (cfg->verbose_level)
4834                                 printf ("CONVERTING a OP_INSERTX_R8_SLOW %d offset %x\n", ins->inst_c0, offset);
4835                         if (ins->inst_c0)
4836                                 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);
4837                         else
4838                                 x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4839                         break;
4840
4841                 case OP_STOREX_MEMBASE_REG:
4842                 case OP_STOREX_MEMBASE:
4843                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4844                         break;
4845                 case OP_LOADX_MEMBASE:
4846                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4847                         break;
4848                 case OP_LOADX_ALIGNED_MEMBASE:
4849                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
4850                         break;
4851                 case OP_STOREX_ALIGNED_MEMBASE_REG:
4852                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
4853                         break;
4854                 case OP_STOREX_NTA_MEMBASE_REG:
4855                         x86_sse_alu_reg_membase (code, X86_SSE_MOVNTPS, ins->dreg, ins->sreg1, ins->inst_offset);
4856                         break;
4857                 case OP_PREFETCH_MEMBASE:
4858                         x86_sse_alu_reg_membase (code, X86_SSE_PREFETCH, ins->backend.arg_info, ins->sreg1, ins->inst_offset);
4859
4860                         break;
4861                 case OP_XMOVE:
4862                         /*FIXME the peephole pass should have killed this*/
4863                         if (ins->dreg != ins->sreg1)
4864                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
4865                         break;          
4866                 case OP_XZERO:
4867                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
4868                         break;
4869                 case OP_ICONV_TO_R8_RAW:
4870                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
4871                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
4872                         break;
4873
4874                 case OP_FCONV_TO_R8_X:
4875                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4876                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4877                         break;
4878
4879                 case OP_XCONV_R8_TO_I4:
4880                         x86_cvttsd2si (code, ins->dreg, ins->sreg1);
4881                         switch (ins->backend.source_opcode) {
4882                         case OP_FCONV_TO_I1:
4883                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, FALSE);
4884                                 break;
4885                         case OP_FCONV_TO_U1:
4886                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
4887                                 break;
4888                         case OP_FCONV_TO_I2:
4889                                 x86_widen_reg (code, ins->dreg, ins->dreg, TRUE, TRUE);
4890                                 break;
4891                         case OP_FCONV_TO_U2:
4892                                 x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, TRUE);
4893                                 break;
4894                         }                       
4895                         break;
4896
4897                 case OP_EXPAND_I1:
4898                         /*FIXME this causes a partial register stall, maybe it would not be that bad to use shift + mask + or*/
4899                         /*The +4 is to get a mov ?h, ?l over the same reg.*/
4900                         x86_mov_reg_reg (code, ins->dreg + 4, ins->dreg, 1);
4901                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4902                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4903                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4904                         break;
4905                 case OP_EXPAND_I2:
4906                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 0);
4907                         x86_sse_alu_pd_reg_reg_imm (code, X86_SSE_PINSRW, ins->dreg, ins->sreg1, 1);
4908                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4909                         break;
4910                 case OP_EXPAND_I4:
4911                         x86_movd_xreg_reg (code, ins->dreg, ins->sreg1);
4912                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4913                         break;
4914                 case OP_EXPAND_R4:
4915                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE, TRUE);
4916                         x86_movd_xreg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4917                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0);
4918                         break;
4919                 case OP_EXPAND_R8:
4920                         x86_fst_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, TRUE, TRUE);
4921                         x86_movsd_reg_membase (code, ins->dreg, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset);
4922                         x86_sse_shift_reg_imm (code, X86_SSE_PSHUFD, ins->dreg, ins->dreg, 0x44);
4923                         break;
4924
4925                 case OP_CVTDQ2PD:
4926                         x86_sse_alu_ss_reg_reg (code, X86_SSE_CVTDQ2PD, ins->dreg, ins->sreg1);
4927                         break;
4928                 case OP_CVTDQ2PS:
4929                         x86_sse_alu_ps_reg_reg (code, X86_SSE_CVTDQ2PS, ins->dreg, ins->sreg1);
4930                         break;
4931                 case OP_CVTPD2DQ:
4932                         x86_sse_alu_sd_reg_reg (code, X86_SSE_CVTPD2DQ, ins->dreg, ins->sreg1);
4933                         break;
4934                 case OP_CVTPD2PS:
4935                         x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTPD2PS, ins->dreg, ins->sreg1);
4936                         break;
4937                 case OP_CVTPS2DQ:
4938                         x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTPS2DQ, ins->dreg, ins->sreg1);
4939                         break;
4940                 case OP_CVTPS2PD:
4941                         x86_sse_alu_ps_reg_reg (code, X86_SSE_CVTPS2PD, ins->dreg, ins->sreg1);
4942                         break;
4943                 case OP_CVTTPD2DQ:
4944                         x86_sse_alu_pd_reg_reg (code, X86_SSE_CVTTPD2DQ, ins->dreg, ins->sreg1);
4945                         break;
4946                 case OP_CVTTPS2DQ:
4947                         x86_sse_alu_ss_reg_reg (code, X86_SSE_CVTTPS2DQ, ins->dreg, ins->sreg1);
4948                         break;
4949
4950 #endif
4951                 case OP_LIVERANGE_START: {
4952                         if (cfg->verbose_level > 1)
4953                                 printf ("R%d START=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4954                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_start = code - cfg->native_code;
4955                         break;
4956                 }
4957                 case OP_LIVERANGE_END: {
4958                         if (cfg->verbose_level > 1)
4959                                 printf ("R%d END=0x%x\n", MONO_VARINFO (cfg, ins->inst_c0)->vreg, (int)(code - cfg->native_code));
4960                         MONO_VARINFO (cfg, ins->inst_c0)->live_range_end = code - cfg->native_code;
4961                         break;
4962                 }
4963                 case OP_NACL_GC_SAFE_POINT: {
4964 #if defined(__native_client_codegen__) && defined(__native_client_gc__)
4965                         if (cfg->compile_aot)
4966                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc);
4967                         else {
4968                                 guint8 *br [1];
4969
4970                                 x86_test_mem_imm8 (code, (gpointer)&__nacl_thread_suspension_needed, 0xFFFFFFFF);
4971                                 br[0] = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
4972                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, (gpointer)mono_nacl_gc);
4973                                 x86_patch (br[0], code);
4974                         }
4975 #endif
4976                         break;
4977                 }
4978                 case OP_GC_LIVENESS_DEF:
4979                 case OP_GC_LIVENESS_USE:
4980                 case OP_GC_PARAM_SLOT_LIVENESS_DEF:
4981                         ins->backend.pc_offset = code - cfg->native_code;
4982                         break;
4983                 case OP_GC_SPILL_SLOT_LIVENESS_DEF:
4984                         ins->backend.pc_offset = code - cfg->native_code;
4985                         bb->spill_slot_defs = g_slist_prepend_mempool (cfg->mempool, bb->spill_slot_defs, ins);
4986                         break;
4987                 default:
4988                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
4989                         g_assert_not_reached ();
4990                 }
4991
4992                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
4993 #ifndef __native_client_codegen__
4994                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4995                                            mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4996                         g_assert_not_reached ();
4997 #endif  /* __native_client_codegen__ */
4998                 }
4999                
5000                 cpos += max_len;
5001         }
5002
5003         cfg->code_len = code - cfg->native_code;
5004 }
5005
5006 #endif /* DISABLE_JIT */
5007
5008 void
5009 mono_arch_register_lowlevel_calls (void)
5010 {
5011 }
5012
5013 void
5014 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, MonoCodeManager *dyn_code_mp, gboolean run_cctors)
5015 {
5016         MonoJumpInfo *patch_info;
5017         gboolean compile_aot = !run_cctors;
5018
5019         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
5020                 unsigned char *ip = patch_info->ip.i + code;
5021                 const unsigned char *target;
5022
5023                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
5024
5025                 if (compile_aot) {
5026                         switch (patch_info->type) {
5027                         case MONO_PATCH_INFO_BB:
5028                         case MONO_PATCH_INFO_LABEL:
5029                                 break;
5030                         default:
5031                                 /* No need to patch these */
5032                                 continue;
5033                         }
5034                 }
5035
5036                 switch (patch_info->type) {
5037                 case MONO_PATCH_INFO_IP:
5038                         *((gconstpointer *)(ip)) = target;
5039                         break;
5040                 case MONO_PATCH_INFO_CLASS_INIT: {
5041                         guint8 *code = ip;
5042                         /* Might already been changed to a nop */
5043                         x86_call_code (code, 0);
5044                         x86_patch (ip, target);
5045                         break;
5046                 }
5047                 case MONO_PATCH_INFO_ABS:
5048                 case MONO_PATCH_INFO_METHOD:
5049                 case MONO_PATCH_INFO_METHOD_JUMP:
5050                 case MONO_PATCH_INFO_INTERNAL_METHOD:
5051                 case MONO_PATCH_INFO_BB:
5052                 case MONO_PATCH_INFO_LABEL:
5053                 case MONO_PATCH_INFO_RGCTX_FETCH:
5054                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
5055                 case MONO_PATCH_INFO_MONITOR_ENTER:
5056                 case MONO_PATCH_INFO_MONITOR_EXIT:
5057                 case MONO_PATCH_INFO_JIT_ICALL_ADDR:
5058 #if defined(__native_client_codegen__) && defined(__native_client__)
5059                         if (nacl_is_code_address (code)) {
5060                                 /* For tail calls, code is patched after being installed */
5061                                 /* but not through the normal "patch callsite" method.   */
5062                                 unsigned char buf[kNaClAlignment];
5063                                 unsigned char *aligned_code = (uintptr_t)code & ~kNaClAlignmentMask;
5064                                 unsigned char *_target = target;
5065                                 int ret;
5066                                 /* All patch targets modified in x86_patch */
5067                                 /* are IP relative.                        */
5068                                 _target = _target + (uintptr_t)buf - (uintptr_t)aligned_code;
5069                                 memcpy (buf, aligned_code, kNaClAlignment);
5070                                 /* Patch a temp buffer of bundle size, */
5071                                 /* then install to actual location.    */
5072                                 x86_patch (buf + ((uintptr_t)code - (uintptr_t)aligned_code), _target);
5073                                 ret = nacl_dyncode_modify (aligned_code, buf, kNaClAlignment);
5074                                 g_assert (ret == 0);
5075                         }
5076                         else {
5077                                 x86_patch (ip, target);
5078                         }
5079 #else
5080                         x86_patch (ip, target);
5081 #endif
5082                         break;
5083                 case MONO_PATCH_INFO_NONE:
5084                         break;
5085                 case MONO_PATCH_INFO_R4:
5086                 case MONO_PATCH_INFO_R8: {
5087                         guint32 offset = mono_arch_get_patch_offset (ip);
5088                         *((gconstpointer *)(ip + offset)) = target;
5089                         break;
5090                 }
5091                 default: {
5092                         guint32 offset = mono_arch_get_patch_offset (ip);
5093 #if !defined(__native_client__)
5094                         *((gconstpointer *)(ip + offset)) = target;
5095 #else
5096                         *((gconstpointer *)(ip + offset)) = nacl_modify_patch_target (target);
5097 #endif
5098                         break;
5099                 }
5100                 }
5101         }
5102 }
5103
5104 static G_GNUC_UNUSED void
5105 stack_unaligned (MonoMethod *m, gpointer caller)
5106 {
5107         printf ("%s\n", mono_method_full_name (m, TRUE));
5108         g_assert_not_reached ();
5109 }
5110
5111 guint8 *
5112 mono_arch_emit_prolog (MonoCompile *cfg)
5113 {
5114         MonoMethod *method = cfg->method;
5115         MonoBasicBlock *bb;
5116         MonoMethodSignature *sig;
5117         MonoInst *inst;
5118         int alloc_size, pos, max_offset, i, cfa_offset;
5119         guint8 *code;
5120         gboolean need_stack_frame;
5121 #ifdef __native_client_codegen__
5122         guint alignment_check;
5123 #endif
5124
5125         cfg->code_size = MAX (cfg->header->code_size * 4, 10240);
5126
5127         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
5128                 cfg->code_size += 512;
5129
5130 #if defined(__default_codegen__)
5131         code = cfg->native_code = g_malloc (cfg->code_size);
5132 #elif defined(__native_client_codegen__)
5133         /* native_code_alloc is not 32-byte aligned, native_code is. */
5134         cfg->code_size = NACL_BUNDLE_ALIGN_UP (cfg->code_size);
5135         cfg->native_code_alloc = g_malloc (cfg->code_size + kNaClAlignment);
5136
5137         /* Align native_code to next nearest kNaclAlignment byte. */
5138         cfg->native_code = (guint)cfg->native_code_alloc + kNaClAlignment; 
5139         cfg->native_code = (guint)cfg->native_code & ~kNaClAlignmentMask;
5140         
5141         code = cfg->native_code;
5142
5143         alignment_check = (guint)cfg->native_code & kNaClAlignmentMask;
5144         g_assert(alignment_check == 0);
5145 #endif
5146
5147 #if 0
5148         {
5149                 guint8 *br [16];
5150
5151         /* Check that the stack is aligned on osx */
5152         x86_mov_reg_reg (code, X86_EAX, X86_ESP, sizeof (mgreg_t));
5153         x86_alu_reg_imm (code, X86_AND, X86_EAX, 15);
5154         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0xc);
5155         br [0] = code;
5156         x86_branch_disp (code, X86_CC_Z, 0, FALSE);
5157         x86_push_membase (code, X86_ESP, 0);
5158         x86_push_imm (code, cfg->method);
5159         x86_mov_reg_imm (code, X86_EAX, stack_unaligned);
5160         x86_call_reg (code, X86_EAX);
5161         x86_patch (br [0], code);
5162         }
5163 #endif
5164
5165         /* Offset between RSP and the CFA */
5166         cfa_offset = 0;
5167
5168         // CFA = sp + 4
5169         cfa_offset = sizeof (gpointer);
5170         mono_emit_unwind_op_def_cfa (cfg, code, X86_ESP, sizeof (gpointer));
5171         // IP saved at CFA - 4
5172         /* There is no IP reg on x86 */
5173         mono_emit_unwind_op_offset (cfg, code, X86_NREG, -cfa_offset);
5174         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5175
5176         need_stack_frame = needs_stack_frame (cfg);
5177
5178         if (need_stack_frame) {
5179                 x86_push_reg (code, X86_EBP);
5180                 cfa_offset += sizeof (gpointer);
5181                 mono_emit_unwind_op_def_cfa_offset (cfg, code, cfa_offset);
5182                 mono_emit_unwind_op_offset (cfg, code, X86_EBP, - cfa_offset);
5183                 x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
5184                 mono_emit_unwind_op_def_cfa_reg (cfg, code, X86_EBP);
5185                 /* These are handled automatically by the stack marking code */
5186                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5187         } else {
5188                 cfg->frame_reg = X86_ESP;
5189         }
5190
5191         alloc_size = cfg->stack_offset;
5192         pos = 0;
5193
5194         if (method->save_lmf) {
5195                 pos += sizeof (MonoLMF);
5196
5197                 /* save the current IP */
5198                 if (cfg->compile_aot) {
5199                         /* This pushes the current ip */
5200                         x86_call_imm (code, 0);
5201                 } else {
5202                         mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
5203                         x86_push_imm_template (code);
5204                 }
5205                 cfa_offset += sizeof (gpointer);
5206                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5207
5208                 /* save all caller saved regs */
5209                 x86_push_reg (code, X86_EBP);
5210                 cfa_offset += sizeof (gpointer);
5211                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5212                 x86_push_reg (code, X86_ESI);
5213                 cfa_offset += sizeof (gpointer);
5214                 mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
5215                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5216                 x86_push_reg (code, X86_EDI);
5217                 cfa_offset += sizeof (gpointer);
5218                 mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
5219                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5220                 x86_push_reg (code, X86_EBX);
5221                 cfa_offset += sizeof (gpointer);
5222                 mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
5223                 mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5224
5225                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
5226                         /*
5227                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
5228                          * through the mono_lmf_addr TLS variable.
5229                          */
5230                         /* %eax = previous_lmf */
5231                         code = mono_x86_emit_tls_get (code, X86_EAX, lmf_tls_offset);
5232                         /* skip esp + method_info + lmf */
5233                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
5234                         cfa_offset += 12;
5235                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5236                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 4, SLOT_NOREF);
5237                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset + 8, SLOT_NOREF);
5238                         /* push previous_lmf */
5239                         x86_push_reg (code, X86_EAX);
5240                         cfa_offset += 4;
5241                         mini_gc_set_slot_type_from_cfa (cfg, -cfa_offset, SLOT_NOREF);
5242                         /* new lmf = ESP */
5243                         code = mono_x86_emit_tls_set (code, X86_ESP, lmf_tls_offset);
5244                 } else {
5245                         /* get the address of lmf for the current thread */
5246                         /* 
5247                          * This is performance critical so we try to use some tricks to make
5248                          * it fast.
5249                          */                                                                        
5250
5251                         if (lmf_addr_tls_offset != -1) {
5252                                 /* Load lmf quicky using the GS register */
5253                                 code = mono_x86_emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
5254 #ifdef TARGET_WIN32
5255                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
5256                                 /* FIXME: Add a separate key for LMF to avoid this */
5257                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
5258 #endif
5259                         } else {
5260                                 if (cfg->compile_aot)
5261                                         code = mono_arch_emit_load_got_addr (cfg->native_code, code, cfg, NULL);
5262                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
5263                         }
5264
5265                         /* Skip esp + method info */
5266                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
5267
5268                         /* push lmf */
5269                         x86_push_reg (code, X86_EAX); 
5270                         /* push *lfm (previous_lmf) */
5271                         x86_push_membase (code, X86_EAX, 0);
5272                         /* *(lmf) = ESP */
5273                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
5274                 }
5275         } else {
5276
5277                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5278                         x86_push_reg (code, X86_EBX);
5279                         pos += 4;
5280                         cfa_offset += sizeof (gpointer);
5281                         mono_emit_unwind_op_offset (cfg, code, X86_EBX, - cfa_offset);
5282                         /* These are handled automatically by the stack marking code */
5283                         mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF);
5284                 }
5285
5286                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5287                         x86_push_reg (code, X86_EDI);
5288                         pos += 4;
5289                         cfa_offset += sizeof (gpointer);
5290                         mono_emit_unwind_op_offset (cfg, code, X86_EDI, - cfa_offset);
5291                         mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF);
5292                 }
5293
5294                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5295                         x86_push_reg (code, X86_ESI);
5296                         pos += 4;
5297                         cfa_offset += sizeof (gpointer);
5298                         mono_emit_unwind_op_offset (cfg, code, X86_ESI, - cfa_offset);
5299                         mini_gc_set_slot_type_from_cfa (cfg, - cfa_offset, SLOT_NOREF);
5300                 }
5301         }
5302
5303         alloc_size -= pos;
5304
5305         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
5306         if (mono_do_x86_stack_align && need_stack_frame) {
5307                 int tot = alloc_size + pos + 4; /* ret ip */
5308                 if (need_stack_frame)
5309                         tot += 4; /* ebp */
5310                 tot &= MONO_ARCH_FRAME_ALIGNMENT - 1;
5311                 if (tot) {
5312                         alloc_size += MONO_ARCH_FRAME_ALIGNMENT - tot;
5313                         for (i = 0; i < MONO_ARCH_FRAME_ALIGNMENT - tot; i += sizeof (mgreg_t))
5314                                 mini_gc_set_slot_type_from_fp (cfg, - (alloc_size + pos - i), SLOT_NOREF);
5315                 }
5316         }
5317
5318         cfg->arch.sp_fp_offset = alloc_size + pos;
5319
5320         if (alloc_size) {
5321                 /* See mono_emit_stack_alloc */
5322 #if defined(TARGET_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
5323                 guint32 remaining_size = alloc_size;
5324                 /*FIXME handle unbounded code expansion, we should use a loop in case of more than X interactions*/
5325                 guint32 required_code_size = ((remaining_size / 0x1000) + 1) * 8; /*8 is the max size of x86_alu_reg_imm + x86_test_membase_reg*/
5326                 guint32 offset = code - cfg->native_code;
5327                 if (G_UNLIKELY (required_code_size >= (cfg->code_size - offset))) {
5328                         while (required_code_size >= (cfg->code_size - offset))
5329                                 cfg->code_size *= 2;
5330                         cfg->native_code = mono_realloc_native_code(cfg);
5331                         code = cfg->native_code + offset;
5332                         cfg->stat_code_reallocs++;
5333                 }
5334                 while (remaining_size >= 0x1000) {
5335                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
5336                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
5337                         remaining_size -= 0x1000;
5338                 }
5339                 if (remaining_size)
5340                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
5341 #else
5342                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
5343 #endif
5344
5345                 g_assert (need_stack_frame);
5346         }
5347
5348         if (cfg->method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED ||
5349                         cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE) {
5350                 x86_alu_reg_imm (code, X86_AND, X86_ESP, -MONO_ARCH_FRAME_ALIGNMENT);
5351         }
5352
5353 #if DEBUG_STACK_ALIGNMENT
5354         /* check the stack is aligned */
5355         if (need_stack_frame && method->wrapper_type == MONO_WRAPPER_NONE) {
5356                 x86_mov_reg_reg (code, X86_ECX, X86_ESP, 4);
5357                 x86_alu_reg_imm (code, X86_AND, X86_ECX, MONO_ARCH_FRAME_ALIGNMENT - 1);
5358                 x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
5359                 x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
5360                 x86_breakpoint (code);
5361         }
5362 #endif
5363
5364         /* compute max_offset in order to use short forward jumps */
5365         max_offset = 0;
5366         if (cfg->opt & MONO_OPT_BRANCH) {
5367                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
5368                         MonoInst *ins;
5369                         bb->max_offset = max_offset;
5370
5371                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
5372                                 max_offset += 6;
5373                         /* max alignment for loops */
5374                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
5375                                 max_offset += LOOP_ALIGNMENT;
5376 #ifdef __native_client_codegen__
5377                         /* max alignment for native client */
5378                         if (bb->flags & BB_INDIRECT_JUMP_TARGET || bb->flags & BB_EXCEPTION_HANDLER)
5379                                 max_offset += kNaClAlignment;
5380 #endif
5381                         MONO_BB_FOR_EACH_INS (bb, ins) {
5382                                 if (ins->opcode == OP_LABEL)
5383                                         ins->inst_c1 = max_offset;
5384 #ifdef __native_client_codegen__
5385                                 switch (ins->opcode)
5386                                 {
5387                                         case OP_FCALL:
5388                                         case OP_LCALL:
5389                                         case OP_VCALL:
5390                                         case OP_VCALL2:
5391                                         case OP_VOIDCALL:
5392                                         case OP_CALL:
5393                                         case OP_FCALL_REG:
5394                                         case OP_LCALL_REG:
5395                                         case OP_VCALL_REG:
5396                                         case OP_VCALL2_REG:
5397                                         case OP_VOIDCALL_REG:
5398                                         case OP_CALL_REG:
5399                                         case OP_FCALL_MEMBASE:
5400                                         case OP_LCALL_MEMBASE:
5401                                         case OP_VCALL_MEMBASE:
5402                                         case OP_VCALL2_MEMBASE:
5403                                         case OP_VOIDCALL_MEMBASE:
5404                                         case OP_CALL_MEMBASE:
5405                                                 max_offset += kNaClAlignment;
5406                                                 break;
5407                                         default:
5408                                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN] - 1;
5409                                                 break;
5410                                 }
5411 #endif  /* __native_client_codegen__ */
5412                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
5413                         }
5414                 }
5415         }
5416
5417         /* store runtime generic context */
5418         if (cfg->rgctx_var) {
5419                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
5420
5421                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
5422         }
5423
5424         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5425                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
5426
5427         /* load arguments allocated to register from the stack */
5428         sig = mono_method_signature (method);
5429         pos = 0;
5430
5431         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5432                 inst = cfg->args [pos];
5433                 if (inst->opcode == OP_REGVAR) {
5434                         g_assert (need_stack_frame);
5435                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
5436                         if (cfg->verbose_level > 2)
5437                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
5438                 }
5439                 pos++;
5440         }
5441
5442         cfg->code_len = code - cfg->native_code;
5443
5444         g_assert (cfg->code_len < cfg->code_size);
5445
5446         return code;
5447 }
5448
5449 void
5450 mono_arch_emit_epilog (MonoCompile *cfg)
5451 {
5452         MonoMethod *method = cfg->method;
5453         MonoMethodSignature *sig = mono_method_signature (method);
5454         int quad, pos;
5455         guint32 stack_to_pop;
5456         guint8 *code;
5457         int max_epilog_size = 16;
5458         CallInfo *cinfo;
5459         gboolean need_stack_frame = needs_stack_frame (cfg);
5460
5461         if (cfg->method->save_lmf)
5462                 max_epilog_size += 128;
5463
5464         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
5465                 cfg->code_size *= 2;
5466                 cfg->native_code = mono_realloc_native_code(cfg);
5467                 cfg->stat_code_reallocs++;
5468         }
5469
5470         code = cfg->native_code + cfg->code_len;
5471
5472         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
5473                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
5474
5475         /* the code restoring the registers must be kept in sync with OP_JMP */
5476         pos = 0;
5477         
5478         if (method->save_lmf) {
5479                 gint32 prev_lmf_reg;
5480                 gint32 lmf_offset = -sizeof (MonoLMF);
5481
5482                 /* check if we need to restore protection of the stack after a stack overflow */
5483                 if (mono_get_jit_tls_offset () != -1) {
5484                         guint8 *patch;
5485                         code = mono_x86_emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
5486                         /* we load the value in a separate instruction: this mechanism may be
5487                          * used later as a safer way to do thread interruption
5488                          */
5489                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
5490                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
5491                         patch = code;
5492                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
5493                         /* note that the call trampoline will preserve eax/edx */
5494                         x86_call_reg (code, X86_ECX);
5495                         x86_patch (patch, code);
5496                 } else {
5497                         /* FIXME: maybe save the jit tls in the prolog */
5498                 }
5499                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
5500                         /*
5501                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
5502                          * through the mono_lmf_addr TLS variable.
5503                          */
5504                         /* reg = previous_lmf */
5505                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5506
5507                         /* lmf = previous_lmf */
5508                         code = mono_x86_emit_tls_set (code, X86_ECX, lmf_tls_offset);
5509                 } else {
5510                         /* Find a spare register */
5511                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
5512                         case MONO_TYPE_I8:
5513                         case MONO_TYPE_U8:
5514                                 prev_lmf_reg = X86_EDI;
5515                                 cfg->used_int_regs |= (1 << X86_EDI);
5516                                 break;
5517                         default:
5518                                 prev_lmf_reg = X86_EDX;
5519                                 break;
5520                         }
5521
5522                         /* reg = previous_lmf */
5523                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
5524
5525                         /* ecx = lmf */
5526                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
5527
5528                         /* *(lmf) = previous_lmf */
5529                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
5530                 }
5531
5532                 /* restore caller saved regs */
5533                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5534                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
5535                 }
5536
5537                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5538                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
5539                 }
5540                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5541                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
5542                 }
5543
5544                 /* EBP is restored by LEAVE */
5545         } else {
5546                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5547                         pos -= 4;
5548                 }
5549                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5550                         pos -= 4;
5551                 }
5552                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5553                         pos -= 4;
5554                 }
5555
5556                 if (pos) {
5557                         g_assert (need_stack_frame);
5558                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
5559                 }
5560
5561                 if (cfg->used_int_regs & (1 << X86_ESI)) {
5562                         x86_pop_reg (code, X86_ESI);
5563                 }
5564                 if (cfg->used_int_regs & (1 << X86_EDI)) {
5565                         x86_pop_reg (code, X86_EDI);
5566                 }
5567                 if (cfg->used_int_regs & (1 << X86_EBX)) {
5568                         x86_pop_reg (code, X86_EBX);
5569                 }
5570         }
5571
5572         /* Load returned vtypes into registers if needed */
5573         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig);
5574         if (cinfo->ret.storage == ArgValuetypeInReg) {
5575                 for (quad = 0; quad < 2; quad ++) {
5576                         switch (cinfo->ret.pair_storage [quad]) {
5577                         case ArgInIReg:
5578                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
5579                                 break;
5580                         case ArgOnFloatFpStack:
5581                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
5582                                 break;
5583                         case ArgOnDoubleFpStack:
5584                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
5585                                 break;
5586                         case ArgNone:
5587                                 break;
5588                         default:
5589                                 g_assert_not_reached ();
5590                         }
5591                 }
5592         }
5593
5594         if (need_stack_frame)
5595                 x86_leave (code);
5596
5597         if (CALLCONV_IS_STDCALL (sig)) {
5598                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
5599
5600                 stack_to_pop = mono_arch_get_argument_info (NULL, sig, sig->param_count, arg_info);
5601         } else if (cinfo->vtype_retaddr)
5602                 stack_to_pop = 4;
5603         else
5604                 stack_to_pop = 0;
5605
5606         if (stack_to_pop) {
5607                 g_assert (need_stack_frame);
5608                 x86_ret_imm (code, stack_to_pop);
5609         } else {
5610                 x86_ret (code);
5611         }
5612
5613         cfg->code_len = code - cfg->native_code;
5614
5615         g_assert (cfg->code_len < cfg->code_size);
5616 }
5617
5618 void
5619 mono_arch_emit_exceptions (MonoCompile *cfg)
5620 {
5621         MonoJumpInfo *patch_info;
5622         int nthrows, i;
5623         guint8 *code;
5624         MonoClass *exc_classes [16];
5625         guint8 *exc_throw_start [16], *exc_throw_end [16];
5626         guint32 code_size;
5627         int exc_count = 0;
5628
5629         /* Compute needed space */
5630         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5631                 if (patch_info->type == MONO_PATCH_INFO_EXC)
5632                         exc_count++;
5633         }
5634
5635         /* 
5636          * make sure we have enough space for exceptions
5637          * 16 is the size of two push_imm instructions and a call
5638          */
5639         if (cfg->compile_aot)
5640                 code_size = exc_count * 32;
5641         else
5642                 code_size = exc_count * 16;
5643
5644         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
5645                 cfg->code_size *= 2;
5646                 cfg->native_code = mono_realloc_native_code(cfg);
5647                 cfg->stat_code_reallocs++;
5648         }
5649
5650         code = cfg->native_code + cfg->code_len;
5651
5652         nthrows = 0;
5653         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
5654                 switch (patch_info->type) {
5655                 case MONO_PATCH_INFO_EXC: {
5656                         MonoClass *exc_class;
5657                         guint8 *buf, *buf2;
5658                         guint32 throw_ip;
5659
5660                         x86_patch (patch_info->ip.i + cfg->native_code, code);
5661
5662                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
5663                         g_assert (exc_class);
5664                         throw_ip = patch_info->ip.i;
5665
5666                         /* Find a throw sequence for the same exception class */
5667                         for (i = 0; i < nthrows; ++i)
5668                                 if (exc_classes [i] == exc_class)
5669                                         break;
5670                         if (i < nthrows) {
5671                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
5672                                 x86_jump_code (code, exc_throw_start [i]);
5673                                 patch_info->type = MONO_PATCH_INFO_NONE;
5674                         }
5675                         else {
5676                                 guint32 size;
5677
5678                                 /* Compute size of code following the push <OFFSET> */
5679 #if defined(__default_codegen__)
5680                                 size = 5 + 5;
5681 #elif defined(__native_client_codegen__)
5682                                 code = mono_nacl_align (code);
5683                                 size = kNaClAlignment;
5684 #endif
5685                                 /*This is aligned to 16 bytes by the callee. This way we save a few bytes here.*/
5686
5687                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
5688                                         /* Use the shorter form */
5689                                         buf = buf2 = code;
5690                                         x86_push_imm (code, 0);
5691                                 }
5692                                 else {
5693                                         buf = code;
5694                                         x86_push_imm (code, 0xf0f0f0f0);
5695                                         buf2 = code;
5696                                 }
5697
5698                                 if (nthrows < 16) {
5699                                         exc_classes [nthrows] = exc_class;
5700                                         exc_throw_start [nthrows] = code;
5701                                 }
5702
5703                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
5704                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
5705                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
5706                                 patch_info->ip.i = code - cfg->native_code;
5707                                 x86_call_code (code, 0);
5708                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
5709                                 while (buf < buf2)
5710                                         x86_nop (buf);
5711
5712                                 if (nthrows < 16) {
5713                                         exc_throw_end [nthrows] = code;
5714                                         nthrows ++;
5715                                 }
5716                         }
5717                         break;
5718                 }
5719                 default:
5720                         /* do nothing */
5721                         break;
5722                 }
5723         }
5724
5725         cfg->code_len = code - cfg->native_code;
5726
5727         g_assert (cfg->code_len < cfg->code_size);
5728 }
5729
5730 void
5731 mono_arch_flush_icache (guint8 *code, gint size)
5732 {
5733         /* not needed */
5734 }
5735
5736 void
5737 mono_arch_flush_register_windows (void)
5738 {
5739 }
5740
5741 gboolean 
5742 mono_arch_is_inst_imm (gint64 imm)
5743 {
5744         return TRUE;
5745 }
5746
5747 void
5748 mono_arch_finish_init (void)
5749 {
5750         if (!getenv ("MONO_NO_TLS")) {
5751 #ifdef TARGET_WIN32
5752                 /* 
5753                  * We need to init this multiple times, since when we are first called, the key might not
5754                  * be initialized yet.
5755                  */
5756                 appdomain_tls_offset = mono_domain_get_tls_key ();
5757                 lmf_tls_offset = mono_get_jit_tls_key ();
5758
5759                 /* Only 64 tls entries can be accessed using inline code */
5760                 if (appdomain_tls_offset >= 64)
5761                         appdomain_tls_offset = -1;
5762                 if (lmf_tls_offset >= 64)
5763                         lmf_tls_offset = -1;
5764 #else
5765 #if MONO_XEN_OPT
5766                 optimize_for_xen = access ("/proc/xen", F_OK) == 0;
5767 #endif
5768                 appdomain_tls_offset = mono_domain_get_tls_offset ();
5769                 lmf_tls_offset = mono_get_lmf_tls_offset ();
5770                 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5771 #endif
5772         }               
5773 }
5774
5775 void
5776 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5777 {
5778 }
5779
5780 #ifdef MONO_ARCH_HAVE_IMT
5781
5782 // Linear handler, the bsearch head compare is shorter
5783 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
5784 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
5785 //        x86_patch(ins,target)
5786 //[1 + 5] x86_jump_mem(inst,mem)
5787
5788 #define CMP_SIZE 6
5789 #if defined(__default_codegen__)
5790 #define BR_SMALL_SIZE 2
5791 #define BR_LARGE_SIZE 5
5792 #elif defined(__native_client_codegen__)
5793 /* I suspect the size calculation below is actually incorrect. */
5794 /* TODO: fix the calculation that uses these sizes.  */
5795 #define BR_SMALL_SIZE 16
5796 #define BR_LARGE_SIZE 12
5797 #endif  /*__native_client_codegen__*/
5798 #define JUMP_IMM_SIZE 6
5799 #define ENABLE_WRONG_METHOD_CHECK 0
5800 #define DEBUG_IMT 0
5801
5802 static int
5803 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
5804 {
5805         int i, distance = 0;
5806         for (i = start; i < target; ++i)
5807                 distance += imt_entries [i]->chunk_size;
5808         return distance;
5809 }
5810
5811 /*
5812  * LOCKING: called with the domain lock held
5813  */
5814 gpointer
5815 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5816         gpointer fail_tramp)
5817 {
5818         int i;
5819         int size = 0;
5820         guint8 *code, *start;
5821
5822         for (i = 0; i < count; ++i) {
5823                 MonoIMTCheckItem *item = imt_entries [i];
5824                 if (item->is_equals) {
5825                         if (item->check_target_idx) {
5826                                 if (!item->compare_done)
5827                                         item->chunk_size += CMP_SIZE;
5828                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
5829                         } else {
5830                                 if (fail_tramp) {
5831                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
5832                                 } else {
5833                                         item->chunk_size += JUMP_IMM_SIZE;
5834 #if ENABLE_WRONG_METHOD_CHECK
5835                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
5836 #endif
5837                                 }
5838                         }
5839                 } else {
5840                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
5841                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5842                 }
5843                 size += item->chunk_size;
5844         }
5845 #if defined(__native_client__) && defined(__native_client_codegen__)
5846         /* In Native Client, we don't re-use thunks, allocate from the */
5847         /* normal code manager paths. */
5848         size = NACL_BUNDLE_ALIGN_UP (size);
5849         code = mono_domain_code_reserve (domain, size);
5850 #else
5851         if (fail_tramp)
5852                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
5853         else
5854                 code = mono_domain_code_reserve (domain, size);
5855 #endif
5856         start = code;
5857         for (i = 0; i < count; ++i) {
5858                 MonoIMTCheckItem *item = imt_entries [i];
5859                 item->code_target = code;
5860                 if (item->is_equals) {
5861                         if (item->check_target_idx) {
5862                                 if (!item->compare_done)
5863                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5864                                 item->jmp_code = code;
5865                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
5866                                 if (item->has_target_code)
5867                                         x86_jump_code (code, item->value.target_code);
5868                                 else
5869                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5870                         } else {
5871                                 if (fail_tramp) {
5872                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5873                                         item->jmp_code = code;
5874                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5875                                         if (item->has_target_code)
5876                                                 x86_jump_code (code, item->value.target_code);
5877                                         else
5878                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5879                                         x86_patch (item->jmp_code, code);
5880                                         x86_jump_code (code, fail_tramp);
5881                                         item->jmp_code = NULL;
5882                                 } else {
5883                                         /* enable the commented code to assert on wrong method */
5884 #if ENABLE_WRONG_METHOD_CHECK
5885                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5886                                         item->jmp_code = code;
5887                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
5888 #endif
5889                                         if (item->has_target_code)
5890                                                 x86_jump_code (code, item->value.target_code);
5891                                         else
5892                                                 x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
5893 #if ENABLE_WRONG_METHOD_CHECK
5894                                         x86_patch (item->jmp_code, code);
5895                                         x86_breakpoint (code);
5896                                         item->jmp_code = NULL;
5897 #endif
5898                                 }
5899                         }
5900                 } else {
5901                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
5902                         item->jmp_code = code;
5903                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
5904                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
5905                         else
5906                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
5907                 }
5908         }
5909         /* patch the branches to get to the target items */
5910         for (i = 0; i < count; ++i) {
5911                 MonoIMTCheckItem *item = imt_entries [i];
5912                 if (item->jmp_code) {
5913                         if (item->check_target_idx) {
5914                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5915                         }
5916                 }
5917         }
5918
5919         if (!fail_tramp)
5920                 mono_stats.imt_thunks_size += code - start;
5921         g_assert (code - start <= size);
5922
5923 #if DEBUG_IMT
5924         {
5925                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5926                 mono_disassemble_code (NULL, (guint8*)start, code - start, buff);
5927                 g_free (buff);
5928         }
5929 #endif
5930         if (mono_jit_map_is_enabled ()) {
5931                 char *buff;
5932                 if (vtable)
5933                         buff = g_strdup_printf ("imt_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5934                 else
5935                         buff = g_strdup_printf ("imt_thunk_entries_%d", count);
5936                 mono_emit_jit_tramp (start, code - start, buff);
5937                 g_free (buff);
5938         }
5939
5940         nacl_domain_code_validate (domain, &start, size, &code);
5941
5942         return start;
5943 }
5944
5945 MonoMethod*
5946 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5947 {
5948         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
5949 }
5950 #endif
5951
5952 MonoVTable*
5953 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5954 {
5955         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5956 }
5957
5958 GSList*
5959 mono_arch_get_cie_program (void)
5960 {
5961         GSList *l = NULL;
5962
5963         mono_add_unwind_op_def_cfa (l, (guint8*)NULL, (guint8*)NULL, X86_ESP, 4);
5964         mono_add_unwind_op_offset (l, (guint8*)NULL, (guint8*)NULL, X86_NREG, -4);
5965
5966         return l;
5967 }
5968
5969 MonoInst*
5970 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5971 {
5972         MonoInst *ins = NULL;
5973         int opcode = 0;
5974
5975         if (cmethod->klass == mono_defaults.math_class) {
5976                 if (strcmp (cmethod->name, "Sin") == 0) {
5977                         opcode = OP_SIN;
5978                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5979                         opcode = OP_COS;
5980                 } else if (strcmp (cmethod->name, "Tan") == 0) {
5981                         opcode = OP_TAN;
5982                 } else if (strcmp (cmethod->name, "Atan") == 0) {
5983                         opcode = OP_ATAN;
5984                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5985                         opcode = OP_SQRT;
5986                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5987                         opcode = OP_ABS;
5988                 } else if (strcmp (cmethod->name, "Round") == 0 && fsig->param_count == 1 && fsig->params [0]->type == MONO_TYPE_R8) {
5989                         opcode = OP_ROUND;
5990                 }
5991                 
5992                 if (opcode) {
5993                         MONO_INST_NEW (cfg, ins, opcode);
5994                         ins->type = STACK_R8;
5995                         ins->dreg = mono_alloc_freg (cfg);
5996                         ins->sreg1 = args [0]->dreg;
5997                         MONO_ADD_INS (cfg->cbb, ins);
5998                 }
5999
6000                 if (cfg->opt & MONO_OPT_CMOV) {
6001                         int opcode = 0;
6002
6003                         if (strcmp (cmethod->name, "Min") == 0) {
6004                                 if (fsig->params [0]->type == MONO_TYPE_I4)
6005                                         opcode = OP_IMIN;
6006                         } else if (strcmp (cmethod->name, "Max") == 0) {
6007                                 if (fsig->params [0]->type == MONO_TYPE_I4)
6008                                         opcode = OP_IMAX;
6009                         }               
6010
6011                         if (opcode) {
6012                                 MONO_INST_NEW (cfg, ins, opcode);
6013                                 ins->type = STACK_I4;
6014                                 ins->dreg = mono_alloc_ireg (cfg);
6015                                 ins->sreg1 = args [0]->dreg;
6016                                 ins->sreg2 = args [1]->dreg;
6017                                 MONO_ADD_INS (cfg->cbb, ins);
6018                         }
6019                 }
6020
6021 #if 0
6022                 /* OP_FREM is not IEEE compatible */
6023                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
6024                         MONO_INST_NEW (cfg, ins, OP_FREM);
6025                         ins->inst_i0 = args [0];
6026                         ins->inst_i1 = args [1];
6027                 }
6028 #endif
6029         }
6030
6031         return ins;
6032 }
6033
6034 gboolean
6035 mono_arch_print_tree (MonoInst *tree, int arity)
6036 {
6037         return 0;
6038 }
6039
6040 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
6041 {
6042         MonoInst* ins;
6043
6044         return NULL;
6045
6046         if (appdomain_tls_offset == -1)
6047                 return NULL;
6048
6049         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
6050         ins->inst_offset = appdomain_tls_offset;
6051         return ins;
6052 }
6053
6054 guint32
6055 mono_arch_get_patch_offset (guint8 *code)
6056 {
6057         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
6058                 return 2;
6059         else if (code [0] == 0xba)
6060                 return 1;
6061         else if (code [0] == 0x68)
6062                 /* push IMM */
6063                 return 1;
6064         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
6065                 /* push <OFFSET>(<REG>) */
6066                 return 2;
6067         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
6068                 /* call *<OFFSET>(<REG>) */
6069                 return 2;
6070         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
6071                 /* fldl <ADDR> */
6072                 return 2;
6073         else if ((code [0] == 0x58) && (code [1] == 0x05))
6074                 /* pop %eax; add <OFFSET>, %eax */
6075                 return 2;
6076         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
6077                 /* pop <REG>; add <OFFSET>, <REG> */
6078                 return 3;
6079         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
6080                 /* mov <REG>, imm */
6081                 return 1;
6082         else {
6083                 g_assert_not_reached ();
6084                 return -1;
6085         }
6086 }
6087
6088 /**
6089  * mono_breakpoint_clean_code:
6090  *
6091  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
6092  * breakpoints in the original code, they are removed in the copy.
6093  *
6094  * Returns TRUE if no sw breakpoint was present.
6095  */
6096 gboolean
6097 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
6098 {
6099         int i;
6100         gboolean can_write = TRUE;
6101         /*
6102          * If method_start is non-NULL we need to perform bound checks, since we access memory
6103          * at code - offset we could go before the start of the method and end up in a different
6104          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
6105          * instead.
6106          */
6107         if (!method_start || code - offset >= method_start) {
6108                 memcpy (buf, code - offset, size);
6109         } else {
6110                 int diff = code - method_start;
6111                 memset (buf, 0, size);
6112                 memcpy (buf + offset - diff, method_start, diff + size - offset);
6113         }
6114         code -= offset;
6115         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
6116                 int idx = mono_breakpoint_info_index [i];
6117                 guint8 *ptr;
6118                 if (idx < 1)
6119                         continue;
6120                 ptr = mono_breakpoint_info [idx].address;
6121                 if (ptr >= code && ptr < code + size) {
6122                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
6123                         can_write = FALSE;
6124                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
6125                         buf [ptr - code] = saved_byte;
6126                 }
6127         }
6128         return can_write;
6129 }
6130
6131 /*
6132  * mono_x86_get_this_arg_offset:
6133  *
6134  *   Return the offset of the stack location where this is passed during a virtual
6135  * call.
6136  */
6137 guint32
6138 mono_x86_get_this_arg_offset (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig)
6139 {
6140         return 0;
6141 }
6142
6143 gpointer
6144 mono_arch_get_this_arg_from_call (mgreg_t *regs, guint8 *code)
6145 {
6146         guint32 esp = regs [X86_ESP];
6147         CallInfo *cinfo = NULL;
6148         gpointer res;
6149         int offset;
6150
6151         offset = 0;
6152
6153         /*
6154          * The stack looks like:
6155          * <other args>
6156          * <this=delegate>
6157          * <return addr>
6158          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
6159          */
6160         res = (((MonoObject**)esp) [5 + (offset / 4)]);
6161         if (cinfo)
6162                 g_free (cinfo);
6163         return res;
6164 }
6165
6166 #define MAX_ARCH_DELEGATE_PARAMS 10
6167
6168 static gpointer
6169 get_delegate_invoke_impl (gboolean has_target, guint32 param_count, guint32 *code_len)
6170 {
6171         guint8 *code, *start;
6172         int code_reserve = 64;
6173
6174         /*
6175          * The stack contains:
6176          * <delegate>
6177          * <return addr>
6178          */
6179
6180         if (has_target) {
6181                 start = code = mono_global_codeman_reserve (code_reserve);
6182
6183                 /* Replace the this argument with the target */
6184                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
6185                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
6186                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
6187                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
6188
6189                 g_assert ((code - start) < code_reserve);
6190         } else {
6191                 int i = 0;
6192                 /* 8 for mov_reg and jump, plus 8 for each parameter */
6193 #ifdef __native_client_codegen__
6194                 /* TODO: calculate this size correctly */
6195                 code_reserve = 13 + (param_count * 8) + 2 * kNaClAlignment;
6196 #else
6197                 code_reserve = 8 + (param_count * 8);
6198 #endif  /* __native_client_codegen__ */
6199                 /*
6200                  * The stack contains:
6201                  * <args in reverse order>
6202                  * <delegate>
6203                  * <return addr>
6204                  *
6205                  * and we need:
6206                  * <args in reverse order>
6207                  * <return addr>
6208                  * 
6209                  * without unbalancing the stack.
6210                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
6211                  * and leaving original spot of first arg as placeholder in stack so
6212                  * when callee pops stack everything works.
6213                  */
6214
6215                 start = code = mono_global_codeman_reserve (code_reserve);
6216
6217                 /* store delegate for access to method_ptr */
6218                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
6219
6220                 /* move args up */
6221                 for (i = 0; i < param_count; ++i) {
6222                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
6223                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
6224                 }
6225
6226                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
6227
6228                 g_assert ((code - start) < code_reserve);
6229         }
6230
6231         nacl_global_codeman_validate(&start, code_reserve, &code);
6232         mono_debug_add_delegate_trampoline (start, code - start);
6233
6234         if (code_len)
6235                 *code_len = code - start;
6236
6237         if (mono_jit_map_is_enabled ()) {
6238                 char *buff;
6239                 if (has_target)
6240                         buff = (char*)"delegate_invoke_has_target";
6241                 else
6242                         buff = g_strdup_printf ("delegate_invoke_no_target_%d", param_count);
6243                 mono_emit_jit_tramp (start, code - start, buff);
6244                 if (!has_target)
6245                         g_free (buff);
6246         }
6247
6248         return start;
6249 }
6250
6251 GSList*
6252 mono_arch_get_delegate_invoke_impls (void)
6253 {
6254         GSList *res = NULL;
6255         guint8 *code;
6256         guint32 code_len;
6257         int i;
6258
6259         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
6260         res = g_slist_prepend (res, mono_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len, NULL, NULL));
6261
6262         for (i = 0; i < MAX_ARCH_DELEGATE_PARAMS; ++i) {
6263                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
6264                 res = g_slist_prepend (res, mono_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len, NULL, NULL));
6265         }
6266
6267         return res;
6268 }
6269
6270 gpointer
6271 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
6272 {
6273         guint8 *code, *start;
6274
6275         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
6276                 return NULL;
6277
6278         /* FIXME: Support more cases */
6279         if (MONO_TYPE_ISSTRUCT (sig->ret))
6280                 return NULL;
6281
6282         /*
6283          * The stack contains:
6284          * <delegate>
6285          * <return addr>
6286          */
6287
6288         if (has_target) {
6289                 static guint8* cached = NULL;
6290                 if (cached)
6291                         return cached;
6292
6293                 if (mono_aot_only)
6294                         start = mono_aot_get_trampoline ("delegate_invoke_impl_has_target");
6295                 else
6296                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
6297
6298                 mono_memory_barrier ();
6299
6300                 cached = start;
6301         } else {
6302                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
6303                 int i = 0;
6304
6305                 for (i = 0; i < sig->param_count; ++i)
6306                         if (!mono_is_regsize_var (sig->params [i]))
6307                                 return NULL;
6308
6309                 code = cache [sig->param_count];
6310                 if (code)
6311                         return code;
6312
6313                 if (mono_aot_only) {
6314                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
6315                         start = mono_aot_get_trampoline (name);
6316                         g_free (name);
6317                 } else {
6318                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
6319                 }
6320
6321                 mono_memory_barrier ();
6322
6323                 cache [sig->param_count] = start;
6324         }
6325
6326         return start;
6327 }
6328
6329 mgreg_t
6330 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
6331 {
6332         switch (reg) {
6333         case X86_EAX: return ctx->eax;
6334         case X86_EBX: return ctx->ebx;
6335         case X86_ECX: return ctx->ecx;
6336         case X86_EDX: return ctx->edx;
6337         case X86_ESP: return ctx->esp;
6338         case X86_EBP: return ctx->ebp;
6339         case X86_ESI: return ctx->esi;
6340         case X86_EDI: return ctx->edi;
6341         default:
6342                 g_assert_not_reached ();
6343                 return 0;
6344         }
6345 }
6346
6347 void
6348 mono_arch_context_set_int_reg (MonoContext *ctx, int reg, mgreg_t val)
6349 {
6350         switch (reg) {
6351         case X86_EAX:
6352                 ctx->eax = val;
6353                 break;
6354         case X86_EBX:
6355                 ctx->ebx = val;
6356                 break;
6357         case X86_ECX:
6358                 ctx->ecx = val;
6359                 break;
6360         case X86_EDX:
6361                 ctx->edx = val;
6362                 break;
6363         case X86_ESP:
6364                 ctx->esp = val;
6365                 break;
6366         case X86_EBP:
6367                 ctx->ebp = val;
6368                 break;
6369         case X86_ESI:
6370                 ctx->esi = val;
6371                 break;
6372         case X86_EDI:
6373                 ctx->edi = val;
6374                 break;
6375         default:
6376                 g_assert_not_reached ();
6377         }
6378 }
6379
6380 #ifdef MONO_ARCH_SIMD_INTRINSICS
6381
6382 static MonoInst*
6383 get_float_to_x_spill_area (MonoCompile *cfg)
6384 {
6385         if (!cfg->fconv_to_r8_x_var) {
6386                 cfg->fconv_to_r8_x_var = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
6387                 cfg->fconv_to_r8_x_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
6388         }       
6389         return cfg->fconv_to_r8_x_var;
6390 }
6391
6392 /*
6393  * Convert all fconv opts that MONO_OPT_SSE2 would get wrong. 
6394  */
6395 void
6396 mono_arch_decompose_opts (MonoCompile *cfg, MonoInst *ins)
6397 {
6398         MonoInst *fconv;
6399         int dreg, src_opcode;
6400
6401         if (!(cfg->opt & MONO_OPT_SSE2) || !(cfg->opt & MONO_OPT_SIMD) || COMPILE_LLVM (cfg))
6402                 return;
6403
6404         switch (src_opcode = ins->opcode) {
6405         case OP_FCONV_TO_I1:
6406         case OP_FCONV_TO_U1:
6407         case OP_FCONV_TO_I2:
6408         case OP_FCONV_TO_U2:
6409         case OP_FCONV_TO_I4:
6410         case OP_FCONV_TO_I:
6411                 break;
6412         default:
6413                 return;
6414         }
6415
6416         /* dreg is the IREG and sreg1 is the FREG */
6417         MONO_INST_NEW (cfg, fconv, OP_FCONV_TO_R8_X);
6418         fconv->klass = NULL; /*FIXME, what can I use here as the Mono.Simd lib might not be loaded yet*/
6419         fconv->sreg1 = ins->sreg1;
6420         fconv->dreg = mono_alloc_ireg (cfg);
6421         fconv->type = STACK_VTYPE;
6422         fconv->backend.spill_var = get_float_to_x_spill_area (cfg);
6423
6424         mono_bblock_insert_before_ins (cfg->cbb, ins, fconv);
6425
6426         dreg = ins->dreg;
6427         NULLIFY_INS (ins);
6428         ins->opcode = OP_XCONV_R8_TO_I4;
6429
6430         ins->klass = mono_defaults.int32_class;
6431         ins->sreg1 = fconv->dreg;
6432         ins->dreg = dreg;
6433         ins->type = STACK_I4;
6434         ins->backend.source_opcode = src_opcode;
6435 }
6436
6437 #endif /* #ifdef MONO_ARCH_SIMD_INTRINSICS */
6438
6439 void
6440 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
6441 {
6442         MonoInst *ins;
6443         int vreg;
6444
6445         if (long_ins->opcode == OP_LNEG) {
6446                 ins = long_ins;
6447                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 1, ins->sreg1 + 1);
6448                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
6449                 MONO_EMIT_NEW_UNALU (cfg, OP_INEG, ins->dreg + 2, ins->dreg + 2);
6450                 NULLIFY_INS (ins);
6451                 return;
6452         }
6453
6454 #ifdef MONO_ARCH_SIMD_INTRINSICS
6455
6456         if (!(cfg->opt & MONO_OPT_SIMD))
6457                 return;
6458         
6459         /*TODO move this to simd-intrinsic.c once we support sse 4.1 dword extractors since we need the runtime caps info */ 
6460         switch (long_ins->opcode) {
6461         case OP_EXTRACT_I8:
6462                 vreg = long_ins->sreg1;
6463         
6464                 if (long_ins->inst_c0) {
6465                         MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6466                         ins->klass = long_ins->klass;
6467                         ins->sreg1 = long_ins->sreg1;
6468                         ins->inst_c0 = 2;
6469                         ins->type = STACK_VTYPE;
6470                         ins->dreg = vreg = alloc_ireg (cfg);
6471                         MONO_ADD_INS (cfg->cbb, ins);
6472                 }
6473         
6474                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6475                 ins->klass = mono_defaults.int32_class;
6476                 ins->sreg1 = vreg;
6477                 ins->type = STACK_I4;
6478                 ins->dreg = long_ins->dreg + 1;
6479                 MONO_ADD_INS (cfg->cbb, ins);
6480         
6481                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6482                 ins->klass = long_ins->klass;
6483                 ins->sreg1 = long_ins->sreg1;
6484                 ins->inst_c0 = long_ins->inst_c0 ? 3 : 1;
6485                 ins->type = STACK_VTYPE;
6486                 ins->dreg = vreg = alloc_ireg (cfg);
6487                 MONO_ADD_INS (cfg->cbb, ins);
6488         
6489                 MONO_INST_NEW (cfg, ins, OP_EXTRACT_I4);
6490                 ins->klass = mono_defaults.int32_class;
6491                 ins->sreg1 = vreg;
6492                 ins->type = STACK_I4;
6493                 ins->dreg = long_ins->dreg + 2;
6494                 MONO_ADD_INS (cfg->cbb, ins);
6495         
6496                 long_ins->opcode = OP_NOP;
6497                 break;
6498         case OP_INSERTX_I8_SLOW:
6499                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6500                 ins->dreg = long_ins->dreg;
6501                 ins->sreg1 = long_ins->dreg;
6502                 ins->sreg2 = long_ins->sreg2 + 1;
6503                 ins->inst_c0 = long_ins->inst_c0 * 2;
6504                 MONO_ADD_INS (cfg->cbb, ins);
6505
6506                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6507                 ins->dreg = long_ins->dreg;
6508                 ins->sreg1 = long_ins->dreg;
6509                 ins->sreg2 = long_ins->sreg2 + 2;
6510                 ins->inst_c0 = long_ins->inst_c0 * 2 + 1;
6511                 MONO_ADD_INS (cfg->cbb, ins);
6512
6513                 long_ins->opcode = OP_NOP;
6514                 break;
6515         case OP_EXPAND_I8:
6516                 MONO_INST_NEW (cfg, ins, OP_ICONV_TO_X);
6517                 ins->dreg = long_ins->dreg;
6518                 ins->sreg1 = long_ins->sreg1 + 1;
6519                 ins->klass = long_ins->klass;
6520                 ins->type = STACK_VTYPE;
6521                 MONO_ADD_INS (cfg->cbb, ins);
6522
6523                 MONO_INST_NEW (cfg, ins, OP_INSERTX_I4_SLOW);
6524                 ins->dreg = long_ins->dreg;
6525                 ins->sreg1 = long_ins->dreg;
6526                 ins->sreg2 = long_ins->sreg1 + 2;
6527                 ins->inst_c0 = 1;
6528                 ins->klass = long_ins->klass;
6529                 ins->type = STACK_VTYPE;
6530                 MONO_ADD_INS (cfg->cbb, ins);
6531
6532                 MONO_INST_NEW (cfg, ins, OP_PSHUFLED);
6533                 ins->dreg = long_ins->dreg;
6534                 ins->sreg1 = long_ins->dreg;;
6535                 ins->inst_c0 = 0x44; /*Magic number for swizzling (X,Y,X,Y)*/
6536                 ins->klass = long_ins->klass;
6537                 ins->type = STACK_VTYPE;
6538                 MONO_ADD_INS (cfg->cbb, ins);
6539
6540                 long_ins->opcode = OP_NOP;
6541                 break;
6542         }
6543 #endif /* MONO_ARCH_SIMD_INTRINSICS */
6544 }
6545
6546 /*MONO_ARCH_HAVE_HANDLER_BLOCK_GUARD*/
6547 gpointer
6548 mono_arch_install_handler_block_guard (MonoJitInfo *ji, MonoJitExceptionInfo *clause, MonoContext *ctx, gpointer new_value)
6549 {
6550         int offset;
6551         gpointer *sp, old_value;
6552         char *bp;
6553         const unsigned char *handler;
6554
6555         /*Decode the first instruction to figure out where did we store the spvar*/
6556         /*Our jit MUST generate the following:
6557          mov %esp, -?(%ebp)
6558          Which is encoded as: 0x89 mod_rm.
6559          mod_rm (esp, ebp, imm) which can be: (imm will never be zero)
6560                 mod (reg + imm8):  01 reg(esp): 100 rm(ebp): 101 -> 01100101 (0x65)
6561                 mod (reg + imm32): 10 reg(esp): 100 rm(ebp): 101 -> 10100101 (0xA5)
6562         */
6563         handler = clause->handler_start;
6564
6565         if (*handler != 0x89)
6566                 return NULL;
6567
6568         ++handler;
6569
6570         if (*handler == 0x65)
6571                 offset = *(signed char*)(handler + 1);
6572         else if (*handler == 0xA5)
6573                 offset = *(int*)(handler + 1);
6574         else
6575                 return NULL;
6576
6577         /*Load the spvar*/
6578         bp = MONO_CONTEXT_GET_BP (ctx);
6579         sp = *(gpointer*)(bp + offset);
6580
6581         old_value = *sp;
6582         if (old_value < ji->code_start || (char*)old_value > ((char*)ji->code_start + ji->code_size))
6583                 return old_value;
6584
6585         *sp = new_value;
6586
6587         return old_value;
6588 }
6589
6590 /*
6591  * mono_aot_emit_load_got_addr:
6592  *
6593  *   Emit code to load the got address.
6594  * On x86, the result is placed into EBX.
6595  */
6596 guint8*
6597 mono_arch_emit_load_got_addr (guint8 *start, guint8 *code, MonoCompile *cfg, MonoJumpInfo **ji)
6598 {
6599         x86_call_imm (code, 0);
6600         /* 
6601          * The patch needs to point to the pop, since the GOT offset needs 
6602          * to be added to that address.
6603          */
6604         if (cfg)
6605                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6606         else
6607                 *ji = mono_patch_info_list_prepend (*ji, code - start, MONO_PATCH_INFO_GOT_OFFSET, NULL);
6608         x86_pop_reg (code, MONO_ARCH_GOT_REG);
6609         x86_alu_reg_imm (code, X86_ADD, MONO_ARCH_GOT_REG, 0xf0f0f0f0);
6610
6611         return code;
6612 }
6613
6614 /*
6615  * mono_ppc_emit_load_aotconst:
6616  *
6617  *   Emit code to load the contents of the GOT slot identified by TRAMP_TYPE and
6618  * TARGET from the mscorlib GOT in full-aot code.
6619  * On x86, the GOT address is assumed to be in EBX, and the result is placed into 
6620  * EAX.
6621  */
6622 guint8*
6623 mono_arch_emit_load_aotconst (guint8 *start, guint8 *code, MonoJumpInfo **ji, int tramp_type, gconstpointer target)
6624 {
6625         /* Load the mscorlib got address */
6626         x86_mov_reg_membase (code, X86_EAX, MONO_ARCH_GOT_REG, sizeof (gpointer), 4);
6627         *ji = mono_patch_info_list_prepend (*ji, code - start, tramp_type, target);
6628         /* arch_emit_got_access () patches this */
6629         x86_mov_reg_membase (code, X86_EAX, X86_EAX, 0xf0f0f0f0, 4);
6630
6631         return code;
6632 }
6633
6634 /* Can't put this into mini-x86.h */
6635 gpointer
6636 mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot);
6637
6638 GSList *
6639 mono_arch_get_trampolines (gboolean aot)
6640 {
6641         MonoTrampInfo *info;
6642         GSList *tramps = NULL;
6643
6644         mono_x86_get_signal_exception_trampoline (&info, aot);
6645
6646         tramps = g_slist_append (tramps, info);
6647
6648         return tramps;
6649 }
6650
6651
6652 #if __APPLE__
6653 #define DBG_SIGNAL SIGBUS
6654 #else
6655 #define DBG_SIGNAL SIGSEGV
6656 #endif
6657
6658 /* Soft Debug support */
6659 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
6660
6661 /*
6662  * mono_arch_set_breakpoint:
6663  *
6664  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
6665  * The location should contain code emitted by OP_SEQ_POINT.
6666  */
6667 void
6668 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
6669 {
6670         guint8 *code = ip;
6671
6672         /* 
6673          * In production, we will use int3 (has to fix the size in the md 
6674          * file). But that could confuse gdb, so during development, we emit a SIGSEGV
6675          * instead.
6676          */
6677         g_assert (code [0] == 0x90);
6678         x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)bp_trigger_page);
6679 }
6680
6681 /*
6682  * mono_arch_clear_breakpoint:
6683  *
6684  *   Clear the breakpoint at IP.
6685  */
6686 void
6687 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
6688 {
6689         guint8 *code = ip;
6690         int i;
6691
6692         for (i = 0; i < 6; ++i)
6693                 x86_nop (code);
6694 }
6695         
6696 /*
6697  * mono_arch_start_single_stepping:
6698  *
6699  *   Start single stepping.
6700  */
6701 void
6702 mono_arch_start_single_stepping (void)
6703 {
6704         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
6705 }
6706         
6707 /*
6708  * mono_arch_stop_single_stepping:
6709  *
6710  *   Stop single stepping.
6711  */
6712 void
6713 mono_arch_stop_single_stepping (void)
6714 {
6715         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
6716 }
6717
6718 /*
6719  * mono_arch_is_single_step_event:
6720  *
6721  *   Return whenever the machine state in SIGCTX corresponds to a single
6722  * step event.
6723  */
6724 gboolean
6725 mono_arch_is_single_step_event (void *info, void *sigctx)
6726 {
6727 #ifdef TARGET_WIN32
6728         EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* Sometimes the address is off by 4 */
6729
6730         if ((einfo->ExceptionInformation[1] >= ss_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)ss_trigger_page + 128))
6731                 return TRUE;
6732         else
6733                 return FALSE;
6734 #else
6735         siginfo_t* sinfo = (siginfo_t*) info;
6736         /* Sometimes the address is off by 4 */
6737         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128))
6738                 return TRUE;
6739         else
6740                 return FALSE;
6741 #endif
6742 }
6743
6744 gboolean
6745 mono_arch_is_breakpoint_event (void *info, void *sigctx)
6746 {
6747 #ifdef TARGET_WIN32
6748         EXCEPTION_RECORD* einfo = ((EXCEPTION_POINTERS*)info)->ExceptionRecord; /* Sometimes the address is off by 4 */
6749         if ((einfo->ExceptionInformation[1] >= bp_trigger_page && (guint8*)einfo->ExceptionInformation[1] <= (guint8*)bp_trigger_page + 128))
6750                 return TRUE;
6751         else
6752                 return FALSE;
6753 #else
6754         siginfo_t* sinfo = (siginfo_t*)info;
6755         /* Sometimes the address is off by 4 */
6756         if (sinfo->si_signo == DBG_SIGNAL && (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128))
6757                 return TRUE;
6758         else
6759                 return FALSE;
6760 #endif
6761 }
6762
6763 #define BREAKPOINT_SIZE 6
6764
6765 /*
6766  * mono_arch_skip_breakpoint:
6767  *
6768  *   See mini-amd64.c for docs.
6769  */
6770 void
6771 mono_arch_skip_breakpoint (MonoContext *ctx, MonoJitInfo *ji)
6772 {
6773         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + BREAKPOINT_SIZE);
6774 }
6775
6776 /*
6777  * mono_arch_skip_single_step:
6778  *
6779  *   See mini-amd64.c for docs.
6780  */
6781 void
6782 mono_arch_skip_single_step (MonoContext *ctx)
6783 {
6784         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 6);
6785 }
6786
6787 /*
6788  * mono_arch_get_seq_point_info:
6789  *
6790  *   See mini-amd64.c for docs.
6791  */
6792 gpointer
6793 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
6794 {
6795         NOT_IMPLEMENTED;
6796         return NULL;
6797 }
6798
6799 #endif
6800
6801 #if defined(MONOTOUCH) || defined(MONO_EXTENSIONS)
6802
6803 #include "../../../mono-extensions/mono/mini/mini-x86-gsharedvt.c"
6804
6805 #endif /* !MONOTOUCH */