Flush
[mono.git] / mono / jit / emit-x86.c
index eb3f4eeee37fb40bcdfc4c65ed046edda1591d65..bbeb063383d03203698b71619751883ce50e694c 100644 (file)
 #include <mono/metadata/cil-coff.h>
 #include <mono/metadata/tabledefs.h>
 #include <mono/metadata/class.h>
+#include <mono/metadata/debug-helpers.h>
 #include <mono/metadata/mono-endian.h>
 #include <mono/arch/x86/x86-codegen.h>
+#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, gpointer ebp)
+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 & (MONO_FRAME_ALIGNMENT - 1)) != 0) {
+               g_error ("unaligned stack detected (%p)", ebp);
+       }
 
-       ebp += 8;
+       sig = method->signature;
 
-       if (method->signature->ret->type == MONO_TYPE_VALUETYPE) {
-               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));
 
-               size = mono_type_size (method->signature->ret, &align);
+       arch_get_argument_info (sig, sig->param_count, arg_info);
 
-               printf ("VALUERET:%p, ", *((gpointer *)ebp));
-               ebp += sizeof (gpointer);
+       if (MONO_TYPE_ISSTRUCT (method->signature->ret)) {
+               g_assert (!method->signature->ret->byref);
+
+               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->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_size (type, &align);
+               gpointer *cpos = (gpointer *)(ebp + arg_info [i + 1].offset);
+               int size = arg_info [i + 1].size;
 
-               switch (type->type) {
+               MonoType *type = method->signature->params [i];
+               
+               if (type->byref) {
+                       printf ("[BYREF:%p], ", *cpos); 
+               } else switch (type->type) {
+                       
                case MONO_TYPE_BOOLEAN:
                case MONO_TYPE_CHAR:
                case MONO_TYPE_I1:
@@ -81,12 +237,12 @@ enter_method (MonoMethod *method, gpointer 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)->klass == mono_defaults.string_class);
+                               g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
                                printf ("[STRING:%p:%s], ", s, mono_string_to_utf8 (s));
                        } else 
                                printf ("[STRING:null], ");
@@ -94,17 +250,18 @@ enter_method (MonoMethod *method, gpointer ebp)
                }
                case MONO_TYPE_CLASS:
                case MONO_TYPE_OBJECT: {
-                       o = *((MonoObject **)ebp);
+                       o = *((MonoObject **)cpos);
                        if (o) {
-                               class = o->klass;
+                               class = o->vtable->klass;
+                   
                                if (class == mono_defaults.string_class) {
                                        printf ("[STRING:%p:%s], ", o, mono_string_to_utf8 ((MonoString *)o));
                                } else if (class == mono_defaults.int32_class) {
-                                       printf ("[INT32:%p:%d], ", o, *(gint32 *)((gpointer)o + sizeof (MonoObject)));
+                                       printf ("[INT32:%p:%d], ", o, *(gint32 *)((char *)o + sizeof (MonoObject)));
                                } else
                                        printf ("[%s.%s:%p], ", class->name_space, class->name, o);
                        } else {
-                               printf ("%p, ", *((gpointer *)(ebp)));                          
+                               printf ("%p, ", *((gpointer *)(cpos)));                         
                        }
                        break;
                }
@@ -112,29 +269,26 @@ enter_method (MonoMethod *method, gpointer 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, ");
                }
-
-               ebp += size + 3;
-               ebp = (gpointer)((unsigned)ebp & ~(3));
        }
 
        printf (")\n");
@@ -144,9 +298,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:
@@ -173,7 +329,7 @@ leave_method (MonoMethod *method, int edx, int eax, double test)
                MonoString *s = (MonoString *)eax;
 
                if (s) {
-                       g_assert (((MonoObject *)s)->klass == mono_defaults.string_class);
+                       g_assert (((MonoObject *)s)->vtable->klass == mono_defaults.string_class);
                        printf ("[STRING:%p:%s]", s, mono_string_to_utf8 (s));
                } else 
                        printf ("[STRING:null], ");
