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