2008-10-03 Mark Probst <mark.probst@gmail.com>
[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  * (C) 2003 Ximian, Inc.
10  */
11 #include "mini.h"
12 #include <string.h>
13 #include <math.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/mono-debug.h>
23 #include <mono/utils/mono-math.h>
24 #include <mono/utils/mono-counters.h>
25
26 #include "trace.h"
27 #include "mini-x86.h"
28 #include "inssel.h"
29 #include "cpu-x86.h"
30
31 /* On windows, these hold the key returned by TlsAlloc () */
32 static gint lmf_tls_offset = -1;
33 static gint lmf_addr_tls_offset = -1;
34 static gint appdomain_tls_offset = -1;
35 static gint thread_tls_offset = -1;
36
37 #ifdef MONO_XEN_OPT
38 static gboolean optimize_for_xen = TRUE;
39 #else
40 #define optimize_for_xen 0
41 #endif
42
43 #ifdef PLATFORM_WIN32
44 static gboolean is_win32 = TRUE;
45 #else
46 static gboolean is_win32 = FALSE;
47 #endif
48
49 /* This mutex protects architecture specific caches */
50 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
51 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
52 static CRITICAL_SECTION mini_arch_mutex;
53
54 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
55
56 #define ARGS_OFFSET 8
57
58 #ifdef PLATFORM_WIN32
59 /* Under windows, the default pinvoke calling convention is stdcall */
60 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
61 #else
62 #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL)
63 #endif
64
65 MonoBreakpointInfo
66 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
67
68 const char*
69 mono_arch_regname (int reg)
70 {
71         switch (reg) {
72         case X86_EAX: return "%eax";
73         case X86_EBX: return "%ebx";
74         case X86_ECX: return "%ecx";
75         case X86_EDX: return "%edx";
76         case X86_ESP: return "%esp";    
77         case X86_EBP: return "%ebp";
78         case X86_EDI: return "%edi";
79         case X86_ESI: return "%esi";
80         }
81         return "unknown";
82 }
83
84 const char*
85 mono_arch_fregname (int reg)
86 {
87         switch (reg) {
88         case 0:
89                 return "%fr0";
90         case 1:
91                 return "%fr1";
92         case 2:
93                 return "%fr2";
94         case 3:
95                 return "%fr3";
96         case 4:
97                 return "%fr4";
98         case 5:
99                 return "%fr5";
100         case 6:
101                 return "%fr6";
102         case 7:
103                 return "%fr7";
104         default:
105                 return "unknown";
106         }
107 }
108
109 const char *
110 mono_arch_xregname (int reg)
111 {
112         switch (reg) {
113         case 0:
114                 return "%xmm0";
115         case 1:
116                 return "%xmm1";
117         case 2:
118                 return "%xmm2";
119         case 3:
120                 return "%xmm3";
121         case 4:
122                 return "%xmm4";
123         case 5:
124                 return "%xmm5";
125         case 6:
126                 return "%xmm6";
127         case 7:
128                 return "%xmm7";
129         default:
130                 return "unknown";
131         }
132 }
133
134
135 typedef enum {
136         ArgInIReg,
137         ArgInFloatSSEReg,
138         ArgInDoubleSSEReg,
139         ArgOnStack,
140         ArgValuetypeInReg,
141         ArgOnFloatFpStack,
142         ArgOnDoubleFpStack,
143         ArgNone
144 } ArgStorage;
145
146 typedef struct {
147         gint16 offset;
148         gint8  reg;
149         ArgStorage storage;
150
151         /* Only if storage == ArgValuetypeInReg */
152         ArgStorage pair_storage [2];
153         gint8 pair_regs [2];
154 } ArgInfo;
155
156 typedef struct {
157         int nargs;
158         guint32 stack_usage;
159         guint32 reg_usage;
160         guint32 freg_usage;
161         gboolean need_stack_align;
162         guint32 stack_align_amount;
163         ArgInfo ret;
164         ArgInfo sig_cookie;
165         ArgInfo args [1];
166 } CallInfo;
167
168 #define PARAM_REGS 0
169
170 #define FLOAT_PARAM_REGS 0
171
172 static X86_Reg_No param_regs [] = { 0 };
173
174 #if defined(PLATFORM_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
175 #define SMALL_STRUCTS_IN_REGS
176 static X86_Reg_No return_regs [] = { X86_EAX, X86_EDX };
177 #endif
178
179 static void inline
180 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
181 {
182     ainfo->offset = *stack_size;
183
184     if (*gr >= PARAM_REGS) {
185                 ainfo->storage = ArgOnStack;
186                 (*stack_size) += sizeof (gpointer);
187     }
188     else {
189                 ainfo->storage = ArgInIReg;
190                 ainfo->reg = param_regs [*gr];
191                 (*gr) ++;
192     }
193 }
194
195 static void inline
196 add_general_pair (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
197 {
198         ainfo->offset = *stack_size;
199
200         g_assert (PARAM_REGS == 0);
201         
202         ainfo->storage = ArgOnStack;
203         (*stack_size) += sizeof (gpointer) * 2;
204 }
205
206 static void inline
207 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
208 {
209     ainfo->offset = *stack_size;
210
211     if (*gr >= FLOAT_PARAM_REGS) {
212                 ainfo->storage = ArgOnStack;
213                 (*stack_size) += is_double ? 8 : 4;
214     }
215     else {
216                 /* A double register */
217                 if (is_double)
218                         ainfo->storage = ArgInDoubleSSEReg;
219                 else
220                         ainfo->storage = ArgInFloatSSEReg;
221                 ainfo->reg = *gr;
222                 (*gr) += 1;
223     }
224 }
225
226
227 static void
228 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
229                gboolean is_return,
230                guint32 *gr, guint32 *fr, guint32 *stack_size)
231 {
232         guint32 size;
233         MonoClass *klass;
234
235         klass = mono_class_from_mono_type (type);
236         size = mini_type_stack_size_full (gsctx, &klass->byval_arg, NULL, sig->pinvoke);
237
238 #ifdef SMALL_STRUCTS_IN_REGS
239         if (sig->pinvoke && is_return) {
240                 MonoMarshalType *info;
241
242                 /*
243                  * the exact rules are not very well documented, the code below seems to work with the 
244                  * code generated by gcc 3.3.3 -mno-cygwin.
245                  */
246                 info = mono_marshal_load_type_info (klass);
247                 g_assert (info);
248
249                 ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
250
251                 /* Special case structs with only a float member */
252                 if ((info->native_size == 8) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R8)) {
253                         ainfo->storage = ArgValuetypeInReg;
254                         ainfo->pair_storage [0] = ArgOnDoubleFpStack;
255                         return;
256                 }
257                 if ((info->native_size == 4) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R4)) {
258                         ainfo->storage = ArgValuetypeInReg;
259                         ainfo->pair_storage [0] = ArgOnFloatFpStack;
260                         return;
261                 }               
262                 if ((info->native_size == 1) || (info->native_size == 2) || (info->native_size == 4) || (info->native_size == 8)) {
263                         ainfo->storage = ArgValuetypeInReg;
264                         ainfo->pair_storage [0] = ArgInIReg;
265                         ainfo->pair_regs [0] = return_regs [0];
266                         if (info->native_size > 4) {
267                                 ainfo->pair_storage [1] = ArgInIReg;
268                                 ainfo->pair_regs [1] = return_regs [1];
269                         }
270                         return;
271                 }
272         }
273 #endif
274
275         ainfo->offset = *stack_size;
276         ainfo->storage = ArgOnStack;
277         *stack_size += ALIGN_TO (size, sizeof (gpointer));
278 }
279
280 /*
281  * get_call_info:
282  *
283  *  Obtain information about a call according to the calling convention.
284  * For x86 ELF, see the "System V Application Binary Interface Intel386 
285  * Architecture Processor Supplment, Fourth Edition" document for more
286  * information.
287  * For x86 win32, see ???.
288  */
289 static CallInfo*
290 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
291 {
292         guint32 i, gr, fr;
293         MonoType *ret_type;
294         int n = sig->hasthis + sig->param_count;
295         guint32 stack_size = 0;
296         CallInfo *cinfo;
297
298         if (mp)
299                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
300         else
301                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
302
303         gr = 0;
304         fr = 0;
305
306         /* return value */
307         {
308                 ret_type = mini_type_get_underlying_type (gsctx, sig->ret);
309                 switch (ret_type->type) {
310                 case MONO_TYPE_BOOLEAN:
311                 case MONO_TYPE_I1:
312                 case MONO_TYPE_U1:
313                 case MONO_TYPE_I2:
314                 case MONO_TYPE_U2:
315                 case MONO_TYPE_CHAR:
316                 case MONO_TYPE_I4:
317                 case MONO_TYPE_U4:
318                 case MONO_TYPE_I:
319                 case MONO_TYPE_U:
320                 case MONO_TYPE_PTR:
321                 case MONO_TYPE_FNPTR:
322                 case MONO_TYPE_CLASS:
323                 case MONO_TYPE_OBJECT:
324                 case MONO_TYPE_SZARRAY:
325                 case MONO_TYPE_ARRAY:
326                 case MONO_TYPE_STRING:
327                         cinfo->ret.storage = ArgInIReg;
328                         cinfo->ret.reg = X86_EAX;
329                         break;
330                 case MONO_TYPE_U8:
331                 case MONO_TYPE_I8:
332                         cinfo->ret.storage = ArgInIReg;
333                         cinfo->ret.reg = X86_EAX;
334                         break;
335                 case MONO_TYPE_R4:
336                         cinfo->ret.storage = ArgOnFloatFpStack;
337                         break;
338                 case MONO_TYPE_R8:
339                         cinfo->ret.storage = ArgOnDoubleFpStack;
340                         break;
341                 case MONO_TYPE_GENERICINST:
342                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
343                                 cinfo->ret.storage = ArgInIReg;
344                                 cinfo->ret.reg = X86_EAX;
345                                 break;
346                         }
347                         /* Fall through */
348                 case MONO_TYPE_VALUETYPE: {
349                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
350
351                         add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
352                         if (cinfo->ret.storage == ArgOnStack)
353                                 /* The caller passes the address where the value is stored */
354                                 add_general (&gr, &stack_size, &cinfo->ret);
355                         break;
356                 }
357                 case MONO_TYPE_TYPEDBYREF:
358                         /* Same as a valuetype with size 24 */
359                         add_general (&gr, &stack_size, &cinfo->ret);
360                         ;
361                         break;
362                 case MONO_TYPE_VOID:
363                         cinfo->ret.storage = ArgNone;
364                         break;
365                 default:
366                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
367                 }
368         }
369
370         /* this */
371         if (sig->hasthis)
372                 add_general (&gr, &stack_size, cinfo->args + 0);
373
374         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
375                 gr = PARAM_REGS;
376                 fr = FLOAT_PARAM_REGS;
377                 
378                 /* Emit the signature cookie just before the implicit arguments */
379                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
380         }
381
382         for (i = 0; i < sig->param_count; ++i) {
383                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
384                 MonoType *ptype;
385
386                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
387                         /* We allways pass the sig cookie on the stack for simplicity */
388                         /* 
389                          * Prevent implicit arguments + the sig cookie from being passed 
390                          * in registers.
391                          */
392                         gr = PARAM_REGS;
393                         fr = FLOAT_PARAM_REGS;
394
395                         /* Emit the signature cookie just before the implicit arguments */
396                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
397                 }
398
399                 if (sig->params [i]->byref) {
400                         add_general (&gr, &stack_size, ainfo);
401                         continue;
402                 }
403                 ptype = mini_type_get_underlying_type (gsctx, sig->params [i]);
404                 switch (ptype->type) {
405                 case MONO_TYPE_BOOLEAN:
406                 case MONO_TYPE_I1:
407                 case MONO_TYPE_U1:
408                         add_general (&gr, &stack_size, ainfo);
409                         break;
410                 case MONO_TYPE_I2:
411                 case MONO_TYPE_U2:
412                 case MONO_TYPE_CHAR:
413                         add_general (&gr, &stack_size, ainfo);
414                         break;
415                 case MONO_TYPE_I4:
416                 case MONO_TYPE_U4:
417                         add_general (&gr, &stack_size, ainfo);
418                         break;
419                 case MONO_TYPE_I:
420                 case MONO_TYPE_U:
421                 case MONO_TYPE_PTR:
422                 case MONO_TYPE_FNPTR:
423                 case MONO_TYPE_CLASS:
424                 case MONO_TYPE_OBJECT:
425                 case MONO_TYPE_STRING:
426                 case MONO_TYPE_SZARRAY:
427                 case MONO_TYPE_ARRAY:
428                         add_general (&gr, &stack_size, ainfo);
429                         break;
430                 case MONO_TYPE_GENERICINST:
431                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
432                                 add_general (&gr, &stack_size, ainfo);
433                                 break;
434                         }
435                         /* Fall through */
436                 case MONO_TYPE_VALUETYPE:
437                         add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
438                         break;
439                 case MONO_TYPE_TYPEDBYREF:
440                         stack_size += sizeof (MonoTypedRef);
441                         ainfo->storage = ArgOnStack;
442                         break;
443                 case MONO_TYPE_U8:
444                 case MONO_TYPE_I8:
445                         add_general_pair (&gr, &stack_size, ainfo);
446                         break;
447                 case MONO_TYPE_R4:
448                         add_float (&fr, &stack_size, ainfo, FALSE);
449                         break;
450                 case MONO_TYPE_R8:
451                         add_float (&fr, &stack_size, ainfo, TRUE);
452                         break;
453                 default:
454                         g_error ("unexpected type 0x%x", ptype->type);
455                         g_assert_not_reached ();
456                 }
457         }
458
459         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
460                 gr = PARAM_REGS;
461                 fr = FLOAT_PARAM_REGS;
462                 
463                 /* Emit the signature cookie just before the implicit arguments */
464                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
465         }
466
467 #if defined(__APPLE__)
468         if ((stack_size % 16) != 0) { 
469                 cinfo->need_stack_align = TRUE;
470                 stack_size += cinfo->stack_align_amount = 16-(stack_size % 16);
471         }
472 #endif
473
474         cinfo->stack_usage = stack_size;
475         cinfo->reg_usage = gr;
476         cinfo->freg_usage = fr;
477         return cinfo;
478 }
479
480 /*
481  * mono_arch_get_argument_info:
482  * @csig:  a method signature
483  * @param_count: the number of parameters to consider
484  * @arg_info: an array to store the result infos
485  *
486  * Gathers information on parameters such as size, alignment and
487  * padding. arg_info should be large enought to hold param_count + 1 entries. 
488  *
489  * Returns the size of the argument area on the stack.
490  */
491 int
492 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
493 {
494         int k, args_size = 0;
495         int size, pad;
496         guint32 align;
497         int offset = 8;
498         CallInfo *cinfo;
499
500         cinfo = get_call_info (NULL, NULL, csig, FALSE);
501
502         if (MONO_TYPE_ISSTRUCT (csig->ret) && (cinfo->ret.storage == ArgOnStack)) {
503                 args_size += sizeof (gpointer);
504                 offset += 4;
505         }
506
507         arg_info [0].offset = offset;
508
509         if (csig->hasthis) {
510                 args_size += sizeof (gpointer);
511                 offset += 4;
512         }
513
514         arg_info [0].size = args_size;
515
516         for (k = 0; k < param_count; k++) {
517                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
518
519                 /* ignore alignment for now */
520                 align = 1;
521
522                 args_size += pad = (align - (args_size & (align - 1))) & (align - 1);   
523                 arg_info [k].pad = pad;
524                 args_size += size;
525                 arg_info [k + 1].pad = 0;
526                 arg_info [k + 1].size = size;
527                 offset += pad;
528                 arg_info [k + 1].offset = offset;
529                 offset += size;
530         }
531
532         align = 4;
533         args_size += pad = (align - (args_size & (align - 1))) & (align - 1);
534         arg_info [k].pad = pad;
535
536         g_free (cinfo);
537
538         return args_size;
539 }
540
541 static const guchar cpuid_impl [] = {
542         0x55,                           /* push   %ebp */
543         0x89, 0xe5,                     /* mov    %esp,%ebp */
544         0x53,                           /* push   %ebx */
545         0x8b, 0x45, 0x08,               /* mov    0x8(%ebp),%eax */
546         0x0f, 0xa2,                     /* cpuid   */
547         0x50,                           /* push   %eax */
548         0x8b, 0x45, 0x10,               /* mov    0x10(%ebp),%eax */
549         0x89, 0x18,                     /* mov    %ebx,(%eax) */
550         0x8b, 0x45, 0x14,               /* mov    0x14(%ebp),%eax */
551         0x89, 0x08,                     /* mov    %ecx,(%eax) */
552         0x8b, 0x45, 0x18,               /* mov    0x18(%ebp),%eax */
553         0x89, 0x10,                     /* mov    %edx,(%eax) */
554         0x58,                           /* pop    %eax */
555         0x8b, 0x55, 0x0c,               /* mov    0xc(%ebp),%edx */
556         0x89, 0x02,                     /* mov    %eax,(%edx) */
557         0x5b,                           /* pop    %ebx */
558         0xc9,                           /* leave   */
559         0xc3,                           /* ret     */
560 };
561
562 typedef void (*CpuidFunc) (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx);
563
564 static int 
565 cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
566 {
567         int have_cpuid = 0;
568 #ifndef _MSC_VER
569         __asm__  __volatile__ (
570                 "pushfl\n"
571                 "popl %%eax\n"
572                 "movl %%eax, %%edx\n"
573                 "xorl $0x200000, %%eax\n"
574                 "pushl %%eax\n"
575                 "popfl\n"
576                 "pushfl\n"
577                 "popl %%eax\n"
578                 "xorl %%edx, %%eax\n"
579                 "andl $0x200000, %%eax\n"
580                 "movl %%eax, %0"
581                 : "=r" (have_cpuid)
582                 :
583                 : "%eax", "%edx"
584         );
585 #else
586         __asm {
587                 pushfd
588                 pop eax
589                 mov edx, eax
590                 xor eax, 0x200000
591                 push eax
592                 popfd
593                 pushfd
594                 pop eax
595                 xor eax, edx
596                 and eax, 0x200000
597                 mov have_cpuid, eax
598         }
599 #endif
600         if (have_cpuid) {
601                 /* Have to use the code manager to get around WinXP DEP */
602                 static CpuidFunc func = NULL;
603                 void *ptr;
604                 if (!func) {
605                         ptr = mono_global_codeman_reserve (sizeof (cpuid_impl));
606                         memcpy (ptr, cpuid_impl, sizeof (cpuid_impl));
607                         func = (CpuidFunc)ptr;
608                 }
609                 func (id, p_eax, p_ebx, p_ecx, p_edx);
610
611                 /*
612                  * We use this approach because of issues with gcc and pic code, see:
613                  * http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view%20audit-trail&database=gcc&pr=7329
614                 __asm__ __volatile__ ("cpuid"
615                         : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
616                         : "a" (id));
617                 */
618                 return 1;
619         }
620         return 0;
621 }
622
623 /*
624  * Initialize the cpu to execute managed code.
625  */
626 void
627 mono_arch_cpu_init (void)
628 {
629         /* spec compliance requires running with double precision */
630 #ifndef _MSC_VER
631         guint16 fpcw;
632
633         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
634         fpcw &= ~X86_FPCW_PRECC_MASK;
635         fpcw |= X86_FPCW_PREC_DOUBLE;
636         __asm__  __volatile__ ("fldcw %0\n": : "m" (fpcw));
637         __asm__  __volatile__ ("fnstcw %0\n": "=m" (fpcw));
638 #else
639         _control87 (_PC_53, MCW_PC);
640 #endif
641 }
642
643 /*
644  * Initialize architecture specific code.
645  */
646 void
647 mono_arch_init (void)
648 {
649         InitializeCriticalSection (&mini_arch_mutex);
650 }
651
652 /*
653  * Cleanup architecture specific code.
654  */
655 void
656 mono_arch_cleanup (void)
657 {
658         DeleteCriticalSection (&mini_arch_mutex);
659 }
660
661 /*
662  * This function returns the optimizations supported on this cpu.
663  */
664 guint32
665 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
666 {
667         int eax, ebx, ecx, edx;
668         guint32 opts = 0;
669         
670         *exclude_mask = 0;
671         /* Feature Flags function, flags returned in EDX. */
672         if (cpuid (1, &eax, &ebx, &ecx, &edx)) {
673                 if (edx & (1 << 15)) {
674                         opts |= MONO_OPT_CMOV;
675                         if (edx & 1)
676                                 opts |= MONO_OPT_FCMOV;
677                         else
678                                 *exclude_mask |= MONO_OPT_FCMOV;
679                 } else
680                         *exclude_mask |= MONO_OPT_CMOV;
681                 if (edx & (1 << 26))
682                         opts |= MONO_OPT_SSE2;
683                 else
684                         *exclude_mask |= MONO_OPT_SSE2;
685 #ifdef MONO_ARCH_SIMD_INTRINSICS
686                 /*SIMD intrinsics require SSE3.*/
687                 if (!(ecx & 1))
688                         *exclude_mask |= MONO_OPT_SIMD;
689 #endif
690         }
691         return opts;
692 }
693
694 /*
695  * Determine whenever the trap whose info is in SIGINFO is caused by
696  * integer overflow.
697  */
698 gboolean
699 mono_arch_is_int_overflow (void *sigctx, void *info)
700 {
701         MonoContext ctx;
702         guint8* ip;
703
704         mono_arch_sigctx_to_monoctx (sigctx, &ctx);
705
706         ip = (guint8*)ctx.eip;
707
708         if ((ip [0] == 0xf7) && (x86_modrm_mod (ip [1]) == 0x3) && (x86_modrm_reg (ip [1]) == 0x7)) {
709                 gint32 reg;
710
711                 /* idiv REG */
712                 switch (x86_modrm_rm (ip [1])) {
713                 case X86_EAX:
714                         reg = ctx.eax;
715                         break;
716                 case X86_ECX:
717                         reg = ctx.ecx;
718                         break;
719                 case X86_EDX:
720                         reg = ctx.edx;
721                         break;
722                 case X86_EBX:
723                         reg = ctx.ebx;
724                         break;
725                 case X86_ESI:
726                         reg = ctx.esi;
727                         break;
728                 case X86_EDI:
729                         reg = ctx.edi;
730                         break;
731                 default:
732                         g_assert_not_reached ();
733                         reg = -1;
734                 }
735
736                 if (reg == -1)
737                         return TRUE;
738         }
739                         
740         return FALSE;
741 }
742
743 GList *
744 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
745 {
746         GList *vars = NULL;
747         int i;
748
749         for (i = 0; i < cfg->num_varinfo; i++) {
750                 MonoInst *ins = cfg->varinfo [i];
751                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
752
753                 /* unused vars */
754                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
755                         continue;
756
757                 if ((ins->flags & (MONO_INST_IS_DEAD|MONO_INST_VOLATILE|MONO_INST_INDIRECT)) || 
758                     (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
759                         continue;
760
761                 /* we dont allocate I1 to registers because there is no simply way to sign extend 
762                  * 8bit quantities in caller saved registers on x86 */
763                 if (mono_is_regsize_var (ins->inst_vtype) && (ins->inst_vtype->type != MONO_TYPE_I1)) {
764                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
765                         g_assert (i == vmv->idx);
766                         vars = g_list_prepend (vars, vmv);
767                 }
768         }
769
770         vars = mono_varlist_sort (cfg, vars, 0);
771
772         return vars;
773 }
774
775 GList *
776 mono_arch_get_global_int_regs (MonoCompile *cfg)
777 {
778         GList *regs = NULL;
779
780         /* we can use 3 registers for global allocation */
781         regs = g_list_prepend (regs, (gpointer)X86_EBX);
782         regs = g_list_prepend (regs, (gpointer)X86_ESI);
783         regs = g_list_prepend (regs, (gpointer)X86_EDI);
784
785         return regs;
786 }
787
788 /*
789  * mono_arch_regalloc_cost:
790  *
791  *  Return the cost, in number of memory references, of the action of 
792  * allocating the variable VMV into a register during global register
793  * allocation.
794  */
795 guint32
796 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
797 {
798         MonoInst *ins = cfg->varinfo [vmv->idx];
799
800         if (cfg->method->save_lmf)
801                 /* The register is already saved */
802                 return (ins->opcode == OP_ARG) ? 1 : 0;
803         else
804                 /* push+pop+possible load if it is an argument */
805                 return (ins->opcode == OP_ARG) ? 3 : 2;
806 }
807  
808 /*
809  * Set var information according to the calling convention. X86 version.
810  * The locals var stuff should most likely be split in another method.
811  */
812 void
813 mono_arch_allocate_vars (MonoCompile *cfg)
814 {
815         MonoMethodSignature *sig;
816         MonoMethodHeader *header;
817         MonoInst *inst;
818         guint32 locals_stack_size, locals_stack_align;
819         int i, offset;
820         gint32 *offsets;
821         CallInfo *cinfo;
822
823         header = mono_method_get_header (cfg->method);
824         sig = mono_method_signature (cfg->method);
825
826         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
827
828         cfg->frame_reg = MONO_ARCH_BASEREG;
829         offset = 0;
830
831         /* Reserve space to save LMF and caller saved registers */
832
833         if (cfg->method->save_lmf) {
834                 offset += sizeof (MonoLMF);
835         } else {
836                 if (cfg->used_int_regs & (1 << X86_EBX)) {
837                         offset += 4;
838                 }
839
840                 if (cfg->used_int_regs & (1 << X86_EDI)) {
841                         offset += 4;
842                 }
843
844                 if (cfg->used_int_regs & (1 << X86_ESI)) {
845                         offset += 4;
846                 }
847         }
848
849         switch (cinfo->ret.storage) {
850         case ArgValuetypeInReg:
851                 /* Allocate a local to hold the result, the epilog will copy it to the correct place */
852                 offset += 8;
853                 cfg->ret->opcode = OP_REGOFFSET;
854                 cfg->ret->inst_basereg = X86_EBP;
855                 cfg->ret->inst_offset = - offset;
856                 break;
857         default:
858                 break;
859         }
860
861         /* Allocate locals */
862         offsets = mono_allocate_stack_slots (cfg, &locals_stack_size, &locals_stack_align);
863         if (locals_stack_align) {
864                 offset += (locals_stack_align - 1);
865                 offset &= ~(locals_stack_align - 1);
866         }
867         for (i = cfg->locals_start; i < cfg->num_varinfo; i++) {
868                 if (offsets [i] != -1) {
869                         MonoInst *inst = cfg->varinfo [i];
870                         inst->opcode = OP_REGOFFSET;
871                         inst->inst_basereg = X86_EBP;
872                         inst->inst_offset = - (offset + offsets [i]);
873                         //printf ("allocated local %d to ", i); mono_print_tree_nl (inst);
874                 }
875         }
876         offset += locals_stack_size;
877
878
879         /*
880          * Allocate arguments+return value
881          */
882
883         switch (cinfo->ret.storage) {
884         case ArgOnStack:
885                 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
886                         /* 
887                          * In the new IR, the cfg->vret_addr variable represents the
888                          * vtype return value.
889                          */
890                         cfg->vret_addr->opcode = OP_REGOFFSET;
891                         cfg->vret_addr->inst_basereg = cfg->frame_reg;
892                         cfg->vret_addr->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
893                         if (G_UNLIKELY (cfg->verbose_level > 1)) {
894                                 printf ("vret_addr =");
895                                 mono_print_ins (cfg->vret_addr);
896                         }
897                 } else {
898                         cfg->ret->opcode = OP_REGOFFSET;
899                         cfg->ret->inst_basereg = X86_EBP;
900                         cfg->ret->inst_offset = cinfo->ret.offset + ARGS_OFFSET;
901                 }
902                 break;
903         case ArgValuetypeInReg:
904                 break;
905         case ArgInIReg:
906                 cfg->ret->opcode = OP_REGVAR;
907                 cfg->ret->inst_c0 = cinfo->ret.reg;
908                 cfg->ret->dreg = cinfo->ret.reg;
909                 break;
910         case ArgNone:
911         case ArgOnFloatFpStack:
912         case ArgOnDoubleFpStack:
913                 break;
914         default:
915                 g_assert_not_reached ();
916         }
917
918         if (sig->call_convention == MONO_CALL_VARARG) {
919                 g_assert (cinfo->sig_cookie.storage == ArgOnStack);
920                 cfg->sig_cookie = cinfo->sig_cookie.offset + ARGS_OFFSET;
921         }
922
923         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
924                 ArgInfo *ainfo = &cinfo->args [i];
925                 inst = cfg->args [i];
926                 if (inst->opcode != OP_REGVAR) {
927                         inst->opcode = OP_REGOFFSET;
928                         inst->inst_basereg = X86_EBP;
929                 }
930                 inst->inst_offset = ainfo->offset + ARGS_OFFSET;
931         }
932
933         offset += (MONO_ARCH_FRAME_ALIGNMENT - 1);
934         offset &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
935
936         cfg->stack_offset = offset;
937 }
938
939 void
940 mono_arch_create_vars (MonoCompile *cfg)
941 {
942         MonoMethodSignature *sig;
943         CallInfo *cinfo;
944
945         sig = mono_method_signature (cfg->method);
946
947         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
948
949         if (cinfo->ret.storage == ArgValuetypeInReg)
950                 cfg->ret_var_is_local = TRUE;
951         if ((cinfo->ret.storage != ArgValuetypeInReg) && MONO_TYPE_ISSTRUCT (sig->ret)) {
952                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
953         }
954 }
955
956 static void
957 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call)
958 {
959         MonoInst *arg;
960         MonoMethodSignature *tmp_sig;
961         MonoInst *sig_arg;
962
963         /* FIXME: Add support for signature tokens to AOT */
964         cfg->disable_aot = TRUE;
965         MONO_INST_NEW (cfg, arg, OP_OUTARG);
966
967         /*
968          * mono_ArgIterator_Setup assumes the signature cookie is 
969          * passed first and all the arguments which were before it are
970          * passed on the stack after the signature. So compensate by 
971          * passing a different signature.
972          */
973         tmp_sig = mono_metadata_signature_dup (call->signature);
974         tmp_sig->param_count -= call->signature->sentinelpos;
975         tmp_sig->sentinelpos = 0;
976         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
977
978         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
979         sig_arg->inst_p0 = tmp_sig;
980
981         arg->inst_left = sig_arg;
982         arg->type = STACK_PTR;
983         /* prepend, so they get reversed */
984         arg->next = call->out_args;
985         call->out_args = arg;
986 }
987
988 /*
989  * It is expensive to adjust esp for each individual fp argument pushed on the stack
990  * so we try to do it just once when we have multiple fp arguments in a row.
991  * We don't use this mechanism generally because for int arguments the generated code
992  * is slightly bigger and new generation cpus optimize away the dependency chains
993  * created by push instructions on the esp value.
994  * fp_arg_setup is the first argument in the execution sequence where the esp register
995  * is modified.
996  */
997 static int
998 collect_fp_stack_space (MonoMethodSignature *sig, int start_arg, int *fp_arg_setup)
999 {
1000         int fp_space = 0;
1001         MonoType *t;
1002
1003         for (; start_arg < sig->param_count; ++start_arg) {
1004                 t = mini_type_get_underlying_type (NULL, sig->params [start_arg]);
1005                 if (!t->byref && t->type == MONO_TYPE_R8) {
1006                         fp_space += sizeof (double);
1007                         *fp_arg_setup = start_arg;
1008                 } else {
1009                         break;
1010                 }
1011         }
1012         return fp_space;
1013 }
1014
1015 /* 
1016  * take the arguments and generate the arch-specific
1017  * instructions to properly call the function in call.
1018  * This includes pushing, moving arguments to the right register
1019  * etc.
1020  */
1021 MonoCallInst*
1022 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
1023         MonoInst *arg, *in;
1024         MonoMethodSignature *sig;
1025         int i, n;
1026         CallInfo *cinfo;
1027         int sentinelpos = 0;
1028         int fp_args_space = 0, fp_args_offset = 0, fp_arg_setup = -1;
1029
1030         sig = call->signature;
1031         n = sig->param_count + sig->hasthis;
1032
1033         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
1034
1035         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1036                 sentinelpos = sig->sentinelpos + (is_virtual ? 1 : 0);
1037
1038         for (i = 0; i < n; ++i) {
1039                 ArgInfo *ainfo = cinfo->args + i;
1040
1041                 /* Emit the signature cookie just before the implicit arguments */
1042                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) {
1043                         emit_sig_cookie (cfg, call);
1044                 }
1045
1046                 if (is_virtual && i == 0) {
1047                         /* the argument will be attached to the call instrucion */
1048                         in = call->args [i];
1049                 } else {
1050                         MonoType *t;
1051
1052                         if (i >= sig->hasthis)
1053                                 t = sig->params [i - sig->hasthis];
1054                         else
1055                                 t = &mono_defaults.int_class->byval_arg;
1056                         t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1057
1058                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1059                         in = call->args [i];
1060                         arg->cil_code = in->cil_code;
1061                         arg->inst_left = in;
1062                         arg->type = in->type;
1063                         /* prepend, so they get reversed */
1064                         arg->next = call->out_args;
1065                         call->out_args = arg;
1066
1067                         if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
1068                                 gint align;
1069                                 guint32 ialign;
1070                                 guint32 size;
1071
1072                                 if (t->type == MONO_TYPE_TYPEDBYREF) {
1073                                         size = sizeof (MonoTypedRef);
1074                                         align = sizeof (gpointer);
1075                                 }
1076                                 else {
1077                                         size = mini_type_stack_size_full (cfg->generic_sharing_context, &in->klass->byval_arg, &ialign, sig->pinvoke);
1078                                 }
1079                                 arg->opcode = OP_OUTARG_VT;
1080                                 arg->klass = in->klass;
1081                                 arg->backend.is_pinvoke = sig->pinvoke;
1082                                 arg->inst_imm = size; 
1083                         }
1084                         else {
1085                                 switch (ainfo->storage) {
1086                                 case ArgOnStack:
1087                                         arg->opcode = OP_OUTARG;
1088                                         if (!t->byref) {
1089                                                 if (t->type == MONO_TYPE_R4) {
1090                                                         arg->opcode = OP_OUTARG_R4;
1091                                                 } else if (t->type == MONO_TYPE_R8) {
1092                                                         arg->opcode = OP_OUTARG_R8;
1093                                                         /* we store in the upper bits of backen.arg_info the needed
1094                                                          * esp adjustment and in the lower bits the offset from esp
1095                                                          * where the arg needs to be stored
1096                                                          */
1097                                                         if (!fp_args_space) {
1098                                                                 fp_args_space = collect_fp_stack_space (sig, i - sig->hasthis, &fp_arg_setup);
1099                                                                 fp_args_offset = fp_args_space;
1100                                                         }
1101                                                         arg->backend.arg_info = fp_args_space - fp_args_offset;
1102                                                         fp_args_offset -= sizeof (double);
1103                                                         if (i - sig->hasthis == fp_arg_setup) {
1104                                                                 arg->backend.arg_info |= fp_args_space << 16;
1105                                                         }
1106                                                         if (fp_args_offset == 0) {
1107                                                                 /* the allocated esp stack is finished:
1108                                                                  * prepare for an eventual second run of fp args
1109                                                                  */
1110                                                                 fp_args_space = 0;
1111                                                         }
1112                                                 }
1113                                         }
1114                                         break;
1115                                 default:
1116                                         g_assert_not_reached ();
1117                                 }
1118                         }
1119                 }
1120         }
1121
1122         /* Handle the case where there are no implicit arguments */
1123         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) {
1124                 emit_sig_cookie (cfg, call);
1125         }
1126
1127         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1128                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1129                         MonoInst *zero_inst;
1130                         /*
1131                          * After the call, the struct is in registers, but needs to be saved to the memory pointed
1132                          * to by vt_arg in this_vret_args. This means that vt_arg needs to be saved somewhere
1133                          * before calling the function. So we add a dummy instruction to represent pushing the 
1134                          * struct return address to the stack. The return address will be saved to this stack slot 
1135                          * by the code emitted in this_vret_args.
1136                          */
1137                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
1138                         MONO_INST_NEW (cfg, zero_inst, OP_ICONST);
1139                         zero_inst->inst_p0 = 0;
1140                         arg->inst_left = zero_inst;
1141                         arg->type = STACK_PTR;
1142                         /* prepend, so they get reversed */
1143                         arg->next = call->out_args;
1144                         call->out_args = arg;
1145                 }
1146                 else
1147                         /* if the function returns a struct, the called method already does a ret $0x4 */
1148                         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret))
1149                                 cinfo->stack_usage -= 4;
1150         }
1151
1152         call->stack_usage = cinfo->stack_usage;
1153
1154 #if defined(__APPLE__)
1155         if (cinfo->need_stack_align) {
1156                 MONO_INST_NEW (cfg, arg, OP_X86_OUTARG_ALIGN_STACK);
1157                 arg->inst_c0 = cinfo->stack_align_amount;
1158                 arg->next = call->out_args;
1159                 call->out_args = arg;
1160         }
1161 #endif 
1162
1163         return call;
1164 }
1165
1166 static void
1167 emit_sig_cookie2 (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1168 {
1169         MonoMethodSignature *tmp_sig;
1170
1171         /* FIXME: Add support for signature tokens to AOT */
1172         cfg->disable_aot = TRUE;
1173
1174         /*
1175          * mono_ArgIterator_Setup assumes the signature cookie is 
1176          * passed first and all the arguments which were before it are
1177          * passed on the stack after the signature. So compensate by 
1178          * passing a different signature.
1179          */
1180         tmp_sig = mono_metadata_signature_dup (call->signature);
1181         tmp_sig->param_count -= call->signature->sentinelpos;
1182         tmp_sig->sentinelpos = 0;
1183         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1184
1185         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_X86_PUSH_IMM, -1, -1, tmp_sig);
1186 }
1187
1188 void
1189 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1190 {
1191         MonoInst *arg, *in;
1192         MonoMethodSignature *sig;
1193         int i, n;
1194         CallInfo *cinfo;
1195         int sentinelpos = 0;
1196
1197         sig = call->signature;
1198         n = sig->param_count + sig->hasthis;
1199
1200         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
1201
1202         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG))
1203                 sentinelpos = sig->sentinelpos + (sig->hasthis ? 1 : 0);
1204
1205 #if defined(__APPLE__)
1206         if (cinfo->need_stack_align) {
1207                 MONO_INST_NEW (cfg, arg, OP_SUB_IMM);
1208                 arg->dreg = X86_ESP;
1209                 arg->sreg1 = X86_ESP;
1210                 arg->inst_imm = cinfo->stack_align_amount;
1211                 MONO_ADD_INS (cfg->cbb, arg);
1212         }
1213 #endif 
1214
1215         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1216                 MonoInst *vtarg;
1217
1218                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1219                         if (cinfo->ret.pair_storage [0] == ArgInIReg && cinfo->ret.pair_storage [1] == ArgNone) {
1220                                 /*
1221                                  * Tell the JIT to use a more efficient calling convention: call using
1222                                  * OP_CALL, compute the result location after the call, and save the 
1223                                  * result there.
1224                                  */
1225                                 call->vret_in_reg = TRUE;
1226                         } else {
1227                                 /*
1228                                  * The valuetype is in EAX:EDX after the call, needs to be copied to
1229                                  * the stack. Save the address here, so the call instruction can
1230                                  * access it.
1231                                  */
1232                                 MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1233                                 vtarg->sreg1 = call->vret_var->dreg;
1234                                 MONO_ADD_INS (cfg->cbb, vtarg);
1235                         }
1236                 }
1237         }
1238
1239         /* Handle the case where there are no implicit arguments */
1240         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sentinelpos)) {
1241                 emit_sig_cookie2 (cfg, call, cinfo);
1242         }
1243
1244         /* Arguments are pushed in the reverse order */
1245         for (i = n - 1; i >= 0; i --) {
1246                 ArgInfo *ainfo = cinfo->args + i;
1247                 MonoType *t;
1248
1249                 if (i >= sig->hasthis)
1250                         t = sig->params [i - sig->hasthis];
1251                 else
1252                         t = &mono_defaults.int_class->byval_arg;
1253                 t = mini_type_get_underlying_type (cfg->generic_sharing_context, t);
1254
1255                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH);
1256
1257                 in = call->args [i];
1258                 arg->cil_code = in->cil_code;
1259                 arg->sreg1 = in->dreg;
1260                 arg->type = in->type;
1261
1262                 g_assert (in->dreg != -1);
1263
1264                 if ((i >= sig->hasthis) && (MONO_TYPE_ISSTRUCT(t))) {
1265                         guint32 align;
1266                         guint32 size;
1267
1268                         g_assert (in->klass);
1269
1270                         if (t->type == MONO_TYPE_TYPEDBYREF) {
1271                                 size = sizeof (MonoTypedRef);
1272                                 align = sizeof (gpointer);
1273                         }
1274                         else {
1275                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, &in->klass->byval_arg, &align, sig->pinvoke);
1276                         }
1277
1278                         if (size > 0) {
1279                                 arg->opcode = OP_OUTARG_VT;
1280                                 arg->sreg1 = in->dreg;
1281                                 arg->klass = in->klass;
1282                                 arg->backend.size = size;
1283
1284                                 MONO_ADD_INS (cfg->cbb, arg);
1285                         }
1286                 }
1287                 else {
1288                         switch (ainfo->storage) {
1289                         case ArgOnStack:
1290                                 arg->opcode = OP_X86_PUSH;
1291                                 if (!t->byref) {
1292                                         if (t->type == MONO_TYPE_R4) {
1293                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 4);
1294                                                 arg->opcode = OP_STORER4_MEMBASE_REG;
1295                                                 arg->inst_destbasereg = X86_ESP;
1296                                                 arg->inst_offset = 0;
1297                                         } else if (t->type == MONO_TYPE_R8) {
1298                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, 8);
1299                                                 arg->opcode = OP_STORER8_MEMBASE_REG;
1300                                                 arg->inst_destbasereg = X86_ESP;
1301                                                 arg->inst_offset = 0;
1302                                         } else if (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8) {
1303                                                 arg->sreg1 ++;
1304                                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_PUSH, -1, in->dreg + 2);
1305                                         }
1306                                 }
1307                                 break;
1308                         default:
1309                                 g_assert_not_reached ();
1310                         }
1311                         
1312                         MONO_ADD_INS (cfg->cbb, arg);
1313                 }
1314
1315                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sentinelpos)) {
1316                         /* Emit the signature cookie just before the implicit arguments */
1317                         emit_sig_cookie2 (cfg, call, cinfo);
1318                 }
1319         }
1320
1321         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1322                 MonoInst *vtarg;
1323
1324                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1325                         /* Already done */
1326                 }
1327                 else if (cinfo->ret.storage == ArgInIReg) {
1328                         NOT_IMPLEMENTED;
1329                         /* The return address is passed in a register */
1330                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1331                         vtarg->sreg1 = call->inst.dreg;
1332                         vtarg->dreg = mono_regstate_next_int (cfg->rs);
1333                         MONO_ADD_INS (cfg->cbb, vtarg);
1334                                 
1335                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
1336                 } else {
1337                         MonoInst *vtarg;
1338                         MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1339                         vtarg->type = STACK_MP;
1340                         vtarg->sreg1 = call->vret_var->dreg;
1341                         MONO_ADD_INS (cfg->cbb, vtarg);
1342                 }
1343
1344                 /* if the function returns a struct, the called method already does a ret $0x4 */
1345                 cinfo->stack_usage -= 4;
1346         }
1347
1348         call->stack_usage = cinfo->stack_usage;
1349 }
1350
1351 void
1352 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1353 {
1354         MonoInst *arg;
1355         int size = ins->backend.size;
1356
1357         if (size <= 4) {
1358                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_MEMBASE);
1359                 arg->sreg1 = src->dreg;
1360
1361                 MONO_ADD_INS (cfg->cbb, arg);
1362         } else if (size <= 20) {        
1363                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SUB_IMM, X86_ESP, X86_ESP, ALIGN_TO (size, 4));
1364                 mini_emit_memcpy2 (cfg, X86_ESP, 0, src->dreg, 0, size, 4);
1365         } else {
1366                 MONO_INST_NEW (cfg, arg, OP_X86_PUSH_OBJ);
1367                 arg->inst_basereg = src->dreg;
1368                 arg->inst_offset = 0;
1369                 arg->inst_imm = size;
1370                                         
1371                 MONO_ADD_INS (cfg->cbb, arg);
1372         }
1373 }
1374
1375 void
1376 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1377 {
1378         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1379
1380         if (!ret->byref) {
1381                 if (ret->type == MONO_TYPE_R4) {
1382                         /* Nothing to do */
1383                         return;
1384                 } else if (ret->type == MONO_TYPE_R8) {
1385                         /* Nothing to do */
1386                         return;
1387                 } else if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1388                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EAX, val->dreg + 1);
1389                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, X86_EDX, val->dreg + 2);
1390                         return;
1391                 }
1392         }
1393                         
1394         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1395 }
1396
1397 /*
1398  * Allow tracing to work with this interface (with an optional argument)
1399  */
1400 void*
1401 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1402 {
1403         guchar *code = p;
1404
1405 #if __APPLE__
1406         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1407 #endif
1408
1409         /* if some args are passed in registers, we need to save them here */
1410         x86_push_reg (code, X86_EBP);
1411
1412         if (cfg->compile_aot) {
1413                 x86_push_imm (code, cfg->method);
1414                 x86_mov_reg_imm (code, X86_EAX, func);
1415                 x86_call_reg (code, X86_EAX);
1416         } else {
1417                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, cfg->method);
1418                 x86_push_imm (code, cfg->method);
1419                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1420                 x86_call_code (code, 0);
1421         }
1422 #if __APPLE__
1423         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 16);
1424 #else
1425         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1426 #endif
1427
1428         return code;
1429 }
1430
1431 enum {
1432         SAVE_NONE,
1433         SAVE_STRUCT,
1434         SAVE_EAX,
1435         SAVE_EAX_EDX,
1436         SAVE_FP
1437 };
1438
1439 void*
1440 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1441 {
1442         guchar *code = p;
1443         int arg_size = 0, save_mode = SAVE_NONE;
1444         MonoMethod *method = cfg->method;
1445         
1446         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type) {
1447         case MONO_TYPE_VOID:
1448                 /* special case string .ctor icall */
1449                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1450                         save_mode = SAVE_EAX;
1451                 else
1452                         save_mode = SAVE_NONE;
1453                 break;
1454         case MONO_TYPE_I8:
1455         case MONO_TYPE_U8:
1456                 save_mode = SAVE_EAX_EDX;
1457                 break;
1458         case MONO_TYPE_R4:
1459         case MONO_TYPE_R8:
1460                 save_mode = SAVE_FP;
1461                 break;
1462         case MONO_TYPE_GENERICINST:
1463                 if (!mono_type_generic_inst_is_valuetype (mono_method_signature (method)->ret)) {
1464                         save_mode = SAVE_EAX;
1465                         break;
1466                 }
1467                 /* Fall through */
1468         case MONO_TYPE_VALUETYPE:
1469                 save_mode = SAVE_STRUCT;
1470                 break;
1471         default:
1472                 save_mode = SAVE_EAX;
1473                 break;
1474         }
1475
1476         switch (save_mode) {
1477         case SAVE_EAX_EDX:
1478                 x86_push_reg (code, X86_EDX);
1479                 x86_push_reg (code, X86_EAX);
1480                 if (enable_arguments) {
1481                         x86_push_reg (code, X86_EDX);
1482                         x86_push_reg (code, X86_EAX);
1483                         arg_size = 8;
1484                 }
1485                 break;
1486         case SAVE_EAX:
1487                 x86_push_reg (code, X86_EAX);
1488                 if (enable_arguments) {
1489                         x86_push_reg (code, X86_EAX);
1490                         arg_size = 4;
1491                 }
1492                 break;
1493         case SAVE_FP:
1494                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1495                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1496                 if (enable_arguments) {
1497                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1498                         x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1499                         arg_size = 8;
1500                 }
1501                 break;
1502         case SAVE_STRUCT:
1503                 if (enable_arguments) {
1504                         x86_push_membase (code, X86_EBP, 8);
1505                         arg_size = 4;
1506                 }
1507                 break;
1508         case SAVE_NONE:
1509         default:
1510                 break;
1511         }
1512
1513         if (cfg->compile_aot) {
1514                 x86_push_imm (code, method);
1515                 x86_mov_reg_imm (code, X86_EAX, func);
1516                 x86_call_reg (code, X86_EAX);
1517         } else {
1518                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_METHODCONST, method);
1519                 x86_push_imm (code, method);
1520                 mono_add_patch_info (cfg, code-cfg->native_code, MONO_PATCH_INFO_ABS, func);
1521                 x86_call_code (code, 0);
1522         }
1523         x86_alu_reg_imm (code, X86_ADD, X86_ESP, arg_size + 4);
1524
1525         switch (save_mode) {
1526         case SAVE_EAX_EDX:
1527                 x86_pop_reg (code, X86_EAX);
1528                 x86_pop_reg (code, X86_EDX);
1529                 break;
1530         case SAVE_EAX:
1531                 x86_pop_reg (code, X86_EAX);
1532                 break;
1533         case SAVE_FP:
1534                 x86_fld_membase (code, X86_ESP, 0, TRUE);
1535                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1536                 break;
1537         case SAVE_NONE:
1538         default:
1539                 break;
1540         }
1541
1542         return code;
1543 }
1544
1545 #define EMIT_COND_BRANCH(ins,cond,sign) \
1546 if (ins->flags & MONO_INST_BRLABEL) { \
1547         if (ins->inst_i0->inst_c0) { \
1548                 x86_branch (code, cond, cfg->native_code + ins->inst_i0->inst_c0, sign); \
1549         } else { \
1550                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
1551                 if ((cfg->opt & MONO_OPT_BRANCH) && \
1552                     x86_is_imm8 (ins->inst_i0->inst_c1 - cpos)) \
1553                         x86_branch8 (code, cond, 0, sign); \
1554                 else \
1555                         x86_branch32 (code, cond, 0, sign); \
1556         } \
1557 } else { \
1558         if (ins->inst_true_bb->native_offset) { \
1559                 x86_branch (code, cond, cfg->native_code + ins->inst_true_bb->native_offset, sign); \
1560         } else { \
1561                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
1562                 if ((cfg->opt & MONO_OPT_BRANCH) && \
1563                     x86_is_imm8 (ins->inst_true_bb->max_offset - cpos)) \
1564                         x86_branch8 (code, cond, 0, sign); \
1565                 else \
1566                         x86_branch32 (code, cond, 0, sign); \
1567         } \
1568 }
1569
1570 /*  
1571  *      Emit an exception if condition is fail and
1572  *  if possible do a directly branch to target 
1573  */
1574 #define EMIT_COND_SYSTEM_EXCEPTION(cond,signed,exc_name)            \
1575         do {                                                        \
1576                 MonoInst *tins = mono_branch_optimize_exception_target (cfg, bb, exc_name); \
1577                 if (tins == NULL) {                                                                             \
1578                         mono_add_patch_info (cfg, code - cfg->native_code,   \
1579                                         MONO_PATCH_INFO_EXC, exc_name);  \
1580                         x86_branch32 (code, cond, 0, signed);               \
1581                 } else {        \
1582                         EMIT_COND_BRANCH (tins, cond, signed);  \
1583                 }                       \
1584         } while (0); 
1585
1586 #define EMIT_FPCOMPARE(code) do { \
1587         x86_fcompp (code); \
1588         x86_fnstsw (code); \
1589 } while (0); 
1590
1591
1592 static guint8*
1593 emit_call (MonoCompile *cfg, guint8 *code, guint32 patch_type, gconstpointer data)
1594 {
1595         mono_add_patch_info (cfg, code - cfg->native_code, patch_type, data);
1596         x86_call_code (code, 0);
1597
1598         return code;
1599 }
1600
1601 #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)))
1602
1603 /*
1604  * mono_peephole_pass_1:
1605  *
1606  *   Perform peephole opts which should/can be performed before local regalloc
1607  */
1608 void
1609 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
1610 {
1611         MonoInst *ins, *n;
1612
1613         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1614                 MonoInst *last_ins = ins->prev;
1615
1616                 switch (ins->opcode) {
1617                 case OP_IADD_IMM:
1618                 case OP_ADD_IMM:
1619                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
1620                                 /* 
1621                                  * X86_LEA is like ADD, but doesn't have the
1622                                  * sreg1==dreg restriction.
1623                                  */
1624                                 ins->opcode = OP_X86_LEA_MEMBASE;
1625                                 ins->inst_basereg = ins->sreg1;
1626                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1627                                 ins->opcode = OP_X86_INC_REG;
1628                         break;
1629                 case OP_SUB_IMM:
1630                 case OP_ISUB_IMM:
1631                         if ((ins->sreg1 < MONO_MAX_IREGS) && (ins->dreg >= MONO_MAX_IREGS)) {
1632                                 ins->opcode = OP_X86_LEA_MEMBASE;
1633                                 ins->inst_basereg = ins->sreg1;
1634                                 ins->inst_imm = -ins->inst_imm;
1635                         } else if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1636                                 ins->opcode = OP_X86_DEC_REG;
1637                         break;
1638                 case OP_COMPARE_IMM:
1639                 case OP_ICOMPARE_IMM:
1640                         /* OP_COMPARE_IMM (reg, 0) 
1641                          * --> 
1642                          * OP_X86_TEST_NULL (reg) 
1643                          */
1644                         if (!ins->inst_imm)
1645                                 ins->opcode = OP_X86_TEST_NULL;
1646                         break;
1647                 case OP_X86_COMPARE_MEMBASE_IMM:
1648                         /* 
1649                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
1650                          * OP_X86_COMPARE_MEMBASE_IMM offset(basereg), imm
1651                          * -->
1652                          * OP_STORE_MEMBASE_REG reg, offset(basereg)
1653                          * OP_COMPARE_IMM reg, imm
1654                          *
1655                          * Note: if imm = 0 then OP_COMPARE_IMM replaced with OP_X86_TEST_NULL
1656                          */
1657                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG) &&
1658                             ins->inst_basereg == last_ins->inst_destbasereg &&
1659                             ins->inst_offset == last_ins->inst_offset) {
1660                                         ins->opcode = OP_COMPARE_IMM;
1661                                         ins->sreg1 = last_ins->sreg1;
1662
1663                                         /* check if we can remove cmp reg,0 with test null */
1664                                         if (!ins->inst_imm)
1665                                                 ins->opcode = OP_X86_TEST_NULL;
1666                                 }
1667
1668                         break;                  
1669                 case OP_X86_PUSH_MEMBASE:
1670                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG ||
1671                                          last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1672                             ins->inst_basereg == last_ins->inst_destbasereg &&
1673                             ins->inst_offset == last_ins->inst_offset) {
1674                                     ins->opcode = OP_X86_PUSH;
1675                                     ins->sreg1 = last_ins->sreg1;
1676                         }
1677                         break;
1678                 }
1679
1680                 mono_peephole_ins (bb, ins);
1681         }
1682 }
1683
1684 void
1685 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
1686 {
1687         MonoInst *ins, *n;
1688
1689         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
1690                 switch (ins->opcode) {
1691                 case OP_ICONST:
1692                         /* reg = 0 -> XOR (reg, reg) */
1693                         /* XOR sets cflags on x86, so we cant do it always */
1694                         if (ins->inst_c0 == 0 && (!ins->next || (ins->next && INST_IGNORES_CFLAGS (ins->next->opcode)))) {
1695                                 MonoInst *ins2;
1696
1697                                 ins->opcode = OP_IXOR;
1698                                 ins->sreg1 = ins->dreg;
1699                                 ins->sreg2 = ins->dreg;
1700
1701                                 /* 
1702                                  * Convert succeeding STORE_MEMBASE_IMM 0 ins to STORE_MEMBASE_REG 
1703                                  * since it takes 3 bytes instead of 7.
1704                                  */
1705                                 for (ins2 = ins->next; ins2; ins2 = ins2->next) {
1706                                         if ((ins2->opcode == OP_STORE_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
1707                                                 ins2->opcode = OP_STORE_MEMBASE_REG;
1708                                                 ins2->sreg1 = ins->dreg;
1709                                         }
1710                                         else if ((ins2->opcode == OP_STOREI4_MEMBASE_IMM) && (ins2->inst_imm == 0)) {
1711                                                 ins2->opcode = OP_STOREI4_MEMBASE_REG;
1712                                                 ins2->sreg1 = ins->dreg;
1713                                         }
1714                                         else if ((ins2->opcode == OP_STOREI1_MEMBASE_IMM) || (ins2->opcode == OP_STOREI2_MEMBASE_IMM)) {
1715                                                 /* Continue iteration */
1716                                         }
1717                                         else
1718                                                 break;
1719                                 }
1720                         }
1721                         break;
1722                 case OP_IADD_IMM:
1723                 case OP_ADD_IMM:
1724                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1725                                 ins->opcode = OP_X86_INC_REG;
1726                         break;
1727                 case OP_ISUB_IMM:
1728                 case OP_SUB_IMM:
1729                         if ((ins->inst_imm == 1) && (ins->dreg == ins->sreg1))
1730                                 ins->opcode = OP_X86_DEC_REG;
1731                         break;
1732                 }
1733
1734                 mono_peephole_ins (bb, ins);
1735         }
1736 }
1737
1738 /*
1739  * mono_arch_lowering_pass:
1740  *
1741  *  Converts complex opcodes into simpler ones so that each IR instruction
1742  * corresponds to one machine instruction.
1743  */
1744 void
1745 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1746 {
1747         MonoInst *ins, *next;
1748
1749         if (bb->max_vreg > cfg->rs->next_vreg)
1750                 cfg->rs->next_vreg = bb->max_vreg;
1751
1752         /*
1753          * FIXME: Need to add more instructions, but the current machine 
1754          * description can't model some parts of the composite instructions like
1755          * cdq.
1756          */
1757         MONO_BB_FOR_EACH_INS_SAFE (bb, next, ins) {
1758                 switch (ins->opcode) {
1759                 case OP_IREM_IMM:
1760                 case OP_IDIV_IMM:
1761                 case OP_IDIV_UN_IMM:
1762                 case OP_IREM_UN_IMM:
1763                         /* 
1764                          * Keep the cases where we could generated optimized code, otherwise convert
1765                          * to the non-imm variant.
1766                          */
1767                         if ((ins->opcode == OP_IREM_IMM) && mono_is_power_of_two (ins->inst_imm) >= 0)
1768                                 break;
1769                         mono_decompose_op_imm (cfg, bb, ins);
1770                         break;
1771                 default:
1772                         break;
1773                 }
1774         }
1775
1776         bb->max_vreg = cfg->rs->next_vreg;
1777 }
1778
1779 static const int 
1780 branch_cc_table [] = {
1781         X86_CC_EQ, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
1782         X86_CC_NE, X86_CC_GE, X86_CC_GT, X86_CC_LE, X86_CC_LT,
1783         X86_CC_O, X86_CC_NO, X86_CC_C, X86_CC_NC
1784 };
1785
1786 /* Maps CMP_... constants to X86_CC_... constants */
1787 static const int
1788 cc_table [] = {
1789         X86_CC_EQ, X86_CC_NE, X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT,
1790         X86_CC_LE, X86_CC_GE, X86_CC_LT, X86_CC_GT
1791 };
1792
1793 static const int
1794 cc_signed_table [] = {
1795         TRUE, TRUE, TRUE, TRUE, TRUE, TRUE,
1796         FALSE, FALSE, FALSE, FALSE
1797 };
1798
1799 static unsigned char*
1800 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int size, gboolean is_signed)
1801 {
1802 #define XMM_TEMP_REG 0
1803         if (cfg->opt & MONO_OPT_SSE2 && size < 8) {
1804                 /* optimize by assigning a local var for this use so we avoid
1805                  * the stack manipulations */
1806                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1807                 x86_fst_membase (code, X86_ESP, 0, TRUE, TRUE);
1808                 x86_movsd_reg_membase (code, XMM_TEMP_REG, X86_ESP, 0);
1809                 x86_cvttsd2si (code, dreg, XMM_TEMP_REG);
1810                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
1811                 if (size == 1)
1812                         x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
1813                 else if (size == 2)
1814                         x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
1815                 return code;
1816         }
1817         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
1818         x86_fnstcw_membase(code, X86_ESP, 0);
1819         x86_mov_reg_membase (code, dreg, X86_ESP, 0, 2);
1820         x86_alu_reg_imm (code, X86_OR, dreg, 0xc00);
1821         x86_mov_membase_reg (code, X86_ESP, 2, dreg, 2);
1822         x86_fldcw_membase (code, X86_ESP, 2);
1823         if (size == 8) {
1824                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1825                 x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
1826                 x86_pop_reg (code, dreg);
1827                 /* FIXME: need the high register 
1828                  * x86_pop_reg (code, dreg_high);
1829                  */
1830         } else {
1831                 x86_push_reg (code, X86_EAX); // SP = SP - 4
1832                 x86_fist_pop_membase (code, X86_ESP, 0, FALSE);
1833                 x86_pop_reg (code, dreg);
1834         }
1835         x86_fldcw_membase (code, X86_ESP, 0);
1836         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
1837
1838         if (size == 1)
1839                 x86_widen_reg (code, dreg, dreg, is_signed, FALSE);
1840         else if (size == 2)
1841                 x86_widen_reg (code, dreg, dreg, is_signed, TRUE);
1842         return code;
1843 }
1844
1845 static unsigned char*
1846 mono_emit_stack_alloc (guchar *code, MonoInst* tree)
1847 {
1848         int sreg = tree->sreg1;
1849         int need_touch = FALSE;
1850
1851 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
1852         need_touch = TRUE;
1853 #endif
1854
1855         if (need_touch) {
1856                 guint8* br[5];
1857
1858                 /*
1859                  * Under Windows:
1860                  * If requested stack size is larger than one page,
1861                  * perform stack-touch operation
1862                  */
1863                 /*
1864                  * Generate stack probe code.
1865                  * Under Windows, it is necessary to allocate one page at a time,
1866                  * "touching" stack after each successful sub-allocation. This is
1867                  * because of the way stack growth is implemented - there is a
1868                  * guard page before the lowest stack page that is currently commited.
1869                  * Stack normally grows sequentially so OS traps access to the
1870                  * guard page and commits more pages when needed.
1871                  */
1872                 x86_test_reg_imm (code, sreg, ~0xFFF);
1873                 br[0] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
1874
1875                 br[2] = code; /* loop */
1876                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
1877                 x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
1878
1879                 /* 
1880                  * By the end of the loop, sreg2 is smaller than 0x1000, so the init routine
1881                  * that follows only initializes the last part of the area.
1882                  */
1883                 /* Same as the init code below with size==0x1000 */
1884                 if (tree->flags & MONO_INST_INIT) {
1885                         x86_push_reg (code, X86_EAX);
1886                         x86_push_reg (code, X86_ECX);
1887                         x86_push_reg (code, X86_EDI);
1888                         x86_mov_reg_imm (code, X86_ECX, (0x1000 >> 2));
1889                         x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);                              
1890                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
1891                         x86_cld (code);
1892                         x86_prefix (code, X86_REP_PREFIX);
1893                         x86_stosl (code);
1894                         x86_pop_reg (code, X86_EDI);
1895                         x86_pop_reg (code, X86_ECX);
1896                         x86_pop_reg (code, X86_EAX);
1897                 }
1898
1899                 x86_alu_reg_imm (code, X86_SUB, sreg, 0x1000);
1900                 x86_alu_reg_imm (code, X86_CMP, sreg, 0x1000);
1901                 br[3] = code; x86_branch8 (code, X86_CC_AE, 0, FALSE);
1902                 x86_patch (br[3], br[2]);
1903                 x86_test_reg_reg (code, sreg, sreg);
1904                 br[4] = code; x86_branch8 (code, X86_CC_Z, 0, FALSE);
1905                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
1906
1907                 br[1] = code; x86_jump8 (code, 0);
1908
1909                 x86_patch (br[0], code);
1910                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, sreg);
1911                 x86_patch (br[1], code);
1912                 x86_patch (br[4], code);
1913         }
1914         else
1915                 x86_alu_reg_reg (code, X86_SUB, X86_ESP, tree->sreg1);
1916
1917         if (tree->flags & MONO_INST_INIT) {
1918                 int offset = 0;
1919                 if (tree->dreg != X86_EAX && sreg != X86_EAX) {
1920                         x86_push_reg (code, X86_EAX);
1921                         offset += 4;
1922                 }
1923                 if (tree->dreg != X86_ECX && sreg != X86_ECX) {
1924                         x86_push_reg (code, X86_ECX);
1925                         offset += 4;
1926                 }
1927                 if (tree->dreg != X86_EDI && sreg != X86_EDI) {
1928                         x86_push_reg (code, X86_EDI);
1929                         offset += 4;
1930                 }
1931                 
1932                 x86_shift_reg_imm (code, X86_SHR, sreg, 2);
1933                 if (sreg != X86_ECX)
1934                         x86_mov_reg_reg (code, X86_ECX, sreg, 4);
1935                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EAX);
1936                                 
1937                 x86_lea_membase (code, X86_EDI, X86_ESP, offset);
1938                 x86_cld (code);
1939                 x86_prefix (code, X86_REP_PREFIX);
1940                 x86_stosl (code);
1941                 
1942                 if (tree->dreg != X86_EDI && sreg != X86_EDI)
1943                         x86_pop_reg (code, X86_EDI);
1944                 if (tree->dreg != X86_ECX && sreg != X86_ECX)
1945                         x86_pop_reg (code, X86_ECX);
1946                 if (tree->dreg != X86_EAX && sreg != X86_EAX)
1947                         x86_pop_reg (code, X86_EAX);
1948         }
1949         return code;
1950 }
1951
1952
1953 static guint8*
1954 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
1955 {
1956         CallInfo *cinfo;
1957         int quad;
1958
1959         /* Move return value to the target register */
1960         switch (ins->opcode) {
1961         case OP_CALL:
1962         case OP_CALL_REG:
1963         case OP_CALL_MEMBASE:
1964                 if (ins->dreg != X86_EAX)
1965                         x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
1966                 break;
1967         case OP_VCALL:
1968         case OP_VCALL_REG:
1969         case OP_VCALL_MEMBASE:
1970         case OP_VCALL2:
1971         case OP_VCALL2_REG:
1972         case OP_VCALL2_MEMBASE:
1973                 cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
1974                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1975                         /* Pop the destination address from the stack */
1976                         x86_pop_reg (code, X86_ECX);
1977                         
1978                         for (quad = 0; quad < 2; quad ++) {
1979                                 switch (cinfo->ret.pair_storage [quad]) {
1980                                 case ArgInIReg:
1981                                         g_assert (cinfo->ret.pair_regs [quad] != X86_ECX);
1982                                         x86_mov_membase_reg (code, X86_ECX, (quad * sizeof (gpointer)), cinfo->ret.pair_regs [quad], sizeof (gpointer));
1983                                         break;
1984                                 case ArgNone:
1985                                         break;
1986                                 default:
1987                                         g_assert_not_reached ();
1988                                 }
1989                         }
1990                 }
1991                 break;
1992         case OP_FCALL: {
1993                 MonoCallInst *call = (MonoCallInst*)ins;
1994                 if (call->method && !mono_method_signature (call->method)->ret->byref && mono_method_signature (call->method)->ret->type == MONO_TYPE_R4) {
1995                         /* Avoid some precision issues by saving/reloading the return value */
1996                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
1997                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
1998                         x86_fld_membase (code, X86_ESP, 0, FALSE);
1999                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
2000                 }
2001                 break;
2002         }
2003         default:
2004                 break;
2005         }
2006
2007         return code;
2008 }
2009
2010 /*
2011  * emit_tls_get:
2012  * @code: buffer to store code to
2013  * @dreg: hard register where to place the result
2014  * @tls_offset: offset info
2015  *
2016  * emit_tls_get emits in @code the native code that puts in the dreg register
2017  * the item in the thread local storage identified by tls_offset.
2018  *
2019  * Returns: a pointer to the end of the stored code
2020  */
2021 static guint8*
2022 emit_tls_get (guint8* code, int dreg, int tls_offset)
2023 {
2024 #ifdef PLATFORM_WIN32
2025         /* 
2026          * See the Under the Hood article in the May 1996 issue of Microsoft Systems 
2027          * Journal and/or a disassembly of the TlsGet () function.
2028          */
2029         g_assert (tls_offset < 64);
2030         x86_prefix (code, X86_FS_PREFIX);
2031         x86_mov_reg_mem (code, dreg, 0x18, 4);
2032         /* Dunno what this does but TlsGetValue () contains it */
2033         x86_alu_membase_imm (code, X86_AND, dreg, 0x34, 0);
2034         x86_mov_reg_membase (code, dreg, dreg, 3600 + (tls_offset * 4), 4);
2035 #else
2036         if (optimize_for_xen) {
2037                 x86_prefix (code, X86_GS_PREFIX);
2038                 x86_mov_reg_mem (code, dreg, 0, 4);
2039                 x86_mov_reg_membase (code, dreg, dreg, tls_offset, 4);
2040         } else {
2041                 x86_prefix (code, X86_GS_PREFIX);
2042                 x86_mov_reg_mem (code, dreg, tls_offset, 4);
2043         }
2044 #endif
2045         return code;
2046 }
2047
2048 /*
2049  * emit_load_volatile_arguments:
2050  *
2051  *  Load volatile arguments from the stack to the original input registers.
2052  * Required before a tail call.
2053  */
2054 static guint8*
2055 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2056 {
2057         MonoMethod *method = cfg->method;
2058         MonoMethodSignature *sig;
2059         MonoInst *inst;
2060         CallInfo *cinfo;
2061         guint32 i;
2062
2063         /* FIXME: Generate intermediate code instead */
2064
2065         sig = mono_method_signature (method);
2066
2067         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
2068         
2069         /* This is the opposite of the code in emit_prolog */
2070
2071         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2072                 ArgInfo *ainfo = cinfo->args + i;
2073                 MonoType *arg_type;
2074                 inst = cfg->args [i];
2075
2076                 if (sig->hasthis && (i == 0))
2077                         arg_type = &mono_defaults.object_class->byval_arg;
2078                 else
2079                         arg_type = sig->params [i - sig->hasthis];
2080
2081                 /*
2082                  * On x86, the arguments are either in their original stack locations, or in
2083                  * global regs.
2084                  */
2085                 if (inst->opcode == OP_REGVAR) {
2086                         g_assert (ainfo->storage == ArgOnStack);
2087                         
2088                         x86_mov_membase_reg (code, X86_EBP, inst->inst_offset, inst->dreg, 4);
2089                 }
2090         }
2091
2092         return code;
2093 }
2094
2095 #define REAL_PRINT_REG(text,reg) \
2096 mono_assert (reg >= 0); \
2097 x86_push_reg (code, X86_EAX); \
2098 x86_push_reg (code, X86_EDX); \
2099 x86_push_reg (code, X86_ECX); \
2100 x86_push_reg (code, reg); \
2101 x86_push_imm (code, reg); \
2102 x86_push_imm (code, text " %d %p\n"); \
2103 x86_mov_reg_imm (code, X86_EAX, printf); \
2104 x86_call_reg (code, X86_EAX); \
2105 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 3*4); \
2106 x86_pop_reg (code, X86_ECX); \
2107 x86_pop_reg (code, X86_EDX); \
2108 x86_pop_reg (code, X86_EAX);
2109
2110 /* benchmark and set based on cpu */
2111 #define LOOP_ALIGNMENT 8
2112 #define bb_is_loop_start(bb) ((bb)->loop_body_start && (bb)->nesting)
2113
2114 void
2115 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
2116 {
2117         MonoInst *ins;
2118         MonoCallInst *call;
2119         guint offset;
2120         guint8 *code = cfg->native_code + cfg->code_len;
2121         int max_len, cpos;
2122
2123         if (cfg->opt & MONO_OPT_LOOP) {
2124                 int pad, align = LOOP_ALIGNMENT;
2125                 /* set alignment depending on cpu */
2126                 if (bb_is_loop_start (bb) && (pad = (cfg->code_len & (align - 1)))) {
2127                         pad = align - pad;
2128                         /*g_print ("adding %d pad at %x to loop in %s\n", pad, cfg->code_len, cfg->method->name);*/
2129                         x86_padding (code, pad);
2130                         cfg->code_len += pad;
2131                         bb->native_offset = cfg->code_len;
2132                 }
2133         }
2134
2135         if (cfg->verbose_level > 2)
2136                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
2137
2138         cpos = bb->max_offset;
2139
2140         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
2141                 MonoProfileCoverageInfo *cov = cfg->coverage_info;
2142                 g_assert (!cfg->compile_aot);
2143                 cpos += 6;
2144
2145                 cov->data [bb->dfn].cil_code = bb->cil_code;
2146                 /* this is not thread save, but good enough */
2147                 x86_inc_mem (code, &cov->data [bb->dfn].count); 
2148         }
2149
2150         offset = code - cfg->native_code;
2151
2152         mono_debug_open_block (cfg, bb, offset);
2153
2154         MONO_BB_FOR_EACH_INS (bb, ins) {
2155                 offset = code - cfg->native_code;
2156
2157                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
2158
2159                 if (G_UNLIKELY (offset > (cfg->code_size - max_len - 16))) {
2160                         cfg->code_size *= 2;
2161                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2162                         code = cfg->native_code + offset;
2163                         mono_jit_stats.code_reallocs++;
2164                 }
2165
2166                 if (cfg->debug_info)
2167                         mono_debug_record_line_number (cfg, ins, offset);
2168
2169                 switch (ins->opcode) {
2170                 case OP_BIGMUL:
2171                         x86_mul_reg (code, ins->sreg2, TRUE);
2172                         break;
2173                 case OP_BIGMUL_UN:
2174                         x86_mul_reg (code, ins->sreg2, FALSE);
2175                         break;
2176                 case OP_X86_SETEQ_MEMBASE:
2177                 case OP_X86_SETNE_MEMBASE:
2178                         x86_set_membase (code, ins->opcode == OP_X86_SETEQ_MEMBASE ? X86_CC_EQ : X86_CC_NE,
2179                                          ins->inst_basereg, ins->inst_offset, TRUE);
2180                         break;
2181                 case OP_STOREI1_MEMBASE_IMM:
2182                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 1);
2183                         break;
2184                 case OP_STOREI2_MEMBASE_IMM:
2185                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 2);
2186                         break;
2187                 case OP_STORE_MEMBASE_IMM:
2188                 case OP_STOREI4_MEMBASE_IMM:
2189                         x86_mov_membase_imm (code, ins->inst_destbasereg, ins->inst_offset, ins->inst_imm, 4);
2190                         break;
2191                 case OP_STOREI1_MEMBASE_REG:
2192                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 1);
2193                         break;
2194                 case OP_STOREI2_MEMBASE_REG:
2195                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 2);
2196                         break;
2197                 case OP_STORE_MEMBASE_REG:
2198                 case OP_STOREI4_MEMBASE_REG:
2199                         x86_mov_membase_reg (code, ins->inst_destbasereg, ins->inst_offset, ins->sreg1, 4);
2200                         break;
2201                 case OP_STORE_MEM_IMM:
2202                         x86_mov_mem_imm (code, ins->inst_p0, ins->inst_c0, 4);
2203                         break;
2204                 case OP_LOADU4_MEM:
2205                         if (cfg->new_ir)
2206                                 x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2207                         else
2208                                 x86_mov_reg_mem (code, ins->dreg, ins->inst_p0, 4);
2209                         break;
2210                 case OP_LOAD_MEM:
2211                 case OP_LOADI4_MEM:
2212                         /* These are created by the cprop pass so they use inst_imm as the source */
2213                         x86_mov_reg_mem (code, ins->dreg, ins->inst_imm, 4);
2214                         break;
2215                 case OP_LOADU1_MEM:
2216                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, FALSE);
2217                         break;
2218                 case OP_LOADU2_MEM:
2219                         x86_widen_mem (code, ins->dreg, ins->inst_imm, FALSE, TRUE);
2220                         break;
2221                 case OP_LOAD_MEMBASE:
2222                 case OP_LOADI4_MEMBASE:
2223                 case OP_LOADU4_MEMBASE:
2224                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, 4);
2225                         break;
2226                 case OP_LOADU1_MEMBASE:
2227                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, FALSE);
2228                         break;
2229                 case OP_LOADI1_MEMBASE:
2230                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, FALSE);
2231                         break;
2232                 case OP_LOADU2_MEMBASE:
2233                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, FALSE, TRUE);
2234                         break;
2235                 case OP_LOADI2_MEMBASE:
2236                         x86_widen_membase (code, ins->dreg, ins->inst_basereg, ins->inst_offset, TRUE, TRUE);
2237                         break;
2238                 case OP_ICONV_TO_I1:
2239                 case OP_SEXT_I1:
2240                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, FALSE);
2241                         break;
2242                 case OP_ICONV_TO_I2:
2243                 case OP_SEXT_I2:
2244                         x86_widen_reg (code, ins->dreg, ins->sreg1, TRUE, TRUE);
2245                         break;
2246                 case OP_ICONV_TO_U1:
2247                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, FALSE);
2248                         break;
2249                 case OP_ICONV_TO_U2:
2250                         x86_widen_reg (code, ins->dreg, ins->sreg1, FALSE, TRUE);
2251                         break;
2252                 case OP_COMPARE:
2253                 case OP_ICOMPARE:
2254                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2255                         break;
2256                 case OP_COMPARE_IMM:
2257                 case OP_ICOMPARE_IMM:
2258                         x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
2259                         break;
2260                 case OP_X86_COMPARE_MEMBASE_REG:
2261                         x86_alu_membase_reg (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2262                         break;
2263                 case OP_X86_COMPARE_MEMBASE_IMM:
2264                         x86_alu_membase_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2265                         break;
2266                 case OP_X86_COMPARE_MEMBASE8_IMM:
2267                         x86_alu_membase8_imm (code, X86_CMP, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2268                         break;
2269                 case OP_X86_COMPARE_REG_MEMBASE:
2270                         x86_alu_reg_membase (code, X86_CMP, ins->sreg1, ins->sreg2, ins->inst_offset);
2271                         break;
2272                 case OP_X86_COMPARE_MEM_IMM:
2273                         x86_alu_mem_imm (code, X86_CMP, ins->inst_offset, ins->inst_imm);
2274                         break;
2275                 case OP_X86_TEST_NULL:
2276                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
2277                         break;
2278                 case OP_X86_ADD_MEMBASE_IMM:
2279                         x86_alu_membase_imm (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2280                         break;
2281                 case OP_X86_ADD_REG_MEMBASE:
2282                         x86_alu_reg_membase (code, X86_ADD, ins->sreg1, ins->sreg2, ins->inst_offset);
2283                         break;
2284                 case OP_X86_SUB_MEMBASE_IMM:
2285                         x86_alu_membase_imm (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2286                         break;
2287                 case OP_X86_SUB_REG_MEMBASE:
2288                         x86_alu_reg_membase (code, X86_SUB, ins->sreg1, ins->sreg2, ins->inst_offset);
2289                         break;
2290                 case OP_X86_AND_MEMBASE_IMM:
2291                         x86_alu_membase_imm (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2292                         break;
2293                 case OP_X86_OR_MEMBASE_IMM:
2294                         x86_alu_membase_imm (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2295                         break;
2296                 case OP_X86_XOR_MEMBASE_IMM:
2297                         x86_alu_membase_imm (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->inst_imm);
2298                         break;
2299                 case OP_X86_ADD_MEMBASE_REG:
2300                         x86_alu_membase_reg (code, X86_ADD, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2301                         break;
2302                 case OP_X86_SUB_MEMBASE_REG:
2303                         x86_alu_membase_reg (code, X86_SUB, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2304                         break;
2305                 case OP_X86_AND_MEMBASE_REG:
2306                         x86_alu_membase_reg (code, X86_AND, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2307                         break;
2308                 case OP_X86_OR_MEMBASE_REG:
2309                         x86_alu_membase_reg (code, X86_OR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2310                         break;
2311                 case OP_X86_XOR_MEMBASE_REG:
2312                         x86_alu_membase_reg (code, X86_XOR, ins->inst_basereg, ins->inst_offset, ins->sreg2);
2313                         break;
2314                 case OP_X86_INC_MEMBASE:
2315                         x86_inc_membase (code, ins->inst_basereg, ins->inst_offset);
2316                         break;
2317                 case OP_X86_INC_REG:
2318                         x86_inc_reg (code, ins->dreg);
2319                         break;
2320                 case OP_X86_DEC_MEMBASE:
2321                         x86_dec_membase (code, ins->inst_basereg, ins->inst_offset);
2322                         break;
2323                 case OP_X86_DEC_REG:
2324                         x86_dec_reg (code, ins->dreg);
2325                         break;
2326                 case OP_X86_MUL_REG_MEMBASE:
2327                         x86_imul_reg_membase (code, ins->sreg1, ins->sreg2, ins->inst_offset);
2328                         break;
2329                 case OP_X86_AND_REG_MEMBASE:
2330                         x86_alu_reg_membase (code, X86_AND, ins->sreg1, ins->sreg2, ins->inst_offset);
2331                         break;
2332                 case OP_X86_OR_REG_MEMBASE:
2333                         x86_alu_reg_membase (code, X86_OR, ins->sreg1, ins->sreg2, ins->inst_offset);
2334                         break;
2335                 case OP_X86_XOR_REG_MEMBASE:
2336                         x86_alu_reg_membase (code, X86_XOR, ins->sreg1, ins->sreg2, ins->inst_offset);
2337                         break;
2338                 case OP_BREAK:
2339                         x86_breakpoint (code);
2340                         break;
2341                 case OP_RELAXED_NOP:
2342                         x86_prefix (code, X86_REP_PREFIX);
2343                         x86_nop (code);
2344                         break;
2345                 case OP_NOP:
2346                 case OP_DUMMY_USE:
2347                 case OP_DUMMY_STORE:
2348                 case OP_NOT_REACHED:
2349                 case OP_NOT_NULL:
2350                         break;
2351                 case OP_ADDCC:
2352                 case OP_IADDCC:
2353                 case OP_IADD:
2354                         x86_alu_reg_reg (code, X86_ADD, ins->sreg1, ins->sreg2);
2355                         break;
2356                 case OP_ADC:
2357                 case OP_IADC:
2358                         x86_alu_reg_reg (code, X86_ADC, ins->sreg1, ins->sreg2);
2359                         break;
2360                 case OP_ADDCC_IMM:
2361                 case OP_ADD_IMM:
2362                 case OP_IADD_IMM:
2363                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, ins->inst_imm);
2364                         break;
2365                 case OP_ADC_IMM:
2366                 case OP_IADC_IMM:
2367                         x86_alu_reg_imm (code, X86_ADC, ins->dreg, ins->inst_imm);
2368                         break;
2369                 case OP_SUBCC:
2370                 case OP_ISUBCC:
2371                 case OP_ISUB:
2372                         x86_alu_reg_reg (code, X86_SUB, ins->sreg1, ins->sreg2);
2373                         break;
2374                 case OP_SBB:
2375                 case OP_ISBB:
2376                         x86_alu_reg_reg (code, X86_SBB, ins->sreg1, ins->sreg2);
2377                         break;
2378                 case OP_SUBCC_IMM:
2379                 case OP_SUB_IMM:
2380                 case OP_ISUB_IMM:
2381                         x86_alu_reg_imm (code, X86_SUB, ins->dreg, ins->inst_imm);
2382                         break;
2383                 case OP_SBB_IMM:
2384                 case OP_ISBB_IMM:
2385                         x86_alu_reg_imm (code, X86_SBB, ins->dreg, ins->inst_imm);
2386                         break;
2387                 case OP_IAND:
2388                         x86_alu_reg_reg (code, X86_AND, ins->sreg1, ins->sreg2);
2389                         break;
2390                 case OP_AND_IMM:
2391                 case OP_IAND_IMM:
2392                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ins->inst_imm);
2393                         break;
2394                 case OP_IDIV:
2395                 case OP_IREM:
2396                         /* 
2397                          * The code is the same for div/rem, the allocator will allocate dreg
2398                          * to RAX/RDX as appropriate.
2399                          */
2400                         if (ins->sreg2 == X86_EDX) {
2401                                 /* cdq clobbers this */
2402                                 x86_push_reg (code, ins->sreg2);
2403                                 x86_cdq (code);
2404                                 x86_div_membase (code, X86_ESP, 0, TRUE);
2405                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2406                         } else {
2407                                 x86_cdq (code);
2408                                 x86_div_reg (code, ins->sreg2, TRUE);
2409                         }
2410                         break;
2411                 case OP_IDIV_UN:
2412                 case OP_IREM_UN:
2413                         if (ins->sreg2 == X86_EDX) {
2414                                 x86_push_reg (code, ins->sreg2);
2415                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2416                                 x86_div_membase (code, X86_ESP, 0, FALSE);
2417                                 x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);                            
2418                         } else {
2419                                 x86_alu_reg_reg (code, X86_XOR, X86_EDX, X86_EDX);
2420                                 x86_div_reg (code, ins->sreg2, FALSE);
2421                         }
2422                         break;
2423                 case OP_DIV_IMM:
2424                         x86_mov_reg_imm (code, ins->sreg2, ins->inst_imm);
2425                         x86_cdq (code);
2426                         x86_div_reg (code, ins->sreg2, TRUE);
2427                         break;
2428                 case OP_IREM_IMM: {
2429                         int power = mono_is_power_of_two (ins->inst_imm);
2430
2431                         g_assert (ins->sreg1 == X86_EAX);
2432                         g_assert (ins->dreg == X86_EAX);
2433                         g_assert (power >= 0);
2434
2435                         if (power == 1) {
2436                                 /* Based on http://compilers.iecc.com/comparch/article/93-04-079 */
2437                                 x86_cdq (code);
2438                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, 1);
2439                                 /* 
2440                                  * If the divident is >= 0, this does not nothing. If it is positive, it
2441                                  * it transforms %eax=0 into %eax=0, and %eax=1 into %eax=-1.
2442                                  */
2443                                 x86_alu_reg_reg (code, X86_XOR, X86_EAX, X86_EDX);
2444                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2445                         } else {
2446                                 /* Based on gcc code */
2447
2448                                 /* Add compensation for negative dividents */
2449                                 x86_cdq (code);
2450                                 x86_shift_reg_imm (code, X86_SHR, X86_EDX, 32 - power);
2451                                 x86_alu_reg_reg (code, X86_ADD, X86_EAX, X86_EDX);
2452                                 /* Compute remainder */
2453                                 x86_alu_reg_imm (code, X86_AND, X86_EAX, (1 << power) - 1);
2454                                 /* Remove compensation */
2455                                 x86_alu_reg_reg (code, X86_SUB, X86_EAX, X86_EDX);
2456                         }
2457                         break;
2458                 }
2459                 case OP_IOR:
2460                         x86_alu_reg_reg (code, X86_OR, ins->sreg1, ins->sreg2);
2461                         break;
2462                 case OP_OR_IMM:
2463                 case OP_IOR_IMM:
2464                         x86_alu_reg_imm (code, X86_OR, ins->sreg1, ins->inst_imm);
2465                         break;
2466                 case OP_IXOR:
2467                         x86_alu_reg_reg (code, X86_XOR, ins->sreg1, ins->sreg2);
2468                         break;
2469                 case OP_XOR_IMM:
2470                 case OP_IXOR_IMM:
2471                         x86_alu_reg_imm (code, X86_XOR, ins->sreg1, ins->inst_imm);
2472                         break;
2473                 case OP_ISHL:
2474                         g_assert (ins->sreg2 == X86_ECX);
2475                         x86_shift_reg (code, X86_SHL, ins->dreg);
2476                         break;
2477                 case OP_ISHR:
2478                         g_assert (ins->sreg2 == X86_ECX);
2479                         x86_shift_reg (code, X86_SAR, ins->dreg);
2480                         break;
2481                 case OP_SHR_IMM:
2482                 case OP_ISHR_IMM:
2483                         x86_shift_reg_imm (code, X86_SAR, ins->dreg, ins->inst_imm);
2484                         break;
2485                 case OP_SHR_UN_IMM:
2486                 case OP_ISHR_UN_IMM:
2487                         x86_shift_reg_imm (code, X86_SHR, ins->dreg, ins->inst_imm);
2488                         break;
2489                 case OP_ISHR_UN:
2490                         g_assert (ins->sreg2 == X86_ECX);
2491                         x86_shift_reg (code, X86_SHR, ins->dreg);
2492                         break;
2493                 case OP_SHL_IMM:
2494                 case OP_ISHL_IMM:
2495                         x86_shift_reg_imm (code, X86_SHL, ins->dreg, ins->inst_imm);
2496                         break;
2497                 case OP_LSHL: {
2498                         guint8 *jump_to_end;
2499
2500                         /* handle shifts below 32 bits */
2501                         x86_shld_reg (code, ins->backend.reg3, ins->sreg1);
2502                         x86_shift_reg (code, X86_SHL, ins->sreg1);
2503
2504                         x86_test_reg_imm (code, X86_ECX, 32);
2505                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
2506
2507                         /* handle shift over 32 bit */
2508                         x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2509                         x86_clear_reg (code, ins->sreg1);
2510                         
2511                         x86_patch (jump_to_end, code);
2512                         }
2513                         break;
2514                 case OP_LSHR: {
2515                         guint8 *jump_to_end;
2516
2517                         /* handle shifts below 32 bits */
2518                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2519                         x86_shift_reg (code, X86_SAR, ins->backend.reg3);
2520
2521                         x86_test_reg_imm (code, X86_ECX, 32);
2522                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2523
2524                         /* handle shifts over 31 bits */
2525                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2526                         x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 31);
2527                         
2528                         x86_patch (jump_to_end, code);
2529                         }
2530                         break;
2531                 case OP_LSHR_UN: {
2532                         guint8 *jump_to_end;
2533
2534                         /* handle shifts below 32 bits */
2535                         x86_shrd_reg (code, ins->sreg1, ins->backend.reg3);
2536                         x86_shift_reg (code, X86_SHR, ins->backend.reg3);
2537
2538                         x86_test_reg_imm (code, X86_ECX, 32);
2539                         jump_to_end = code; x86_branch8 (code, X86_CC_EQ, 0, FALSE);
2540
2541                         /* handle shifts over 31 bits */
2542                         x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2543                         x86_clear_reg (code, ins->backend.reg3);
2544                         
2545                         x86_patch (jump_to_end, code);
2546                         }
2547                         break;
2548                 case OP_LSHL_IMM:
2549                         if (ins->inst_imm >= 32) {
2550                                 x86_mov_reg_reg (code, ins->backend.reg3, ins->sreg1, 4);
2551                                 x86_clear_reg (code, ins->sreg1);
2552                                 x86_shift_reg_imm (code, X86_SHL, ins->backend.reg3, ins->inst_imm - 32);
2553                         } else {
2554                                 x86_shld_reg_imm (code, ins->backend.reg3, ins->sreg1, ins->inst_imm);
2555                                 x86_shift_reg_imm (code, X86_SHL, ins->sreg1, ins->inst_imm);
2556                         }
2557                         break;
2558                 case OP_LSHR_IMM:
2559                         if (ins->inst_imm >= 32) {
2560                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3,  4);
2561                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, 0x1f);
2562                                 x86_shift_reg_imm (code, X86_SAR, ins->sreg1, ins->inst_imm - 32);
2563                         } else {
2564                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
2565                                 x86_shift_reg_imm (code, X86_SAR, ins->backend.reg3, ins->inst_imm);
2566                         }
2567                         break;
2568                 case OP_LSHR_UN_IMM:
2569                         if (ins->inst_imm >= 32) {
2570                                 x86_mov_reg_reg (code, ins->sreg1, ins->backend.reg3, 4);
2571                                 x86_clear_reg (code, ins->backend.reg3);
2572                                 x86_shift_reg_imm (code, X86_SHR, ins->sreg1, ins->inst_imm - 32);
2573                         } else {
2574                                 x86_shrd_reg_imm (code, ins->sreg1, ins->backend.reg3, ins->inst_imm);
2575                                 x86_shift_reg_imm (code, X86_SHR, ins->backend.reg3, ins->inst_imm);
2576                         }
2577                         break;
2578                 case OP_INOT:
2579                         x86_not_reg (code, ins->sreg1);
2580                         break;
2581                 case OP_INEG:
2582                         x86_neg_reg (code, ins->sreg1);
2583                         break;
2584
2585                 case OP_IMUL:
2586                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2587                         break;
2588                 case OP_MUL_IMM:
2589                 case OP_IMUL_IMM:
2590                         switch (ins->inst_imm) {
2591                         case 2:
2592                                 /* MOV r1, r2 */
2593                                 /* ADD r1, r1 */
2594                                 if (ins->dreg != ins->sreg1)
2595                                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2596                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2597                                 break;
2598                         case 3:
2599                                 /* LEA r1, [r2 + r2*2] */
2600                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2601                                 break;
2602                         case 5:
2603                                 /* LEA r1, [r2 + r2*4] */
2604                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2605                                 break;
2606                         case 6:
2607                                 /* LEA r1, [r2 + r2*2] */
2608                                 /* ADD r1, r1          */
2609                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2610                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2611                                 break;
2612                         case 9:
2613                                 /* LEA r1, [r2 + r2*8] */
2614                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 3);
2615                                 break;
2616                         case 10:
2617                                 /* LEA r1, [r2 + r2*4] */
2618                                 /* ADD r1, r1          */
2619                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2620                                 x86_alu_reg_reg (code, X86_ADD, ins->dreg, ins->dreg);
2621                                 break;
2622                         case 12:
2623                                 /* LEA r1, [r2 + r2*2] */
2624                                 /* SHL r1, 2           */
2625                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 1);
2626                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
2627                                 break;
2628                         case 25:
2629                                 /* LEA r1, [r2 + r2*4] */
2630                                 /* LEA r1, [r1 + r1*4] */
2631                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2632                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
2633                                 break;
2634                         case 100:
2635                                 /* LEA r1, [r2 + r2*4] */
2636                                 /* SHL r1, 2           */
2637                                 /* LEA r1, [r1 + r1*4] */
2638                                 x86_lea_memindex (code, ins->dreg, ins->sreg1, 0, ins->sreg1, 2);
2639                                 x86_shift_reg_imm (code, X86_SHL, ins->dreg, 2);
2640                                 x86_lea_memindex (code, ins->dreg, ins->dreg, 0, ins->dreg, 2);
2641                                 break;
2642                         default:
2643                                 x86_imul_reg_reg_imm (code, ins->dreg, ins->sreg1, ins->inst_imm);
2644                                 break;
2645                         }
2646                         break;
2647                 case OP_IMUL_OVF:
2648                         x86_imul_reg_reg (code, ins->sreg1, ins->sreg2);
2649                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2650                         break;
2651                 case OP_IMUL_OVF_UN: {
2652                         /* the mul operation and the exception check should most likely be split */
2653                         int non_eax_reg, saved_eax = FALSE, saved_edx = FALSE;
2654                         /*g_assert (ins->sreg2 == X86_EAX);
2655                         g_assert (ins->dreg == X86_EAX);*/
2656                         if (ins->sreg2 == X86_EAX) {
2657                                 non_eax_reg = ins->sreg1;
2658                         } else if (ins->sreg1 == X86_EAX) {
2659                                 non_eax_reg = ins->sreg2;
2660                         } else {
2661                                 /* no need to save since we're going to store to it anyway */
2662                                 if (ins->dreg != X86_EAX) {
2663                                         saved_eax = TRUE;
2664                                         x86_push_reg (code, X86_EAX);
2665                                 }
2666                                 x86_mov_reg_reg (code, X86_EAX, ins->sreg1, 4);
2667                                 non_eax_reg = ins->sreg2;
2668                         }
2669                         if (ins->dreg == X86_EDX) {
2670                                 if (!saved_eax) {
2671                                         saved_eax = TRUE;
2672                                         x86_push_reg (code, X86_EAX);
2673                                 }
2674                         } else if (ins->dreg != X86_EAX) {
2675                                 saved_edx = TRUE;
2676                                 x86_push_reg (code, X86_EDX);
2677                         }
2678                         x86_mul_reg (code, non_eax_reg, FALSE);
2679                         /* save before the check since pop and mov don't change the flags */
2680                         if (ins->dreg != X86_EAX)
2681                                 x86_mov_reg_reg (code, ins->dreg, X86_EAX, 4);
2682                         if (saved_edx)
2683                                 x86_pop_reg (code, X86_EDX);
2684                         if (saved_eax)
2685                                 x86_pop_reg (code, X86_EAX);
2686                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_O, FALSE, "OverflowException");
2687                         break;
2688                 }
2689                 case OP_ICONST:
2690                         x86_mov_reg_imm (code, ins->dreg, ins->inst_c0);
2691                         break;
2692                 case OP_AOTCONST:
2693                         g_assert_not_reached ();
2694                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2695                         x86_mov_reg_imm (code, ins->dreg, 0);
2696                         break;
2697                 case OP_JUMP_TABLE:
2698                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2699                         x86_mov_reg_imm (code, ins->dreg, 0);
2700                         break;
2701                 case OP_LOAD_GOTADDR:
2702                         x86_call_imm (code, 0);
2703                         /* 
2704                          * The patch needs to point to the pop, since the GOT offset needs 
2705                          * to be added to that address.
2706                          */
2707                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_GOT_OFFSET, NULL);
2708                         x86_pop_reg (code, ins->dreg);
2709                         x86_alu_reg_imm (code, X86_ADD, ins->dreg, 0xf0f0f0f0);
2710                         break;
2711                 case OP_GOT_ENTRY:
2712                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
2713                         x86_mov_reg_membase (code, ins->dreg, ins->inst_basereg, 0xf0f0f0f0, 4);
2714                         break;
2715                 case OP_X86_PUSH_GOT_ENTRY:
2716                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_right->inst_i1, ins->inst_right->inst_p0);
2717                         x86_push_membase (code, ins->inst_basereg, 0xf0f0f0f0);
2718                         break;
2719                 case OP_MOVE:
2720                         x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
2721                         break;
2722                 case OP_JMP: {
2723                         /*
2724                          * Note: this 'frame destruction' logic is useful for tail calls, too.
2725                          * Keep in sync with the code in emit_epilog.
2726                          */
2727                         int pos = 0;
2728
2729                         /* FIXME: no tracing support... */
2730                         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2731                                 code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
2732                         /* reset offset to make max_len work */
2733                         offset = code - cfg->native_code;
2734
2735                         g_assert (!cfg->method->save_lmf);
2736
2737                         code = emit_load_volatile_arguments (cfg, code);
2738
2739                         if (cfg->used_int_regs & (1 << X86_EBX))
2740                                 pos -= 4;
2741                         if (cfg->used_int_regs & (1 << X86_EDI))
2742                                 pos -= 4;
2743                         if (cfg->used_int_regs & (1 << X86_ESI))
2744                                 pos -= 4;
2745                         if (pos)
2746                                 x86_lea_membase (code, X86_ESP, X86_EBP, pos);
2747         
2748                         if (cfg->used_int_regs & (1 << X86_ESI))
2749                                 x86_pop_reg (code, X86_ESI);
2750                         if (cfg->used_int_regs & (1 << X86_EDI))
2751                                 x86_pop_reg (code, X86_EDI);
2752                         if (cfg->used_int_regs & (1 << X86_EBX))
2753                                 x86_pop_reg (code, X86_EBX);
2754         
2755                         /* restore ESP/EBP */
2756                         x86_leave (code);
2757                         offset = code - cfg->native_code;
2758                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2759                         x86_jump32 (code, 0);
2760
2761                         cfg->disable_aot = TRUE;
2762                         break;
2763                 }
2764                 case OP_CHECK_THIS:
2765                         /* ensure ins->sreg1 is not NULL
2766                          * note that cmp DWORD PTR [eax], eax is one byte shorter than
2767                          * cmp DWORD PTR [eax], 0
2768                          */
2769                         x86_alu_membase_reg (code, X86_CMP, ins->sreg1, 0, ins->sreg1);
2770                         break;
2771                 case OP_ARGLIST: {
2772                         int hreg = ins->sreg1 == X86_EAX? X86_ECX: X86_EAX;
2773                         x86_push_reg (code, hreg);
2774                         x86_lea_membase (code, hreg, X86_EBP, cfg->sig_cookie);
2775                         x86_mov_membase_reg (code, ins->sreg1, 0, hreg, 4);
2776                         x86_pop_reg (code, hreg);
2777                         break;
2778                 }
2779                 case OP_FCALL:
2780                 case OP_LCALL:
2781                 case OP_VCALL:
2782                 case OP_VCALL2:
2783                 case OP_VOIDCALL:
2784                 case OP_CALL:
2785                         call = (MonoCallInst*)ins;
2786                         if (ins->flags & MONO_INST_HAS_METHOD)
2787                                 code = emit_call (cfg, code, MONO_PATCH_INFO_METHOD, call->method);
2788                         else
2789                                 code = emit_call (cfg, code, MONO_PATCH_INFO_ABS, call->fptr);
2790                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2791                                 /* a pop is one byte, while an add reg, imm is 3. So if there are 4 or 8
2792                                  * bytes to pop, we want to use pops. GCC does this (note it won't happen
2793                                  * for P4 or i686 because gcc will avoid using pop push at all. But we aren't
2794                                  * smart enough to do that optimization yet
2795                                  *
2796                                  * It turns out that on my P4, doing two pops for 8 bytes on the stack makes
2797                                  * mcs botstrap slow down. However, doing 1 pop for 4 bytes creates a small,
2798                                  * (most likely from locality benefits). People with other processors should
2799                                  * check on theirs to see what happens.
2800                                  */
2801                                 if (call->stack_usage == 4) {
2802                                         /* we want to use registers that won't get used soon, so use
2803                                          * ecx, as eax will get allocated first. edx is used by long calls,
2804                                          * so we can't use that.
2805                                          */
2806                                         
2807                                         x86_pop_reg (code, X86_ECX);
2808                                 } else {
2809                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2810                                 }
2811                         }
2812                         code = emit_move_return_value (cfg, ins, code);
2813                         break;
2814                 case OP_FCALL_REG:
2815                 case OP_LCALL_REG:
2816                 case OP_VCALL_REG:
2817                 case OP_VCALL2_REG:
2818                 case OP_VOIDCALL_REG:
2819                 case OP_CALL_REG:
2820                         call = (MonoCallInst*)ins;
2821                         x86_call_reg (code, ins->sreg1);
2822                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2823                                 if (call->stack_usage == 4)
2824                                         x86_pop_reg (code, X86_ECX);
2825                                 else
2826                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2827                         }
2828                         code = emit_move_return_value (cfg, ins, code);
2829                         break;
2830                 case OP_FCALL_MEMBASE:
2831                 case OP_LCALL_MEMBASE:
2832                 case OP_VCALL_MEMBASE:
2833                 case OP_VCALL2_MEMBASE:
2834                 case OP_VOIDCALL_MEMBASE:
2835                 case OP_CALL_MEMBASE:
2836                         call = (MonoCallInst*)ins;
2837                         x86_call_membase (code, ins->sreg1, ins->inst_offset);
2838                         if (call->stack_usage && !CALLCONV_IS_STDCALL (call->signature)) {
2839                                 if (call->stack_usage == 4)
2840                                         x86_pop_reg (code, X86_ECX);
2841                                 else
2842                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, call->stack_usage);
2843                         }
2844                         code = emit_move_return_value (cfg, ins, code);
2845                         break;
2846                 case OP_OUTARG:
2847                 case OP_X86_PUSH:
2848                         x86_push_reg (code, ins->sreg1);
2849                         break;
2850                 case OP_X86_PUSH_IMM:
2851                         x86_push_imm (code, ins->inst_imm);
2852                         break;
2853                 case OP_X86_PUSH_MEMBASE:
2854                         x86_push_membase (code, ins->inst_basereg, ins->inst_offset);
2855                         break;
2856                 case OP_X86_PUSH_OBJ: 
2857                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, ins->inst_imm);
2858                         x86_push_reg (code, X86_EDI);
2859                         x86_push_reg (code, X86_ESI);
2860                         x86_push_reg (code, X86_ECX);
2861                         if (ins->inst_offset)
2862                                 x86_lea_membase (code, X86_ESI, ins->inst_basereg, ins->inst_offset);
2863                         else
2864                                 x86_mov_reg_reg (code, X86_ESI, ins->inst_basereg, 4);
2865                         x86_lea_membase (code, X86_EDI, X86_ESP, 12);
2866                         x86_mov_reg_imm (code, X86_ECX, (ins->inst_imm >> 2));
2867                         x86_cld (code);
2868                         x86_prefix (code, X86_REP_PREFIX);
2869                         x86_movsd (code);
2870                         x86_pop_reg (code, X86_ECX);
2871                         x86_pop_reg (code, X86_ESI);
2872                         x86_pop_reg (code, X86_EDI);
2873                         break;
2874                 case OP_X86_LEA:
2875                         x86_lea_memindex (code, ins->dreg, ins->sreg1, ins->inst_imm, ins->sreg2, ins->backend.shift_amount);
2876                         break;
2877                 case OP_X86_LEA_MEMBASE:
2878                         x86_lea_membase (code, ins->dreg, ins->sreg1, ins->inst_imm);
2879                         break;
2880                 case OP_X86_XCHG:
2881                         x86_xchg_reg_reg (code, ins->sreg1, ins->sreg2, 4);
2882                         break;
2883                 case OP_LOCALLOC:
2884                         /* keep alignment */
2885                         x86_alu_reg_imm (code, X86_ADD, ins->sreg1, MONO_ARCH_LOCALLOC_ALIGNMENT - 1);
2886                         x86_alu_reg_imm (code, X86_AND, ins->sreg1, ~(MONO_ARCH_LOCALLOC_ALIGNMENT - 1));
2887                         code = mono_emit_stack_alloc (code, ins);
2888                         x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2889                         break;
2890                 case OP_LOCALLOC_IMM: {
2891                         guint32 size = ins->inst_imm;
2892                         size = (size + (MONO_ARCH_FRAME_ALIGNMENT - 1)) & ~ (MONO_ARCH_FRAME_ALIGNMENT - 1);
2893
2894                         if (ins->flags & MONO_INST_INIT) {
2895                                 /* FIXME: Optimize this */
2896                                 x86_mov_reg_imm (code, ins->dreg, size);
2897                                 ins->sreg1 = ins->dreg;
2898
2899                                 code = mono_emit_stack_alloc (code, ins);
2900                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2901                         } else {
2902                                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, size);
2903                                 x86_mov_reg_reg (code, ins->dreg, X86_ESP, 4);
2904                         }
2905                         break;
2906                 }
2907                 case OP_THROW: {
2908                         x86_push_reg (code, ins->sreg1);
2909                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2910                                                           (gpointer)"mono_arch_throw_exception");
2911                         break;
2912                 }
2913                 case OP_RETHROW: {
2914                         x86_push_reg (code, ins->sreg1);
2915                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2916                                                           (gpointer)"mono_arch_rethrow_exception");
2917                         break;
2918                 }
2919                 case OP_CALL_HANDLER:
2920 #if __APPLE__
2921                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
2922 #endif
2923                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2924                         x86_call_imm (code, 0);
2925 #ifdef __APPLE__
2926                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
2927 #endif
2928                         break;
2929                 case OP_START_HANDLER: {
2930                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2931                         x86_mov_membase_reg (code, spvar->inst_basereg, spvar->inst_offset, X86_ESP, 4);
2932                         break;
2933                 }
2934                 case OP_ENDFINALLY: {
2935                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2936                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
2937                         x86_ret (code);
2938                         break;
2939                 }
2940                 case OP_ENDFILTER: {
2941                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
2942                         x86_mov_reg_membase (code, X86_ESP, spvar->inst_basereg, spvar->inst_offset, 4);
2943                         /* The local allocator will put the result into EAX */
2944                         x86_ret (code);
2945                         break;
2946                 }
2947
2948                 case OP_LABEL:
2949                         ins->inst_c0 = code - cfg->native_code;
2950                         break;
2951                 case OP_BR:
2952                         if (ins->flags & MONO_INST_BRLABEL) {
2953                                 if (ins->inst_i0->inst_c0) {
2954                                         x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2955                                 } else {
2956                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2957                                         if ((cfg->opt & MONO_OPT_BRANCH) &&
2958                                             x86_is_imm8 (ins->inst_i0->inst_c1 - cpos))
2959                                                 x86_jump8 (code, 0);
2960                                         else 
2961                                                 x86_jump32 (code, 0);
2962                                 }
2963                         } else {
2964                                 if (ins->inst_target_bb->native_offset) {
2965                                         x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2966                                 } else {
2967                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2968                                         if ((cfg->opt & MONO_OPT_BRANCH) &&
2969                                             x86_is_imm8 (ins->inst_target_bb->max_offset - cpos))
2970                                                 x86_jump8 (code, 0);
2971                                         else 
2972                                                 x86_jump32 (code, 0);
2973                                 } 
2974                         }
2975                         break;
2976                 case OP_BR_REG:
2977                         x86_jump_reg (code, ins->sreg1);
2978                         break;
2979                 case OP_CEQ:
2980                 case OP_CLT:
2981                 case OP_CLT_UN:
2982                 case OP_CGT:
2983                 case OP_CGT_UN:
2984                 case OP_CNE:
2985                 case OP_ICEQ:
2986                 case OP_ICLT:
2987                 case OP_ICLT_UN:
2988                 case OP_ICGT:
2989                 case OP_ICGT_UN:
2990                         x86_set_reg (code, cc_table [mono_opcode_to_cond (ins->opcode)], ins->dreg, cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
2991                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
2992                         break;
2993                 case OP_COND_EXC_EQ:
2994                 case OP_COND_EXC_NE_UN:
2995                 case OP_COND_EXC_LT:
2996                 case OP_COND_EXC_LT_UN:
2997                 case OP_COND_EXC_GT:
2998                 case OP_COND_EXC_GT_UN:
2999                 case OP_COND_EXC_GE:
3000                 case OP_COND_EXC_GE_UN:
3001                 case OP_COND_EXC_LE:
3002                 case OP_COND_EXC_LE_UN:
3003                 case OP_COND_EXC_IEQ:
3004                 case OP_COND_EXC_INE_UN:
3005                 case OP_COND_EXC_ILT:
3006                 case OP_COND_EXC_ILT_UN:
3007                 case OP_COND_EXC_IGT:
3008                 case OP_COND_EXC_IGT_UN:
3009                 case OP_COND_EXC_IGE:
3010                 case OP_COND_EXC_IGE_UN:
3011                 case OP_COND_EXC_ILE:
3012                 case OP_COND_EXC_ILE_UN:
3013                         EMIT_COND_SYSTEM_EXCEPTION (cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)], ins->inst_p1);
3014                         break;
3015                 case OP_COND_EXC_OV:
3016                 case OP_COND_EXC_NO:
3017                 case OP_COND_EXC_C:
3018                 case OP_COND_EXC_NC:
3019                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_EQ], (ins->opcode < OP_COND_EXC_NE_UN), ins->inst_p1);
3020                         break;
3021                 case OP_COND_EXC_IOV:
3022                 case OP_COND_EXC_INO:
3023                 case OP_COND_EXC_IC:
3024                 case OP_COND_EXC_INC:
3025                         EMIT_COND_SYSTEM_EXCEPTION (branch_cc_table [ins->opcode - OP_COND_EXC_IEQ], (ins->opcode < OP_COND_EXC_INE_UN), ins->inst_p1);
3026                         break;
3027                 case OP_IBEQ:
3028                 case OP_IBNE_UN:
3029                 case OP_IBLT:
3030                 case OP_IBLT_UN:
3031                 case OP_IBGT:
3032                 case OP_IBGT_UN:
3033                 case OP_IBGE:
3034                 case OP_IBGE_UN:
3035                 case OP_IBLE:
3036                 case OP_IBLE_UN:
3037                         EMIT_COND_BRANCH (ins, cc_table [mono_opcode_to_cond (ins->opcode)], cc_signed_table [mono_opcode_to_cond (ins->opcode)]);
3038                         break;
3039
3040                 case OP_CMOV_IEQ:
3041                 case OP_CMOV_IGE:
3042                 case OP_CMOV_IGT:
3043                 case OP_CMOV_ILE:
3044                 case OP_CMOV_ILT:
3045                 case OP_CMOV_INE_UN:
3046                 case OP_CMOV_IGE_UN:
3047                 case OP_CMOV_IGT_UN:
3048                 case OP_CMOV_ILE_UN:
3049                 case OP_CMOV_ILT_UN:
3050                         g_assert (ins->dreg == ins->sreg1);
3051                         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);
3052                         break;
3053
3054                 /* floating point opcodes */
3055                 case OP_R8CONST: {
3056                         double d = *(double *)ins->inst_p0;
3057
3058                         if ((d == 0.0) && (mono_signbit (d) == 0)) {
3059                                 x86_fldz (code);
3060                         } else if (d == 1.0) {
3061                                 x86_fld1 (code);
3062                         } else {
3063                                 if (cfg->compile_aot) {
3064                                         guint32 *val = (guint32*)&d;
3065                                         x86_push_imm (code, val [1]);
3066                                         x86_push_imm (code, val [0]);
3067                                         x86_fld_membase (code, X86_ESP, 0, TRUE);
3068                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3069                                 }
3070                                 else {
3071                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R8, ins->inst_p0);
3072                                         x86_fld (code, NULL, TRUE);
3073                                 }
3074                         }
3075                         break;
3076                 }
3077                 case OP_R4CONST: {
3078                         float f = *(float *)ins->inst_p0;
3079
3080                         if ((f == 0.0) && (mono_signbit (f) == 0)) {
3081                                 x86_fldz (code);
3082                         } else if (f == 1.0) {
3083                                 x86_fld1 (code);
3084                         } else {
3085                                 if (cfg->compile_aot) {
3086                                         guint32 val = *(guint32*)&f;
3087                                         x86_push_imm (code, val);
3088                                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3089                                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3090                                 }
3091                                 else {
3092                                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_R4, ins->inst_p0);
3093                                         x86_fld (code, NULL, FALSE);
3094                                 }
3095                         }
3096                         break;
3097                 }
3098                 case OP_STORER8_MEMBASE_REG:
3099                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, TRUE, TRUE);
3100                         break;
3101                 case OP_LOADR8_SPILL_MEMBASE:
3102                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3103                         x86_fxch (code, 1);
3104                         break;
3105                 case OP_LOADR8_MEMBASE:
3106                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3107                         break;
3108                 case OP_STORER4_MEMBASE_REG:
3109                         x86_fst_membase (code, ins->inst_destbasereg, ins->inst_offset, FALSE, TRUE);
3110                         break;
3111                 case OP_LOADR4_MEMBASE:
3112                         x86_fld_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3113                         break;
3114                 case OP_ICONV_TO_R4: /* FIXME: change precision */
3115                 case OP_ICONV_TO_R8:
3116                         x86_push_reg (code, ins->sreg1);
3117                         x86_fild_membase (code, X86_ESP, 0, FALSE);
3118                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3119                         break;
3120                 case OP_ICONV_TO_R_UN:
3121                         x86_push_imm (code, 0);
3122                         x86_push_reg (code, ins->sreg1);
3123                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3124                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3125                         break;
3126                 case OP_X86_FP_LOAD_I8:
3127                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, TRUE);
3128                         break;
3129                 case OP_X86_FP_LOAD_I4:
3130                         x86_fild_membase (code, ins->inst_basereg, ins->inst_offset, FALSE);
3131                         break;
3132                 case OP_FCONV_TO_R4:
3133                         /* FIXME: nothing to do ?? */
3134                         break;
3135                 case OP_FCONV_TO_I1:
3136                         code = emit_float_to_int (cfg, code, ins->dreg, 1, TRUE);
3137                         break;
3138                 case OP_FCONV_TO_U1:
3139                         code = emit_float_to_int (cfg, code, ins->dreg, 1, FALSE);
3140                         break;
3141                 case OP_FCONV_TO_I2:
3142                         code = emit_float_to_int (cfg, code, ins->dreg, 2, TRUE);
3143                         break;
3144                 case OP_FCONV_TO_U2:
3145                         code = emit_float_to_int (cfg, code, ins->dreg, 2, FALSE);
3146                         break;
3147                 case OP_FCONV_TO_I4:
3148                 case OP_FCONV_TO_I:
3149                         code = emit_float_to_int (cfg, code, ins->dreg, 4, TRUE);
3150                         break;
3151                 case OP_FCONV_TO_I8:
3152                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3153                         x86_fnstcw_membase(code, X86_ESP, 0);
3154                         x86_mov_reg_membase (code, ins->dreg, X86_ESP, 0, 2);
3155                         x86_alu_reg_imm (code, X86_OR, ins->dreg, 0xc00);
3156                         x86_mov_membase_reg (code, X86_ESP, 2, ins->dreg, 2);
3157                         x86_fldcw_membase (code, X86_ESP, 2);
3158                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3159                         x86_fist_pop_membase (code, X86_ESP, 0, TRUE);
3160                         x86_pop_reg (code, ins->dreg);
3161                         x86_pop_reg (code, ins->backend.reg3);
3162                         x86_fldcw_membase (code, X86_ESP, 0);
3163                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3164                         break;
3165                 case OP_LCONV_TO_R8_2:
3166                         x86_push_reg (code, ins->sreg2);
3167                         x86_push_reg (code, ins->sreg1);
3168                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3169                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3170                         break;
3171                 case OP_LCONV_TO_R4_2:
3172                         x86_push_reg (code, ins->sreg2);
3173                         x86_push_reg (code, ins->sreg1);
3174                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3175                         /* Change precision */
3176                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3177                         x86_fld_membase (code, X86_ESP, 0, FALSE);
3178                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 8);
3179                         break;
3180                 case OP_LCONV_TO_R_UN:
3181                 case OP_LCONV_TO_R_UN_2: { 
3182                         static guint8 mn[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x40 };
3183                         guint8 *br;
3184
3185                         /* load 64bit integer to FP stack */
3186                         x86_push_imm (code, 0);
3187                         x86_push_reg (code, ins->sreg2);
3188                         x86_push_reg (code, ins->sreg1);
3189                         x86_fild_membase (code, X86_ESP, 0, TRUE);
3190                         /* store as 80bit FP value */
3191                         x86_fst80_membase (code, X86_ESP, 0);
3192                         
3193                         /* test if lreg is negative */
3194                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3195                         br = code; x86_branch8 (code, X86_CC_GEZ, 0, TRUE);
3196         
3197                         /* add correction constant mn */
3198                         x86_fld80_mem (code, mn);
3199                         x86_fld80_membase (code, X86_ESP, 0);
3200                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3201                         x86_fst80_membase (code, X86_ESP, 0);
3202
3203                         x86_patch (br, code);
3204
3205                         x86_fld80_membase (code, X86_ESP, 0);
3206                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 12);
3207
3208                         break;
3209                 }
3210                 case OP_LCONV_TO_OVF_I:
3211                 case OP_LCONV_TO_OVF_I4_2: {
3212                         guint8 *br [3], *label [1];
3213                         MonoInst *tins;
3214
3215                         /* 
3216                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
3217                          */
3218                         x86_test_reg_reg (code, ins->sreg1, ins->sreg1);
3219
3220                         /* If the low word top bit is set, see if we are negative */
3221                         br [0] = code; x86_branch8 (code, X86_CC_LT, 0, TRUE);
3222                         /* We are not negative (no top bit set, check for our top word to be zero */
3223                         x86_test_reg_reg (code, ins->sreg2, ins->sreg2);
3224                         br [1] = code; x86_branch8 (code, X86_CC_EQ, 0, TRUE);
3225                         label [0] = code;
3226
3227                         /* throw exception */
3228                         tins = mono_branch_optimize_exception_target (cfg, bb, "OverflowException");
3229                         if (tins) {
3230                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, tins->inst_true_bb);
3231                                 if ((cfg->opt & MONO_OPT_BRANCH) && x86_is_imm8 (tins->inst_true_bb->max_offset - cpos))
3232                                         x86_jump8 (code, 0);
3233                                 else
3234                                         x86_jump32 (code, 0);
3235                         } else {
3236                                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC, "OverflowException");
3237                                 x86_jump32 (code, 0);
3238                         }
3239         
3240         
3241                         x86_patch (br [0], code);
3242                         /* our top bit is set, check that top word is 0xfffffff */
3243                         x86_alu_reg_imm (code, X86_CMP, ins->sreg2, 0xffffffff);
3244                 
3245                         x86_patch (br [1], code);
3246                         /* nope, emit exception */
3247                         br [2] = code; x86_branch8 (code, X86_CC_NE, 0, TRUE);
3248                         x86_patch (br [2], label [0]);
3249
3250                         if (ins->dreg != ins->sreg1)
3251                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg1, 4);
3252                         break;
3253                 }
3254                 case OP_FMOVE:
3255                         /* Not needed on the fp stack */
3256                         break;
3257                 case OP_FADD:
3258                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3259                         break;
3260                 case OP_FSUB:
3261                         x86_fp_op_reg (code, X86_FSUB, 1, TRUE);
3262                         break;          
3263                 case OP_FMUL:
3264                         x86_fp_op_reg (code, X86_FMUL, 1, TRUE);
3265                         break;          
3266                 case OP_FDIV:
3267                         x86_fp_op_reg (code, X86_FDIV, 1, TRUE);
3268                         break;          
3269                 case OP_FNEG:
3270                         x86_fchs (code);
3271                         break;          
3272                 case OP_SIN:
3273                         x86_fsin (code);
3274                         x86_fldz (code);
3275                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3276                         break;          
3277                 case OP_COS:
3278                         x86_fcos (code);
3279                         x86_fldz (code);
3280                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3281                         break;          
3282                 case OP_ABS:
3283                         x86_fabs (code);
3284                         break;          
3285                 case OP_TAN: {
3286                         /* 
3287                          * it really doesn't make sense to inline all this code,
3288                          * it's here just to show that things may not be as simple 
3289                          * as they appear.
3290                          */
3291                         guchar *check_pos, *end_tan, *pop_jump;
3292                         x86_push_reg (code, X86_EAX);
3293                         x86_fptan (code);
3294                         x86_fnstsw (code);
3295                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3296                         check_pos = code;
3297                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3298                         x86_fstp (code, 0); /* pop the 1.0 */
3299                         end_tan = code;
3300                         x86_jump8 (code, 0);
3301                         x86_fldpi (code);
3302                         x86_fp_op (code, X86_FADD, 0);
3303                         x86_fxch (code, 1);
3304                         x86_fprem1 (code);
3305                         x86_fstsw (code);
3306                         x86_test_reg_imm (code, X86_EAX, X86_FP_C2);
3307                         pop_jump = code;
3308                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3309                         x86_fstp (code, 1);
3310                         x86_fptan (code);
3311                         x86_patch (pop_jump, code);
3312                         x86_fstp (code, 0); /* pop the 1.0 */
3313                         x86_patch (check_pos, code);
3314                         x86_patch (end_tan, code);
3315                         x86_fldz (code);
3316                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3317                         x86_pop_reg (code, X86_EAX);
3318                         break;
3319                 }
3320                 case OP_ATAN:
3321                         x86_fld1 (code);
3322                         x86_fpatan (code);
3323                         x86_fldz (code);
3324                         x86_fp_op_reg (code, X86_FADD, 1, TRUE);
3325                         break;          
3326                 case OP_SQRT:
3327                         x86_fsqrt (code);
3328                         break;
3329                 case OP_IMIN:
3330                         g_assert (cfg->opt & MONO_OPT_CMOV);
3331                         g_assert (ins->dreg == ins->sreg1);
3332                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3333                         x86_cmov_reg (code, X86_CC_GT, TRUE, ins->dreg, ins->sreg2);
3334                         break;
3335                 case OP_IMIN_UN:
3336                         g_assert (cfg->opt & MONO_OPT_CMOV);
3337                         g_assert (ins->dreg == ins->sreg1);
3338                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3339                         x86_cmov_reg (code, X86_CC_GT, FALSE, ins->dreg, ins->sreg2);
3340                         break;
3341                 case OP_IMAX:
3342                         g_assert (cfg->opt & MONO_OPT_CMOV);
3343                         g_assert (ins->dreg == ins->sreg1);
3344                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3345                         x86_cmov_reg (code, X86_CC_LT, TRUE, ins->dreg, ins->sreg2);
3346                         break;
3347                 case OP_IMAX_UN:
3348                         g_assert (cfg->opt & MONO_OPT_CMOV);
3349                         g_assert (ins->dreg == ins->sreg1);
3350                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
3351                         x86_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2);
3352                         break;
3353                 case OP_X86_FPOP:
3354                         x86_fstp (code, 0);
3355                         break;
3356                 case OP_X86_FXCH:
3357                         x86_fxch (code, ins->inst_imm);
3358                         break;
3359                 case OP_FREM: {
3360                         guint8 *l1, *l2;
3361
3362                         x86_push_reg (code, X86_EAX);
3363                         /* we need to exchange ST(0) with ST(1) */
3364                         x86_fxch (code, 1);
3365
3366                         /* this requires a loop, because fprem somtimes 
3367                          * returns a partial remainder */
3368                         l1 = code;
3369                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
3370                         /* x86_fprem1 (code); */
3371                         x86_fprem (code);
3372                         x86_fnstsw (code);
3373                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3374                         l2 = code + 2;
3375                         x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE);
3376
3377                         /* pop result */
3378                         x86_fstp (code, 1);
3379
3380                         x86_pop_reg (code, X86_EAX);
3381                         break;
3382                 }
3383                 case OP_FCOMPARE:
3384                         if (cfg->opt & MONO_OPT_FCMOV) {
3385                                 x86_fcomip (code, 1);
3386                                 x86_fstp (code, 0);
3387                                 break;
3388                         }
3389                         /* this overwrites EAX */
3390                         EMIT_FPCOMPARE(code);
3391                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3392                         break;
3393                 case OP_FCEQ:
3394                         if (cfg->opt & MONO_OPT_FCMOV) {
3395                                 /* zeroing the register at the start results in 
3396                                  * shorter and faster code (we can also remove the widening op)
3397                                  */
3398                                 guchar *unordered_check;
3399                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3400                                 x86_fcomip (code, 1);
3401                                 x86_fstp (code, 0);
3402                                 unordered_check = code;
3403                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3404                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3405                                 x86_patch (unordered_check, code);
3406                                 break;
3407                         }
3408                         if (ins->dreg != X86_EAX) 
3409                                 x86_push_reg (code, X86_EAX);
3410
3411                         EMIT_FPCOMPARE(code);
3412                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3413                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3414                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3415                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3416
3417                         if (ins->dreg != X86_EAX) 
3418                                 x86_pop_reg (code, X86_EAX);
3419                         break;
3420                 case OP_FCLT:
3421                 case OP_FCLT_UN:
3422                         if (cfg->opt & MONO_OPT_FCMOV) {
3423                                 /* zeroing the register at the start results in 
3424                                  * shorter and faster code (we can also remove the widening op)
3425                                  */
3426                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3427                                 x86_fcomip (code, 1);
3428                                 x86_fstp (code, 0);
3429                                 if (ins->opcode == OP_FCLT_UN) {
3430                                         guchar *unordered_check = code;
3431                                         guchar *jump_to_end;
3432                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3433                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3434                                         jump_to_end = code;
3435                                         x86_jump8 (code, 0);
3436                                         x86_patch (unordered_check, code);
3437                                         x86_inc_reg (code, ins->dreg);
3438                                         x86_patch (jump_to_end, code);
3439                                 } else {
3440                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3441                                 }
3442                                 break;
3443                         }
3444                         if (ins->dreg != X86_EAX) 
3445                                 x86_push_reg (code, X86_EAX);
3446
3447                         EMIT_FPCOMPARE(code);
3448                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3449                         if (ins->opcode == OP_FCLT_UN) {
3450                                 guchar *is_not_zero_check, *end_jump;
3451                                 is_not_zero_check = code;
3452                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3453                                 end_jump = code;
3454                                 x86_jump8 (code, 0);
3455                                 x86_patch (is_not_zero_check, code);
3456                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3457
3458                                 x86_patch (end_jump, code);
3459                         }
3460                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3461                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3462
3463                         if (ins->dreg != X86_EAX) 
3464                                 x86_pop_reg (code, X86_EAX);
3465                         break;
3466                 case OP_FCGT:
3467                 case OP_FCGT_UN:
3468                         if (cfg->opt & MONO_OPT_FCMOV) {
3469                                 /* zeroing the register at the start results in 
3470                                  * shorter and faster code (we can also remove the widening op)
3471                                  */
3472                                 guchar *unordered_check;
3473                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3474                                 x86_fcomip (code, 1);
3475                                 x86_fstp (code, 0);
3476                                 if (ins->opcode == OP_FCGT) {
3477                                         unordered_check = code;
3478                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3479                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3480                                         x86_patch (unordered_check, code);
3481                                 } else {
3482                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3483                                 }
3484                                 break;
3485                         }
3486                         if (ins->dreg != X86_EAX) 
3487                                 x86_push_reg (code, X86_EAX);
3488
3489                         EMIT_FPCOMPARE(code);
3490                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3491                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3492                         if (ins->opcode == OP_FCGT_UN) {
3493                                 guchar *is_not_zero_check, *end_jump;
3494                                 is_not_zero_check = code;
3495                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3496                                 end_jump = code;
3497                                 x86_jump8 (code, 0);
3498                                 x86_patch (is_not_zero_check, code);
3499                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3500         
3501                                 x86_patch (end_jump, code);
3502                         }
3503                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3504                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3505
3506                         if (ins->dreg != X86_EAX) 
3507                                 x86_pop_reg (code, X86_EAX);
3508                         break;
3509                 case OP_FBEQ:
3510                         if (cfg->opt & MONO_OPT_FCMOV) {
3511                                 guchar *jump = code;
3512                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
3513                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3514                                 x86_patch (jump, code);
3515                                 break;
3516                         }
3517                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3518                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
3519                         break;
3520                 case OP_FBNE_UN:
3521                         /* Branch if C013 != 100 */
3522                         if (cfg->opt & MONO_OPT_FCMOV) {
3523                                 /* branch if !ZF or (PF|CF) */
3524                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3525                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3526                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
3527                                 break;
3528                         }
3529                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3530                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3531                         break;
3532                 case OP_FBLT:
3533                         if (cfg->opt & MONO_OPT_FCMOV) {
3534                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3535                                 break;
3536                         }
3537                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3538                         break;
3539                 case OP_FBLT_UN:
3540                         if (cfg->opt & MONO_OPT_FCMOV) {
3541                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3542                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3543                                 break;
3544                         }
3545                         if (ins->opcode == OP_FBLT_UN) {
3546                                 guchar *is_not_zero_check, *end_jump;
3547                                 is_not_zero_check = code;
3548                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3549                                 end_jump = code;
3550                                 x86_jump8 (code, 0);
3551                                 x86_patch (is_not_zero_check, code);
3552                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3553
3554                                 x86_patch (end_jump, code);
3555                         }
3556                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3557                         break;
3558                 case OP_FBGT:
3559                 case OP_FBGT_UN:
3560                         if (cfg->opt & MONO_OPT_FCMOV) {
3561                                 if (ins->opcode == OP_FBGT) {
3562                                         guchar *br1;
3563
3564                                         /* skip branch if C1=1 */
3565                                         br1 = code;
3566                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3567                                         /* branch if (C0 | C3) = 1 */
3568                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3569                                         x86_patch (br1, code);
3570                                 } else {
3571                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3572                                 }
3573                                 break;
3574                         }
3575                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3576                         if (ins->opcode == OP_FBGT_UN) {
3577                                 guchar *is_not_zero_check, *end_jump;
3578                                 is_not_zero_check = code;
3579                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3580                                 end_jump = code;
3581                                 x86_jump8 (code, 0);
3582                                 x86_patch (is_not_zero_check, code);
3583                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3584
3585                                 x86_patch (end_jump, code);
3586                         }
3587                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3588                         break;
3589                 case OP_FBGE:
3590                         /* Branch if C013 == 100 or 001 */
3591                         if (cfg->opt & MONO_OPT_FCMOV) {
3592                                 guchar *br1;
3593
3594                                 /* skip branch if C1=1 */
3595                                 br1 = code;
3596                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3597                                 /* branch if (C0 | C3) = 1 */
3598                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
3599                                 x86_patch (br1, code);
3600                                 break;
3601                         }
3602                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3603                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3604                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3605                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3606                         break;
3607                 case OP_FBGE_UN:
3608                         /* Branch if C013 == 000 */
3609                         if (cfg->opt & MONO_OPT_FCMOV) {
3610                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
3611                                 break;
3612                         }
3613                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3614                         break;
3615                 case OP_FBLE:
3616                         /* Branch if C013=000 or 100 */
3617                         if (cfg->opt & MONO_OPT_FCMOV) {
3618                                 guchar *br1;
3619
3620                                 /* skip branch if C1=1 */
3621                                 br1 = code;
3622                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3623                                 /* branch if C0=0 */
3624                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
3625                                 x86_patch (br1, code);
3626                                 break;
3627                         }
3628                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
3629                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
3630                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3631                         break;
3632                 case OP_FBLE_UN:
3633                         /* Branch if C013 != 001 */
3634                         if (cfg->opt & MONO_OPT_FCMOV) {
3635                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3636                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
3637                                 break;
3638                         }
3639                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3640                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3641                         break;
3642                 case OP_CKFINITE: {
3643                         guchar *br1;
3644                         x86_push_reg (code, X86_EAX);
3645                         x86_fxam (code);
3646                         x86_fnstsw (code);
3647                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
3648                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3649                         x86_pop_reg (code, X86_EAX);
3650
3651                         /* Have to clean up the fp stack before throwing the exception */
3652                         br1 = code;
3653                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3654
3655                         x86_fstp (code, 0);                     
3656                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
3657
3658                         x86_patch (br1, code);
3659                         break;
3660                 }
3661                 case OP_TLS_GET: {
3662                         code = emit_tls_get (code, ins->dreg, ins->inst_offset);
3663                         break;
3664                 }
3665                 case OP_MEMORY_BARRIER: {
3666                         /* Not needed on x86 */
3667                         break;
3668                 }
3669                 case OP_ATOMIC_ADD_I4: {
3670                         int dreg = ins->dreg;
3671
3672                         if (dreg == ins->inst_basereg) {
3673                                 x86_push_reg (code, ins->sreg2);
3674                                 dreg = ins->sreg2;
3675                         } 
3676                         
3677                         if (dreg != ins->sreg2)
3678                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
3679
3680                         x86_prefix (code, X86_LOCK_PREFIX);
3681                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3682
3683                         if (dreg != ins->dreg) {
3684                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3685                                 x86_pop_reg (code, dreg);
3686                         }
3687
3688                         break;
3689                 }
3690                 case OP_ATOMIC_ADD_NEW_I4: {
3691                         int dreg = ins->dreg;
3692
3693                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
3694                         if (ins->sreg2 == dreg) {
3695                                 if (dreg == X86_EBX) {
3696                                         dreg = X86_EDI;
3697                                         if (ins->inst_basereg == X86_EDI)
3698                                                 dreg = X86_ESI;
3699                                 } else {
3700                                         dreg = X86_EBX;
3701                                         if (ins->inst_basereg == X86_EBX)
3702                                                 dreg = X86_EDI;
3703                                 }
3704                         } else if (ins->inst_basereg == dreg) {
3705                                 if (dreg == X86_EBX) {
3706                                         dreg = X86_EDI;
3707                                         if (ins->sreg2 == X86_EDI)
3708                                                 dreg = X86_ESI;
3709                                 } else {
3710                                         dreg = X86_EBX;
3711                                         if (ins->sreg2 == X86_EBX)
3712                                                 dreg = X86_EDI;
3713                                 }
3714                         }
3715
3716                         if (dreg != ins->dreg) {
3717                                 x86_push_reg (code, dreg);
3718                         }
3719
3720                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
3721                         x86_prefix (code, X86_LOCK_PREFIX);
3722                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3723                         /* dreg contains the old value, add with sreg2 value */
3724                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
3725                         
3726                         if (ins->dreg != dreg) {
3727                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3728                                 x86_pop_reg (code, dreg);
3729                         }
3730
3731                         break;
3732                 }
3733                 case OP_ATOMIC_EXCHANGE_I4:
3734                 case OP_ATOMIC_CAS_IMM_I4: {
3735                         guchar *br[2];
3736                         int sreg2 = ins->sreg2;
3737                         int breg = ins->inst_basereg;
3738
3739                         /* cmpxchg uses eax as comperand, need to make sure we can use it
3740                          * hack to overcome limits in x86 reg allocator 
3741                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
3742                          */
3743                         g_assert (ins->dreg == X86_EAX);
3744                         
3745                         /* We need the EAX reg for the cmpxchg */
3746                         if (ins->sreg2 == X86_EAX) {
3747                                 x86_push_reg (code, X86_EDX);
3748                                 x86_mov_reg_reg (code, X86_EDX, X86_EAX, 4);
3749                                 sreg2 = X86_EDX;
3750                         }
3751
3752                         if (breg == X86_EAX) {
3753                                 x86_push_reg (code, X86_ESI);
3754                                 x86_mov_reg_reg (code, X86_ESI, X86_EAX, 4);
3755                                 breg = X86_ESI;
3756                         }
3757
3758                         if (ins->opcode == OP_ATOMIC_CAS_IMM_I4) {
3759                                 x86_mov_reg_imm (code, X86_EAX, ins->backend.data);
3760
3761                                 x86_prefix (code, X86_LOCK_PREFIX);
3762                                 x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3763                         } else {
3764                                 x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
3765
3766                                 br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
3767                                 x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3768                                 br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
3769                                 x86_patch (br [1], br [0]);
3770                         }
3771
3772                         if (breg != ins->inst_basereg)
3773                                 x86_pop_reg (code, X86_ESI);
3774
3775                         if (ins->sreg2 != sreg2)
3776                                 x86_pop_reg (code, X86_EDX);
3777
3778                         break;
3779                 }
3780 #ifdef MONO_ARCH_SIMD_INTRINSICS
3781                 case OP_ADDPS:
3782                         x86_sse_alu_ps_reg_reg (code, X86_SSE_ADD, ins->sreg1, ins->sreg2);
3783                         break;
3784                 case OP_DIVPS:
3785                         x86_sse_alu_ps_reg_reg (code, X86_SSE_DIV, ins->sreg1, ins->sreg2);
3786                         break;
3787                 case OP_MULPS:
3788                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MUL, ins->sreg1, ins->sreg2);
3789                         break;
3790                 case OP_SUBPS:
3791                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SUB, ins->sreg1, ins->sreg2);
3792                         break;
3793                 case OP_MAXPS:
3794                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MAX, ins->sreg1, ins->sreg2);
3795                         break;
3796                 case OP_MINPS:
3797                         x86_sse_alu_ps_reg_reg (code, X86_SSE_MIN, ins->sreg1, ins->sreg2);
3798                         break;
3799                 case OP_SQRTPS:
3800                         x86_sse_alu_ps_reg_reg (code, X86_SSE_SQRT, ins->dreg, ins->sreg1);
3801                         break;
3802                 case OP_RSQRTPS:
3803                         x86_sse_alu_ps_reg_reg (code, X86_SSE_RSQRT, ins->dreg, ins->sreg1);
3804                         break;
3805                 case OP_ADDSUBPS:
3806                         x86_sse_alu_sd_reg_reg (code, X86_SSE_ADDSUB, ins->sreg1, ins->sreg2);
3807                         break;
3808                 case OP_HADDPS:
3809                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HADD, ins->sreg1, ins->sreg2);
3810                         break;
3811                 case OP_HSUBPS:
3812                         x86_sse_alu_sd_reg_reg (code, X86_SSE_HSUB, ins->sreg1, ins->sreg2);
3813                         break;
3814                 case OP_SHUFLEPS:
3815                         g_assert (ins->inst_c0 >= 0 && ins->inst_c0 <= 0xFF);
3816                         x86_pshufd_reg_reg (code, ins->dreg, ins->sreg1, ins->inst_c0);
3817                         break;
3818                 case OP_PAND:
3819                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PAND, ins->sreg1, ins->sreg2);
3820                         break;
3821                 case OP_POR:
3822                         x86_sse_alu_pd_reg_reg (code, X86_SSE_POR, ins->sreg1, ins->sreg2);
3823                         break;
3824                 case OP_PXOR:
3825                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->sreg1, ins->sreg2);
3826                         break;
3827                 case OP_EXTRACT_I4:
3828                         x86_movd_reg_xreg (code, ins->dreg, ins->sreg1);
3829                         break;
3830                 case OP_STOREX_MEMBASE_REG:
3831                 case OP_STOREX_MEMBASE:
3832                         x86_movups_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
3833                         break;
3834                 case OP_LOADX_MEMBASE:
3835                         x86_movups_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
3836                         break;
3837                 case OP_LOADX_ALIGNED_MEMBASE:
3838                         x86_movaps_reg_membase (code, ins->dreg, ins->sreg1, ins->inst_offset);
3839                         break;
3840                 case OP_STOREX_ALIGNED_MEMBASE_REG:
3841                         x86_movaps_membase_reg (code, ins->dreg, ins->inst_offset, ins->sreg1);
3842                         break;
3843                 case OP_XMOVE:
3844                         /*FIXME the peephole pass should have killed this*/
3845                         if (ins->dreg != ins->sreg1)
3846                                 x86_movaps_reg_reg (code, ins->dreg, ins->sreg1);
3847                         break;          
3848                 case OP_XZERO:
3849                         x86_sse_alu_pd_reg_reg (code, X86_SSE_PXOR, ins->dreg, ins->dreg);
3850                         break;
3851                 case OP_ICONV_TO_R8_RAW:
3852                         x86_mov_membase_reg (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, ins->sreg1, 4);
3853                         x86_fld_membase (code, ins->backend.spill_var->inst_basereg, ins->backend.spill_var->inst_offset, FALSE);
3854                         break;
3855                 case OP_PUSH_R4:
3856                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 4);
3857                         x86_fst_membase (code, X86_ESP, 0, FALSE, TRUE);
3858                         break;
3859                 case OP_LOADX_STACK: 
3860                         x86_movups_reg_membase (code, ins->dreg, X86_ESP, 0);
3861                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 16);
3862                         break;
3863 #endif
3864                 default:
3865                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
3866                         g_assert_not_reached ();
3867                 }
3868
3869                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
3870                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3871                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3872                         g_assert_not_reached ();
3873                 }
3874                
3875                 cpos += max_len;
3876         }
3877
3878         cfg->code_len = code - cfg->native_code;
3879 }
3880
3881 void
3882 mono_arch_register_lowlevel_calls (void)
3883 {
3884 }
3885
3886 void
3887 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3888 {
3889         MonoJumpInfo *patch_info;
3890         gboolean compile_aot = !run_cctors;
3891
3892         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3893                 unsigned char *ip = patch_info->ip.i + code;
3894                 const unsigned char *target;
3895
3896                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3897
3898                 if (compile_aot) {
3899                         switch (patch_info->type) {
3900                         case MONO_PATCH_INFO_BB:
3901                         case MONO_PATCH_INFO_LABEL:
3902                                 break;
3903                         default:
3904                                 /* No need to patch these */
3905                                 continue;
3906                         }
3907                 }
3908
3909                 switch (patch_info->type) {
3910                 case MONO_PATCH_INFO_IP:
3911                         *((gconstpointer *)(ip)) = target;
3912                         break;
3913                 case MONO_PATCH_INFO_CLASS_INIT: {
3914                         guint8 *code = ip;
3915                         /* Might already been changed to a nop */
3916                         x86_call_code (code, 0);
3917                         x86_patch (ip, target);
3918                         break;
3919                 }
3920                 case MONO_PATCH_INFO_ABS:
3921                 case MONO_PATCH_INFO_METHOD:
3922                 case MONO_PATCH_INFO_METHOD_JUMP:
3923                 case MONO_PATCH_INFO_INTERNAL_METHOD:
3924                 case MONO_PATCH_INFO_BB:
3925                 case MONO_PATCH_INFO_LABEL:
3926                 case MONO_PATCH_INFO_RGCTX_FETCH:
3927                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
3928                         x86_patch (ip, target);
3929                         break;
3930                 case MONO_PATCH_INFO_NONE:
3931                         break;
3932                 default: {
3933                         guint32 offset = mono_arch_get_patch_offset (ip);
3934                         *((gconstpointer *)(ip + offset)) = target;
3935                         break;
3936                 }
3937                 }
3938         }
3939 }
3940
3941 guint8 *
3942 mono_arch_emit_prolog (MonoCompile *cfg)
3943 {
3944         MonoMethod *method = cfg->method;
3945         MonoBasicBlock *bb;
3946         MonoMethodSignature *sig;
3947         MonoInst *inst;
3948         int alloc_size, pos, max_offset, i;
3949         guint8 *code;
3950
3951         cfg->code_size =  MAX (mono_method_get_header (method)->code_size * 4, 10240);
3952
3953         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3954                 cfg->code_size += 512;
3955
3956         code = cfg->native_code = g_malloc (cfg->code_size);
3957
3958         x86_push_reg (code, X86_EBP);
3959         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
3960
3961         alloc_size = cfg->stack_offset;
3962         pos = 0;
3963
3964         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3965                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
3966                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
3967                         guint8 *buf, *no_domain_branch;
3968
3969                         code = emit_tls_get (code, X86_EAX, appdomain_tls_offset);
3970                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
3971                         no_domain_branch = code;
3972                         x86_branch8 (code, X86_CC_NE, 0, 0);
3973                         code = emit_tls_get ( code, X86_EAX, lmf_tls_offset);
3974                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
3975                         buf = code;
3976                         x86_branch8 (code, X86_CC_NE, 0, 0);
3977                         x86_patch (no_domain_branch, code);
3978                         x86_push_imm (code, cfg->domain);
3979                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3980                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3981                         x86_patch (buf, code);
3982 #ifdef PLATFORM_WIN32
3983                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
3984                         /* FIXME: Add a separate key for LMF to avoid this */
3985                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3986 #endif
3987                 }
3988                 else {
3989                         g_assert (!cfg->compile_aot);
3990                         x86_push_imm (code, cfg->domain);
3991                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3992                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3993                 }
3994         }
3995
3996         if (method->save_lmf) {
3997                 pos += sizeof (MonoLMF);
3998
3999                 /* save the current IP */
4000                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
4001                 x86_push_imm_template (code);
4002
4003                 /* save all caller saved regs */
4004                 x86_push_reg (code, X86_EBP);
4005                 x86_push_reg (code, X86_ESI);
4006                 x86_push_reg (code, X86_EDI);
4007                 x86_push_reg (code, X86_EBX);
4008
4009                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4010                         /*
4011                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4012                          * through the mono_lmf_addr TLS variable.
4013                          */
4014                         /* %eax = previous_lmf */
4015                         x86_prefix (code, X86_GS_PREFIX);
4016                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
4017                         /* skip esp + method_info + lmf */
4018                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
4019                         /* push previous_lmf */
4020                         x86_push_reg (code, X86_EAX);
4021                         /* new lmf = ESP */
4022                         x86_prefix (code, X86_GS_PREFIX);
4023                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
4024                 } else {
4025                         /* get the address of lmf for the current thread */
4026                         /* 
4027                          * This is performance critical so we try to use some tricks to make
4028                          * it fast.
4029                          */                                                                        
4030
4031                         if (lmf_addr_tls_offset != -1) {
4032                                 /* Load lmf quicky using the GS register */
4033                                 code = emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
4034 #ifdef PLATFORM_WIN32
4035                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
4036                                 /* FIXME: Add a separate key for LMF to avoid this */
4037                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
4038 #endif
4039                         } else {
4040                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
4041                         }
4042
4043                         /* Skip esp + method info */
4044                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
4045
4046                         /* push lmf */
4047                         x86_push_reg (code, X86_EAX); 
4048                         /* push *lfm (previous_lmf) */
4049                         x86_push_membase (code, X86_EAX, 0);
4050                         /* *(lmf) = ESP */
4051                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
4052                 }
4053         } else {
4054
4055                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4056                         x86_push_reg (code, X86_EBX);
4057                         pos += 4;
4058                 }
4059
4060                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4061                         x86_push_reg (code, X86_EDI);
4062                         pos += 4;
4063                 }
4064
4065                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4066                         x86_push_reg (code, X86_ESI);
4067                         pos += 4;
4068                 }
4069         }
4070
4071         alloc_size -= pos;
4072
4073 #if __APPLE__
4074         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
4075         {
4076                 int tot = alloc_size + pos + 4 + 4; /* ret ip + ebp */
4077                 if (tot & 4) {
4078                         tot += 4;
4079                         alloc_size += 4;
4080                 }
4081                 if (tot & 8) {
4082                         alloc_size += 8;
4083                 }
4084         }
4085 #endif
4086
4087         if (alloc_size) {
4088                 /* See mono_emit_stack_alloc */
4089 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
4090                 guint32 remaining_size = alloc_size;
4091                 while (remaining_size >= 0x1000) {
4092                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
4093                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
4094                         remaining_size -= 0x1000;
4095                 }
4096                 if (remaining_size)
4097                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
4098 #else
4099                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
4100 #endif
4101         }
4102
4103 #if __APPLE__ && DEBUG_APPLE_ALIGNMENT
4104         /* check the stack is aligned */
4105         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
4106         x86_alu_reg_imm (code, X86_AND, X86_EDX, 15);
4107         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
4108         x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
4109         x86_breakpoint (code);
4110 #endif
4111
4112         /* compute max_offset in order to use short forward jumps */
4113         max_offset = 0;
4114         if (cfg->opt & MONO_OPT_BRANCH) {
4115                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4116                         MonoInst *ins;
4117                         bb->max_offset = max_offset;
4118
4119                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4120                                 max_offset += 6;
4121                         /* max alignment for loops */
4122                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
4123                                 max_offset += LOOP_ALIGNMENT;
4124
4125                         MONO_BB_FOR_EACH_INS (bb, ins) {
4126                                 if (ins->opcode == OP_LABEL)
4127                                         ins->inst_c1 = max_offset;
4128                                 
4129                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4130                         }
4131                 }
4132         }
4133
4134         /* store runtime generic context */
4135         if (cfg->rgctx_var) {
4136                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
4137
4138                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
4139         }
4140
4141         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4142                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4143
4144         /* load arguments allocated to register from the stack */
4145         sig = mono_method_signature (method);
4146         pos = 0;
4147
4148         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4149                 inst = cfg->args [pos];
4150                 if (inst->opcode == OP_REGVAR) {
4151                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
4152                         if (cfg->verbose_level > 2)
4153                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4154                 }
4155                 pos++;
4156         }
4157
4158         cfg->code_len = code - cfg->native_code;
4159
4160         g_assert (cfg->code_len < cfg->code_size);
4161
4162         return code;
4163 }
4164
4165 void
4166 mono_arch_emit_epilog (MonoCompile *cfg)
4167 {
4168         MonoMethod *method = cfg->method;
4169         MonoMethodSignature *sig = mono_method_signature (method);
4170         int quad, pos;
4171         guint32 stack_to_pop;
4172         guint8 *code;
4173         int max_epilog_size = 16;
4174         CallInfo *cinfo;
4175         
4176         if (cfg->method->save_lmf)
4177                 max_epilog_size += 128;
4178
4179         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4180                 cfg->code_size *= 2;
4181                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4182                 mono_jit_stats.code_reallocs++;
4183         }
4184
4185         code = cfg->native_code + cfg->code_len;
4186
4187         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4188                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4189
4190         /* the code restoring the registers must be kept in sync with OP_JMP */
4191         pos = 0;
4192         
4193         if (method->save_lmf) {
4194                 gint32 prev_lmf_reg;
4195                 gint32 lmf_offset = -sizeof (MonoLMF);
4196
4197                 /* check if we need to restore protection of the stack after a stack overflow */
4198                 if (mono_get_jit_tls_offset () != -1) {
4199                         guint8 *patch;
4200                         code = emit_tls_get (code, X86_ECX, mono_get_jit_tls_offset ());
4201                         /* we load the value in a separate instruction: this mechanism may be
4202                          * used later as a safer way to do thread interruption
4203                          */
4204                         x86_mov_reg_membase (code, X86_ECX, X86_ECX, G_STRUCT_OFFSET (MonoJitTlsData, restore_stack_prot), 4);
4205                         x86_alu_reg_imm (code, X86_CMP, X86_ECX, 0);
4206                         patch = code;
4207                         x86_branch8 (code, X86_CC_Z, 0, FALSE);
4208                         /* note that the call trampoline will preserve eax/edx */
4209                         x86_call_reg (code, X86_ECX);
4210                         x86_patch (patch, code);
4211                 } else {
4212                         /* FIXME: maybe save the jit tls in the prolog */
4213                 }
4214                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4215                         /*
4216                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4217                          * through the mono_lmf_addr TLS variable.
4218                          */
4219                         /* reg = previous_lmf */
4220                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4221
4222                         /* lmf = previous_lmf */
4223                         x86_prefix (code, X86_GS_PREFIX);
4224                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
4225                 } else {
4226                         /* Find a spare register */
4227                         switch (mini_type_get_underlying_type (cfg->generic_sharing_context, sig->ret)->type) {
4228                         case MONO_TYPE_I8:
4229                         case MONO_TYPE_U8:
4230                                 prev_lmf_reg = X86_EDI;
4231                                 cfg->used_int_regs |= (1 << X86_EDI);
4232                                 break;
4233                         default:
4234                                 prev_lmf_reg = X86_EDX;
4235                                 break;
4236                         }
4237
4238                         /* reg = previous_lmf */
4239                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4240
4241                         /* ecx = lmf */
4242                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
4243
4244                         /* *(lmf) = previous_lmf */
4245                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
4246                 }
4247
4248                 /* restore caller saved regs */
4249                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4250                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
4251                 }
4252
4253                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4254                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
4255                 }
4256                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4257                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
4258                 }
4259
4260                 /* EBP is restored by LEAVE */
4261         } else {
4262                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4263                         pos -= 4;
4264                 }
4265                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4266                         pos -= 4;
4267                 }
4268                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4269                         pos -= 4;
4270                 }
4271
4272                 if (pos)
4273                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
4274
4275                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4276                         x86_pop_reg (code, X86_ESI);
4277                 }
4278                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4279                         x86_pop_reg (code, X86_EDI);
4280                 }
4281                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4282                         x86_pop_reg (code, X86_EBX);
4283                 }
4284         }
4285
4286         /* Load returned vtypes into registers if needed */
4287         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
4288         if (cinfo->ret.storage == ArgValuetypeInReg) {
4289                 for (quad = 0; quad < 2; quad ++) {
4290                         switch (cinfo->ret.pair_storage [quad]) {
4291                         case ArgInIReg:
4292                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
4293                                 break;
4294                         case ArgOnFloatFpStack:
4295                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
4296                                 break;
4297                         case ArgOnDoubleFpStack:
4298                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
4299                                 break;
4300                         case ArgNone:
4301                                 break;
4302                         default:
4303                                 g_assert_not_reached ();
4304                         }
4305                 }
4306         }
4307
4308         x86_leave (code);
4309
4310         if (CALLCONV_IS_STDCALL (sig)) {
4311                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
4312
4313                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
4314         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
4315                 stack_to_pop = 4;
4316         else
4317                 stack_to_pop = 0;
4318
4319         if (stack_to_pop)
4320                 x86_ret_imm (code, stack_to_pop);
4321         else
4322                 x86_ret (code);
4323
4324         cfg->code_len = code - cfg->native_code;
4325
4326         g_assert (cfg->code_len < cfg->code_size);
4327 }
4328
4329 void
4330 mono_arch_emit_exceptions (MonoCompile *cfg)
4331 {
4332         MonoJumpInfo *patch_info;
4333         int nthrows, i;
4334         guint8 *code;
4335         MonoClass *exc_classes [16];
4336         guint8 *exc_throw_start [16], *exc_throw_end [16];
4337         guint32 code_size;
4338         int exc_count = 0;
4339
4340         /* Compute needed space */
4341         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4342                 if (patch_info->type == MONO_PATCH_INFO_EXC)
4343                         exc_count++;
4344         }
4345
4346         /* 
4347          * make sure we have enough space for exceptions
4348          * 16 is the size of two push_imm instructions and a call
4349          */
4350         if (cfg->compile_aot)
4351                 code_size = exc_count * 32;
4352         else
4353                 code_size = exc_count * 16;
4354
4355         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4356                 cfg->code_size *= 2;
4357                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4358                 mono_jit_stats.code_reallocs++;
4359         }
4360
4361         code = cfg->native_code + cfg->code_len;
4362
4363         nthrows = 0;
4364         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4365                 switch (patch_info->type) {
4366                 case MONO_PATCH_INFO_EXC: {
4367                         MonoClass *exc_class;
4368                         guint8 *buf, *buf2;
4369                         guint32 throw_ip;
4370
4371                         x86_patch (patch_info->ip.i + cfg->native_code, code);
4372
4373                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4374                         g_assert (exc_class);
4375                         throw_ip = patch_info->ip.i;
4376
4377                         /* Find a throw sequence for the same exception class */
4378                         for (i = 0; i < nthrows; ++i)
4379                                 if (exc_classes [i] == exc_class)
4380                                         break;
4381                         if (i < nthrows) {
4382                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
4383                                 x86_jump_code (code, exc_throw_start [i]);
4384                                 patch_info->type = MONO_PATCH_INFO_NONE;
4385                         }
4386                         else {
4387                                 guint32 size;
4388
4389                                 /* Compute size of code following the push <OFFSET> */
4390                                 size = 5 + 5;
4391
4392                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
4393                                         /* Use the shorter form */
4394                                         buf = buf2 = code;
4395                                         x86_push_imm (code, 0);
4396                                 }
4397                                 else {
4398                                         buf = code;
4399                                         x86_push_imm (code, 0xf0f0f0f0);
4400                                         buf2 = code;
4401                                 }
4402
4403                                 if (nthrows < 16) {
4404                                         exc_classes [nthrows] = exc_class;
4405                                         exc_throw_start [nthrows] = code;
4406                                 }
4407
4408                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
4409                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
4410                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4411                                 patch_info->ip.i = code - cfg->native_code;
4412                                 x86_call_code (code, 0);
4413                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
4414                                 while (buf < buf2)
4415                                         x86_nop (buf);
4416
4417                                 if (nthrows < 16) {
4418                                         exc_throw_end [nthrows] = code;
4419                                         nthrows ++;
4420                                 }
4421                         }
4422                         break;
4423                 }
4424                 default:
4425                         /* do nothing */
4426                         break;
4427                 }
4428         }
4429
4430         cfg->code_len = code - cfg->native_code;
4431
4432         g_assert (cfg->code_len < cfg->code_size);
4433 }
4434
4435 void
4436 mono_arch_flush_icache (guint8 *code, gint size)
4437 {
4438         /* not needed */
4439 }
4440
4441 void
4442 mono_arch_flush_register_windows (void)
4443 {
4444 }
4445
4446 gboolean 
4447 mono_arch_is_inst_imm (gint64 imm)
4448 {
4449         return TRUE;
4450 }
4451
4452 /*
4453  * Support for fast access to the thread-local lmf structure using the GS
4454  * segment register on NPTL + kernel 2.6.x.
4455  */
4456
4457 static gboolean tls_offset_inited = FALSE;
4458
4459 void
4460 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4461 {
4462         if (!tls_offset_inited) {
4463                 if (!getenv ("MONO_NO_TLS")) {
4464 #ifdef PLATFORM_WIN32
4465                         /* 
4466                          * We need to init this multiple times, since when we are first called, the key might not
4467                          * be initialized yet.
4468                          */
4469                         appdomain_tls_offset = mono_domain_get_tls_key ();
4470                         lmf_tls_offset = mono_get_jit_tls_key ();
4471                         thread_tls_offset = mono_thread_get_tls_key ();
4472
4473                         /* Only 64 tls entries can be accessed using inline code */
4474                         if (appdomain_tls_offset >= 64)
4475                                 appdomain_tls_offset = -1;
4476                         if (lmf_tls_offset >= 64)
4477                                 lmf_tls_offset = -1;
4478                         if (thread_tls_offset >= 64)
4479                                 thread_tls_offset = -1;
4480 #else
4481 #if MONO_XEN_OPT
4482                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
4483 #endif
4484                         tls_offset_inited = TRUE;
4485                         appdomain_tls_offset = mono_domain_get_tls_offset ();
4486                         lmf_tls_offset = mono_get_lmf_tls_offset ();
4487                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
4488                         thread_tls_offset = mono_thread_get_tls_offset ();
4489 #endif
4490                 }
4491         }               
4492 }
4493
4494 void
4495 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4496 {
4497 }
4498
4499 void
4500 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4501 {
4502         MonoCallInst *call = (MonoCallInst*)inst;
4503         CallInfo *cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, inst->signature, FALSE);
4504
4505         /* add the this argument */
4506         if (this_reg != -1) {
4507                 if (cinfo->args [0].storage == ArgInIReg) {
4508                         MonoInst *this;
4509                         MONO_INST_NEW (cfg, this, OP_MOVE);
4510                         this->type = this_type;
4511                         this->sreg1 = this_reg;
4512                         this->dreg = mono_regstate_next_int (cfg->rs);
4513                         mono_bblock_add_inst (cfg->cbb, this);
4514
4515                         mono_call_inst_add_outarg_reg (cfg, call, this->dreg, cinfo->args [0].reg, FALSE);
4516                 }
4517                 else {
4518                         MonoInst *this;
4519                         MONO_INST_NEW (cfg, this, OP_OUTARG);
4520                         this->type = this_type;
4521                         this->sreg1 = this_reg;
4522                         mono_bblock_add_inst (cfg->cbb, this);
4523                 }
4524         }
4525
4526         if (vt_reg != -1) {
4527                 MonoInst *vtarg;
4528
4529                 if (cinfo->ret.storage == ArgValuetypeInReg) {
4530                         /*
4531                          * The valuetype is in EAX:EDX after the call, needs to be copied to
4532                          * the stack. Save the address here, so the call instruction can
4533                          * access it.
4534                          */
4535                         MONO_INST_NEW (cfg, vtarg, OP_STORE_MEMBASE_REG);
4536                         vtarg->inst_destbasereg = X86_ESP;
4537                         vtarg->inst_offset = inst->stack_usage;
4538                         vtarg->sreg1 = vt_reg;
4539                         mono_bblock_add_inst (cfg->cbb, vtarg);
4540                 }
4541                 else if (cinfo->ret.storage == ArgInIReg) {
4542                         /* The return address is passed in a register */
4543                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4544                         vtarg->sreg1 = vt_reg;
4545                         vtarg->dreg = mono_regstate_next_int (cfg->rs);
4546                         mono_bblock_add_inst (cfg->cbb, vtarg);
4547
4548                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
4549                 } else {
4550                         MonoInst *vtarg;
4551                         MONO_INST_NEW (cfg, vtarg, OP_OUTARG);
4552                         vtarg->type = STACK_MP;
4553                         vtarg->sreg1 = vt_reg;
4554                         mono_bblock_add_inst (cfg->cbb, vtarg);
4555                 }
4556         }
4557 }
4558
4559 #ifdef MONO_ARCH_HAVE_IMT
4560
4561 // Linear handler, the bsearch head compare is shorter
4562 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
4563 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
4564 //        x86_patch(ins,target)
4565 //[1 + 5] x86_jump_mem(inst,mem)
4566
4567 #define CMP_SIZE 6
4568 #define BR_SMALL_SIZE 2
4569 #define BR_LARGE_SIZE 5
4570 #define JUMP_IMM_SIZE 6
4571 #define ENABLE_WRONG_METHOD_CHECK 0
4572
4573 static int
4574 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
4575 {
4576         int i, distance = 0;
4577         for (i = start; i < target; ++i)
4578                 distance += imt_entries [i]->chunk_size;
4579         return distance;
4580 }
4581
4582 /*
4583  * LOCKING: called with the domain lock held
4584  */
4585 gpointer
4586 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
4587         gpointer fail_tramp)
4588 {
4589         int i;
4590         int size = 0;
4591         guint8 *code, *start;
4592
4593         for (i = 0; i < count; ++i) {
4594                 MonoIMTCheckItem *item = imt_entries [i];
4595                 if (item->is_equals) {
4596                         if (item->check_target_idx) {
4597                                 if (!item->compare_done)
4598                                         item->chunk_size += CMP_SIZE;
4599                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
4600                         } else {
4601                                 if (fail_tramp) {
4602                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + JUMP_IMM_SIZE * 2;
4603                                 } else {
4604                                         item->chunk_size += JUMP_IMM_SIZE;
4605 #if ENABLE_WRONG_METHOD_CHECK
4606                                         item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
4607 #endif
4608                                 }
4609                         }
4610                 } else {
4611                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
4612                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4613                 }
4614                 size += item->chunk_size;
4615         }
4616         if (fail_tramp)
4617                 code = mono_method_alloc_generic_virtual_thunk (domain, size);
4618         else
4619                 code = mono_code_manager_reserve (domain->code_mp, size);
4620         start = code;
4621         for (i = 0; i < count; ++i) {
4622                 MonoIMTCheckItem *item = imt_entries [i];
4623                 item->code_target = code;
4624                 if (item->is_equals) {
4625                         if (item->check_target_idx) {
4626                                 if (!item->compare_done)
4627                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
4628                                 item->jmp_code = code;
4629                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
4630                                 if (fail_tramp)
4631                                         x86_jump_code (code, item->value.target_code);
4632                                 else
4633                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
4634                         } else {
4635                                 if (fail_tramp) {
4636                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
4637                                         item->jmp_code = code;
4638                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
4639                                         x86_jump_code (code, item->value.target_code);
4640                                         x86_patch (item->jmp_code, code);
4641                                         x86_jump_code (code, fail_tramp);
4642                                         item->jmp_code = NULL;
4643                                 } else {
4644                                         /* enable the commented code to assert on wrong method */
4645 #if ENABLE_WRONG_METHOD_CHECK
4646                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
4647                                         item->jmp_code = code;
4648                                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
4649 #endif
4650                                         x86_jump_mem (code, & (vtable->vtable [item->value.vtable_slot]));
4651 #if ENABLE_WRONG_METHOD_CHECK
4652                                         x86_patch (item->jmp_code, code);
4653                                         x86_breakpoint (code);
4654                                         item->jmp_code = NULL;
4655 #endif
4656                                 }
4657                         }
4658                 } else {
4659                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->key);
4660                         item->jmp_code = code;
4661                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
4662                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
4663                         else
4664                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
4665                 }
4666         }
4667         /* patch the branches to get to the target items */
4668         for (i = 0; i < count; ++i) {
4669                 MonoIMTCheckItem *item = imt_entries [i];
4670                 if (item->jmp_code) {
4671                         if (item->check_target_idx) {
4672                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4673                         }
4674                 }
4675         }
4676
4677         if (!fail_tramp)
4678                 mono_stats.imt_thunks_size += code - start;
4679         g_assert (code - start <= size);
4680         return start;
4681 }
4682
4683 MonoMethod*
4684 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4685 {
4686         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4687 }
4688
4689 MonoObject*
4690 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4691 {
4692         MonoMethodSignature *sig = mono_method_signature (method);
4693         CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
4694         int this_argument_offset;
4695         MonoObject *this_argument;
4696
4697         /* 
4698          * this is the offset of the this arg from esp as saved at the start of 
4699          * mono_arch_create_trampoline_code () in tramp-x86.c.
4700          */
4701         this_argument_offset = 5;
4702         if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
4703                 this_argument_offset++;
4704
4705         this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
4706
4707         g_free (cinfo);
4708         return this_argument;
4709 }
4710 #endif
4711
4712 MonoVTable*
4713 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4714 {
4715         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4716 }
4717
4718 MonoInst*
4719 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4720 {
4721         MonoInst *ins = NULL;
4722
4723         if (cmethod->klass == mono_defaults.math_class) {
4724                 if (strcmp (cmethod->name, "Sin") == 0) {
4725                         MONO_INST_NEW (cfg, ins, OP_SIN);
4726                         ins->inst_i0 = args [0];
4727                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4728                         MONO_INST_NEW (cfg, ins, OP_COS);
4729                         ins->inst_i0 = args [0];
4730                 } else if (strcmp (cmethod->name, "Tan") == 0) {
4731                         MONO_INST_NEW (cfg, ins, OP_TAN);
4732                         ins->inst_i0 = args [0];
4733                 } else if (strcmp (cmethod->name, "Atan") == 0) {
4734                         MONO_INST_NEW (cfg, ins, OP_ATAN);
4735                         ins->inst_i0 = args [0];
4736                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4737                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4738                         ins->inst_i0 = args [0];
4739                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4740                         MONO_INST_NEW (cfg, ins, OP_ABS);
4741                         ins->inst_i0 = args [0];
4742                 }
4743
4744                 if (cfg->opt & MONO_OPT_CMOV) {
4745                         int opcode = 0;
4746
4747                         if (strcmp (cmethod->name, "Min") == 0) {
4748                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4749                                         opcode = OP_IMIN;
4750                                 else if (fsig->params [0]->type == MONO_TYPE_U4)
4751                                         opcode = OP_IMIN_UN;
4752                         } else if (strcmp (cmethod->name, "Max") == 0) {
4753                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4754                                         opcode = OP_IMAX;
4755                                 else if (fsig->params [0]->type == MONO_TYPE_U4)
4756                                         opcode = OP_IMAX_UN;
4757                         }               
4758
4759                         if (opcode) {
4760                                 MONO_INST_NEW (cfg, ins, opcode);
4761                                 ins->inst_i0 = args [0];
4762                                 ins->inst_i1 = args [1];
4763                         }
4764                 }
4765
4766 #if 0
4767                 /* OP_FREM is not IEEE compatible */
4768                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
4769                         MONO_INST_NEW (cfg, ins, OP_FREM);
4770                         ins->inst_i0 = args [0];
4771                         ins->inst_i1 = args [1];
4772                 }
4773 #endif
4774         }
4775
4776         return ins;
4777 }
4778
4779 MonoInst*
4780 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4781 {
4782         MonoInst *ins = NULL;
4783         int opcode = 0;
4784
4785         if (cmethod->klass == mono_defaults.math_class) {
4786                 if (strcmp (cmethod->name, "Sin") == 0) {
4787                         opcode = OP_SIN;
4788                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4789                         opcode = OP_COS;
4790                 } else if (strcmp (cmethod->name, "Tan") == 0) {
4791                         opcode = OP_TAN;
4792                 } else if (strcmp (cmethod->name, "Atan") == 0) {
4793                         opcode = OP_ATAN;
4794                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4795                         opcode = OP_SQRT;
4796                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4797                         opcode = OP_ABS;
4798                 }
4799                 
4800                 if (opcode) {
4801                         MONO_INST_NEW (cfg, ins, opcode);
4802                         ins->type = STACK_R8;
4803                         ins->dreg = mono_alloc_freg (cfg);
4804                         ins->sreg1 = args [0]->dreg;
4805                         MONO_ADD_INS (cfg->cbb, ins);
4806                 }
4807
4808                 if (cfg->opt & MONO_OPT_CMOV) {
4809                         int opcode = 0;
4810
4811                         if (strcmp (cmethod->name, "Min") == 0) {
4812                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4813                                         opcode = OP_IMIN;
4814                         } else if (strcmp (cmethod->name, "Max") == 0) {
4815                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4816                                         opcode = OP_IMAX;
4817                         }               
4818
4819                         if (opcode) {
4820                                 MONO_INST_NEW (cfg, ins, opcode);
4821                                 ins->type = STACK_I4;
4822                                 ins->dreg = mono_alloc_ireg (cfg);
4823                                 ins->sreg1 = args [0]->dreg;
4824                                 ins->sreg2 = args [1]->dreg;
4825                                 MONO_ADD_INS (cfg->cbb, ins);
4826                         }
4827                 }
4828
4829 #if 0
4830                 /* OP_FREM is not IEEE compatible */
4831                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
4832                         MONO_INST_NEW (cfg, ins, OP_FREM);
4833                         ins->inst_i0 = args [0];
4834                         ins->inst_i1 = args [1];
4835                 }
4836 #endif
4837         }
4838
4839         return ins;
4840 }
4841
4842 gboolean
4843 mono_arch_print_tree (MonoInst *tree, int arity)
4844 {
4845         return 0;
4846 }
4847
4848 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4849 {
4850         MonoInst* ins;
4851
4852         return NULL;
4853
4854         if (appdomain_tls_offset == -1)
4855                 return NULL;
4856
4857         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4858         ins->inst_offset = appdomain_tls_offset;
4859         return ins;
4860 }
4861
4862 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4863 {
4864         MonoInst* ins;
4865
4866         if (thread_tls_offset == -1)
4867                 return NULL;
4868
4869         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4870         ins->inst_offset = thread_tls_offset;
4871         return ins;
4872 }
4873
4874 guint32
4875 mono_arch_get_patch_offset (guint8 *code)
4876 {
4877         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
4878                 return 2;
4879         else if ((code [0] == 0xba))
4880                 return 1;
4881         else if ((code [0] == 0x68))
4882                 /* push IMM */
4883                 return 1;
4884         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
4885                 /* push <OFFSET>(<REG>) */
4886                 return 2;
4887         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
4888                 /* call *<OFFSET>(<REG>) */
4889                 return 2;
4890         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
4891                 /* fldl <ADDR> */
4892                 return 2;
4893         else if ((code [0] == 0x58) && (code [1] == 0x05))
4894                 /* pop %eax; add <OFFSET>, %eax */
4895                 return 2;
4896         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
4897                 /* pop <REG>; add <OFFSET>, <REG> */
4898                 return 3;
4899         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
4900                 /* mov <REG>, imm */
4901                 return 1;
4902         else {
4903                 g_assert_not_reached ();
4904                 return -1;
4905         }
4906 }
4907
4908 /**
4909  * mono_breakpoint_clean_code:
4910  *
4911  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
4912  * breakpoints in the original code, they are removed in the copy.
4913  *
4914  * Returns TRUE if no sw breakpoint was present.
4915  */
4916 gboolean
4917 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
4918 {
4919         int i;
4920         gboolean can_write = TRUE;
4921         /*
4922          * If method_start is non-NULL we need to perform bound checks, since we access memory
4923          * at code - offset we could go before the start of the method and end up in a different
4924          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
4925          * instead.
4926          */
4927         if (!method_start || code - offset >= method_start) {
4928                 memcpy (buf, code - offset, size);
4929         } else {
4930                 int diff = code - method_start;
4931                 memset (buf, 0, size);
4932                 memcpy (buf + offset - diff, method_start, diff + size - offset);
4933         }
4934         code -= offset;
4935         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
4936                 int idx = mono_breakpoint_info_index [i];
4937                 guint8 *ptr;
4938                 if (idx < 1)
4939                         continue;
4940                 ptr = mono_breakpoint_info [idx].address;
4941                 if (ptr >= code && ptr < code + size) {
4942                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
4943                         can_write = FALSE;
4944                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
4945                         buf [ptr - code] = saved_byte;
4946                 }
4947         }
4948         return can_write;
4949 }
4950
4951 gpointer
4952 mono_arch_get_vcall_slot (guint8 *code, gpointer *regs, int *displacement)
4953 {
4954         guint8 buf [8];
4955         guint8 reg = 0;
4956         gint32 disp = 0;
4957
4958         mono_breakpoint_clean_code (NULL, code, 8, buf, sizeof (buf));
4959         code = buf + 8;
4960
4961         *displacement = 0;
4962
4963         /* go to the start of the call instruction
4964          *
4965          * address_byte = (m << 6) | (o << 3) | reg
4966          * call opcode: 0xff address_byte displacement
4967          * 0xff m=1,o=2 imm8
4968          * 0xff m=2,o=2 imm32
4969          */
4970         code -= 6;
4971
4972         /* 
4973          * A given byte sequence can match more than case here, so we have to be
4974          * really careful about the ordering of the cases. Longer sequences
4975          * come first.
4976          */
4977         if ((code [-2] == 0x8b) && (x86_modrm_mod (code [-1]) == 0x2) && (code [4] == 0xff) && (x86_modrm_reg (code [5]) == 0x2) && (x86_modrm_mod (code [5]) == 0x0)) {
4978                 /*
4979                  * This is an interface call
4980                  * 8b 80 0c e8 ff ff       mov    0xffffe80c(%eax),%eax
4981                  * ff 10                   call   *(%eax)
4982                  */
4983                 reg = x86_modrm_rm (code [5]);
4984                 disp = 0;
4985 #ifdef MONO_ARCH_HAVE_IMT
4986         } else if ((code [-2] == 0xba) && (code [3] == 0xff) && (x86_modrm_mod (code [4]) == 1) && (x86_modrm_reg (code [4]) == 2) && ((signed char)code [5] < 0)) {
4987                 /* IMT-based interface calls: with MONO_ARCH_IMT_REG == edx
4988                  * ba 14 f8 28 08          mov    $0x828f814,%edx
4989                  * ff 50 fc                call   *0xfffffffc(%eax)
4990                  */
4991                 reg = code [4] & 0x07;
4992                 disp = (signed char)code [5];
4993 #endif
4994         } else if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
4995                 reg = code [4] & 0x07;
4996                 disp = (signed char)code [5];
4997         } else {
4998                 if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
4999                         reg = code [1] & 0x07;
5000                         disp = *((gint32*)(code + 2));
5001                 } else if ((code [1] == 0xe8)) {
5002                         return NULL;
5003                 } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
5004                         /*
5005                          * This is a interface call
5006                          * 8b 40 30   mov    0x30(%eax),%eax
5007                          * ff 10      call   *(%eax)
5008                          */
5009                         disp = 0;
5010                         reg = code [5] & 0x07;
5011                 }
5012                 else
5013                         return NULL;
5014         }
5015
5016         *displacement = disp;
5017         return regs [reg];
5018 }
5019
5020 gpointer*
5021 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
5022 {
5023         gpointer vt;
5024         int displacement;
5025         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
5026         if (!vt)
5027                 return NULL;
5028         return (gpointer*)((char*)vt + displacement);
5029 }
5030
5031 gpointer
5032 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
5033                 gssize *regs, guint8 *code)
5034 {
5035         guint32 esp = regs [X86_ESP];
5036         CallInfo *cinfo;
5037         gpointer res;
5038
5039         if (!gsctx && code)
5040                 gsctx = mono_get_generic_context_from_code (code);
5041         cinfo = get_call_info (gsctx, NULL, sig, FALSE);
5042
5043         /*
5044          * The stack looks like:
5045          * <other args>
5046          * <this=delegate>
5047          * <possible vtype return address>
5048          * <return addr>
5049          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
5050          */
5051         res = (((MonoObject**)esp) [5 + (cinfo->args [0].offset / 4)]);
5052         g_free (cinfo);
5053         return res;
5054 }
5055
5056 #define MAX_ARCH_DELEGATE_PARAMS 10
5057
5058 gpointer
5059 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
5060 {
5061         guint8 *code, *start;
5062
5063         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
5064                 return NULL;
5065
5066         /* FIXME: Support more cases */
5067         if (MONO_TYPE_ISSTRUCT (sig->ret))
5068                 return NULL;
5069
5070         /*
5071          * The stack contains:
5072          * <delegate>
5073          * <return addr>
5074          */
5075
5076         if (has_target) {
5077                 static guint8* cached = NULL;
5078                 if (cached)
5079                         return cached;
5080                 
5081                 start = code = mono_global_codeman_reserve (64);
5082
5083                 /* Replace the this argument with the target */
5084                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
5085                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
5086                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
5087                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5088
5089                 g_assert ((code - start) < 64);
5090
5091                 mono_debug_add_delegate_trampoline (start, code - start);
5092
5093                 mono_memory_barrier ();
5094
5095                 cached = start;
5096         } else {
5097                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
5098                 int i = 0;
5099                 /* 8 for mov_reg and jump, plus 8 for each parameter */
5100                 int code_reserve = 8 + (sig->param_count * 8);
5101
5102                 for (i = 0; i < sig->param_count; ++i)
5103                         if (!mono_is_regsize_var (sig->params [i]))
5104                                 return NULL;
5105
5106                 code = cache [sig->param_count];
5107                 if (code)
5108                         return code;
5109
5110                 /*
5111                  * The stack contains:
5112                  * <args in reverse order>
5113                  * <delegate>
5114                  * <return addr>
5115                  *
5116                  * and we need:
5117                  * <args in reverse order>
5118                  * <return addr>
5119                  * 
5120                  * without unbalancing the stack.
5121                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
5122                  * and leaving original spot of first arg as placeholder in stack so
5123                  * when callee pops stack everything works.
5124                  */
5125
5126                 start = code = mono_global_codeman_reserve (code_reserve);
5127
5128                 /* store delegate for access to method_ptr */
5129                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
5130
5131                 /* move args up */
5132                 for (i = 0; i < sig->param_count; ++i) {
5133                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
5134                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
5135                 }
5136
5137                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
5138
5139                 g_assert ((code - start) < code_reserve);
5140
5141                 mono_debug_add_delegate_trampoline (start, code - start);
5142
5143                 mono_memory_barrier ();
5144
5145                 cache [sig->param_count] = start;
5146         }
5147
5148         return start;
5149 }
5150
5151 gpointer
5152 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5153 {
5154         switch (reg) {
5155         case X86_ECX: return (gpointer)ctx->ecx;
5156         case X86_EDX: return (gpointer)ctx->edx;
5157         case X86_EBP: return (gpointer)ctx->ebp;
5158         case X86_ESP: return (gpointer)ctx->esp;
5159         default: return ((gpointer)(&ctx->eax)[reg]);
5160         }
5161 }