@@ -181,17 +337,19 @@ leave_method (MonoMethod *method, int edx, int eax, double test)
        }
        case MONO_TYPE_OBJECT: {
                MonoObject *o = (MonoObject *)eax;
-               
-               if (o->klass == mono_defaults.boolean_class) {
-                       printf ("[BOOLEAN:%p:%d]", o, *((guint8 *)o + sizeof (MonoObject)));            
-               } else if  (o->klass == mono_defaults.int32_class) {
-                       printf ("[INT32:%p:%d]", o, *((gint32 *)((gpointer)o + sizeof (MonoObject))));  
-               } else {
-                       if (o)
-                               printf ("[%s.%s:%p]", o->klass->name_space, o->klass->name, o);
-                       else
-                               printf ("[OBJECT:%p]", (gpointer)eax);
-               }
+
+               if (o) {
+                       if (o->vtable->klass == mono_defaults.boolean_class) {
+                               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
+                       printf ("[OBJECT:%p]", o);
+              
                break;
        }
        case MONO_TYPE_CLASS:
@@ -225,27 +383,188 @@ leave_method (MonoMethod *method, int edx, int eax, double test)
 static void
 arch_emit_prologue (MonoFlowGraph *cfg)
 {
+       MonoMethod *method = cfg->method;
+       MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
+       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);
                x86_push_imm (cfg->code, cfg->method);
-               x86_call_code (cfg->code, enter_method);
+               x86_mov_reg_imm (cfg->code, X86_EAX, enter_method);
+               x86_call_reg (cfg->code, X86_EAX);
                x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
        }
+       if (mono_jit_profile) {
+               x86_push_imm (cfg->code, cfg->method);
+               x86_mov_reg_imm (cfg->code, X86_EAX, mono_profiler_method_enter);
+               x86_call_reg (cfg->code, X86_EAX);
+               x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
+       }
+
+       /* 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 (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);
+                               return;
+                       }
+                       
+                       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);
+                               x86_lea_membase (cfg->code, X86_EDI, X86_EBP, offset);
+                               x86_alu_reg_reg (cfg->code, X86_XOR, X86_EAX, X86_EAX);
+                               x86_mov_reg_imm (cfg->code, X86_ECX, i);
+                               x86_cld (cfg->code);
+                               x86_prefix (cfg->code, X86_REP_PREFIX);
+                               x86_stosl (cfg->code);
+                               for (i = 0; i < j; i++)
+                                       x86_stosb (cfg->code);
+                               if (!mono_regset_reg_used (cfg->rs, X86_EDI)) 
+                                       x86_pop_reg (cfg->code, X86_EDI);
+                       } else {
+
+                               g_assert (j == 3);
+                               x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 2);
+                               x86_mov_membase_imm (cfg->code, X86_EBP, offset + 2, 0, 1);
+                       }
+                       
+               } else {
+
+                       /* we always need to initialize object pointers */
+
+                       for (i = 0; i < header->num_locals; ++i) {
+                               MonoType *t = header->locals [i];
+                               int offset = VARINFO (cfg, cfg->locals_start_index + i).offset;  
+
+                               if (t->byref) {
+                                       x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
+                                       continue;
+                               }
+
+                               switch (t->type) {
+                               case MONO_TYPE_STRING:
+                               case MONO_TYPE_CLASS:
+                               case MONO_TYPE_ARRAY:
+                               case MONO_TYPE_SZARRAY:
+                               case MONO_TYPE_OBJECT:
+                                       x86_mov_membase_imm (cfg->code, X86_EBP, offset, 0, 4);
+                                       break;
+                               }
+
+                       }
+               }
+       }
 }
 
 /**
@@ -257,6 +576,10 @@ 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.
+        */
        if (mono_jit_trace_calls) {
                x86_fld_reg (cfg->code, 0);
                x86_alu_reg_imm (cfg->code, X86_SUB, X86_ESP, 8);
@@ -264,307 +587,284 @@ arch_emit_epilogue (MonoFlowGraph *cfg)
                x86_push_reg (cfg->code, X86_EAX);
                x86_push_reg (cfg->code, X86_EDX);
                x86_push_imm (cfg->code, cfg->method);
-               x86_call_code (cfg->code, leave_method);
+               x86_mov_reg_imm (cfg->code, X86_EAX, leave_method);
+               x86_call_reg (cfg->code, X86_EAX);
                x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
                x86_pop_reg (cfg->code, X86_EDX);
                x86_pop_reg (cfg->code, X86_EAX);
                x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 8);
        }
+       if (mono_jit_profile) {
+               x86_push_reg (cfg->code, X86_EAX);
+               x86_push_reg (cfg->code, X86_EDX);
+               x86_push_imm (cfg->code, cfg->method);
+               x86_mov_reg_imm (cfg->code, X86_EAX, mono_profiler_method_leave);
+               x86_call_reg (cfg->code, X86_EAX);
+               x86_alu_reg_imm (cfg->code, X86_ADD, X86_ESP, 4);
+               x86_pop_reg (cfg->code, X86_EDX);
+               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);
 
