2007-06-05 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 813153967a5bc346a4f0a39bbe88d2a1bc69137a..18a69edbce30ca3a7d2b7a3abfaca7675d005950 100644 (file)
 
 #include <config.h>
 #include <signal.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <math.h>
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
+
+#ifdef PLATFORM_MACOSX
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+#endif
 
-#ifdef sun    // Solaris x86
-#include <sys/types.h>
-#include <sys/ucontext.h>
+#ifdef PLATFORM_WIN32
+#define _WIN32_WINNT 0x0500
 #endif
 
 #ifdef HAVE_VALGRIND_MEMCHECK_H
@@ -79,6 +90,8 @@
 #define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
 
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == OP_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+
 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
 static void setup_stat_profiler (void);
@@ -87,6 +100,7 @@ static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 op
 static gpointer mono_jit_compile_method (MonoMethod *method);
 static gpointer mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method);
 static gpointer mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method);
+inline static int mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer func, MonoInst **args, const guint8 *ip);
 
 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
                          const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
@@ -102,6 +116,7 @@ static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
 static MonoMethodSignature *helper_sig_domain_get = NULL;
 
 static guint32 default_opt = 0;
+static gboolean default_opt_set = FALSE;
 
 guint32 mono_jit_tls_id = -1;
 MonoTraceSpec *mono_jit_trace_calls = NULL;
@@ -189,9 +204,9 @@ get_method_from_ip (void *ip)
 {
        MonoJitInfo *ji;
        char *method;
-       char *source;
        char *res;
        MonoDomain *domain = mono_domain_get ();
+       MonoDebugSourceLocation *location;
        FindTrampUserData user_data;
        
        ji = mono_jit_info_table_find (domain, ip);
@@ -211,29 +226,52 @@ get_method_from_ip (void *ip)
                        return NULL;
        }
        method = mono_method_full_name (ji->method, TRUE);
-       source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
+       /* FIXME: unused ? */
+       location = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
 
        res = g_strdup_printf (" %s + 0x%x (%p %p) [%p - %s]", method, (int)((char*)ip - (char*)ji->code_start), ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 
-       g_free (source);
+       mono_debug_free_source_location (location);
        g_free (method);
 
        return res;
 }
 
+/** 
+ * mono_pmip:
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.   This routine is typically invoked from
+ * a debugger like this:
+ *
+ * (gdb) print mono_pmip ($pc)
+ *
+ * Returns: the name of the method at address @ip.
+ */
 G_GNUC_UNUSED char *
 mono_pmip (void *ip)
 {
        return get_method_from_ip (ip);
 }
 
-/* debug function */
+/** 
+ * mono_print_method_from_ip
+ * @ip: an instruction pointer address
+ *
+ * This method is used from a debugger to get the name of the
+ * method at address @ip.
+ *
+ * This prints the name of the method at address @ip in the standard
+ * output.  Unlike mono_pmip which returns a string, this routine
+ * prints the value on the standard output. 
+ */
 void
 mono_print_method_from_ip (void *ip)
 {
        MonoJitInfo *ji;
        char *method;
-       char *source;
+       MonoDebugSourceLocation *source;
        MonoDomain *domain = mono_domain_get ();
        FindTrampUserData user_data;
        
@@ -254,14 +292,14 @@ mono_print_method_from_ip (void *ip)
                return;
        }
        method = mono_method_full_name (ji->method, TRUE);
-       source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
+       source = mono_debug_lookup_source_location (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), domain);
 
        g_print ("IP %p at offset 0x%x of method %s (%p %p)[domain %p - %s]\n", ip, (int)((char*)ip - (char*)ji->code_start), method, ji->code_start, (char*)ji->code_start + ji->code_size, domain, domain->friendly_name);
 
        if (source)
-               g_print ("%s\n", source);
+               g_print ("%s:%d\n", source->source_file, source->row);
 
-       g_free (source);
+       mono_debug_free_source_location (source);
        g_free (method);
 }
        
@@ -331,7 +369,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 } while (0)
 
 //#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
-#define UNVERIFIED do { goto unverified; } while (0)
+#define UNVERIFIED do { if (debug_options.break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
 
 /*
  * Basic blocks have two numeric identifiers:
@@ -339,19 +377,19 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
  * block_num: unique ID assigned at bblock creation
  */
 #define NEW_BBLOCK(cfg) (mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock)))
-#define ADD_BBLOCK(cfg,bbhash,b) do {  \
-               g_hash_table_insert (bbhash, (b)->cil_code, (b));       \
+#define ADD_BBLOCK(cfg,b) do { \
+               cfg->cil_offset_to_bb [(b)->cil_code - cfg->cil_start] = (b);   \
                (b)->block_num = cfg->num_bblocks++;    \
                (b)->real_offset = real_offset; \
        } while (0)
 
-#define GET_BBLOCK(cfg,bbhash,tblock,ip) do {  \
-               (tblock) = g_hash_table_lookup (bbhash, (ip));  \
+#define GET_BBLOCK(cfg,tblock,ip) do { \
+               (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
                if (!(tblock)) {        \
                        if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
                        (tblock) = NEW_BBLOCK (cfg);    \
                        (tblock)->cil_code = (ip);      \
-                       ADD_BBLOCK (cfg, (bbhash), (tblock));   \
+                       ADD_BBLOCK (cfg, (tblock));     \
                } \
        } while (0)
 
@@ -403,7 +441,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_PTR;                               \
        } while (0)
 
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
                MonoInst *group, *got_var, *got_loc;                    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
                (dest)->opcode = OP_GOT_ENTRY;                          \
@@ -413,7 +451,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
                (dest)->inst_p0 = got_var;                              \
                (dest)->inst_p1 = group;                                \
-               (dest)->type = (stack_type);                            \
+               (dest)->type = (stack_type);                    \
+        (dest)->klass = (stack_class);          \
        } while (0)
 
 #else
@@ -426,12 +465,13 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_PTR;       \
     } while (0)
 
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do {    \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->opcode = OP_AOTCONST;   \
                (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
                (dest)->inst_p1 = (gpointer)(patch_type); \
                (dest)->type = (stack_type);    \
+        (dest)->klass = (stack_class);          \
     } while (0)
 
 #endif
@@ -448,15 +488,15 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
 
-#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
+#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
 
-#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ)
+#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ, mono_defaults.monotype_class)
 
-#define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
+#define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
 
 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
                if (cfg->compile_aot) { \
-                       NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ); \
+                       NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
                } else { \
                        NEW_PCONST (cfg, args [0], (entry).blob); \
                } \
@@ -640,7 +680,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                ins->inst_i0 = cmp;     \
                MONO_ADD_INS (bblock, ins);     \
                ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
-               GET_BBLOCK (cfg, bbhash, tblock, target);               \
+               GET_BBLOCK (cfg, tblock, target);               \
                link_bblock (cfg, bblock, tblock);      \
                ins->inst_true_bb = tblock;     \
                CHECK_BBLOCK (target, ip, tblock);      \
@@ -649,7 +689,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                        ins->inst_false_bb = (next_block);      \
                        start_new_bblock = 1;   \
                } else {        \
-                       GET_BBLOCK (cfg, bbhash, tblock, ip);           \
+                       GET_BBLOCK (cfg, tblock, ip);           \
                        link_bblock (cfg, bblock, tblock);      \
                        ins->inst_false_bb = tblock;    \
                        start_new_bblock = 2;   \
@@ -682,11 +722,11 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                ins->opcode = (istrue)? CEE_BNE_UN: CEE_BEQ;    \
                MONO_ADD_INS (bblock, ins);     \
                ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
-               GET_BBLOCK (cfg, bbhash, tblock, target);               \
+               GET_BBLOCK (cfg, tblock, target);               \
                link_bblock (cfg, bblock, tblock);      \
                ins->inst_true_bb = tblock;     \
                CHECK_BBLOCK (target, ip, tblock);      \
-               GET_BBLOCK (cfg, bbhash, tblock, ip);           \
+               GET_BBLOCK (cfg, tblock, ip);           \
                link_bblock (cfg, bblock, tblock);      \
                ins->inst_false_bb = tblock;    \
                start_new_bblock = 2;   \
@@ -857,9 +897,11 @@ mono_find_block_region (MonoCompile *cfg, int offset)
                        return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
                           
                if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
-                       if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
+                       if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
                                return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
-                       else
+                       else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                               return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
+                       else if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE)
                                return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
                }
        }
@@ -889,7 +931,7 @@ mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *targe
                if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
                    (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
                        if (clause->flags == type) {
-                               handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
+                               handler = cfg->cil_offset_to_bb [clause->handler_offset];
                                g_assert (handler);
                                res = g_list_append (res, handler);
                        }
@@ -962,32 +1004,22 @@ df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
        }
 }
 
-typedef struct {
-       const guchar *code;
-       MonoBasicBlock *best;
-} PrevStruct;
-
-static void
-previous_foreach (gconstpointer key, gpointer val, gpointer data)
+static MonoBasicBlock*
+find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
 {
-       PrevStruct *p = data;
-       MonoBasicBlock *bb = val;
-       //printf ("FIDPREV %d %p  %p %p %p %p %d %d %d\n", bb->block_num, p->code, bb, p->best, bb->cil_code, p->best->cil_code,
-       //bb->method == p->best->method, bb->cil_code < p->code, bb->cil_code > p->best->cil_code);
-
-       if (bb->cil_code && bb->cil_code < p->code && bb->cil_code > p->best->cil_code)
-               p->best = bb;
-}
+       MonoBasicBlock *best = start;
+       int i;
 
-static MonoBasicBlock*
-find_previous (GHashTable *bb_hash, MonoBasicBlock *start, const guchar *code) {
-       PrevStruct p;
+       for (i = 0; i < n_bblocks; ++i) {
+               if (bblocks [i]) {
+                       MonoBasicBlock *bb = bblocks [i];
 
-       p.code = code;
-       p.best = start;
+                       if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
+                               best = bb;
+               }
+       }
 
-       g_hash_table_foreach (bb_hash, (GHFunc)previous_foreach, &p);
-       return p.best;
+       return best;
 }
 
 static void
@@ -1074,6 +1106,27 @@ reverse_branch_op (guint32 opcode)
        return opcode;
 }
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+static int
+condbr_to_fp_br (int opcode)
+{
+       switch (opcode) {
+       case CEE_BEQ: return OP_FBEQ;
+       case CEE_BGE: return OP_FBGE;
+       case CEE_BGT: return OP_FBGT;
+       case CEE_BLE: return OP_FBLE;
+       case CEE_BLT: return OP_FBLT;
+       case CEE_BNE_UN: return OP_FBNE_UN;
+       case CEE_BGE_UN: return OP_FBGE_UN;
+       case CEE_BGT_UN: return OP_FBGT_UN;
+       case CEE_BLE_UN: return OP_FBLE_UN;
+       case CEE_BLT_UN: return OP_FBLT_UN;
+       }
+       g_assert_not_reached ();
+       return 0;
+}
+#endif
+
 /*
  * Returns the type used in the eval stack when @type is loaded.
  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
@@ -1242,7 +1295,7 @@ ovf3ops_op_map [STACK_MAX] = {
 /* handles from CEE_CEQ to CEE_CLT_UN */
 static const guint16
 ceqops_op_map [STACK_MAX] = {
-       0, 0, OP_LCEQ-CEE_CEQ, OP_PCEQ-CEE_CEQ, OP_FCEQ-CEE_CEQ, OP_LCEQ-CEE_CEQ
+       0, 0, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_LCEQ-OP_CEQ
 };
 
 /*
@@ -1288,11 +1341,15 @@ type_from_op (MonoInst *ins) {
                        ins->opcode = OP_LCOMPARE;
                return;
        case OP_CEQ:
+               ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               ins->opcode += ceqops_op_map [ins->inst_i0->type];
+               return;
+               
        case OP_CGT:
        case OP_CGT_UN:
        case OP_CLT:
        case OP_CLT_UN:
-               ins->type = bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] ? STACK_I4: STACK_INV;
+               ins->type = (bin_comp_table [ins->inst_i0->type] [ins->inst_i1->type] & 1) ? STACK_I4: STACK_INV;
                ins->opcode += ceqops_op_map [ins->inst_i0->type];
                return;
        /* unops */
