*** empty log message ***
[mono.git] / mono / jit / emit-x86.c
index 41bb381cd28cb9934b574385d6d2fe1bc339a9f1..90930f55b6bc949b8e5ad524c82dd04a6015c984 100644 (file)
 #include <mono/metadata/profiler-private.h>
 
 #include "jit.h"
+#include "helpers.h"
 #include "codegen.h"
 #include "debug.h"
 
+
+//#define DEBUG_REGALLOC
+//#define DEBUG_SPILLS
+
+const char *
+arch_get_reg_name (int regnum)
+{
+       switch (regnum) {
+       case 0:
+               return "EAX";
+       case 1:
+               return "ECX";
+       case 2:
+               return "EDX";
+       case 3:
+               return "EBX";
+       case 4:
+               return "ESP";
+       case 5:
+               return "EBP";
+       case 6:
+               return "ESI";
+       case 7:
+               return "EDI";
+       }
+
+       g_assert_not_reached ();
+       return NULL;
+}
+
+
+/* 
+ * we may want a x86-specific header or we 
+ * can just declare it extern in x86.brg.
+ */
+int mono_x86_have_cmov = 0;
+
+static int 
+cpuid (int id, int* p_eax, int* p_ebx, int* p_ecx, int* p_edx)
+{
+#ifdef PIC
+       return 0;
+#else
+       int have_cpuid = 0;
+       __asm__  __volatile__ (
+               "pushfl\n"
+               "popl %%eax\n"
+               "movl %%eax, %%edx\n"
+               "xorl $0x200000, %%eax\n"
+               "pushl %%eax\n"
+               "popfl\n"
+               "pushfl\n"
+               "popl %%eax\n"
+               "xorl %%edx, %%eax\n"
+               "andl $0x200000, %%eax\n"
+               "movl %%eax, %0"
+               : "=r" (have_cpuid)
+               :
+               : "%eax", "%edx"
+       );
+
+       if (have_cpuid) {
+               __asm__ __volatile__ ("cpuid"
+                       : "=a" (*p_eax), "=b" (*p_ebx), "=c" (*p_ecx), "=d" (*p_edx)
+                       : "a" (id));
+               return 1;
+       }
+       return 0;
+#endif
+}
+
+void
+mono_cpu_detect (void) {
+       int eax, ebx, ecx, edx;
+
+       /* Feature Flags function, flags returned in EDX. */
+       if (cpuid(1, &eax, &ebx, &ecx, &edx)) {
+               if (edx & (1U << 15)) {
+                       mono_x86_have_cmov = 1;
+               }
+       }
+}
+
+/*
+ * arch_get_argument_info:
+ * @csig:  a method signature
+ * @param_count: the number of parameters to consider
+ * @arg_info: an array to store the result infos
+ *
+ * Gathers information on parameters such as size, alignment and
+ * padding. arg_info should be large enought to hold param_count + 1 entries. 
+ *
+ * Returns the size of the activation frame.
+ */
+int
+arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
+{
+       int k, frame_size = 0;
+       int size, align, pad;
+       int offset = 8;
+
+       if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
+               frame_size += sizeof (gpointer);
+               offset += 4;
+       }
+
+       arg_info [0].offset = offset;
+
+       if (csig->hasthis) {
+               frame_size += sizeof (gpointer);
+               offset += 4;
+       }
+
+       arg_info [0].size = frame_size;
+
+       for (k = 0; k < param_count; k++) {
+               
+               if (csig->pinvoke)
+                       size = mono_type_native_stack_size (csig->params [k], &align);
+               else
+                       size = mono_type_stack_size (csig->params [k], &align);
+               
+               frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
+               arg_info [k].pad = pad;
+               frame_size += size;
+               arg_info [k + 1].pad = 0;
+               arg_info [k + 1].size = size;
+               offset += pad;
+               arg_info [k + 1].offset = offset;
+               offset += size;
+       }
+
+       align = MONO_FRAME_ALIGNMENT;
+       frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
+       arg_info [k].pad = pad;
+
+       return frame_size;
+}
+
 static void
 enter_method (MonoMethod *method, char *ebp)
 {
        int i, j;
        MonoClass *class;
        MonoObject *o;
+       MonoJitArgumentInfo *arg_info;
+       MonoMethodSignature *sig;
+       char *fname;
 
-       printf ("ENTER: %s.%s::%s\n(", method->klass->name_space,
-               method->klass->name, method->name);
-
+       fname = mono_method_full_name (method, TRUE);
+       printf ("ENTER: %s\n(", fname);
+       g_free (fname);
        
-       if (((int)ebp & 3) != 0) {
+       if (((int)ebp & (MONO_FRAME_ALIGNMENT - 1)) != 0) {
                g_error ("unaligned stack detected (%p)", ebp);
        }
 
-       ebp += 8;
+       sig = method->signature;
 
-       if (ISSTRUCT (method->signature->ret)) {
-               int size, align;
-               
-               g_assert (!method->signature->ret->byref);
+       if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+               g_assert (!sig->pinvoke);
+
+       arg_info = alloca (sizeof (MonoJitArgumentInfo) * (sig->param_count + 1));
+
+       arch_get_argument_info (sig, sig->param_count, arg_info);
 
-               size = mono_type_stack_size (method->signature->ret, &align);
+       if (MONO_TYPE_ISSTRUCT (method->signature->ret)) {
+               g_assert (!method->signature->ret->byref);
 
-               printf ("VALUERET:%p, ", *((gpointer *)ebp));
-               ebp += sizeof (gpointer);
+               printf ("VALUERET:%p, ", *((gpointer *)(ebp + 8)));
        }
 
        if (method->signature->hasthis) {
+               gpointer *this = (gpointer *)(ebp + arg_info [0].offset);
                if (method->klass->valuetype) {
-                       printf ("value:%p, ", *((gpointer *)ebp));
+                       printf ("value:%p, ", *this);
                } else {
-                       o = *((MonoObject **)ebp);
-
-                       g_assert (o);
+                       o = *((MonoObject **)this);
 
-                       class = o->vtable->klass;
+                       if (o) {
+                               class = o->vtable->klass;
 
-                       if (class == mono_defaults.string_class) {
-                               printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
-                       } else {
-                               printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
-                       }
+                               if (class == mono_defaults.string_class) {
+                                       printf ("this:[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
+                               } else {
+                                       printf ("this:%p[%s.%s], ", o, class->name_space, class->name);
+                               }
+                       } else 
+                               printf ("this:NULL, ");
                }
-               ebp += sizeof (gpointer);
        }
 
        for (i = 0; i < method->signature->param_count; ++i) {
-               MonoType *type = method->signature->params [i];
-               int size, align;
-               size = mono_type_stack_size (type, &align);
+               gpointer *cpos = (gpointer *)(ebp + arg_info [i + 1].offset);
+               int size = arg_info [i + 1].size;
 
+               MonoType *type = method->signature->params [i];
+               
                if (type->byref) {
-                       printf ("[BYREF:%p], ", *((gpointer *)ebp)); 
+                       printf ("[BYREF:%p], ", *cpos); 
                } else switch (type->type) {
                        
                case MONO_TYPE_BOOLEAN:
@@ -91,10 +238,10 @@ enter_method (MonoMethod *method, char *ebp)
                case MONO_TYPE_U4:
                case MONO_TYPE_I:
                case MONO_TYPE_U:
-                       printf ("%d, ", *((int *)(ebp)));
+                       printf ("%d, ", *((int *)(cpos)));
                        break;
                case MONO_TYPE_STRING: {
-                       MonoString *s = *((MonoString **)ebp);
+                       MonoString *s = *((MonoString **)cpos);
                        if (s) {
                                g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
                                printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
@@ -104,7 +251,7 @@ enter_method (MonoMethod *method, char *ebp)
                }
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT: {
-                       o = *((MonoObject **)ebp);
+                       o = *((MonoObject **)cpos);
                        if (o) {
                                class = o->vtable->klass;
                    
@@ -115,7 +262,7 @@ enter_method (MonoMethod *method, char *ebp)
                                } else
                                        printf ("[%s.%s:%p], ", class->name_space, class->name, o);
                        } else {
-                               printf ("%p, ", *((gpointer *)(ebp)));                          
+                               printf ("%p, ", *((gpointer *)(cpos)));                         
                        }
                        break;
                }
@@ -123,30 +270,26 @@ enter_method (MonoMethod *method, char *ebp)
                case MONO_TYPE_FNPTR:
                case MONO_TYPE_ARRAY:
                case MONO_TYPE_SZARRAY:
-                       printf ("%p, ", *((gpointer *)(ebp)));
+                       printf ("%p, ", *((gpointer *)(cpos)));
                        break;
                case MONO_TYPE_I8:
-                       printf ("%lld, ", *((gint64 *)(ebp)));
+                       printf ("%lld, ", *((gint64 *)(cpos)));
                        break;
                case MONO_TYPE_R4:
-                       printf ("%f, ", *((float *)(ebp)));
+                       printf ("%f, ", *((float *)(cpos)));
                        break;
                case MONO_TYPE_R8:
-                       printf ("%f, ", *((double *)(ebp)));
+                       printf ("%f, ", *((double *)(cpos)));
                        break;
                case MONO_TYPE_VALUETYPE: 
                        printf ("[");
                        for (j = 0; j < size; j++)
-                               printf ("%02x,", *((guint8*)ebp +j));
+                               printf ("%02x,", *((guint8*)cpos +j));
                        printf ("], ");
                        break;
                default:
                        printf ("XX, ");
                }
-
-               g_assert (align == 4 || align == 8);
-               ebp += size + align - 1;
-               ebp = (gpointer)((unsigned)ebp & ~(align - 1));
        }
 
        printf (")\n");
@@ -156,9 +299,11 @@ static void
 leave_method (MonoMethod *method, int edx, int eax, double test)
 {
        gint64 l;
+       char *fname;
 
-       printf ("LEAVE: %s.%s::%s ", method->klass->name_space,
-               method->klass->name, method->name);
+       fname = mono_method_full_name (method, TRUE);
+       printf ("LEAVE: %s", fname);
+       g_free (fname);
 
        switch (method->signature->ret->type) {
        case MONO_TYPE_VOID:
@@ -199,6 +344,8 @@ leave_method (MonoMethod *method, int edx, int eax, double test)
                                printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
                        } else if  (o->vtable->klass == mono_defaults.int32_class) {
                                printf ("[INT32:%p:%d]", o, *((gint32 *)((char *)o + sizeof (MonoObject))));    
+                       } else if  (o->vtable->klass == mono_defaults.int64_class) {
+                               printf ("[INT64:%p:%lld]", o, *((gint64 *)((char *)o + sizeof (MonoObject))));  
                        } else
                                printf ("[%s.%s:%p]", o->vtable->klass->name_space, o->vtable->klass->name, o);
                } else
@@ -239,22 +386,71 @@ arch_emit_prologue (MonoFlowGraph *cfg)
 {
        MonoMethod *method = cfg->method;
        MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
-       int i, j;
+       int i, j, k, alloc_size, pos;
 
        x86_push_reg (cfg->code, X86_EBP);
        x86_mov_reg_reg (cfg->code, X86_EBP, X86_ESP, 4);
 
-       if (cfg->locals_size)
-               x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, cfg->locals_size);
+       alloc_size = cfg->locals_size;
+       pos = 0;
 
-       if (mono_regset_reg_used (cfg->rs, X86_EBX)) 
-               x86_push_reg (cfg->code, X86_EBX);
+       if (method->save_lmf) {
+               
+               pos += sizeof (MonoLMF);
 
-       if (mono_regset_reg_used (cfg->rs, X86_EDI)) 
+               /* save the current IP */
+               cfg->lmfip_offset = cfg->code + 1 - cfg->start;
+               x86_push_imm (cfg->code, 0);
+               /* save all caller saved regs */
+               x86_push_reg (cfg->code, X86_EBX);
                x86_push_reg (cfg->code, X86_EDI);
-
-       if (mono_regset_reg_used (cfg->rs, X86_ESI))
                x86_push_reg (cfg->code, X86_ESI);
+               x86_push_reg (cfg->code, X86_EBP);
+
+               /* save method info */
+               x86_push_imm (cfg->code, method);
+       
+               /* get the address of lmf for the current thread */
+               mono_add_jump_info (cfg, cfg->code, MONO_JUMP_INFO_ABS, mono_get_lmf_addr);
+               x86_call_code (cfg->code, 0);
+
+               /* push lmf */
+               x86_push_reg (cfg->code, X86_EAX); 
+               /* push *lfm (previous_lmf) */
+               x86_push_membase (cfg->code, X86_EAX, 0);
+               /* *(lmf) = ESP */
+               x86_mov_membase_reg (cfg->code, X86_EAX, 0, X86_ESP, 4);
+       } else {
+
+#if 0
+               /* activation frame alignment check */
+               x86_mov_reg_reg (cfg->code, X86_EAX, X86_ESP, 4);
+               x86_alu_reg_imm (cfg->code, X86_AND, X86_EAX, MONO_FRAME_ALIGNMENT - 1);
+               x86_alu_reg_imm (cfg->code, X86_CMP, X86_EAX, 0);
+               x86_branch32 (cfg->code, X86_CC_EQ, 1, FALSE);
+               x86_breakpoint (cfg->code);
+#endif
+
+               if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+                       x86_push_reg (cfg->code, X86_EBX);
+                       pos += 4;
+               }
+
+               if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+                       x86_push_reg (cfg->code, X86_EDI);
+                       pos += 4;
+               }
+
+               if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+                       x86_push_reg (cfg->code, X86_ESI);
+                       pos += 4;
+               }
+       }
+
+       alloc_size -= pos;
+
+       if (alloc_size)
+               x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, alloc_size);
 
        if (mono_jit_trace_calls) {
                x86_push_reg (cfg->code, X86_EBP);
@@ -272,11 +468,34 @@ arch_emit_prologue (MonoFlowGraph *cfg)
 
        /* initialize local vars */
        if (header->num_locals) {
+               gboolean unassigned_locals = TRUE;
+
+               if (cfg->bblocks [0].live_in_set) {
+                       i = mono_bitset_find_first (cfg->bblocks [0].live_in_set, 
+                                                   cfg->locals_start_index - 1);
+                       unassigned_locals = (i >= 0 && i < cfg->locals_start_index + 
+                                            header->num_locals);
+               }
 
-               if (header->init_locals) {
-                       int offset = g_array_index (cfg->varinfo, MonoVarInfo, 
-                                                   cfg->locals_start_index + header->num_locals - 1).offset;  
+               if (unassigned_locals && header->init_locals) {
+                       MonoVarInfo *vi = &VARINFO (cfg, cfg->locals_start_index + header->num_locals - 1);
+                       int offset = vi->offset;  
                        int size = - offset;
+                       int inited = 0;
+                       
+                       /* do not clear caller saved registers */
+                       size -= 12;
+
+                       for (i = 0; i < header->num_locals; ++i) {
+                               MonoVarInfo *rv = &VARINFO (cfg, cfg->locals_start_index + i);
+
+                               if (rv->reg >= 0) {
+                                       int ind = 1 << rv->reg;
+                                       if (!(inited & ind))
+                                               x86_alu_reg_reg (cfg->code, X86_XOR, rv->reg, rv->reg);
+                                       inited |= ind;
+                               }
+                       }
 
                        if (size == 1 || size == 2 || size == 4) {
                                x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, size);
@@ -285,7 +504,22 @@ arch_emit_prologue (MonoFlowGraph *cfg)
                        
                        i = size / 4;
                        j = size % 4;
-       
+
+                       if (i < 3) {
+                               for (k = 0; k < i; k++) {
+                                       x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
+                                       offset += 4;
+                               }
+
+                               if (j & 2) {
+                                       x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 2);
+                                       offset += 2;
+                               }
+                               if (j & 1)
+                                       x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 1);
+                               return;
+                       }
+                       
                        if (i) {
                                if (!mono_regset_reg_used (cfg->rs, X86_EDI)) 
                                        x86_push_reg (cfg->code, X86_EDI);
@@ -312,7 +546,7 @@ arch_emit_prologue (MonoFlowGraph *cfg)
 
                        for (i = 0; i < header->num_locals; ++i) {
                                MonoType *t = header->locals [i];
-                               int offset = g_array_index (cfg->varinfo, MonoVarInfo, cfg->locals_start_index + i).offset;  
+                               int offset = VARINFO (cfg, cfg->locals_start_index + i).offset;  
 
                                if (t->byref) {
                                        x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
@@ -343,6 +577,7 @@ arch_emit_prologue (MonoFlowGraph *cfg)
 static void
 arch_emit_epilogue (MonoFlowGraph *cfg)
 {
+       int pos;
        /*
         * note: with trace and profiling the value on the FP stack may get clobbered.
         */
@@ -371,20 +606,108 @@ arch_emit_epilogue (MonoFlowGraph *cfg)
                x86_pop_reg (cfg->code, X86_EAX);
        }
 
-       if (mono_regset_reg_used (cfg->rs, X86_ESI))
-               x86_pop_reg (cfg->code, X86_ESI);
+       pos = 0;
+       
+       if (cfg->method->save_lmf) {
+               pos = -sizeof (MonoLMF);
+       } else {
+               if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+                       pos -= 4;
+       }
+               if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+                       pos -= 4;
+               }
+               if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+                       pos -= 4;
+               }
+       }
+       if (pos)
+               x86_lea_membase (cfg->code, X86_ESP, X86_EBP, pos);
 
-       if (mono_regset_reg_used (cfg->rs, X86_EDI))
+       if (cfg->method->save_lmf) {
+               /* ebx = previous_lmf */
+               x86_pop_reg (cfg->code, X86_EBX);
+               /* edi = lmf */
                x86_pop_reg (cfg->code, X86_EDI);
+               /* *(lmf) = previous_lmf */
+               x86_mov_membase_reg (cfg->code, X86_EDI, 0, X86_EBX, 4);
+
+               /* discard method info */
+               x86_pop_reg (cfg->code, X86_ESI);
 
-       if (mono_regset_reg_used (cfg->rs, X86_EBX))
+               /* restore caller saved regs */
+               x86_pop_reg (cfg->code, X86_EBP);
+               x86_pop_reg (cfg->code, X86_ESI);
+               x86_pop_reg (cfg->code, X86_EDI);
                x86_pop_reg (cfg->code, X86_EBX);
 
+       } else {
+
+               if (mono_regset_reg_used (cfg->rs, X86_ESI)) {
+                       x86_pop_reg (cfg->code, X86_ESI);
+               }
+               if (mono_regset_reg_used (cfg->rs, X86_EDI)) {
+                       x86_pop_reg (cfg->code, X86_EDI);
+               }
+               if (mono_regset_reg_used (cfg->rs, X86_EBX)) {
+                       x86_pop_reg (cfg->code, X86_EBX);
+               }
+       }
+
        x86_leave (cfg->code);
        x86_ret (cfg->code);
 }
 
 static void
+init_varinfo (MonoFlowGraph *cfg, MonoVarInfo *vi)
+{
+       vi->range.last_use.abs_pos = 0;
+       vi->range.first_use.pos.bid = 0xffff;
+       vi->range.first_use.pos.tid = 0;        
+       vi->isvolatile = 0;
+       vi->reg = -1;
+       vi->varnum = cfg->varinfo->len;
+}
+
+int
+arch_allocate_arg (MonoFlowGraph *cfg, MonoJitArgumentInfo *info, MonoValueType type)
+{
+       MonoVarInfo vi;
+
+       mono_jit_stats.allocate_var++;
+
+       init_varinfo (cfg, &vi);
+       vi.isvolatile = 1;
+       
+       SET_VARINFO (vi, type, MONO_ARGVAR, info->offset, info->size);
+       g_array_append_val (cfg->varinfo, vi);
+
+       return cfg->varinfo->len - 1;
+}
+
+int
+arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoVarType vartype, MonoValueType type)
+{
+       MonoVarInfo vi;
+
+       mono_jit_stats.allocate_var++;
+
+       init_varinfo (cfg, &vi);
+
+       if (size != sizeof (gpointer))
+               vi.isvolatile = 1;
+       
+       cfg->locals_size += size;
+       cfg->locals_size += align - 1;
+       cfg->locals_size &= ~(align - 1);
+
+       SET_VARINFO (vi, type, vartype, - cfg->locals_size, size);
+       g_array_append_val (cfg->varinfo, vi);
+
+       return cfg->varinfo->len - 1;
+}
+
+static gboolean
 mono_label_cfg (MonoFlowGraph *cfg)
 {
        int i, j;
@@ -401,101 +724,150 @@ mono_label_cfg (MonoFlowGraph *cfg)
                for (j = 0; j < top; j++) {
                        MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
                        MBState *mbstate;
-
+                       
                        mbstate =  mono_burg_label (t1, cfg);
 
                        if (!mbstate) {
-                               cfg->invalid = 1;
-                               if (mono_debug_handle)
-                                       return;
-                               g_warning ("tree does not match");
-                               mono_print_ctree (t1); printf ("\n\n");
+                               if (mono_debug_format != MONO_DEBUG_FORMAT_NONE)
+                                       return FALSE;
+                               g_warning ("tree does not match in %s: 0x%04x",
+                                          mono_method_full_name (cfg->method, TRUE), t1->cli_addr);
+                               mono_print_ctree (cfg, t1); printf ("\n\n");
 
-                               mono_print_forest (forest);
+                               mono_print_forest (cfg, forest);
                                g_assert_not_reached ();
                        }
                }
        }