-       if (mono_regset_reg_used (cfg->rs, X86_EBX))
+               /* discard method info */
+               x86_pop_reg (cfg->code, X86_ESI);
+
+               /* 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);
 }
 
-/*
- * get_unbox_trampoline:
- * @m: method pointer
- *
- * when value type methods are called through the vtable we need to unbox the
- * this argument. This method returns a pointer to a trampoline which does
- * unboxing before calling the method
- */
-static gpointer
-get_unbox_trampoline (MonoMethod *m)
+static void
+init_varinfo (MonoFlowGraph *cfg, MonoVarInfo *vi)
 {
-       gpointer p = arch_compile_method (m);
-       guint8 *code, *start;
-       int this_pos = 4;
-
-       if (!m->signature->ret->byref && m->signature->ret->type == MONO_TYPE_VALUETYPE)
-               this_pos = 8;
-           
-       start = code = g_malloc (16);
-
-       x86_alu_membase_imm (code, X86_ADD, X86_ESP, this_pos, sizeof (MonoObject));
-       x86_jump_code (code, p);
-       g_assert ((code - start) < 16);
-
-       return start;
+       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;
 }
 
-/**
- * x86_magic_trampoline:
- * @eax: saved x86 register 
- * @ecx: saved x86 register 
- * @edx: saved x86 register 
- * @esi: saved x86 register 
- * @edi: saved x86 register 
- * @ebx: saved x86 register
- * @code: pointer into caller code
- * @method: the method to translate
- *
- * This method is called by the trampoline functions for virtual
- * methods. It inspects the caller code to find the address of the
- * vtable slot, then calls the JIT compiler and writes the address
- * of the compiled method back to the vtable. All virtual methods 
- * are called with: x86_call_membase (inst, basereg, disp). We always
- * use 32 bit displacement to ensure that the length of the call 
- * instruction is 6 bytes. We need to get the value of the basereg 
- * and the constant displacement.
- */
-static gpointer
-x86_magic_trampoline (int eax, int ecx, int edx, int esi, int edi, 
-                     int ebx, guint8 *code, MonoMethod *m)
+int
+arch_allocate_arg (MonoFlowGraph *cfg, MonoJitArgumentInfo *info, MonoValueType type)
 {
-       guint8 ab, reg;
-       gint32 disp;
-       gpointer o;
+       MonoVarInfo vi;
 
-       /* go to the start of the call instruction */
-       code -= 6;
-       g_assert (*code == 0xff);
+       mono_jit_stats.allocate_var++;
 
-       code++;
-       ab = *code;
-       g_assert ((ab >> 6) == 2);
+       init_varinfo (cfg, &vi);
+       vi.isvolatile = 1;
        
-       /* extract the register number containing the address */
-       reg = ab & 0x07;
-       code++;
-
-       /* extract the displacement */
-       disp = *((gint32*)code);
-
-       switch (reg) {
-       case X86_EAX:
-               o = (gpointer)eax;
-               break;
-       case X86_EDX:
-               o = (gpointer)edx;
-               break;
-       case X86_ECX:
-               o = (gpointer)ecx;
-               break;
-       case X86_ESI:
-               o = (gpointer)esi;
-               break;
-       case X86_EDI:
-               o = (gpointer)edi;
-               break;
-       case X86_EBX:
-               o = (gpointer)ebx;
-               break;
-       default:
-               g_assert_not_reached ();
-       }
+       SET_VARINFO (vi, type, MONO_ARGVAR, info->offset, info->size);
+       g_array_append_val (cfg->varinfo, vi);
 
-       o += disp;
-
-       if (m->klass->valuetype) {
-               return *((gpointer *)o) = get_unbox_trampoline (m);
-       } else
-               return *((gpointer *)o) = arch_compile_method (m);
+       return cfg->varinfo->len - 1;
 }
 