@@ -1352,8 +1409,12 @@ type_from_op (MonoInst *ins) {
                ins->type = STACK_PTR;
                switch (ins->inst_i0->type) {
                case STACK_I4:
+                       break;
                case STACK_PTR:
                case STACK_MP:
+#if SIZEOF_VOID_P == 8
+                       ins->opcode = OP_LCONV_TO_U;
+#endif
                        break;
                case STACK_I8:
                        ins->opcode = OP_LCONV_TO_U;
@@ -1383,7 +1444,7 @@ type_from_op (MonoInst *ins) {
                ins->type = STACK_R8;
                ins->opcode += unops_op_map [ins->inst_i0->type];
                return;
-       case CEE_CKFINITE:
+       case OP_CKFINITE:
                ins->type = STACK_R8;           
                return;
        case CEE_CONV_U2:
@@ -1561,7 +1622,7 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
        inst->inst_vtype = type;
        inst->klass = mono_class_from_mono_type (type);
        /* if set to 1 the variable is native */
-       inst->unused = 0;
+       inst->backend.is_pinvoke = 0;
 
        cfg->varinfo [num] = inst;
 
@@ -1569,7 +1630,8 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
        MONO_INIT_VARINFO (cfg->vars [num], num);
 
        cfg->num_varinfo++;
-       //g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
+       if (cfg->verbose_level > 2)
+               g_print ("created temp %d of type %s\n", num, mono_type_get_name (type));
        return inst;
 }
 
@@ -1613,8 +1675,23 @@ type_from_stack_type (MonoInst *ins) {
        case STACK_I8: return &mono_defaults.int64_class->byval_arg;
        case STACK_PTR: return &mono_defaults.int_class->byval_arg;
        case STACK_R8: return &mono_defaults.double_class->byval_arg;
-       case STACK_MP: return &mono_defaults.int_class->byval_arg;
-       case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
+       case STACK_MP:
+               /* 
+                * this if used to be commented without any specific reason, but
+                * it breaks #80235 when commented
+                */
+               if (ins->klass)
+                       return &ins->klass->this_arg;
+               else
+                       return &mono_defaults.object_class->this_arg;
+       case STACK_OBJ:
+               /* ins->klass may not be set for ldnull.
+                * Also, if we have a boxed valuetype, we want an object lass,
+                * not the valuetype class
+                */
+               if (ins->klass && !ins->klass->valuetype)
+                       return &ins->klass->byval_arg;
+               return &mono_defaults.object_class->byval_arg;
        case STACK_VTYPE: return &ins->klass->byval_arg;
        default:
                g_error ("stack type %d to montype not handled\n", ins->type);
@@ -1628,7 +1705,7 @@ mono_type_from_stack_type (MonoInst *ins) {
 }
 
 static MonoClass*
-array_access_to_klass (int opcode)
+array_access_to_klass (int opcode, MonoInst *array_obj)
 {
        switch (opcode) {
        case CEE_LDELEM_U1:
@@ -1659,8 +1736,13 @@ array_access_to_klass (int opcode)
        case CEE_STELEM_R8:
                return mono_defaults.double_class;
        case CEE_LDELEM_REF:
-       case CEE_STELEM_REF:
+       case CEE_STELEM_REF: {
+               MonoClass *klass = array_obj->klass;
+               /* FIXME: add assert */
+               if (klass && klass->rank)
+                       return klass->element_class;
                return mono_defaults.object_class;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -1686,7 +1768,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
        case CEE_BGT_UN:
        case CEE_BLE_UN:
        case CEE_BLT_UN:
-       case CEE_BR:
+       case OP_BR:
        case CEE_SWITCH:
                prev = bb->code;
                while (prev->next && prev->next != bb->last_ins)
@@ -1729,36 +1811,63 @@ mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest
 }
 
 /*
- * We try to share variables when possible
+ * merge_stacks:
+ *
+ * Merge stack state between two basic blocks according to Ecma 335, Partition III,
+ * section 1.8.1.1. Store the resulting stack state into stack_2.
+ * Returns: TRUE, if verification succeeds, FALSE otherwise.
+ * FIXME: We should store the stack state in a dedicated structure instead of in
+ * MonoInst's.
  */
-static MonoInst *
-mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
+static gboolean
+merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
 {
-       MonoInst *res;
-       int pos, vnum;
+       int i;
 
-       /* inlining can result in deeper stacks */ 
-       if (slot >= mono_method_get_header (cfg->method)->max_stack)
-               return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+       if (cfg->dont_verify_stack_merge)
+               return TRUE;
 
-       pos = ins->type - 1 + slot * STACK_MAX;
+       /* FIXME: Implement all checks from the spec */
 
-       switch (ins->type) {
-       case STACK_I4:
-       case STACK_I8:
-       case STACK_R8:
-       case STACK_PTR:
-       case STACK_MP:
-       case STACK_OBJ:
-               if ((vnum = cfg->intvars [pos]))
-                       return cfg->varinfo [vnum];
-               res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
-               cfg->intvars [pos] = res->inst_c0;
-               break;
-       default:
-               res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+       for (i = 0; i < size; ++i) {
+               MonoStackSlot *slot1 = &state_1 [i];
+               MonoStackSlot *slot2 = &state_2 [i];
+
+               if (slot1->type != slot2->type)
+                       return FALSE;
+
+               switch (slot1->type) {
+               case STACK_PTR:
+                       /* FIXME: Perform merge ? */
+                       /* klass == NULL means a native int */
+                       if (slot1->klass && slot2->klass) {
+                               if (slot1->klass != slot2->klass)
+                                       return FALSE;
+                       }
+                       break;
+               case STACK_MP:
+                       /* FIXME: Change this to an assert and fix the JIT to allways fill this */
+                       if (slot1->klass && slot2->klass) {
+                               if (slot1->klass != slot2->klass)
+                                       return FALSE;
+                       }
+                       break;
+               case STACK_OBJ: {
+                       MonoClass *klass1 = slot1->klass;
+                       MonoClass *klass2 = slot2->klass;
+
+                       if (!klass1) {
+                               /* slot1 is ldnull */
+                       } else if (!klass2) {
+                               /* slot2 is ldnull */
+                               slot2->klass = slot1->klass;
+                       }
+                       break;
+               }
+               }
        }
-       return res;
+
+       return TRUE;
 }
 
 /*
@@ -1771,18 +1880,64 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
  * which case its old value should be used.
  * A single joint point will use the same variables (stored in the array bb->out_stack or
  * bb->in_stack, if the basic block is before or after the joint point).
+ * If the stack merge fails at a join point, cfg->unverifiable is set.
  */
 static int
 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
        int i, bindex;
        MonoBasicBlock *outb;
        MonoInst *inst, **locals;
+       MonoStackSlot *stack_state;
        gboolean found;
 
        if (!count)
                return 0;
        if (cfg->verbose_level > 3)
                g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
+
+       stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
+       for (i = 0; i < count; ++i) {
+               stack_state [i].type = sp [i]->type;
+               stack_state [i].klass = sp [i]->klass;
+
+               /* Check that instructions other than ldnull have ins->klass set */
+               if (!cfg->dont_verify_stack_merge && (sp [i]->type == STACK_OBJ) && !((sp [i]->opcode == OP_PCONST) && sp [i]->inst_c0 == 0))
+                       g_assert (sp [i]->klass);
+       }
+
+       /* Perform verification and stack state merge */
+       for (i = 0; i < bb->out_count; ++i) {
+               outb = bb->out_bb [i];
+
+               /* exception handlers are linked, but they should not be considered for stack args */
+               if (outb->flags & BB_EXCEPTION_HANDLER)
+                       continue;
+               if (outb->stack_state) {
+                       gboolean verified;
+
+                       if (count != outb->in_scount) {
+                               cfg->unverifiable = TRUE;
+                               return 0;
+                       }
+                       verified = merge_stacks (cfg, stack_state, outb->stack_state, count);
+                       if (!verified) {
+                               cfg->unverifiable = TRUE;
+                               return 0;
+                       }
+
+                       if (cfg->verbose_level > 3) {
+                               int j;
+
+                               for (j = 0; j < count; ++j)
+                                       printf ("\tStack state of BB%d, slot %d=%d\n", outb->block_num, j, outb->stack_state [j].type);
+                       }
+               } else {
+                       /* Make a copy of the stack state */
+                       outb->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
+                       memcpy (outb->stack_state, stack_state, sizeof (MonoStackSlot) * count);
+               }
+       }
+
        if (!bb->out_scount) {
                bb->out_scount = count;
                //g_print ("bblock %d has out:", bb->block_num);
@@ -1814,11 +1969,16 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                                 * in the inlined methods do not inherit their in_stack from
                                 * the bblock they are inlined to. See bug #58863 for an
                                 * example.
+                                * This hack is disabled since it also prevents proper tracking of types.
                                 */
+#if 1
+                               bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+#else
                                if (cfg->inlined_method)
                                        bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
                                else
                                        bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
+#endif
                        }
                }
        }
@@ -1959,6 +2119,17 @@ mono_create_jump_table (MonoCompile *cfg, MonoInst *label, MonoBasicBlock **bbs,
        cfg->patch_info = ji;
 }
 
+static void
+mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
+{
+       if (cfg->compile_aot) {
+               MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
+               jump_info_token->image = image;
+               jump_info_token->token = token;
+               g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
+       }
+}
+
 /*
  * When we add a tree of instructions, we need to ensure the instructions currently
  * on the stack are executed before (like, if we load a value from a local).
@@ -2046,9 +2217,20 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                if (arg->type != STACK_I4 && arg->type != STACK_PTR)
                        return 1;
                return 0;
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_STRING:
        case MONO_TYPE_OBJECT:
+               if (arg->type != STACK_OBJ)
+                       return 1;
+               return 0;
+       case MONO_TYPE_STRING:
+               if (arg->type != STACK_OBJ)
+                       return 1;
+               /* ldnull has arg->klass unset */
+               /*if (arg->klass && arg->klass != mono_defaults.string_class) {
+                       G_BREAKPOINT ();
+                       return 1;
+               }*/
+               return 0;
+       case MONO_TYPE_CLASS:
        case MONO_TYPE_SZARRAY:
        case MONO_TYPE_ARRAY:    
                if (arg->type != STACK_OBJ)
@@ -2081,9 +2263,11 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
                return 0;
        case MONO_TYPE_GENERICINST:
                if (mono_type_generic_inst_is_valuetype (simple_type)) {
+                       klass = mono_class_from_mono_type (simple_type);
+                       if (klass->enumtype)
+                               return target_type_is_incompatible (cfg, klass->enum_basetype, arg);
                        if (arg->type != STACK_VTYPE)
                                return 1;
-                       klass = mono_class_from_mono_type (simple_type);
                        if (klass != arg->klass)
                                return 1;
                        return 0;
@@ -2224,7 +2408,7 @@ mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, M
                                MONO_ADD_INS (bblock, dummy_store);
 
                        /* we use this to allocate native sized structs */
-                       temp->unused = sig->pinvoke;
+                       temp->backend.is_pinvoke = sig->pinvoke;
 
                        NEW_TEMPLOADA (cfg, loada, temp->inst_c0);
                        if (call->inst.opcode == OP_VCALL)
@@ -2262,13 +2446,31 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        MonoInst *arg;
 
        MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
-       
+
+#ifdef MONO_ARCH_SOFT_FLOAT
+       /* we need to convert the r4 value to an int value */
+       {
+               int i;
+               for (i = 0; i < sig->param_count; ++i) {
+                       if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4) {
+                               MonoInst *iargs [1];
+                               int temp;
+                               iargs [0] = args [i + sig->hasthis];
+
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_fload_r4_arg, iargs, ip);
+                               NEW_TEMPLOAD (cfg, arg, temp);
+                               args [i + sig->hasthis] = arg;
+                       }
+               }
+       }
+#endif
+
        call->inst.cil_code = ip;
        call->args = args;
        call->signature = sig;
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
        type_to_eval_stack_type (sig->ret, &call->inst);
-       
+
        for (arg = call->out_args; arg;) {
                MonoInst *narg = arg->next;
                arg->next = NULL;
@@ -2434,42 +2636,6 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
        }
 }
 
-static MonoMethodSignature *
-mono_get_element_address_signature (int arity)
-{
-       static GHashTable *sighash = NULL;
-       MonoMethodSignature *res;
-       int i;
-
-       mono_jit_lock ();
-       if (!sighash) {
-               sighash = g_hash_table_new (NULL, NULL);
-       }
-       else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
-               LeaveCriticalSection (&jit_mutex);
-               return res;
-       }
-
-       res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
-
-       res->pinvoke = 1;
-#ifdef MONO_ARCH_VARARG_ICALLS
-       /* Only set this only some archs since not all backends can handle varargs+pinvoke */
-       res->call_convention = MONO_CALL_VARARG;
-#endif
-       res->params [0] = &mono_defaults.array_class->byval_arg; 
-       
-       for (i = 1; i <= arity; i++)
-               res->params [i] = &mono_defaults.int_class->byval_arg;
-
-       res->ret = &mono_defaults.int_class->byval_arg;
-
-       g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
-       mono_jit_unlock ();
-
-       return res;
-}
-
 static MonoMethodSignature *
 mono_get_array_new_va_signature (int arity)
 {
@@ -2494,6 +2660,10 @@ mono_get_array_new_va_signature (int arity)
        res->call_convention = MONO_CALL_VARARG;
 #endif
 
+#ifdef PLATFORM_WIN32
+       res->call_convention = MONO_CALL_C;
+#endif
+
        res->params [0] = &mono_defaults.int_class->byval_arg;  
        for (i = 0; i < arity; i++)
                res->params [i + 1] = &mono_defaults.int_class->byval_arg;
@@ -2506,6 +2676,65 @@ mono_get_array_new_va_signature (int arity)
        return res;
 }
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+static void
+handle_store_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, MonoInst *val, const unsigned char *ip)
+{
+       MonoInst *iargs [2];
+       iargs [0] = val;
+       iargs [1] = ptr;
+
+       mono_emit_jit_icall (cfg, bblock, mono_fstore_r4, iargs, ip);
+}
+
+static int
+handle_load_float (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *ptr, const unsigned char *ip)
+{
+       MonoInst *iargs [1];
+       iargs [0] = ptr;
+
+       return mono_emit_jit_icall (cfg, bblock, mono_fload_r4, iargs, ip);
+}
+
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
+                       int temp;       \
+                       NEW_LOCLOADA (cfg, (ins), (idx));       \
+                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
+                       NEW_TEMPLOAD (cfg, (ins), temp);        \
+               }       \
+       } while (0)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (header->locals [(idx)]->type == MONO_TYPE_R4 && !header->locals [(idx)]->byref) {   \
+                       int temp;       \
+                       NEW_LOCLOADA (cfg, (ins), (idx));       \
+                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
+                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
+               }       \
+       } while (0)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+                       int temp;       \
+                       NEW_ARGLOADA (cfg, (ins), (idx));       \
+                       temp = handle_load_float (cfg, bblock, (ins), (ip));    \
+                       NEW_TEMPLOAD (cfg, (ins), temp);        \
+               }       \
+       } while (0)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip) do {\
+               if (param_types [(idx)]->type == MONO_TYPE_R4 && !param_types [(idx)]->byref) { \
+                       int temp;       \
+                       NEW_ARGLOADA (cfg, (ins), (idx));       \
+                       handle_store_float (cfg, bblock, (ins), *sp, (ip));     \
+                       MONO_INST_NEW (cfg, (ins), OP_NOP);     \
+               }       \
+       } while (0)
+#else
+#define LDLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STLOC_SOFT_FLOAT(cfg,ins,idx,ip)
+#define LDARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#define STARG_SOFT_FLOAT(cfg,ins,idx,ip)
+#endif
+
 static MonoMethod*
 get_memcpy_method (void)
 {
@@ -2560,7 +2789,7 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
                inst->inst_left = dest;
                inst->inst_right = src;
                inst->cil_code = ip;
-               inst->unused = n;
+               inst->backend.size = n;
                MONO_ADD_INS (bblock, inst);
                return;
        }
@@ -2617,7 +2846,7 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
                if (n <= sizeof (gpointer) * 5) {
                        ins->opcode = OP_MEMSET;
                        ins->inst_imm = 0;
-                       ins->unused = n;
+                       ins->backend.size = n;
                        MONO_ADD_INS (bblock, ins);
                        break;
                }
@@ -2707,6 +2936,11 @@ handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const gucha
        vstore->inst_left = add;
        vstore->inst_right = val;
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+       if (vstore->opcode == CEE_STIND_R4) {
+               handle_store_float (cfg, bblock, add, val, ip);
+       } else
+#endif
        if (vstore->opcode == CEE_STOBJ) {
                handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
        } else
@@ -2727,19 +2961,20 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
        /* Need to register the icall so it gets an icall wrapper */
        sprintf (icall_name, "ves_array_new_va_%d", rank);
 
+       mono_jit_lock ();
        info = mono_find_jit_icall_by_name (icall_name);
        if (info == NULL) {
                esig = mono_get_array_new_va_signature (rank);
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
 
-               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               mono_jit_unlock ();
        }
+       mono_jit_unlock ();
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
 
+       /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
        return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, TRUE, FALSE);
 }
 
@@ -2783,8 +3018,6 @@ mini_class_is_system_array (MonoClass *klass)
 {
        if (klass->parent == mono_defaults.array_class)
                return TRUE;
-       else if (mono_defaults.generic_array_class && klass->parent && klass->parent->generic_class)
-               return klass->parent->generic_class->container_class == mono_defaults.generic_array_class;
        else
                return FALSE;
 }
@@ -2815,11 +3048,21 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
            MONO_TYPE_ISSTRUCT (signature->ret))
                return FALSE;
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+       /* this complicates things, fix later */
+       if (signature->ret->type == MONO_TYPE_R4)
+               return FALSE;
+#endif
        /* its not worth to inline methods with valuetype arguments?? */
        for (i = 0; i < signature->param_count; i++) {
                if (MONO_TYPE_ISSTRUCT (signature->params [i])) {
                        return FALSE;
                }
+#ifdef MONO_ARCH_SOFT_FLOAT
+               /* this complicates things, fix later */
+               if (!signature->params [i]->byref && signature->params [i]->type == MONO_TYPE_R4)
+                       return FALSE;
+#endif
        }
 
        /*
@@ -2831,8 +3074,14 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (!(cfg->opt & MONO_OPT_SHARED)) {
                vtable = mono_class_vtable (cfg->domain, method->klass);
                if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
-                       if (cfg->run_cctors)
+                       if (cfg->run_cctors) {
+                               /* This makes so that inline cannot trigger */
+                               /* .cctors: too many apps depend on them */
+                               /* running with a specific order... */
+                               if (! vtable->initialized)
+                                       return FALSE;
                                mono_runtime_class_init (vtable);
+                       }
                }
                else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
                        return FALSE;
@@ -2889,10 +3138,8 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
 {
        int temp, rank;
        MonoInst *addr;
-       MonoMethodSignature *esig;
-       char icall_name [256];
-       char *name;
-       MonoJitICallInfo *info;
+       MonoMethod *addr_method;
+       int element_size;
 
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
@@ -2907,7 +3154,7 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        }
 
        if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
-#ifdef MONO_ARCH_EMULATE_MUL_DIV
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(MONO_ARCH_NO_EMULATE_MUL)
                /* OP_LDELEMA2D depends on OP_LMUL */
 #else
                MonoInst *indexes;
@@ -2917,43 +3164,47 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                addr->inst_right = indexes;
                addr->cil_code = ip;
                addr->type = STACK_MP;
-               addr->klass = cmethod->klass;
+               addr->klass = cmethod->klass->element_class;
                return addr;
 #endif
        }
 
-       /* Need to register the icall so it gets an icall wrapper */
-       sprintf (icall_name, "ves_array_element_address_%d", rank);
-
-       info = mono_find_jit_icall_by_name (icall_name);
-       if (info == NULL) {
-               esig = mono_get_element_address_signature (rank);
-               name = g_strdup (icall_name);
-               info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
-
-               mono_jit_lock ();
-               g_hash_table_insert (jit_icall_name_hash, name, name);
-               mono_jit_unlock ();
-       }
-
-       temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
-       cfg->flags |= MONO_CFG_HAS_VARARGS;
-
+       element_size = mono_class_array_element_size (cmethod->klass->element_class);
+       addr_method = mono_marshal_get_array_address (rank, element_size);
+       temp = mono_emit_method_call_spilled (cfg, bblock, addr_method, addr_method->signature, sp, ip, NULL);
        NEW_TEMPLOAD (cfg, addr, temp);
        return addr;
+
 }
 
-MonoJitICallInfo **emul_opcode_map = NULL;
+static MonoJitICallInfo **emul_opcode_map = NULL;
 
 MonoJitICallInfo *
 mono_find_jit_opcode_emulation (int opcode)
 {
+       g_assert (opcode >= 0 && opcode <= OP_LAST);
        if  (emul_opcode_map)
                return emul_opcode_map [opcode];
        else
                return NULL;
 }
 
