* mini.c: Made so that inline is locally disabled if it would
[mono.git] / mono / mini / mini.c
index f1ca32e0d9e2a27ea1de000cf944de63d2db8077..a887fda2d3ad2940be7ea7243a54bc49e148ab9e 100644 (file)
@@ -51,6 +51,8 @@
 #include <mono/metadata/rawbuffer.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
+#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-logger.h>
 #include <mono/os/gc_wrapper.h>
 
 #include "mini.h"
 #include "inssel.h"
 #include "trace.h"
 
-#include "jit-icalls.c"
+#include "jit-icalls.h"
 
 #include "aliasing.h"
 
+#define BRANCH_COST 100
+#define INLINE_LENGTH_LIMIT 20
+#define INLINE_FAILURE do {\
+               if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
+                       goto inline_failure;\
+       } while (0)
+
 /* 
  * this is used to determine when some branch optimizations are possible: we exclude FP compares
  * because they have weird semantics with NaNs.
@@ -70,6 +79,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 == CEE_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);
@@ -77,9 +88,10 @@ gboolean  mono_arch_print_tree(MonoInst *tree, int arity);
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
 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);
 
 static void handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, 
-                         const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native);
+                         const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier);
 
 static void dec_foreach (MonoInst *tree, MonoCompile *cfg);
 
@@ -92,6 +104,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;
@@ -159,26 +172,54 @@ mono_create_ftnptr (MonoDomain *domain, gpointer addr)
 #endif
 }
 
+typedef struct {
+       void *ip;
+       MonoMethod *method;
+} FindTrampUserData;
+
+static void
+find_tramp (gpointer key, gpointer value, gpointer user_data)
+{
+       FindTrampUserData *ud = (FindTrampUserData*)user_data;
+
+       if (value == ud->ip)
+               ud->method = (MonoMethod*)key;
+}
+
 /* debug function */
 G_GNUC_UNUSED static char*
 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);
        if (!ji) {
-               return NULL;
+               user_data.ip = ip;
+               user_data.method = NULL;
+               mono_domain_lock (domain);
+               g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+               mono_domain_unlock (domain);
+               if (user_data.method) {
+                       char *mname = mono_method_full_name (user_data.method, TRUE);
+                       res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
+                       g_free (mname);
+                       return res;
+               }
+               else
+                       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;
@@ -191,36 +232,42 @@ mono_pmip (void *ip)
 }
 
 /* debug function */
-G_GNUC_UNUSED static void
-print_method_from_ip (void *ip)
+void
+mono_print_method_from_ip (void *ip)
 {
        MonoJitInfo *ji;
        char *method;
-       char *source;
+       MonoDebugSourceLocation *source;
        MonoDomain *domain = mono_domain_get ();
+       FindTrampUserData user_data;
        
        ji = mono_jit_info_table_find (domain, ip);
        if (!ji) {
-               g_print ("No method at %p\n", ip);
+               user_data.ip = ip;
+               user_data.method = NULL;
+               mono_domain_lock (domain);
+               g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+               mono_domain_unlock (domain);
+               if (user_data.method) {
+                       char *mname = mono_method_full_name (user_data.method, TRUE);
+                       printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
+                       g_free (mname);
+               }
+               else
+                       g_print ("No method at %p\n", 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);
 }
-
-G_GNUC_UNUSED void
-mono_print_method_from_ip (void *ip)
-{
-       print_method_from_ip (ip);
-}
        
 /* 
  * mono_method_same_domain:
@@ -287,6 +334,9 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
         (vi)->idx = (id); \
 } while (0)
 
+//#define UNVERIFIED do { G_BREAKPOINT (); goto unverified; } while (0)
+#define UNVERIFIED do { goto unverified; } while (0)
+
 /*
  * Basic blocks have two numeric identifiers:
  * dfn: Depth First Number
@@ -302,7 +352,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define GET_BBLOCK(cfg,bbhash,tblock,ip) do {  \
                (tblock) = g_hash_table_lookup (bbhash, (ip));  \
                if (!(tblock)) {        \
-                       if ((ip) >= end || (ip) < header->code) goto unverified; \
+                       if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
                        (tblock) = NEW_BBLOCK (cfg);    \
                        (tblock)->cil_code = (ip);      \
                        ADD_BBLOCK (cfg, (bbhash), (tblock));   \
@@ -357,7 +407,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;                          \
@@ -367,7 +417,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
@@ -380,12 +431,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
@@ -402,15 +454,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); \
                } \
@@ -735,6 +787,52 @@ link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
        }
 }
 
+/**
+ * mono_unlink_bblock:
+ *
+ *   Unlink two basic blocks.
+ */
+static void
+mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
+{
+       int i, pos;
+       gboolean found;
+
+       found = FALSE;
+       for (i = 0; i < from->out_count; ++i) {
+               if (to == from->out_bb [i]) {
+                       found = TRUE;
+                       break;
+               }
+       }
+       if (found) {
+               pos = 0;
+               for (i = 0; i < from->out_count; ++i) {
+                       if (from->out_bb [i] != to)
+                               from->out_bb [pos ++] = from->out_bb [i];
+               }
+               g_assert (pos == from->out_count - 1);
+               from->out_count--;
+       }
+
+       found = FALSE;
+       for (i = 0; i < to->in_count; ++i) {
+               if (from == to->in_bb [i]) {
+                       found = TRUE;
+                       break;
+               }
+       }
+       if (found) {
+               pos = 0;
+               for (i = 0; i < to->in_count; ++i) {
+                       if (to->in_bb [i] != from)
+                               to->in_bb [pos ++] = to->in_bb [i];
+               }
+               g_assert (pos == to->in_count - 1);
+               to->in_count--;
+       }
+}
+
 /**
  * mono_find_block_region:
  *
@@ -982,117 +1080,6 @@ reverse_branch_op (guint32 opcode)
        return opcode;
 }
 
-guint
-mono_type_to_ldind (MonoType *type)
-{
-       if (type->byref)
-               return CEE_LDIND_I;
-
-handle_enum:
-       switch (type->type) {
-       case MONO_TYPE_I1:
-               return CEE_LDIND_I1;
-       case MONO_TYPE_U1:
-       case MONO_TYPE_BOOLEAN:
-               return CEE_LDIND_U1;
-       case MONO_TYPE_I2:
-               return CEE_LDIND_I2;
-       case MONO_TYPE_U2:
-       case MONO_TYPE_CHAR:
-               return CEE_LDIND_U2;
-       case MONO_TYPE_I4:
-               return CEE_LDIND_I4;
-       case MONO_TYPE_U4:
-               return CEE_LDIND_U4;
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_FNPTR:
-               return CEE_LDIND_I;
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_OBJECT:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_ARRAY:    
-               return CEE_LDIND_REF;
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-               return CEE_LDIND_I8;
-       case MONO_TYPE_R4:
-               return CEE_LDIND_R4;
-       case MONO_TYPE_R8:
-               return CEE_LDIND_R8;
-       case MONO_TYPE_VALUETYPE:
-               if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
-                       goto handle_enum;
-               }
-               return CEE_LDOBJ;
-       case MONO_TYPE_TYPEDBYREF:
-               return CEE_LDOBJ;
-       case MONO_TYPE_GENERICINST:
-               type = &type->data.generic_class->container_class->byval_arg;
-               goto handle_enum;
-       default:
-               g_error ("unknown type 0x%02x in type_to_ldind", type->type);
-       }
-       return -1;
-}
-
-guint
-mono_type_to_stind (MonoType *type)
-{
-       if (type->byref)
-               return CEE_STIND_I;
-
-handle_enum:
-       switch (type->type) {
-       case MONO_TYPE_I1:
-       case MONO_TYPE_U1:
-       case MONO_TYPE_BOOLEAN:
-               return CEE_STIND_I1;
-       case MONO_TYPE_I2:
-       case MONO_TYPE_U2:
-       case MONO_TYPE_CHAR:
-               return CEE_STIND_I2;
-       case MONO_TYPE_I4:
-       case MONO_TYPE_U4:
-               return CEE_STIND_I4;
-       case MONO_TYPE_I:
-       case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
-       case MONO_TYPE_FNPTR:
-               return CEE_STIND_I;
-       case MONO_TYPE_CLASS:
-       case MONO_TYPE_STRING:
-       case MONO_TYPE_OBJECT:
-       case MONO_TYPE_SZARRAY:
-       case MONO_TYPE_ARRAY:    
-               return CEE_STIND_REF;
-       case MONO_TYPE_I8:
-       case MONO_TYPE_U8:
-               return CEE_STIND_I8;
-       case MONO_TYPE_R4:
-               return CEE_STIND_R4;
-       case MONO_TYPE_R8:
-               return CEE_STIND_R8;
-       case MONO_TYPE_VALUETYPE:
-               if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
-                       goto handle_enum;
-               }
-               return CEE_STOBJ;
-       case MONO_TYPE_TYPEDBYREF:
-               return CEE_STOBJ;
-       case MONO_TYPE_GENERICINST:
-               type = &type->data.generic_class->container_class->byval_arg;
-               goto handle_enum;
-       default:
-               g_error ("unknown type 0x%02x in type_to_stind", type->type);
-       }
-       return -1;
-}
-
 /*
  * Returns the type used in the eval stack when @type is loaded.
  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
@@ -1102,13 +1089,12 @@ type_to_eval_stack_type (MonoType *type, MonoInst *inst)
 {
        MonoClass *klass;
 
+       inst->klass = klass = mono_class_from_mono_type (type);
        if (type->byref) {
                inst->type = STACK_MP;
                return;
        }
 
-       klass = mono_class_from_mono_type (type);
-
 handle_enum:
        switch (type->type) {
        case MONO_TYPE_VOID:
@@ -1633,7 +1619,19 @@ 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_MP:
+               /* 
+                * FIXME: This doesn't work because mono_class_from_mono_type ()
+                * returns the original klass for a byref type, not a 'byref' class,
+                * causing the JIT to create variables with the wrong type, for
+                * example.
+                */
+               /*
+               if (ins->klass)
+                       return &ins->klass->this_arg;
+               else
+               */
+                       return &mono_defaults.object_class->this_arg;
        case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
        case STACK_VTYPE: return &ins->klass->byval_arg;
        default:
@@ -1741,7 +1739,7 @@ mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest
        NEW_TEMPSTORE (cfg, inst, dest, load);
        if (inst->opcode == CEE_STOBJ) {
                NEW_TEMPLOADA (cfg, inst, dest);
-               handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE);
+               handle_stobj (cfg, bb, inst, load, NULL, inst->klass, TRUE, FALSE, FALSE);
        } else {
                inst->cil_code = NULL;
                mono_add_ins_to_end (bb, inst);
@@ -1781,6 +1779,66 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
        return res;
 }
 