-/**
- * arch_create_jit_trampoline:
- * @method: pointer to the method info
- *
- * Creates a trampoline function for virtual methods. If the created
- * code is called it first starts JIT compilation of method,
- * and then calls the newly created method. I also replaces the
- * corresponding vtable entry (see x86_magic_trampoline).
- * 
- * Returns: a pointer to the newly created code 
- */
-gpointer
-arch_create_jit_trampoline (MonoMethod *method)
+int
+arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoVarType vartype, MonoValueType type)
 {
-       guint8 *code, *buf;
-       static guint8 *vc = NULL;
-
-       if (method->addr)
-               return method->addr;
-
-       if (!vc) {
-               vc = buf = g_malloc (24);
-
-               /* push the return address onto the stack */
-               x86_push_membase (buf, X86_ESP, 4);
+       MonoVarInfo vi;
 
-               /* save all register values */
-               x86_push_reg (buf, X86_EBX);
-               x86_push_reg (buf, X86_EDI);
-               x86_push_reg (buf, X86_ESI);
-               x86_push_reg (buf, X86_EDX);
-               x86_push_reg (buf, X86_ECX);
-               x86_push_reg (buf, X86_EAX);
+       mono_jit_stats.allocate_var++;
 
-               x86_call_code (buf, x86_magic_trampoline);
-               x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 8*4);
-
-               /* call the compiled method */
-               x86_jump_reg (buf, X86_EAX);
-
-               g_assert ((buf - vc) <= 24);
-       }
+       init_varinfo (cfg, &vi);
 
-       code = buf = g_malloc (16);
-       x86_push_imm (buf, method);
-       x86_jump_code (buf, vc);
-       g_assert ((buf - code) <= 16);
-
-       return code;
-}
-
-/**
- * arch_create_simple_jit_trampoline:
- * @method: pointer to the method info
- *
- * Creates a trampoline function for method. If the created
- * code is called it first starts JIT compilation of method,
- * and then calls the newly created method. I also replaces the
- * address in method->addr with the result of the JIT 
- * compilation step (in arch_compile_method).
- * 
- * Returns: a pointer to the newly created code 
- */
-gpointer
-arch_create_simple_jit_trampoline (MonoMethod *method)
-{
-       guint8 *code, *buf;
-
-       if (method->addr)
-               return method->addr;
+       if (size != sizeof (gpointer))
+               vi.isvolatile = 1;
+       
+       cfg->locals_size += size;
+       cfg->locals_size += align - 1;
+       cfg->locals_size &= ~(align - 1);
 
-       /* we never free the allocated code buffer */
-       code = buf = g_malloc (16);
-       x86_push_imm (buf, method);
-       x86_call_code (buf, arch_compile_method);
-       x86_alu_reg_imm (buf, X86_ADD, X86_ESP, 4);
-       /* jump to the compiled method */
-       x86_jump_reg (buf, X86_EAX);
-       g_assert ((buf - code) < 16);
+       SET_VARINFO (vi, type, vartype, - cfg->locals_size, size);
+       g_array_append_val (cfg->varinfo, vi);
 
-       return code;
+       return cfg->varinfo->len - 1;
 }
 
-static void
+static gboolean
 mono_label_cfg (MonoFlowGraph *cfg)
 {
        int i, j;
-       
+
        for (i = 0; i < cfg->block_count; i++) {
                GPtrArray *forest = cfg->bblocks [i].forest;
-               const int top = forest->len;
+               int top;
+
+               if (!cfg->bblocks [i].reached) /* unreachable code */
+                       continue;
+               
+               top = forest->len;
 
                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");
+                               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_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);
-                       }
-                       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);
-       guint16 *nts = mono_burg_nts [ern];
+       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\n",  tree->op, rs->free_mask, goal);
+       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);
-               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);
@@ -572,22 +872,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;
 
@@ -597,85 +935,207 @@ 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;
-               const int top = forest->len;
+               int top;
+
+               if (!cfg->bblocks [i].reached) /* unreachable code */
+                       continue;
+
+               top = forest->len;
 
                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 *s, MBTree *tree
+tree_emit (int goal, MonoFlowGraph *cfg, MBTree *tree, int *spillcount
 {
        MBTree *kids[10];
-       int i, ern = mono_burg_rule (tree->state, goal);
-       guint16 *nts = mono_burg_nts [ern];
+       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], s, 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 = s->code - s->start;
+       tree->addr = offset = cfg->code - cfg->start;
+
+       /* 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;
+               mono_jit_stats.code_reallocs++;
+               cfg->start = g_realloc (cfg->start, cfg->code_size);
+               g_assert (cfg->start);
+               cfg->code = cfg->start + offset;
+       }
 
        if ((emit = mono_burg_func [ern]))
-               emit (tree, s);
+               emit (tree, cfg);
+
+       g_assert ((cfg->code - cfg->start) < cfg->code_size);
 }
 
 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];
                GPtrArray *forest = bb->forest;
-               const int top = forest->len;
+               int top;
+
+               if (!bb->reached) /* unreachable code */
+                       continue;
+               
+               top = forest->len;
 
                bb->addr = cfg->code - cfg->start;
          
                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);
                }
        }
                
