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