+/*
+ * 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 gboolean
+merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
+{
+       int i;
+
+       if (cfg->dont_verify_stack_merge)
+               return TRUE;
+
+       /* FIXME: Implement all checks from the spec */
+
+       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 TRUE;
+}
+
 /*
  * This function is called to handle items that are left on the evaluation stack
  * at basic block boundaries. What happens is that we save the values to local variables
@@ -1791,18 +1849,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);
@@ -1863,7 +1967,7 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
                if (inst->opcode == CEE_STOBJ) {
                        NEW_TEMPLOADA (cfg, inst, locals [i]->inst_c0);
-                       handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE);
+                       handle_stobj (cfg, bb, inst, sp [i], sp [i]->cil_code, inst->klass, TRUE, FALSE, FALSE);
                } else {
                        inst->cil_code = sp [i]->cil_code;
                        mono_add_ins_to_end (bb, inst);
@@ -2004,7 +2108,7 @@ handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack,
                        store->cil_code = ins->cil_code;
                        if (store->opcode == CEE_STOBJ) {
                                NEW_TEMPLOADA (cfg, store, temp->inst_c0);
-                               handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE);
+                               handle_stobj (cfg, bblock, store, ins, ins->cil_code, temp->klass, FALSE, FALSE, FALSE);
                        } else
                                MONO_ADD_INS (bblock, store);
                        NEW_TEMPLOAD (cfg, load, temp->inst_c0);
@@ -2034,7 +2138,9 @@ target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
 
        if (target->byref) {
                /* FIXME: check that the pointed to types match */
-               if (arg->type == STACK_MP && arg->type == STACK_PTR)
+               if (arg->type == STACK_MP)
+                       return arg->klass != mono_class_from_mono_type (target);
+               if (arg->type == STACK_PTR)
                        return 0;
                return 1;
        }
@@ -2053,9 +2159,13 @@ 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_PTR:
+               /* STACK_MP is needed when setting pinned locals */
+               if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
+                       return 1;
+               return 0;
        case MONO_TYPE_I:
        case MONO_TYPE_U:
-       case MONO_TYPE_PTR:
        case MONO_TYPE_FNPTR:
                if (arg->type != STACK_I4 && arg->type != STACK_PTR)
                        return 1;
@@ -2327,9 +2437,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod
        call->inst.flags |= MONO_INST_HAS_METHOD;
        call->inst.inst_left = this;
 
-       if (!virtual)
-               mono_get_got_var (cfg);
-       else if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
+       if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
                /* Needed by the code generated in inssel.brg */
                mono_get_got_var (cfg);
 
@@ -2373,8 +2481,6 @@ mono_emit_native_call (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer f
        call = mono_emit_call_args (cfg, bblock, sig, args, FALSE, FALSE, ip, to_end);
        call->fptr = func;
 
-       mono_get_got_var (cfg);
-
        return mono_spill_call (cfg, bblock, call, sig, ret_object, ip, to_end);
 }
 
@@ -2388,7 +2494,6 @@ mono_emit_jit_icall (MonoCompile *cfg, MonoBasicBlock *bblock, gconstpointer fun
                g_assert_not_reached ();
        }
 
-       mono_get_got_var (cfg);
        return mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, args, ip, FALSE, FALSE);
 }
 
@@ -2411,8 +2516,6 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
 
        call = mono_arch_call_opcode (cfg, cfg->cbb, call, FALSE);
 
-       mono_get_got_var (cfg);
-
        if (!MONO_TYPE_IS_VOID (info->sig->ret)) {
                temp = mono_compile_create_var (cfg, info->sig->ret, OP_LOCAL);
                temp->flags |= MONO_INST_IS_TEMP;
@@ -2540,7 +2643,7 @@ get_memcpy_method (void)
 }
 
 static void
-handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
+handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native, gboolean write_barrier) {
        MonoInst *iargs [3];
        int n;
        guint32 align = 0;
@@ -2557,6 +2660,19 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
        else
                n = mono_class_value_size (klass, &align);
 
+#if HAVE_WRITE_BARRIERS
+       /* if native is true there should be no references in the struct */
+       if (write_barrier && klass->has_references && !native) {
+               iargs [0] = dest;
+               iargs [1] = src;
+               NEW_PCONST (cfg, iargs [2], klass);
+
+               mono_emit_jit_icall (cfg, bblock, mono_value_copy, iargs, ip);
+               return;
+       }
+#endif
+
+       /* FIXME: add write barrier handling */
        if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
                MonoInst *inst;
                if (dest->opcode == OP_LDADDR) {
@@ -2650,10 +2766,15 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboole
                NEW_CLASSCONST (cfg, iargs [1], klass);
 
                alloc_ftn = mono_object_new;
+       } else if (cfg->compile_aot && bblock->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
+               /* This happens often in argument checking code, eg. throw new FooException... */
+               /* Avoid relocations by calling a helper function specialized to mscorlib */
+               NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
+               return mono_emit_jit_icall (cfg, bblock, mono_helper_newobj_mscorlib, iargs, ip);
        } else {
                MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
                gboolean pass_lw;
-               
+
                alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
                if (pass_lw) {
                        guint32 lw = vtable->klass->instance_size;
@@ -2711,7 +2832,7 @@ handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const gucha
        vstore->inst_right = val;
 
        if (vstore->opcode == CEE_STOBJ) {
-               handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE);
+               handle_stobj (cfg, bblock, add, val, ip, klass, FALSE, FALSE, TRUE);
        } else
                MONO_ADD_INS (bblock, vstore);
 
@@ -2834,8 +2955,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;
@@ -2862,7 +2989,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
                        return TRUE;
                }
-       } else if (header->code_size < 20)
+       } else if (header->code_size < INLINE_LENGTH_LIMIT)
                return TRUE;
 
        return FALSE;
@@ -2946,9 +3073,9 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        return addr;
 }
 
-static MonoJitICallInfo **emul_opcode_map = NULL;
+MonoJitICallInfo **emul_opcode_map = NULL;
 
-static inline MonoJitICallInfo *
+MonoJitICallInfo *
 mono_find_jit_opcode_emulation (int opcode)
 {
        if  (emul_opcode_map)
@@ -2957,38 +3084,6 @@ mono_find_jit_opcode_emulation (int opcode)
                return NULL;
 }
 
-static MonoException*
-mini_loader_error_to_exception (MonoLoaderError *error)
-{
-       MonoException *ex = NULL;
-
-       switch (error->kind) {
-       case MONO_LOADER_ERROR_TYPE: {
-               MonoString *class_name = mono_string_new (mono_domain_get (), error->class_name);
-               
-               ex = mono_get_exception_type_load (class_name, error->assembly_name);
-               break;
-       }
-       case MONO_LOADER_ERROR_METHOD:
-       case MONO_LOADER_ERROR_FIELD: {
-               char *class_name;
-               
-               class_name = g_strdup_printf ("%s%s%s", error->klass->name_space, *error->klass->name_space ? "." : "", error->klass->name);
-
-               if (error->kind == MONO_LOADER_ERROR_METHOD)
-                       ex = mono_get_exception_missing_method (class_name, error->member_name);
-               else
-                       ex = mono_get_exception_missing_field (class_name, error->member_name);
-               g_free (class_name);
-               break;
-       }
-       default:
-               g_assert_not_reached ();
-       }
-
-       return ex;
-}
-
 static MonoInst*
 mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -3025,10 +3120,9 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        MONO_INST_NEW (cfg, ins, OP_GETTYPE);
                        ins->inst_i0 = args [0];
                        return ins;
-               } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
-#ifdef MONO_ARCH_EMULATE_MUL_DIV
                /* The OP_GETHASHCODE rule depends on OP_MUL */
-#else
+#if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
+               } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
                        MONO_INST_NEW (cfg, ins, OP_GETHASHCODE);
                        ins->inst_i0 = args [0];
                        return ins;
