2008-07-09 Zoltan Varga <vargaz@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_IMIN_UN:
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_GT, FALSE, ins->dreg, ins->sreg2);
2968                         break;
2969                 case OP_IMAX:
2970                         g_assert (cfg->opt & MONO_OPT_CMOV);
2971                         g_assert (ins->dreg == ins->sreg1);
2972                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2973                         x86_cmov_reg (code, X86_CC_LT, TRUE, ins->dreg, ins->sreg2);
2974                         break;
2975                 case OP_IMAX_UN:
2976                         g_assert (cfg->opt & MONO_OPT_CMOV);
2977                         g_assert (ins->dreg == ins->sreg1);
2978                         x86_alu_reg_reg (code, X86_CMP, ins->sreg1, ins->sreg2);
2979                         x86_cmov_reg (code, X86_CC_LT, FALSE, ins->dreg, ins->sreg2);
2980                         break;
2981                 case OP_X86_FPOP:
2982                         x86_fstp (code, 0);
2983                         break;
2984                 case OP_X86_FXCH:
2985                         x86_fxch (code, ins->inst_imm);
2986                         break;
2987                 case OP_FREM: {
2988                         guint8 *l1, *l2;
2989
2990                         x86_push_reg (code, X86_EAX);
2991                         /* we need to exchange ST(0) with ST(1) */
2992                         x86_fxch (code, 1);
2993
2994                         /* this requires a loop, because fprem somtimes 
2995                          * returns a partial remainder */
2996                         l1 = code;
2997                         /* looks like MS is using fprem instead of the IEEE compatible fprem1 */
2998                         /* x86_fprem1 (code); */
2999                         x86_fprem (code);
3000                         x86_fnstsw (code);
3001                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_C2);
3002                         l2 = code + 2;
3003                         x86_branch8 (code, X86_CC_NE, l1 - l2, FALSE);
3004
3005                         /* pop result */
3006                         x86_fstp (code, 1);
3007
3008                         x86_pop_reg (code, X86_EAX);
3009                         break;
3010                 }
3011                 case OP_FCOMPARE:
3012                         if (cfg->opt & MONO_OPT_FCMOV) {
3013                                 x86_fcomip (code, 1);
3014                                 x86_fstp (code, 0);
3015                                 break;
3016                         }
3017                         /* this overwrites EAX */
3018                         EMIT_FPCOMPARE(code);
3019                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3020                         break;
3021                 case OP_FCEQ:
3022                         if (cfg->opt & MONO_OPT_FCMOV) {
3023                                 /* zeroing the register at the start results in 
3024                                  * shorter and faster code (we can also remove the widening op)
3025                                  */
3026                                 guchar *unordered_check;
3027                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3028                                 x86_fcomip (code, 1);
3029                                 x86_fstp (code, 0);
3030                                 unordered_check = code;
3031                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3032                                 x86_set_reg (code, X86_CC_EQ, ins->dreg, FALSE);
3033                                 x86_patch (unordered_check, code);
3034                                 break;
3035                         }
3036                         if (ins->dreg != X86_EAX) 
3037                                 x86_push_reg (code, X86_EAX);
3038
3039                         EMIT_FPCOMPARE(code);
3040                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3041                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3042                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3043                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3044
3045                         if (ins->dreg != X86_EAX) 
3046                                 x86_pop_reg (code, X86_EAX);
3047                         break;
3048                 case OP_FCLT:
3049                 case OP_FCLT_UN:
3050                         if (cfg->opt & MONO_OPT_FCMOV) {
3051                                 /* zeroing the register at the start results in 
3052                                  * shorter and faster code (we can also remove the widening op)
3053                                  */
3054                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3055                                 x86_fcomip (code, 1);
3056                                 x86_fstp (code, 0);
3057                                 if (ins->opcode == OP_FCLT_UN) {
3058                                         guchar *unordered_check = code;
3059                                         guchar *jump_to_end;
3060                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3061                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3062                                         jump_to_end = code;
3063                                         x86_jump8 (code, 0);
3064                                         x86_patch (unordered_check, code);
3065                                         x86_inc_reg (code, ins->dreg);
3066                                         x86_patch (jump_to_end, code);
3067                                 } else {
3068                                         x86_set_reg (code, X86_CC_GT, ins->dreg, FALSE);
3069                                 }
3070                                 break;
3071                         }
3072                         if (ins->dreg != X86_EAX) 
3073                                 x86_push_reg (code, X86_EAX);
3074
3075                         EMIT_FPCOMPARE(code);
3076                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3077                         if (ins->opcode == OP_FCLT_UN) {
3078                                 guchar *is_not_zero_check, *end_jump;
3079                                 is_not_zero_check = code;
3080                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3081                                 end_jump = code;
3082                                 x86_jump8 (code, 0);
3083                                 x86_patch (is_not_zero_check, code);
3084                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3085
3086                                 x86_patch (end_jump, code);
3087                         }
3088                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3089                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3090
3091                         if (ins->dreg != X86_EAX) 
3092                                 x86_pop_reg (code, X86_EAX);
3093                         break;
3094                 case OP_FCGT:
3095                 case OP_FCGT_UN:
3096                         if (cfg->opt & MONO_OPT_FCMOV) {
3097                                 /* zeroing the register at the start results in 
3098                                  * shorter and faster code (we can also remove the widening op)
3099                                  */
3100                                 guchar *unordered_check;
3101                                 x86_alu_reg_reg (code, X86_XOR, ins->dreg, ins->dreg);
3102                                 x86_fcomip (code, 1);
3103                                 x86_fstp (code, 0);
3104                                 if (ins->opcode == OP_FCGT) {
3105                                         unordered_check = code;
3106                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3107                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3108                                         x86_patch (unordered_check, code);
3109                                 } else {
3110                                         x86_set_reg (code, X86_CC_LT, ins->dreg, FALSE);
3111                                 }
3112                                 break;
3113                         }
3114                         if (ins->dreg != X86_EAX) 
3115                                 x86_push_reg (code, X86_EAX);
3116
3117                         EMIT_FPCOMPARE(code);
3118                         x86_alu_reg_imm (code, X86_AND, X86_EAX, X86_FP_CC_MASK);
3119                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3120                         if (ins->opcode == OP_FCGT_UN) {
3121                                 guchar *is_not_zero_check, *end_jump;
3122                                 is_not_zero_check = code;
3123                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3124                                 end_jump = code;
3125                                 x86_jump8 (code, 0);
3126                                 x86_patch (is_not_zero_check, code);
3127                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3128         
3129                                 x86_patch (end_jump, code);
3130                         }
3131                         x86_set_reg (code, X86_CC_EQ, ins->dreg, TRUE);
3132                         x86_widen_reg (code, ins->dreg, ins->dreg, FALSE, FALSE);
3133
3134                         if (ins->dreg != X86_EAX) 
3135                                 x86_pop_reg (code, X86_EAX);
3136                         break;
3137                 case OP_FBEQ:
3138                         if (cfg->opt & MONO_OPT_FCMOV) {
3139                                 guchar *jump = code;
3140                                 x86_branch8 (code, X86_CC_P, 0, TRUE);
3141                                 EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3142                                 x86_patch (jump, code);
3143                                 break;
3144                         }
3145                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0x4000);
3146                         EMIT_COND_BRANCH (ins, X86_CC_EQ, TRUE);
3147                         break;
3148                 case OP_FBNE_UN:
3149                         /* Branch if C013 != 100 */
3150                         if (cfg->opt & MONO_OPT_FCMOV) {
3151                                 /* branch if !ZF or (PF|CF) */
3152                                 EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3153                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3154                                 EMIT_COND_BRANCH (ins, X86_CC_B, FALSE);
3155                                 break;
3156                         }
3157                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3158                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3159                         break;
3160                 case OP_FBLT:
3161                         if (cfg->opt & MONO_OPT_FCMOV) {
3162                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3163                                 break;
3164                         }
3165                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3166                         break;
3167                 case OP_FBLT_UN:
3168                         if (cfg->opt & MONO_OPT_FCMOV) {
3169                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3170                                 EMIT_COND_BRANCH (ins, X86_CC_GT, FALSE);
3171                                 break;
3172                         }
3173                         if (ins->opcode == OP_FBLT_UN) {
3174                                 guchar *is_not_zero_check, *end_jump;
3175                                 is_not_zero_check = code;
3176                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3177                                 end_jump = code;
3178                                 x86_jump8 (code, 0);
3179                                 x86_patch (is_not_zero_check, code);
3180                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3181
3182                                 x86_patch (end_jump, code);
3183                         }
3184                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3185                         break;
3186                 case OP_FBGT:
3187                 case OP_FBGT_UN:
3188                         if (cfg->opt & MONO_OPT_FCMOV) {
3189                                 if (ins->opcode == OP_FBGT) {
3190                                         guchar *br1;
3191
3192                                         /* skip branch if C1=1 */
3193                                         br1 = code;
3194                                         x86_branch8 (code, X86_CC_P, 0, FALSE);
3195                                         /* branch if (C0 | C3) = 1 */
3196                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3197                                         x86_patch (br1, code);
3198                                 } else {
3199                                         EMIT_COND_BRANCH (ins, X86_CC_LT, FALSE);
3200                                 }
3201                                 break;
3202                         }
3203                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3204                         if (ins->opcode == OP_FBGT_UN) {
3205                                 guchar *is_not_zero_check, *end_jump;
3206                                 is_not_zero_check = code;
3207                                 x86_branch8 (code, X86_CC_NZ, 0, TRUE);
3208                                 end_jump = code;
3209                                 x86_jump8 (code, 0);
3210                                 x86_patch (is_not_zero_check, code);
3211                                 x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_CC_MASK);
3212
3213                                 x86_patch (end_jump, code);
3214                         }
3215                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3216                         break;
3217                 case OP_FBGE:
3218                         /* Branch if C013 == 100 or 001 */
3219                         if (cfg->opt & MONO_OPT_FCMOV) {
3220                                 guchar *br1;
3221
3222                                 /* skip branch if C1=1 */
3223                                 br1 = code;
3224                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3225                                 /* branch if (C0 | C3) = 1 */
3226                                 EMIT_COND_BRANCH (ins, X86_CC_BE, FALSE);
3227                                 x86_patch (br1, code);
3228                                 break;
3229                         }
3230                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3231                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3232                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C3);
3233                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3234                         break;
3235                 case OP_FBGE_UN:
3236                         /* Branch if C013 == 000 */
3237                         if (cfg->opt & MONO_OPT_FCMOV) {
3238                                 EMIT_COND_BRANCH (ins, X86_CC_LE, FALSE);
3239                                 break;
3240                         }
3241                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3242                         break;
3243                 case OP_FBLE:
3244                         /* Branch if C013=000 or 100 */
3245                         if (cfg->opt & MONO_OPT_FCMOV) {
3246                                 guchar *br1;
3247
3248                                 /* skip branch if C1=1 */
3249                                 br1 = code;
3250                                 x86_branch8 (code, X86_CC_P, 0, FALSE);
3251                                 /* branch if C0=0 */
3252                                 EMIT_COND_BRANCH (ins, X86_CC_NB, FALSE);
3253                                 x86_patch (br1, code);
3254                                 break;
3255                         }
3256                         x86_alu_reg_imm (code, X86_AND, X86_EAX, (X86_FP_C0|X86_FP_C1));
3257                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, 0);
3258                         EMIT_COND_BRANCH (ins, X86_CC_EQ, FALSE);
3259                         break;
3260                 case OP_FBLE_UN:
3261                         /* Branch if C013 != 001 */
3262                         if (cfg->opt & MONO_OPT_FCMOV) {
3263                                 EMIT_COND_BRANCH (ins, X86_CC_P, FALSE);
3264                                 EMIT_COND_BRANCH (ins, X86_CC_GE, FALSE);
3265                                 break;
3266                         }
3267                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3268                         EMIT_COND_BRANCH (ins, X86_CC_NE, FALSE);
3269                         break;
3270                 case OP_CKFINITE: {
3271                         guchar *br1;
3272                         x86_push_reg (code, X86_EAX);
3273                         x86_fxam (code);
3274                         x86_fnstsw (code);
3275                         x86_alu_reg_imm (code, X86_AND, X86_EAX, 0x4100);
3276                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, X86_FP_C0);
3277                         x86_pop_reg (code, X86_EAX);
3278
3279                         /* Have to clean up the fp stack before throwing the exception */
3280                         br1 = code;
3281                         x86_branch8 (code, X86_CC_NE, 0, FALSE);
3282
3283                         x86_fstp (code, 0);                     
3284                         EMIT_COND_SYSTEM_EXCEPTION (X86_CC_EQ, FALSE, "ArithmeticException");
3285
3286                         x86_patch (br1, code);
3287                         break;
3288                 }
3289                 case OP_TLS_GET: {
3290                         code = emit_tls_get (code, ins->dreg, ins->inst_offset);
3291                         break;
3292                 }
3293                 case OP_MEMORY_BARRIER: {
3294                         /* Not needed on x86 */
3295                         break;
3296                 }
3297                 case OP_ATOMIC_ADD_I4: {
3298                         int dreg = ins->dreg;
3299
3300                         if (dreg == ins->inst_basereg) {
3301                                 x86_push_reg (code, ins->sreg2);
3302                                 dreg = ins->sreg2;
3303                         } 
3304                         
3305                         if (dreg != ins->sreg2)
3306                                 x86_mov_reg_reg (code, ins->dreg, ins->sreg2, 4);
3307
3308                         x86_prefix (code, X86_LOCK_PREFIX);
3309                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3310
3311                         if (dreg != ins->dreg) {
3312                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3313                                 x86_pop_reg (code, dreg);
3314                         }
3315
3316                         break;
3317                 }
3318                 case OP_ATOMIC_ADD_NEW_I4: {
3319                         int dreg = ins->dreg;
3320
3321                         /* hack: limit in regalloc, dreg != sreg1 && dreg != sreg2 */
3322                         if (ins->sreg2 == dreg) {
3323                                 if (dreg == X86_EBX) {
3324                                         dreg = X86_EDI;
3325                                         if (ins->inst_basereg == X86_EDI)
3326                                                 dreg = X86_ESI;
3327                                 } else {
3328                                         dreg = X86_EBX;
3329                                         if (ins->inst_basereg == X86_EBX)
3330                                                 dreg = X86_EDI;
3331                                 }
3332                         } else if (ins->inst_basereg == dreg) {
3333                                 if (dreg == X86_EBX) {
3334                                         dreg = X86_EDI;
3335                                         if (ins->sreg2 == X86_EDI)
3336                                                 dreg = X86_ESI;
3337                                 } else {
3338                                         dreg = X86_EBX;
3339                                         if (ins->sreg2 == X86_EBX)
3340                                                 dreg = X86_EDI;
3341                                 }
3342                         }
3343
3344                         if (dreg != ins->dreg) {
3345                                 x86_push_reg (code, dreg);
3346                         }
3347
3348                         x86_mov_reg_reg (code, dreg, ins->sreg2, 4);
3349                         x86_prefix (code, X86_LOCK_PREFIX);
3350                         x86_xadd_membase_reg (code, ins->inst_basereg, ins->inst_offset, dreg, 4);
3351                         /* dreg contains the old value, add with sreg2 value */
3352                         x86_alu_reg_reg (code, X86_ADD, dreg, ins->sreg2);
3353                         
3354                         if (ins->dreg != dreg) {
3355                                 x86_mov_reg_reg (code, ins->dreg, dreg, 4);
3356                                 x86_pop_reg (code, dreg);
3357                         }
3358
3359                         break;
3360                 }
3361                 case OP_ATOMIC_EXCHANGE_I4:
3362                 case OP_ATOMIC_CAS_IMM_I4: {
3363                         guchar *br[2];
3364                         int sreg2 = ins->sreg2;
3365                         int breg = ins->inst_basereg;
3366
3367                         /* cmpxchg uses eax as comperand, need to make sure we can use it
3368                          * hack to overcome limits in x86 reg allocator 
3369                          * (req: dreg == eax and sreg2 != eax and breg != eax) 
3370                          */
3371                         g_assert (ins->dreg == X86_EAX);
3372                         
3373                         /* We need the EAX reg for the cmpxchg */
3374                         if (ins->sreg2 == X86_EAX) {
3375                                 x86_push_reg (code, X86_EDX);
3376                                 x86_mov_reg_reg (code, X86_EDX, X86_EAX, 4);
3377                                 sreg2 = X86_EDX;
3378                         }
3379
3380                         if (breg == X86_EAX) {
3381                                 x86_push_reg (code, X86_ESI);
3382                                 x86_mov_reg_reg (code, X86_ESI, X86_EAX, 4);
3383                                 breg = X86_ESI;
3384                         }
3385
3386                         if (ins->opcode == OP_ATOMIC_CAS_IMM_I4) {
3387                                 x86_mov_reg_imm (code, X86_EAX, ins->backend.data);
3388
3389                                 x86_prefix (code, X86_LOCK_PREFIX);
3390                                 x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3391                         } else {
3392                                 x86_mov_reg_membase (code, X86_EAX, breg, ins->inst_offset, 4);
3393
3394                                 br [0] = code; x86_prefix (code, X86_LOCK_PREFIX);
3395                                 x86_cmpxchg_membase_reg (code, breg, ins->inst_offset, sreg2);
3396                                 br [1] = code; x86_branch8 (code, X86_CC_NE, -1, FALSE);
3397                                 x86_patch (br [1], br [0]);
3398                         }
3399
3400                         if (breg != ins->inst_basereg)
3401                                 x86_pop_reg (code, X86_ESI);
3402
3403                         if (ins->sreg2 != sreg2)
3404                                 x86_pop_reg (code, X86_EDX);
3405
3406                         break;
3407                 }
3408                 default:
3409                         g_warning ("unknown opcode %s\n", mono_inst_name (ins->opcode));
3410                         g_assert_not_reached ();
3411                 }
3412
3413                 if (G_UNLIKELY ((code - cfg->native_code - offset) > max_len)) {
3414                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
3415                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
3416                         g_assert_not_reached ();
3417                 }
3418                
3419                 cpos += max_len;
3420         }
3421
3422         cfg->code_len = code - cfg->native_code;
3423 }
3424
3425 void
3426 mono_arch_register_lowlevel_calls (void)
3427 {
3428 }
3429
3430 void
3431 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
3432 {
3433         MonoJumpInfo *patch_info;
3434         gboolean compile_aot = !run_cctors;
3435
3436         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
3437                 unsigned char *ip = patch_info->ip.i + code;
3438                 const unsigned char *target;
3439
3440                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
3441
3442                 if (compile_aot) {
3443                         switch (patch_info->type) {
3444                         case MONO_PATCH_INFO_BB:
3445                         case MONO_PATCH_INFO_LABEL:
3446                                 break;
3447                         default:
3448                                 /* No need to patch these */
3449                                 continue;
3450                         }
3451                 }
3452
3453                 switch (patch_info->type) {
3454                 case MONO_PATCH_INFO_IP:
3455                         *((gconstpointer *)(ip)) = target;
3456                         break;
3457                 case MONO_PATCH_INFO_CLASS_INIT: {
3458                         guint8 *code = ip;
3459                         /* Might already been changed to a nop */
3460                         x86_call_code (code, 0);
3461                         x86_patch (ip, target);
3462                         break;
3463                 }
3464                 case MONO_PATCH_INFO_ABS:
3465                 case MONO_PATCH_INFO_METHOD:
3466                 case MONO_PATCH_INFO_METHOD_JUMP:
3467                 case MONO_PATCH_INFO_INTERNAL_METHOD:
3468                 case MONO_PATCH_INFO_BB:
3469                 case MONO_PATCH_INFO_LABEL:
3470                         x86_patch (ip, target);
3471                         break;
3472                 case MONO_PATCH_INFO_NONE:
3473                         break;
3474                 default: {
3475                         guint32 offset = mono_arch_get_patch_offset (ip);
3476                         *((gconstpointer *)(ip + offset)) = target;
3477                         break;
3478                 }
3479                 }
3480         }
3481 }
3482
3483 guint8 *
3484 mono_arch_emit_prolog (MonoCompile *cfg)
3485 {
3486         MonoMethod *method = cfg->method;
3487         MonoBasicBlock *bb;
3488         MonoMethodSignature *sig;
3489         MonoInst *inst;
3490         int alloc_size, pos, max_offset, i;
3491         guint8 *code;
3492
3493         cfg->code_size =  MAX (mono_method_get_header (method)->code_size * 4, 10240);
3494
3495         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3496                 cfg->code_size += 512;
3497
3498         code = cfg->native_code = g_malloc (cfg->code_size);
3499
3500         x86_push_reg (code, X86_EBP);
3501         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
3502
3503         alloc_size = cfg->stack_offset;
3504         pos = 0;
3505
3506         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3507                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
3508                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
3509                         guint8 *buf, *no_domain_branch;
3510
3511                         code = emit_tls_get (code, X86_EAX, appdomain_tls_offset);
3512                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
3513                         no_domain_branch = code;
3514                         x86_branch8 (code, X86_CC_NE, 0, 0);
3515                         code = emit_tls_get ( code, X86_EAX, lmf_tls_offset);
3516                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
3517                         buf = code;
3518                         x86_branch8 (code, X86_CC_NE, 0, 0);
3519                         x86_patch (no_domain_branch, code);
3520                         x86_push_imm (code, cfg->domain);
3521                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3522                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3523                         x86_patch (buf, code);
3524 #ifdef PLATFORM_WIN32
3525                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
3526                         /* FIXME: Add a separate key for LMF to avoid this */
3527                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3528 #endif
3529                 } else {
3530                         g_assert (!cfg->compile_aot);
3531                         x86_push_imm (code, cfg->domain);
3532                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3533                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3534                 }
3535         }
3536
3537         if (method->save_lmf) {
3538                 pos += sizeof (MonoLMF);
3539
3540                 /* save the current IP */
3541                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3542                 x86_push_imm_template (code);
3543
3544                 /* save all caller saved regs */
3545                 x86_push_reg (code, X86_EBP);
3546                 x86_push_reg (code, X86_ESI);
3547                 x86_push_reg (code, X86_EDI);
3548                 x86_push_reg (code, X86_EBX);
3549
3550                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
3551                         /*
3552                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
3553                          * through the mono_lmf_addr TLS variable.
3554                          */
3555                         /* %eax = previous_lmf */
3556                         x86_prefix (code, X86_GS_PREFIX);
3557                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
3558                         /* skip esp + method_info + lmf */
3559                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
3560                         /* push previous_lmf */
3561                         x86_push_reg (code, X86_EAX);
3562                         /* new lmf = ESP */
3563                         x86_prefix (code, X86_GS_PREFIX);
3564                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
3565                 } else {
3566                         /* get the address of lmf for the current thread */
3567                         /* 
3568                          * This is performance critical so we try to use some tricks to make
3569                          * it fast.
3570                          */                                                                        
3571
3572                         if (lmf_addr_tls_offset != -1) {
3573                                 /* Load lmf quicky using the GS register */
3574                                 code = emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
3575 #ifdef PLATFORM_WIN32
3576                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
3577                                 /* FIXME: Add a separate key for LMF to avoid this */
3578                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3579 #endif
3580                         } else {
3581                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
3582                         }
3583
3584                         /* Skip esp + method info */
3585                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3586
3587                         /* push lmf */
3588                         x86_push_reg (code, X86_EAX); 
3589                         /* push *lfm (previous_lmf) */
3590                         x86_push_membase (code, X86_EAX, 0);
3591                         /* *(lmf) = ESP */
3592                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
3593                 }
3594         } else {
3595
3596                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3597                         x86_push_reg (code, X86_EBX);
3598                         pos += 4;
3599                 }
3600
3601                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3602                         x86_push_reg (code, X86_EDI);
3603                         pos += 4;
3604                 }
3605
3606                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3607                         x86_push_reg (code, X86_ESI);
3608                         pos += 4;
3609                 }
3610         }
3611
3612         alloc_size -= pos;
3613
3614 #if __APPLE__
3615         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
3616         {
3617                 int tot = alloc_size + pos + 4 + 4; /* ret ip + ebp */
3618                 if (tot & 4) {
3619                         tot += 4;
3620                         alloc_size += 4;
3621                 }
3622                 if (tot & 8) {
3623                         alloc_size += 8;
3624                 }
3625         }
3626 #endif
3627
3628         if (alloc_size) {
3629                 /* See mono_emit_stack_alloc */
3630 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3631                 guint32 remaining_size = alloc_size;
3632                 while (remaining_size >= 0x1000) {
3633                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
3634                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
3635                         remaining_size -= 0x1000;
3636                 }
3637                 if (remaining_size)
3638                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
3639 #else
3640                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
3641 #endif
3642         }
3643
3644 #if __APPLE_
3645         /* check the stack is aligned */
3646         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
3647         x86_alu_reg_imm (code, X86_AND, X86_EDX, 15);
3648         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
3649         x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
3650         x86_breakpoint (code);
3651 #endif
3652
3653         /* compute max_offset in order to use short forward jumps */
3654         max_offset = 0;
3655         if (cfg->opt & MONO_OPT_BRANCH) {
3656                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
3657                         MonoInst *ins;
3658                         bb->max_offset = max_offset;
3659
3660                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
3661                                 max_offset += 6;
3662                         /* max alignment for loops */
3663                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
3664                                 max_offset += LOOP_ALIGNMENT;
3665
3666                         MONO_BB_FOR_EACH_INS (bb, ins) {
3667                                 if (ins->opcode == OP_LABEL)
3668                                         ins->inst_c1 = max_offset;
3669                                 
3670                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3671                         }
3672                 }
3673         }
3674
3675         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3676                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
3677
3678         /* store runtime generic context */
3679         if (cfg->rgctx_var) {
3680                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
3681
3682                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
3683         }
3684
3685         /* load arguments allocated to register from the stack */
3686         sig = mono_method_signature (method);
3687         pos = 0;
3688
3689         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3690                 inst = cfg->args [pos];
3691                 if (inst->opcode == OP_REGVAR) {
3692                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
3693                         if (cfg->verbose_level > 2)
3694                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
3695                 }
3696                 pos++;
3697         }
3698
3699         cfg->code_len = code - cfg->native_code;
3700
3701         g_assert (cfg->code_len < cfg->code_size);
3702
3703         return code;
3704 }
3705
3706 void
3707 mono_arch_emit_epilog (MonoCompile *cfg)
3708 {
3709         MonoMethod *method = cfg->method;
3710         MonoMethodSignature *sig = mono_method_signature (method);
3711         int quad, pos;
3712         guint32 stack_to_pop;
3713         guint8 *code;
3714         int max_epilog_size = 16;
3715         CallInfo *cinfo;
3716         
3717         if (cfg->method->save_lmf)
3718                 max_epilog_size += 128;
3719
3720         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3721                 cfg->code_size *= 2;
3722                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3723                 mono_jit_stats.code_reallocs++;
3724         }
3725
3726         code = cfg->native_code + cfg->code_len;
3727
3728         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
3729                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
3730
3731         /* the code restoring the registers must be kept in sync with OP_JMP */
3732         pos = 0;
3733         
3734         if (method->save_lmf) {
3735                 gint32 prev_lmf_reg;
3736                 gint32 lmf_offset = -sizeof (MonoLMF);
3737
3738                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
3739                         /*
3740                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
3741                          * through the mono_lmf_addr TLS variable.
3742                          */
3743                         /* reg = previous_lmf */
3744                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
3745
3746                         /* lmf = previous_lmf */
3747                         x86_prefix (code, X86_GS_PREFIX);
3748                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
3749                 } else {
3750                         /* Find a spare register */
3751                         switch (mono_type_get_underlying_type (sig->ret)->type) {
3752                         case MONO_TYPE_I8:
3753                         case MONO_TYPE_U8:
3754                                 prev_lmf_reg = X86_EDI;
3755                                 cfg->used_int_regs |= (1 << X86_EDI);
3756                                 break;
3757                         default:
3758                                 prev_lmf_reg = X86_EDX;
3759                                 break;
3760                         }
3761
3762                         /* reg = previous_lmf */
3763                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
3764
3765                         /* ecx = lmf */
3766                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
3767
3768                         /* *(lmf) = previous_lmf */
3769                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
3770                 }
3771
3772                 /* restore caller saved regs */
3773                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3774                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
3775                 }
3776
3777                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3778                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
3779                 }
3780                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3781                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
3782                 }
3783
3784                 /* EBP is restored by LEAVE */
3785         } else {
3786                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3787                         pos -= 4;
3788                 }
3789                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3790                         pos -= 4;
3791                 }
3792                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3793                         pos -= 4;
3794                 }
3795
3796                 if (pos)
3797                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
3798
3799                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3800                         x86_pop_reg (code, X86_ESI);
3801                 }
3802                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3803                         x86_pop_reg (code, X86_EDI);
3804                 }
3805                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3806                         x86_pop_reg (code, X86_EBX);
3807                 }
3808         }
3809
3810         /* Load returned vtypes into registers if needed */
3811         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
3812         if (cinfo->ret.storage == ArgValuetypeInReg) {
3813                 for (quad = 0; quad < 2; quad ++) {
3814                         switch (cinfo->ret.pair_storage [quad]) {
3815                         case ArgInIReg:
3816                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
3817                                 break;
3818                         case ArgOnFloatFpStack:
3819                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
3820                                 break;
3821                         case ArgOnDoubleFpStack:
3822                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
3823                                 break;
3824                         case ArgNone:
3825                                 break;
3826                         default:
3827                                 g_assert_not_reached ();
3828                         }
3829                 }
3830         }
3831
3832         x86_leave (code);
3833
3834         if (CALLCONV_IS_STDCALL (sig)) {
3835                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
3836
3837                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
3838         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
3839                 stack_to_pop = 4;
3840         else
3841                 stack_to_pop = 0;
3842
3843         if (stack_to_pop)
3844                 x86_ret_imm (code, stack_to_pop);
3845         else
3846                 x86_ret (code);
3847
3848         cfg->code_len = code - cfg->native_code;
3849
3850         g_assert (cfg->code_len < cfg->code_size);
3851 }
3852
3853 void
3854 mono_arch_emit_exceptions (MonoCompile *cfg)
3855 {
3856         MonoJumpInfo *patch_info;
3857         int nthrows, i;
3858         guint8 *code;
3859         MonoClass *exc_classes [16];
3860         guint8 *exc_throw_start [16], *exc_throw_end [16];
3861         guint32 code_size;
3862         int exc_count = 0;
3863
3864         /* Compute needed space */
3865         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3866                 if (patch_info->type == MONO_PATCH_INFO_EXC)
3867                         exc_count++;
3868         }
3869
3870         /* 
3871          * make sure we have enough space for exceptions
3872          * 16 is the size of two push_imm instructions and a call
3873          */
3874         if (cfg->compile_aot)
3875                 code_size = exc_count * 32;
3876         else
3877                 code_size = exc_count * 16;
3878
3879         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
3880                 cfg->code_size *= 2;
3881                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3882                 mono_jit_stats.code_reallocs++;
3883         }
3884
3885         code = cfg->native_code + cfg->code_len;
3886
3887         nthrows = 0;
3888         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3889                 switch (patch_info->type) {
3890                 case MONO_PATCH_INFO_EXC: {
3891                         MonoClass *exc_class;
3892                         guint8 *buf, *buf2;
3893                         guint32 throw_ip;
3894
3895                         x86_patch (patch_info->ip.i + cfg->native_code, code);
3896
3897                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
3898                         g_assert (exc_class);
3899                         throw_ip = patch_info->ip.i;
3900
3901                         /* Find a throw sequence for the same exception class */
3902                         for (i = 0; i < nthrows; ++i)
3903                                 if (exc_classes [i] == exc_class)
3904                                         break;
3905                         if (i < nthrows) {
3906                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
3907                                 x86_jump_code (code, exc_throw_start [i]);
3908                                 patch_info->type = MONO_PATCH_INFO_NONE;
3909                         }
3910                         else {
3911                                 guint32 size;
3912
3913                                 /* Compute size of code following the push <OFFSET> */
3914                                 size = 5 + 5;
3915
3916                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
3917                                         /* Use the shorter form */
3918                                         buf = buf2 = code;
3919                                         x86_push_imm (code, 0);
3920                                 }
3921                                 else {
3922                                         buf = code;
3923                                         x86_push_imm (code, 0xf0f0f0f0);
3924                                         buf2 = code;
3925                                 }
3926
3927                                 if (nthrows < 16) {
3928                                         exc_classes [nthrows] = exc_class;
3929                                         exc_throw_start [nthrows] = code;
3930                                 }
3931
3932                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
3933                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
3934                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3935                                 patch_info->ip.i = code - cfg->native_code;
3936                                 x86_call_code (code, 0);
3937                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
3938                                 while (buf < buf2)
3939                                         x86_nop (buf);
3940
3941                                 if (nthrows < 16) {
3942                                         exc_throw_end [nthrows] = code;
3943                                         nthrows ++;
3944                                 }
3945                         }
3946                         break;
3947                 }
3948                 default:
3949                         /* do nothing */
3950                         break;
3951                 }
3952         }
3953
3954         cfg->code_len = code - cfg->native_code;
3955
3956         g_assert (cfg->code_len < cfg->code_size);
3957 }
3958
3959 void
3960 mono_arch_flush_icache (guint8 *code, gint size)
3961 {
3962         /* not needed */
3963 }
3964
3965 void
3966 mono_arch_flush_register_windows (void)
3967 {
3968 }
3969
3970 /*
3971  * Support for fast access to the thread-local lmf structure using the GS
3972  * segment register on NPTL + kernel 2.6.x.
3973  */
3974
3975 static gboolean tls_offset_inited = FALSE;
3976
3977 void
3978 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3979 {
3980         if (!tls_offset_inited) {
3981                 if (!getenv ("MONO_NO_TLS")) {
3982 #ifdef PLATFORM_WIN32
3983                         /* 
3984                          * We need to init this multiple times, since when we are first called, the key might not
3985                          * be initialized yet.
3986                          */
3987                         appdomain_tls_offset = mono_domain_get_tls_key ();
3988                         lmf_tls_offset = mono_get_jit_tls_key ();
3989                         thread_tls_offset = mono_thread_get_tls_key ();
3990
3991                         /* Only 64 tls entries can be accessed using inline code */
3992                         if (appdomain_tls_offset >= 64)
3993                                 appdomain_tls_offset = -1;
3994                         if (lmf_tls_offset >= 64)
3995                                 lmf_tls_offset = -1;
3996                         if (thread_tls_offset >= 64)
3997                                 thread_tls_offset = -1;
3998 #else
3999 #if MONO_XEN_OPT
4000                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
4001 #endif
4002                         tls_offset_inited = TRUE;
4003                         appdomain_tls_offset = mono_domain_get_tls_offset ();
4004                         lmf_tls_offset = mono_get_lmf_tls_offset ();
4005                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
4006                         thread_tls_offset = mono_thread_get_tls_offset ();
4007 #endif
4008                 }
4009         }               
4010 }
4011
4012 void
4013 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4014 {
4015 }
4016
4017 void
4018 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4019 {
4020         MonoCallInst *call = (MonoCallInst*)inst;
4021         CallInfo *cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, inst->signature, FALSE);
4022
4023         /* add the this argument */
4024         if (this_reg != -1) {
4025                 if (cinfo->args [0].storage == ArgInIReg) {
4026                         MonoInst *this;
4027                         MONO_INST_NEW (cfg, this, OP_MOVE);
4028                         this->type = this_type;
4029                         this->sreg1 = this_reg;
4030                         this->dreg = mono_regstate_next_int (cfg->rs);
4031                         mono_bblock_add_inst (cfg->cbb, this);
4032
4033                         mono_call_inst_add_outarg_reg (cfg, call, this->dreg, cinfo->args [0].reg, FALSE);
4034                 }
4035                 else {
4036                         MonoInst *this;
4037                         MONO_INST_NEW (cfg, this, OP_OUTARG);
4038                         this->type = this_type;
4039                         this->sreg1 = this_reg;
4040                         mono_bblock_add_inst (cfg->cbb, this);
4041                 }
4042         }
4043
4044         if (vt_reg != -1) {
4045                 MonoInst *vtarg;
4046
4047                 if (cinfo->ret.storage == ArgValuetypeInReg) {
4048                         /*
4049                          * The valuetype is in EAX:EDX after the call, needs to be copied to
4050                          * the stack. Save the address here, so the call instruction can
4051                          * access it.
4052                          */
4053                         MONO_INST_NEW (cfg, vtarg, OP_STORE_MEMBASE_REG);
4054                         vtarg->inst_destbasereg = X86_ESP;
4055                         vtarg->inst_offset = inst->stack_usage;
4056                         vtarg->sreg1 = vt_reg;
4057                         mono_bblock_add_inst (cfg->cbb, vtarg);
4058                 }
4059                 else if (cinfo->ret.storage == ArgInIReg) {
4060                         /* The return address is passed in a register */
4061                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4062                         vtarg->sreg1 = vt_reg;
4063                         vtarg->dreg = mono_regstate_next_int (cfg->rs);
4064                         mono_bblock_add_inst (cfg->cbb, vtarg);
4065
4066                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
4067                 } else {
4068                         MonoInst *vtarg;
4069                         MONO_INST_NEW (cfg, vtarg, OP_OUTARG);
4070                         vtarg->type = STACK_MP;
4071                         vtarg->sreg1 = vt_reg;
4072                         mono_bblock_add_inst (cfg->cbb, vtarg);
4073                 }
4074         }
4075 }
4076
4077 #ifdef MONO_ARCH_HAVE_IMT
4078
4079 // Linear handler, the bsearch head compare is shorter
4080 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
4081 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
4082 //        x86_patch(ins,target)
4083 //[1 + 5] x86_jump_mem(inst,mem)
4084
4085 #define CMP_SIZE 6
4086 #define BR_SMALL_SIZE 2
4087 #define BR_LARGE_SIZE 5
4088 #define JUMP_IMM_SIZE 6
4089 #define ENABLE_WRONG_METHOD_CHECK 0
4090
4091 static int
4092 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
4093 {
4094         int i, distance = 0;
4095         for (i = start; i < target; ++i)
4096                 distance += imt_entries [i]->chunk_size;
4097         return distance;
4098 }
4099
4100 /*
4101  * LOCKING: called with the domain lock held
4102  */
4103 gpointer
4104 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4105 {
4106         int i;
4107         int size = 0;
4108         guint8 *code, *start;
4109
4110         for (i = 0; i < count; ++i) {
4111                 MonoIMTCheckItem *item = imt_entries [i];
4112                 if (item->is_equals) {
4113                         if (item->check_target_idx) {
4114                                 if (!item->compare_done)
4115                                         item->chunk_size += CMP_SIZE;
4116                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
4117                         } else {
4118                                 item->chunk_size += JUMP_IMM_SIZE;
4119 #if ENABLE_WRONG_METHOD_CHECK
4120                                 item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
4121 #endif
4122                         }
4123                 } else {
4124                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
4125                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4126                 }
4127                 size += item->chunk_size;
4128         }
4129         code = mono_code_manager_reserve (domain->code_mp, size);
4130         start = code;
4131         for (i = 0; i < count; ++i) {
4132                 MonoIMTCheckItem *item = imt_entries [i];
4133                 item->code_target = code;
4134                 if (item->is_equals) {
4135                         if (item->check_target_idx) {
4136                                 if (!item->compare_done)
4137                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
4138                                 item->jmp_code = code;
4139                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
4140                                 x86_jump_mem (code, & (vtable->vtable [item->vtable_slot]));
4141                         } else {
4142                                 /* enable the commented code to assert on wrong method */
4143 #if ENABLE_WRONG_METHOD_CHECK
4144                                 x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
4145                                 item->jmp_code = code;
4146                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
4147 #endif
4148                                 x86_jump_mem (code, & (vtable->vtable [item->vtable_slot]));
4149 #if ENABLE_WRONG_METHOD_CHECK
4150                                 x86_patch (item->jmp_code, code);
4151                                 x86_breakpoint (code);
4152                                 item->jmp_code = NULL;
4153 #endif
4154                         }
4155                 } else {
4156                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
4157                         item->jmp_code = code;
4158                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
4159                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
4160                         else
4161                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
4162                 }
4163         }
4164         /* patch the branches to get to the target items */
4165         for (i = 0; i < count; ++i) {
4166                 MonoIMTCheckItem *item = imt_entries [i];
4167                 if (item->jmp_code) {
4168                         if (item->check_target_idx) {
4169                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4170                         }
4171                 }
4172         }
4173                 
4174         mono_stats.imt_thunks_size += code - start;
4175         g_assert (code - start <= size);
4176         return start;
4177 }
4178
4179 MonoMethod*
4180 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4181 {
4182         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4183 }
4184
4185 MonoObject*
4186 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4187 {
4188         MonoMethodSignature *sig = mono_method_signature (method);
4189         CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
4190         int this_argument_offset;
4191         MonoObject *this_argument;
4192
4193         /* 
4194          * this is the offset of the this arg from esp as saved at the start of 
4195          * mono_arch_create_trampoline_code () in tramp-x86.c.
4196          */
4197         this_argument_offset = 5;
4198         if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
4199                 this_argument_offset++;
4200
4201         this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
4202
4203         g_free (cinfo);
4204         return this_argument;
4205 }
4206 #endif
4207
4208 MonoVTable*
4209 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4210 {
4211         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4212 }
4213
4214 MonoInst*
4215 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4216 {
4217         MonoInst *ins = NULL;
4218
4219         if (cmethod->klass == mono_defaults.math_class) {
4220                 if (strcmp (cmethod->name, "Sin") == 0) {
4221                         MONO_INST_NEW (cfg, ins, OP_SIN);
4222                         ins->inst_i0 = args [0];
4223                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4224                         MONO_INST_NEW (cfg, ins, OP_COS);
4225                         ins->inst_i0 = args [0];
4226                 } else if (strcmp (cmethod->name, "Tan") == 0) {
4227                         MONO_INST_NEW (cfg, ins, OP_TAN);
4228                         ins->inst_i0 = args [0];
4229                 } else if (strcmp (cmethod->name, "Atan") == 0) {
4230                         MONO_INST_NEW (cfg, ins, OP_ATAN);
4231                         ins->inst_i0 = args [0];
4232                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4233                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4234                         ins->inst_i0 = args [0];
4235                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4236                         MONO_INST_NEW (cfg, ins, OP_ABS);
4237                         ins->inst_i0 = args [0];
4238                 }
4239
4240                 if (cfg->opt & MONO_OPT_CMOV) {
4241                         int opcode = 0;
4242
4243                         if (strcmp (cmethod->name, "Min") == 0) {
4244                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4245                                         opcode = OP_IMIN;
4246                                 else if (fsig->params [0]->type == MONO_TYPE_U4)
4247                                         opcode = OP_IMIN_UN;
4248                         } else if (strcmp (cmethod->name, "Max") == 0) {
4249                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4250                                         opcode = OP_IMAX;
4251                                 else if (fsig->params [0]->type == MONO_TYPE_U4)
4252                                         opcode = OP_IMAX_UN;
4253                         }               
4254
4255                         if (opcode) {
4256                                 MONO_INST_NEW (cfg, ins, opcode);
4257                                 ins->inst_i0 = args [0];
4258                                 ins->inst_i1 = args [1];
4259                         }
4260                 }
4261
4262 #if 0
4263                 /* OP_FREM is not IEEE compatible */
4264                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
4265                         MONO_INST_NEW (cfg, ins, OP_FREM);
4266                         ins->inst_i0 = args [0];
4267                         ins->inst_i1 = args [1];
4268                 }
4269 #endif
4270         }
4271
4272         return ins;
4273 }
4274
4275
4276 gboolean
4277 mono_arch_print_tree (MonoInst *tree, int arity)
4278 {
4279         return 0;
4280 }
4281
4282 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4283 {
4284         MonoInst* ins;
4285         
4286         if (appdomain_tls_offset == -1)
4287                 return NULL;
4288
4289         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4290         ins->inst_offset = appdomain_tls_offset;
4291         return ins;
4292 }
4293
4294 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4295 {
4296         MonoInst* ins;
4297
4298         if (thread_tls_offset == -1)
4299                 return NULL;
4300
4301         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4302         ins->inst_offset = thread_tls_offset;
4303         return ins;
4304 }
4305
4306 guint32
4307 mono_arch_get_patch_offset (guint8 *code)
4308 {
4309         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
4310                 return 2;
4311         else if ((code [0] == 0xba))
4312                 return 1;
4313         else if ((code [0] == 0x68))
4314                 /* push IMM */
4315                 return 1;
4316         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
4317                 /* push <OFFSET>(<REG>) */
4318                 return 2;
4319         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
4320                 /* call *<OFFSET>(<REG>) */
4321                 return 2;
4322         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
4323                 /* fldl <ADDR> */
4324                 return 2;
4325         else if ((code [0] == 0x58) && (code [1] == 0x05))
4326                 /* pop %eax; add <OFFSET>, %eax */
4327                 return 2;
4328         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
4329                 /* pop <REG>; add <OFFSET>, <REG> */
4330                 return 3;
4331         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
4332                 /* mov <REG>, imm */
4333                 return 1;
4334         else {
4335                 g_assert_not_reached ();
4336                 return -1;
4337         }
4338 }
4339
4340 /**
4341  * mono_breakpoint_clean_code:
4342  *
4343  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
4344  * breakpoints in the original code, they are removed in the copy.
4345  *
4346  * Returns TRUE if no sw breakpoint was present.
4347  */
4348 gboolean
4349 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
4350 {
4351         int i;
4352         gboolean can_write = TRUE;
4353         /*
4354          * If method_start is non-NULL we need to perform bound checks, since we access memory
4355          * at code - offset we could go before the start of the method and end up in a different
4356          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
4357          * instead.
4358          */
4359         if (!method_start || code - offset >= method_start) {
4360                 memcpy (buf, code - offset, size);
4361         } else {
4362                 int diff = code - method_start;
4363                 memset (buf, 0, size);
4364                 memcpy (buf + offset - diff, method_start, diff + size - offset);
4365         }
4366         code -= offset;
4367         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
4368                 int idx = mono_breakpoint_info_index [i];
4369                 guint8 *ptr;
4370                 if (idx < 1)
4371                         continue;
4372                 ptr = mono_breakpoint_info [idx].address;
4373                 if (ptr >= code && ptr < code + size) {
4374                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
4375                         can_write = FALSE;
4376                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
4377                         buf [ptr - code] = saved_byte;
4378                 }
4379         }
4380         return can_write;
4381 }
4382
4383 gpointer
4384 mono_arch_get_vcall_slot (guint8 *code, gpointer *regs, int *displacement)
4385 {
4386         guint8 buf [8];
4387         guint8 reg = 0;
4388         gint32 disp = 0;
4389
4390         mono_breakpoint_clean_code (NULL, code, 8, buf, sizeof (buf));
4391         code = buf + 8;
4392
4393         *displacement = 0;
4394
4395         /* go to the start of the call instruction
4396          *
4397          * address_byte = (m << 6) | (o << 3) | reg
4398          * call opcode: 0xff address_byte displacement
4399          * 0xff m=1,o=2 imm8
4400          * 0xff m=2,o=2 imm32
4401          */
4402         code -= 6;
4403
4404         /* 
4405          * A given byte sequence can match more than case here, so we have to be
4406          * really careful about the ordering of the cases. Longer sequences
4407          * come first.
4408          */
4409         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)) {
4410                 /*
4411                  * This is an interface call
4412                  * 8b 80 0c e8 ff ff       mov    0xffffe80c(%eax),%eax
4413                  * ff 10                   call   *(%eax)
4414                  */
4415                 reg = x86_modrm_rm (code [5]);
4416                 disp = 0;
4417 #ifdef MONO_ARCH_HAVE_IMT
4418         } 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)) {
4419                 /* IMT-based interface calls: with MONO_ARCH_IMT_REG == edx
4420                  * ba 14 f8 28 08          mov    $0x828f814,%edx
4421                  * ff 50 fc                call   *0xfffffffc(%eax)
4422                  */
4423                 reg = code [4] & 0x07;
4424                 disp = (signed char)code [5];
4425 #endif
4426         } else if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
4427                 reg = code [4] & 0x07;
4428                 disp = (signed char)code [5];
4429         } else {
4430                 if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
4431                         reg = code [1] & 0x07;
4432                         disp = *((gint32*)(code + 2));
4433                 } else if ((code [1] == 0xe8)) {
4434                         return NULL;
4435                 } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
4436                         /*
4437                          * This is a interface call
4438                          * 8b 40 30   mov    0x30(%eax),%eax
4439                          * ff 10      call   *(%eax)
4440                          */
4441                         disp = 0;
4442                         reg = code [5] & 0x07;
4443                 }
4444                 else
4445                         return NULL;
4446         }
4447
4448         *displacement = disp;
4449         return regs [reg];
4450 }
4451
4452 gpointer*
4453 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
4454 {
4455         gpointer vt;
4456         int displacement;
4457         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4458         if (!vt)
4459                 return NULL;
4460         return (gpointer*)((char*)vt + displacement);
4461 }
4462
4463 gpointer
4464 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
4465                 gssize *regs, guint8 *code)
4466 {
4467         guint32 esp = regs [X86_ESP];
4468         CallInfo *cinfo;
4469         gpointer res;
4470
4471         if (!gsctx && code)
4472                 gsctx = mono_get_generic_context_from_code (code);
4473         cinfo = get_call_info (gsctx, NULL, sig, FALSE);
4474
4475         /*
4476          * The stack looks like:
4477          * <other args>
4478          * <this=delegate>
4479          * <possible vtype return address>
4480          * <return addr>
4481          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
4482          */
4483         res = (((MonoObject**)esp) [5 + (cinfo->args [0].offset / 4)]);
4484         g_free (cinfo);
4485         return res;
4486 }
4487
4488 #define MAX_ARCH_DELEGATE_PARAMS 10
4489
4490 gpointer
4491 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4492 {
4493         guint8 *code, *start;
4494
4495         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
4496                 return NULL;
4497
4498         /* FIXME: Support more cases */
4499         if (MONO_TYPE_ISSTRUCT (sig->ret))
4500                 return NULL;
4501
4502         /*
4503          * The stack contains:
4504          * <delegate>
4505          * <return addr>
4506          */
4507
4508         if (has_target) {
4509                 static guint8* cached = NULL;
4510                 if (cached)
4511                         return cached;
4512                 
4513                 start = code = mono_global_codeman_reserve (64);
4514
4515                 /* Replace the this argument with the target */
4516                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
4517                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
4518                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
4519                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4520
4521                 g_assert ((code - start) < 64);
4522
4523                 mono_debug_add_delegate_trampoline (start, code - start);
4524
4525                 mono_memory_barrier ();
4526
4527                 cached = start;
4528         } else {
4529                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
4530                 int i = 0;
4531                 /* 8 for mov_reg and jump, plus 8 for each parameter */
4532                 int code_reserve = 8 + (sig->param_count * 8);
4533
4534                 for (i = 0; i < sig->param_count; ++i)
4535                         if (!mono_is_regsize_var (sig->params [i]))
4536                                 return NULL;
4537
4538                 code = cache [sig->param_count];
4539                 if (code)
4540                         return code;
4541
4542                 /*
4543                  * The stack contains:
4544                  * <args in reverse order>
4545                  * <delegate>
4546                  * <return addr>
4547                  *
4548                  * and we need:
4549                  * <args in reverse order>
4550                  * <return addr>
4551                  * 
4552                  * without unbalancing the stack.
4553                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
4554                  * and leaving original spot of first arg as placeholder in stack so
4555                  * when callee pops stack everything works.
4556                  */
4557
4558                 start = code = mono_global_codeman_reserve (code_reserve);
4559
4560                 /* store delegate for access to method_ptr */
4561                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
4562
4563                 /* move args up */
4564                 for (i = 0; i < sig->param_count; ++i) {
4565                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
4566                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
4567                 }
4568
4569                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4570
4571                 g_assert ((code - start) < code_reserve);
4572
4573                 mono_debug_add_delegate_trampoline (start, code - start);
4574
4575                 mono_memory_barrier ();
4576
4577                 cache [sig->param_count] = start;
4578         }
4579
4580         return start;
4581 }
4582
4583 gpointer
4584 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
4585 {
4586         switch (reg) {
4587         case X86_ECX: return (gpointer)ctx->ecx;
4588         case X86_EDX: return (gpointer)ctx->edx;
4589         case X86_EBP: return (gpointer)ctx->ebp;
4590         case X86_ESP: return (gpointer)ctx->esp;
4591         default: return ((gpointer)(&ctx->eax)[reg]);
4592         }
4593 }