-}
-
-static void
-tree_preallocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
-{
-       switch (tree->op) {
-       case MB_TERM_CALL_I4:
-       case MB_TERM_CALL_I8:
-       case MB_TERM_CALL_R8:
-//     case MB_TERM_CALL_VOID :
-               tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
-               tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
-               tree->reg3 = mono_regset_alloc_reg (rs, X86_ECX, tree->exclude_mask);
-               return;
-       default: break;
-       }
 
-       switch (goal) {
-       case MB_NTERM_reg:
-       case MB_NTERM_lreg: {
-               switch (tree->op) {
-               case MB_TERM_SHL:
-               case MB_TERM_SHR:
-               case MB_TERM_SHR_UN:
-                       tree->exclude_mask |= (1 << X86_ECX);
-                       tree->left->exclude_mask |= (1 << X86_ECX);
-                       break;
-               case MB_TERM_MUL:
-               case MB_TERM_MUL_OVF:
-               case MB_TERM_MUL_OVF_UN:
-               case MB_TERM_DIV:
-               case MB_TERM_DIV_UN:
-               case MB_TERM_REM:
-               case MB_TERM_REM_UN:
-                       tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, tree->exclude_mask);
-                       tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, tree->exclude_mask);
-                       if (goal == MB_NTERM_reg) {
-                               tree->left->exclude_mask |= (1 << X86_EDX);
-                               tree->right->exclude_mask |= (1 << X86_EDX) | (1 << X86_EAX);
-                       }
-                       break;
-               default:
-                       break;
-               }
-               break;
-       }
-       default:
-               break;
-       }
+       return TRUE;
 }
 