@@ -3061,6 +3155,27 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
        } else if (cmethod->klass == mono_defaults.thread_class) {
                if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
                        return ins;
+       } else if (mini_class_is_system_array (cmethod->klass) &&
+                       strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
+               MonoInst *sp [2];
+               MonoInst *ldelem, *store, *load;
+               MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
+               int n;
+               n = mono_type_to_stind (&eklass->byval_arg);
+               if (n == CEE_STOBJ)
+                       return NULL;
+               sp [0] = args [0];
+               sp [1] = args [1];
+               NEW_LDELEMA (cfg, ldelem, sp, eklass);
+               ldelem->flags |= MONO_INST_NORANGECHECK;
+               MONO_INST_NEW (cfg, store, n);
+               n = mono_type_to_ldind (&eklass->byval_arg);
+               MONO_INST_NEW (cfg, load, mono_type_to_ldind (&eklass->byval_arg));
+               type_to_eval_stack_type (&eklass->byval_arg, load);
+               load->inst_left = ldelem;
+               store->inst_left = args [2];
+               store->inst_right = load;
+               return store;
        }
 
        return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
@@ -3100,7 +3215,7 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                        store->cil_code = sp [0]->cil_code;
                        if (store->opcode == CEE_STOBJ) {
                                NEW_TEMPLOADA (cfg, store, temp->inst_c0);
-                               handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE);
+                               handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, temp->klass, FALSE, FALSE, FALSE);
                        } else {
                                MONO_ADD_INS (bblock, store);
                        } 
@@ -3108,6 +3223,56 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                sp++;
        }
 }
+#define MONO_INLINE_CALLED_LIMITED_METHODS 0
+#define MONO_INLINE_CALLER_LIMITED_METHODS 0
+
+#if (MONO_INLINE_CALLED_LIMITED_METHODS)
+static char*
+mono_inline_called_method_name_limit = NULL;
+static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
+       char *called_method_name = mono_method_full_name (called_method, TRUE);
+       int strncmp_result;
+       
+       if (mono_inline_called_method_name_limit == NULL) {
+               char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
+               if (limit_string != NULL) {
+                       mono_inline_called_method_name_limit = limit_string;
+               } else {
+                       mono_inline_called_method_name_limit = (char *) "";
+               }
+       }
+       
+       strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
+       g_free (called_method_name);
+       
+       //return (strncmp_result <= 0);
+       return (strncmp_result == 0);
+}
+#endif
+
+#if (MONO_INLINE_CALLER_LIMITED_METHODS)
+static char*
+mono_inline_caller_method_name_limit = NULL;
+static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
+       char *caller_method_name = mono_method_full_name (caller_method, TRUE);
+       int strncmp_result;
+       
+       if (mono_inline_caller_method_name_limit == NULL) {
+               char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
+               if (limit_string != NULL) {
+                       mono_inline_caller_method_name_limit = limit_string;
+               } else {
+                       mono_inline_caller_method_name_limit = (char *) "";
+               }
+       }
+       
+       strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
+       g_free (caller_method_name);
+       
+       //return (strncmp_result <= 0);
+       return (strncmp_result == 0);
+}
+#endif
 
 static int
 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
@@ -3118,6 +3283,14 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
        MonoBasicBlock *ebblock, *sbblock;
        int i, costs, new_locals_offset;
        MonoMethod *prev_inlined_method;
+#if (MONO_INLINE_CALLED_LIMITED_METHODS)
+       if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
+               return 0;
+#endif
+#if (MONO_INLINE_CALLER_LIMITED_METHODS)
+       if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
+               return 0;
+#endif
 
        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));
@@ -3206,13 +3379,13 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
  * * consider using an array instead of an hash table (bb_hash)
  */
 
-#define CHECK_TYPE(ins) if (!(ins)->type) goto unverified
-#define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
-#define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
-#define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) goto unverified
-#define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) goto unverified
-#define CHECK_OPSIZE(size) if (ip + size > end) goto unverified
-
+#define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
+#define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
+#define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
+#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
 
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
@@ -3239,7 +3412,7 @@ get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header
                cli_addr = ip - start;
                i = mono_opcode_value ((const guint8 **)&ip, end);
                if (i < 0)
-                       goto unverified;
+                       UNVERIFIED;
                opcode = &mono_opcodes [i];
                switch (opcode->argument) {
                case MonoInlineNone:
@@ -3304,7 +3477,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) {
+                       while ((bb_start >= start) && !bblock) {
                                bblock = g_hash_table_lookup (bbhash, (bb_start));
                                bb_start --;
                        }
@@ -3367,12 +3540,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 */
@@ -3391,8 +3574,110 @@ void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
                cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
                cfg->exception_data = result;
        }
+       
+       return FALSE;
+}
+
+static gboolean
+can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
+{
+       GSList *tmp;
+       if (accessing == accessed)
+               return TRUE;
+       if (!accessed || !accessing)
+               return FALSE;
+       for (tmp = accessed->friend_assembly_names; tmp; tmp = tmp->next) {
+               MonoAssemblyName *friend = tmp->data;
+               /* Be conservative with checks */
+               if (!friend->name)
+                       continue;
+               if (strcmp (accessing->aname.name, friend->name))
+                       continue;
+               if (friend->public_key_token [0]) {
+                       if (!accessing->aname.public_key_token [0])
+                               continue;
+                       if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
+                               continue;
+               }
+               return TRUE;
+       }
+       return FALSE;
 }
 
+/* FIXME: check visibility of type, too */
+static gboolean
+can_access_member (MonoClass *access_klass, MonoClass *member_klass, int access_level)
+{
+       /* Partition I 8.5.3.2 */
+       /* the access level values are the same for fields and methods */
+       switch (access_level) {
+       case FIELD_ATTRIBUTE_COMPILER_CONTROLLED:
+               /* same compilation unit */
+               return access_klass->image == member_klass->image;
+       case FIELD_ATTRIBUTE_PRIVATE:
+               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))
+                       return TRUE;
+               return FALSE;
+       case FIELD_ATTRIBUTE_ASSEMBLY:
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+       case FIELD_ATTRIBUTE_FAMILY:
+               if (mono_class_has_parent (access_klass, member_klass))
+                       return TRUE;
+               return FALSE;
+       case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
+               if (mono_class_has_parent (access_klass, member_klass))
+                       return TRUE;
+               return can_access_internals (access_klass->image->assembly, member_klass->image->assembly);
+       case FIELD_ATTRIBUTE_PUBLIC:
+               return TRUE;
+       }
+       return FALSE;
+}
+
+static gboolean
+can_access_field (MonoMethod *method, MonoClassField *field)
+{
+       /* FIXME: check all overlapping fields */
+       int can = can_access_member (method->klass, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+       if (!can) {
+               MonoClass *nested = method->klass->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, field->parent, field->type->attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK);
+                       if (can)
+                               return TRUE;
+                       nested = nested->nested_in;
+               }
+       }
+       return can;
+}
+
+static gboolean
+can_access_method (MonoMethod *method, MonoMethod *called)
+{
+       int can = can_access_member (method->klass, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+       if (!can) {
+               MonoClass *nested = method->klass->nested_in;
+               while (nested) {
+                       can = can_access_member (nested, called->klass, called->flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK);
+                       if (can)
+                               return TRUE;
+                       nested = nested->nested_in;
+               }
+       }
+       /* 
+        * FIXME:
+        * with generics calls to explicit interface implementations can be expressed
+        * directly: the method is private, but we must allow it. This may be opening
+        * a hole or the generics code should handle this differently.
+        * Maybe just ensure the interface type is public.
+        */
+       if ((called->flags & METHOD_ATTRIBUTE_VIRTUAL) && (called->flags & METHOD_ATTRIBUTE_FINAL))
+               return TRUE;
+       return can;
+}
 
 /*
  * mono_method_to_ir: translates IL into basic blocks containing trees
@@ -3429,6 +3714,21 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoSecurityManager* secman = NULL;
        MonoDeclSecurityActions actions;
        GSList *class_inits = NULL;
+       gboolean dont_verify, dont_verify_stloc;
+
+       /* serialization and xdomain stuff may need access to private fields and methods */
+       dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
+       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 */
+
+       /* still some type unsefety 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);
@@ -3460,10 +3760,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_inline = g_list_prepend (dont_inline, method);
        if (cfg->method == method) {
 
-               if (cfg->method->save_lmf)
-                       /* Needed by the prolog code */
-                       mono_get_got_var (cfg);
-
                if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
                        cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
 
@@ -3528,6 +3824,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
@@ -3542,6 +3842,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        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);
@@ -3655,7 +3960,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end, &err_pos)) {
                ip = err_pos;
-               goto unverified;
+               UNVERIFIED;
        }
 
        if (cfg->method == method)
@@ -3666,6 +3971,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
        for (n = 0; n < sig->param_count; ++n)
                param_types [n + sig->hasthis] = sig->params [n];
+       for (n = 0; n < header->num_locals; ++n) {
+               if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
+                       UNVERIFIED;
+       }
        class_inits = NULL;
 
        /* do this somewhere outside - not here */
@@ -3724,6 +4033,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);
                                }
                                bblock->next_bb = tblock;
                                bblock = tblock;
@@ -3803,9 +4113,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        NEW_LOCSTORE (cfg, ins, n, *sp);
                        ins->cil_code = ip;
+                       if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
+                               UNVERIFIED;
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, n);
-                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                        } else
                                MONO_ADD_INS (bblock, ins);
                        ++ip;