@@ -685,6 +1145,7 @@ mono_emit_cfg (MonoFlowGraph *cfg)
 static void
 mono_compute_branches (MonoFlowGraph *cfg)
 {
+       MonoJumpInfo *ji;
        guint8 *end;
        int i, j;
 
@@ -693,450 +1154,146 @@ mono_compute_branches (MonoFlowGraph *cfg)
        for (j = 0; j < cfg->block_count; j++) {
                MonoBBlock *bb = &cfg->bblocks [j];
                GPtrArray *forest = bb->forest;
-               const int top = forest->len;
+               int top;
+               
+               if (!bb->reached) /* unreachable code */
+                       continue;
+
+               top = forest->len;
        
                for (i = 0; i < top; i++) {
                        MBTree *t1 = (MBTree *) g_ptr_array_index (forest, i);
 
-                       if (t1->is_jump) {
-
-                               if (t1->op == MB_TERM_SWITCH) {
-                                       MonoBBlock **jt = (MonoBBlock **)t1->data.p;
-                                       guint32 *rt = (guint32 *)t1->data.p;
-
-                                       int m = *((guint32 *)t1->data.p) + 1;
-                                       int j;
-                                       
-                                       for (j = 1; j <= m; j++)
-                                               rt [j] = (int)(jt [j]->addr + cfg->start);
-                               }
-
-                               /* emit the jump instruction again to update addresses */
+                       if (t1->op == MB_TERM_SWITCH) {
+                               MonoBBlock **jt = (MonoBBlock **)t1->data.p;
+                               guint32 *rt = (guint32 *)t1->data.p;
+                               int m = *((guint32 *)t1->data.p) + 1;
+                               int k;
+                               
+                               for (k = 1; k <= m; k++)
+                                       rt [k] = (int)(jt [k]->addr + cfg->start);
+                               
+                               /* emit the switch instruction again to update addresses */
                                cfg->code = cfg->start + t1->addr;
                                ((MBEmitFunc)t1->emit) (t1, cfg);
-
                        }
                }
        }
 
        cfg->code = end;
-}
-
-static int
-match_debug_method (MonoMethod* method)
-{
-       GList *tmp = mono_debug_methods;
-
-       for (; tmp; tmp = tmp->next) {
-               if (strcmp (method->name, tmp->data) == 0) {
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/**
- * arch_compile_method:
- * @method: pointer to the method info
- *
- * JIT compilation of a single method. This method also writes the result 
- * back to method->addr, an thus overwrites the trampoline function.
- *
- * Returns: a pointer to the newly created code.
- */
-gpointer
-arch_compile_method (MonoMethod *method)
-{
-       MonoFlowGraph *cfg;
-       MonoMemPool *mp = mono_mempool_new ();
-
-       g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL));
-       g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
-
-       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) {
-               MonoClassField *field;
-               const char *name = method->name;
-               static guint target_offset = 0;
-               static guint method_offset = 0;
-               guint8 *code;
-               gboolean delegate = FALSE;
-
-               if (method->klass->parent && 
-                   method->klass->parent->parent == mono_defaults.delegate_class)
-                       delegate = TRUE;
-                               
-               if (!target_offset) {
-                       mono_class_init (mono_defaults.delegate_class);
-
-                       field = mono_class_get_field_from_name (mono_defaults.delegate_class, "m_target");
-                       target_offset = field->offset;
-                       field = mono_class_get_field_from_name (mono_defaults.delegate_class, "method_ptr");
-                       method_offset = field->offset;
-               }
-               
-               if (delegate && *name == '.' && (strcmp (name, ".ctor") == 0)) {
-                       method->addr = code = g_malloc (32);
-                       x86_push_reg (code, X86_EBP);
-                       x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
-                       
-                       /* load the this pointer */
-                       x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4); 
-                       /* load m_target arg */
-                       x86_mov_reg_membase (code, X86_EDX, X86_EBP, 12, 4);
-                       /* store mtarget */
-                       x86_mov_membase_reg (code, X86_EAX, target_offset, X86_EDX, 4); 
-                       /* load method_ptr arg */
-                       x86_mov_reg_membase (code, X86_EDX, X86_EBP, 16, 4);
-                       /* store method_ptr */
-                       x86_mov_membase_reg (code, X86_EAX, method_offset, X86_EDX, 4); 
-
-                       x86_leave (code);
-                       x86_ret (code);
-
-                       g_assert ((code - (guint8*)method->addr) < 32);
-
-               } else if (delegate && *name == 'I' && (strcmp (name, "Invoke") == 0)) {
-                       MonoMethodSignature *csig = method->signature;
-                       int i, target, this_pos = 4;
-                       guint8 *source;
-
-                       method->addr = g_malloc (32);
-
-                       if (csig->ret->type == MONO_TYPE_VALUETYPE) {
-                               g_assert (!csig->ret->byref);
-                               this_pos = 8;
-                       }
-
-                       for (i = 0; i < 2; i ++) {
-                               code = method->addr;
-                               /* load the this pointer */
-                               x86_mov_reg_membase (code, X86_EAX, X86_ESP, this_pos, 4);
-                               /* load mtarget */
-                               x86_mov_reg_membase (code, X86_EDX, X86_EAX, target_offset, 4); 
-                               /* check if zero (static method call without this pointer) */
-                               x86_alu_reg_imm (code, X86_CMP, X86_EDX, 0);
-                               x86_branch32 (code, X86_CC_EQ, target, TRUE); 
-                               source = code;
-                               
-                               /* virtual call -  we have to replace the this pointer */
-                               x86_mov_membase_reg (code, X86_ESP, this_pos, X86_EDX, 4); 
-
-                               /* jump to method_ptr() */
-                               target = code - source;
-                               x86_jump_membase (code, X86_EAX, method_offset);
-                       }
-
-                       g_assert ((code - (guint8*)method->addr) < 32);
-
-               } else {
-                       if (mono_debug_handle)
-                               return NULL;
-                       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;
-               MonoJitInfo *ji = g_new0 (MonoJitInfo, 1);
 
-               cfg = mono_cfg_new (method, mp);
+       for (ji = cfg->jump_info; ji; ji = ji->next) {
+               unsigned char *ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ji->ip) + cfg->start);
+               unsigned char *target;
 
-               mono_analyze_flow (cfg);
-               if (cfg->invalid)
-                       return NULL;
-
-               mono_analyze_stack (cfg);
-               if (cfg->invalid)
-                       return NULL;
-       
-               cfg->code = NULL;
-               cfg->rs = mono_regset_new (X86_NREG);
-               mono_regset_reserve_reg (cfg->rs, X86_ESP);
-               mono_regset_reserve_reg (cfg->rs, X86_EBP);
-
-               // fixme: remove limitation to 8192 bytes
-               ji->code_size = 8192*2;
-               method->addr = cfg->start = cfg->code = g_malloc (ji->code_size);
-               
-               if (match_debug_method (method))
-                       x86_breakpoint (cfg->code);
-
-               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);
-                       }
-               }
-       
-               mono_label_cfg (cfg);
-               if (cfg->invalid)
-                       return NULL;
-
-               arch_allocate_regs (cfg);
-
-               /* align to 8 byte boundary */
-               cfg->locals_size += 7;
-               cfg->locals_size &= ~7;
-
-               arch_emit_prologue (cfg);
-
-               mono_emit_cfg (cfg);
-
-               arch_emit_epilogue (cfg);
-
-               g_assert ((cfg->code - cfg->start) < ji->code_size);
-
-               mono_compute_branches (cfg);
-               
-               if (mono_jit_dump_asm)
-                       mono_disassemble_code (cfg->start, cfg->code - cfg->start);
-
-               if (mono_debug_handle)
-                       mono_debug_add_method (mono_debug_handle, cfg);
-
-               ji->used_regs = cfg->rs->used_mask;
-               ji->method = method;
-               ji->code_start = method->addr;
-               mono_jit_info_table_add (mono_jit_info_table, ji);
-
-               if (header->num_clauses) {
-                       int i, start_block, end_block;
-
-                       ji->num_clauses = header->num_clauses;
-                       ji->clauses = g_new0 (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);
-                       }
+               switch (ji->type) {
+               case MONO_JUMP_INFO_BB:
+                       target = ji->data.bb->addr + cfg->start;
+                       break;
+               case MONO_JUMP_INFO_ABS:
+                       target = ji->data.target;
+                       break;
+               case MONO_JUMP_INFO_EPILOG:
+                       target = cfg->epilog + cfg->start;
+                       break;
+               case MONO_JUMP_INFO_IP:
+                       *(unsigned char**)ip = ip;
+                       continue;
+               default:
+                       g_assert_not_reached ();
                }