+static int
+is_signed_regsize_type (MonoType *type)
+{
+       switch (type->type) {
+       case MONO_TYPE_I1:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_I4:
+#if SIZEOF_VOID_P == 8
+       /*case MONO_TYPE_I8: this requires different opcodes in inssel.brg */
+#endif
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}
+
 static MonoInst*
 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -2998,7 +3249,7 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        return ins;
 #endif
                } else if (strcmp (cmethod->name, ".ctor") == 0) {
-                       MONO_INST_NEW (cfg, ins, CEE_NOP);
+                       MONO_INST_NEW (cfg, ins, OP_NOP);
                        return ins;
                } else
                        return NULL;
@@ -3046,6 +3297,37 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                store->inst_left = args [2];
                store->inst_right = load;
                return store;
+       } else if (cmethod->klass == mono_defaults.math_class) {
+               if (strcmp (cmethod->name, "Min") == 0) {
+                       if (is_signed_regsize_type (fsig->params [0])) {
+                               MONO_INST_NEW (cfg, ins, OP_MIN);
+                               ins->inst_i0 = args [0];
+                               ins->inst_i1 = args [1];
+                               return ins;
+                       }
+               } else if (strcmp (cmethod->name, "Max") == 0) {
+                       if (is_signed_regsize_type (fsig->params [0])) {
+                               MONO_INST_NEW (cfg, ins, OP_MAX);
+                               ins->inst_i0 = args [0];
+                               ins->inst_i1 = args [1];
+                               return ins;
+                       }
+               }
+       } else if (cmethod->klass->image == mono_defaults.corlib) {
+               if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
+                               && strcmp (cmethod->klass->name, "Debugger") == 0) {
+                       MONO_INST_NEW (cfg, ins, OP_BREAK);
+                       return ins;
+               }
+               if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
+                               && strcmp (cmethod->klass->name, "Environment") == 0) {
+#ifdef PLATFORM_WIN32
+                       NEW_ICONST (cfg, ins, 1);
+#else
+                       NEW_ICONST (cfg, ins, 0);
+#endif
+                       return ins;
+               }
        }
 
        return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
@@ -3093,8 +3375,8 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                sp++;
        }
 }
-#define MONO_INLINE_CALLED_LIMITED_METHODS 1
-#define MONO_INLINE_CALLER_LIMITED_METHODS 1
+#define MONO_INLINE_CALLED_LIMITED_METHODS 0
+#define MONO_INLINE_CALLER_LIMITED_METHODS 0
 
 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
 static char*
@@ -3153,6 +3435,10 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        MonoBasicBlock *ebblock, *sbblock;
        int i, costs, new_locals_offset;
        MonoMethod *prev_inlined_method;
+       MonoBasicBlock **prev_cil_offset_to_bb;
+       unsigned char* prev_cil_start;
+       guint32 prev_cil_offset_to_bb_len;
+
 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
        if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
                return 0;
@@ -3162,6 +3448,9 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                return 0;
 #endif
 
+       if (bblock->out_of_line && !inline_allways)
+               return 0;
+
        if (cfg->verbose_level > 2)
                g_print ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
 
@@ -3191,10 +3480,16 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 
        prev_inlined_method = cfg->inlined_method;
        cfg->inlined_method = cmethod;
+       prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
+       prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
+       prev_cil_start = cfg->cil_start;
 
        costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
 
        cfg->inlined_method = prev_inlined_method;
+       cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
+       cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
+       cfg->cil_start = prev_cil_start;
 
        if ((costs >= 0 && costs < 60) || inline_allways) {
                if (cfg->verbose_level > 2)
@@ -3203,7 +3498,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
                mono_jit_stats.inlined_methods++;
 
                /* always add some code to avoid block split failures */
-               MONO_INST_NEW (cfg, ins, CEE_NOP);
+               MONO_INST_NEW (cfg, ins, OP_NOP);
                MONO_ADD_INS (bblock, ins);
                ins->cil_code = ip;
 
@@ -3245,8 +3540,6 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
  * or through repeated runs where the compiler applies offline the optimizations to 
  * each method and then decides if it was worth it.
  *
- * TODO:
- * * consider using an array instead of an hash table (bb_hash)
  */
 
 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
@@ -3255,21 +3548,22 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
-
+#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
+#define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
 
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
 
-static gboolean
+static inline gboolean
 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
 {
-       MonoBasicBlock *b = g_hash_table_lookup (cfg->bb_hash, ip);
+       MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
        
        return b == NULL || b == bb;
 }
 
 static int
-get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
+get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
 {
        unsigned char *ip = start;
        unsigned char *target;
@@ -3307,17 +3601,17 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        break;
                case MonoShortInlineBrTarget:
                        target = start + cli_addr + 2 + (signed char)ip [1];
-                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       GET_BBLOCK (cfg, bblock, target);
                        ip += 2;
                        if (ip < end)
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                        break;
                case MonoInlineBrTarget:
                        target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
-                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       GET_BBLOCK (cfg, bblock, target);
                        ip += 5;
                        if (ip < end)
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                        break;
                case MonoInlineSwitch: {
                        guint32 n = read32 (ip + 1);
@@ -3325,11 +3619,11 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        ip += 5;
                        cli_addr += 5 + 4 * n;
                        target = start + cli_addr;
-                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       GET_BBLOCK (cfg, bblock, target);
                        
                        for (j = 0; j < n; ++j) {
                                target = start + cli_addr + (gint32)read32 (ip);
-                               GET_BBLOCK (cfg, bbhash, bblock, target);
+                               GET_BBLOCK (cfg, bblock, target);
                                ip += 4;
                        }
                        break;
@@ -3348,7 +3642,7 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                        /* Find the start of the bblock containing the throw */
                        bblock = NULL;
                        while ((bb_start >= start) && !bblock) {
-                               bblock = g_hash_table_lookup (bbhash, (bb_start));
+                               bblock = cfg->cil_offset_to_bb [(bb_start) - start];
                                bb_start --;
                        }
                        if (bblock)
@@ -3410,12 +3704,22 @@ mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
        return klass;
 }
 
+/*
+ * Returns TRUE if the JIT should abort inlining because "callee"
+ * is influenced by security attributes.
+ */
 static
-void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
+gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
 {
-       guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
+       guint32 result;
+       
+       if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
+               return TRUE;
+       }
+       
+       result = mono_declsec_linkdemand (cfg->domain, caller, callee);
        if (result == MONO_JIT_SECURITY_OK)
-               return;
+               return FALSE;
 
        if (result == MONO_JIT_LINKDEMAND_ECMA) {
                /* Generate code to throw a SecurityException before the actual call/link */
@@ -3434,6 +3738,8 @@ void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
                cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
                cfg->exception_data = result;
        }
+       
+       return FALSE;
 }
 
 static gboolean
@@ -3466,6 +3772,13 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
 static gboolean
 can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
 {
+       if (access_klass->generic_class && member_klass->generic_class &&
+           access_klass->generic_class->container_class && member_klass->generic_class->container_class) {
+               if (can_access_member (access_klass->generic_class->container_class,
+                                      member_klass->generic_class->container_class, access_level))
+                       return TRUE;
+       }
+
        /* Partition I 8.5.3.2 */
        /* the access level values are the same for fields and methods */
        switch (access_level) {
@@ -3476,7 +3789,7 @@ can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_
                return access_klass == member_klass;
        case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
                if (mono_class_has_parent (access_klass, member_klass) &&
-                               can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
+                   can_access_internals (access_klass->image->assembly, member_klass->image->assembly))
                        return TRUE;
                return FALSE;
        case FIELD_ATTRIBUTE_ASSEMBLY:
@@ -3537,6 +3850,75 @@ can_access_method (MonoMethod *method, MonoMethod *called)
        return can;
 }
 
+/*
+ * Check that the IL instructions at ip are the array initialization
+ * sequence and return the pointer to the data and the size.
+ */
+static const char*
+initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoInst *newarr, int *out_size)
+{
+       /*
+        * newarr[System.Int32]
+        * dup
+        * ldtoken field valuetype ...
+        * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
+        */
+       if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
+               MonoClass *klass = newarr->inst_newa_class;
+               guint32 token = read32 (ip + 7);
+               guint32 rva, field_index;
+               const char *data_ptr;
+               int size = 0;
+               MonoMethod *cmethod;
+
+               if (newarr->inst_newa_len->opcode != OP_ICONST)
+                       return NULL;
+               cmethod = mini_get_method (method, token, NULL, NULL);
+               if (!cmethod)
+                       return NULL;
+               if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
+                       return NULL;
+               switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+                       size = 1; break;
+               /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+                       size = 2; break;
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+               case MONO_TYPE_R4:
+                       size = 4; break;
+               case MONO_TYPE_R8:
+#ifdef ARM_FPU_FPA
+                       return NULL; /* stupid ARM FP swapped format */
+#endif
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+                       size = 8; break;
+#endif
+               default:
+                       return NULL;
+               }
+               size *= newarr->inst_newa_len->inst_c0;
+               *out_size = size;
+               /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
+               field_index = read32 (ip + 2) & 0xffffff;
+               mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
+               data_ptr = mono_image_rva_map (method->klass->image, rva);
+               /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
+               /* for aot code we do the lookup on load */
+               if (aot && data_ptr)
+                       return GUINT_TO_POINTER (rva);
+               return data_ptr;
+       }
+       return NULL;
+}
+
 /*
  * mono_method_to_ir: translates IL into basic blocks containing trees
  */
@@ -3548,7 +3930,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
        MonoInst *ins, **sp, **stack_start;
        MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
-       GHashTable *bbhash;
        MonoMethod *cmethod;
        MonoInst **arg_array;
        MonoMethodHeader *header;
@@ -3579,35 +3960,41 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
 
-       /* still some type unsefety issues in marshal wrappers... (unknown is PtrToStructure) */
+       /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
        dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
        dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
        dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
 
+       /* Not turned on yet */
+       cfg->dont_verify_stack_merge = TRUE;
+
        image = method->klass->image;
        header = mono_method_get_header (method);
        generic_container = method->generic_container;
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
        ip = (unsigned char*)header->code;
+       cfg->cil_start = ip;
        end = ip + header->code_size;
        mono_jit_stats.cil_code_size += header->code_size;
 
        if (sig->is_inflated)
-               generic_context = ((MonoMethodInflated *) method)->context;
+               generic_context = mono_method_get_context (method);
        else if (generic_container)
                generic_context = &generic_container->context;
 
        g_assert (!sig->has_type_parameters);
 
-       if (cfg->method == method) {
+       if (cfg->method == method)
                real_offset = 0;
-               bbhash = cfg->bb_hash;
-       } else {
+       else
                real_offset = inline_offset;
-               bbhash = g_hash_table_new (g_direct_hash, NULL);
-       }
+
+       cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
+       cfg->cil_offset_to_bb_len = header->code_size;
 
        if (cfg->verbose_level > 2)
                g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
@@ -3643,9 +4030,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                for (i = 0; i < header->num_clauses; ++i) {
                        MonoBasicBlock *try_bb;
                        MonoExceptionClause *clause = &header->clauses [i];
-                       GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+                       GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
                        try_bb->real_offset = clause->try_offset;
-                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
+                       GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
                        tblock->flags |= BB_EXCEPTION_HANDLER;
 
@@ -3655,7 +4042,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
 
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
-                           clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                           clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
+                           clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
                                MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                MONO_ADD_INS (tblock, ins);
 
@@ -3679,6 +4067,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                tblock->in_scount = 1;
                                tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
                                tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
+                               tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
+                               tblock->stack_state [0].type = STACK_OBJ;
+                               /* FIXME? */
+                               tblock->stack_state [0].klass = mono_defaults.object_class;
 
                                /* 
                                 * Add a dummy use for the exvar so its liveness info will be
@@ -3689,10 +4081,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_ADD_INS (tblock, dummy_use);
                                
                                if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
-                                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->data.filter_offset);
+                                       GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
                                        tblock->real_offset = clause->data.filter_offset;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
+                                       tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
+                                       tblock->stack_state [0].type = STACK_OBJ;
+                                       /* FIXME? */
+                                       tblock->stack_state [0].klass = mono_defaults.object_class;
+
                                        /* The filter block shares the exvar with the handler block */
                                        tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
                                        MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
@@ -3709,12 +4106,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        bblock = NEW_BBLOCK (cfg);
        bblock->cil_code = ip;
 
-       ADD_BBLOCK (cfg, bbhash, bblock);
+       ADD_BBLOCK (cfg, bblock);
 
        if (cfg->method == method) {
                breakpoint_id = mono_debugger_method_has_breakpoint (method);
                if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
-                       MONO_INST_NEW (cfg, ins, CEE_BREAK);
+                       MONO_INST_NEW (cfg, ins, OP_BREAK);
                        MONO_ADD_INS (bblock, ins);
                }
        }
@@ -3755,7 +4152,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || mono_compile_aot || security || pinvoke) {
+       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
                /* we use a separate basic block for the initialization code */
                cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
                init_localsbb->real_offset = real_offset;
@@ -3804,7 +4201,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                mono_emit_method_call_spilled (cfg, init_localsbb, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, ip, NULL);
        }
 
-       if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
+       if (get_basic_blocks (cfg, header, real_offset, ip, end, &err_pos)) {
                ip = err_pos;
                UNVERIFIED;
        }
@@ -3860,7 +4257,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (start_new_bblock == 2) {
                                g_assert (ip == tblock->cil_code);
                        } else {
-                               GET_BBLOCK (cfg, bbhash, tblock, ip);
+                               GET_BBLOCK (cfg, tblock, ip);
                        }
                        bblock->next_bb = tblock;
                        bblock = tblock;
@@ -3874,11 +4271,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        g_slist_free (class_inits);
                        class_inits = NULL;
                } else {
-                       if ((tblock = g_hash_table_lookup (bbhash, ip)) && (tblock != bblock)) {
+                       if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
                                link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                        sp = stack_start;
+                                       CHECK_UNVERIFIABLE (cfg);
                                }
                                bblock->next_bb = tblock;
                                bblock = tblock;
@@ -3920,8 +4318,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                switch (*ip) {
                case CEE_NOP:
+                       MONO_INST_NEW (cfg, ins, OP_NOP);
+                       ins->cil_code = ip++;
+                       MONO_ADD_INS (bblock, ins);
+                       break;
                case CEE_BREAK:
-                       MONO_INST_NEW (cfg, ins, *ip);
+                       MONO_INST_NEW (cfg, ins, OP_BREAK);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        break;
@@ -3933,6 +4335,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = (*ip)-CEE_LDARG_0;
                        CHECK_ARG (n);
                        NEW_ARGLOAD (cfg, ins, n);
+                       LDARG_SOFT_FLOAT (cfg, ins, n, ip);
                        ins->cil_code = ip++;
                        *sp++ = ins;
                        break;
@@ -3944,6 +4347,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = (*ip)-CEE_LDLOC_0;
                        CHECK_LOCAL (n);
                        NEW_LOCLOAD (cfg, ins, n);
+                       LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
                        ins->cil_code = ip++;
                        *sp++ = ins;
                        break;
@@ -3960,6 +4364,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
                                UNVERIFIED;
+                       STLOC_SOFT_FLOAT (cfg, ins, n, ip);
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, n);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -3973,6 +4378,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        CHECK_ARG (ip [1]);
                        NEW_ARGLOAD (cfg, ins, ip [1]);
+                       LDARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
@@ -3996,6 +4402,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
                                UNVERIFIED;
+                       STARG_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_ARGLOADA (cfg, ins, ip [1]);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -4008,6 +4415,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        CHECK_LOCAL (ip [1]);
                        NEW_LOCLOAD (cfg, ins, ip [1]);
+                       LDLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 2;
@@ -4031,6 +4439,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip;
                        if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
                                UNVERIFIED;
+                       STLOC_SOFT_FLOAT (cfg, ins, ip [1], ip);
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, ip [1]);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -4185,7 +4594,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        if (stack_start != sp)
                                UNVERIFIED;
-                       MONO_INST_NEW (cfg, ins, CEE_JMP);
+                       MONO_INST_NEW (cfg, ins, OP_JMP);
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
                        cmethod = mini_get_method (method, token, NULL, generic_context);
@@ -4194,7 +4603,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
 
                        if (mono_use_security_manager) {
-                               check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                       INLINE_FAILURE;
                        }
 
                        ins->inst_p0 = cmethod;
@@ -4225,18 +4635,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                n = fsig->param_count + fsig->hasthis;
                        } else {
+                               MonoMethod *cil_method;
+                               
                                if (method->wrapper_type != MONO_WRAPPER_NONE) {
                                        cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
+                                       cil_method = cmethod;
                                } else if (constrained_call) {
-                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context);
+                                       cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
                                        cmethod = mono_get_inflated_method (cmethod);
+                                       cil_method = cmethod;
                                } else {
                                        cmethod = mini_get_method (method, token, NULL, generic_context);
+                                       cil_method = cmethod;
                                }
 
                                if (!cmethod)
                                        goto load_error;