@@ -3837,9 +4149,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        NEW_ARGSTORE (cfg, ins, ip [1], *sp);
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        ins->cil_code = ip;
+                       if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
+                               UNVERIFIED;
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_ARGLOADA (cfg, ins, ip [1]);
-                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                        } else
                                MONO_ADD_INS (bblock, ins);
                        ip += 2;
@@ -3870,9 +4184,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_LOCAL (ip [1]);
                        NEW_LOCSTORE (cfg, ins, ip [1], *sp);
                        ins->cil_code = ip;
+                       if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
+                               UNVERIFIED;
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, ip [1]);
-                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                        } else
                                MONO_ADD_INS (bblock, ins);
                        ip += 2;
@@ -3997,7 +4313,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                store->cil_code = ip;
                                if (store->opcode == CEE_STOBJ) {
                                        NEW_TEMPLOADA (cfg, store, temp->inst_c0);
-                                       handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE);
+                                       handle_stobj (cfg, bblock, store, sp [0], sp [0]->cil_code, store->klass, TRUE, FALSE, FALSE);
                                } else {
                                        MONO_ADD_INS (bblock, store);
                                }
@@ -4023,7 +4339,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_JMP:
                        CHECK_OPSIZE (5);
                        if (stack_start != sp)
-                               goto unverified;
+                               UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, CEE_JMP);
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
@@ -4033,7 +4349,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;
@@ -4075,13 +4392,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if (!cmethod)
                                        goto load_error;
+                               if (!dont_verify && !can_access_method (method, cmethod))
+                                       UNVERIFIED;
 
                                if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
                                        /* MS.NET seems to silently convert this to a callvirt */
                                        virtual = 1;
 
-                               if (!cmethod->klass->inited)
-                                       mono_class_init (cmethod->klass);
+                               if (!cmethod->klass->inited){
+                                       if (!mono_class_init (cmethod->klass))
+                                               goto load_error;
+                               }
 
                                if (mono_method_signature (cmethod)->pinvoke) {
                                        MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod);
@@ -4095,7 +4416,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                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 &&
@@ -4108,20 +4430,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        }
 
-                       if (!virtual) {
-                               mono_get_got_var (cfg);
-                       } else {
-                               /* code in inssel.brg might transform a virtual call to a normal call */
-                               if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
-                                       ((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
-                                        cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))
-                                       mono_get_got_var (cfg);
-                       }
-
-                       if (cmethod && cmethod->klass->generic_container) {
-                               // G_BREAKPOINT ();
-                               goto unverified;
-                       }
+                       if (cmethod && cmethod->klass->generic_container)
+                               UNVERIFIED;
 
                        CHECK_STACK (n);
 
@@ -4160,16 +4470,15 @@ 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;
                                constrained_call = NULL;
                        }
 
-                       if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp)) {
-                               // G_BREAKPOINT ();
-                               goto unverified;
-                       }
+                       if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+                               UNVERIFIED;
 
                        if (cmethod && virtual && 
                            (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
@@ -4180,6 +4489,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *iargs [3];
 
                                g_assert (mono_method_signature (cmethod)->is_inflated);
+                               /* Prevent inlining of methods that contain indirect calls */
+                               INLINE_FAILURE;
 
                                this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
                                this_temp->cil_code = ip;
@@ -4191,7 +4502,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
                                NEW_PCONST (cfg, iargs [1], cmethod);
                                NEW_PCONST (cfg, iargs [2], ((MonoMethodInflated *) cmethod)->context);
-                               temp = mono_emit_jit_icall (cfg, bblock, helper_compile_generic_method, iargs, ip);
+                               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);
@@ -4208,6 +4519,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        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 */
                                for (i = 0; i < n; ++i) {
                                        /* Check if argument is the same */
@@ -4221,7 +4534,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->cil_code = ip;
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_ARGLOADA (cfg, ins, i);
-                                               handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE);
+                                               handle_stobj (cfg, bblock, ins, sp [i], sp [i]->cil_code, ins->klass, FALSE, FALSE, FALSE);
                                        }
                                        else
                                                MONO_ADD_INS (bblock, ins);
@@ -4265,6 +4578,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                                        (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                                       /* Prevent inlining of methods that call wrappers */
+                                       INLINE_FAILURE;
                                        cmethod = mono_marshal_get_native_wrapper (cmethod);
                                        allways = TRUE;
                                }
@@ -4296,6 +4611,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                gboolean has_vtargs = FALSE;
                                int i;
                                
+                               /* Prevent inlining of methods with tail calls (the call stack would be altered) */
+                               INLINE_FAILURE;
                                /* keep it simple */
                                for (i =  fsig->param_count - 1; i >= 0; i--) {
                                        if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
@@ -4327,12 +4644,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        if (*ip == CEE_CALLI) {
-
+                               /* Prevent inlining of methods with indirect calls */
+                               INLINE_FAILURE;
                                if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                        sp++;
-                               }
-                                       
+                               }                                       
                        } else if (array_rank) {
                                MonoInst *addr;
 
@@ -4361,7 +4678,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                 * the same MonoInst is added to two different trees and this is not 
                                                 * allowed by burg.
                                                 */
-                                               mono_emit_jit_icall (cfg, bblock, helper_stelem_ref_check, iargs, ip);
+                                               mono_emit_jit_icall (cfg, bblock, mono_helper_stelem_ref_check, iargs, ip);
 
                                                NEW_TEMPLOAD (cfg, sp [0], array->inst_c0);
                                                NEW_TEMPLOAD (cfg, sp [fsig->param_count], to_store->inst_c0);
@@ -4371,7 +4688,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
                                        ins->cil_code = ip;
                                        if (ins->opcode == CEE_STOBJ) {
-                                               handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE);
+                                               handle_stobj (cfg, bblock, addr, sp [fsig->param_count], ip, mono_class_from_mono_type (fsig->params [fsig->param_count-1]), FALSE, FALSE, TRUE);
                                        } else {
                                                MONO_ADD_INS (bblock, ins);
                                        }
@@ -4390,6 +4707,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                        } else {
+                               /* Prevent inlining of methods which call other methods */
+                               INLINE_FAILURE;
                                if (ip_in_bb (cfg, bblock, ip + 5) 
                                    && (!MONO_TYPE_ISSTRUCT (fsig->ret))
                                    && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
@@ -4421,7 +4740,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        if (store->opcode == CEE_STOBJ) {
                                                g_assert_not_reached ();
                                                NEW_TEMPLOADA (cfg, store, return_var->inst_c0);
-                                               handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE);
+                                               /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
+                                               handle_stobj (cfg, bblock, store, *sp, sp [0]->cil_code, return_var->klass, FALSE, FALSE, FALSE);
                                        } else
                                                MONO_ADD_INS (bblock, store);
                                } 
@@ -4434,7 +4754,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->opcode = mono_type_to_stind (mono_method_signature (method)->ret);
                                        if (ins->opcode == CEE_STOBJ) {
                                                NEW_RETLOADA (cfg, ins);
-                                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                                               /* FIXME: it is possible some optimization will pass the a heap pointer for the struct address, so we'll need the write barrier */
+                                               handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                                        } else {
                                                ins->opcode = OP_SETRET;
                                                ins->cil_code = ip;
@@ -4445,7 +4766,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        }
                        if (sp != stack_start)
-                               goto unverified;
+                               UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, CEE_BR);
                        ins->cil_code = ip++;
                        ins->inst_target_bb = end_bblock;
@@ -4467,16 +4788,17 @@ 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);
                        }
                        start_new_bblock = 1;
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BRFALSE_S:
                case CEE_BRTRUE_S:
                        CHECK_OPSIZE (2);
                        CHECK_STACK (1);
                        if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
-                               goto unverified;
+                               UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
                        ins->cil_code = ip++;
                        target = ip + 1 + *(signed char*)ip;
@@ -4485,8 +4807,9 @@ 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 += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BEQ_S:
                case CEE_BGE_S:
@@ -4508,8 +4831,9 @@ 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 += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BR:
                        CHECK_OPSIZE (5);
@@ -4525,16 +4849,17 @@ 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);
                        }
                        start_new_bblock = 1;
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BRFALSE:
                case CEE_BRTRUE:
                        CHECK_OPSIZE (5);
                        CHECK_STACK (1);
                        if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
-                               goto unverified;
+                               UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip++;
                        target = ip + 4 + (gint32)read32(ip);
@@ -4543,8 +4868,9 @@ 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 += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BEQ:
                case CEE_BGE:
@@ -4566,8 +4892,9 @@ 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 += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_SWITCH:
                        CHECK_OPSIZE (5);
@@ -4577,7 +4904,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        ins->inst_left = *sp;
                        if ((ins->inst_left->type != STACK_I4) && (ins->inst_left->type != STACK_PTR)) 
-                               goto unverified;
+                               UNVERIFIED;
                        ins->cil_code = ip;
                        ip += 5;
                        CHECK_OPSIZE (n * sizeof (guint32));
@@ -4598,10 +4925,11 @@ 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);
-                       inline_costs += 20;
+                       inline_costs += (BRANCH_COST * 2);
                        break;
                case CEE_LDIND_I1:
                case CEE_LDIND_U1:
@@ -4623,6 +4951,8 @@ 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;
                        ++ip;
                        break;
                case CEE_STIND_REF:
@@ -4633,6 +4963,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_STIND_R4:
                case CEE_STIND_R8:
                        CHECK_STACK (2);