-               
-               mono_regset_free (cfg->rs);
-
-               mono_cfg_free (cfg);
-
-               mono_mempool_destroy (mp);
-
+               x86_patch (ip, target);
        }
 
-       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, method->addr);
+       /* patch the IP in the LMF saving code */
+       if (cfg->lmfip_offset) {
+               *((guint32 *)(cfg->start + cfg->lmfip_offset)) =  
+                       (gint32)(cfg->start + cfg->lmfip_offset);
        }
-
-
-       return method->addr;
 }
 
-/*
- * arch_get_restore_context:
- *
- * Returns a pointer to a method which restores a previously saved sigcontext.
- */
-static gpointer
-arch_get_restore_context ()
+void
+mono_add_jump_info (MonoFlowGraph *cfg, gpointer ip, MonoJumpInfoType type, gpointer target)
 {
-       static guint8 *start = NULL;
-       guint8 *code;
-
-       if (start)
-               return start;
+       MonoJumpInfo *ji = mono_mempool_alloc (cfg->mp, sizeof (MonoJumpInfo));
 
-       /* restore_contect (struct sigcontext *ctx) */
-       /* we do not restore X86_EAX, X86_EDX */
+       ji->type = type;
+       ji->ip = GUINT_TO_POINTER (GPOINTER_TO_UINT (ip) - GPOINTER_TO_UINT (cfg->start));
+       ji->data.target = target;
+       ji->next = cfg->jump_info;
 
-       start = code = malloc (1024);
-       
-       /* load ctx */
-       x86_mov_reg_membase (code, X86_EAX, X86_ESP, 4, 4);
-
-       /* get return address, stored in EDX */
-       x86_mov_reg_membase (code, X86_EDX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, eip), 4);
-
-       /* restore EBX */
-       x86_mov_reg_membase (code, X86_EBX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebx), 4);
-       /* restore EDI */
-       x86_mov_reg_membase (code, X86_EDI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, edi), 4);
-       /* restore ESI */
-       x86_mov_reg_membase (code, X86_ESI, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, esi), 4);
-       /* restore ESP */
-       x86_mov_reg_membase (code, X86_ESP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, esp), 4);
-       /* restore EBP */
-       x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
-       /* restore ECX. the exception object is passed here to the catch handler */
-       x86_mov_reg_membase (code, X86_ECX, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ecx), 4);
-
-       /* jump to the saved IP */
-       x86_jump_reg (code, X86_EDX);
-
-       return start;
+       cfg->jump_info = ji;
 }
 
