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