+#if HAVE_WRITE_BARRIERS
+                       if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER) {
+                               /* insert call to write barrier */
+                               MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
+                               sp -= 2;
+                               mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), sp, ip, NULL);
+                               ip++;
+                               break;
+                       }
+#endif
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip++;
                        sp -= 2;
@@ -4669,7 +5009,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
-                               mono_get_got_var (cfg);
                        }
                        ip++;
                        break;
@@ -4701,7 +5040,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
-                               mono_get_got_var (cfg);
                        }
                        ip++;
                        break;
@@ -4723,7 +5061,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
-                               mono_get_got_var (cfg);
                        }
                        ip++;                   
                        break;
@@ -4785,6 +5122,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;
@@ -4833,6 +5171,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 = klass;
                                ins->flags |= ins_flag;
                                ins_flag = 0;
                                *sp++ = ins;
@@ -4866,7 +5205,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->cil_code = ip;
                                        g_assert (ins->opcode == CEE_STOBJ);
                                        NEW_LOCLOADA (cfg, ins, loc_index);
-                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                                        ip += 5;
                                        ip += stloc_len;
                                        break;
@@ -4908,6 +5247,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                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) {
@@ -4941,10 +5281,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                MonoInst *iargs [2];
                                                int temp;
 
-                                               /* Avoid creating the string object */
-                                               NEW_IMAGECONST (cfg, iargs [0], image);
-                                               NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
-                                               temp = mono_emit_jit_icall (cfg, bblock, helper_ldstr, iargs, ip);
+                                               if (cfg->compile_aot && cfg->method->klass->image == mono_defaults.corlib) {
+                                                       /* 
+                                                        * Avoid relocations by using a version of helper_ldstr
+                                                        * specialized to mscorlib.
+                                                        */
+                                                       NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
+                                                       temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr_mscorlib, iargs, ip);
+                                               } else {
+                                                       /* Avoid creating the string object */
+                                                       NEW_IMAGECONST (cfg, iargs [0], image);
+                                                       NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
+                                                       temp = mono_emit_jit_icall (cfg, bblock, mono_helper_ldstr, iargs, ip);
+                                               }
                                                NEW_TEMPLOAD (cfg, *sp, temp);
                                        } 
                                        else
@@ -4957,6 +5306,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;
                                        }
                                }
@@ -4977,10 +5327,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
                        fsig = mono_method_get_signature (cmethod, image, token);
 
-                       mono_class_init (cmethod->klass);
+                       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;
@@ -5018,10 +5370,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        /* 
                                         * The code generated by mini_emit_virtual_call () expects
                                         * iargs [0] to be a boxed instance, but luckily the vcall
-                                        * will be transformed into a normal call there. The AOT
-                                        * case needs an already allocate got_var.
+                                        * will be transformed into a normal call there.
                                         */
-                                       mono_get_got_var (cfg);
                                } else {
                                        temp = handle_alloc (cfg, bblock, cmethod->klass, FALSE, ip);
                                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -5057,9 +5407,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                break;
                                                
                                        } else {
+                                               /* Prevent inlining of methods which call other methods */
+                                               INLINE_FAILURE;
                                                mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                        }
                                } else {
+                                       /* Prevent inlining of methods which call other methods */
+                                       INLINE_FAILURE;
                                        /* now call the actual ctor */
                                        mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                }
@@ -5081,7 +5435,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!klass)
                                goto load_error;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -5201,6 +5555,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 */
@@ -5262,6 +5617,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 = klass;
                        *sp++ = add;
                        ip += 5;
                        inline_costs += 2;
@@ -5276,7 +5632,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!klass)
                                goto load_error;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -5336,7 +5692,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        
                        link_bblock (cfg, bblock, end_bblock);
                        start_new_bblock = 1;
-                       mono_get_got_var (cfg);
                        break;
                case CEE_LDFLD:
                case CEE_LDFLDA:
@@ -5355,9 +5710,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                --sp;
                        }
                        if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
-                               goto unverified;
+                               UNVERIFIED;
                        if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
-                               goto unverified;
+                               UNVERIFIED;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        if (method->wrapper_type != MONO_WRAPPER_NONE) {
@@ -5369,12 +5724,14 @@ 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))
+                               UNVERIFIED;
 
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
                        /* FIXME: mark instructions for use in SSA */
                        if (*ip == CEE_STFLD) {
                                if (target_type_is_incompatible (cfg, field->type, sp [1]))
-                                       goto unverified;
+                                       UNVERIFIED;
                                if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
                                        MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
                                        MonoInst *iargs [5];
@@ -5407,6 +5764,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } else {
                                                mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, ip, NULL);
                                        }
+#if HAVE_WRITE_BARRIERS
+                               } else if (mono_type_to_stind (field->type) == CEE_STIND_REF) {
+                                       /* insert call to write barrier */
+                                       MonoMethod *write_barrier = mono_marshal_get_write_barrier ();
+                                       MonoInst *iargs [2];
+                                       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;
+                                       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
                                } else {
                                        MonoInst *store;
                                        NEW_ICONST (cfg, offset_ins, foffset);
@@ -5425,7 +5798,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins_flag = 0;
                                        if (store->opcode == CEE_STOBJ) {
                                                handle_stobj (cfg, bblock, ins, sp [1], ip, 
-                                                             mono_class_from_mono_type (field->type), FALSE, FALSE);
+                                                             mono_class_from_mono_type (field->type), FALSE, FALSE, TRUE);
                                        } else
                                                MONO_ADD_INS (bblock, store);
                                }
@@ -5476,6 +5849,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->type = STACK_MP;
 
                                        if (*ip == CEE_LDFLDA) {
+                                               ins->klass = mono_class_from_mono_type (field->type);
                                                *sp++ = ins;
                                        } else {
                                                MonoInst *load;
@@ -5550,8 +5924,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;
 
@@ -5576,6 +5956,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        /* FIXME: mark instructions for use in SSA */
                        if (*ip == CEE_LDSFLDA) {
+                               ins->klass = mono_class_from_mono_type (field->type);
                                *sp++ = ins;
                        } else if (*ip == CEE_STSFLD) {
                                MonoInst *store;
@@ -5589,7 +5970,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins_flag = 0;
 
                                if (store->opcode == CEE_STOBJ) {
-                                       handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE);
+                                       handle_stobj (cfg, bblock, ins, sp [0], ip, mono_class_from_mono_type (field->type), FALSE, FALSE, FALSE);
                                } else
                                        MONO_ADD_INS (bblock, store);
                        } else {
@@ -5632,6 +6013,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                NEW_ICONST (cfg, *sp, *((guint32 *)addr));
                                                sp++;
                                                break;
+#ifndef HAVE_MOVING_COLLECTOR
                                        case MONO_TYPE_I:
                                        case MONO_TYPE_U:
                                        case MONO_TYPE_STRING:
@@ -5645,6 +6027,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                type_to_eval_stack_type (field->type, *sp);
                                                sp++;
                                                break;
+#endif
                                        case MONO_TYPE_I8:
                                        case MONO_TYPE_U8:
                                                MONO_INST_NEW (cfg, *sp, OP_I8CONST);
@@ -5688,7 +6071,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
                        n = mono_type_to_stind (&klass->byval_arg);
                        if (n == CEE_STOBJ) {
-                               handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
+                               handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE, TRUE);
                        } else {
                                /* FIXME: should check item at sp [1] is compatible with the type of the store. */
                                MonoInst *store;
@@ -5719,10 +6102,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 5;
                                break;
                        }
+                       if (klass == mono_defaults.void_class)
+                               UNVERIFIED;
                        if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
-                               goto unverified;
+                               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);
@@ -5750,6 +6136,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);
                                }
                                start_new_bblock = 1;
                                break;
@@ -5784,6 +6171,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
+                       ins->klass = klass;
                        ip += 5;
                        *sp++ = ins;
                        /* 
@@ -5807,7 +6195,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (1);
                        --sp;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip++;
                        ins->inst_left = *sp;
@@ -5819,7 +6207,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        CHECK_OPSIZE (5);
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
 
                        klass = mini_get_class (method, read32 (ip + 1), generic_context);
                        if (!klass)
@@ -5835,6 +6223,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                check->klass = klass;
                                check->inst_left = sp [0];
                                check->type = STACK_OBJ;
+                               check->klass = klass;
                                sp [0] = check;
                        }
                        
@@ -5849,7 +6238,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        sp -= 2;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
@@ -5886,7 +6275,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        sp -= 2;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
                        klass = array_access_to_klass (*ip);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -5895,6 +6284,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_left = load;
                        *sp++ = ins;
                        ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
+                       ins->klass = klass;
                        ++ip;
                        break;
                }
@@ -5914,7 +6304,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (3);
                        sp -= 3;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
                        klass = array_access_to_klass (*ip);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -5938,7 +6328,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (3);
                        sp -= 3;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
@@ -5961,7 +6351,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                n = mono_type_to_stind (&klass->byval_arg);
                                if (n == CEE_STOBJ)
-                                       handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE);
+                                       handle_stobj (cfg, bblock, load, sp [2], ip, klass, FALSE, FALSE, TRUE);
                                else {
                                        MONO_INST_NEW (cfg, ins, n);
                                        ins->cil_code = ip;
@@ -5982,9 +6372,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (3);
                        sp -= 3;
                        if (sp [0]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
                        if (sp [2]->type != STACK_OBJ)
-                               goto unverified;
+                               UNVERIFIED;
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
 
@@ -6162,7 +6552,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (mono_find_jit_opcode_emulation (ins->opcode)) {
                                --sp;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 1);
-                               mono_get_got_var (cfg);
                        }
                        ip++;
                        break;
@@ -6212,7 +6601,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        for (i = 0; i < header->num_clauses; ++i) {
                                MonoExceptionClause *clause = &header->clauses [i];
 
-                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) == (clause->handler_offset + clause->handler_len)) {
+                               /* 
+                                * Use <= in the final comparison to handle clauses with multiple
+                                * leave statements, like in bug #78024.
+                                * The ordering of the exception clauses guarantees that we find the
+                                * innermost clause.
+                                */
+                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
                                        int temp;
                                        MonoInst *load;
 