-static void
-tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs) 
+static gboolean
+tree_allocate_regs (MonoFlowGraph *cfg, MBTree *tree, int goal, MonoRegSet *rs, 
+                   guint8 exclude_mask, int *spillcount) 
 {
        MBTree *kids[10];
        int ern = mono_burg_rule (tree->state, goal);
        const guint16 *nts = mono_burg_nts [ern];
+       guint8 left_exclude_mask = 0, right_exclude_mask = 0;
        int i;
        
+#ifdef DEBUG_REGALLOC
+       printf ("tree_allocate_regs start %d %08x %d %d\n",  tree->op, rs->free_mask, goal, 
+               (nts [0] && kids [0] == tree));
+#endif
+
        mono_burg_kids (tree, ern, kids);
 
-       //printf ("RALLOC START %d %p %d %d\n",  tree->op, rs->free_mask, goal, (nts [0] && kids [0] == tree));
+       switch (tree->op) {
+       case MB_TERM_SHL:
+       case MB_TERM_SHR:
+       case MB_TERM_SHR_UN:
+               exclude_mask |= (1 << X86_ECX);
+               left_exclude_mask |= (1 << X86_ECX);
+               break;
+       case MB_TERM_MUL:
+       case MB_TERM_MUL_OVF:
+       case MB_TERM_MUL_OVF_UN:
+       case MB_TERM_DIV:
+       case MB_TERM_DIV_UN:
+       case MB_TERM_REM:
+       case MB_TERM_REM_UN:
+               if (goal == MB_NTERM_reg) {
+                       left_exclude_mask |= (1 << X86_EDX);
+                       right_exclude_mask |= (1 << X86_EDX) | (1 << X86_EAX);
+               }
+               break;
+       default:
+               break;
+       }
 
        if (nts [0] && kids [0] == tree) {
                /* chain rule */
-               tree_allocate_regs (kids [0], nts [0], rs);
-               /* special case reg: coni4 */
-               if (goal == MB_NTERM_reg) {
-                       if (tree->reg1 == -1)
-                               tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
-                       g_assert (tree->reg1 != -1);
-               }
-               return;
+               if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, exclude_mask, spillcount))
+                       return FALSE;
+               return TRUE;
        }
 
