2002-05-16 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / jit / jit.c
index 4ce4d0d3677ce03477e2b7fd5ce517ffaf48ddbf..0cf36d3e6be55f8944a7282c95cd9b35c1f47221 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * testjit.c: The mono JIT compiler.
+ * jit.c: The mono JIT compiler.
  *
  * Author:
  *   Dietmar Maurer (dietmar@ximian.com)
 #include <mono/metadata/appdomain.h>
 #include <mono/arch/x86/x86-codegen.h>
 #include <mono/io-layer/io-layer.h>
+#include <mono/io-layer/threads.h>
 
 #include "jit.h"
 #include "regset.h"
 #include "codegen.h"
 #include "debug.h"
-#include "message.h"
 
-/*
- * Pull the list of opcodes
- */
-#define OPDEF(a,b,c,d,e,f,g,h,i,j) \
-       a = i,
+/* 
+ * if OPT_BOOL is defined we use 32bit to store boolean local variables.  This
+ * gives great speedup for boolean expressions, but unfortunately it changes
+ * semantics, so i disable it until we have a real solution  */
+/* #define OPT_BOOL */
 
-enum {
-#include "mono/cil/opcode.def"
-       LAST = 0xff
-};
-#undef OPDEF
+/* this is x86 specific */
+#define MB_TERM_LDIND_REF MB_TERM_LDIND_I4
+#define MB_TERM_LDIND_U4 MB_TERM_LDIND_I4
+#define MB_TERM_STIND_REF MB_TERM_STIND_I4
+#define MB_TERM_REMOTE_STIND_REF MB_TERM_REMOTE_STIND_I4
 
 #define SET_VARINFO(vi,t,k,o,s) do { vi.type=t; vi.kind=k; vi.offset=o; vi.size=s; } while (0)
 
@@ -61,7 +61,8 @@ case CEE_##name##_S: {                                                        \
        int near_jump = *ip == CEE_##name##_S;                                \
        ++ip;                                                                 \
        sp -= 2;                                                              \
-       t1 = mono_ctree_new (mp, MB_TERM_##name, sp [0], sp [1]);             \
+        t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]);            \
+       t1 = mono_ctree_new (mp, MB_TERM_CBRANCH, t1, NULL);                  \
        if (near_jump)                                                        \
                target = cli_addr + 2 + (signed char) *ip;                    \
        else                                                                  \
@@ -71,7 +72,8 @@ case CEE_##name##_S: {                                                        \
        tbb = &cfg->bblocks [bcinfo [target].block_id];                       \
        create_outstack (cfg, bb, stack, sp - stack);                         \
        mark_reached (cfg, tbb, bb->outstack, bb->outdepth);                  \
-       t1->data.p = tbb;                                                     \
+       t1->data.bi.target = tbb;                                             \
+       t1->data.bi.cond = CEE_##name;                                        \
        ADD_TREE (t1, cli_addr);                                              \
        ip += near_jump ? 1: 4;                                               \
        break;                                                                \
@@ -90,7 +92,9 @@ case CEE_##name: {                                                            \
 case CEE_##cname: {                                                           \
        ++ip;                                                                 \
        sp -= 2;                                                              \
-       t1 = mono_ctree_new (mp, MB_TERM_##cname, sp [0], sp [1]);            \
+       t1 = mono_ctree_new (mp, MB_TERM_COMPARE, sp [0], sp [1]);            \
+       t1 = mono_ctree_new (mp, MB_TERM_CSET, t1, NULL);                     \
+        t1->data.i = CEE_##cname;                                             \
        PUSH_TREE (t1, VAL_I32);                                              \
        break;                                                                \
 }
@@ -179,6 +183,13 @@ case CEE_##name: {                                                            \
        ADD_TREE (t1, cli_addr);                                              \
        break;                                                                \
 }
+
+typedef struct {
+       MonoMethod *method;
+       MBTree **arg_map;
+       const unsigned char *end, *saved_ip;
+       MonoImage *saved_image;
+} MonoInlineInfo;
        
 /* Whether to dump the assembly code after genreating it */
 gboolean mono_jit_dump_asm = FALSE;
@@ -189,12 +200,27 @@ gboolean mono_jit_dump_forest = FALSE;
 /* Whether to print function call traces */
 gboolean mono_jit_trace_calls = FALSE;
 
+/* Whether to insert in the code profile callbacks */
+gboolean mono_jit_profile = FALSE;
+
 /* Force jit to share code between application domains */
 gboolean mono_jit_share_code = FALSE;
 
+/* use linear scan register allocation */
+gboolean mono_use_linear_scan = TRUE;
+
+/* inline code */
+gboolean mono_jit_inline_code = TRUE;
+
+/* Use alternative (faster) sequence to convert FP values to integers */
+gboolean mono_use_fast_iconv = FALSE;
+
 /* maximum number of worker threads */
 int mono_worker_threads = 1;
 
+/* TLS id to store jit data */
+guint32  mono_jit_tls_id;
+
 MonoDebugHandle *mono_debug_handle = NULL;
 GList *mono_debug_methods = NULL;
 
@@ -206,17 +232,6 @@ int mono_debug_insert_breakpoint = 0;
 /* This is the address of the last breakpoint which was inserted. */
 gchar *mono_debug_last_breakpoint_address = NULL;
 
-gpointer mono_end_of_stack = NULL;
-
-/* last managed frame (used by pinvoke) */ 
-guint32 lmf_thread_id = 0;
-
-/* used to store a function pointer called after uncatched exceptions */ 
-guint32 exc_cleanup_id = 0;
-
-/* stores a pointer to async result used by exceptions */ 
-guint32 async_result_id = 0;
-
 MonoJitStats mono_jit_stats;
 
 CRITICAL_SECTION *metadata_section = NULL;
@@ -238,37 +253,6 @@ mono_alloc_static0 (int size)
 
 typedef void (*MonoCCtor) (void);
 
-/**
- * runtime_class_init:
- * @klass: the class to initialise
- *
- * Initialise the class @klass by calling the class constructor.
- */
-static void
-runtime_class_init (MonoClass *klass)
-{
-       MonoCCtor cctor;
-       MonoMethod *method;
-       int i;
-
-       if (mono_debug_handle)
-               mono_debug_add_type (mono_debug_handle, klass);
-       
-       for (i = 0; i < klass->method.count; ++i) {
-               method = klass->methods [i];
-               if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
-                   (strcmp (".cctor", method->name) == 0)) {
-       
-                       cctor = arch_compile_method (method);
-                       if (!cctor && mono_debug_handle)
-                               return;
-                       g_assert (cctor != NULL);
-                       cctor ();
-                       return;
-               }
-       }
-       /* No class constructor found */
-}
 
 static int
 map_store_svt_type (int svt)
@@ -343,6 +327,61 @@ map_stind_type (MonoType *type)
        return -1;
 }
 