@@ -6380,10 +6775,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
 
                                NEW_RETLOADA (cfg, ins);
-                               handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE);
+                               handle_stobj (cfg, bblock, ins, *sp, ip, klass, FALSE, TRUE, FALSE);
                                
                                if (sp != stack_start)
-                                       goto unverified;
+                                       UNVERIFIED;
                                
                                MONO_INST_NEW (cfg, ins, CEE_BR);
                                ins->cil_code = ip;
@@ -6515,7 +6910,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);
@@ -6545,7 +6941,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);
@@ -6590,9 +6987,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_ARG (n);
                                NEW_ARGSTORE (cfg, ins, n, *sp);
                                ins->cil_code = ip;
+                               if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
+                                       UNVERIFIED;
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_ARGLOADA (cfg, ins, n);
-                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                                } else
                                        MONO_ADD_INS (bblock, ins);
                                ip += 4;
@@ -6625,10 +7024,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_LOCAL (n);
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
                                NEW_LOCSTORE (cfg, ins, n, *sp);
+                               if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
+                                       UNVERIFIED;
                                ins->cil_code = ip;
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_LOCLOADA (cfg, ins, n);
-                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
+                                       handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE, FALSE);
                                } else
                                        MONO_ADD_INS (bblock, ins);
                                ip += 4;
@@ -6638,7 +7039,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                --sp;
                                if (sp != stack_start) 
-                                       goto unverified;
+                                       UNVERIFIED;
                                if (cfg->method != method) 
                                        /* 
                                         * Inlining this into a loop in a parent could lead to 
@@ -6649,7 +7050,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
                                ins->inst_left = *sp;
                                ins->cil_code = ip;
-                               ins->type = STACK_MP;
+                               ins->type = STACK_PTR;
 
                                cfg->flags |= MONO_CFG_HAS_ALLOCA;
                                if (header->init_locals)
@@ -6666,7 +7067,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                --sp;
                                if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
-                                       goto unverified;
+                                       UNVERIFIED;
                                MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
                                ins->inst_left = *sp;
                                ins->cil_code = ip;
@@ -6687,7 +7088,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                                g_assert (nearest);
                                if ((ip - header->code) != nearest->handler_offset)
-                                       goto unverified;
+                                       UNVERIFIED;
 
                                break;
                        }
@@ -6721,6 +7122,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        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);
@@ -6808,7 +7210,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                link_bblock (cfg, bblock, end_bblock);
                                start_new_bblock = 1;
                                ip += 2;
-                               mono_get_got_var (cfg);
                                break;
                        }
                        case CEE_SIZEOF:
@@ -6856,7 +7257,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
        }
        if (start_new_bblock != 1)
-               goto unverified;
+               UNVERIFIED;
 
        bblock->cil_length = ip - bblock->cil_code;
        bblock->next_bb = end_bblock;
@@ -6952,6 +7353,18 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
+
+       if (inline_costs < 0) {
+               char *mname;
+
+               /* Method is too large */
+               mname = mono_method_full_name (method, TRUE);
+               cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+               cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
+               g_free (mname);
+               return -1;
+       }
+
        return inline_costs;
 
  inline_failure:
@@ -7129,24 +7542,22 @@ mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
 {
        char *name;
        MonoMethod *wrapper;
-       gconstpointer code;
        
-       if (callinfo->wrapper)
+       if (callinfo->wrapper) {
                return callinfo->wrapper;
-       
+       }
+
+       if (callinfo->trampoline)
+               return callinfo->trampoline;
+
        name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
        wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
-       /* Must be domain neutral since there is only one copy */
-       code = mono_jit_compile_method_with_opt (wrapper, default_opt | MONO_OPT_SHARED);
+       g_free (name);
 
-       if (!callinfo->wrapper) {
-               callinfo->wrapper = code;
-               mono_register_jit_icall_wrapper (callinfo, code);
-               mono_debug_add_icall_wrapper (wrapper, callinfo);
-       }
+       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);
 
-       g_free (name);
-       return callinfo->wrapper;
+       return callinfo->trampoline;
 }
 
 static void
@@ -7157,6 +7568,7 @@ mono_init_trampolines (void)
        mono_trampoline_code [MONO_TRAMPOLINE_CLASS_INIT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_CLASS_INIT);
 #ifdef MONO_ARCH_HAVE_PIC_AOT
        mono_trampoline_code [MONO_TRAMPOLINE_AOT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT);
+       mono_trampoline_code [MONO_TRAMPOLINE_AOT_PLT] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_AOT_PLT);
 #endif
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
        mono_trampoline_code [MONO_TRAMPOLINE_DELEGATE] = mono_arch_create_trampoline_code (MONO_TRAMPOLINE_DELEGATE);
@@ -7243,7 +7655,9 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
        code = mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_JUMP, mono_domain_get (), &code_size);
 
-       ji = g_new0 (MonoJitInfo, 1);
+       mono_domain_lock (domain);
+       ji = mono_mempool_alloc0 (domain->mp, sizeof (MonoJitInfo));
+       mono_domain_unlock (domain);
        ji->code_start = code;
        ji->code_size = code_size;
        ji->method = method;
@@ -7265,10 +7679,9 @@ mono_create_jump_trampoline (MonoDomain *domain, MonoMethod *method,
        return ji->code_start;
 }
 
-gpointer
-mono_create_jit_trampoline (MonoMethod *method)
+static gpointer
+mono_create_jit_trampoline_in_domain (MonoDomain *domain, MonoMethod *method)
 {
-       MonoDomain *domain = mono_domain_get ();
        gpointer tramp;
 
        mono_domain_lock (domain);
@@ -7281,7 +7694,7 @@ mono_create_jit_trampoline (MonoMethod *method)
                return mono_create_jit_trampoline (mono_marshal_get_synchronized_wrapper (method));
 
 #ifdef MONO_ARCH_HAVE_CREATE_SPECIFIC_TRAMPOLINE
-       tramp =  mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, mono_domain_get (), NULL);
+       tramp =  mono_arch_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC, domain, NULL);
 #else
        tramp = mono_arch_create_jit_trampoline (method);
 #endif
@@ -7295,6 +7708,12 @@ mono_create_jit_trampoline (MonoMethod *method)
        return tramp;
 }      
 
+gpointer
+mono_create_jit_trampoline (MonoMethod *method)
+{
+       return mono_create_jit_trampoline_in_domain (mono_domain_get (), method);
+}
+
 #ifdef MONO_ARCH_HAVE_CREATE_TRAMPOLINE_FROM_TOKEN
 gpointer
 mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
@@ -7320,7 +7739,7 @@ mono_create_jit_trampoline_from_token (MonoImage *image, guint32 token)
 }      
 #endif
 
-gpointer
+static gpointer
 mono_create_delegate_trampoline (MonoMethod *method, gpointer addr)
 {
 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
@@ -7540,7 +7959,7 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                         * efficient copying (and to work around the fact that OP_MEMCPY
                         * and OP_MEMSET ignores alignment).
                         */
-                       if (t->type == MONO_TYPE_VALUETYPE)
+                       if (MONO_TYPE_ISSTRUCT (t))
                                align = sizeof (gpointer);
 
                        if (backward) {
@@ -7934,6 +8353,7 @@ mini_thread_cleanup (MonoThread *thread)
                g_free (jit_tls->first_lmf);
                g_free (jit_tls);
                thread->jit_data = NULL;
+               TlsSetValue (mono_jit_tls_id, NULL);
        }
 }
 
@@ -8041,6 +8461,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                mono_class_init (patch_info->data.klass);
                target = GINT_TO_POINTER ((int)patch_info->data.klass->interface_id);
                break;
+       case MONO_PATCH_INFO_ADJUSTED_IID:
+               mono_class_init (patch_info->data.klass);
+               target = GINT_TO_POINTER ((int)(-((patch_info->data.klass->interface_id + 1) * SIZEOF_VOID_P)));
+               break;
        case MONO_PATCH_INFO_VTABLE:
                target = mono_class_vtable (domain, patch_info->data.klass);
                break;
@@ -8236,39 +8660,6 @@ replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl
        }
 }
 
-static void 
-replace_or_add_in_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
-{
-       gboolean found = FALSE;
-       int i;
-
-       for (i = 0; i < bb->in_count; i++) {
-               MonoBasicBlock *ib = bb->in_bb [i];
-               if (ib == orig) {
-                       if (!repl) {
-                               if (bb->in_count > 1) {
-                                       bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
-                               }
-                               bb->in_count--;
-                       } else {
-                               bb->in_bb [i] = repl;
-                       }
-                       found = TRUE;
-               }
-       }
-       
-       if (! found) {
-               MonoBasicBlock **new_in_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (bb->in_count + 1));
-               for (i = 0; i < bb->in_count; i++) {
-                       new_in_bb [i] = bb->in_bb [i];
-               }
-               new_in_bb [i] = repl;
-               bb->in_count++;
-               bb->in_bb = new_in_bb;
-       }
-}
-
-
 static void
 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
        MonoInst *inst;
