2008-08-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-x86.c
1 /*
2  * mini-x86.c: x86 backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Patrik Torstensson
8  *
9  * (C) 2003 Ximian, Inc.
10  */
11 #include "mini.h"
12 #include <string.h>
13 #include <math.h>
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/threads.h>
21 #include <mono/metadata/profiler-private.h>
22 #include <mono/metadata/mono-debug.h>
23 #include <mono/utils/mono-math.h>
24
25 #include "trace.h"
26 #include "mini-x86.h"
27 #include "inssel.h"
28 #include "cpu-x86.h"
29
30 /* On windows, these hold the key returned by TlsAlloc () */
31 static gint lmf_tls_offset = -1;
32 static gint lmf_addr_tls_offset = -1;
33 static gint appdomain_tls_offset = -1;
34 static gint thread_tls_offset = -1;
35
36 #ifdef MONO_XEN_OPT
37 static gboolean optimize_for_xen = TRUE;
38 #else
39 #define optimize_for_xen 0
40 #endif
41
42 #ifdef PLATFORM_WIN32
43 static gboolean is_win32 = TRUE;
44 #else
45 static gboolean is_win32 = FALSE;
46 #endif
47
48 /* This mutex protects architecture specific caches */
49 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
50 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
51 static CRITICAL_SECTION mini_arch_mutex;
52
53 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
54
55 #define ARGS_OFFSET 8
56
57 #ifdef PLATFORM_WIN32
58 /* Under windows, the default pinvoke calling convention is stdcall */
59 #define CALLCONV_IS_STDCALL(sig) ((((sig)->call_convention) == MONO_CALL_STDCALL) || ((sig)->pinvoke && ((sig)->call_convention) == MONO_CALL_DEFAULT))
60 #else
61 #define CALLCONV_IS_STDCALL(sig) (((sig)->call_convention) == MONO_CALL_STDCALL)
62 #endif
63
64 MonoBreakpointInfo
65 mono_breakpoint_info [MONO_BREAKPOINT_ARRAY_SIZE];
66
67 const char*
68 mono_arch_regname (int reg)
69 {
70         switch (reg) {
71         case X86_EAX: return "%eax";
72         case X86_EBX: return "%ebx";
73         case X86_ECX: return "%ecx";
74         case X86_EDX: return "%edx";
75         case X86_ESP: return "%esp";    
76         case X86_EBP: return "%ebp";
77         case X86_EDI: return "%edi";
78         case X86_ESI: return "%esi";
79         }
80         return "unknown";
81 }
82
83 const char*
84 mono_arch_fregname (int reg)
85 {
86         switch (reg) {
87         case 0:
88                 return "%fr0";
89         case 1:
90                 return "%fr1";
91         case 2:
92                 return "%fr2";
93         case 3:
94                 return "%fr3";
95         case 4:
96                 return "%fr4";
97         case 5:
98                 return "%fr5";
99         case 6:
100                 return "%fr6";
101         case 7:
102                 return "%fr7";
103         default:
104                 return "unknown";
105         }
106 }
107
108 typedef enum {
109         ArgInIReg,
110         ArgInFloatSSEReg,
111         ArgInDoubleSSEReg,
112         ArgOnStack,
113         ArgValuetypeInReg,
114         ArgOnFloatFpStack,
115         ArgOnDoubleFpStack,
116         ArgNone
117 } ArgStorage;
118
119 typedef struct {
120         gint16 offset;
121         gint8  reg;
122         ArgStorage storage;
123
124         /* Only if storage == ArgValuetypeInReg */
125         ArgStorage pair_storage [2];
126         gint8 pair_regs [2];
127 } ArgInfo;
128
129 typedef struct {
130         int nargs;
131         guint32 stack_usage;
132         guint32 reg_usage;
133         guint32 freg_usage;
134         gboolean need_stack_align;
135         guint32 stack_align_amount;
136         ArgInfo ret;
137         ArgInfo sig_cookie;
138         ArgInfo args [1];
139 } CallInfo;
140
141 #define PARAM_REGS 0
142
143 #define FLOAT_PARAM_REGS 0
144
145 static X86_Reg_No param_regs [] = { 0 };
146
147 #if defined(PLATFORM_WIN32) || defined(__APPLE__) || defined(__FreeBSD__)
148 #define SMALL_STRUCTS_IN_REGS
149 static X86_Reg_No return_regs [] = { X86_EAX, X86_EDX };
150 #endif
151
152 static void inline
153 add_general (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
154 {
155     ainfo->offset = *stack_size;
156
157     if (*gr >= PARAM_REGS) {
158                 ainfo->storage = ArgOnStack;
159                 (*stack_size) += sizeof (gpointer);
160     }
161     else {
162                 ainfo->storage = ArgInIReg;
163                 ainfo->reg = param_regs [*gr];
164                 (*gr) ++;
165     }
166 }
167
168 static void inline
169 add_general_pair (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo)
170 {
171         ainfo->offset = *stack_size;
172
173         g_assert (PARAM_REGS == 0);
174         
175         ainfo->storage = ArgOnStack;
176         (*stack_size) += sizeof (gpointer) * 2;
177 }
178
179 static void inline
180 add_float (guint32 *gr, guint32 *stack_size, ArgInfo *ainfo, gboolean is_double)
181 {
182     ainfo->offset = *stack_size;
183
184     if (*gr >= FLOAT_PARAM_REGS) {
185                 ainfo->storage = ArgOnStack;
186                 (*stack_size) += is_double ? 8 : 4;
187     }
188     else {
189                 /* A double register */
190                 if (is_double)
191                         ainfo->storage = ArgInDoubleSSEReg;
192                 else
193                         ainfo->storage = ArgInFloatSSEReg;
194                 ainfo->reg = *gr;
195                 (*gr) += 1;
196     }
197 }
198
199
200 static void
201 add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgInfo *ainfo, MonoType *type,
202                gboolean is_return,
203                guint32 *gr, guint32 *fr, guint32 *stack_size)
204 {
205         guint32 size;
206         MonoClass *klass;
207
208         klass = mono_class_from_mono_type (type);
209         if (sig->pinvoke) 
210                 size = mono_type_native_stack_size (&klass->byval_arg, NULL);
211         else 
212                 size = mini_type_stack_size (gsctx, &klass->byval_arg, NULL);
213
214 #ifdef SMALL_STRUCTS_IN_REGS
215         if (sig->pinvoke && is_return) {
216                 MonoMarshalType *info;
217
218                 /*
219                  * the exact rules are not very well documented, the code below seems to work with the 
220                  * code generated by gcc 3.3.3 -mno-cygwin.
221                  */
222                 info = mono_marshal_load_type_info (klass);
223                 g_assert (info);
224
225                 ainfo->pair_storage [0] = ainfo->pair_storage [1] = ArgNone;
226
227                 /* Special case structs with only a float member */
228                 if ((info->native_size == 8) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R8)) {
229                         ainfo->storage = ArgValuetypeInReg;
230                         ainfo->pair_storage [0] = ArgOnDoubleFpStack;
231                         return;
232                 }
233                 if ((info->native_size == 4) && (info->num_fields == 1) && (info->fields [0].field->type->type == MONO_TYPE_R4)) {
234                         ainfo->storage = ArgValuetypeInReg;
235                         ainfo->pair_storage [0] = ArgOnFloatFpStack;
236                         return;
237                 }               
238                 if ((info->native_size == 1) || (info->native_size == 2) || (info->native_size == 4) || (info->native_size == 8)) {
239                         ainfo->storage = ArgValuetypeInReg;
240                         ainfo->pair_storage [0] = ArgInIReg;
241                         ainfo->pair_regs [0] = return_regs [0];
242                         if (info->native_size > 4) {
243                                 ainfo->pair_storage [1] = ArgInIReg;
244                                 ainfo->pair_regs [1] = return_regs [1];
245                         }
246                         return;
247                 }
248         }
249 #endif
250
251         ainfo->offset = *stack_size;
252         ainfo->storage = ArgOnStack;
253         *stack_size += ALIGN_TO (size, sizeof (gpointer));
254 }
255
256 /*
257  * get_call_info:
258  *
259  *  Obtain information about a call according to the calling convention.
260  * For x86 ELF, see the "System V Application Binary Interface Intel386 
261  * Architecture Processor Supplment, Fourth Edition" document for more
262  * information.
263  * For x86 win32, see ???.
264  */
265 static CallInfo*
266 get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
267 {
268         guint32 i, gr, fr;
269         MonoType *ret_type;
270         int n = sig->hasthis + sig->param_count;
271         guint32 stack_size = 0;
272         CallInfo *cinfo;
273
274         if (mp)
275                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
276         else
277                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
278
279         gr = 0;
280         fr = 0;
281
282         /* return value */
283         {
284                 ret_type = mono_type_get_underlying_type (sig->ret);
285                 ret_type = mini_get_basic_type_from_generic (gsctx, ret_type);
286                 switch (ret_type->type) {
287                 case MONO_TYPE_BOOLEAN:
288                 case MONO_TYPE_I1:
289                 case MONO_TYPE_U1:
290                 case MONO_TYPE_I2:
291                 case MONO_TYPE_U2:
292                 case MONO_TYPE_CHAR:
293                 case MONO_TYPE_I4:
294                 case MONO_TYPE_U4:
295                 case MONO_TYPE_I:
296                 case MONO_TYPE_U:
297                 case MONO_TYPE_PTR:
298                 case MONO_TYPE_FNPTR:
299                 case MONO_TYPE_CLASS:
300                 case MONO_TYPE_OBJECT:
301                 case MONO_TYPE_SZARRAY:
302                 case MONO_TYPE_ARRAY:
303                 case MONO_TYPE_STRING:
304                         cinfo->ret.storage = ArgInIReg;
305                         cinfo->ret.reg = X86_EAX;
306                         break;
307                 case MONO_TYPE_U8:
308                 case MONO_TYPE_I8:
309                         cinfo->ret.storage = ArgInIReg;
310                         cinfo->ret.reg = X86_EAX;
311                         break;
312                 case MONO_TYPE_R4:
313                         cinfo->ret.storage = ArgOnFloatFpStack;
314                         break;
315                 case MONO_TYPE_R8:
316                         cinfo->ret.storage = ArgOnDoubleFpStack;
317                         break;
318                 case MONO_TYPE_GENERICINST:
319                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
320                                 cinfo->ret.storage = ArgInIReg;
321                                 cinfo->ret.reg = X86_EAX;
322                                 break;
323                         }
324                         /* Fall through */
325                 case MONO_TYPE_VALUETYPE: {
326                         guint32 tmp_gr = 0, tmp_fr = 0, tmp_stacksize = 0;
327
328                         add_valuetype (gsctx, sig, &cinfo->ret, sig->ret, TRUE, &tmp_gr, &tmp_fr, &tmp_stacksize);
329                         if (cinfo->ret.storage == ArgOnStack)
330                                 /* The caller passes the address where the value is stored */
331                                 add_general (&gr, &stack_size, &cinfo->ret);
332                         break;
333                 }
334                 case MONO_TYPE_TYPEDBYREF:
335                         /* Same as a valuetype with size 24 */
336                         add_general (&gr, &stack_size, &cinfo->ret);
337                         ;
338                         break;
339                 case MONO_TYPE_VOID:
340                         cinfo->ret.storage = ArgNone;
341                         break;
342                 default:
343                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
344                 }
345         }
346
347         /* this */
348         if (sig->hasthis)
349                 add_general (&gr, &stack_size, cinfo->args + 0);
350
351         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == 0)) {
352                 gr = PARAM_REGS;
353                 fr = FLOAT_PARAM_REGS;
354                 
355                 /* Emit the signature cookie just before the implicit arguments */
356                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
357         }
358
359         for (i = 0; i < sig->param_count; ++i) {
360                 ArgInfo *ainfo = &cinfo->args [sig->hasthis + i];
361                 MonoType *ptype;
362
363                 if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
364                         /* We allways pass the sig cookie on the stack for simplicity */
365                         /* 
366                          * Prevent implicit arguments + the sig cookie from being passed 
367                          * in registers.
368                          */
369                         gr = PARAM_REGS;
370                         fr = FLOAT_PARAM_REGS;
371
372                         /* Emit the signature cookie just before the implicit arguments */
373                         add_general (&gr, &stack_size, &cinfo->sig_cookie);
374                 }
375
376                 if (sig->params [i]->byref) {
377                         add_general (&gr, &stack_size, ainfo);
378                         continue;
379                 }
380                 ptype = mono_type_get_underlying_type (sig->params [i]);
381                 ptype = mini_get_basic_type_from_generic (gsctx, ptype);
382                 switch (ptype->type) {
383                 case MONO_TYPE_BOOLEAN:
384                 case MONO_TYPE_I1:
385                 case MONO_TYPE_U1:
386                         add_general (&gr, &stack_size, ainfo);
387                         break;
388                 case MONO_TYPE_I2:
389                 case MONO_TYPE_U2:
390                 case MONO_TYPE_CHAR:
391                         add_general (&gr, &stack_size, ainfo);
392                         break;
393                 case MONO_TYPE_I4:
394                 case MONO_TYPE_U4:
395                         add_general (&gr, &stack_size, ainfo);
396                         break;
397                 case MONO_TYPE_I:
398                 case MONO_TYPE_U:
399                 case MONO_TYPE_PTR:
400                 case MONO_TYPE_FNPTR:
401                 case MONO_TYPE_CLASS:
402                 case MONO_TYPE_OBJECT:
403                 case MONO_TYPE_STRING:
404                 case MONO_TYPE_SZARRAY:
405                 case MONO_TYPE_ARRAY:
406                         add_general (&gr, &stack_size, ainfo);
407                         break;
408                 case MONO_TYPE_GENERICINST:
409                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
410                                 add_general (&gr, &stack_size, ainfo);
411                                 break;
412                         }
413                         /* Fall through */
414                 case MONO_TYPE_VALUETYPE:
415                         add_valuetype (gsctx, sig, ainfo, sig->params [i], FALSE, &gr, &fr, &stack_size);
416                         break;
417                 case MONO_TYPE_TYPEDBYREF:
418                         stack_size += sizeof (MonoTypedRef);
419                         ainfo->storage = ArgOnStack;
420                         break;
421                 case MONO_TYPE_U8:
422                 case MONO_TYPE_I8:
423                         add_general_pair (&gr, &stack_size, ainfo);
424                         break;
425                 case MONO_TYPE_R4:
426                         add_float (&fr, &stack_size, ainfo, FALSE);
427                         break;
428                 case MONO_TYPE_R8:
429                         add_float (&fr, &stack_size, ainfo, TRUE);
430                         break;
431                 default:
432                         g_error ("unexpected type 0x%x", ptype->type);
433                         g_assert_not_reached ();
434                 }
435         }
436
437         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n > 0) && (sig->sentinelpos == sig->param_count)) {
438                 gr = PARAM_REGS;
439                 fr = FLOAT_PARAM_REGS;
440                 
441                 /* Emit the signature cookie just before the implicit arguments */
442                 add_general (&gr, &stack_size, &cinfo->sig_cookie);
443         }
444
445 #if defined(__APPLE__)
446         if ((stack_size % 16) != 0) { 
447                 cinfo->need_stack_align = TRUE;
448                 stack_size += cinfo->stack_align_amount = 16-(stack_size % 16);
449         }
450 #endif
451
452         cinfo->stack_usage = stack_size;
453         cinfo->reg_usage = gr;
454         cinfo->freg_usage = fr;
455         return cinfo;
456 }
457
458 /*
459  * mono_arch_get_argument_info:
460  * @csig:  a method signature
461  * @param_count: the number of parameters to consider
462  * @arg_info: an array to store the result infos
463  *
464  * Gathers information on parameters such as size, alignment and
465  * padding. arg_info should be large enought to hold param_count + 1 entries. 
466  *
467  * Returns the size of the argument area on the stack.
468  */
469 int
470 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
471 {
472         int k, args_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                 args_size += sizeof (gpointer);
482                 offset += 4;
483         }
484
485         arg_info [0].offset = offset;
486
487         if (csig->hasthis) {
488                 args_size += sizeof (gpointer);
489                 offset += 4;
490         }
491
492         arg_info [0].size = args_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                 args_size += pad = (align - (args_size & (align - 1))) & (align - 1);   
508                 arg_info [k].pad = pad;
509                 args_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 = 4;
518         args_size += pad = (align - (args_size & (align - 1))) & (align - 1);
519         arg_info [k].pad = pad;
520
521         g_free (cinfo);
522
523         return args_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 defined(__APPLE__)
1191         if (cinfo->need_stack_align) {
1192                 MONO_INST_NEW (cfg, arg, OP_SUB_IMM);
1193                 arg->dreg = X86_ESP;
1194                 arg->sreg1 = X86_ESP;
1195                 arg->inst_imm = cinfo->stack_align_amount;
1196                 MONO_ADD_INS (cfg->cbb, arg);
1197         }
1198 #endif 
1199
1200         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1201                 MonoInst *vtarg;
1202
1203                 if (cinfo->ret.storage == ArgValuetypeInReg) {
1204                         if (cinfo->ret.pair_storage [0] == ArgInIReg && cinfo->ret.pair_storage [1] == ArgNone) {
1205                                 /*
1206                                  * Tell the JIT to use a more efficient calling convention: call using
1207                                  * OP_CALL, compute the result location after the call, and save the 
1208                                  * result there.
1209                                  */
1210                                 call->vret_in_reg = TRUE;
1211                         } else {
1212                                 /*
1213                                  * The valuetype is in EAX:EDX after the call, needs to be copied to
1214                                  * the stack. Save the address here, so the call instruction can
1215                                  * access it.
1216                                  */
1217                                 MONO_INST_NEW (cfg, vtarg, OP_X86_PUSH);
1218                                 vtarg->sreg1 = call->vret_var->dreg;
1219                                 MONO_ADD_INS (cfg->cbb, vtarg);
1220                         }
1221                 }
1222         }
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, 12);
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                 case MONO_PATCH_INFO_RGCTX_FETCH:
3827                 case MONO_PATCH_INFO_GENERIC_CLASS_INIT:
3828                         x86_patch (ip, target);
3829                         break;
3830                 case MONO_PATCH_INFO_NONE:
3831                         break;
3832                 default: {
3833                         guint32 offset = mono_arch_get_patch_offset (ip);
3834                         *((gconstpointer *)(ip + offset)) = target;
3835                         break;
3836                 }
3837                 }
3838         }
3839 }
3840
3841 guint8 *
3842 mono_arch_emit_prolog (MonoCompile *cfg)
3843 {
3844         MonoMethod *method = cfg->method;
3845         MonoBasicBlock *bb;
3846         MonoMethodSignature *sig;
3847         MonoInst *inst;
3848         int alloc_size, pos, max_offset, i;
3849         guint8 *code;
3850
3851         cfg->code_size =  MAX (mono_method_get_header (method)->code_size * 4, 10240);
3852
3853         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
3854                 cfg->code_size += 512;
3855
3856         code = cfg->native_code = g_malloc (cfg->code_size);
3857
3858         x86_push_reg (code, X86_EBP);
3859         x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
3860
3861         alloc_size = cfg->stack_offset;
3862         pos = 0;
3863
3864         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
3865                 /* Might need to attach the thread to the JIT  or change the domain for the callback */
3866                 if (appdomain_tls_offset != -1 && lmf_tls_offset != -1) {
3867                         guint8 *buf, *no_domain_branch;
3868
3869                         code = emit_tls_get (code, X86_EAX, appdomain_tls_offset);
3870                         x86_alu_reg_imm (code, X86_CMP, X86_EAX, GPOINTER_TO_UINT (cfg->domain));
3871                         no_domain_branch = code;
3872                         x86_branch8 (code, X86_CC_NE, 0, 0);
3873                         code = emit_tls_get ( code, X86_EAX, lmf_tls_offset);
3874                         x86_test_reg_reg (code, X86_EAX, X86_EAX);
3875                         buf = code;
3876                         x86_branch8 (code, X86_CC_NE, 0, 0);
3877                         x86_patch (no_domain_branch, code);
3878                         x86_push_imm (code, cfg->domain);
3879                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3880                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3881                         x86_patch (buf, code);
3882 #ifdef PLATFORM_WIN32
3883                         /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
3884                         /* FIXME: Add a separate key for LMF to avoid this */
3885                         x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3886 #endif
3887                 }
3888                 else {
3889                         g_assert (!cfg->compile_aot);
3890                         x86_push_imm (code, cfg->domain);
3891                         code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_jit_thread_attach");
3892                         x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
3893                 }
3894         }
3895
3896         if (method->save_lmf) {
3897                 pos += sizeof (MonoLMF);
3898
3899                 /* save the current IP */
3900                 mono_add_patch_info (cfg, code + 1 - cfg->native_code, MONO_PATCH_INFO_IP, NULL);
3901                 x86_push_imm_template (code);
3902
3903                 /* save all caller saved regs */
3904                 x86_push_reg (code, X86_EBP);
3905                 x86_push_reg (code, X86_ESI);
3906                 x86_push_reg (code, X86_EDI);
3907                 x86_push_reg (code, X86_EBX);
3908
3909                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
3910                         /*
3911                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
3912                          * through the mono_lmf_addr TLS variable.
3913                          */
3914                         /* %eax = previous_lmf */
3915                         x86_prefix (code, X86_GS_PREFIX);
3916                         x86_mov_reg_mem (code, X86_EAX, lmf_tls_offset, 4);
3917                         /* skip esp + method_info + lmf */
3918                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 12);
3919                         /* push previous_lmf */
3920                         x86_push_reg (code, X86_EAX);
3921                         /* new lmf = ESP */
3922                         x86_prefix (code, X86_GS_PREFIX);
3923                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ESP, 4);
3924                 } else {
3925                         /* get the address of lmf for the current thread */
3926                         /* 
3927                          * This is performance critical so we try to use some tricks to make
3928                          * it fast.
3929                          */                                                                        
3930
3931                         if (lmf_addr_tls_offset != -1) {
3932                                 /* Load lmf quicky using the GS register */
3933                                 code = emit_tls_get (code, X86_EAX, lmf_addr_tls_offset);
3934 #ifdef PLATFORM_WIN32
3935                                 /* The TLS key actually contains a pointer to the MonoJitTlsData structure */
3936                                 /* FIXME: Add a separate key for LMF to avoid this */
3937                                 x86_alu_reg_imm (code, X86_ADD, X86_EAX, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
3938 #endif
3939                         } else {
3940                                 code = emit_call (cfg, code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_get_lmf_addr");
3941                         }
3942
3943                         /* Skip esp + method info */
3944                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 8);
3945
3946                         /* push lmf */
3947                         x86_push_reg (code, X86_EAX); 
3948                         /* push *lfm (previous_lmf) */
3949                         x86_push_membase (code, X86_EAX, 0);
3950                         /* *(lmf) = ESP */
3951                         x86_mov_membase_reg (code, X86_EAX, 0, X86_ESP, 4);
3952                 }
3953         } else {
3954
3955                 if (cfg->used_int_regs & (1 << X86_EBX)) {
3956                         x86_push_reg (code, X86_EBX);
3957                         pos += 4;
3958                 }
3959
3960                 if (cfg->used_int_regs & (1 << X86_EDI)) {
3961                         x86_push_reg (code, X86_EDI);
3962                         pos += 4;
3963                 }
3964
3965                 if (cfg->used_int_regs & (1 << X86_ESI)) {
3966                         x86_push_reg (code, X86_ESI);
3967                         pos += 4;
3968                 }
3969         }
3970
3971         alloc_size -= pos;
3972
3973 #if __APPLE__
3974         /* the original alloc_size is already aligned: there is %ebp and retip pushed, so realign */
3975         {
3976                 int tot = alloc_size + pos + 4 + 4; /* ret ip + ebp */
3977                 if (tot & 4) {
3978                         tot += 4;
3979                         alloc_size += 4;
3980                 }
3981                 if (tot & 8) {
3982                         alloc_size += 8;
3983                 }
3984         }
3985 #endif
3986
3987         if (alloc_size) {
3988                 /* See mono_emit_stack_alloc */
3989 #if defined(PLATFORM_WIN32) || defined(MONO_ARCH_SIGSEGV_ON_ALTSTACK)
3990                 guint32 remaining_size = alloc_size;
3991                 while (remaining_size >= 0x1000) {
3992                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, 0x1000);
3993                         x86_test_membase_reg (code, X86_ESP, 0, X86_ESP);
3994                         remaining_size -= 0x1000;
3995                 }
3996                 if (remaining_size)
3997                         x86_alu_reg_imm (code, X86_SUB, X86_ESP, remaining_size);
3998 #else
3999                 x86_alu_reg_imm (code, X86_SUB, X86_ESP, alloc_size);
4000 #endif
4001         }
4002
4003 #if __APPLE__ && DEBUG_APPLE_ALIGNMENT
4004         /* check the stack is aligned */
4005         x86_mov_reg_reg (code, X86_EDX, X86_ESP, 4);
4006         x86_alu_reg_imm (code, X86_AND, X86_EDX, 15);
4007         x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
4008         x86_branch_disp (code, X86_CC_EQ, 3, FALSE);
4009         x86_breakpoint (code);
4010 #endif
4011
4012         /* compute max_offset in order to use short forward jumps */
4013         max_offset = 0;
4014         if (cfg->opt & MONO_OPT_BRANCH) {
4015                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4016                         MonoInst *ins;
4017                         bb->max_offset = max_offset;
4018
4019                         if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4020                                 max_offset += 6;
4021                         /* max alignment for loops */
4022                         if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb))
4023                                 max_offset += LOOP_ALIGNMENT;
4024
4025                         MONO_BB_FOR_EACH_INS (bb, ins) {
4026                                 if (ins->opcode == OP_LABEL)
4027                                         ins->inst_c1 = max_offset;
4028                                 
4029                                 max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4030                         }
4031                 }
4032         }
4033
4034         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4035                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4036
4037         /* store runtime generic context */
4038         if (cfg->rgctx_var) {
4039                 g_assert (cfg->rgctx_var->opcode == OP_REGOFFSET && cfg->rgctx_var->inst_basereg == X86_EBP);
4040
4041                 x86_mov_membase_reg (code, X86_EBP, cfg->rgctx_var->inst_offset, MONO_ARCH_RGCTX_REG, 4);
4042         }
4043
4044         /* load arguments allocated to register from the stack */
4045         sig = mono_method_signature (method);
4046         pos = 0;
4047
4048         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4049                 inst = cfg->args [pos];
4050                 if (inst->opcode == OP_REGVAR) {
4051                         x86_mov_reg_membase (code, inst->dreg, X86_EBP, inst->inst_offset, 4);
4052                         if (cfg->verbose_level > 2)
4053                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4054                 }
4055                 pos++;
4056         }
4057
4058         cfg->code_len = code - cfg->native_code;
4059
4060         g_assert (cfg->code_len < cfg->code_size);
4061
4062         return code;
4063 }
4064
4065 void
4066 mono_arch_emit_epilog (MonoCompile *cfg)
4067 {
4068         MonoMethod *method = cfg->method;
4069         MonoMethodSignature *sig = mono_method_signature (method);
4070         int quad, pos;
4071         guint32 stack_to_pop;
4072         guint8 *code;
4073         int max_epilog_size = 16;
4074         CallInfo *cinfo;
4075         
4076         if (cfg->method->save_lmf)
4077                 max_epilog_size += 128;
4078
4079         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4080                 cfg->code_size *= 2;
4081                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4082                 mono_jit_stats.code_reallocs++;
4083         }
4084
4085         code = cfg->native_code + cfg->code_len;
4086
4087         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4088                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4089
4090         /* the code restoring the registers must be kept in sync with OP_JMP */
4091         pos = 0;
4092         
4093         if (method->save_lmf) {
4094                 gint32 prev_lmf_reg;
4095                 gint32 lmf_offset = -sizeof (MonoLMF);
4096
4097                 if ((lmf_tls_offset != -1) && !is_win32 && !optimize_for_xen) {
4098                         /*
4099                          * Optimized version which uses the mono_lmf TLS variable instead of indirection
4100                          * through the mono_lmf_addr TLS variable.
4101                          */
4102                         /* reg = previous_lmf */
4103                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4104
4105                         /* lmf = previous_lmf */
4106                         x86_prefix (code, X86_GS_PREFIX);
4107                         x86_mov_mem_reg (code, lmf_tls_offset, X86_ECX, 4);
4108                 } else {
4109                         /* Find a spare register */
4110                         switch (mono_type_get_underlying_type (sig->ret)->type) {
4111                         case MONO_TYPE_I8:
4112                         case MONO_TYPE_U8:
4113                                 prev_lmf_reg = X86_EDI;
4114                                 cfg->used_int_regs |= (1 << X86_EDI);
4115                                 break;
4116                         default:
4117                                 prev_lmf_reg = X86_EDX;
4118                                 break;
4119                         }
4120
4121                         /* reg = previous_lmf */
4122                         x86_mov_reg_membase (code, prev_lmf_reg, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, previous_lmf), 4);
4123
4124                         /* ecx = lmf */
4125                         x86_mov_reg_membase (code, X86_ECX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, lmf_addr), 4);
4126
4127                         /* *(lmf) = previous_lmf */
4128                         x86_mov_membase_reg (code, X86_ECX, 0, prev_lmf_reg, 4);
4129                 }
4130
4131                 /* restore caller saved regs */
4132                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4133                         x86_mov_reg_membase (code, X86_EBX, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, ebx), 4);
4134                 }
4135
4136                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4137                         x86_mov_reg_membase (code, X86_EDI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, edi), 4);
4138                 }
4139                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4140                         x86_mov_reg_membase (code, X86_ESI, X86_EBP, lmf_offset + G_STRUCT_OFFSET (MonoLMF, esi), 4);
4141                 }
4142
4143                 /* EBP is restored by LEAVE */
4144         } else {
4145                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4146                         pos -= 4;
4147                 }
4148                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4149                         pos -= 4;
4150                 }
4151                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4152                         pos -= 4;
4153                 }
4154
4155                 if (pos)
4156                         x86_lea_membase (code, X86_ESP, X86_EBP, pos);
4157
4158                 if (cfg->used_int_regs & (1 << X86_ESI)) {
4159                         x86_pop_reg (code, X86_ESI);
4160                 }
4161                 if (cfg->used_int_regs & (1 << X86_EDI)) {
4162                         x86_pop_reg (code, X86_EDI);
4163                 }
4164                 if (cfg->used_int_regs & (1 << X86_EBX)) {
4165                         x86_pop_reg (code, X86_EBX);
4166                 }
4167         }
4168
4169         /* Load returned vtypes into registers if needed */
4170         cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
4171         if (cinfo->ret.storage == ArgValuetypeInReg) {
4172                 for (quad = 0; quad < 2; quad ++) {
4173                         switch (cinfo->ret.pair_storage [quad]) {
4174                         case ArgInIReg:
4175                                 x86_mov_reg_membase (code, cinfo->ret.pair_regs [quad], cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), 4);
4176                                 break;
4177                         case ArgOnFloatFpStack:
4178                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), FALSE);
4179                                 break;
4180                         case ArgOnDoubleFpStack:
4181                                 x86_fld_membase (code, cfg->ret->inst_basereg, cfg->ret->inst_offset + (quad * sizeof (gpointer)), TRUE);
4182                                 break;
4183                         case ArgNone:
4184                                 break;
4185                         default:
4186                                 g_assert_not_reached ();
4187                         }
4188                 }
4189         }
4190
4191         x86_leave (code);
4192
4193         if (CALLCONV_IS_STDCALL (sig)) {
4194                 MonoJitArgumentInfo *arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
4195
4196                 stack_to_pop = mono_arch_get_argument_info (sig, sig->param_count, arg_info);
4197         } else if (MONO_TYPE_ISSTRUCT (mono_method_signature (cfg->method)->ret) && (cinfo->ret.storage == ArgOnStack))
4198                 stack_to_pop = 4;
4199         else
4200                 stack_to_pop = 0;
4201
4202         if (stack_to_pop)
4203                 x86_ret_imm (code, stack_to_pop);
4204         else
4205                 x86_ret (code);
4206
4207         cfg->code_len = code - cfg->native_code;
4208
4209         g_assert (cfg->code_len < cfg->code_size);
4210 }
4211
4212 void
4213 mono_arch_emit_exceptions (MonoCompile *cfg)
4214 {
4215         MonoJumpInfo *patch_info;
4216         int nthrows, i;
4217         guint8 *code;
4218         MonoClass *exc_classes [16];
4219         guint8 *exc_throw_start [16], *exc_throw_end [16];
4220         guint32 code_size;
4221         int exc_count = 0;
4222
4223         /* Compute needed space */
4224         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4225                 if (patch_info->type == MONO_PATCH_INFO_EXC)
4226                         exc_count++;
4227         }
4228
4229         /* 
4230          * make sure we have enough space for exceptions
4231          * 16 is the size of two push_imm instructions and a call
4232          */
4233         if (cfg->compile_aot)
4234                 code_size = exc_count * 32;
4235         else
4236                 code_size = exc_count * 16;
4237
4238         while (cfg->code_len + code_size > (cfg->code_size - 16)) {
4239                 cfg->code_size *= 2;
4240                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4241                 mono_jit_stats.code_reallocs++;
4242         }
4243
4244         code = cfg->native_code + cfg->code_len;
4245
4246         nthrows = 0;
4247         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4248                 switch (patch_info->type) {
4249                 case MONO_PATCH_INFO_EXC: {
4250                         MonoClass *exc_class;
4251                         guint8 *buf, *buf2;
4252                         guint32 throw_ip;
4253
4254                         x86_patch (patch_info->ip.i + cfg->native_code, code);
4255
4256                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4257                         g_assert (exc_class);
4258                         throw_ip = patch_info->ip.i;
4259
4260                         /* Find a throw sequence for the same exception class */
4261                         for (i = 0; i < nthrows; ++i)
4262                                 if (exc_classes [i] == exc_class)
4263                                         break;
4264                         if (i < nthrows) {
4265                                 x86_push_imm (code, (exc_throw_end [i] - cfg->native_code) - throw_ip);
4266                                 x86_jump_code (code, exc_throw_start [i]);
4267                                 patch_info->type = MONO_PATCH_INFO_NONE;
4268                         }
4269                         else {
4270                                 guint32 size;
4271
4272                                 /* Compute size of code following the push <OFFSET> */
4273                                 size = 5 + 5;
4274
4275                                 if ((code - cfg->native_code) - throw_ip < 126 - size) {
4276                                         /* Use the shorter form */
4277                                         buf = buf2 = code;
4278                                         x86_push_imm (code, 0);
4279                                 }
4280                                 else {
4281                                         buf = code;
4282                                         x86_push_imm (code, 0xf0f0f0f0);
4283                                         buf2 = code;
4284                                 }
4285
4286                                 if (nthrows < 16) {
4287                                         exc_classes [nthrows] = exc_class;
4288                                         exc_throw_start [nthrows] = code;
4289                                 }
4290
4291                                 x86_push_imm (code, exc_class->type_token - MONO_TOKEN_TYPE_DEF);
4292                                 patch_info->data.name = "mono_arch_throw_corlib_exception";
4293                                 patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4294                                 patch_info->ip.i = code - cfg->native_code;
4295                                 x86_call_code (code, 0);
4296                                 x86_push_imm (buf, (code - cfg->native_code) - throw_ip);
4297                                 while (buf < buf2)
4298                                         x86_nop (buf);
4299
4300                                 if (nthrows < 16) {
4301                                         exc_throw_end [nthrows] = code;
4302                                         nthrows ++;
4303                                 }
4304                         }
4305                         break;
4306                 }
4307                 default:
4308                         /* do nothing */
4309                         break;
4310                 }
4311         }
4312
4313         cfg->code_len = code - cfg->native_code;
4314
4315         g_assert (cfg->code_len < cfg->code_size);
4316 }
4317
4318 void
4319 mono_arch_flush_icache (guint8 *code, gint size)
4320 {
4321         /* not needed */
4322 }
4323
4324 void
4325 mono_arch_flush_register_windows (void)
4326 {
4327 }
4328
4329 gboolean 
4330 mono_arch_is_inst_imm (gint64 imm)
4331 {
4332         return TRUE;
4333 }
4334
4335 /*
4336  * Support for fast access to the thread-local lmf structure using the GS
4337  * segment register on NPTL + kernel 2.6.x.
4338  */
4339
4340 static gboolean tls_offset_inited = FALSE;
4341
4342 void
4343 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
4344 {
4345         if (!tls_offset_inited) {
4346                 if (!getenv ("MONO_NO_TLS")) {
4347 #ifdef PLATFORM_WIN32
4348                         /* 
4349                          * We need to init this multiple times, since when we are first called, the key might not
4350                          * be initialized yet.
4351                          */
4352                         appdomain_tls_offset = mono_domain_get_tls_key ();
4353                         lmf_tls_offset = mono_get_jit_tls_key ();
4354                         thread_tls_offset = mono_thread_get_tls_key ();
4355
4356                         /* Only 64 tls entries can be accessed using inline code */
4357                         if (appdomain_tls_offset >= 64)
4358                                 appdomain_tls_offset = -1;
4359                         if (lmf_tls_offset >= 64)
4360                                 lmf_tls_offset = -1;
4361                         if (thread_tls_offset >= 64)
4362                                 thread_tls_offset = -1;
4363 #else
4364 #if MONO_XEN_OPT
4365                         optimize_for_xen = access ("/proc/xen", F_OK) == 0;
4366 #endif
4367                         tls_offset_inited = TRUE;
4368                         appdomain_tls_offset = mono_domain_get_tls_offset ();
4369                         lmf_tls_offset = mono_get_lmf_tls_offset ();
4370                         lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
4371                         thread_tls_offset = mono_thread_get_tls_offset ();
4372 #endif
4373                 }
4374         }               
4375 }
4376
4377 void
4378 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
4379 {
4380 }
4381
4382 void
4383 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
4384 {
4385         MonoCallInst *call = (MonoCallInst*)inst;
4386         CallInfo *cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, inst->signature, FALSE);
4387
4388         /* add the this argument */
4389         if (this_reg != -1) {
4390                 if (cinfo->args [0].storage == ArgInIReg) {
4391                         MonoInst *this;
4392                         MONO_INST_NEW (cfg, this, OP_MOVE);
4393                         this->type = this_type;
4394                         this->sreg1 = this_reg;
4395                         this->dreg = mono_regstate_next_int (cfg->rs);
4396                         mono_bblock_add_inst (cfg->cbb, this);
4397
4398                         mono_call_inst_add_outarg_reg (cfg, call, this->dreg, cinfo->args [0].reg, FALSE);
4399                 }
4400                 else {
4401                         MonoInst *this;
4402                         MONO_INST_NEW (cfg, this, OP_OUTARG);
4403                         this->type = this_type;
4404                         this->sreg1 = this_reg;
4405                         mono_bblock_add_inst (cfg->cbb, this);
4406                 }
4407         }
4408
4409         if (vt_reg != -1) {
4410                 MonoInst *vtarg;
4411
4412                 if (cinfo->ret.storage == ArgValuetypeInReg) {
4413                         /*
4414                          * The valuetype is in EAX:EDX after the call, needs to be copied to
4415                          * the stack. Save the address here, so the call instruction can
4416                          * access it.
4417                          */
4418                         MONO_INST_NEW (cfg, vtarg, OP_STORE_MEMBASE_REG);
4419                         vtarg->inst_destbasereg = X86_ESP;
4420                         vtarg->inst_offset = inst->stack_usage;
4421                         vtarg->sreg1 = vt_reg;
4422                         mono_bblock_add_inst (cfg->cbb, vtarg);
4423                 }
4424                 else if (cinfo->ret.storage == ArgInIReg) {
4425                         /* The return address is passed in a register */
4426                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
4427                         vtarg->sreg1 = vt_reg;
4428                         vtarg->dreg = mono_regstate_next_int (cfg->rs);
4429                         mono_bblock_add_inst (cfg->cbb, vtarg);
4430
4431                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
4432                 } else {
4433                         MonoInst *vtarg;
4434                         MONO_INST_NEW (cfg, vtarg, OP_OUTARG);
4435                         vtarg->type = STACK_MP;
4436                         vtarg->sreg1 = vt_reg;
4437                         mono_bblock_add_inst (cfg->cbb, vtarg);
4438                 }
4439         }
4440 }
4441
4442 #ifdef MONO_ARCH_HAVE_IMT
4443
4444 // Linear handler, the bsearch head compare is shorter
4445 //[2 + 4] x86_alu_reg_imm (code, X86_CMP, ins->sreg1, ins->inst_imm);
4446 //[1 + 1] x86_branch8(inst,cond,imm,is_signed)
4447 //        x86_patch(ins,target)
4448 //[1 + 5] x86_jump_mem(inst,mem)
4449
4450 #define CMP_SIZE 6
4451 #define BR_SMALL_SIZE 2
4452 #define BR_LARGE_SIZE 5
4453 #define JUMP_IMM_SIZE 6
4454 #define ENABLE_WRONG_METHOD_CHECK 0
4455
4456 static int
4457 imt_branch_distance (MonoIMTCheckItem **imt_entries, int start, int target)
4458 {
4459         int i, distance = 0;
4460         for (i = start; i < target; ++i)
4461                 distance += imt_entries [i]->chunk_size;
4462         return distance;
4463 }
4464
4465 /*
4466  * LOCKING: called with the domain lock held
4467  */
4468 gpointer
4469 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count)
4470 {
4471         int i;
4472         int size = 0;
4473         guint8 *code, *start;
4474
4475         for (i = 0; i < count; ++i) {
4476                 MonoIMTCheckItem *item = imt_entries [i];
4477                 if (item->is_equals) {
4478                         if (item->check_target_idx) {
4479                                 if (!item->compare_done)
4480                                         item->chunk_size += CMP_SIZE;
4481                                 item->chunk_size += BR_SMALL_SIZE + JUMP_IMM_SIZE;
4482                         } else {
4483                                 item->chunk_size += JUMP_IMM_SIZE;
4484 #if ENABLE_WRONG_METHOD_CHECK
4485                                 item->chunk_size += CMP_SIZE + BR_SMALL_SIZE + 1;
4486 #endif
4487                         }
4488                 } else {
4489                         item->chunk_size += CMP_SIZE + BR_LARGE_SIZE;
4490                         imt_entries [item->check_target_idx]->compare_done = TRUE;
4491                 }
4492                 size += item->chunk_size;
4493         }
4494         code = mono_code_manager_reserve (domain->code_mp, size);
4495         start = code;
4496         for (i = 0; i < count; ++i) {
4497                 MonoIMTCheckItem *item = imt_entries [i];
4498                 item->code_target = code;
4499                 if (item->is_equals) {
4500                         if (item->check_target_idx) {
4501                                 if (!item->compare_done)
4502                                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
4503                                 item->jmp_code = code;
4504                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
4505                                 x86_jump_mem (code, & (vtable->vtable [item->vtable_slot]));
4506                         } else {
4507                                 /* enable the commented code to assert on wrong method */
4508 #if ENABLE_WRONG_METHOD_CHECK
4509                                 x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
4510                                 item->jmp_code = code;
4511                                 x86_branch8 (code, X86_CC_NE, 0, FALSE);
4512 #endif
4513                                 x86_jump_mem (code, & (vtable->vtable [item->vtable_slot]));
4514 #if ENABLE_WRONG_METHOD_CHECK
4515                                 x86_patch (item->jmp_code, code);
4516                                 x86_breakpoint (code);
4517                                 item->jmp_code = NULL;
4518 #endif
4519                         }
4520                 } else {
4521                         x86_alu_reg_imm (code, X86_CMP, MONO_ARCH_IMT_REG, (guint32)item->method);
4522                         item->jmp_code = code;
4523                         if (x86_is_imm8 (imt_branch_distance (imt_entries, i, item->check_target_idx)))
4524                                 x86_branch8 (code, X86_CC_GE, 0, FALSE);
4525                         else
4526                                 x86_branch32 (code, X86_CC_GE, 0, FALSE);
4527                 }
4528         }
4529         /* patch the branches to get to the target items */
4530         for (i = 0; i < count; ++i) {
4531                 MonoIMTCheckItem *item = imt_entries [i];
4532                 if (item->jmp_code) {
4533                         if (item->check_target_idx) {
4534                                 x86_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
4535                         }
4536                 }
4537         }
4538                 
4539         mono_stats.imt_thunks_size += code - start;
4540         g_assert (code - start <= size);
4541         return start;
4542 }
4543
4544 MonoMethod*
4545 mono_arch_find_imt_method (gpointer *regs, guint8 *code)
4546 {
4547         return (MonoMethod*) regs [MONO_ARCH_IMT_REG];
4548 }
4549
4550 MonoObject*
4551 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
4552 {
4553         MonoMethodSignature *sig = mono_method_signature (method);
4554         CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
4555         int this_argument_offset;
4556         MonoObject *this_argument;
4557
4558         /* 
4559          * this is the offset of the this arg from esp as saved at the start of 
4560          * mono_arch_create_trampoline_code () in tramp-x86.c.
4561          */
4562         this_argument_offset = 5;
4563         if (MONO_TYPE_ISSTRUCT (sig->ret) && (cinfo->ret.storage == ArgOnStack))
4564                 this_argument_offset++;
4565
4566         this_argument = * (MonoObject**) (((guint8*) regs [X86_ESP]) + this_argument_offset * sizeof (gpointer));
4567
4568         g_free (cinfo);
4569         return this_argument;
4570 }
4571 #endif
4572
4573 MonoVTable*
4574 mono_arch_find_static_call_vtable (gpointer *regs, guint8 *code)
4575 {
4576         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
4577 }
4578
4579 MonoInst*
4580 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4581 {
4582         MonoInst *ins = NULL;
4583
4584         if (cmethod->klass == mono_defaults.math_class) {
4585                 if (strcmp (cmethod->name, "Sin") == 0) {
4586                         MONO_INST_NEW (cfg, ins, OP_SIN);
4587                         ins->inst_i0 = args [0];
4588                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4589                         MONO_INST_NEW (cfg, ins, OP_COS);
4590                         ins->inst_i0 = args [0];
4591                 } else if (strcmp (cmethod->name, "Tan") == 0) {
4592                         MONO_INST_NEW (cfg, ins, OP_TAN);
4593                         ins->inst_i0 = args [0];
4594                 } else if (strcmp (cmethod->name, "Atan") == 0) {
4595                         MONO_INST_NEW (cfg, ins, OP_ATAN);
4596                         ins->inst_i0 = args [0];
4597                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4598                         MONO_INST_NEW (cfg, ins, OP_SQRT);
4599                         ins->inst_i0 = args [0];
4600                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4601                         MONO_INST_NEW (cfg, ins, OP_ABS);
4602                         ins->inst_i0 = args [0];
4603                 }
4604
4605                 if (cfg->opt & MONO_OPT_CMOV) {
4606                         int opcode = 0;
4607
4608                         if (strcmp (cmethod->name, "Min") == 0) {
4609                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4610                                         opcode = OP_IMIN;
4611                                 else if (fsig->params [0]->type == MONO_TYPE_U4)
4612                                         opcode = OP_IMIN_UN;
4613                         } else if (strcmp (cmethod->name, "Max") == 0) {
4614                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4615                                         opcode = OP_IMAX;
4616                                 else if (fsig->params [0]->type == MONO_TYPE_U4)
4617                                         opcode = OP_IMAX_UN;
4618                         }               
4619
4620                         if (opcode) {
4621                                 MONO_INST_NEW (cfg, ins, opcode);
4622                                 ins->inst_i0 = args [0];
4623                                 ins->inst_i1 = args [1];
4624                         }
4625                 }
4626
4627 #if 0
4628                 /* OP_FREM is not IEEE compatible */
4629                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
4630                         MONO_INST_NEW (cfg, ins, OP_FREM);
4631                         ins->inst_i0 = args [0];
4632                         ins->inst_i1 = args [1];
4633                 }
4634 #endif
4635         }
4636
4637         return ins;
4638 }
4639
4640 MonoInst*
4641 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4642 {
4643         MonoInst *ins = NULL;
4644         int opcode = 0;
4645
4646         if (cmethod->klass == mono_defaults.math_class) {
4647                 if (strcmp (cmethod->name, "Sin") == 0) {
4648                         opcode = OP_SIN;
4649                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4650                         opcode = OP_COS;
4651                 } else if (strcmp (cmethod->name, "Tan") == 0) {
4652                         opcode = OP_TAN;
4653                 } else if (strcmp (cmethod->name, "Atan") == 0) {
4654                         opcode = OP_ATAN;
4655                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4656                         opcode = OP_SQRT;
4657                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4658                         opcode = OP_ABS;
4659                 }
4660                 
4661                 if (opcode) {
4662                         MONO_INST_NEW (cfg, ins, opcode);
4663                         ins->type = STACK_R8;
4664                         ins->dreg = mono_alloc_freg (cfg);
4665                         ins->sreg1 = args [0]->dreg;
4666                         MONO_ADD_INS (cfg->cbb, ins);
4667                 }
4668
4669                 if (cfg->opt & MONO_OPT_CMOV) {
4670                         int opcode = 0;
4671
4672                         if (strcmp (cmethod->name, "Min") == 0) {
4673                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4674                                         opcode = OP_IMIN;
4675                         } else if (strcmp (cmethod->name, "Max") == 0) {
4676                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4677                                         opcode = OP_IMAX;
4678                         }               
4679
4680                         if (opcode) {
4681                                 MONO_INST_NEW (cfg, ins, opcode);
4682                                 ins->type = STACK_I4;
4683                                 ins->dreg = mono_alloc_ireg (cfg);
4684                                 ins->sreg1 = args [0]->dreg;
4685                                 ins->sreg2 = args [1]->dreg;
4686                                 MONO_ADD_INS (cfg->cbb, ins);
4687                         }
4688                 }
4689
4690 #if 0
4691                 /* OP_FREM is not IEEE compatible */
4692                 else if (strcmp (cmethod->name, "IEEERemainder") == 0) {
4693                         MONO_INST_NEW (cfg, ins, OP_FREM);
4694                         ins->inst_i0 = args [0];
4695                         ins->inst_i1 = args [1];
4696                 }
4697 #endif
4698         }
4699
4700         return ins;
4701 }
4702
4703 gboolean
4704 mono_arch_print_tree (MonoInst *tree, int arity)
4705 {
4706         return 0;
4707 }
4708
4709 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
4710 {
4711         MonoInst* ins;
4712
4713         return NULL;
4714
4715         if (appdomain_tls_offset == -1)
4716                 return NULL;
4717
4718         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4719         ins->inst_offset = appdomain_tls_offset;
4720         return ins;
4721 }
4722
4723 MonoInst* mono_arch_get_thread_intrinsic (MonoCompile* cfg)
4724 {
4725         MonoInst* ins;
4726
4727         if (thread_tls_offset == -1)
4728                 return NULL;
4729
4730         MONO_INST_NEW (cfg, ins, OP_TLS_GET);
4731         ins->inst_offset = thread_tls_offset;
4732         return ins;
4733 }
4734
4735 guint32
4736 mono_arch_get_patch_offset (guint8 *code)
4737 {
4738         if ((code [0] == 0x8b) && (x86_modrm_mod (code [1]) == 0x2))
4739                 return 2;
4740         else if ((code [0] == 0xba))
4741                 return 1;
4742         else if ((code [0] == 0x68))
4743                 /* push IMM */
4744                 return 1;
4745         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x6))
4746                 /* push <OFFSET>(<REG>) */
4747                 return 2;
4748         else if ((code [0] == 0xff) && (x86_modrm_reg (code [1]) == 0x2))
4749                 /* call *<OFFSET>(<REG>) */
4750                 return 2;
4751         else if ((code [0] == 0xdd) || (code [0] == 0xd9))
4752                 /* fldl <ADDR> */
4753                 return 2;
4754         else if ((code [0] == 0x58) && (code [1] == 0x05))
4755                 /* pop %eax; add <OFFSET>, %eax */
4756                 return 2;
4757         else if ((code [0] >= 0x58) && (code [0] <= 0x58 + X86_NREG) && (code [1] == 0x81))
4758                 /* pop <REG>; add <OFFSET>, <REG> */
4759                 return 3;
4760         else if ((code [0] >= 0xb8) && (code [0] < 0xb8 + 8))
4761                 /* mov <REG>, imm */
4762                 return 1;
4763         else {
4764                 g_assert_not_reached ();
4765                 return -1;
4766         }
4767 }
4768
4769 /**
4770  * mono_breakpoint_clean_code:
4771  *
4772  * Copy @size bytes from @code - @offset to the buffer @buf. If the debugger inserted software
4773  * breakpoints in the original code, they are removed in the copy.
4774  *
4775  * Returns TRUE if no sw breakpoint was present.
4776  */
4777 gboolean
4778 mono_breakpoint_clean_code (guint8 *method_start, guint8 *code, int offset, guint8 *buf, int size)
4779 {
4780         int i;
4781         gboolean can_write = TRUE;
4782         /*
4783          * If method_start is non-NULL we need to perform bound checks, since we access memory
4784          * at code - offset we could go before the start of the method and end up in a different
4785          * page of memory that is not mapped or read incorrect data anyway. We zero-fill the bytes
4786          * instead.
4787          */
4788         if (!method_start || code - offset >= method_start) {
4789                 memcpy (buf, code - offset, size);
4790         } else {
4791                 int diff = code - method_start;
4792                 memset (buf, 0, size);
4793                 memcpy (buf + offset - diff, method_start, diff + size - offset);
4794         }
4795         code -= offset;
4796         for (i = 0; i < MONO_BREAKPOINT_ARRAY_SIZE; ++i) {
4797                 int idx = mono_breakpoint_info_index [i];
4798                 guint8 *ptr;
4799                 if (idx < 1)
4800                         continue;
4801                 ptr = mono_breakpoint_info [idx].address;
4802                 if (ptr >= code && ptr < code + size) {
4803                         guint8 saved_byte = mono_breakpoint_info [idx].saved_byte;
4804                         can_write = FALSE;
4805                         /*g_print ("patching %p with 0x%02x (was: 0x%02x)\n", ptr, saved_byte, buf [ptr - code]);*/
4806                         buf [ptr - code] = saved_byte;
4807                 }
4808         }
4809         return can_write;
4810 }
4811
4812 gpointer
4813 mono_arch_get_vcall_slot (guint8 *code, gpointer *regs, int *displacement)
4814 {
4815         guint8 buf [8];
4816         guint8 reg = 0;
4817         gint32 disp = 0;
4818
4819         mono_breakpoint_clean_code (NULL, code, 8, buf, sizeof (buf));
4820         code = buf + 8;
4821
4822         *displacement = 0;
4823
4824         /* go to the start of the call instruction
4825          *
4826          * address_byte = (m << 6) | (o << 3) | reg
4827          * call opcode: 0xff address_byte displacement
4828          * 0xff m=1,o=2 imm8
4829          * 0xff m=2,o=2 imm32
4830          */
4831         code -= 6;
4832
4833         /* 
4834          * A given byte sequence can match more than case here, so we have to be
4835          * really careful about the ordering of the cases. Longer sequences
4836          * come first.
4837          */
4838         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)) {
4839                 /*
4840                  * This is an interface call
4841                  * 8b 80 0c e8 ff ff       mov    0xffffe80c(%eax),%eax
4842                  * ff 10                   call   *(%eax)
4843                  */
4844                 reg = x86_modrm_rm (code [5]);
4845                 disp = 0;
4846 #ifdef MONO_ARCH_HAVE_IMT
4847         } 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)) {
4848                 /* IMT-based interface calls: with MONO_ARCH_IMT_REG == edx
4849                  * ba 14 f8 28 08          mov    $0x828f814,%edx
4850                  * ff 50 fc                call   *0xfffffffc(%eax)
4851                  */
4852                 reg = code [4] & 0x07;
4853                 disp = (signed char)code [5];
4854 #endif
4855         } else if ((code [1] != 0xe8) && (code [3] == 0xff) && ((code [4] & 0x18) == 0x10) && ((code [4] >> 6) == 1)) {
4856                 reg = code [4] & 0x07;
4857                 disp = (signed char)code [5];
4858         } else {
4859                 if ((code [0] == 0xff) && ((code [1] & 0x18) == 0x10) && ((code [1] >> 6) == 2)) {
4860                         reg = code [1] & 0x07;
4861                         disp = *((gint32*)(code + 2));
4862                 } else if ((code [1] == 0xe8)) {
4863                         return NULL;
4864                 } else if ((code [4] == 0xff) && (((code [5] >> 6) & 0x3) == 0) && (((code [5] >> 3) & 0x7) == 2)) {
4865                         /*
4866                          * This is a interface call
4867                          * 8b 40 30   mov    0x30(%eax),%eax
4868                          * ff 10      call   *(%eax)
4869                          */
4870                         disp = 0;
4871                         reg = code [5] & 0x07;
4872                 }
4873                 else
4874                         return NULL;
4875         }
4876
4877         *displacement = disp;
4878         return regs [reg];
4879 }
4880
4881 gpointer*
4882 mono_arch_get_vcall_slot_addr (guint8 *code, gpointer *regs)
4883 {
4884         gpointer vt;
4885         int displacement;
4886         vt = mono_arch_get_vcall_slot (code, regs, &displacement);
4887         if (!vt)
4888                 return NULL;
4889         return (gpointer*)((char*)vt + displacement);
4890 }
4891
4892 gpointer
4893 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig,
4894                 gssize *regs, guint8 *code)
4895 {
4896         guint32 esp = regs [X86_ESP];
4897         CallInfo *cinfo;
4898         gpointer res;
4899
4900         if (!gsctx && code)
4901                 gsctx = mono_get_generic_context_from_code (code);
4902         cinfo = get_call_info (gsctx, NULL, sig, FALSE);
4903
4904         /*
4905          * The stack looks like:
4906          * <other args>
4907          * <this=delegate>
4908          * <possible vtype return address>
4909          * <return addr>
4910          * <4 pointers pushed by mono_arch_create_trampoline_code ()>
4911          */
4912         res = (((MonoObject**)esp) [5 + (cinfo->args [0].offset / 4)]);
4913         g_free (cinfo);
4914         return res;
4915 }
4916
4917 #define MAX_ARCH_DELEGATE_PARAMS 10
4918
4919 gpointer
4920 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
4921 {
4922         guint8 *code, *start;
4923
4924         if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
4925                 return NULL;
4926
4927         /* FIXME: Support more cases */
4928         if (MONO_TYPE_ISSTRUCT (sig->ret))
4929                 return NULL;
4930
4931         /*
4932          * The stack contains:
4933          * <delegate>
4934          * <return addr>
4935          */
4936
4937         if (has_target) {
4938                 static guint8* cached = NULL;
4939                 if (cached)
4940                         return cached;
4941                 
4942                 start = code = mono_global_codeman_reserve (64);
4943
4944                 /* Replace the this argument with the target */
4945                 x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
4946                 x86_mov_reg_membase (code, X86_ECX, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, target), 4);
4947                 x86_mov_membase_reg (code, X86_ESP, 4, X86_ECX, 4);
4948                 x86_jump_membase (code, X86_EAX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4949
4950                 g_assert ((code - start) < 64);
4951
4952                 mono_debug_add_delegate_trampoline (start, code - start);
4953
4954                 mono_memory_barrier ();
4955
4956                 cached = start;
4957         } else {
4958                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
4959                 int i = 0;
4960                 /* 8 for mov_reg and jump, plus 8 for each parameter */
4961                 int code_reserve = 8 + (sig->param_count * 8);
4962
4963                 for (i = 0; i < sig->param_count; ++i)
4964                         if (!mono_is_regsize_var (sig->params [i]))
4965                                 return NULL;
4966
4967                 code = cache [sig->param_count];
4968                 if (code)
4969                         return code;
4970
4971                 /*
4972                  * The stack contains:
4973                  * <args in reverse order>
4974                  * <delegate>
4975                  * <return addr>
4976                  *
4977                  * and we need:
4978                  * <args in reverse order>
4979                  * <return addr>
4980                  * 
4981                  * without unbalancing the stack.
4982                  * So move each arg up a spot in the stack (overwriting un-needed 'this' arg)
4983                  * and leaving original spot of first arg as placeholder in stack so
4984                  * when callee pops stack everything works.
4985                  */
4986
4987                 start = code = mono_global_codeman_reserve (code_reserve);
4988
4989                 /* store delegate for access to method_ptr */
4990                 x86_mov_reg_membase (code, X86_ECX, X86_ESP, 4, 4);
4991
4992                 /* move args up */
4993                 for (i = 0; i < sig->param_count; ++i) {
4994                         x86_mov_reg_membase (code, X86_EAX, X86_ESP, (i+2)*4, 4);
4995                         x86_mov_membase_reg (code, X86_ESP, (i+1)*4, X86_EAX, 4);
4996                 }
4997
4998                 x86_jump_membase (code, X86_ECX, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
4999
5000                 g_assert ((code - start) < code_reserve);
5001
5002                 mono_debug_add_delegate_trampoline (start, code - start);
5003
5004                 mono_memory_barrier ();
5005
5006                 cache [sig->param_count] = start;
5007         }
5008
5009         return start;
5010 }
5011
5012 gpointer
5013 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5014 {
5015         switch (reg) {
5016         case X86_ECX: return (gpointer)ctx->ecx;
5017         case X86_EDX: return (gpointer)ctx->edx;
5018         case X86_EBP: return (gpointer)ctx->ebp;
5019         case X86_ESP: return (gpointer)ctx->esp;
5020         default: return ((gpointer)(&ctx->eax)[reg]);
5021         }
5022 }