+/**
+ * map_remote_stind_type:
+ * @type: the type to map
+ *
+ * Translates the MonoType @type into the corresponding remote store opcode 
+ * for the code generator.
+ */
+static int
+map_remote_stind_type (MonoType *type)
+{
+       if (type->byref) {
+               return MB_TERM_REMOTE_STIND_REF;
+       }
+
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+               return MB_TERM_REMOTE_STIND_I1; 
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
+               return MB_TERM_REMOTE_STIND_I2; 
+       case MONO_TYPE_I:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+               return MB_TERM_REMOTE_STIND_I4; 
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_PTR:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_ARRAY:    
+               return MB_TERM_REMOTE_STIND_REF;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               return MB_TERM_REMOTE_STIND_I8;
+       case MONO_TYPE_R4:
+               return MB_TERM_REMOTE_STIND_R4;
+       case MONO_TYPE_R8:
+               return MB_TERM_REMOTE_STIND_R8;
+       case MONO_TYPE_VALUETYPE: 
+               if (type->data.klass->enumtype)
+                       return map_remote_stind_type (type->data.klass->enum_basetype);
+               else
+                       return MB_TERM_REMOTE_STIND_OBJ;
+       default:
+               g_warning ("unknown type %02x", type->type);
+               g_assert_not_reached ();
+       }
+
+       g_assert_not_reached ();
+       return -1;
+}
+
 static int
 map_starg_type (MonoType *type)
 {
@@ -622,7 +661,7 @@ map_call_type (MonoType *type, MonoValueType *svt)
  * prints the tree to stdout
  */
 void
-mono_print_ctree (MBTree *tree)
+mono_print_ctree (MonoFlowGraph *cfg, MBTree *tree)
 {
        int arity;
 
@@ -637,15 +676,21 @@ mono_print_ctree (MBTree *tree)
                printf (" %s", mono_burg_term_string [tree->op]);
 
        switch (tree->op) {
-       case MB_TERM_ADDR_L:
+       case MB_TERM_CONST_I4:
                printf ("[%d]", tree->data.i);
                break;
+       case MB_TERM_ADDR_L:
+               if (VARINFO (cfg, tree->data.i).reg >= 0)
+                       printf ("[R%d]", tree->data.i);
+               else
+                       printf ("[%d]", tree->data.i);
+               break;
        }
 
        g_assert (!(tree->right && !tree->left));
 
-       mono_print_ctree (tree->left);
-       mono_print_ctree (tree->right);
+       mono_print_ctree (cfg, tree->left);
+       mono_print_ctree (cfg, tree->right);
 
        if (arity)
                printf (")");
@@ -655,7 +700,7 @@ mono_print_ctree (MBTree *tree)
  * prints the whole forest to stdout
  */
 void
-mono_print_forest (GPtrArray *forest)
+mono_print_forest (MonoFlowGraph *cfg, GPtrArray *forest)
 {
        const int top = forest->len;
        int i;
@@ -663,7 +708,7 @@ mono_print_forest (GPtrArray *forest)
        for (i = 0; i < top; i++) {
                MBTree *t = (MBTree *) g_ptr_array_index (forest, i);
                printf ("       ");
-               mono_print_ctree (t);
+               mono_print_ctree (cfg, t);
                printf ("\n");
        }
 
@@ -695,13 +740,23 @@ mono_disassemble_code (guint8 *code, int size, char *id)
        system ("as /tmp/test.s -o /tmp/test.o;objdump -d /tmp/test.o"); 
 }
 
-static int
+int
 arch_allocate_var (MonoFlowGraph *cfg, int size, int align, MonoValueKind kind, MonoValueType type)
 {
        MonoVarInfo vi;
 
        mono_jit_stats.allocate_var++;
 
+       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;
+
+       if (size != sizeof (gpointer))
+               vi.isvolatile = 1;
+       
        switch (kind) {
        case MONO_TEMPVAR:
        case MONO_LOCALVAR: {
@@ -895,23 +950,12 @@ ctree_create_dup (MonoMemPool *mp, MBTree *s)
                t = mono_ctree_new (mp, MB_TERM_LDIND_I2, t, NULL);
                t->svt = VAL_I32;
                break;
-       case MB_TERM_STIND_REF:
-       case MB_TERM_LDIND_REF:
-               t = ctree_dup_address (mp, s->left);
-               t = mono_ctree_new (mp, MB_TERM_LDIND_REF, t, NULL);
-               t->svt = VAL_POINTER;
-               break;
        case MB_TERM_STIND_I4:
        case MB_TERM_LDIND_I4:
                t = ctree_dup_address (mp, s->left);
                t = mono_ctree_new (mp, MB_TERM_LDIND_I4, t, NULL);
                t->svt = VAL_I32;
                break;
-       case MB_TERM_LDIND_U4:
-               t = ctree_dup_address (mp, s->left);
-               t = mono_ctree_new (mp, MB_TERM_LDIND_U4, t, NULL);
-               t->svt = VAL_I32;
-               break;
        case MB_TERM_STIND_I8:
        case MB_TERM_LDIND_I8:
                t = ctree_dup_address (mp, s->left);
@@ -952,8 +996,6 @@ mono_store_tree (MonoFlowGraph *cfg, int slot, MBTree *s, MBTree **tdup)
        case MB_TERM_LDIND_I2:
        case MB_TERM_STIND_I4:
        case MB_TERM_LDIND_I4:
-       case MB_TERM_STIND_REF:
-       case MB_TERM_LDIND_REF:
        case MB_TERM_STIND_I8:
        case MB_TERM_LDIND_I8:
        case MB_TERM_STIND_R4:
@@ -1014,6 +1056,10 @@ mono_cfg_new (MonoMethod *method, MonoMemPool *mp)
        cfg->method = method;
        cfg->mp = mp;
 
+       /* reserve space for caller saved registers */
+       /* fixme: this is arch dependent */
+       cfg->locals_size = 12;
+
        /* fixme: we should also consider loader optimisation attributes */
        cfg->share_code = mono_jit_share_code;
 
@@ -1036,6 +1082,7 @@ mono_cfg_free (MonoFlowGraph *cfg)
                if (!cfg->bblocks [i].reached)
                        continue;
                g_ptr_array_free (cfg->bblocks [i].forest, TRUE);
+               g_list_free (cfg->bblocks [i].succ);
        }
 
        if (cfg->bcinfo)
@@ -1043,35 +1090,12 @@ mono_cfg_free (MonoFlowGraph *cfg)
 
        if (cfg->bblocks)
                g_free (cfg->bblocks);
-
+               
        g_array_free (cfg->varinfo, TRUE);
 }
 
-
-static void
-runtime_object_init (MonoObject *obj)
-{
-       MonoClass *klass = obj->vtable->klass;
-       MonoMethod *method = NULL;
-       void (*ctor) (gpointer this);
-       int i;
-
-       for (i = 0; i < klass->method.count; ++i) {
-               if (!strcmp (".ctor", klass->methods [i]->name) &&
-                   klass->methods [i]->signature->param_count == 0) {
-                       method = klass->methods [i];
-                       break;
-               }
-       }
-
-       g_assert (method);
-
-       ctor = arch_compile_method (method);
-       ctor (obj);
-}
-
 static MonoBBlock *
-mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, int type)
+mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, guint32 target, int type)
 {
        MonoMethod *method = cfg->method;
        MonoBytecodeInfo *bcinfo = cfg->bcinfo;
@@ -1081,20 +1105,39 @@ mono_find_final_block (MonoFlowGraph *cfg, guint32 ip, int type)
 
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
-               if (MONO_OFFSET_IN_HANDLER (clause, ip))
-                       continue;
 
-               if (MONO_OFFSET_IN_CLAUSE (clause, ip)) {
+               if (MONO_OFFSET_IN_CLAUSE (clause, ip) && 
+                   (!MONO_OFFSET_IN_CLAUSE (clause, target))) {
                        if (clause->flags & type) {
                                g_assert (bcinfo [clause->handler_offset].is_block_start);
                                return &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
-                       } else
-                               return NULL;
+                       }
                }
        }
        return NULL;
 }
 
+static void
+mono_cfg_add_successor (MonoFlowGraph *cfg, MonoBBlock *bb, gint32 target)
+{
+       MonoBBlock *tbb;
+       GList *l;
+
+       g_assert (cfg->bcinfo [target].is_block_start);
+
+       tbb = &cfg->bblocks [cfg->bcinfo [target].block_id];
+       g_assert (tbb);
+
+       for (l = bb->succ; l; l = l->next) {
+               MonoBBlock *t = (MonoBBlock *)l->data;
+               if (t == tbb)
+                       return;
+       }
+
+       bb->succ = g_list_prepend (bb->succ, tbb);
+}
+
+
 #define CREATE_BLOCK(t) {if (!bcinfo [t].is_block_start) {block_count++;bcinfo [t].is_block_start = 1; }}
 
 void
@@ -1192,6 +1235,7 @@ mono_analyze_flow (MonoFlowGraph *cfg)
                        ip++;
                        CREATE_BLOCK (cli_addr + 2 + i);
                        block_end = 1;
+                      
                        break;
                case MonoInlineBrTarget:
                        ip++;