@@ -8348,7 +8739,10 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        MonoInst *inst;
        
        /* Do not touch handlers */
-       if (bb->region != -1) return FALSE;
+       if (bb->region != -1) {
+               bb->not_useless = TRUE;
+               return FALSE;
+       }
        
        for (inst = bb->code; inst != NULL; inst = inst->next) {
                switch (inst->opcode) {
@@ -8358,6 +8752,7 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
                        target_bb = inst->inst_target_bb;
                        break;
                default:
+                       bb->not_useless = TRUE;
                        return FALSE;
                }
        }
@@ -8381,6 +8776,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)) {
@@ -8390,17 +8792,16 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
                        printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
                }
                
-               for (i = 0; i < bb->in_count; i++) {
-                       MonoBasicBlock *in_bb = bb->in_bb [i];
-                       replace_out_block (in_bb, bb, target_bb);
+               /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
+               while (bb->in_count) {
+                       MonoBasicBlock *in_bb = bb->in_bb [0];
+                       mono_unlink_bblock (cfg, in_bb, bb);
+                       link_bblock (cfg, in_bb, target_bb);
                        replace_out_block_in_code (in_bb, bb, target_bb);
-                       if (bb->in_count == 1) {
-                               replace_in_block (target_bb, bb, in_bb);
-                       } else {
-                               replace_or_add_in_block (cfg, target_bb, bb, in_bb);
-                       }
                }
                
+               mono_unlink_bblock (cfg, bb, target_bb);
+               
                if ((previous_bb != cfg->bb_entry) &&
                                (previous_bb->region == bb->region) &&
                                ((previous_bb->last_ins == NULL) ||
@@ -8436,6 +8837,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 = CEE_NOP;
+       }               
+
        if (bb->last_ins) {
                if (bbn->code) {
                        bb->last_ins->next = bbn->code;
@@ -8616,7 +9022,7 @@ optimize_branches (MonoCompile *cfg)
                        if (bb->region != -1)
                                continue;
 
-                       if (remove_block_if_useless (cfg, bb, previous_bb)) {
+                       if (!bb->not_useless && remove_block_if_useless (cfg, bb, previous_bb)) {
                                changed = TRUE;
                                continue;
                        }
@@ -8671,6 +9077,7 @@ optimize_branches (MonoCompile *cfg)
                                                                g_print ("block merge triggered %d -> %d\n", bb->block_num, bbn->block_num);
                                                        merge_basic_blocks (bb, bbn);
                                                        changed = TRUE;
+                                                       continue;
                                                }
 
                                                //mono_print_bb_code (bb);
@@ -8688,10 +9095,9 @@ optimize_branches (MonoCompile *cfg)
 
                                nullify_basic_block (bbn);                      
                                changed = TRUE;
-                               break;
+                               continue;
                        }
 
-
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
@@ -8709,7 +9115,7 @@ optimize_branches (MonoCompile *cfg)
                                                link_bblock (cfg, bb, bbn->code->inst_target_bb);
                                                bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
                                                changed = TRUE;
-                                               break;
+                                               continue;
                                        }
                                }
                        } else if (bb->out_count == 2) {
@@ -8729,10 +9135,9 @@ optimize_branches (MonoCompile *cfg)
                                                 */
                                                bb->last_ins->opcode = CEE_BR;
                                                bb->last_ins->inst_target_bb = taken_branch_target;
-                                               replace_out_block (bb, untaken_branch_target, NULL);
-                                               replace_in_block (untaken_branch_target, bb, NULL);
+                                               mono_unlink_bblock (cfg, bb, untaken_branch_target);
                                                changed = TRUE;
-                                               break;
+                                               continue;
                                        }
                                        bbn = bb->last_ins->inst_true_bb;
                                        if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
@@ -8742,17 +9147,21 @@ optimize_branches (MonoCompile *cfg)
                                                                 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
                                                                 bbn->code->opcode);
 
-                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
+                                               /* 
+                                                * Unlink, then relink bblocks to avoid various
+                                                * tricky situations when the two targets of the branch
+                                                * are equal, or will become equal after the change.
+                                                */
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               replace_in_block (bbn, bb, NULL);
-                                               if (!bbn->in_count)
-                                                       replace_in_block (bbn->code->inst_target_bb, bbn, bb);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
 
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
                                                changed = TRUE;
-                                               break;
+                                               continue;
                                        }
 
                                        bbn = bb->last_ins->inst_false_bb;
@@ -8763,17 +9172,16 @@ optimize_branches (MonoCompile *cfg)
                                                                 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
                                                                 bbn->code->opcode);
 
-                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               replace_in_block (bbn, bb, NULL);
-                                               if (!bbn->in_count)
-                                                       replace_in_block (bbn->code->inst_target_bb, bbn, bb);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
 
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
                                                changed = TRUE;
-                                               break;
+                                               continue;
                                        }
                                }
 
@@ -8782,7 +9190,7 @@ optimize_branches (MonoCompile *cfg)
                                        if (try_unsigned_compare (cfg, bb)) {
                                                /*g_print ("applied in bb %d (->%d) %s\n", bb->block_num, bb->last_ins->inst_target_bb->block_num, mono_method_full_name (cfg->method, TRUE));*/
                                                changed = TRUE;
-                                               break;
+                                               continue;
                                        }
                                }
 