-/*
- * arch_get_call_finally:
- *
- * Returns a pointer to a method which calls a finally handler.
- */
-static gpointer
-arch_get_call_finally ()
-{
-       static guint8 *start = NULL;
-       guint8 *code;
-
-       if (start)
-               return start;
-
-       /* call_finally (struct sigcontext *ctx, unsigned long eip) */
-       start = code = malloc (1024);
-
-       x86_push_reg (code, X86_EBP);
-       x86_mov_reg_reg (code, X86_EBP, X86_ESP, 4);
-       x86_push_reg (code, X86_EBX);
-       x86_push_reg (code, X86_EDI);
-       x86_push_reg (code, X86_ESI);
-
-       /* load ctx */
-       x86_mov_reg_membase (code, X86_EAX, X86_EBP, 8, 4);
-       /* load eip */
-       x86_mov_reg_membase (code, X86_ECX, X86_EBP, 12, 4);
-       /* save EBP */
-       x86_push_reg (code, X86_EBP);
-       /* set new EBP */
-       x86_mov_reg_membase (code, X86_EBP, X86_EAX,  G_STRUCT_OFFSET (struct sigcontext, ebp), 4);
-       /* call the handler */
-       x86_call_reg (code, X86_ECX);
-       /* restore EBP */
-       x86_pop_reg (code, X86_EBP);
-       /* restore saved regs */
-       x86_pop_reg (code, X86_ESI);
-       x86_pop_reg (code, X86_EDI);
-       x86_pop_reg (code, X86_EBX);
-       x86_leave (code);
-       x86_ret (code);
-
-       return start;
-}
-
-/**
- * arch_handle_exception:
- * @ctx: saved processor state
- * @obj:
- */
-void
-arch_handle_exception (struct sigcontext *ctx, gpointer obj)
+MonoJitInfo *
+arch_jit_compile_cfg (MonoDomain *target_domain, MonoFlowGraph *cfg)
 {
        MonoJitInfo *ji;
-       gpointer ip = (gpointer)ctx->eip;
-       static void (*restore_context) (struct sigcontext *);
-       static void (*call_finally) (struct sigcontext *, unsigned long);
-
-       ji = mono_jit_info_table_find (mono_jit_info_table, ip);
-
-       if (!restore_context)
-               restore_context = arch_get_restore_context ();
-       
-       if (!call_finally)
-               call_finally = arch_get_call_finally ();
-
-       if (ji) { /* we are inside managed code */
-               MonoMethod *m = ji->method;
-               unsigned next_bp, next_ip;
-               int offset = 2;
+       guint32 ls_used_mask = 0;
+       MonoMethod *method = cfg->method;
+       int offset, gap;
 
-               if (ji->num_clauses) {
-                       int i;
-
-                       g_assert (ji->clauses);
-                       
-                       for (i = 0; i < ji->num_clauses; i++) {
-                               MonoJitExceptionInfo *ei = &ji->clauses [i];
-
-                               if (ei->try_start <= ip && ip <= (ei->try_end)) { 
-                                       /* catch block */
-                                       if (ei->flags == 0 && mono_object_isinst (obj, 
-                                               mono_class_get (m->klass->image, ei->token_or_filter))) {
-                                       
-                                               ctx->eip = (unsigned long)ei->handler_start;
-                                               ctx->ecx = (unsigned long)obj;
-                                               restore_context (ctx);
-                                               g_assert_not_reached ();
-                                       }
-                               }
-                       }
-
-                       /* no handler found - we need to call all finally handlers */
-                       for (i = 0; i < ji->num_clauses; i++) {
-                               MonoJitExceptionInfo *ei = &ji->clauses [i];
-
-                               if (ei->try_start <= ip && ip < (ei->try_end) &&
-                                   (ei->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
-                                       call_finally (ctx, (unsigned long)ei->handler_start);
-                               }
-                       }
-               }
-
-               /* continue unwinding */
-
-               /* restore caller saved registers */
-               if (ji->used_regs & X86_ESI_MASK) {
-                       ctx->esi = *((int *)ctx->ebp + offset);
-                       offset++;
-               }
-               if (ji->used_regs & X86_EDI_MASK) {
-                       ctx->edi = *((int *)ctx->ebp + offset);
-                       offset++;
-               }
-               if (ji->used_regs & X86_EBX_MASK) {
-                       ctx->ebx = *((int *)ctx->ebp + offset);
-               }
-
-               ctx->esp = ctx->ebp;
-
-               next_bp = *((int *)ctx->ebp);
-               next_ip = *((int *)ctx->ebp + 1);
+       ji = mono_mempool_alloc0 (target_domain->mp, sizeof (MonoJitInfo));
                
-               if (next_bp < (unsigned)mono_end_of_stack) {
+       cfg->rs = mono_regset_new (X86_NREG);
+       mono_regset_reserve_reg (cfg->rs, X86_ESP);
+       mono_regset_reserve_reg (cfg->rs, X86_EBP);
 
-                       ctx->eip = next_ip;
-                       ctx->ebp = next_bp;
-                       arch_handle_exception (ctx, obj);
+       /* 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);
 
-               } else {
-                       mono_jit_abort (obj);
+       if (mono_use_linear_scan) {
+               mono_linear_scan (cfg, &ls_used_mask);
+               cfg->rs->used_mask |= ls_used_mask;
+       }
+       
+       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);
                }
-
-       } else {
-               /* fixme: implement exceptions inside unmanaged code */
-               mono_jit_abort (obj);
+       }
+                       
+       if (!mono_label_cfg (cfg))
+               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;
+
+       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;
        }
 
-       g_assert_not_reached ();
-}
+       mono_compute_branches (cfg);
 
+       ji->code_size = cfg->code - cfg->start;
+       ji->used_regs = cfg->rs->used_mask;
+       ji->method = method;
+       ji->code_start = cfg->start;
 
+       return ji;
+}