-                               if (!dont_verify && !can_access_method (method, cmethod))
+                               if (!dont_verify && !cfg->skip_visibility && !can_access_method (method, cil_method))
                                        UNVERIFIED;
 
                                if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
@@ -4257,10 +4672,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
                                }
 
+                               mono_save_token_info (cfg, image, token, cmethod);
+
                                n = fsig->param_count + fsig->hasthis;
 
                                if (mono_use_security_manager) {
-                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                                       if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                               INLINE_FAILURE;
                                }
 
                                if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
@@ -4313,6 +4731,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->cil_code = ip;
                                        ins->inst_i0 = sp [0];
                                        ins->type = STACK_OBJ;
+                                       ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
                                        sp [0] = ins;
                                } else if (cmethod->klass->valuetype)
                                        virtual = 0;
@@ -4327,8 +4746,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                            !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
                              cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
                            mono_method_signature (cmethod)->generic_param_count) {
-                               MonoInst *this_temp, *store;
-                               MonoInst *iargs [3];
+                               MonoInst *this_temp, *this_arg_temp, *store;
+                               MonoInst *iargs [4];
 
                                g_assert (mono_method_signature (cmethod)->is_inflated);
                                /* Prevent inlining of methods that contain indirect calls */
@@ -4341,13 +4760,20 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                store->cil_code = ip;
                                MONO_ADD_INS (bblock, store);
 
+                               /* FIXME: This should be a managed pointer */
+                               this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                               this_arg_temp->cil_code = ip;
+
+                               /* Because of the PCONST below */
+                               cfg->disable_aot = TRUE;
                                NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
-                               NEW_PCONST (cfg, iargs [1], cmethod);
-                               NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
+                               NEW_METHODCONST (cfg, iargs [1], cmethod);
+                               NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
+                               NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
                                temp = mono_emit_jit_icall (cfg, bblock, mono_helper_compile_generic_method, iargs, ip);
 
                                NEW_TEMPLOAD (cfg, addr, temp);
-                               NEW_TEMPLOAD (cfg, sp [0], this_temp->inst_c0);
+                               NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
 
                                if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
                                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -4355,23 +4781,36 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                ip += 5;
+                               ins_flag = 0;
                                break;
                        }
 
                        if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
                                 (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
                                int i;
+
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
                                INLINE_FAILURE;
                                /* FIXME: This assumes the two methods has the same number and type of arguments */
+                               /*
+                                * We implement tail calls by storing the actual arguments into the 
+                                * argument variables, then emitting a OP_JMP. Since the actual arguments
+                                * can refer to the arg variables, we have to spill them.
+                                */
+                               handle_loaded_temps (cfg, bblock, sp, sp + n);
                                for (i = 0; i < n; ++i) {
+                                       /* Prevent argument from being register allocated */
+                                       arg_array [i]->flags |= MONO_INST_VOLATILE;
+
                                        /* Check if argument is the same */
+                                       /* 
+                                        * FIXME: This loses liveness info, so it can only be done if the
+                                        * argument is not register allocated.
+                                        */
                                        NEW_ARGLOAD (cfg, ins, i);
                                        if ((ins->opcode == sp [i]->opcode) && (ins->inst_i0 == sp [i]->inst_i0))
                                                continue;
 
-                                       /* Prevent argument from being register allocated */
-                                       arg_array [i]->flags |= MONO_INST_VOLATILE;
                                        NEW_ARGSTORE (cfg, ins, i, sp [i]);
                                        ins->cil_code = ip;
                                        if (ins->opcode == CEE_STOBJ) {
@@ -4381,7 +4820,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        else
                                                MONO_ADD_INS (bblock, ins);
                                }
-                               MONO_INST_NEW (cfg, ins, CEE_JMP);
+                               MONO_INST_NEW (cfg, ins, OP_JMP);
                                ins->cil_code = ip;
                                ins->inst_p0 = cmethod;
                                ins->inst_p1 = arg_array [0];
@@ -4405,6 +4844,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                ip += 5;
+                               ins_flag = 0;
                                break;
                        }
 
@@ -4430,7 +4870,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ip += 5;
                                        real_offset += 5;
 
-                                       GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                       GET_BBLOCK (cfg, bblock, ip);
                                        ebblock->next_bb = bblock;
                                        link_bblock (cfg, ebblock, bblock);
 
@@ -4442,6 +4882,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        bblock = ebblock;
 
                                        inline_costs += costs;
+                                       ins_flag = 0;
                                        break;
                                }
                        }
@@ -4467,7 +4908,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ins->cil_code = ip;
                                                MONO_ADD_INS (bblock, ins);
                                        }
-                                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                                       MONO_INST_NEW (cfg, ins, OP_BR);
                                        ins->cil_code = ip;
                                        MONO_ADD_INS (bblock, ins);
                                        tblock = start_bblock->out_bb [0];
@@ -4480,7 +4921,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 6;
                                        else
                                                ip += 5;
-
+                                       ins_flag = 0;
                                        break;
                                }
                        }
@@ -4567,6 +5008,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        ip += 5;
+                       ins_flag = 0;
                        break;
                }
                case CEE_RET:
@@ -4592,7 +5034,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        g_assert (!return_var);
                                        CHECK_STACK (1);
                                        --sp;
-                                       MONO_INST_NEW (cfg, ins, CEE_NOP);
+                                       MONO_INST_NEW (cfg, ins, OP_NOP);
                                        ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_RETLOADA (cfg, ins);
@@ -4609,7 +5051,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        if (sp != stack_start)
                                UNVERIFIED;
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip++;
                        ins->inst_target_bb = end_bblock;
                        MONO_ADD_INS (bblock, ins);
@@ -4618,18 +5060,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_BR_S:
                        CHECK_OPSIZE (2);
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        target = ip + 1 + (signed char)(*ip);
                        ++ip;
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        CHECK_BBLOCK (target, ip, tblock);
                        ins->inst_target_bb = tblock;
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        start_new_bblock = 1;
                        inline_costs += BRANCH_COST;
@@ -4648,6 +5091,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4667,27 +5111,44 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip++;
                        target = ip + 1 + *(signed char*)ip;
                        ip++;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+                               ins->opcode = condbr_to_fp_br (ins->opcode);
+                               sp -= 2;
+                               ins->inst_left = sp [0];
+                               ins->inst_right = sp [1];
+                               ins->type = STACK_I4;
+                               *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+                               MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+                               ADD_UNCOND (TRUE);
+                       } else {
+                               ADD_BINCOND (NULL);
+                       }
+#else
                        ADD_BINCOND (NULL);
+#endif
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
                case CEE_BR:
                        CHECK_OPSIZE (5);
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip++;
                        MONO_ADD_INS (bblock, ins);
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        CHECK_BBLOCK (target, ip, tblock);
                        ins->inst_target_bb = tblock;
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        start_new_bblock = 1;
                        inline_costs += BRANCH_COST;
@@ -4706,6 +5167,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4725,10 +5187,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip++;
                        target = ip + 4 + (gint32)read32(ip);
                        ip += 4;
-                       ADD_BINCOND(NULL);
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (sp [-1]->type == STACK_R8 || sp [-2]->type == STACK_R8) {
+                               ins->opcode = condbr_to_fp_br (ins->opcode);
+                               sp -= 2;
+                               ins->inst_left = sp [0];
+                               ins->inst_right = sp [1];
+                               ins->type = STACK_I4;
+                               *sp++ = emit_tree (cfg, bblock, ins, ins->cil_code);
+                               MONO_INST_NEW (cfg, ins, CEE_BRTRUE);
+                               ADD_UNCOND (TRUE);
+                       } else {
+                               ADD_BINCOND (NULL);
+                       }
+#else
+                       ADD_BINCOND (NULL);
+#endif
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4746,14 +5224,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (n * sizeof (guint32));
                        target = ip + n * sizeof (guint32);
                        MONO_ADD_INS (bblock, ins);
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        ins->klass = GUINT_TO_POINTER (n);
                        ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (n + 1));
                        ins->inst_many_bb [n] = tblock;
 
                        for (i = 0; i < n; ++i) {
-                               GET_BBLOCK (cfg, bbhash, tblock, target + (gint32)read32(ip));
+                               GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
                                link_bblock (cfg, bblock, tblock);
                                ins->inst_many_bb [i] = tblock;
                                ip += 4;
@@ -4761,6 +5239,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -4786,6 +5265,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->type = ldind_type [*ip - CEE_LDIND_I1];
                        ins->flags |= ins_flag;
                        ins_flag = 0;
+                       if (ins->type == STACK_OBJ)
+                               ins->klass = mono_defaults.object_class;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_LDIND_R4) {
+                               int temp;
+                               --sp;
+                               temp = handle_load_float (cfg, bblock, ins->inst_i0, ip);
+                               NEW_TEMPLOAD (cfg, *sp, temp);
+                               sp++;
+                       }
+#endif
                        ++ip;
                        break;
                case CEE_STIND_REF:
@@ -4796,6 +5286,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_STIND_R4:
                case CEE_STIND_R8:
                        CHECK_STACK (2);
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_STIND_R4) {
+                               sp -= 2;
+                               handle_store_float (cfg, bblock, sp [0], sp [1], ip);
+                               ip++;
+                               break;
+                       }
+#endif
 #if HAVE_WRITE_BARRIERS
                        if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
                                /* insert call to write barrier */
@@ -4946,8 +5444,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        sp -= 2;
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MonoInst *store, *load;
@@ -4955,6 +5452,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                load->cil_code = ip;
                                load->inst_i0 = sp [1];
                                load->type = STACK_OBJ;
+                               load->klass = klass;
                                load->flags |= ins_flag;
                                MONO_INST_NEW (cfg, store, CEE_STIND_REF);
                                store->cil_code = ip;
@@ -4971,7 +5469,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        copy->inst_left = sp [0];
                                        copy->inst_right = sp [1];
                                        copy->cil_code = ip;
-                                       copy->unused = n;
+                                       copy->backend.size = n;
                                        MONO_ADD_INS (bblock, copy);
                                } else {
                                        MonoMethod *memcpy_method = get_memcpy_method ();
@@ -4996,13 +5494,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
                                ins->cil_code = ip;
                                ins->inst_i0 = sp [0];
                                ins->type = STACK_OBJ;
+                               ins->klass = klass;
                                ins->flags |= ins_flag;
                                ins_flag = 0;
                                *sp++ = ins;
@@ -5052,7 +5550,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                copy->inst_left = iargs [0];
                                copy->inst_right = *sp;
                                copy->cil_code = ip;
-                               copy->unused = n;
+                               copy->backend.size = n;
                                MONO_ADD_INS (bblock, copy);
                        } else {
                                MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5075,9 +5573,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        n = read32 (ip + 1);
 
                        if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+                               /* FIXME: moving GC */
                                NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
                                ins->cil_code = ip;
                                ins->type = STACK_OBJ;
+                               ins->klass = mono_defaults.string_class;
                                *sp = ins;
                        }
                        else if (method->wrapper_type != MONO_WRAPPER_NONE) {
@@ -5096,6 +5596,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoInst* domain_var;
                                        
                                        if (cfg->compile_aot) {
+                                               /* FIXME: bug when inlining methods from different assemblies (n is a token valid just in one). */
                                                cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
                                        }
                                        /* avoid depending on undefined C behavior in sequence points */
@@ -5136,6 +5637,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ins->cil_code = ip;
                                                ins->type = STACK_OBJ;
                                                ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+                                               ins->klass = mono_defaults.string_class;
                                                *sp = ins;
                                        }
                                }
@@ -5156,11 +5658,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
 
+                       mono_save_token_info (cfg, image, token, cmethod);
+
                        if (!mono_class_init (cmethod->klass))
                                goto load_error;
 
                        if (mono_use_security_manager) {
-                               check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                       INLINE_FAILURE;
                        }
 
                        n = fsig->param_count;
@@ -5220,7 +5725,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 5;
                                                real_offset += 5;
                                                
-                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               GET_BBLOCK (cfg, bblock, ip);
                                                ebblock->next_bb = bblock;
                                                link_bblock (cfg, ebblock, bblock);
 
@@ -5260,8 +5765,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
@@ -5287,7 +5791,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 5;
                                real_offset += 5;
                        
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                                ebblock->next_bb = bblock;
                                link_bblock (cfg, ebblock, bblock);
 
@@ -5317,8 +5821,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                /* CASTCLASS */
@@ -5340,7 +5843,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ip += 5;
                                        real_offset += 5;
                                
-                                       GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                       GET_BBLOCK (cfg, bblock, ip);
                                        ebblock->next_bb = bblock;
                                        link_bblock (cfg, ebblock, bblock);
        
@@ -5383,6 +5886,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        add->inst_left = ins;
                        add->inst_right = vtoffset;
                        add->type = STACK_MP;
+                       add->klass = mono_defaults.object_class;
                        *sp = add;
                        ip += 5;
                        /* LDOBJ impl */
@@ -5395,7 +5899,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                copy->inst_left = iargs [0];
                                copy->inst_right = *sp;
                                copy->cil_code = ip;
-                               copy->unused = n;
+                               copy->backend.size = n;
                                MONO_ADD_INS (bblock, copy);
                        } else {
                                MonoMethod *memcpy_method = get_memcpy_method ();
@@ -5418,8 +5922,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
 
                        if (mono_class_is_nullable (klass)) {
                                int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
@@ -5456,8 +5959,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
 
@@ -5483,7 +5985,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 5;
                                real_offset += 5;
                        
-                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                               GET_BBLOCK (cfg, bblock, ip);
                                ebblock->next_bb = bblock;
                                link_bblock (cfg, ebblock, bblock);
 
@@ -5506,7 +6008,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_THROW:
                        CHECK_STACK (1);
-                       MONO_INST_NEW (cfg, ins, *ip);
+                       MONO_INST_NEW (cfg, ins, OP_THROW);
                        --sp;
                        ins->inst_left = *sp;
                        ins->cil_code = ip++;
@@ -5551,7 +6053,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!field)
                                goto load_error;
                        mono_class_init (klass);
-                       if (!dont_verify && !can_access_field (method, field))
+                       if (!dont_verify && !cfg->skip_visibility && !can_access_field (method, field))
                                UNVERIFIED;
 
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
@@ -5578,7 +6080,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 5;
                                                real_offset += 5;
 
-                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               GET_BBLOCK (cfg, bblock, ip);
                                                ebblock->next_bb = bblock;
                                                link_bblock (cfg, ebblock, bblock);
 
@@ -5602,9 +6104,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
+                                       ins->klass = mono_defaults.object_class;
                                        iargs [0] = ins;
                                        iargs [1] = sp [1];
                                        mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
+#endif
+#ifdef MONO_ARCH_SOFT_FLOAT
+                               } else if (mono_type_to_stind (field->type) == CEE_STIND_R4) {
+                                       NEW_ICONST (cfg, offset_ins, foffset);
+                                       MONO_INST_NEW (cfg, ins, OP_PADD);
+                                       ins->cil_code = ip;
+                                       ins->inst_left = *sp;
+                                       ins->inst_right = offset_ins;
+                                       ins->type = STACK_MP;
+                                       ins->klass = mono_defaults.object_class;
+                                       handle_store_float (cfg, bblock, ins, sp [1], ip);
 #endif
                                } else {
                                        MonoInst *store;
@@ -5646,7 +6160,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 5;
                                                real_offset += 5;
 
-                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               GET_BBLOCK (cfg, bblock, ip);
                                                ebblock->next_bb = bblock;
                                                link_bblock (cfg, ebblock, bblock);
 
@@ -5685,6 +6199,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                load->inst_left = ins;
                                                load->flags |= ins_flag;
                                                ins_flag = 0;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                                               if (mono_type_to_ldind (field->type) == CEE_LDIND_R4) {
+                                                       int temp;
+                                                       temp = handle_load_float (cfg, bblock, ins, ip);
+                                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                                       sp++;
+                                               } else
+#endif
                                                *sp++ = load;
                                        }
                                }
@@ -5750,8 +6272,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
                                                class_inits = g_slist_prepend (class_inits, vtable);
                                        } else {
-                                               if (cfg->run_cctors)
+                                               if (cfg->run_cctors) {
+                                                       /* This makes so that inline cannot trigger */
+                                                       /* .cctors: too many apps depend on them */
+                                                       /* running with a specific order... */
+                                                       if (! vtable->initialized)
+                                                               INLINE_FAILURE;
                                                        mono_runtime_class_init (vtable);
+                                               }
                                        }
                                        addr = (char*)vtable->data + field->offset;
 
