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