-       for (i = 0; nts [i]; i++)
-               tree_preallocate_regs (kids [i], nts [i], rs);
+       if (tree->spilled) {
+               if (tree->reg1 >= 0)
+                       (*spillcount)--;
+               if (tree->reg2 >= 0)
+                       (*spillcount)--;
+               if (tree->reg3 >= 0)
+                       (*spillcount)--;
+       }
+
+       tree->reg1 = -1;
+       tree->reg2 = -1;
+       tree->reg3 = -1;
+       
+       tree->spilled = 0;
+       if (nts [0]) {
+               if (nts [1]) { /* two kids */
+                       MonoRegSet saved_rs;
+
+                       if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, left_exclude_mask, spillcount))
+                               return FALSE;
+
+                       saved_rs = *rs;
+
+                       if (!tree_allocate_regs (cfg, kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
+
+#ifdef DEBUG_REGALLOC
+                               printf ("tree_allocate_regs try 1 failed %d %d %d %d\n", 
+                                       nts [1], kids [1]->reg1,
+                                       kids [1]->reg2,kids [1]->reg3);
+#endif
+                               *rs = saved_rs;
+
+                               if (kids [0]->reg1 != -1) {
+                                       right_exclude_mask |= 1 << kids [0]->reg1;
+                                       (*spillcount)++;
+                               }
+                               if (kids [0]->reg2 != -1) {
+                                       right_exclude_mask |= 1 << kids [0]->reg2;
+                                       (*spillcount)++;
+                               }
+                               if (kids [0]->reg3 != -1) {
+                                       right_exclude_mask |= 1 << kids [0]->reg3;
+                                       (*spillcount)++;
+                               }
+
+                               mono_regset_free_reg (rs, kids [0]->reg1);
+                               mono_regset_free_reg (rs, kids [0]->reg2);
+                               mono_regset_free_reg (rs, kids [0]->reg3);
+
+                               kids [0]->spilled = 1;
+
+                               if (!tree_allocate_regs (cfg, kids [1], nts [1], rs, right_exclude_mask, spillcount)) {
+#ifdef DEBUG_REGALLOC
+                                       printf ("tree_allocate_regs try 2 failed\n");
+#endif
+                                       return FALSE;
+                               }
+#ifdef DEBUG_REGALLOC
+                               printf ("tree_allocate_regs try 2 succesfull\n");
+#endif
+                       }
+
+                       if (nts [2]) {
+                               if (nts [3]) /* we cant handle four kids */
+                                       g_assert_not_reached ();
+
+                               if (!tree_allocate_regs (cfg, kids [2], nts [2], rs, right_exclude_mask, spillcount))
+                                       return FALSE;
+                               
+                       }
+
+               } else { /* one kid */
+                       if (!tree_allocate_regs (cfg, kids [0], nts [0], rs, left_exclude_mask, spillcount))
+                               return FALSE;                   
+               }
+       }
 
