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