@@ -5887,8 +6415,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        n = mono_type_to_stind (&klass->byval_arg);
                        if (n == CEE_STOBJ) {
                                handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
@@ -5914,8 +6441,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
 
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                *sp++ = val;
@@ -5927,14 +6453,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
                                UNVERIFIED;
                        /* frequent check in generic code: box (struct), brtrue */
-                       if (ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
+                       if (!mono_class_is_nullable (klass) &&
+                           ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
                                /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
                                MONO_INST_NEW (cfg, ins, CEE_POP);
                                MONO_ADD_INS (bblock, ins);
                                ins->cil_code = ip;
                                ins->inst_i0 = *sp;
                                ip += 5;
-                               MONO_INST_NEW (cfg, ins, CEE_BR);
+                               MONO_INST_NEW (cfg, ins, OP_BR);
                                ins->cil_code = ip;
                                MONO_ADD_INS (bblock, ins);
                                if (*ip == CEE_BRTRUE_S) {
@@ -5948,13 +6475,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        target = ip + 4 + (gint)(read32 (ip));
                                        ip += 4;
                                }
-                               GET_BBLOCK (cfg, bbhash, tblock, target);
+                               GET_BBLOCK (cfg, tblock, target);
                                link_bblock (cfg, bblock, tblock);
                                CHECK_BBLOCK (target, ip, tblock);
                                ins->inst_target_bb = tblock;
+                               GET_BBLOCK (cfg, tblock, ip);
+                               link_bblock (cfg, bblock, tblock);
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                        sp = stack_start;
+                                       CHECK_UNVERIFIABLE (cfg);
                                }
                                start_new_bblock = 1;
                                break;
@@ -5984,11 +6514,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        mono_get_got_var (cfg);
 
                        klass = mini_get_class (method, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
+                       ins->klass = mono_array_class_get (klass, 1);
                        ip += 5;
                        *sp++ = ins;
                        /* 
@@ -5997,11 +6527,40 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        if (1) {
                                MonoInst *store, *temp, *load;
+                               const char *data_ptr;
+                               int data_size = 0;
                                --sp;
                                temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
                                NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
                                store->cil_code = ins->cil_code;
                                MONO_ADD_INS (bblock, store);
+                               /* 
+                                * we inline/optimize the initialization sequence if possible.
+                                * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
+                                * for small sizes open code the memcpy
+                                * ensure the rva field is big enough
+                                */
+                               if ((cfg->opt & MONO_OPT_INTRINS) && ip_in_bb (cfg, bblock, ip + 6) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, ins, &data_size))) {
+                                       MonoMethod *memcpy_method = get_memcpy_method ();
+                                       MonoInst *data_offset, *add;
+                                       MonoInst *iargs [3];
+                                       NEW_ICONST (cfg, iargs [2], data_size);
+                                       NEW_TEMPLOAD (cfg, load, temp->inst_c0);
+                                       load->cil_code = ins->cil_code;
+                                       NEW_ICONST (cfg, data_offset, G_STRUCT_OFFSET (MonoArray, vector));
+                                       MONO_INST_NEW (cfg, add, OP_PADD);
+                                       add->inst_left = load;
+                                       add->inst_right = data_offset;
+                                       add->cil_code = ip;
+                                       iargs [0] = add;
+                                       if (cfg->compile_aot) {
+                                               NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
+                                       } else {
+                                               NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
+                                       }
+                                       mono_emit_method_call_spilled (cfg, bblock, memcpy_method, memcpy_method->signature, iargs, ip, NULL);
+                                       ip += 11;
+                               }
                                NEW_TEMPLOAD (cfg, load, temp->inst_c0);
                                load->cil_code = ins->cil_code;
                                *sp++ = load;
@@ -6027,19 +6586,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                UNVERIFIED;
 
                        klass = mini_get_class (method, read32 (ip + 1), generic_context);
-                       if (!klass)
-                               goto load_error;                        
+                       CHECK_TYPELOAD (klass);
                        /* we need to make sure that this array is exactly the type it needs
                         * to be for correctness. the wrappers are lax with their usage
                         * so we need to ignore them here
                         */
                        if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE) {
                                MonoInst* check;
+
+                               /* Needed by the code generated in inssel.brg */
+                               mono_get_got_var (cfg);
+
                                MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
                                check->cil_code = ip;
                                check->klass = klass;
                                check->inst_left = sp [0];
                                check->type = STACK_OBJ;
+                               check->klass = klass;
                                sp [0] = check;
                        }
                        
@@ -6058,8 +6621,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -6092,14 +6654,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
-                       klass = array_access_to_klass (*ip);
+                       klass = array_access_to_klass (*ip, sp [0]);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_LDELEM_R4) {
+                               int temp;
+                               temp = handle_load_float (cfg, bblock, load, ip);
+                               NEW_TEMPLOAD (cfg, *sp, temp);
+                               sp++;
+                               ++ip;
+                               break;
+                       }
+#endif
                        MONO_INST_NEW (cfg, ins, ldelem_to_ldind [*ip - CEE_LDELEM_I1]);
                        ins->cil_code = ip;
                        ins->inst_left = load;
                        *sp++ = ins;
                        ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
+                       ins->klass = klass;
                        ++ip;
                        break;
                }
@@ -6120,9 +6693,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 3;
                        if (sp [0]->type != STACK_OBJ)
                                UNVERIFIED;
-                       klass = array_access_to_klass (*ip);
+                       klass = array_access_to_klass (*ip, sp [0]);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
+#ifdef MONO_ARCH_SOFT_FLOAT
+                       if (*ip == CEE_STELEM_R4) {
+                               handle_store_float (cfg, bblock, load, sp [2], ip);
+                               ip++;
+                               break;
+                       }
+#endif
                        MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
                        ins->cil_code = ip;
                        ins->inst_left = load;
@@ -6147,19 +6727,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
-                               MonoMethod* helper = mono_marshal_get_stelemref ();
-                               MonoInst *iargs [3];
-                               handle_loaded_temps (cfg, bblock, stack_start, sp);
+                               /* storing a NULL doesn't need any of the complex checks in stelemref */
+                               if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
+                                       MonoInst *load;
+                                       NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
+                                       load->cil_code = ip;
+                                       MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+                                       ins->cil_code = ip;
+                                       ins->inst_left = load;
+                                       ins->inst_right = sp [2];
+                                       MONO_ADD_INS (bblock, ins);
+                               } else {
+                                       MonoMethod* helper = mono_marshal_get_stelemref ();
+                                       MonoInst *iargs [3];
+                                       handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                               iargs [2] = sp [2];
-                               iargs [1] = sp [1];
-                               iargs [0] = sp [0];
-                               
-                               mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+                                       iargs [2] = sp [2];
+                                       iargs [1] = sp [1];
+                                       iargs [0] = sp [0];
+
+                                       mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+                               }
                        } else {
                                NEW_LDELEMA (cfg, load, sp, klass);
                                load->cil_code = ip;
@@ -6193,24 +6784,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
 
-                       iargs [2] = sp [2];
-                       iargs [1] = sp [1];
-                       iargs [0] = sp [0];
+                       /* storing a NULL doesn't need any of the complex checks in stelemref */
+                       if (sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL) {
+                               MonoInst *load;
+                               NEW_LDELEMA (cfg, load, sp, mono_defaults.object_class);
+                               load->cil_code = ip;
+                               MONO_INST_NEW (cfg, ins, stelem_to_stind [*ip - CEE_STELEM_I]);
+                               ins->cil_code = ip;
+                               ins->inst_left = load;
+                               ins->inst_right = sp [2];
+                               MONO_ADD_INS (bblock, ins);
+                       } else {
+                               iargs [2] = sp [2];
+                               iargs [1] = sp [1];
+                               iargs [0] = sp [0];
                        
-                       mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
-
-                       /*
-                       MonoInst *group;
-                       NEW_GROUP (cfg, group, sp [0], sp [1]);
-                       MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
-                       ins->cil_code = ip;
-                       ins->inst_left = group;
-                       ins->inst_right = sp [2];
-                       MONO_ADD_INS (bblock, ins);
-                       */
+                               mono_emit_method_call_spilled (cfg, bblock, helper, mono_method_signature (helper), iargs, ip, NULL);
+                               inline_costs += 1;
+                       }
 
                        ++ip;
-                       inline_costs += 1;
                        break;
                }
                case CEE_CKFINITE: {
@@ -6223,7 +6816,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         * this check */
 
                        
-                       MONO_INST_NEW (cfg, ins, CEE_CKFINITE);
+                       MONO_INST_NEW (cfg, ins, OP_CKFINITE);
                        ins->cil_code = ip;
                        ins->inst_left = sp [-1];
                        temp = mono_compile_create_var (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL);
@@ -6243,8 +6836,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        ins->type = STACK_MP;
                        ins->inst_left = *sp;
@@ -6262,8 +6854,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        CHECK_OPSIZE (5);
                        klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
-                       if (!klass)
-                               goto load_error;
+                       CHECK_TYPELOAD (klass);
                        mono_class_init (klass);
                        ins->cil_code = ip;
 
@@ -6371,7 +6962,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip++;
                        break;
                case CEE_ENDFINALLY:
-                       MONO_INST_NEW (cfg, ins, *ip);
+                       MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
                        MONO_ADD_INS (bblock, ins);
                        ins->cil_code = ip++;
                        start_new_bblock = 1;
@@ -6440,8 +7031,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
 
-                       /* fixme: call fault handler ? */
-
                        if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
                                GList *tmp;
                                for (tmp = handlers; tmp; tmp = tmp->next) {
@@ -6455,10 +7044,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                g_list_free (handlers);
                        } 
 
-                       MONO_INST_NEW (cfg, ins, CEE_BR);
+                       MONO_INST_NEW (cfg, ins, OP_BR);
                        ins->cil_code = ip;
                        MONO_ADD_INS (bblock, ins);
-                       GET_BBLOCK (cfg, bbhash, tblock, target);
+                       GET_BBLOCK (cfg, tblock, target);
                        link_bblock (cfg, bblock, tblock);
                        CHECK_BBLOCK (target, ip, tblock);
                        ins->inst_target_bb = tblock;
@@ -6503,7 +7092,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                token = read32 (ip + 2);
                                func = mono_method_get_wrapper_data (method, token);
                                info = mono_find_jit_icall_by_addr (func);
-                               g_assert (info);
+                               if (info == NULL){
+                                       g_error ("An attempt has been made to perform an icall to address %p, "
+                                                "but the address has not been registered as an icall\n", info);
+                                       g_assert_not_reached ();
+                               }
 
                                CHECK_STACK (info->sig->param_count);
                                sp -= info->sig->param_count;
@@ -6595,7 +7188,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp != stack_start)
                                        UNVERIFIED;
                                
-                               MONO_INST_NEW (cfg, ins, CEE_BR);
+                               MONO_INST_NEW (cfg, ins, OP_BR);
                                ins->cil_code = ip;
                                ins->inst_target_bb = end_bblock;
                                MONO_ADD_INS (bblock, ins);
@@ -6694,13 +7287,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cmp->cil_code = ip;
                                type_from_op (cmp);
                                CHECK_TYPE (cmp);
+                               ins->cil_code = ip;
+                               ins->type = STACK_I4;
+                               ins->inst_i0 = cmp;
+#if MONO_ARCH_SOFT_FLOAT
+                               if (sp [0]->type == STACK_R8) {
+                                       cmp->type = STACK_I4;
+                                       *sp++ = emit_tree (cfg, bblock, cmp, ip + 2);
+                                       ip += 2;
+                                       break;
+                               }
+#endif
                                if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
                                        cmp->opcode = OP_LCOMPARE;
                                else
                                        cmp->opcode = OP_COMPARE;
-                               ins->cil_code = ip;
-                               ins->type = STACK_I4;
-                               ins->inst_i0 = cmp;
                                *sp++ = ins;
                                /* spill it to reduce the expression complexity
                                 * and workaround bug 54209 
@@ -6725,7 +7326,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
-                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                                       if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                               INLINE_FAILURE;
                                }
 
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -6755,7 +7357,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
-                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                                       if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                               INLINE_FAILURE;
                                }
 
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -6777,6 +7380,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_ARG (n);
                                NEW_ARGLOAD (cfg, ins, n);
+                               LDARG_SOFT_FLOAT (cfg, ins, n, ip);
                                ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
@@ -6802,6 +7406,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->cil_code = ip;
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
                                        UNVERIFIED;
+                               STARG_SOFT_FLOAT (cfg, ins, n, ip);
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_ARGLOADA (cfg, ins, n);
                                        handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -6815,6 +7420,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read16 (ip + 2);
                                CHECK_LOCAL (n);
                                NEW_LOCLOAD (cfg, ins, n);
+                               LDLOC_SOFT_FLOAT (cfg, ins, n, ip);
                                ins->cil_code = ip;
                                *sp++ = ins;
                                ip += 4;
@@ -6840,6 +7446,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
                                        UNVERIFIED;
                                ins->cil_code = ip;
+                               STLOC_SOFT_FLOAT (cfg, ins, n, ip);
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_LOCLOADA (cfg, ins, n);
                                        handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
@@ -6928,13 +7535,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
                                klass = mini_get_class (method, token, generic_context);
-                               if (!klass)
-                                       goto load_error;
+                               CHECK_TYPELOAD (klass);
                                if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
                                        MonoInst *store, *load;
                                        NEW_PCONST (cfg, load, NULL);
                                        load->cil_code = ip;
                                        load->type = STACK_OBJ;
+                                       load->klass = klass;
                                        MONO_INST_NEW (cfg, store, CEE_STIND_REF);
                                        store->cil_code = ip;
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -6952,8 +7559,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_OPSIZE (6);
                                token = read32 (ip + 2);
                                constrained_call = mono_class_get_full (image, token, generic_context);
-                               if (!constrained_call)
-                                       goto load_error;
+                               CHECK_TYPELOAD (constrained_call);
                                ip += 6;
                                break;
                        case CEE_CPBLK:
@@ -6967,7 +7573,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        copy->inst_left = sp [0];
                                        copy->inst_right = sp [1];
                                        copy->cil_code = ip;
-                                       copy->unused = n;
+                                       copy->backend.size = n;
                                        MONO_ADD_INS (bblock, copy);
                                        ip += 2;
                                        break;
@@ -7034,8 +7640,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        token = mono_type_size (type, &ialign);
                                } else {
                                        MonoClass *klass = mono_class_get_full (image, token, generic_context);
-                                       if (!klass)
-                                               goto load_error;
+                                       CHECK_TYPELOAD (klass);
                                        mono_class_init (klass);
                                        token = mono_class_value_size (klass, &align);
                                }
@@ -7117,11 +7722,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
                        } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
+#ifdef MONO_ARCH_SOFT_FLOAT
+                               /* FIXME: handle init of R4 */
+#else
                                MONO_INST_NEW (cfg, ins, OP_R8CONST);
                                ins->type = STACK_R8;
                                ins->inst_p0 = (void*)&r8_0;
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
+#endif
                        } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
                                   ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
                                NEW_LOCLOADA (cfg, ins, i);
@@ -7138,7 +7747,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        for (tmp = bb_recheck; tmp; tmp = tmp->next) {
                bblock = tmp->data;
                /*g_print ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
-               tblock = find_previous (bbhash, start_bblock, bblock->cil_code);
+               tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
                if (tblock != start_bblock) {
                        int l;
                        split_bblock (cfg, tblock, bblock);
@@ -7159,8 +7768,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->verbose_level > 2)
                                g_print ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
                }
-       } else {
-               g_hash_table_destroy (bbhash);
        }
 
        g_slist_free (class_inits);
@@ -7180,23 +7787,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        return inline_costs;
 
  inline_failure:
-       if (cfg->method != method) 
-               g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
        return -1;
 
  load_error:
-       if (cfg->method != method)
-               g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
        return -1;
 
  unverified:
-       if (cfg->method != method) 
-               g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
        cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
@@ -7279,9 +7880,9 @@ mono_print_tree (MonoInst *tree) {
        }
        case OP_RENAME:
        case OP_RETARG:
-       case CEE_NOP:
-       case CEE_JMP:
-       case CEE_BREAK:
+       case OP_NOP:
+       case OP_JMP:
+       case OP_BREAK:
                break;
        case OP_LOAD_MEMBASE:
        case OP_LOADI4_MEMBASE:
@@ -7292,7 +7893,7 @@ mono_print_tree (MonoInst *tree) {
        case OP_LOADI2_MEMBASE:
                printf ("[%s] <- [%s + 0x%x]", mono_arch_regname (tree->dreg), mono_arch_regname (tree->inst_basereg), (int)tree->inst_offset);
                break;
-       case CEE_BR:
+       case OP_BR:
        case OP_CALL_HANDLER:
                printf ("[B%d]", tree->inst_target_bb->block_num);
                break;
@@ -7354,6 +7955,8 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
 {
        char *name;
        MonoMethod *wrapper;
+       gconstpointer trampoline;
+       MonoDomain *domain = mono_get_root_domain ();
        
        if (callinfo->wrapper) {
                return callinfo->wrapper;
@@ -7362,13 +7965,28 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
        if (callinfo->trampoline)
                return callinfo->trampoline;
 
+       /* 
+        * We use the lock on the root domain instead of the JIT lock to protect 
+        * callinfo->trampoline, since we do a lot of stuff inside the critical section.
+        */
+       mono_domain_lock (domain);
+
+       if (callinfo->trampoline) {
+               mono_domain_unlock (domain);
+               return callinfo->trampoline;
+       }
+
        name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
        g_free (name);
 
-       callinfo->trampoline = mono_create_ftnptr (mono_get_root_domain (), mono_create_jit_trampoline_in_domain (mono_get_root_domain (), wrapper));
-       mono_register_jit_icall_wrapper (callinfo, callinfo->trampoline);
+       trampoline = mono_create_ftnptr (domain, mono_create_jit_trampoline_in_domain (domain, wrapper));
+       mono_register_jit_icall_wrapper (callinfo, trampoline);
 
+       callinfo->trampoline = trampoline;
+
+       mono_domain_unlock (domain);
+       
        return callinfo->trampoline;
 }
 