-       for (i = 0; nts [i]; i++)
-               tree_allocate_regs (kids [i], nts [i], rs);
 
        for (i = 0; nts [i]; i++) {
                mono_regset_free_reg (rs, kids [i]->reg1);
@@ -503,22 +875,60 @@ tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs)
                mono_regset_free_reg (rs, kids [i]->reg3);
        }
 
+       tree->emit = mono_burg_func [ern];
+
+       switch (tree->op) {
+       case MB_TERM_CALL_I4:
+       case MB_TERM_CALL_I8:
+       case MB_TERM_CALL_R8:
+       // case MB_TERM_CALL_VOID :
+               if ((tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, exclude_mask)) == -1)
+                       return FALSE;
+               if ((tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, exclude_mask)) == -1)
+                       return FALSE;
+               if ((tree->reg3 = mono_regset_alloc_reg (rs, X86_ECX, exclude_mask)) == -1)
+                       return FALSE;
+               return TRUE;
+       }
+
        switch (goal) {
        case MB_NTERM_reg:
-               if (tree->reg1 < 0) { 
-                       tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
-                       g_assert (tree->reg1 != -1);
+               switch (tree->op) {
+               case MB_TERM_MUL_OVF_UN:
+               case MB_TERM_DIV:
+               case MB_TERM_DIV_UN:
+               case MB_TERM_REM:
+               case MB_TERM_REM_UN:
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, exclude_mask)) == -1)
+                               return FALSE;                   
+                       if ((tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, exclude_mask)) == -1)
+                               return FALSE;
+                       break;
+               default:
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, -1, exclude_mask)) == -1)
+                               return FALSE;
                }
                break;
 
        case MB_NTERM_lreg:
-               if (tree->reg1 < 0) { 
-                       tree->reg1 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
-                       g_assert (tree->reg1 != -1);
-               }
-               if (tree->reg2 < 0) { 
-                       tree->reg2 = mono_regset_alloc_reg (rs, -1, tree->exclude_mask);
-                       g_assert (tree->reg2 != -1);
+               switch (tree->op) {
+               case MB_TERM_MUL:
+               case MB_TERM_MUL_OVF:
+               case MB_TERM_MUL_OVF_UN:
+               case MB_TERM_DIV:
+               case MB_TERM_DIV_UN:
+               case MB_TERM_REM:
+               case MB_TERM_REM_UN:
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, X86_EAX, exclude_mask)) == -1)
+                               return FALSE;                   
+                       if ((tree->reg2 = mono_regset_alloc_reg (rs, X86_EDX, exclude_mask)) == -1)
+                               return FALSE;
+                       break;
+               default:
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, -1, exclude_mask)) == -1)
+                               return FALSE;
+                       if ((tree->reg2 = mono_regset_alloc_reg (rs, -1, exclude_mask)) == -1)
+                               return FALSE;
                }
                break;
 
@@ -528,36 +938,43 @@ tree_allocate_regs (MBTree *tree, int goal, MonoRegSet *rs)
       
        case MB_NTERM_addr:
                if (tree->op == MB_TERM_ADD) {
-                       tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
-                       tree->reg2 = mono_regset_alloc_reg (rs, tree->right->reg1, tree->exclude_mask);
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, exclude_mask)) == -1)
+                               return FALSE;
+                       if ((tree->reg2 = mono_regset_alloc_reg (rs, tree->right->reg1, exclude_mask)) == -1)
+                               return FALSE;
                }
                break;
                
        case MB_NTERM_base:
                if (tree->op == MB_TERM_ADD) {
-                       tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, exclude_mask)) == -1)
+                               return FALSE;
                }
                break;
               
        case MB_NTERM_index:
                if (tree->op == MB_TERM_SHL ||
                    tree->op == MB_TERM_MUL) {
-                       tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, tree->exclude_mask);
+                       if ((tree->reg1 = mono_regset_alloc_reg (rs, tree->left->reg1, exclude_mask)) == -1)
+                               return FALSE;
                }
                break;
               
        default:
                /* do nothing */