@@ -1238,6 +1282,8 @@ mono_analyze_flow (MonoFlowGraph *cfg)
        for (i = 0; i < header->code_size; i++) {
                if (bcinfo [i].is_block_start) {
                        bb->cli_addr = i;
+                       bb->num = block_count;
+                       bb->forest = g_ptr_array_new ();
                        if (block_count)
                                bb [-1].length = i - bb [-1].cli_addr; 
                        bcinfo [i].block_id = block_count;
@@ -1250,6 +1296,100 @@ mono_analyze_flow (MonoFlowGraph *cfg)
        cfg->bcinfo = bcinfo;
        cfg->bblocks = bblocks;
        cfg->block_count = block_count;
+       
+       for (i = 0; i < header->num_clauses; ++i) {
+               MonoBBlock *sbb, *tbb;
+               clause = &header->clauses [i];
+               sbb = &cfg->bblocks [bcinfo [clause->try_offset].block_id];
+               tbb = &cfg->bblocks [bcinfo [clause->handler_offset].block_id];
+               g_assert (sbb && tbb);
+               sbb->succ = g_list_prepend (sbb->succ, tbb);
+       }
+
+       ip = header->code;
+       end = ip + header->code_size;
+       bb = NULL;
+
+       while (ip < end) {
+               guint32 cli_addr = ip - header->code;
+
+               if (bcinfo [cli_addr].is_block_start) {
+                       MonoBBlock *tbb = &cfg->bblocks [bcinfo [cli_addr].block_id];           
+                       if (bb && !bb->succ)
+                               bb->succ = g_list_prepend (bb->succ, tbb);
+                       bb = tbb;
+               }
+               g_assert (bb);
+
+               if (*ip == 0xfe) {
+                       ++ip;
+                       i = *ip + 256;
+               } else {
+                       i = *ip;
+               }
+
+               opcode = &mono_opcodes [i];
+
+               switch (opcode->argument) {
+               case MonoInlineNone:
+                       ++ip;
+                       break;
+               case MonoInlineString:
+               case MonoInlineType:
+               case MonoInlineField:
+               case MonoInlineMethod:
+               case MonoInlineTok:
+               case MonoInlineSig:
+               case MonoShortInlineR:
+               case MonoInlineI:
+                       ip += 5;
+                       break;
+               case MonoInlineVar:
+                       ip += 3;
+                       break;
+               case MonoShortInlineVar:
+               case MonoShortInlineI:
+                       ip += 2;
+                       break;
+               case MonoShortInlineBrTarget:
+                       ip++;
+                       i = (signed char)*ip;
+                       ip++;
+                       mono_cfg_add_successor (cfg, bb, cli_addr + 2 + i);
+                       if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
+                               mono_cfg_add_successor (cfg, bb, cli_addr + 2);
+                       break;
+               case MonoInlineBrTarget:
+                       ip++;
+                       i = read32 (ip);
+                       ip += 4;
+                       mono_cfg_add_successor (cfg, bb, cli_addr + 5 + i);
+                       if (opcode->flow_type == MONO_FLOW_COND_BRANCH)
+                               mono_cfg_add_successor (cfg, bb, cli_addr + 5);
+                       break;
+               case MonoInlineSwitch: {
+                       gint32 st, target, n;
+                       ++ip;
+                       n = read32 (ip);
+                       ip += 4;
+                       st = cli_addr + 5 + 4 * n;
+                       mono_cfg_add_successor (cfg, bb, st);
+
+                       for (i = 0; i < n; i++) {
+                               target = read32 (ip) + st;
+                               ip += 4;
+                               mono_cfg_add_successor (cfg, bb, target);
+                       }
+                       break;
+               }
+               case MonoInlineR:
+               case MonoInlineI8:
+                       ip += 9;
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+       }
 }
 
 /**
@@ -1272,10 +1412,13 @@ ves_array_element_address (MonoArray *this, ...)
 
        class = this->obj.vtable->klass;
 
-       ind = va_arg(ap, int) - this->bounds [0].lower_bound;
-       for (i = 1; i < class->rank; i++) {
-               ind = ind*this->bounds [i].length + va_arg(ap, int) -
-                       this->bounds [i].lower_bound;;
+       ind = va_arg(ap, int);
+       if (this->bounds != NULL) {
+               ind -= this->bounds [0].lower_bound;
+               for (i = 1; i < class->rank; i++) {
+                       ind = ind*this->bounds [i].length + va_arg(ap, int) -
+                               this->bounds [i].lower_bound;;
+               }
        }
 
        esize = mono_array_element_size (class);
@@ -1322,12 +1465,362 @@ mono_array_new_va (MonoMethod *cm, ...)
 #define PUSH_TREE(t,k)  do { int tt = k; *sp = t; t->svt = tt; sp++; } while (0)
 
 #define LOCAL_POS(n)    (1 + n)
+
+#ifdef OPT_BOOL
+#define LOCAL_TYPE(n)   ((header)->locals [(n)]->type == MONO_TYPE_BOOLEAN && !(header)->locals [(n)]->byref ? &mono_defaults.int32_class->byval_arg : (header)->locals [(n)])
+#else
 #define LOCAL_TYPE(n)   ((header)->locals [(n)])
+#endif
 
 #define ARG_POS(n)      (firstarg + n)
 #define ARG_TYPE(n)     ((n) ? (signature)->params [(n) - (signature)->hasthis] : \
                        (signature)->hasthis ? &method->klass->this_arg: (signature)->params [(0)])
 
+
+/*
+ * replaces all occurences of variable @varnum in @tree with @copy. 
+ */
+static void
+mono_copy_used_var (MonoFlowGraph *cfg, MBTree *tree, int varnum, MBTree **copy)
+{
+       MBTree *t1, *t2;
+       int v, size, align;
+
+       if (tree->left)
+               mono_copy_used_var (cfg, tree->left, varnum, copy);
+       if (tree->right)
+               mono_copy_used_var (cfg, tree->right, varnum, copy);
+
+       switch (tree->op) {
+       case MB_TERM_LDIND_I1:
+       case MB_TERM_LDIND_I2:
+       case MB_TERM_LDIND_I4:
+       case MB_TERM_LDIND_I8:
+       case MB_TERM_LDIND_R4:
+       case MB_TERM_LDIND_R8:
+               if (tree->left->op == MB_TERM_ADDR_L &&
+                   tree->left->data.i == varnum) {
+                       if (*copy) {
+                               tree->left->data.i = (*copy)->left->data.i;
+                               return;
+                       } 
+                       
+                       mono_get_val_sizes (tree->svt, &size, &align);
+                       v = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, tree->svt);
+                       t1 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
+                       t1->data.i = v;
+                      
+                       t2 = mono_ctree_new_leaf (cfg->mp, MB_TERM_ADDR_L);
+                       t2->data.i = varnum;
+                       t2 = mono_ctree_new (cfg->mp, tree->op, t2, NULL);
+
+                       t2 = mono_ctree_new (cfg->mp, map_store_svt_type (tree->svt), t1, t2);
+                       t2->svt = tree->svt;
+
+                       tree->left->data.i = v;
+
+                       *copy = t2;
+               }
+       }
+}
+
+/* 
+ * if a variable is modified and there are still referencence
+ * to it on the runtime stack we need to store the value into
+ * a temporary variable and use that value instead of the 
+ * modified one.
+ */
+static MBTree *
+mono_stack_duplicate_used_var (MonoFlowGraph *cfg, MBTree **stack, MBTree **sp, int varnum)
+{
+       MBTree *res = NULL;
+
+       while (stack < sp) {
+               mono_copy_used_var (cfg, *stack, varnum, &res);
+               stack++;
+       }
+
+       return res;
+}
+
+static int
+check_inlining (MonoMethod *method)
+{
+       MonoMethodHeader *header;
+       MonoMethodSignature *signature = method->signature;
+       register const unsigned char *ip, *end;
+       gboolean stop;
+       int i, arg_used [256];
+
+       g_assert (method);
+
+       if (method->inline_info)
+               return method->inline_count;
+
+       method->inline_info = 1;
+       
+       if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
+           (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
+           (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
+           (method->klass->marshalbyref) ||
+           ISSTRUCT (signature->ret))
+               goto fail;;
+       
+       if (!(header = ((MonoMethodNormal *)method)->header) ||
+           header->num_clauses)
+               goto fail;;
+
+       if (header->num_clauses)
+               goto fail;
+       
+       ip = header->code;
+       end = ip + header->code_size;
+
+       for (i = 0; i < 256; i++)
+               arg_used [i] = 0;
+
+       stop = FALSE;        
+       while (!stop && ip < end) {
+
+               switch (*ip) {
+               case CEE_NOP:
+               case CEE_BREAK:
+               case CEE_DUP:
+               case CEE_POP:
+               case CEE_LDIND_I1:
+               case CEE_LDIND_U1:
+               case CEE_LDIND_I2:
+               case CEE_LDIND_U2:
+               case CEE_LDIND_I4:
+               case CEE_LDIND_U4:
+               case CEE_LDIND_I8:
+               case CEE_LDIND_I:
+               case CEE_LDIND_R4:
+               case CEE_LDIND_R8:
+               case CEE_LDIND_REF:
+               case CEE_STIND_REF:
+               case CEE_STIND_I1:
+               case CEE_STIND_I2:
+               case CEE_STIND_I4:
+               case CEE_STIND_I8:
+               case CEE_STIND_R4:
+               case CEE_STIND_R8:
+               case CEE_ADD:
+               case CEE_SUB:
+               case CEE_MUL:
+               case CEE_DIV:
+               case CEE_DIV_UN:
+               case CEE_REM:
+               case CEE_REM_UN:
+               case CEE_AND:
+               case CEE_OR:
+               case CEE_XOR:
+               case CEE_SHL:
+               case CEE_SHR:
+               case CEE_SHR_UN:
+               case CEE_NEG:
+               case CEE_NOT:
+               case CEE_CONV_I1:
+               case CEE_CONV_I2:
+               case CEE_CONV_I4:
+               case CEE_CONV_I8:
+               case CEE_CONV_R4:
+               case CEE_CONV_R8:
+               case CEE_CONV_U4:
+               case CEE_CONV_U8:
+               case CEE_CONV_R_UN:
+               case CEE_THROW:
+               case CEE_CONV_OVF_I1_UN:
+               case CEE_CONV_OVF_I2_UN:
+               case CEE_CONV_OVF_I4_UN:
+               case CEE_CONV_OVF_I8_UN:
+               case CEE_CONV_OVF_U1_UN:
+               case CEE_CONV_OVF_U2_UN:
+               case CEE_CONV_OVF_U4_UN:
+               case CEE_CONV_OVF_U8_UN:
+               case CEE_CONV_OVF_I_UN:
+               case CEE_CONV_OVF_U_UN:
+               case CEE_LDLEN:
+               case CEE_LDELEM_I1:
+               case CEE_LDELEM_U1:
+               case CEE_LDELEM_I2:
+               case CEE_LDELEM_U2:
+               case CEE_LDELEM_I4:
+               case CEE_LDELEM_U4:
+               case CEE_LDELEM_I8:
+               case CEE_LDELEM_I:
+               case CEE_LDELEM_R4:
+               case CEE_LDELEM_R8:
+               case CEE_LDELEM_REF:
+               case CEE_STELEM_I:
+               case CEE_STELEM_I1:
+               case CEE_STELEM_I2:
+               case CEE_STELEM_I4:
+               case CEE_STELEM_I8:
+               case CEE_STELEM_R4:
+               case CEE_STELEM_R8:
+               case CEE_STELEM_REF:
+               case CEE_CONV_OVF_I1:
+               case CEE_CONV_OVF_U1:
+               case CEE_CONV_OVF_I2:
+               case CEE_CONV_OVF_U2:
+               case CEE_CONV_OVF_I4:
+               case CEE_CONV_OVF_U4:
+               case CEE_CONV_OVF_I8:
+               case CEE_CONV_OVF_U8:
+               case CEE_CKFINITE:
+               case CEE_CONV_U2:
+               case CEE_CONV_U1:
+               case CEE_CONV_I:
+               case CEE_CONV_OVF_I:
+               case CEE_CONV_OVF_U:
+               case CEE_ADD_OVF:
+               case CEE_ADD_OVF_UN:
+               case CEE_MUL_OVF:
+               case CEE_MUL_OVF_UN:
+               case CEE_SUB_OVF:
+               case CEE_SUB_OVF_UN:
+               case CEE_STIND_I:
+               case CEE_CONV_U:
+               case CEE_LDNULL:
+               case CEE_LDC_I4_M1:
+               case CEE_LDC_I4_0:
+               case CEE_LDC_I4_1:
+               case CEE_LDC_I4_2:
+               case CEE_LDC_I4_3:
+               case CEE_LDC_I4_4:
+               case CEE_LDC_I4_5:
+               case CEE_LDC_I4_6:
+               case CEE_LDC_I4_7:
+               case CEE_LDC_I4_8:
+                       ++ip;
+                       break;
+               case CEE_LDC_I4_S:
+                       ip += 2;
+                       break;
+               case CEE_LDC_I4:
+               case CEE_LDC_R4:
+               case CEE_CPOBJ:
+               case CEE_LDOBJ:
+               case CEE_LDSTR:
+               case CEE_NEWOBJ:
+               case CEE_CASTCLASS:
+               case CEE_ISINST:
+               case CEE_UNBOX:
+               case CEE_LDFLD:
+               case CEE_LDFLDA:
+               case CEE_STFLD:
+               case CEE_LDSFLD:
+               case CEE_LDSFLDA:
+               case CEE_STSFLD:
+               case CEE_STOBJ:
+               case CEE_BOX:
+               case CEE_NEWARR:
+               case CEE_LDELEMA:
+               case CEE_LDTOKEN:
+                       ip += 5;
+                       break;
+               case CEE_LDC_I8:
+               case CEE_LDC_R8:
+                       ip += 9;
+                       break;
+               case CEE_CALL:
+               case CEE_CALLVIRT: {
+                       MonoMethod *cm;
+                       guint32 token;
+                       ++ip;
+                       token = read32 (ip);
+                       ip += 4;
+
+                       cm = mono_get_method (method->klass->image, token, NULL);
+                       g_assert (cm);
+
+                       if (cm == method)
+                               goto fail;
+
+                       break;
+               }
+               case CEE_LDARG_0:
+               case CEE_LDARG_1:
+               case CEE_LDARG_2:
+               case CEE_LDARG_3: {
+                       int an = (*ip) - CEE_LDARG_0;
+                       if (arg_used [an])
+                               goto fail;
+                       arg_used [an] = TRUE;
+                       ++ip;
+                       break;
+               }       
+               case CEE_LDARG_S:
+                       ++ip;
+                       if (arg_used [*ip])
+                               goto fail;
+                       arg_used [*ip] = TRUE;
+                       ++ip;
+                       break;
+       
+               case CEE_PREFIX1: {
+                       ++ip;                   
+                       switch (*ip) {
+                       case CEE_LDARG: {
+                               int an;
+                               ip++;
+                               an = read32 (ip);
+                               ip += 4;
+                               if (an > 255 || arg_used [an])
+                                       goto fail;
+                               arg_used [an] = TRUE;
+                               break;
+                       }       
+
+                       case CEE_CEQ:
+                       case CEE_CGT:
+                       case CEE_CGT_UN:
+                       case CEE_CLT:
+                       case CEE_CLT_UN:
+                       case CEE_CPBLK:
+                       case CEE_INITBLK:
+                               ip++;
+                               break;
+                       case CEE_LDFTN:
+                       case CEE_LDVIRTFTN:
+                       case CEE_INITOBJ:
+                       case CEE_SIZEOF:
+                               ip += 5;
+                               break;
+                       default:
+                               stop = TRUE;
+                               break;
+                       }
+               }
+               default:
+                       stop = TRUE;
+                       break;                  
+               }
+       }
+
+       if (ip >= end ||
+           !(ip [0] == CEE_RET ||
+             ((ip + 4) < end &&
+              ip [0] == CEE_STLOC_0 &&
+              ip [1] == CEE_BR_S &&
+              ip [2] == 0 &&
+              ip [3] == CEE_LDLOC_0 &&
+              ip [4] == CEE_RET)))
+               goto fail;
+       
+       if (signature->hasthis && arg_used [0])
+               method->uses_this = 1;
+
+       mono_jit_stats.inlineable_methods++;
+
+       return method->inline_count = ip - header->code;
+
+ fail:
+       return method->inline_count = -1;
+}
+
 static void
 create_outstack (MonoFlowGraph *cfg, MonoBBlock *bb, MBTree **stack, int depth)
 {
@@ -1409,26 +1902,32 @@ mono_analyze_stack (MonoFlowGraph *cfg)
        MonoMethodSignature *signature;
        MonoImage *image;
        MonoValueType svt;
-       MBTree **sp, **stack, **arg_sp, *t1, *t2, *t3;
+       MBTree **sp, **stack, **arg_sp, **arg_map = NULL, *t1, *t2, *t3;
        register const unsigned char *ip, *end;
        GPtrArray *forest;
        int i, j, depth, repeat_count;
        int varnum = 0, firstarg = 0, retvtarg = 0;
        gboolean repeat, superblock_end;
        MonoBBlock *bb, *tbb;
+       int maxstack;
+       GList *inline_list = NULL;
 
        header = ((MonoMethodNormal *)method)->header;
        signature = method->signature;
        image = method->klass->image; 
 
-       sp = stack = alloca (sizeof (MBTree *) * (header->max_stack + 1));
+       /* we add 10 extra slots for method inlining */
+       maxstack = header->max_stack + 10;
+       sp = stack = alloca (sizeof (MBTree *) * (maxstack + 1));
 
        if (header->num_locals) {
                int size, align;
-
+               
                for (i = 0; i < header->num_locals; ++i) {
-                       size = mono_type_size (header->locals [i], &align);
-                       varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, VAL_UNKNOWN);
+                       MonoValueType svt;
+                       size = mono_type_size (LOCAL_TYPE (i), &align);
+                       map_ldind_type (header->locals [i], &svt);
+                       varnum = arch_allocate_var (cfg, size, align, MONO_LOCALVAR, svt);
                        if (i == 0)
                                cfg->locals_start_index = varnum;
                }
@@ -1450,15 +1949,19 @@ mono_analyze_stack (MonoFlowGraph *cfg)
        cfg->args_start_index = firstarg = varnum + 1;
  
        if (signature->hasthis) {
-               arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
+               int thisvar;
+               thisvar = arch_allocate_var (cfg, sizeof (gpointer), sizeof (gpointer), MONO_ARGVAR, VAL_POINTER);
+               VARINFO (cfg, thisvar).isvolatile = 1;
        }
 
        if (signature->param_count) {
                int align, size;
 
                for (i = 0; i < signature->param_count; ++i) {
+                       int argvar;
                        size = mono_type_stack_size (signature->params [i], &align);
-                       arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
+                       argvar = arch_allocate_var (cfg, size, align, MONO_ARGVAR, VAL_UNKNOWN);
+                       VARINFO (cfg, argvar).isvolatile = 1;
                }
        }
 
@@ -1517,12 +2020,31 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                        ip = header->code + bb->cli_addr;
                                        end = ip + bb->length;
 
-                                       bb->forest = forest = g_ptr_array_new ();
+                                       forest = bb->forest;
                                
                                        superblock_end = FALSE;
 
-        while (ip < end) {
-               guint32 cli_addr = ip - header->code;
+
+        while (inline_list || ip < end) {
+               guint32 cli_addr;
+
+               if (inline_list) {
+                       MonoInlineInfo *ii = (MonoInlineInfo *)inline_list->data;
+                       if (ip >= ii->end) {
+                               inline_list = g_list_remove_link (inline_list, inline_list);
+                               ip = ii->saved_ip;
+                               image = ii->saved_image;
+                               if (inline_list)
+                                       arg_map = ((MonoInlineInfo *)inline_list->data)->arg_map;
+                               else 
+                                       arg_map = NULL;
+                               continue;
+                       }
+               } else 
+                       cli_addr = ip - header->code;
+
+               
+               //if (inline_list) printf ("INLINE IL%04x OPCODE %s\n", cli_addr, mono_opcode_names [*ip]);
 
                //printf ("%d IL%04x OPCODE %s %d %d %d\n", i, cli_addr, mono_opcode_names [*ip], 
                //forest->len, superblock_end, sp - stack);
@@ -1716,17 +2238,23 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                field = mono_class_get_field (klass, token);
                        }
                        g_assert (field);
-
-                       t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
                        
-                       if (klass->valuetype)
-                               t1->data.i = field->offset - sizeof (MonoObject);
-                       else 
-                               t1->data.i = field->offset;
+                       if (klass->marshalbyref) {
+                               t1 = mono_ctree_new (mp, MB_TERM_REMOTE_LDFLDA, sp [0], NULL);
+                               t1->data.fi.klass = klass;
+                               t1->data.fi.field = field;
+                       } else {
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+
+                               if (klass->valuetype)
+                                       t1->data.i = field->offset - sizeof (MonoObject);
+                               else 
+                                       t1->data.i = field->offset;
 
-                       t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
+                               t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
+                       }
 
-                       if (!load_addr)
+                       if (!load_addr) 
                                t1 = ctree_create_load (cfg, field->type, t1, &svt, FALSE);
                        else
                                svt = VAL_POINTER;
@@ -1794,16 +2322,17 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        }
                        g_assert (field);
 
-                       t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
-                       if (klass->valuetype)
-                               t1->data.i = field->offset - sizeof (MonoObject);
-                       else 
-                               t1->data.i = field->offset;
-
-                       //printf ("VALUETYPE %d %d %d\n", klass->valuetype, field->offset, t1->data.i);
+                       if (klass->marshalbyref) {
+                               t1 = mono_ctree_new (mp, map_remote_stind_type (field->type), sp [0], sp [1]);
+                               t1->data.fi.klass = klass;
+                               t1->data.fi.field = field;
+                       } else {
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+                               t1->data.i = klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset;
+                               t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
+                               t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
+                       }
 
-                       t1 = mono_ctree_new (mp, MB_TERM_ADD, sp [0], t1);
-                       t1 = ctree_create_store (cfg, field->type, t1, sp [1], FALSE);
 
                        ADD_TREE (t1, cli_addr);
                        break;
@@ -1900,10 +2429,19 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        class = mono_class_get (image, token);
                        ip += 4;
 
-                       t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
-                       t1->data.p = class;
-                       PUSH_TREE (t1, VAL_POINTER);
+                       if (cfg->share_code) {
+                               t1 = mono_ctree_new (mp, MB_TERM_NEWARR, *sp, NULL);
+                               t1->data.p = class;
+                       }
+                       else {
+                               MonoClass  *ac = mono_array_class_get (&class->byval_arg, 1);
+                               MonoVTable *vt = mono_class_vtable (cfg->domain, ac);
+
+                               t1 = mono_ctree_new (mp, MB_TERM_NEWARR_SPEC, *sp, NULL);
+                               t1->data.p = vt;
+                       }
 
+                       PUSH_TREE (t1, VAL_POINTER);
                        break;
                }
                case CEE_CPOBJ: {
@@ -1923,12 +2461,12 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                }
                case CEE_NEWOBJ: {
                        MonoMethodSignature *csig;
-                       MethodCallInfo *ci;
                        MonoMethod *cm;
                        MBTree *this = NULL;
                        guint32 token;
                        int k, align, size, args_size = 0;
                        int newarr = FALSE;
+                       int newstr = FALSE;
 
                        ++ip;
                        token = read32 (ip);
@@ -1938,9 +2476,6 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        g_assert (cm);
                        g_assert (!strcmp (cm->name, ".ctor"));
                        
-                       ci =  mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
-                       ci->m = cm;
-
                        csig = cm->signature;
                        g_assert (csig->call_convention == MONO_CALL_DEFAULT);
                        g_assert (csig->hasthis);
@@ -1954,13 +2489,21 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                newarr = TRUE;
                                this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
                                this->data.m = cm;
+                       } else if (cm->klass == mono_defaults.string_class) {
+                               newstr = TRUE;
+                               this = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+                               this->data.m = cm;
                        } else {                                
                                if (cm->klass->valuetype) {
                                        this = mono_ctree_new_leaf (mp, MB_TERM_NEWSTRUCT);
                                        this->data.i =  mono_class_value_size (cm->klass, NULL);
-                               } else {
+                               } else if (cfg->share_code) {
                                        this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ);
                                        this->data.klass = cm->klass;
+                               } else {
+                                       MonoVTable *vt = mono_class_vtable (cfg->domain, cm->klass);
+                                       this = mono_ctree_new_leaf (mp, MB_TERM_NEWOBJ_SPEC);
+                                       this->data.p = vt;
                                }
 
                                this->svt = VAL_POINTER;
@@ -1982,15 +2525,21 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                args_size += size;
                        }
 
-                       ci->args_size = args_size;
 
-                       if (newarr) {
+                       if (newarr || newstr) {
 
                                t2 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
-                               t2->data.p = mono_array_new_va;
+                               if (newarr) {
+                                       t2->data.p = mono_array_new_va;
+                               } else {
+                                       t2->data.p = arch_create_jit_trampoline (cm);
+                               }
 
                                t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
-                               t1->data.p = ci;
+                               t1->data.ci.m = cm;
+                               t1->data.ci.args_size = args_size;
+                               t1->data.ci.vtype_num = 0;
+                               
                                t1->svt = VAL_POINTER;
 
                                t1 = mono_store_tree (cfg, -1, t1, &t2);
@@ -1999,17 +2548,20 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                PUSH_TREE (t2, t2->svt);
 
                        } else {
-                               
+
                                t2 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_G);
                                t2->data.p = arch_create_jit_trampoline (cm);
 
                                t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
-                               t1->data.p = ci;
+                               t1->data.ci.m = cm;
+                               t1->data.ci.args_size = args_size;
+                               t1->data.ci.vtype_num = 0;
                                t1->svt = svt;
 
-                               ADD_TREE (t1, cli_addr); 
-                               t1 = ctree_create_dup (mp, this);       
+                               ADD_TREE (t1, cli_addr);
 
+                               t1 = ctree_create_dup (mp, this);       
+                               
                                if (cm->klass->valuetype) {
                                        t2 = ctree_create_load (cfg, &cm->klass->byval_arg, t1, &svt, FALSE);
                                        PUSH_TREE (t2, svt);
@@ -2022,7 +2574,6 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                case CEE_CALL: 
                case CEE_CALLVIRT: {
                        MonoMethodSignature *csig;
-                       MethodCallInfo *ci;
                        MonoMethod *cm;
                        MBTree *this = NULL;
                        guint32 token;
@@ -2030,7 +2581,8 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        int virtual = *ip == CEE_CALLVIRT;
                        gboolean array_set = FALSE;
                        gboolean array_get = FALSE;
-
+                       /* fixme: compute this value */
+                       gboolean shared_to_unshared_call = FALSE;
                        int nargs, vtype_num = 0;
 
                        ++ip;
@@ -2040,39 +2592,59 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        cm = mono_get_method (image, token, NULL);
                        g_assert (cm);
 
-                       ci =  mono_mempool_alloc0 (mp, sizeof (MethodCallInfo));
-                       ci->m = cm;
+                       if (cm->klass == mono_defaults.string_class &&
+                           *cm->name == '.' && !strcmp (cm->name, ".ctor"))
+                               g_assert_not_reached ();
 
-                       
-#ifndef EXT_VTABLE_HACK
-                       if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
+                       arg_sp = sp -= cm->signature->param_count;
+
+                       if ((cm->flags & METHOD_ATTRIBUTE_FINAL && cm->klass != mono_defaults.object_class) ||
                            !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL))
                                virtual = 0;
-#else
-                       if ((cm->flags & METHOD_ATTRIBUTE_FINAL) ||
-                           !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
-                               /* fixme: compute this value */
-                               gboolean shared_to_unshared_call = FALSE;
-                               /* we call all marshalbyref methods and Object.GetType 
-                                  through the vtable */
-                               if (!(shared_to_unshared_call ||
-                                     cm->klass->marshalbyref ||
-                                     ((cm->klass == mono_defaults.object_class) && 
-                                      !strcmp (cm->name, "GetType"))))
-                                       virtual = 0;
-                       }
-#endif;
 
+                       if (mono_jit_inline_code && !virtual && cm->inline_count != -1 &&
+                           (cm->inline_info || check_inlining (cm) >= 0)) {
+                               MonoInlineInfo *ii = alloca (sizeof (MonoInlineInfo));
+                               int args;
+
+                               mono_jit_stats.inlined_methods++;
+                               
+                               if (cm->signature->hasthis)
+                                       sp--;
+
+                               args = cm->signature->param_count + cm->signature->hasthis;
+
+                               ii->method = cm;
+                               ii->saved_ip = ip;
+                               ii->saved_image = image;
+                               ii->arg_map = alloca (args * sizeof (MBTree *));
+                               memcpy (ii->arg_map, sp, args * sizeof (MBTree *));
+
+                               if (cm->signature->hasthis && !cm->uses_this && 
+                                   (ii->arg_map [0]->op != MB_TERM_CHECKTHIS)) {
+                                       ii->arg_map [0] = mono_ctree_new (mp, MB_TERM_CHECKTHIS, 
+                                                                         ii->arg_map [0], NULL);
+                                       ADD_TREE (ii->arg_map [0], cli_addr);
+                               }
+                               
+                               if (cm->inline_count) {
+                                       inline_list = g_list_prepend (inline_list, ii);
+                                       ip = ((MonoMethodNormal *)cm)->header->code;
+                                       ii->end = ip + cm->inline_count;
+                                       arg_map = ii->arg_map;
+                                       image = cm->klass->image;
+                               }
+                               continue;
+                       }
+                       
                        csig = cm->signature;
+                       nargs = csig->param_count;
                        g_assert (csig->call_convention == MONO_CALL_DEFAULT);
                        g_assert (!virtual || csig->hasthis);
 
                        /* fixme: we need to unbox the this pointer for value types ?*/
                        g_assert (!virtual || !cm->klass->valuetype);
 
-                       nargs = csig->param_count;
-                       arg_sp = sp -= nargs;
-                       
                        if (cm->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) {
                                if (cm->klass->parent == mono_defaults.array_class) {
                                        if (!strcmp (cm->name, "Set")) { 
@@ -2094,7 +2666,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        }
 
                        if (csig->hasthis) {
-                               this = *(--sp);                         
+                               this = *(--sp);         
                                args_size += sizeof (gpointer);
                        } else
                                this = mono_ctree_new_leaf (mp, MB_TERM_NOP);
@@ -2104,9 +2676,6 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                vtype_num = arch_allocate_var (cfg, size, align, MONO_TEMPVAR, VAL_UNKNOWN);
                        }
 
-                       ci->args_size = args_size;
-                       ci->vtype_num = vtype_num;
-
                        if (array_get) {
                                int vnum;
                                
@@ -2114,7 +2683,9 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                t2->data.p = ves_array_element_address;
 
                                t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
-                               t1->data.p = ci;
+                               t1->data.ci.m = cm;
+                               t1->data.ci.args_size = args_size;
+                               t1->data.ci.vtype_num = vtype_num;
  
                                t1 = mono_ctree_new (mp, map_ldind_type (csig->ret, &svt), t1, NULL);
                                t1->svt = svt;          
@@ -2137,14 +2708,19 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                t2->data.p = ves_array_element_address;
 
                                t1 = mono_ctree_new (mp, MB_TERM_CALL_I4, this, t2);
-                               t1->data.p = ci;
+                               t1->data.ci.m = cm;
+                               t1->data.ci.args_size = args_size;
+                               t1->data.ci.vtype_num = vtype_num;
 
                                t1 = ctree_create_store (cfg, csig->params [nargs], t1, arg_sp [nargs], FALSE);
                                ADD_TREE (t1, cli_addr);
                        
                        } else {
 
-                               if (virtual) {
+                               if (virtual || (csig->hasthis && 
+                                               !(cm->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
+                                               (cm->klass->marshalbyref || shared_to_unshared_call))) {
+
                                        mono_class_init (cm->klass);
                                        
                                        if (cm->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
@@ -2160,7 +2736,9 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                }
 
                                t1 = mono_ctree_new (mp, map_call_type (csig->ret, &svt), this, t2);
-                               t1->data.p = ci;
+                               t1->data.ci.m = cm;
+                               t1->data.ci.args_size = args_size;
+                               t1->data.ci.vtype_num = vtype_num;
                                t1->svt = svt;
 
                                if (csig->ret->type != MONO_TYPE_VOID) {
@@ -2191,6 +2769,8 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        --sp;
 
                        c = mono_class_get (image, token);
+                       if (!c->inited)
+                               mono_class_init (c);
 
                        t1 = mono_ctree_new (mp, MB_TERM_ISINST, *sp, NULL);
                        t1->data.klass = c;
@@ -2208,6 +2788,8 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        --sp;
 
                        c = mono_class_get (image, token);
+                       if (!c->inited)
+                               mono_class_init (c);
 
                        t1 = mono_ctree_new (mp, MB_TERM_CASTCLASS, *sp, NULL);
                        t1->data.klass = c;
@@ -2317,6 +2899,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                        t1->data.i = LOCAL_POS (*ip);
+                       VARINFO (cfg, t1->data.i).isvolatile = 1;
                        ++ip;
                        PUSH_TREE (t1, VAL_POINTER);                    
                        break;
@@ -2331,8 +2914,11 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                        t1->data.i = LOCAL_POS (n);
-                       t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
 
+                       if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
+                               ADD_TREE (t2, cli_addr); 
+
+                       t1 = ctree_create_store (cfg, LOCAL_TYPE (n), t1, *sp, FALSE);
                        ADD_TREE (t1, cli_addr);                        
                        break;
                }
@@ -2342,35 +2928,15 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                        t1->data.i = LOCAL_POS (*ip);
-                       t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
+                       if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
+                               ADD_TREE (t2, cli_addr); 
 
+                       t1 = ctree_create_store (cfg, LOCAL_TYPE (*ip), t1, *sp, FALSE);
                        ++ip;
                        ADD_TREE (t1, cli_addr);                        
                        break;
                }
 
-               case CEE_SHR: {
-                       ++ip;  
-                       sp -= 2;
-                       t1 = mono_ctree_new (mp, MB_TERM_SHR, sp [0], sp [1]); 
-                       PUSH_TREE (t1, sp [0]->svt);     
-                       break;
-               }
-               case CEE_SHR_UN: {
-                       ++ip;  
-                       sp -= 2;
-                       t1 = mono_ctree_new (mp, MB_TERM_SHR_UN, sp [0], sp [1]); 
-                       PUSH_TREE (t1, sp [0]->svt);     
-                       break;
-               }
-               case CEE_SHL: {
-                       ++ip;  
-                       sp -= 2;
-                       t1 = mono_ctree_new (mp, MB_TERM_SHL, sp [0], sp [1]); 
-                       PUSH_TREE (t1, sp [0]->svt);     
-                       break;
-               }
-
                MAKE_BI_ALU (ADD)
                MAKE_BI_ALU (ADD_OVF)
                MAKE_BI_ALU (ADD_OVF_UN)
@@ -2380,6 +2946,9 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                MAKE_BI_ALU (AND)
                MAKE_BI_ALU (OR)
                MAKE_BI_ALU (XOR)
+               MAKE_SPILLED_BI_ALU (SHL)
+               MAKE_SPILLED_BI_ALU (SHR)
+               MAKE_SPILLED_BI_ALU (SHR_UN)
                MAKE_SPILLED_BI_ALU (MUL)
                MAKE_SPILLED_BI_ALU (MUL_OVF)
                MAKE_SPILLED_BI_ALU (MUL_OVF_UN)
@@ -2496,7 +3065,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        /* fixme: fault handler */
 
-                       if ((hb = mono_find_final_block (cfg, cli_addr, MONO_EXCEPTION_CLAUSE_FINALLY))) {
+                       if ((hb = mono_find_final_block (cfg, cli_addr, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
                                mark_reached (cfg, hb, NULL, 0);
                                t1 = mono_ctree_new_leaf (mp, MB_TERM_HANDLER);
                                t1->data.p = hb;
@@ -2602,7 +3171,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                        if (sp > stack) {
                                g_warning ("more values on stack at IL_%04x: %d",  ip - header->code, sp - stack);
-                               mono_print_ctree (sp [-1]);
+                               mono_print_ctree (cfg, sp [-1]);
                                printf ("\n");
                        }
                        superblock_end = TRUE;
@@ -2626,22 +3195,33 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        int n = (*ip) - CEE_LDARG_0;
                        ++ip;
 
-                       t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
-                       t1->data.i = ARG_POS (n);
-                       if (!ISSTRUCT (ARG_TYPE (n))) 
-                               t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
+                       if (arg_map) {
+                               *sp = arg_map [n];
+                               sp++;
+                       } else {
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
+                               t1->data.i = ARG_POS (n);
+                               if (!ISSTRUCT (ARG_TYPE (n))) 
+                                       t1 = ctree_create_load (cfg, ARG_TYPE (n), t1, &svt, TRUE);
                        
-                       PUSH_TREE (t1, svt);
+                               PUSH_TREE (t1, svt);
+                       }
+
                        break;
                }
                case CEE_LDARG_S: {
                        ++ip;
 
-                       t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
-                       t1->data.i = ARG_POS (*ip);
-                       if (!ISSTRUCT (ARG_TYPE (*ip))) 
-                               t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
-                       PUSH_TREE (t1, svt);
+                       if (arg_map) {
+                               *sp = arg_map [*ip];
+                               sp++;
+                       } else {
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
+                               t1->data.i = ARG_POS (*ip);
+                               if (!ISSTRUCT (ARG_TYPE (*ip))) 
+                                       t1 = ctree_create_load (cfg, ARG_TYPE (*ip), t1, &svt, TRUE);
+                               PUSH_TREE (t1, svt);
+                       }
                        ++ip;
                        break;
                }
@@ -2668,21 +3248,30 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        int vnum;
 
                        ++ip; 
-                       sp--;
 
-                       vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
-                       t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
-                       t1->data.i = vnum;
-                      
-                       t2 = mono_ctree_new (mp, map_store_svt_type (sp [0]->svt), t1, sp [0]);
-                       t2->svt = sp [0]->svt;
-                       ADD_TREE (t2, cli_addr);
+                       /* fixme: maybe we should add more of these optimisations */
+                       if (sp [-1]->op == MB_TERM_CONST_I4) {
 
-                       t1 = ctree_create_dup (mp, t2);         
-                       PUSH_TREE (t1, t1->svt);
-                       t1 = ctree_create_dup (mp, t1);         
-                       PUSH_TREE (t1, t1->svt);
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_CONST_I4);
+                               t1->data.i = sp [-1]->data.i;
+                               PUSH_TREE (t1, VAL_I32);
+                             
+                       } else {
+                               sp--;
 
+                               vnum = mono_allocate_intvar (cfg, sp - stack, sp [0]->svt);
+                               t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
+                               t1->data.i = vnum;
+                      
+                               t2 = mono_ctree_new (mp, map_store_svt_type (sp [0]->svt), t1, sp [0]);
+                               t2->svt = sp [0]->svt;
+                               ADD_TREE (t2, cli_addr);
+
+                               t1 = ctree_create_dup (mp, t2);         
+                               PUSH_TREE (t1, t1->svt);
+                               t1 = ctree_create_dup (mp, t1);         
+                               PUSH_TREE (t1, t1->svt);
+                       }
                        break;
                }
                case CEE_POP: {
@@ -2695,171 +3284,163 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                        break;
                }
                case CEE_CONV_U1: 
-               case CEE_CONV_I1: {
+                       ++ip;
+                       sp--;
+                       t1 = mono_ctree_new (mp, MB_TERM_CONV_U1, *sp, NULL);
+                       PUSH_TREE (t1, VAL_I32);                
+                       break;
+               case CEE_CONV_I1:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_I1, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);                
                        break;
-               }
                case CEE_CONV_U2: 
-               case CEE_CONV_I2: {
+                       ++ip;
+                       sp--;
+                       t1 = mono_ctree_new (mp, MB_TERM_CONV_U2, *sp, NULL);
+                       PUSH_TREE (t1, VAL_I32);                
+                       break;
+               case CEE_CONV_I2:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_I2, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);                
                        break;
-               }
                case CEE_CONV_I: 
+               case CEE_CONV_I4:
+                       ++ip;
+                       sp--;
+                       t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
+                       PUSH_TREE (t1, VAL_I32);                
+                       break;
                case CEE_CONV_U: 
                case CEE_CONV_U4: 
-               case CEE_CONV_I4: {
                        ++ip;
                        sp--;
-                       t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
+                       t1 = mono_ctree_new (mp, MB_TERM_CONV_U4, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);                
                        break;
-               }
-               case CEE_CONV_I8: {
+               case CEE_CONV_I8:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
                        PUSH_TREE (t1, VAL_I64);                
                        break;
-               }
-               case CEE_CONV_U8: {
+               case CEE_CONV_U8:
                        ++ip;
                        sp--;
-                       t1 = mono_ctree_new (mp, MB_TERM_CONV_I8, *sp, NULL);
+                       t1 = mono_ctree_new (mp, MB_TERM_CONV_U8, *sp, NULL);
                        PUSH_TREE (t1, VAL_I64);                
                        break;
-               }
-               case CEE_CONV_R8: {
+               case CEE_CONV_R8:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_R8, *sp, NULL);
                        PUSH_TREE (t1, VAL_DOUBLE);             
                        break;
-               }
-               case CEE_CONV_R4: {
+               case CEE_CONV_R4:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_R4, *sp, NULL);
                        PUSH_TREE (t1, VAL_DOUBLE);             
                        break;
-               }
-               case CEE_CONV_R_UN: {
+               case CEE_CONV_R_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_R_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_DOUBLE);             
                        break;
-               }
                case CEE_CONV_OVF_I:
-               case CEE_CONV_OVF_I4: {
+               case CEE_CONV_OVF_I4:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
                case CEE_CONV_OVF_I_UN:
-               case CEE_CONV_OVF_I4_UN: {
+               case CEE_CONV_OVF_I4_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I4_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);                
                        break;
-               }
                case CEE_CONV_OVF_U:
-               case CEE_CONV_OVF_U4: {
+               case CEE_CONV_OVF_U4:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U4, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);                
                        break;
-               }
-               case CEE_CONV_OVF_I1: {
+               case CEE_CONV_OVF_I1:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_I1_UN: {
+               case CEE_CONV_OVF_I1_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I1_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_U1_UN: {
+               case CEE_CONV_OVF_U1_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               
-               case CEE_CONV_OVF_U1: {
+               case CEE_CONV_OVF_U1:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U1, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_I2: {
+               case CEE_CONV_OVF_I2:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_U2_UN: {
+               case CEE_CONV_OVF_U2_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_U2: {
+               case CEE_CONV_OVF_U2:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U2, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_I2_UN: {
+               case CEE_CONV_OVF_I2_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I2_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
-               case CEE_CONV_OVF_U8: {
+               case CEE_CONV_OVF_U8:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_U8, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);
                        break;
-               }
                case CEE_CONV_OVF_U_UN:
-               case CEE_CONV_OVF_U4_UN: {
+               case CEE_CONV_OVF_U4_UN:
                        // fixme: raise exceptions ?
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_I4, *sp, NULL);
                        PUSH_TREE (t1, VAL_I32);                
                        break;
-               }
-               case CEE_CONV_OVF_I8_UN: {
+               case CEE_CONV_OVF_I8_UN:
                        ++ip;
                        sp--;
                        t1 = mono_ctree_new (mp, MB_TERM_CONV_OVF_I8_UN, *sp, NULL);
                        PUSH_TREE (t1, VAL_I64);
                        break;
-               }
-               case 0xFE: {
+               case CEE_PREFIX1: {
                        ++ip;                   
                        switch (*ip) {
                                
@@ -2882,6 +3463,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                                t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                                t1->data.i = LOCAL_POS (read16 (ip));
+                               VARINFO (cfg, t1->data.i).isvolatile = 1;
                                ip += 2;
                                PUSH_TREE (t1, VAL_POINTER);                    
                                break;
@@ -2892,8 +3474,10 @@ mono_analyze_stack (MonoFlowGraph *cfg)
 
                                t1 = mono_ctree_new_leaf (mp, MB_TERM_ADDR_L);
                                t1->data.i = LOCAL_POS (read16 (ip));
-                               t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
+                               if ((t2 = mono_stack_duplicate_used_var (cfg, stack, sp, t1->data.i)))
+                                       ADD_TREE (t2, cli_addr); 
 
+                               t1 = ctree_create_store (cfg, LOCAL_TYPE (read16 (ip)), t1, *sp, FALSE);
                                ip += 2;
                                ADD_TREE (t1, cli_addr);                        
                                break;
@@ -3017,14 +3601,14 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                cfg->invalid = 1;
                                return;
                        }
-                       mono_print_forest (forest);
+                       mono_print_forest (cfg, forest);
                        g_assert_not_reached ();
                }
        }               
 
         if ((depth = sp - stack)) {
                //printf ("DEPTH %d %d\n",  depth, sp [0]->op);
-               //mono_print_forest (forest);
+               //mono_print_forest (cfg, forest);
                create_outstack (cfg, bb, stack, sp - stack);
        }
 
@@ -3036,7 +3620,7 @@ mono_analyze_stack (MonoFlowGraph *cfg)
                                //printf ("unreached block %d\n", i);
                                repeat = TRUE;
                                if (repeat_count >= 10) {
-                                       /*mono_print_forest (forest);
+                                       /*mono_print_forest (cfg, forest);
                                        g_warning ("repeat count exceeded at ip: 0x%04x in %s\n", bb->cli_addr, cfg->method->name);*/
                                        repeat = FALSE;
                                }
@@ -3068,22 +3652,6 @@ ves_array_get (MonoArray *this, ...)
        g_assert_not_reached ();
 }
        
-static gint32
-jit_exec_main (MonoMethod *method, MonoArray *args)
-{
-       gint32 (*mfunc) (MonoArray*);
-       gint32 res;
-
-       mfunc = arch_compile_method (method);
-
-       res = mfunc (args);
-
-       if (method->signature->ret->type == MONO_TYPE_VOID)
-               res = 0;
-       
-       return res;
-}
-
 /**
  * mono_jit_exec:
  * @assembly: reference to an assembly
@@ -3095,32 +3663,34 @@ jit_exec_main (MonoMethod *method, MonoArray *args)
 int 
 mono_jit_exec (MonoDomain *domain, MonoAssembly *assembly, int argc, char *argv[])
 {
-       MonoArray *args = NULL;
        MonoImage *image = assembly->image;
        MonoCLIImageInfo *iinfo;
        MonoMethod *method;
+       MonoObject *exc;
+       int rval;
 
        iinfo = image->image_info;
        method = mono_get_method (image, iinfo->cli_cli_header.ch_entry_point, NULL);
 
-       if (method->signature->param_count) {
-               int i;
-               args = (MonoArray*)mono_array_new (domain, mono_defaults.string_class, argc);
-               for (i = 0; i < argc; ++i) {
-                       MonoString *arg = mono_string_new (domain, argv [i]);
-                       mono_array_set (args, gpointer, i, arg);
-               }
-       }
-       
-       return mono_runtime_exec_main (method, args);
+       rval = mono_runtime_run_main (method, argc, argv, &exc);
+
+       return rval;
 }
 
+#ifdef PLATFORM_WIN32
+#define GET_CONTEXT \
+       struct sigcontext *ctx = (struct sigcontext*)_dummy;
+#else
+#define GET_CONTEXT \
+       void **_p = (void **)&_dummy; \
+       struct sigcontext *ctx = (struct sigcontext *)++_p;
+#endif
+
 static void
 sigfpe_signal_handler (int _dummy)
 {
        MonoException *exc;
-       void **_p = (void **)&_dummy;
-       struct sigcontext *ctx = (struct sigcontext *)++_p;
+       GET_CONTEXT
 
        exc = mono_get_exception_divide_by_zero ();
        
@@ -3133,8 +3703,7 @@ static void
 sigill_signal_handler (int _dummy)
 {
        MonoException *exc;
-       void **_p = (void **)&_dummy;
-       struct sigcontext *ctx = (struct sigcontext *)++_p;
+       GET_CONTEXT
 
        exc = mono_get_exception_execution_engine ("SIGILL");
        
@@ -3147,8 +3716,7 @@ static void
 sigsegv_signal_handler (int _dummy)
 {
        MonoException *exc;
-       void **_p = (void **)&_dummy;
-       struct sigcontext *ctx = (struct sigcontext *)++_p;
+       GET_CONTEXT
 
        exc = mono_get_exception_null_reference ();
        
@@ -3158,45 +3726,58 @@ sigsegv_signal_handler (int _dummy)
 }
 
 /**
- * mono_jit_abort:
+ * mono_thread_abort:
  * @obj: exception object
  *
- * abort the program, print exception information and stack trace
+ * abort the thread, print exception information and stack trace
  */
 static void
-mono_jit_abort (MonoObject *obj)
+mono_thread_abort (MonoObject *obj)
 {
-       const char *message = "";
-       char *trace = NULL;
-       MonoString *str; ;
-
+       MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
+       
        g_assert (obj);
 
-       if (mono_object_isinst (obj, mono_defaults.exception_class)) {
-               if ((str = ((MonoException *)obj)->message))
-                       message = mono_string_to_utf8 (str);
-               if ((str = ((MonoException *)obj)->stack_trace))
-                       trace = mono_string_to_utf8 (str);
-       }                               
-       
-       g_warning ("unhandled exception %s.%s: \"%s\"", obj->vtable->klass->name_space, 
-                  obj->vtable->klass->name, message);
-       
-       if (trace) {
-               g_printerr (trace);
-               g_printerr ("\n");
+       if (jit_tls->env) {     
+               longjmp (*jit_tls->env, obj);
        }
+              
+       if (obj) 
+               mono_unhandled_exception (obj);
+       
+       ExitThread (-1);
+}
+               
+static void
+mono_thread_start_cb (gpointer stack_start)
+{
+       MonoJitTlsData *jit_tls;
 
-       exit (1);
+       jit_tls = g_new0 (MonoJitTlsData, 1);
+
+       TlsSetValue (mono_jit_tls_id, jit_tls);
+
+       jit_tls->abort_func = mono_thread_abort;
+       jit_tls->end_of_stack = stack_start;
 }
 
 static CRITICAL_SECTION ms;
 
 MonoDomain*
 mono_jit_init (char *file) {
+#ifndef PLATFORM_WIN32
        struct sigaction sa;
+#endif
        MonoDomain *domain;
 
+       mono_cpu_detect ();
+
+#ifdef PLATFORM_WIN32
+       win32_seh_init();
+       win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
+       win32_seh_set_handler(SIGILL, sigill_signal_handler);
+       win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
+#else /* !PLATFORM_WIN32 */
        /* catch SIGFPE */
        sa.sa_handler = sigfpe_signal_handler;
        sigemptyset (&sa.sa_mask);
@@ -3216,31 +3797,27 @@ mono_jit_init (char *file) {
        sa.sa_flags = 0;
        g_assert (syscall (SYS_sigaction, SIGSEGV, &sa, NULL) != -1);
 #endif
+#endif /* PLATFORM_WIN32 */
 
        mono_init_icall ();
-       mono_add_internal_call ("__array_Set", ves_array_set);
-       mono_add_internal_call ("__array_Get", ves_array_get);
-       mono_add_internal_call ("__array_Address", ves_array_element_address);
+       mono_add_internal_call ("System.Array::Set", ves_array_set);
+       mono_add_internal_call ("System.Array::Get", ves_array_get);
+       mono_add_internal_call ("System.Array::Address", ves_array_element_address);
 
        metadata_section = &ms;
        InitializeCriticalSection (metadata_section);
 
-       lmf_thread_id = TlsAlloc ();
-       TlsSetValue (lmf_thread_id, NULL);
-       exc_cleanup_id = TlsAlloc ();
-       TlsSetValue (exc_cleanup_id, mono_jit_abort);
-       async_result_id = TlsAlloc ();
+       mono_jit_tls_id = TlsAlloc ();
+       mono_thread_start_cb (&file);
 
        mono_install_trampoline (arch_create_jit_trampoline);
        mono_install_remoting_trampoline (arch_create_remoting_trampoline);
-       mono_install_runtime_class_init (runtime_class_init);
-       mono_install_runtime_object_init (runtime_object_init);
-       mono_install_runtime_exec_main (jit_exec_main);
        mono_install_handler (arch_get_throw_exception ());
        mono_install_runtime_invoke (arch_runtime_invoke);
 
        domain = mono_init (file);
-       mono_thread_init (domain);
+       mono_runtime_init (domain);
+       mono_thread_init (domain, mono_thread_start_cb);
        mono_network_init ();
        mono_delegate_init ();
 
@@ -3253,6 +3830,10 @@ mono_jit_cleanup (MonoDomain *domain)
        if (mono_debug_handle)
                mono_debug_close (mono_debug_handle);
 
+#ifdef PLATFORM_WIN32
+       win32_seh_cleanup();
+#endif
+
        mono_delegate_cleanup ();
        mono_network_cleanup ();
        mono_thread_cleanup ();
@@ -3274,6 +3855,14 @@ mono_jit_cleanup (MonoDomain *domain)
                                mono_jit_stats.biggest_method->klass->name, mono_jit_stats.biggest_method->name);
                g_print ("Code reallocs:          %ld\n", mono_jit_stats.code_reallocs);
                g_print ("Allocated code size:    %ld\n", mono_jit_stats.allocated_code_size);
+               g_print ("Inlineable methods:     %ld\n", mono_jit_stats.inlineable_methods);
+               g_print ("Inlined methods:        %ld\n", mono_jit_stats.inlined_methods);
+               
+               g_print ("\nCreated object count:   %ld\n", mono_stats.new_object_count);
+               g_print ("Initialized classes:    %ld\n", mono_stats.initialized_class_count);
+               g_print ("Used classes:           %ld\n", mono_stats.used_class_count);
+               g_print ("Static data size:       %ld\n", mono_stats.class_static_data_size);
+               g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
        }
 
        DeleteCriticalSection (metadata_section);