@@ -7552,43 +8170,32 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 #endif
 
 static gpointer
-mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
+mono_create_delegate_trampoline (MonoClass *klass)
 {
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
+       MonoDomain *domain = mono_domain_get ();
        gpointer code, ptr;
        guint32 code_size;
-       MonoDomain *domain = mono_domain_get ();
-
-#ifndef __ia64__
-       code = mono_jit_find_compiled_method (domain, method);
-       if (code)
-               return code;
-#else
-       /* 
-        * FIXME: We should return a function descriptor here but it is not stored
-        * anywhere so it would be leaked.
-        */
-#endif
 
        mono_domain_lock (domain);
-       ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, method);
+       ptr = g_hash_table_lookup (domain->delegate_trampoline_hash, klass);
        mono_domain_unlock (domain);
        if (ptr)
                return ptr;
 
-       code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_DELEGATE, domain, &code_size);
+    code = mono_arch_create_specific_trampoline (klass, MONO_TRAMPOLINE_DELEGATE, mono_domain_get (), &code_size);
 
        ptr = mono_create_ftnptr (domain, code);
 
        /* store trampoline address */
        mono_domain_lock (domain);
        g_hash_table_insert (domain->delegate_trampoline_hash,
-                                                         method, ptr);
+                                                         klass, ptr);
        mono_domain_unlock (domain);
 
        return ptr;
 #else
-       return addr;
+       return NULL;
 #endif
 }
 
@@ -7629,15 +8236,28 @@ mono_dynamic_code_hash_lookup (MonoDomain *domain, MonoMethod *method)
 typedef struct {
        MonoClass *vtype;
        GList *active;
-       GList *slots;
+       GSList *slots;
 } StackSlotInfo;
 
+static inline GSList*
+g_slist_prepend_mempool (MonoMemPool *mp, GSList   *list,
+                                                gpointer  data)
+{
+  GSList *new_list;
+
+  new_list = mono_mempool_alloc (mp, sizeof (GSList));
+  new_list->data = data;
+  new_list->next = list;
+
+  return new_list;
+}
+
 /*
- * mono_allocate_stack_slots_full:
+ *  mono_allocate_stack_slots_full:
  *
  *  Allocate stack slots for all non register allocated variables using a
  * linear scan algorithm.
- * Returns: an array of stack offsets which the caller should free.
+ * Returns: an array of stack offsets.
  * STACK_SIZE is set to the amount of stack space needed.
  * STACK_ALIGN is set to the alignment needed by the locals area.
  */
@@ -7654,11 +8274,11 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
        MonoType *t;
        int nvtypes;
 
-       scalar_stack_slots = g_new0 (StackSlotInfo, MONO_TYPE_PINNED);
-       vtype_stack_slots = g_new0 (StackSlotInfo, 256);
+       scalar_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * MONO_TYPE_PINNED);
+       vtype_stack_slots = NULL;
        nvtypes = 0;
 
-       offsets = g_new (gint32, m->num_varinfo);
+       offsets = mono_mempool_alloc (m->mempool, sizeof (gint32) * m->num_varinfo);
        for (i = 0; i < m->num_varinfo; ++i)
                offsets [i] = -1;
 
@@ -7679,9 +8299,9 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                vmv = l->data;
                inst = m->varinfo [vmv->idx];
 
-               /* inst->unused indicates native sized value types, this is used by the
+               /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
                * pinvoke wrappers when they call functions returning structures */
-               if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
+               if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
                        size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
                else {
                        int ialign;
@@ -7691,28 +8311,50 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                }
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
-               switch (t->type) {
-               case MONO_TYPE_GENERICINST:
-                       if (!mono_type_generic_inst_is_valuetype (t)) {
-                               slot_info = &scalar_stack_slots [t->type];
-                               break;
-                       }
-                       /* Fall through */
-               case MONO_TYPE_VALUETYPE:
-                       for (i = 0; i < nvtypes; ++i)
-                               if (t->data.klass == vtype_stack_slots [i].vtype)
+               if (t->byref) {
+                       slot_info = &scalar_stack_slots [MONO_TYPE_I];
+               } else {
+                       switch (t->type) {
+                       case MONO_TYPE_GENERICINST:
+                               if (!mono_type_generic_inst_is_valuetype (t)) {
+                                       slot_info = &scalar_stack_slots [t->type];
                                        break;
-                       if (i < nvtypes)
-                               slot_info = &vtype_stack_slots [i];
-                       else {
-                               g_assert (nvtypes < 256);
-                               vtype_stack_slots [nvtypes].vtype = t->data.klass;
-                               slot_info = &vtype_stack_slots [nvtypes];
-                               nvtypes ++;
+                               }
+                               /* Fall through */
+                       case MONO_TYPE_VALUETYPE:
+                               if (!vtype_stack_slots)
+                                       vtype_stack_slots = mono_mempool_alloc0 (m->mempool, sizeof (StackSlotInfo) * 256);
+                               for (i = 0; i < nvtypes; ++i)
+                                       if (t->data.klass == vtype_stack_slots [i].vtype)
+                                               break;
+                               if (i < nvtypes)
+                                       slot_info = &vtype_stack_slots [i];
+                               else {
+                                       g_assert (nvtypes < 256);
+                                       vtype_stack_slots [nvtypes].vtype = t->data.klass;
+                                       slot_info = &vtype_stack_slots [nvtypes];
+                                       nvtypes ++;
+                               }
+                               break;
+                       case MONO_TYPE_CLASS:
+                       case MONO_TYPE_OBJECT:
+                       case MONO_TYPE_ARRAY:
+                       case MONO_TYPE_SZARRAY:
+                       case MONO_TYPE_STRING:
+                       case MONO_TYPE_PTR:
+                       case MONO_TYPE_I:
+                       case MONO_TYPE_U:
+#if SIZEOF_VOID_P == 4
+                       case MONO_TYPE_I4:
+#else
+                       case MONO_TYPE_I8:
+#endif
+                               /* Share non-float stack slots of the same size */
+                               slot_info = &scalar_stack_slots [MONO_TYPE_CLASS];
+                               break;
+                       default:
+                               slot_info = &scalar_stack_slots [t->type];
                        }
-                       break;
-               default:
-                       slot_info = &scalar_stack_slots [t->type];
                }
 
                slot = 0xffffff;
@@ -7729,7 +8371,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                //printf ("EXPIR  %2d %08x %08x C%d R%d\n", amv->idx, amv->range.first_use.abs_pos, amv->range.last_use.abs_pos, amv->spill_costs, amv->reg);
 
                                slot_info->active = g_list_delete_link (slot_info->active, slot_info->active);
-                               slot_info->slots = g_list_prepend (slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
+                               slot_info->slots = g_slist_prepend_mempool (m->mempool, slot_info->slots, GINT_TO_POINTER (offsets [amv->idx]));
                        }
 
                        /* 
@@ -7744,7 +8386,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                                if (slot_info->slots) {
                                        slot = GPOINTER_TO_INT (slot_info->slots->data);
 
-                                       slot_info->slots = g_list_delete_link (slot_info->slots, slot_info->slots);
+                                       slot_info->slots = slot_info->slots->next;
                                }
 
                                slot_info->active = mono_varlist_insert_sorted (m, slot_info->active, vmv, TRUE);
@@ -7795,15 +8437,15 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
        }
        g_list_free (vars);
        for (i = 0; i < MONO_TYPE_PINNED; ++i) {
-               g_list_free (scalar_stack_slots [i].active);
-               g_list_free (scalar_stack_slots [i].slots);
+               if (scalar_stack_slots [i].active)
+                       g_list_free (scalar_stack_slots [i].active);
        }
        for (i = 0; i < nvtypes; ++i) {
-               g_list_free (vtype_stack_slots [i].active);
-               g_list_free (vtype_stack_slots [i].slots);
+               if (vtype_stack_slots [i].active)
+                       g_list_free (vtype_stack_slots [i].active);
        }
-       g_free (scalar_stack_slots);
-       g_free (vtype_stack_slots);
+
+       mono_jit_stats.locals_stack_size += offset;
 
        *stack_size = offset;
        return offsets;
@@ -7888,6 +8530,58 @@ decompose_foreach (MonoInst *tree, gpointer data)
                        dec_foreach (iargs [i], cfg);
                break;
        }
+#ifdef MONO_ARCH_SOFT_FLOAT
+       case OP_FBEQ:
+       case OP_FBGE:
+       case OP_FBGT:
+       case OP_FBLE:
+       case OP_FBLT:
+       case OP_FBNE_UN:
+       case OP_FBGE_UN:
+       case OP_FBGT_UN:
+       case OP_FBLE_UN:
+       case OP_FBLT_UN: {
+               if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+                       MonoCompile *cfg = data;
+                       MonoInst *iargs [2];
+               
+                       iargs [0] = tree->inst_i0;
+                       iargs [1] = tree->inst_i1;
+               
+                       mono_emulate_opcode (cfg, tree, iargs, info);
+
+                       dec_foreach (iargs [0], cfg);
+                       dec_foreach (iargs [1], cfg);
+                       break;
+               } else {
+                       g_assert_not_reached ();
+               }
+               break;
+       }
+       case OP_FCEQ:
+       case OP_FCGT:
+       case OP_FCGT_UN:
+       case OP_FCLT:
+       case OP_FCLT_UN: {
+               if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+                       MonoCompile *cfg = data;
+                       MonoInst *iargs [2];
+
+                       /* the args are in the compare opcode ... */
+                       iargs [0] = tree->inst_i0;
+                       iargs [1] = tree->inst_i1;
+               
+                       mono_emulate_opcode (cfg, tree, iargs, info);
+
+                       dec_foreach (iargs [0], cfg);
+                       dec_foreach (iargs [1], cfg);
+                       break;
+               } else {
+                       g_assert_not_reached ();
+               }
+               break;
+       }
+#endif
 
        default:
                break;
@@ -8001,7 +8695,6 @@ void
 mono_destroy_compile (MonoCompile *cfg)
 {
        //mono_mempool_stats (cfg->mempool);
-       g_hash_table_destroy (cfg->bb_hash);
        mono_free_loop_info (cfg);
        if (cfg->rs)
                mono_regstate_free (cfg->rs);
@@ -8011,6 +8704,7 @@ mono_destroy_compile (MonoCompile *cfg)
                g_hash_table_destroy (cfg->exvars);
        mono_mempool_destroy (cfg->mempool);
        g_list_free (cfg->ldstr_list);
+       g_hash_table_destroy (cfg->token_info_hash);
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
@@ -8020,6 +8714,13 @@ mono_destroy_compile (MonoCompile *cfg)
 
 #ifdef HAVE_KW_THREAD
 static __thread gpointer mono_lmf_addr MONO_TLS_FAST;
+#ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
+/* 
+ * When this is defined, the current lmf is stored in this tls variable instead of in 
+ * jit_tls->lmf.
+ */
+static __thread gpointer mono_lmf MONO_TLS_FAST;
+#endif
 #endif
 
 guint32
@@ -8030,12 +8731,40 @@ mono_get_jit_tls_key (void)
 
 gint32
 mono_get_lmf_tls_offset (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       int offset;
+       MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
+       return offset;
+#else
+       return -1;
+#endif
+}
+
+gint32
+mono_get_lmf_addr_tls_offset (void)
 {
        int offset;
        MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
        return offset;
 }
 
+MonoLMF *
+mono_get_lmf (void)
+{
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       return mono_lmf;
+#else
+       MonoJitTlsData *jit_tls;
+
+       if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
+               return jit_tls->lmf;
+
+       g_assert_not_reached ();
+       return NULL;
+#endif
+}
+
 MonoLMF **
 mono_get_lmf_addr (void)
 {
@@ -8103,10 +8832,18 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
        lmf = g_new0 (MonoLMF, 1);
        lmf->ebp = -1;
 
-       jit_tls->lmf = jit_tls->first_lmf = lmf;
+       jit_tls->first_lmf = lmf;
 
-#ifdef HAVE_KW_THREAD
-       mono_lmf_addr = &jit_tls->lmf;
+#if defined(HAVE_KW_THREAD) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       /* jit_tls->lmf is unused */
+       mono_lmf = lmf;
+       mono_lmf_addr = &mono_lmf;
+#else
+#if defined(HAVE_KW_THREAD)
+       mono_lmf_addr = &jit_tls->lmf;  
+#endif
+
+       jit_tls->lmf = lmf;
 #endif
 
        mono_arch_setup_jit_tls_data (jit_tls);
@@ -8195,6 +8932,89 @@ mono_remove_patch_info (MonoCompile *cfg, int ip)
        }
 }
 