+               break;
        }
 
-       //printf ("RALLOC END %d %p\n",  tree->op, rs->free_mask);
-       tree->emit = mono_burg_func [ern];
+#ifdef DEBUG_REGALLOC
+       printf ("tree_allocate_regs end %d %08x\n",  tree->op, rs->free_mask);
+#endif
+       return TRUE;
 }
 
 static void
 arch_allocate_regs (MonoFlowGraph *cfg)
 {
-       int i, j;
+       int i, j, max_spillcount = 0;
        
        for (i = 0; i < cfg->block_count; i++) {
                GPtrArray *forest = cfg->bblocks [i].forest;
@@ -570,31 +987,121 @@ arch_allocate_regs (MonoFlowGraph *cfg)
 
                for (j = 0; j < top; j++) {
                        MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
-                       //printf ("AREGSTART %d:%d %p\n", i, j, cfg->rs->free_mask);
-                       tree_allocate_regs (t1, 1, cfg->rs);
-                       //printf ("AREGENDT %d:%d %p\n", i, j, cfg->rs->free_mask);
+                       int spillcount = 0;
+#ifdef DEBUG_REGALLOC
+                       printf ("arch_allocate_regs start %d:%d %08x\n", i, j, cfg->rs->free_mask);
+#endif
+                       if (!tree_allocate_regs (cfg, t1, 1, cfg->rs, 0, &spillcount)) {
+                               mono_print_ctree (cfg, t1);
+                               printf ("\n");
+                               g_error ("register allocation failed");
+                       }
+
+                       max_spillcount = MAX (max_spillcount, spillcount);
+
+#ifdef DEBUG_REGALLOC
+                       printf ("arch_allocate_regs end %d:%d %08x\n", i, j, cfg->rs->free_mask);
+#endif
                        g_assert (cfg->rs->free_mask == 0xffffffff);
                }
        }
+
+       /* allocate space for spilled regs */
+
+       cfg->spillvars = mono_mempool_alloc0 (cfg->mp, sizeof (gint) *  max_spillcount);
+       cfg->spillcount = max_spillcount;
+
+       for (i = 0; i < max_spillcount; i++) {
+               int spillvar;
+               spillvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer),
+                                             MONO_TEMPVAR, VAL_I32);
+               cfg->spillvars [i] = VARINFO (cfg, spillvar).offset;
+       }
 }
 
 static void
-tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree) 
+tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree, int *spillcount
 {
        MBTree *kids[10];
-       int i, ern = mono_burg_rule (tree->state, goal);
+       int ern = mono_burg_rule (tree->state, goal);
        const guint16 *nts = mono_burg_nts [ern];
        MBEmitFunc emit;
        int offset;
 
        mono_burg_kids (tree, ern, kids);
 
-       for (i = 0; nts [i]; i++) 
-               tree_emit (nts [i], cfg, kids [i]);
+       if (nts [0]) {
+               if (nts [1]) {
+                       int spilloffset1, spilloffset2, spilloffset3;
+                       
+                       tree_emit (nts [0], cfg, kids [0], spillcount);
+
+                       if (kids [0]->spilled) {
+#ifdef DEBUG_SPILLS
+                               printf ("SPILL_REGS %d %03x %s.%s:%s\n", 
+                                       nts [0], cfg->code - cfg->start,
+                                       cfg->method->klass->name_space,
+                                       cfg->method->klass->name, cfg->method->name);
+
+                               mono_print_ctree (cfg, kids [0]);printf ("\n\n");
+#endif
+                               spilloffset1 = 0;
+                               spilloffset2 = 0;
+                               spilloffset3 = 0;
+
+                               if (kids [0]->reg1 != -1) {
+                                       spilloffset1 = cfg->spillvars [(*spillcount)++];
+                                       x86_mov_membase_reg (cfg->code, X86_EBP, spilloffset1, 
+                                                            kids [0]->reg1, 4);
+                               }
+                               if (kids [0]->reg2 != -1) {
+                                       spilloffset2 = cfg->spillvars [(*spillcount)++];
+                                       x86_mov_membase_reg (cfg->code, X86_EBP, spilloffset2, 
+                                                            kids [0]->reg2, 4);
+                               }
+                               if (kids [0]->reg3 != -1) {
+                                       spilloffset3 = cfg->spillvars [(*spillcount)++];
+                                       x86_mov_membase_reg (cfg->code, X86_EBP, spilloffset3, 
+                                                            kids [0]->reg3, 4);
+                               }
+                       }
+
+                       tree_emit (nts [1], cfg, kids [1], spillcount);
+
+                       if (kids [0]->spilled) {
+
+#ifdef DEBUG_SPILLS
+                               printf ("RELOAD_REGS %03x %s.%s:%s\n", 
+                                       cfg->code - cfg->start,
+                                       cfg->method->klass->name_space,
+                                       cfg->method->klass->name, cfg->method->name);
+#endif
+
+                               if (kids [0]->reg3 != -1) 
+                                       x86_mov_reg_membase (cfg->code, kids [0]->reg3, X86_EBP, 
+                                                            spilloffset3, 4);
+                               if (kids [0]->reg2 != -1) 
+                                       x86_mov_reg_membase (cfg->code, kids [0]->reg2, X86_EBP, 
+                                                            spilloffset2, 4);
+                               if (kids [0]->reg1 != -1) 
+                                       x86_mov_reg_membase (cfg->code, kids [0]->reg1, X86_EBP, 
+                                                            spilloffset1, 4);
+                       }
+
+                       if (nts [2]) {
+                               g_assert (!nts [3]);
+                               tree_emit (nts [2], cfg, kids [2], spillcount);
+                       }
+               } else {
+                       tree_emit (nts [0], cfg, kids [0], spillcount);
+               }
+       }
+
+       g_assert ((*spillcount) <= cfg->spillcount);
 
        tree->addr = offset = cfg->code - cfg->start;
 
-       // we assume an instruction uses a maximum of 128 bytes
+       /* we assume an instruction uses a maximum of 128 bytes */
        if ((cfg->code_size - offset) <= 128) {
                int add = MIN (cfg->code_size, 128);
                cfg->code_size += add;
@@ -613,7 +1120,7 @@ tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree)
 static void
 mono_emit_cfg (MonoFlowGraph *cfg)
 {
-       int i, j;
+       int i, j, spillcount;
 
        for (i = 0; i < cfg->block_count; i++) {
                MonoBBlock *bb = &cfg->bblocks [i];
@@ -630,7 +1137,8 @@ mono_emit_cfg (MonoFlowGraph *cfg)
                for (j = 0; j < top; j++) {
                        MBTree *t1 = (MBTree *) g_ptr_array_index (forest, j);
                        
-                       tree_emit (1, cfg, t1);
+                       spillcount = 0;
+                       tree_emit (1, cfg, t1, &spillcount);
                }
        }
                
@@ -678,28 +1186,32 @@ mono_compute_branches (MonoFlowGraph *cfg)
        cfg->code = end;
 
        for (ji = cfg->jump_info; ji; ji = ji->next) {
-               gpointer *ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ji->ip) + cfg->start);
-               char *target;
+               unsigned char *ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ji->ip) + cfg->start);
+               unsigned char *target;
 
                switch (ji->type) {
                case MONO_JUMP_INFO_BB:
                        target = ji->data.bb->addr + cfg->start;
-                       *ip = target - GPOINTER_TO_UINT(ip) - 4;
                        break;
                case MONO_JUMP_INFO_ABS:
                        target = ji->data.target;
-                       *ip = target - GPOINTER_TO_UINT(ip) - 4;
                        break;
                case MONO_JUMP_INFO_EPILOG:
                        target = cfg->epilog + cfg->start;
-                       *ip = target - GPOINTER_TO_UINT(ip) - 4;
                        break;
                case MONO_JUMP_INFO_IP:
-                       *ip = ip;
-                       break;
+                       *(unsigned char**)ip = ip;
+                       continue;
                default:
                        g_assert_not_reached ();
                }