@@ -9119,8 +9527,15 @@ mono_codegen (MonoCompile *cfg)
                                         */
                                        ;
                                else {
-                                       patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
-                                       patch_info->data.name = info->name;
+                                       /* for these array methods we currently register the same function pointer
+                                        * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
+                                        * will return the incorrect one depending on the order they are registered.
+                                        * See tests/test-arr.cs
+                                        */
+                                       if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
+                                               patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
+                                               patch_info->data.name = info->name;
+                                       }
                                }
                        }
                        else {
@@ -9159,9 +9574,9 @@ mono_codegen (MonoCompile *cfg)
        
        if (cfg->verbose_level > 0) {
                char* nm = mono_method_full_name (cfg->method, TRUE);
-               g_print ("Method %s emitted at %p to %p [%s]\n", 
+               g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
                                 nm, 
-                                cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
+                                cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
                g_free (nm);
        }
 
@@ -9184,190 +9599,7 @@ mono_codegen (MonoCompile *cfg)
        mono_debug_close_method (cfg);
 }
 
-static void
-mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
-{
-       MonoInst *cp;
-       int arity;
-
-       if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) && 
-           (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
-
-               if (cp->opcode == OP_ICONST) {
-                       if (cfg->opt & MONO_OPT_CONSPROP) {
-                               //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
-                               *tree = *cp;
-                       }
-               } else {
-                       if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
-                               if (cfg->opt & MONO_OPT_COPYPROP) {
-                                       //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
-                                       tree->inst_i0 = cp;
-                               } 
-                       }
-               } 
-       } else {
-               arity = mono_burg_arity [tree->opcode];
-
-               if (arity) {
-                       mono_cprop_copy_values (cfg, tree->inst_i0, acp);
-                       if (cfg->opt & MONO_OPT_CFOLD)
-                               mono_constant_fold_inst (tree, NULL); 
-                       /* The opcode may have changed */
-                       if (mono_burg_arity [tree->opcode] > 1) {
-                               mono_cprop_copy_values (cfg, tree->inst_i1, acp);
-                               if (cfg->opt & MONO_OPT_CFOLD)
-                                       mono_constant_fold_inst (tree, NULL); 
-                       }
-                       mono_constant_fold_inst (tree, NULL); 
-               }
-       }
-}
-
-static void
-mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
-{
-       int arity;
-
-       switch (tree->opcode) {
-       case CEE_STIND_I:
-       case CEE_STIND_I1:
-       case CEE_STIND_I2:
-       case CEE_STIND_I4:
-       case CEE_STIND_REF:
-       case CEE_STIND_I8:
-       case CEE_STIND_R4:
-       case CEE_STIND_R8:
-       case CEE_STOBJ:
-               if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
-                       memset (acp, 0, sizeof (MonoInst *) * acp_size);
-                       return;
-               }
-
-               break;
-       case CEE_CALL:
-       case OP_CALL_REG:
-       case CEE_CALLVIRT:
-       case OP_LCALL_REG:
-       case OP_LCALLVIRT:
-       case OP_LCALL:
-       case OP_FCALL_REG:
-       case OP_FCALLVIRT:
-       case OP_FCALL:
-       case OP_VCALL_REG:
-       case OP_VCALLVIRT:
-       case OP_VCALL:
-       case OP_VOIDCALL_REG:
-       case OP_VOIDCALLVIRT:
-       case OP_VOIDCALL: {
-               MonoCallInst *call = (MonoCallInst *)tree;
-               MonoMethodSignature *sig = call->signature;
-               int i, byref = FALSE;
-
-               for (i = 0; i < sig->param_count; i++) {
-                       if (sig->params [i]->byref) {
-                               byref = TRUE;
-                               break;
-                       }
-               }
-
-               if (byref)
-                       memset (acp, 0, sizeof (MonoInst *) * acp_size);
-
-               return;
-       }
-       default:
-               break;
-       }
-
-       arity = mono_burg_arity [tree->opcode];
-
-       switch (arity) {
-       case 0:
-               break;
-       case 1:
-               mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
-               break;
-       case 2:
-               mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
-               mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-}
-
-static void
-mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
-{
-       MonoInst *tree = bb->code;      
-       int i;
-
-       if (!tree)
-               return;
-
-       for (; tree; tree = tree->next) {
-
-               mono_cprop_copy_values (cfg, tree, acp);
-
-               mono_cprop_invalidate_values (tree, acp, acp_size);
-
-               if (tree->ssa_op == MONO_SSA_STORE  && 
-                   (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
-                       MonoInst *i1 = tree->inst_i1;
-
-                       acp [tree->inst_i0->inst_c0] = NULL;
-
-                       for (i = 0; i < acp_size; i++) {
-                               if (acp [i] && acp [i]->opcode != OP_ICONST && 
-                                   acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
-                                       acp [i] = NULL;
-                               }
-                       }
-
-                       if (i1->opcode == OP_ICONST) {
-                               acp [tree->inst_i0->inst_c0] = i1;
-                               //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
-                       }
-                       if (i1->ssa_op == MONO_SSA_LOAD && 
-                           (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
-                           (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
-                               acp [tree->inst_i0->inst_c0] = i1->inst_i0;
-                               //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
-                       }
-               }
-
-               /*
-                 if (tree->opcode == CEE_BEQ) {
-                 g_assert (tree->inst_i0->opcode == OP_COMPARE);
-                 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
-                 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
-                 
-                 tree->opcode = CEE_BR;
-                 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
-                 tree->inst_target_bb = tree->inst_true_bb;
-                 } else {
-                 tree->inst_target_bb = tree->inst_false_bb;
-                 }
-                 }
-                 }
-               */
-       }
-}
-
-static void
-mono_local_cprop (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb;
-       MonoInst **acp;
-
-       acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
 
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
-               mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
-       }
-}
 
 static void
 remove_critical_edges (MonoCompile *cfg) {
@@ -9600,7 +9832,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
                                if (bbn && bbn->region == -1 && !bbn->dfn) {
                                        if (cfg->verbose_level > 1)
-                                               g_print ("found unreachabel code in BB%d\n", bbn->block_num);
+                                               g_print ("found unreachable code in BB%d\n", bbn->block_num);
                                        bb->next_bb = bbn->next_bb;
                                        nullify_basic_block (bbn);                      
                                } else {
@@ -9682,6 +9914,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) {
@@ -9842,16 +10080,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 }
 
 static gpointer
-mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
+mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, int opt)
 {
        MonoCompile *cfg;
        GHashTable *jit_code_hash;
        gpointer code = NULL;
-       guint32 opt;
        MonoJitInfo *info;
 
-       opt = default_opt;
-
        jit_code_hash = target_domain->jit_code_hash;
 
        method = mono_get_inflated_method (method);
@@ -9930,8 +10165,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
 
                mono_destroy_compile (cfg);
                if (error) {
-                       MonoException *ex = mini_loader_error_to_exception (error);
-                       mono_loader_clear_error ();
+                       MonoException *ex = mono_loader_error_prepare_exception (error);
                        mono_raise_exception (ex);
                } else {
                        g_assert_not_reached ();
@@ -10017,10 +10251,26 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
 static gpointer
 mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
 {
-       /* FIXME: later copy the code from mono */
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
        gpointer p;
+       MonoJitICallInfo *callinfo = NULL;
+
+       /*
+        * ICALL wrappers are handled specially, since there is only one copy of them
+        * shared by all appdomains.
+        */
+       if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
+               const char *icall_name;
+
+               icall_name = method->name + strlen ("__icall_wrapper_");
+               g_assert (icall_name);
+               callinfo = mono_find_jit_icall_by_name (icall_name);
+               g_assert (callinfo);
+
+               /* Must be domain neutral since there is only one copy */
+               opt |= MONO_OPT_SHARED;
+       }
 
        if (opt & MONO_OPT_SHARED)
                target_domain = mono_get_root_domain ();
@@ -10040,8 +10290,19 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
        }
 
        mono_domain_unlock (target_domain);
-       p = mono_jit_compile_method_inner (method, target_domain);
-       return mono_create_ftnptr (target_domain, p);
+       p = mono_create_ftnptr (target_domain, mono_jit_compile_method_inner (method, target_domain, opt));
+
+       if (callinfo) {
+               mono_jit_lock ();
+               if (!callinfo->wrapper) {
+                       callinfo->wrapper = p;
+                       mono_register_jit_icall_wrapper (callinfo, p);
+                       mono_debug_add_icall_wrapper (method, callinfo);
+               }
+               mono_jit_unlock ();
+       }
+
+       return p;
 }
 
 static gpointer
@@ -10080,6 +10341,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
        mono_domain_lock (domain);
        g_hash_table_remove (domain->dynamic_code_hash, method);
        g_hash_table_remove (domain->jit_code_hash, method);
+       g_hash_table_remove (domain->jump_trampoline_hash, method);
        mono_domain_unlock (domain);
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -10272,12 +10534,24 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 
        ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
        if (!ji) {
-               mono_handle_native_sigsegv (ctx);
+               mono_handle_native_sigsegv (SIGSEGV, ctx);
        }
                        
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+static void
+SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
+{
+       MonoJitInfo *ji;
+       GET_CONTEXT;
+
+       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+       if (!ji) {
+               mono_handle_native_sigsegv (SIGABRT, ctx);
+       }
+}
+
 static void
 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
 {
@@ -10408,6 +10682,8 @@ mono_runtime_install_handlers (void)
        add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
        signal (SIGPIPE, SIG_IGN);
 
+       add_signal_handler (SIGABRT, sigabrt_signal_handler);
+
        /* catch SIGSEGV */
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        sa.sa_sigaction = sigsegv_signal_handler;
@@ -10417,7 +10693,6 @@ mono_runtime_install_handlers (void)
 #else
        add_signal_handler (SIGSEGV, sigsegv_signal_handler);
 #endif
-
 #endif /* PLATFORM_WIN32 */
 }
 
@@ -10562,7 +10837,7 @@ mini_init (const char *filename)
        MonoDomain *domain;
 
        /* Happens when using the embedding interface */
-       if (default_opt == 0)
+       if (!default_opt_set)
                default_opt = mono_parse_default_optimizations (NULL);
 
        InitializeCriticalSection (&jit_mutex);
@@ -10582,7 +10857,12 @@ mini_init (const char *filename)
        if (getenv ("MONO_DEBUG") != NULL)
                mini_parse_debug_options ();
 
-       /* we used to do this only when running on valgrind,
+       /*
+        * Handle the case when we are called from a thread different from the main thread,
+        * confusing libgc.
+        * FIXME: Move this to libgc where it belongs.
+        *
+        * we used to do this only when running on valgrind,
         * but it happens also in other setups.
         */
 #if defined(HAVE_BOEHM_GC)
@@ -10593,8 +10873,16 @@ mini_init (const char *filename)
                pthread_attr_t attr;
                pthread_getattr_np (pthread_self (), &attr);
                pthread_attr_getstack (&attr, &sstart, &size);
+               pthread_attr_destroy (&attr); 
                /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/
+#ifdef __ia64__
+               /*
+                * The calculation above doesn't seem to work on ia64, also we need to set
+                * GC_register_stackbottom as well, but don't know how.
+                */
+#else
                GC_stackbottom = (char*)sstart + size;
+#endif
        }
 #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
                GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ());
@@ -10760,8 +11048,8 @@ 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 (helper_stelem_ref, "helper_stelem_ref", "void ptr int32 object", FALSE);
-       register_icall (helper_stelem_ref_check, "helper_stelem_ref_check", "void object object", 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);
        register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
@@ -10770,8 +11058,11 @@ 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 (helper_compile_generic_method, "compile_generic_method", "ptr object ptr ptr", FALSE);
-       register_icall (helper_ldstr, "helper_ldstr", "object ptr int", FALSE);
+       register_icall (mono_helper_compile_generic_method, "compile_generic_method", "ptr object 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);
+       register_icall (mono_value_copy, "mono_value_copy", "void ptr ptr ptr", FALSE);
 #endif
 
 #define JIT_RUNTIME_WORKS
@@ -10854,6 +11145,9 @@ mini_cleanup (MonoDomain *domain)
         */
        mono_domain_finalize (domain, 2000);
 
+       /* This accesses metadata so needs to be called before runtime shutdown */
+       print_jit_stats ();
+
        mono_runtime_cleanup (domain);
 
        mono_profiler_shutdown ();
@@ -10872,8 +11166,13 @@ mini_cleanup (MonoDomain *domain)
        g_hash_table_destroy (jit_icall_name_hash);
        if (class_init_hash_addr)
                g_hash_table_destroy (class_init_hash_addr);
+       g_free (emul_opcode_map);
 
-       print_jit_stats ();
+       mono_cleanup ();
+
+       mono_trace_cleanup ();
+
+       mono_counters_dump (-1, stdout);
 }
 
 void
@@ -10881,6 +11180,7 @@ mono_set_defaults (int verbose_level, guint32 opts)
 {
        mini_verbose = verbose_level;
        default_opt = opts;
+       default_opt_set = TRUE;
 }
 
 static void