+/**
+ * mono_patch_info_dup_mp:
+ *
+ * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
+ */
+MonoJumpInfo*
+mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
+{
+       MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+       memcpy (res, patch_info, sizeof (MonoJumpInfo));
+
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_RVA:
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
+               memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
+               break;
+       case MONO_PATCH_INFO_SWITCH:
+               res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
+               memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
+guint
+mono_patch_info_hash (gconstpointer data)
+{
+       const MonoJumpInfo *ji = (MonoJumpInfo*)data;
+
+       switch (ji->type) {
+       case MONO_PATCH_INFO_RVA:
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               return (ji->type << 8) | ji->data.token->token;
+       default:
+               return (ji->type << 8);
+       }
+}
+
+/* 
+ * mono_patch_info_equal:
+ * 
+ * This might fail to recognize equivalent patches, i.e. floats, so its only
+ * usable in those cases where this is not a problem, i.e. sharing GOT slots
+ * in AOT.
+ */
+gint
+mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
+{
+       const MonoJumpInfo *ji1 = (MonoJumpInfo*)ka;
+       const MonoJumpInfo *ji2 = (MonoJumpInfo*)kb;
+
+       if (ji1->type != ji2->type)
+               return 0;
+
+       switch (ji1->type) {
+       case MONO_PATCH_INFO_RVA:
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               if ((ji1->data.token->image != ji2->data.token->image) ||
+                       (ji1->data.token->token != ji2->data.token->token))
+                       return 0;
+               break;
+       default:
+               if (ji1->data.name != ji2->data.name)
+                       return 0;
+               break;
+       }
+
+       return 1;
+}
+
 gpointer
 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
 {
@@ -8295,6 +9115,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = (char*)vtable->data + patch_info->data.field->offset;
                break;
        }
+       case MONO_PATCH_INFO_RVA:
+               target = mono_image_rva_map (patch_info->data.token->image, patch_info->data.token->token);
+               break;
        case MONO_PATCH_INFO_R4:
        case MONO_PATCH_INFO_R8:
                target = patch_info->data.target;
@@ -8485,7 +9308,7 @@ replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBl
        }
        if (bb->last_ins != NULL) {
                switch (bb->last_ins->opcode) {
-               case CEE_BR:
+               case OP_BR:
                        if (bb->last_ins->inst_target_bb == orig) {
                                bb->last_ins->inst_target_bb = repl;
                        }
@@ -8558,9 +9381,9 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        
        for (inst = bb->code; inst != NULL; inst = inst->next) {
                switch (inst->opcode) {
-               case CEE_NOP:
+               case OP_NOP:
                        break;
-               case CEE_BR:
+               case OP_BR:
                        target_bb = inst->inst_target_bb;
                        break;
                default:
@@ -8588,6 +9411,13 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
                return FALSE;
        }
+
+       /* 
+        * Do not touch BBs following a try block as the code in 
+        * mini_method_compile needs them to compute the length of the try block.
+        */
+       if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
+               return FALSE;
        
        /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
        if ((target_bb != NULL) && (target_bb != bb)) {
@@ -8610,13 +9440,13 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
                if ((previous_bb != cfg->bb_entry) &&
                                (previous_bb->region == bb->region) &&
                                ((previous_bb->last_ins == NULL) ||
-                               ((previous_bb->last_ins->opcode != CEE_BR) &&
+                               ((previous_bb->last_ins->opcode != OP_BR) &&
                                (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
                                (previous_bb->last_ins->opcode != CEE_SWITCH)))) {
                        for (i = 0; i < previous_bb->out_count; i++) {
                                if (previous_bb->out_bb [i] == target_bb) {
                                        MonoInst *jump;
-                                       MONO_INST_NEW (cfg, jump, CEE_BR);
+                                       MONO_INST_NEW (cfg, jump, OP_BR);
                                        MONO_ADD_INS (previous_bb, jump);
                                        jump->cil_code = previous_bb->cil_code;
                                        jump->inst_target_bb = target_bb;
@@ -8642,6 +9472,11 @@ merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
 
        replace_basic_block (bb, bbn, bb);
 
+       /* Nullify branch at the end of bb */
+       if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
+               bb->last_ins->opcode = OP_NOP;
+       }               
+
        if (bb->last_ins) {
                if (bbn->code) {
                        bb->last_ins->next = bbn->code;
@@ -8679,7 +9514,7 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
        if (next && (!bb->last_ins || (bb->last_ins->opcode != OP_NOT_REACHED))) {
                MonoInst *ins;
 
-               MONO_INST_NEW (cfg, ins, CEE_BR);
+               MONO_INST_NEW (cfg, ins, OP_BR);
                MONO_ADD_INS (bb, ins);
                link_bblock (cfg, bb, next);
                ins->inst_target_bb = next;
@@ -8780,7 +9615,7 @@ try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
                        return FALSE;
                condb->opcode = get_unsigned_condbranch (condb->opcode);
                /* change the original condbranch to just point to the new unsigned check */
-               bb->last_ins->opcode = CEE_BR;
+               bb->last_ins->opcode = OP_BR;
                bb->last_ins->inst_target_bb = falset;
                replace_out_block (bb, truet, NULL);
                replace_in_block (truet, bb, NULL);
@@ -8843,7 +9678,7 @@ optimize_branches (MonoCompile *cfg)
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
-                               /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
+                               /* conditional branches where true and false targets are the same can be also replaced with OP_BR */
                                if (bb->last_ins && MONO_IS_COND_BRANCH_OP (bb->last_ins)) {
                                        MonoInst *pop;
                                        MONO_INST_NEW (cfg, pop, CEE_POP);
@@ -8852,7 +9687,7 @@ optimize_branches (MonoCompile *cfg)
                                        MONO_INST_NEW (cfg, pop, CEE_POP);
                                        pop->inst_left = bb->last_ins->inst_left->inst_right;
                                        mono_add_ins_to_end (bb, pop);
-                                       bb->last_ins->opcode = CEE_BR;
+                                       bb->last_ins->opcode = OP_BR;
                                        bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
                                        changed = TRUE;
                                        if (cfg->verbose_level > 2)
@@ -8863,8 +9698,8 @@ optimize_branches (MonoCompile *cfg)
                                        /* the block are in sequence anyway ... */
 
                                        /* branches to the following block can be removed */
-                                       if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
-                                               bb->last_ins->opcode = CEE_NOP;
+                                       if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
+                                               bb->last_ins->opcode = OP_NOP;
                                                changed = TRUE;
                                                if (cfg->verbose_level > 2)
                                                        g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
@@ -8901,9 +9736,9 @@ optimize_branches (MonoCompile *cfg)
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
-                               if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
+                               if (bb->last_ins && bb->last_ins->opcode == OP_BR) {
                                        bbn = bb->last_ins->inst_target_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
                                            bbn->code->inst_target_bb->region == bb->region) {
                                                
                                                if (cfg->verbose_level > 2)
@@ -8933,14 +9768,14 @@ optimize_branches (MonoCompile *cfg)
                                                /* if mono_eval_cond_branch () is ever taken to handle 
                                                 * non-constant values to compare, issue a pop here.
                                                 */
-                                               bb->last_ins->opcode = CEE_BR;
+                                               bb->last_ins->opcode = OP_BR;
                                                bb->last_ins->inst_target_bb = taken_branch_target;
                                                mono_unlink_bblock (cfg, bb, untaken_branch_target);
                                                changed = TRUE;
                                                continue;
                                        }
                                        bbn = bb->last_ins->inst_true_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
                                            bbn->code->inst_target_bb->region == bb->region) {
                                                if (cfg->verbose_level > 2)             
                                                        g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
@@ -8965,7 +9800,7 @@ optimize_branches (MonoCompile *cfg)
                                        }
 
                                        bbn = bb->last_ins->inst_false_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == OP_BR &&
                                            bbn->code->inst_target_bb->region == bb->region) {
                                                if (cfg->verbose_level > 2)
                                                        g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
@@ -9034,11 +9869,13 @@ mono_compile_create_vars (MonoCompile *cfg)
        if (cfg->verbose_level > 2)
                g_print ("creating vars\n");
 
+       cfg->args = mono_mempool_alloc0 (cfg->mempool, (sig->param_count + sig->hasthis) * sizeof (MonoInst*));
+
        if (sig->hasthis)
-               mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
+               cfg->args [0] = mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
 
        for (i = 0; i < sig->param_count; ++i) {
-               mono_compile_create_var (cfg, sig->params [i], OP_ARG);
+               cfg->args [i + sig->hasthis] = mono_compile_create_var (cfg, sig->params [i], OP_ARG);
                if (sig->params [i]->byref) {
                        cfg->disable_ssa = TRUE;
                }
@@ -9089,7 +9926,6 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
        MBState *kids [10];
        int ern = mono_burg_rule (state, goal);
        const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
-       MBEmitFunc emit;
 
        //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
        switch (goal) {
@@ -9108,7 +9944,12 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
                state->reg2 = mono_regstate_next_int (cfg->rs);
                break;
        case MB_NTERM_freg:
+#ifdef MONO_ARCH_SOFT_FLOAT
+               state->reg1 = mono_regstate_next_int (cfg->rs);
+               state->reg2 = mono_regstate_next_int (cfg->rs);
+#else
                state->reg1 = mono_regstate_next_float (cfg->rs);
+#endif
                break;
        default:
 #ifdef MONO_ARCH_ENABLE_EMIT_STATE_OPT
@@ -9141,8 +9982,7 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
        }
 
 //     g_print ("emit: %s (%p)\n", mono_burg_rule_string [ern], state);
-       if ((emit = mono_burg_func [ern]))
-               emit (state, state->tree, cfg); 
+       mono_burg_emit (ern, state, state->tree, cfg);
 }
 
 #define DEBUG_SELECTION
@@ -9170,7 +10010,7 @@ mini_select_instructions (MonoCompile *cfg)
                                bb->last_ins->opcode = reverse_branch_op (bb->last_ins->opcode);
                        } else {                        
                                MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
-                               inst->opcode = CEE_BR;
+                               inst->opcode = OP_BR;
                                inst->inst_target_bb = bb->last_ins->inst_false_bb;
                                mono_bblock_add_inst (bb, inst);
                        }
@@ -9225,8 +10065,7 @@ mini_select_instructions (MonoCompile *cfg)
                        }
                        emit_state (cfg, mbstate, MB_NTERM_stmt);
                }
-               bb->max_ireg = cfg->rs->next_vireg;
-               bb->max_freg = cfg->rs->next_vfreg;
+               bb->max_vreg = cfg->rs->next_vreg;
 
                if (bb->last_ins)
                        bb->last_ins->next = NULL;
@@ -9441,9 +10280,9 @@ remove_critical_edges (MonoCompile *cfg) {
                                        if (previous_bb->region == bb->region) {
                                                if (previous_bb != cfg->bb_entry) {
                                                        /* If previous_bb "followed through" to bb, */
-                                                       /* keep it linked with a CEE_BR */
+                                                       /* keep it linked with a OP_BR */
                                                        if ((previous_bb->last_ins == NULL) ||
-                                                                       ((previous_bb->last_ins->opcode != CEE_BR) &&
+                                                                       ((previous_bb->last_ins->opcode != OP_BR) &&
                                                                        (! (MONO_IS_COND_BRANCH_OP (previous_bb->last_ins))) &&
                                                                        (previous_bb->last_ins->opcode != CEE_SWITCH))) {
                                                                int i;
@@ -9451,7 +10290,7 @@ remove_critical_edges (MonoCompile *cfg) {
                                                                for (i = 0; i < previous_bb->out_count; i++) {
                                                                        if (previous_bb->out_bb [i] == bb) {
                                                                                MonoInst *jump;
-                                                                               MONO_INST_NEW (cfg, jump, CEE_BR);
+                                                                               MONO_INST_NEW (cfg, jump, OP_BR);
                                                                                MONO_ADD_INS (previous_bb, jump);
                                                                                jump->cil_code = previous_bb->cil_code;
                                                                                jump->inst_target_bb = bb;
@@ -9461,14 +10300,14 @@ remove_critical_edges (MonoCompile *cfg) {
                                                        }
                                                } else {
                                                        /* We cannot add any inst to the entry BB, so we must */
-                                                       /* put a new BB in the middle to hold the CEE_BR */
+                                                       /* put a new BB in the middle to hold the OP_BR */
                                                        MonoInst *jump;
                                                        MonoBasicBlock *new_bb_after_entry = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
                                                        new_bb_after_entry->block_num = cfg->num_bblocks++;
 //                                                     new_bb_after_entry->real_offset = bb->real_offset;
                                                        new_bb_after_entry->region = bb->region;
                                                        
-                                                       MONO_INST_NEW (cfg, jump, CEE_BR);
+                                                       MONO_INST_NEW (cfg, jump, OP_BR);
                                                        MONO_ADD_INS (new_bb_after_entry, jump);
                                                        jump->cil_code = bb->cil_code;
                                                        jump->inst_target_bb = bb;
@@ -9561,10 +10400,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->opt = opts;
        cfg->prof_options = mono_profiler_get_events ();
        cfg->run_cctors = run_cctors;
-       cfg->bb_hash = g_hash_table_new (NULL, NULL);
        cfg->domain = domain;
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
+       cfg->skip_visibility = method->skip_visibility;
+       cfg->token_info_hash = g_hash_table_new (NULL, NULL);
        if (!header) {
                cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
                cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
@@ -9596,7 +10436,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
        mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
 
-       if ((cfg->num_varinfo > 2000) && !mono_compile_aot) {
+       if ((cfg->num_varinfo > 2000) && !cfg->compile_aot) {
                /* 
                 * we disable some optimizations if there are too many variables
                 * because JIT time may become too expensive. The actual number needs 
@@ -9714,6 +10554,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (parts == 3)
                return cfg;
 
+       if (cfg->verbose_level > 4) {
+               printf ("BEFORE DECOMPSE START\n");
+               mono_print_code (cfg);
+               printf ("BEFORE DECOMPSE END\n");
+       }
+       
        decompose_pass (cfg);
 
        if (cfg->got_var) {
@@ -9737,6 +10583,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                g_list_free (regs);
        }
 
+       /* todo: remove code when we have verified that the liveness for try/catch blocks
+        * works perfectly 
+        */
+       /* 
+        * Currently, this can't be commented out since exception blocks are not
+        * processed during liveness analysis.
+        */
+       mono_liveness_handle_exception_clauses (cfg);
+
        if (cfg->opt & MONO_OPT_LINEARS) {
                GList *vars, *regs;
                
@@ -9820,22 +10675,22 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                        ei->exvar_offset = exvar ? exvar->inst_offset : 0;
 
                        if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
-                               tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->data.filter_offset);
+                               tblock = cfg->cil_offset_to_bb [ec->data.filter_offset];
                                g_assert (tblock);
                                ei->data.filter = cfg->native_code + tblock->native_offset;
                        } else {
                                ei->data.catch_class = ec->data.catch_class;
                        }
 
-                       tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
+                       tblock = cfg->cil_offset_to_bb [ec->try_offset];
                        g_assert (tblock);
                        ei->try_start = cfg->native_code + tblock->native_offset;
                        g_assert (tblock->native_offset);
-                       tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
+                       tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
                        g_assert (tblock);
                        ei->try_end = cfg->native_code + tblock->native_offset;
                        g_assert (tblock->native_offset);
-                       tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
+                       tblock = cfg->cil_offset_to_bb [ec->handler_offset];
                        g_assert (tblock);
                        ei->handler_start = cfg->native_code + tblock->native_offset;
                }
@@ -9877,27 +10732,22 @@ static gpointer
 mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
 {
        MonoCompile *cfg;
-       GHashTable *jit_code_hash;
        gpointer code = NULL;
        MonoJitInfo *info;
 
-       jit_code_hash = target_domain->jit_code_hash;
-
        method = mono_get_inflated_method (method);
 
 #ifdef MONO_USE_AOT_COMPILER
-       if (!mono_compile_aot && (opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
-               MonoJitInfo *info;
+       if ((opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
                MonoDomain *domain = mono_domain_get ();
 
-               mono_domain_lock (domain);
-
                mono_class_init (method->klass);
-               if ((info = mono_aot_get_method (domain, method))) {
-                       g_hash_table_insert (domain->jit_code_hash, method, info);
+
+               mono_domain_lock (domain);
+               if ((code = mono_aot_get_method (domain, method))) {
                        mono_domain_unlock (domain);
                        mono_runtime_class_init (mono_class_vtable (domain, method->klass));
-                       return info->code_start;
+                       return code;
                }
 
                mono_domain_unlock (domain);
@@ -9909,7 +10759,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                MonoMethod *nm;
                MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
 
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
                        g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
 
                if (!piinfo->addr) {
@@ -9957,11 +10807,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                /* Throw a type load exception if needed */
                MonoLoaderError *error = mono_loader_get_last_error ();
 
-               mono_destroy_compile (cfg);
                if (error) {
                        MonoException *ex = mono_loader_error_prepare_exception (error);
+                       mono_destroy_compile (cfg);
                        mono_raise_exception (ex);
                } else {
+                       if (cfg->exception_ptr) {
+                               MonoException *ex = mono_class_get_exception_for_failure (cfg->exception_ptr);
+                               mono_destroy_compile (cfg);
+                               mono_raise_exception (ex);
+                       }
                        g_assert_not_reached ();
                }
        }
@@ -10005,7 +10860,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        /* Check if some other thread already did the job. In this case, we can
        discard the code this thread generated. */
 
-       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
                /* We can't use a domain specific method in another domain */
                if ((target_domain == mono_domain_get ()) || info->domain_neutral) {
                        code = info->code_start;
@@ -10014,7 +10869,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        }
        
        if (code == NULL) {
-               g_hash_table_insert (jit_code_hash, method, cfg->jit_info);
+               mono_internal_hash_table_insert (&target_domain->jit_code_hash, method, cfg->jit_info);
                code = cfg->native_code;
        }
 
@@ -10073,7 +10928,7 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
 
        mono_domain_lock (target_domain);
 
-       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -10134,7 +10989,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
                return;
        mono_domain_lock (domain);
        g_hash_table_remove (domain->dynamic_code_hash, method);
-       g_hash_table_remove (domain->jit_code_hash, method);
+       mono_internal_hash_table_remove (&domain->jit_code_hash, method);
        g_hash_table_remove (domain->jump_trampoline_hash, method);
        mono_domain_unlock (domain);
 
@@ -10179,7 +11034,7 @@ mono_jit_find_compiled_method (MonoDomain *domain, MonoMethod *method)
 
        mono_domain_lock (target_domain);
 
-       if ((info = g_hash_table_lookup (target_domain->jit_code_hash, method))) {
+       if ((info = mono_internal_hash_table_lookup (&target_domain->jit_code_hash, method))) {
                /* We can't use a domain specific method in another domain */
                if (! ((domain != target_domain) && !info->domain_neutral)) {
                        mono_domain_unlock (target_domain);
@@ -10225,29 +11080,33 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        return runtime_invoke (obj, params, exc, compiled_method);
 }
 
+#ifdef MONO_GET_CONTEXT
+#define GET_CONTEXT MONO_GET_CONTEXT
+#endif
+
+#ifndef GET_CONTEXT
 #ifdef PLATFORM_WIN32
 #define GET_CONTEXT \
        struct sigcontext *ctx = (struct sigcontext*)_dummy;
 #else
-#ifdef __sparc
+#ifdef MONO_ARCH_USE_SIGACTION
 #define GET_CONTEXT \
     void *ctx = context;
-#elif defined(sun)    // Solaris x86
+#elif defined(__sparc__)
 #define GET_CONTEXT \
-    ucontext_t *uctx = context; \
-    struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
-#elif defined (MONO_ARCH_USE_SIGACTION)
-#define GET_CONTEXT \
-    void *ctx = context;
+    void *ctx = sigctx;
 #else
 #define GET_CONTEXT \
        void **_p = (void **)&_dummy; \
        struct sigcontext *ctx = (struct sigcontext *)++_p;
 #endif
 #endif
+#endif
 
 #ifdef MONO_ARCH_USE_SIGACTION
 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
+#elif defined(__sparc__)
+#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
 #else
 #define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
 #endif
@@ -10334,6 +11193,8 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+#ifndef PLATFORM_WIN32
+
 static void
 SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
 {
@@ -10403,6 +11264,16 @@ SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
        mono_print_thread_dump (ctx);
 }
 
+static void
+SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+{
+       gboolean enabled = mono_trace_is_enabled ();
+
+       mono_trace_enable (!enabled);
+}
+
+#endif
+
 static void
 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
 {
@@ -10414,13 +11285,126 @@ SIG_HANDLER_SIGNATURE (sigint_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+#ifdef PLATFORM_MACOSX
+
+/*
+ * This code disables the CrashReporter of MacOS X by installing
+ * a dummy Mach exception handler.
+ */
+
+/*
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
+ */
+extern
+boolean_t
+exc_server (mach_msg_header_t *request_msg,
+           mach_msg_header_t *reply_msg);
+
+/*
+ * The exception message
+ */
+typedef struct {
+       mach_msg_base_t msg;  /* common mach message header */
+       char payload [1024];  /* opaque */
+} mach_exception_msg_t;
+
+/* The exception port */
+static mach_port_t mach_exception_port = VM_MAP_NULL;
+
+/*
+ * Implicitly called by exc_server. Must be public.
+ *
+ * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
+ */
+kern_return_t
+catch_exception_raise (
+       mach_port_t exception_port,
+       mach_port_t thread,
+       mach_port_t task,
+       exception_type_t exception,
+       exception_data_t code,
+       mach_msg_type_number_t code_count)
+{
+       /* consume the exception */
+       return KERN_FAILURE;
+}
+
+/*
+ * Exception thread handler.
+ */
+static
+void *
+mach_exception_thread (void *arg)
+{
+       for (;;) {
+               mach_exception_msg_t request;
+               mach_exception_msg_t reply;
+               mach_msg_return_t result;
+
+               /* receive from "mach_exception_port" */
+               result = mach_msg (&request.msg.header,
+                                  MACH_RCV_MSG | MACH_RCV_LARGE,
+                                  0,
+                                  sizeof (request),
+                                  mach_exception_port,
+                                  MACH_MSG_TIMEOUT_NONE,
+                                  MACH_PORT_NULL);
+
+               g_assert (result == MACH_MSG_SUCCESS);
+
+               /* dispatch to catch_exception_raise () */
+               exc_server (&request.msg.header, &reply.msg.header);
+
+               /* send back to sender */
+               result = mach_msg (&reply.msg.header,
+                                  MACH_SEND_MSG,
+                                  reply.msg.header.msgh_size,
+                                  0,
+                                  MACH_PORT_NULL,
+                                  MACH_MSG_TIMEOUT_NONE,
+                                  MACH_PORT_NULL);
+
+               g_assert (result == MACH_MSG_SUCCESS);
+       }
+       return NULL;
+}
+
 static void
-SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
+macosx_register_exception_handler ()
 {
-       gboolean enabled = mono_trace_is_enabled ();
+       mach_port_t task;
+       pthread_attr_t attr;
+       pthread_t thread;
 
-       mono_trace_enable (!enabled);
+       if (mach_exception_port != VM_MAP_NULL)
+               return;
+
+       task = mach_task_self ();
+
+       /* create the "mach_exception_port" with send & receive rights */
+       g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
+                                     &mach_exception_port) == KERN_SUCCESS);
+       g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
+                                         MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
+
+       /* create the exception handler thread */
+       g_assert (!pthread_attr_init (&attr));
+       g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
+       g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
+       pthread_attr_destroy (&attr);
+
+       /*
+        * register "mach_exception_port" as a receiver for the
+        * EXC_BAD_ACCESS exception
+        *
+        * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
+        */
+       g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
+                                           mach_exception_port,
+                                           EXCEPTION_DEFAULT,
+                                           MACHINE_THREAD_STATE) == KERN_SUCCESS);
 }
+#endif
 
 #ifndef PLATFORM_WIN32
 static void
@@ -10439,6 +11423,18 @@ add_signal_handler (int signo, gpointer handler)
 #endif
        g_assert (sigaction (signo, &sa, NULL) != -1);
 }
+
+static void
+remove_signal_handler (int signo)
+{
+       struct sigaction sa;
+
+       sa.sa_handler = SIG_DFL;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = 0;
+
+       g_assert (sigaction (signo, &sa, NULL) != -1);
+}
 #endif
 
 static void
@@ -10458,10 +11454,10 @@ mono_runtime_install_handlers (void)
 
 #else /* !PLATFORM_WIN32 */
 
-       /* libpthreads has its own implementation of sigaction(),
-        * but it seems to work well with our current exception
-        * handlers. If not we must call syscall directly instead 
-        * of sigaction */
+
+#ifdef PLATFORM_MACOSX
+       macosx_register_exception_handler ();
+#endif
 
        if (debug_options.handle_sigint)
                add_signal_handler (SIGINT, sigint_signal_handler);
@@ -10490,6 +11486,30 @@ mono_runtime_install_handlers (void)
 #endif /* PLATFORM_WIN32 */
 }
 
+static void
+mono_runtime_cleanup_handlers (void)
+{
+#ifdef PLATFORM_WIN32
+       win32_seh_cleanup();
+#else
+       if (debug_options.handle_sigint)
+               remove_signal_handler (SIGINT);
+
+       remove_signal_handler (SIGFPE);
+       remove_signal_handler (SIGQUIT);
+       remove_signal_handler (SIGILL);
+       remove_signal_handler (SIGBUS);
+       if (mono_jit_trace_calls != NULL)
+               remove_signal_handler (SIGUSR2);
+
+       remove_signal_handler (mono_thread_get_abort_signal ());
+
+       remove_signal_handler (SIGABRT);
+
+       remove_signal_handler (SIGSEGV);
+#endif /* PLATFORM_WIN32 */
+}
+
 
 #ifdef HAVE_LINUX_RTC_H
 #include <linux/rtc.h>
@@ -10518,6 +11538,26 @@ enable_rtc_timer (gboolean enable)
 }
 #endif
 
+#ifdef PLATFORM_WIN32
+static HANDLE win32_main_thread;
+static MMRESULT win32_timer;
+
+static void CALLBACK
+win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+       CONTEXT context;
+
+       context.ContextFlags = CONTEXT_CONTROL;
+       if (GetThreadContext (win32_main_thread, &context)) {
+#ifdef _WIN64
+               mono_profiler_stat_hit ((guchar *) context.Rip, &context);
+#else
+               mono_profiler_stat_hit ((guchar *) context.Eip, &context);
+#endif
+       }
+}
+#endif
+
 static void
 setup_stat_profiler (void)
 {
@@ -10570,6 +11610,27 @@ setup_stat_profiler (void)
                return;
        inited = 1;
        add_signal_handler (SIGPROF, sigprof_signal_handler);
+#elif defined (PLATFORM_WIN32)
+       static int inited = 0;
+       TIMECAPS timecaps;
+
+       if (inited)
+               return;
+
+       inited = 1;
+       if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
+               return;
+
+       if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
+               return;
+
+       if (timeBeginPeriod (1) != TIMERR_NOERROR)
+               return;
+
+       if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
+               timeEndPeriod (1);
+               return;
+       }
 #endif
 }
 
@@ -10617,21 +11678,30 @@ mini_parse_debug_options (void)
                        debug_options.keep_delegates = TRUE;
                else if (!strcmp (arg, "collect-pagefault-stats"))
                        debug_options.collect_pagefault_stats = TRUE;
+               else if (!strcmp (arg, "break-on-unverified"))
+                       debug_options.break_on_unverified = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified'\n");
                        exit (1);
                }
        }
 }
 
 MonoDomain *
-mini_init (const char *filename)
+mini_init (const char *filename, const char *runtime_version)
 {
        MonoDomain *domain;
 
+#ifdef __linux__
+       if (access ("/proc/self/maps", F_OK) != 0) {
+               g_print ("Mono requires /proc to be mounted.\n");
+               exit (1);
+       }
+#endif
+
        /* Happens when using the embedding interface */
-       if (default_opt == 0)
+       if (!default_opt_set)
                default_opt = mono_parse_default_optimizations (NULL);
 
        InitializeCriticalSection (&jit_mutex);
@@ -10675,7 +11745,17 @@ mini_init (const char *filename)
                 * GC_register_stackbottom as well, but don't know how.
                 */
 #else
-               GC_stackbottom = (char*)sstart + size;
+               /* apparently with some linuxthreads implementations sstart can be NULL,
+                * fallback to the more imprecise method (bug# 78096).
+                */
+               if (sstart) {
+                       GC_stackbottom = (char*)sstart + size;
+               } else {
+                       gsize stack_bottom = (gsize)&domain;
+                       stack_bottom += 4095;
+                       stack_bottom &= ~4095;
+                       GC_stackbottom = (char*)stack_bottom;
+               }
 #endif
        }
 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
@@ -10719,6 +11799,7 @@ mini_init (const char *filename)
        mono_install_stack_walk (mono_jit_walk_stack);
        mono_install_init_vtable (mono_aot_init_vtable);
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
+       mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
        if (debug_options.collect_pagefault_stats) {
@@ -10726,7 +11807,10 @@ mini_init (const char *filename)
                mono_aot_set_make_unreadable (TRUE);
        }
 
-       domain = mono_init_from_assembly (filename, filename);
+       if (runtime_version)
+               domain = mono_init_version (filename, runtime_version);
+       else
+               domain = mono_init_from_assembly (filename, filename);
        mono_icall_init ();
 
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
@@ -10794,17 +11878,19 @@ mini_init (const char *filename)
 #endif
 
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
-       mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, TRUE);
-       mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, TRUE);
-       mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, TRUE);
-       mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, TRUE);
+       mono_register_opcode_emulation (CEE_DIV, "__emul_idiv", "int32 int32 int32", mono_idiv, FALSE);
+       mono_register_opcode_emulation (CEE_DIV_UN, "__emul_idiv_un", "int32 int32 int32", mono_idiv_un, FALSE);
+       mono_register_opcode_emulation (CEE_REM, "__emul_irem", "int32 int32 int32", mono_irem, FALSE);
+       mono_register_opcode_emulation (CEE_REM_UN, "__emul_irem_un", "int32 int32 int32", mono_irem_un, FALSE);
 #endif
 
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
-       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, TRUE);
-       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, TRUE);
+       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
+       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
        mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
-       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, TRUE);
+#endif
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
+       mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
 #endif
 
        mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", "ulong double", mono_fconv_u8, FALSE);
@@ -10831,6 +11917,42 @@ mini_init (const char *filename)
        mono_register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, FALSE);
 #endif
 
+#ifdef MONO_ARCH_SOFT_FLOAT
+       mono_register_opcode_emulation (OP_FSUB, "__emul_fsub", "double double double", mono_fsub, FALSE);
+       mono_register_opcode_emulation (OP_FADD, "__emul_fadd", "double double double", mono_fadd, FALSE);
+       mono_register_opcode_emulation (OP_FMUL, "__emul_fmul", "double double double", mono_fmul, FALSE);
+       mono_register_opcode_emulation (OP_FNEG, "__emul_fneg", "double double", mono_fneg, FALSE);
+       mono_register_opcode_emulation (CEE_CONV_R8, "__emul_conv_r8", "double int32", mono_conv_to_r8, FALSE);
+       mono_register_opcode_emulation (CEE_CONV_R4, "__emul_conv_r4", "double int32", mono_conv_to_r4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_R4, "__emul_fconv_to_r4", "double double", mono_fconv_r4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I1, "__emul_fconv_to_i1", "int8 double", mono_fconv_i1, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I2, "__emul_fconv_to_i2", "int16 double", mono_fconv_i2, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
+
+       mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
+       mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
+       mono_register_opcode_emulation (OP_FBGT, "__emul_fcmp_gt", "uint32 double double", mono_fcmp_gt, FALSE);
+       mono_register_opcode_emulation (OP_FBLE, "__emul_fcmp_le", "uint32 double double", mono_fcmp_le, FALSE);
+       mono_register_opcode_emulation (OP_FBGE, "__emul_fcmp_ge", "uint32 double double", mono_fcmp_ge, FALSE);
+       mono_register_opcode_emulation (OP_FBNE_UN, "__emul_fcmp_ne_un", "uint32 double double", mono_fcmp_ne_un, FALSE);
+       mono_register_opcode_emulation (OP_FBLT_UN, "__emul_fcmp_lt_un", "uint32 double double", mono_fcmp_lt_un, FALSE);
+       mono_register_opcode_emulation (OP_FBGT_UN, "__emul_fcmp_gt_un", "uint32 double double", mono_fcmp_gt_un, FALSE);
+       mono_register_opcode_emulation (OP_FBLE_UN, "__emul_fcmp_le_un", "uint32 double double", mono_fcmp_le_un, FALSE);
+       mono_register_opcode_emulation (OP_FBGE_UN, "__emul_fcmp_ge_un", "uint32 double double", mono_fcmp_ge_un, FALSE);
+
+       mono_register_opcode_emulation (OP_FCEQ, "__emul_fcmp_ceq", "uint32 double double", mono_fceq, FALSE);
+       mono_register_opcode_emulation (OP_FCGT, "__emul_fcmp_cgt", "uint32 double double", mono_fcgt, FALSE);
+       mono_register_opcode_emulation (OP_FCGT_UN, "__emul_fcmp_cgt_un", "uint32 double double", mono_fcgt_un, FALSE);
+       mono_register_opcode_emulation (OP_FCLT, "__emul_fcmp_clt", "uint32 double double", mono_fclt, FALSE);
+       mono_register_opcode_emulation (OP_FCLT_UN, "__emul_fcmp_clt_un", "uint32 double double", mono_fclt_un, FALSE);
+
+       register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
+       register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
+       register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
+#endif
+
 #if SIZEOF_VOID_P == 4
        mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, TRUE);
 #endif
@@ -10842,7 +11964,6 @@ mini_init (const char *filename)
        register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
        register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
-       register_icall (mono_helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
        register_icall (mono_helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", FALSE);
        register_icall (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
        register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
@@ -10852,7 +11973,7 @@ mini_init (const char *filename)
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldftn_nosync, "mono_ldftn_nosync", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
-       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
+       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr ptr", FALSE);
        register_icall (mono_helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
        register_icall (mono_helper_ldstr_mscorlib, "helper_ldstr_mscorlib", "object int", FALSE);
        register_icall (mono_helper_newobj_mscorlib, "helper_newobj_mscorlib", "object int", FALSE);
@@ -10894,12 +12015,16 @@ print_jit_stats (void)
                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 ("Locals stack size:      %ld\n", mono_jit_stats.locals_stack_size);
+
                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 ("Generic vtables:        %ld\n", mono_stats.generic_vtable_count);
+               g_print ("Methods:                %ld\n", mono_stats.method_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);
+               g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
 
                g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
                g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
@@ -10950,14 +12075,10 @@ mini_cleanup (MonoDomain *domain)
 
        mono_icall_cleanup ();
 
-#ifdef PLATFORM_WIN32
-       win32_seh_cleanup();
-#endif
+       mono_runtime_cleanup_handlers ();
 
        mono_domain_free (domain, TRUE);
 
-       mono_trace_cleanup ();
-       
        mono_code_manager_destroy (global_codeman);
        g_hash_table_destroy (jit_icall_name_hash);
        if (class_init_hash_addr)
@@ -10969,6 +12090,12 @@ mini_cleanup (MonoDomain *domain)
        mono_trace_cleanup ();
 
        mono_counters_dump (-1, stdout);
+
+       TlsFree(mono_jit_tls_id);
+
+       DeleteCriticalSection (&jit_mutex);
+
+       DeleteCriticalSection (&mono_delegate_section);
 }
 
 void
@@ -10976,6 +12103,7 @@ mono_set_defaults (int verbose_level, guint32 opts)
 {
        mini_verbose = verbose_level;
        default_opt = opts;
+       default_opt_set = TRUE;
 }
 
 static void