+               x86_patch (ip, target);
+       }
+
+       /* patch the IP in the LMF saving code */
+       if (cfg->lmfip_offset) {
+               *((guint32 *)(cfg->start + cfg->lmfip_offset)) =  
+                       (gint32)(cfg->start + cfg->lmfip_offset);
        }
 }
 
@@ -716,253 +1228,75 @@ mono_add_jump_info (MonoFlowGraph *cfg, gpointer ip, MonoJumpInfoType type, gpoi
        cfg->jump_info = ji;
 }
 
-static int
-match_debug_method (MonoMethod* method)
-{
-       GList *tmp = mono_debug_methods;
-
-       for (; tmp; tmp = tmp->next) {
-               if (mono_method_desc_full_match (tmp->data, method))
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * arch_compile_method:
- * @method: pointer to the method info
- *
- * JIT compilation of a single method. 
- *
- * Returns: a pointer to the newly created code.
- */
-gpointer
-arch_compile_method (MonoMethod *method)
+MonoJitInfo *
+arch_jit_compile_cfg (MonoDomain *target_domain, MonoFlowGraph *cfg)
 {
-       MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *ji;
-       guint8 *addr;
-       GHashTable *jit_code_hash;
-
-       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
-           (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
-               if (!method->info)
-                       method->info = arch_create_native_wrapper (method);
-               return method->info;
-       }
-
-       if (mono_jit_share_code)
-               target_domain = mono_root_domain;
-       else 
-               target_domain = domain;
-
-       jit_code_hash = target_domain->jit_code_hash;
-
-       if ((addr = g_hash_table_lookup (jit_code_hash, method))) {
-               mono_jit_stats.methods_lookups++;
-               return addr;
-       }
-
-       mono_jit_stats.methods_compiled++;
-       
-       if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
-               printf ("Start JIT compilation of %s.%s:%s\n", method->klass->name_space,
-                       method->klass->name, method->name);
-       }
-
-       if (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) {
-               const char *name = method->name;
-               guint8 *code;
-               gboolean delegate = FALSE;
-
-               if (method->klass->parent == mono_defaults.multicastdelegate_class)
-                       delegate = TRUE;
-                               
-               if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
-                       addr = (gpointer)mono_delegate_ctor;
-               } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
-                       int size;
-
-                       addr = arch_get_delegate_invoke (method, &size);
-
-                       if (mono_jit_dump_asm) {
-                               char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
-                                                           method->klass->name, method->name);
-                               mono_disassemble_code (addr, size, id);
-                               g_free (id);
-                       }
-               } else if (delegate && *name == 'B' && (strcmp (name, "BeginInvoke") == 0)) {
-                       code = addr = g_malloc (32);
-                       x86_push_imm (code, method);
-                       x86_call_code (code, arch_begin_invoke);
-                       x86_alu_reg_imm (code, X86_ADD, X86_ESP, 4);
-                       x86_ret (code);
-                       g_assert ((code - addr) <= 32);
-               } else if (delegate && *name == 'E' && (strcmp (name, "EndInvoke") == 0)) {
-                       /* this can raise exceptions, so we need a wrapper to save/restore LMF */
-                       method->addr = (gpointer)arch_end_invoke;
-                       addr = arch_create_native_wrapper (method);
-               } else {
-                       mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
-                       if (mono_debug_handle) 
-                               return NULL;
+       guint32 ls_used_mask = 0;
+       MonoMethod *method = cfg->method;
+       int offset, gap;
 
-                       g_error ("Don't know how to exec runtime method %s.%s::%s", 
-                                method->klass->name_space, method->klass->name, method->name);
-               }
-       
-       } else {
-               MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
-               MonoFlowGraph *cfg;
-               MonoMemPool *mp;
-               gulong code_size_ratio;
-       
-               mono_profiler_method_jit (method);
-       
-               ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
+       ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
                
-               mp = mono_mempool_new ();
+       cfg->rs = mono_regset_new (X86_NREG);
+       mono_regset_reserve_reg (cfg->rs, X86_ESP);
+       mono_regset_reserve_reg (cfg->rs, X86_EBP);
 
-               cfg = mono_cfg_new (method, mp);
+       /* we can use this regs for global register allocation */
+       mono_regset_reserve_reg (cfg->rs, X86_EBX);
+       mono_regset_reserve_reg (cfg->rs, X86_ESI);
 
-               mono_analyze_flow (cfg);
-               if (cfg->invalid) {
-                       mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
-                       return NULL;
-               }
-               
-               mono_analyze_stack (cfg);
-               if (cfg->invalid) {
-                       mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
-                       return NULL;
-               }
-               
-               cfg->rs = mono_regset_new (X86_NREG);
-               mono_regset_reserve_reg (cfg->rs, X86_ESP);
-               mono_regset_reserve_reg (cfg->rs, X86_EBP);
-
-               cfg->code_size = MAX (header->code_size * 5, 256);
-               cfg->start = cfg->code = g_malloc (cfg->code_size);
-
-               mono_debug_last_breakpoint_address = cfg->code;
-
-               if (match_debug_method (method) || mono_debug_insert_breakpoint)
-                       x86_breakpoint (cfg->code);
-               else if (mono_debug_handle)
-                       x86_nop (cfg->code);
-
-               if (mono_debug_insert_breakpoint > 0)
-                       mono_debug_insert_breakpoint--;
-
-               if (mono_jit_dump_forest) {
-                       int i;
-                       printf ("FOREST %s.%s:%s\n", method->klass->name_space,
-                               method->klass->name, method->name);
-                       for (i = 0; i < cfg->block_count; i++) {
-                               printf ("BLOCK %d:\n", i);
-                               mono_print_forest (cfg->bblocks [i].forest);
-                       }
-               }
+       if (mono_use_linear_scan) {
+               mono_linear_scan (cfg, &ls_used_mask);
+               cfg->rs->used_mask |= ls_used_mask;
+       }
        
-               mono_label_cfg (cfg);
-               if (cfg->invalid) {
-                       mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
-                       return NULL;
-               }
-               
-               arch_allocate_regs (cfg);
-
-               /* align to 8 byte boundary */
-               cfg->locals_size += 7;
-               cfg->locals_size &= ~7;
-
-               arch_emit_prologue (cfg);
-               cfg->prologue_end = cfg->code - cfg->start;
-               mono_emit_cfg (cfg);
-               arch_emit_epilogue (cfg);               
-               cfg->epilogue_end = cfg->code - cfg->start;
-
-               addr = cfg->start;
-
-               mono_jit_stats.allocated_code_size += cfg->code_size;
-
-               code_size_ratio = cfg->code - cfg->start;
-               if (code_size_ratio > mono_jit_stats.biggest_method_size) {
-                       mono_jit_stats.biggest_method_size = code_size_ratio;
-                       mono_jit_stats.biggest_method = method;
-               }
-               code_size_ratio = (code_size_ratio * 100) / header->code_size;
-               if (code_size_ratio > mono_jit_stats.max_code_size_ratio) {
-                       mono_jit_stats.max_code_size_ratio = code_size_ratio;
-                       mono_jit_stats.max_ratio_method = method;
-               }
-
-               mono_compute_branches (cfg);
-               
-               if (mono_jit_dump_asm) {
-                       char *id = g_strdup_printf ("%s.%s_%s", method->klass->name_space,
-                                                   method->klass->name, method->name);
-                       mono_disassemble_code (cfg->start, cfg->code - cfg->start, id);
-                       g_free (id);
+       if (mono_jit_dump_forest) {
+               int i;
+               printf ("FOREST %s\n", mono_method_full_name (method, TRUE));
+               for (i = 0; i < cfg->block_count; i++) {
+                       printf ("BLOCK %d:\n", i);
+                       mono_print_forest (cfg, cfg->bblocks [i].forest);
                }
-               if (mono_debug_handle)
-                       mono_debug_add_method (mono_debug_handle, cfg);
-
-               ji->code_size = cfg->code - cfg->start;
-               ji->used_regs = cfg->rs->used_mask;
-               ji->method = method;
-               ji->code_start = addr;
-
-               mono_jit_stats.native_code_size += ji->code_size;
-
-               if (header->num_clauses) {
-                       int i, start_block, end_block;
-
-                       ji->num_clauses = header->num_clauses;
-                       ji->clauses = mono_mempool_alloc0 (target_domain->mp, 
-                               sizeof (MonoJitExceptionInfo) * header->num_clauses);
-
-                       for (i = 0; i < header->num_clauses; i++) {
-                               MonoExceptionClause *ec = &header->clauses [i];
-                               MonoJitExceptionInfo *ei = &ji->clauses [i];
+       }
                        
-                               ei->flags = ec->flags;
-                               ei->token_or_filter = ec->token_or_filter;
-
-                               g_assert (cfg->bcinfo [ec->try_offset].is_block_start);
-                               start_block = cfg->bcinfo [ec->try_offset].block_id;
-                               end_block = cfg->bcinfo [ec->try_offset + ec->try_len].block_id;
-                               g_assert (cfg->bcinfo [ec->try_offset + ec->try_len].is_block_start);
-                               
-                               ei->try_start = cfg->start + cfg->bblocks [start_block].addr;
-                               ei->try_end = cfg->start + cfg->bblocks [end_block].addr;
-                               
-                               g_assert (cfg->bcinfo [ec->handler_offset].is_block_start);
-                               start_block = cfg->bcinfo [ec->handler_offset].block_id;
-                               ei->handler_start = cfg->start + cfg->bblocks [start_block].addr;       
-                               
-                               //printf ("TEST %x %x %x\n", ei->try_start, ei->try_end, ei->handler_start);
-                       }
-               }
+       if (!mono_label_cfg (cfg))
+               return NULL;
                
-               mono_jit_info_table_add (target_domain, ji);
-
-               mono_regset_free (cfg->rs);
-
-               mono_cfg_free (cfg);
-
-               mono_mempool_destroy (mp);
-
-               mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
+       arch_allocate_regs (cfg);
+
+       /* align to 8 byte boundary */
+       cfg->locals_size += 7;
+       cfg->locals_size &= ~7;
+
+       arch_emit_prologue (cfg);
+       cfg->prologue_end = cfg->code - cfg->start;
+       mono_emit_cfg (cfg);
+       arch_emit_epilogue (cfg);               
+       cfg->epilogue_end = cfg->code - cfg->start;
+
+       offset = cfg->code - cfg->start;
+       gap = cfg->code_size - offset;
+       if (gap > 0) {
+               char *org = cfg->start;
+#if 0
+               cfg->start = g_realloc (cfg->start, offset);
+#else
+               cfg->start = mono_mempool_alloc (target_domain->code_mp, offset);
+               memcpy (cfg->start, org, offset);
+               g_free (org);
+#endif
+               cfg->code_size = offset;
+               cfg->code = cfg->start + offset;
        }
 
-       if (mono_jit_trace_calls || mono_jit_dump_asm || mono_jit_dump_forest) {
-               printf ("END JIT compilation of %s.%s:%s %p %p\n", method->klass->name_space,
-                       method->klass->name, method->name, method, addr);
-       }
+       mono_compute_branches (cfg);
 
-       g_hash_table_insert (jit_code_hash, method, addr);
+       ji->code_size = cfg->code - cfg->start;
+       ji->used_regs = cfg->rs->used_mask;
+       ji->method = method;
+       ji->code_start = cfg->start;
 
-       return addr;
+       return ji;
 }