2006-04-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 0d9cf5aefd7fd04b9a715435c7dbfb2450d985ec..f8239ccc7207f35592b4c60234935307b99345a0 100644 (file)
 #include <mono/metadata/mono-config.h>
 #include <mono/metadata/environment.h>
 #include <mono/metadata/mono-debug.h>
-#include <mono/metadata/mono-debug-debugger.h>
 #include <mono/metadata/monitor.h>
 #include <mono/metadata/security-manager.h>
 #include <mono/metadata/threads-types.h>
 #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/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
@@ -76,6 +85,7 @@ 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);
@@ -86,7 +96,6 @@ static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlo
                   int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
                   guint inline_offset, gboolean is_virtual_call);
 
-extern guint8 mono_burg_arity [];
 /* helper methods signature */
 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
 static MonoMethodSignature *helper_sig_domain_get = NULL;
@@ -159,6 +168,20 @@ 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)
@@ -168,10 +191,23 @@ get_method_from_ip (void *ip)
        char *source;
        char *res;
        MonoDomain *domain = mono_domain_get ();
+       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);
@@ -184,18 +220,36 @@ get_method_from_ip (void *ip)
        return res;
 }
 
+G_GNUC_UNUSED char *
+mono_pmip (void *ip)
+{
+       return get_method_from_ip (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;
        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);
@@ -209,12 +263,6 @@ print_method_from_ip (void *ip)
        g_free (source);
        g_free (method);
 }
-
-G_GNUC_UNUSED void
-mono_print_method_from_ip (void *ip)
-{
-       print_method_from_ip (ip);
-}
        
 /* 
  * mono_method_same_domain:
@@ -443,7 +491,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_LOCLOADA(cfg,dest,num) do {        \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -455,7 +503,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_RETLOADA(cfg,dest) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->ret;   \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;       \
@@ -467,7 +515,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define NEW_ARGLOADA(cfg,dest,num) do {        \
                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = arg_array [(num)];    \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -487,7 +535,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_TEMPLOADA(cfg,dest,num) do {       \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -729,6 +777,52 @@ link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
        }
 }
 
+/**
+ * mono_unlink_bblock:
+ *
+ *   Unlink two basic blocks.
+ */
+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:
  *
@@ -852,7 +946,7 @@ df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
        int i;
 
        array [*dfn] = start;
-       /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
+       /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
        for (i = 0; i < start->out_count; ++i) {
                if (start->out_bb [i]->dfn)
                        continue;
@@ -1096,13 +1190,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:
@@ -1195,14 +1288,15 @@ bin_int_table [STACK_MAX] [STACK_MAX] = {
 
 static const char
 bin_comp_table [STACK_MAX] [STACK_MAX] = {
+/*     Inv i  L  p  F  &  O  vt */
        {0},
-       {0, 1, 0, 1, 0, 0, 4, 0},
-       {0, 0, 1, 0, 0, 0, 0, 0},
-       {0, 1, 0, 1, 0, 2, 4, 0},
-       {0, 0, 0, 0, 1, 0, 0, 0},
-       {0, 0, 0, 2, 0, 1, 0, 0},
-       {0, 4, 0, 4, 0, 0, 3, 0},
-       {0, 0, 0, 0, 0, 0, 0, 0},
+       {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
+       {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
+       {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
+       {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
+       {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
+       {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
+       {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
 };
 
 /* reduce the size of this table */
@@ -1427,7 +1521,7 @@ type_from_op (MonoInst *ins) {
 
 static const char 
 ldind_type [] = {
-       STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_MP, STACK_R8, STACK_R8, STACK_OBJ
+       STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
 };
 
 /* map ldelem.x to the matching ldind.x opcode */
@@ -1802,6 +1896,9 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                found = FALSE;
                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;
                        //g_print (" %d", outb->block_num);
                        if (outb->in_stack) {
                                found = TRUE;
@@ -1835,8 +1932,14 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
 
        for (i = 0; i < bb->out_count; ++i) {
                outb = bb->out_bb [i];
-               if (outb->in_scount)
+               /* exception handlers are linked, but they should not be considered for stack args */
+               if (outb->flags & BB_EXCEPTION_HANDLER)
+                       continue;
+               if (outb->in_scount) {
+                       if (outb->in_scount != bb->out_scount)
+                               G_BREAKPOINT ();
                        continue; /* check they are the same locals */
+               }
                outb->in_scount = count;
                outb->in_stack = bb->out_stack;
        }
@@ -1869,6 +1972,11 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                found = FALSE;
                while (bindex < bb->out_count) {
                        outb = bb->out_bb [bindex];
+                       /* exception handlers are linked, but they should not be considered for stack args */
+                       if (outb->flags & BB_EXCEPTION_HANDLER) {
+                               bindex++;
+                               continue;
+                       }
                        if (outb->in_stack != locals) {
                                /* 
                                 * Instead of storing sp [i] to locals [i], we need to store
@@ -1994,12 +2102,118 @@ handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack,
        }
 }
 
+/*
+ * target_type_is_incompatible:
+ * @cfg: MonoCompile context
+ *
+ * Check that the item @arg on the evaluation stack can be stored
+ * in the target type (can be a local, or field, etc).
+ * The cfg arg can be used to check if we need verification or just
+ * validity checks.
+ *
+ * Returns: non-0 value if arg can't be stored on a target.
+ */
+static int
+target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
+{
+       MonoType *simple_type;
+       MonoClass *klass;
+
+       if (target->byref) {
+               /* FIXME: check that the pointed to types match */
+               if (arg->type == STACK_MP)
+                       return arg->klass != mono_class_from_mono_type (target);
+               if (arg->type == STACK_PTR)
+                       return 0;
+               return 1;
+       }
+       simple_type = mono_type_get_underlying_type (target);
+       switch (simple_type->type) {
+       case MONO_TYPE_VOID:
+               return 1;
+       case MONO_TYPE_I1:
+       case MONO_TYPE_U1:
+       case MONO_TYPE_BOOLEAN:
+       case MONO_TYPE_I2:
+       case MONO_TYPE_U2:
+       case MONO_TYPE_CHAR:
+       case MONO_TYPE_I4:
+       case MONO_TYPE_U4:
+               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_FNPTR:
+               if (arg->type != STACK_I4 && arg->type != STACK_PTR)
+                       return 1;
+               return 0;
+       case MONO_TYPE_CLASS:
+       case MONO_TYPE_STRING:
+       case MONO_TYPE_OBJECT:
+       case MONO_TYPE_SZARRAY:
+       case MONO_TYPE_ARRAY:    
+               if (arg->type != STACK_OBJ)
+                       return 1;
+               /* FIXME: check type compatibility */
+               return 0;
+       case MONO_TYPE_I8:
+       case MONO_TYPE_U8:
+               if (arg->type != STACK_I8)
+                       return 1;
+               return 0;
+       case MONO_TYPE_R4:
+       case MONO_TYPE_R8:
+               if (arg->type != STACK_R8)
+                       return 1;
+               return 0;
+       case MONO_TYPE_VALUETYPE:
+               if (arg->type != STACK_VTYPE)
+                       return 1;
+               klass = mono_class_from_mono_type (simple_type);
+               if (klass != arg->klass)
+                       return 1;
+               return 0;
+       case MONO_TYPE_TYPEDBYREF:
+               if (arg->type != STACK_VTYPE)
+                       return 1;
+               klass = mono_class_from_mono_type (simple_type);
+               if (klass != arg->klass)
+                       return 1;
+               return 0;
+       case MONO_TYPE_GENERICINST:
+               if (mono_type_generic_inst_is_valuetype (simple_type)) {
+                       if (arg->type != STACK_VTYPE)
+                               return 1;
+                       klass = mono_class_from_mono_type (simple_type);
+                       if (klass != arg->klass)
+                               return 1;
+                       return 0;
+               } else {
+                       if (arg->type != STACK_OBJ)
+                               return 1;
+                       /* FIXME: check type compatibility */
+                       return 0;
+               }
+       default:
+               g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
+       }
+       return 1;
+}
+
 /*
  * Prepare arguments for passing to a function call.
  * Return a non-zero value if the arguments can't be passed to the given
  * signature.
  * The type checks are not yet complete and some conversions may need
  * casts on 32 or 64 bit architectures.
+ *
+ * FIXME: implement this using target_type_is_incompatible ()
  */
 static int
 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
@@ -2422,7 +2636,7 @@ static void
 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
        MonoInst *iargs [3];
        int n;
-       int align = 0;
+       guint32 align = 0;
        MonoMethod *memcpy_method;
 
        g_assert (klass);
@@ -2546,13 +2760,35 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboole
 
        return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
 }
+
+/**
+ * Handles unbox of a Nullable<T>, returning a temp variable
+ * where the result is stored
+ */
+static int
+handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
+{
+       MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
+       return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
        
+}
+
+
+
 static MonoInst *
 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
 {
        MonoInst *dest, *vtoffset, *add, *vstore;
        int temp;
 
+       if (mono_class_is_nullable (klass)) {
+               MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+               temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
+               NEW_TEMPLOAD (cfg, dest, temp);
+               return dest;
+       }
+
+
        temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
        NEW_TEMPLOAD (cfg, dest, temp);
        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
@@ -2719,7 +2955,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;
@@ -2756,6 +2992,16 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
 
        rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
 
+       if (rank == 1) {
+               MONO_INST_NEW (cfg, addr, CEE_LDELEMA);
+               addr->inst_left = sp [0];
+               addr->inst_right = sp [1];
+               addr->cil_code = ip;
+               addr->type = STACK_MP;
+               addr->klass = cmethod->klass->element_class;
+               return addr;
+       }
+
        if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
                /* OP_LDELEMA2D depends on OP_LMUL */
@@ -2793,9 +3039,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)
@@ -2847,9 +3093,6 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        "System.Runtime.CompilerServices", "RuntimeHelpers");
 
        if (cmethod->klass == mono_defaults.string_class) {
-               if (cmethod->name [0] != 'g')
-                       return NULL;
                if (strcmp (cmethod->name, "get_Chars") == 0) {
                        MONO_INST_NEW (cfg, ins, OP_GETCHR);
                        ins->inst_i0 = args [0];
@@ -2859,6 +3102,15 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        MONO_INST_NEW (cfg, ins, OP_STRLEN);
                        ins->inst_i0 = args [0];
                        return ins;
+               } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
+                       MonoInst *get_addr;
+                       MONO_INST_NEW (cfg, get_addr, OP_STR_CHAR_ADDR);
+                       get_addr->inst_i0 = args [0];
+                       get_addr->inst_i1 = args [1];
+                       MONO_INST_NEW (cfg, ins, CEE_STIND_I2);
+                       ins->inst_i0 = get_addr;
+                       ins->inst_i1 = args [2];
+                       return ins;
                } else 
                        return NULL;
        } else if (cmethod->klass == mono_defaults.object_class) {
@@ -2866,10 +3118,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;
@@ -2879,7 +3130,7 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        return ins;
                } else
                        return NULL;
-       } else if (mini_class_is_system_array (cmethod->klass)) {
+       } else if (cmethod->klass == mono_defaults.array_class) {
                if (cmethod->name [0] != 'g')
                        return NULL;
 
@@ -2902,6 +3153,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);
@@ -3234,6 +3506,106 @@ void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
        }
 }
 
+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
@@ -3261,18 +3633,31 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        MonoGenericContainer *generic_container = NULL;
        MonoType **param_types;
        GList *bb_recheck = NULL, *tmp;
-       int i, n, start_new_bblock, align;
+       int i, n, start_new_bblock, ialign;
        int num_calls = 0, inline_costs = 0;
        int breakpoint_id = 0;
+       guint32 align;
        guint real_offset, num_args;
        MonoBoolean security, pinvoke;
        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;
 
        image = method->klass->image;
        header = mono_method_get_header (method);
-       generic_container = ((MonoMethodNormal *)method)->generic_container;
+       generic_container = method->generic_container;
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
        ip = (unsigned char*)header->code;
@@ -3330,19 +3715,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
                /* handle exception clauses */
                for (i = 0; i < header->num_clauses; ++i) {
-                       //unsigned char *p = ip;
+                       MonoBasicBlock *try_bb;
                        MonoExceptionClause *clause = &header->clauses [i];
-                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
-                       tblock->real_offset = clause->try_offset;
+                       GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+                       try_bb->real_offset = clause->try_offset;
                        GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
+                       tblock->flags |= BB_EXCEPTION_HANDLER;
+
+                       link_bblock (cfg, try_bb, tblock);
+
+                       if (*(ip + clause->handler_offset) == CEE_POP)
+                               tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
 
                        if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
                            clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
                                MONO_ADD_INS (tblock, ins);
+
+                               /* todo: is a fault block unsafe to optimize? */
+                               if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                                       tblock->flags |= BB_EXCEPTION_UNSAFE;
                        }
 
+
                        /*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
                          while (p < end) {
                          g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
@@ -3495,6 +3891,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)
+                       goto unverified;
+       }
        class_inits = NULL;
 
        /* do this somewhere outside - not here */
@@ -3632,6 +4032,8 @@ 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))
+                               goto unverified;
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, n);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
@@ -3666,6 +4068,8 @@ 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))
+                               goto unverified;
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_ARGLOADA (cfg, ins, ip [1]);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
@@ -3699,6 +4103,8 @@ 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))
+                               goto unverified;
                        if (ins->opcode == CEE_STOBJ) {
                                NEW_LOCLOADA (cfg, ins, ip [1]);
                                handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
@@ -3904,6 +4310,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if (!cmethod)
                                        goto load_error;
+                               if (!dont_verify && !can_access_method (method, cmethod))
+                                       goto unverified;
 
                                if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
                                        /* MS.NET seems to silently convert this to a callvirt */
@@ -4009,6 +4417,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;
@@ -4037,6 +4447,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 */
@@ -4094,6 +4506,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;
                                }
@@ -4125,6 +4539,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])) 
@@ -4156,12 +4572,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;
 
@@ -4219,6 +4635,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)
@@ -4298,12 +4716,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp = stack_start;
                        }
                        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;
                        MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
                        ins->cil_code = ip++;
                        target = ip + 1 + *(signed char*)ip;
@@ -4313,7 +4733,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BEQ_S:
                case CEE_BGE_S:
@@ -4336,7 +4756,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BR:
                        CHECK_OPSIZE (5);
@@ -4354,12 +4774,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp = stack_start;
                        }
                        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;
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip++;
                        target = ip + 4 + (gint32)read32(ip);
@@ -4369,7 +4791,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BEQ:
                case CEE_BGE:
@@ -4392,7 +4814,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_SWITCH:
                        CHECK_OPSIZE (5);
@@ -4426,7 +4848,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        /* 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:
@@ -4882,9 +5304,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);
                                }
@@ -4905,6 +5331,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        if (!klass)
                                goto load_error;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -4938,13 +5366,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp++;
                                bblock = ebblock;
                                inline_costs += costs;
-
-                       }
-                       else {
+                       } else {
                                MONO_INST_NEW (cfg, ins, *ip);
                                ins->type = STACK_OBJ;
                                ins->inst_left = *sp;
                                ins->inst_newa_class = klass;
+                               ins->klass = klass;
                                ins->cil_code = ip;
                                *sp++ = emit_tree (cfg, bblock, ins, ip + 5);
                                ip += 5;
@@ -4992,8 +5419,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        sp++;
                                        bblock = ebblock;
                                        inline_costs += costs;                          
-                               }
-                               else {
+                               } else {
                                        MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
                                        ins->type = STACK_OBJ;
                                        ins->inst_left = *sp;
@@ -5006,6 +5432,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
+                       if (mono_class_is_nullable (klass)) {
+                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               NEW_TEMPLOAD (cfg, *sp, v);
+                               sp ++;
+                               ip += 5;
+                               break;
+                       }
+
                        MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
                        ins->type = STACK_OBJ;
                        ins->inst_left = *sp;
@@ -5056,6 +5490,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!klass)
                                goto load_error;
 
+                       if (mono_class_is_nullable (klass)) {
+                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               NEW_TEMPLOAD (cfg, *sp, v);
+                               sp ++;
+                               ip += 5;
+                               break;
+                       }
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
 
@@ -5071,6 +5513,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;
@@ -5084,6 +5527,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        klass = mini_get_class (method, token, generic_context);
                        if (!klass)
                                goto load_error;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
 
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -5117,8 +5562,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp++;
                                bblock = ebblock;
                                inline_costs += costs;
-                       }
-                       else {
+                       } else {
                                MONO_INST_NEW (cfg, ins, *ip);
                                ins->type = STACK_OBJ;
                                ins->inst_left = *sp;
@@ -5141,6 +5585,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip - 1;
                        MONO_ADD_INS (bblock, ins);
                        sp = stack_start;
+                       
                        link_bblock (cfg, bblock, end_bblock);
                        start_new_bblock = 1;
                        mono_get_got_var (cfg);
@@ -5161,19 +5606,29 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                CHECK_STACK (1);
                                --sp;
                        }
-                       // FIXME: enable this test later.
-                       //if (sp [0]->type != STACK_OBJ && sp [0]->type != STACK_MP)
-                       //      goto unverified;
+                       if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
+                               goto unverified;
+                       if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
+                               goto unverified;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-                       field = mono_field_from_token (image, token, &klass, generic_context);
+                       if (method->wrapper_type != MONO_WRAPPER_NONE) {
+                               field = mono_method_get_wrapper_data (method, token);
+                               klass = field->parent;
+                       } else {
+                               field = mono_field_from_token (image, token, &klass, generic_context);
+                       }
                        if (!field)
                                goto load_error;
                        mono_class_init (klass);
+                       if (!dont_verify && !can_access_field (method, field))
+                               goto 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;
                                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];
@@ -5230,7 +5685,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        } else {
                                if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
-                                       MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
+                                       MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
                                        MonoInst *iargs [4];
                                        int temp;
                                        
@@ -5238,8 +5693,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_CLASSCONST (cfg, iargs [1], klass);
                                        NEW_FIELDCONST (cfg, iargs [2], field);
                                        NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
-                                       if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (ldfld_wrapper)->ret)) {
-                                               costs = inline_method (cfg, ldfld_wrapper, mono_method_signature (ldfld_wrapper), bblock, 
+                                       if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
+                                               costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
                                                                       iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
                                                g_assert (costs > 0);
                                                      
@@ -5252,12 +5707,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                temp = iargs [0]->inst_i0->inst_c0;
 
-                                               if (*ip == CEE_LDFLDA) {
-                                                       /* not sure howto handle this */
-                                                       NEW_TEMPLOADA (cfg, *sp, temp);
-                                               } else {
-                                                       NEW_TEMPLOAD (cfg, *sp, temp);
-                                               }
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
                                                sp++;
 
                                                /* indicates start of a new block, and triggers a load of
@@ -5267,13 +5717,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                inline_costs += costs;
                                                break;
                                        } else {
-                                               temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, mono_method_signature (ldfld_wrapper), iargs, ip, NULL);
-                                               if (*ip == CEE_LDFLDA) {
-                                                       /* not sure howto handle this */
-                                                       NEW_TEMPLOADA (cfg, *sp, temp);
-                                               } else {
-                                                       NEW_TEMPLOAD (cfg, *sp, temp);
-                                               }
+                                               temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
                                                sp++;
                                        }
                                } else {
@@ -5285,6 +5730,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;
@@ -5309,8 +5755,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
-
-                       field = mono_field_from_token (image, token, &klass, generic_context);
+                       if (method->wrapper_type != MONO_WRAPPER_NONE) {
+                               field = mono_method_get_wrapper_data (method, token);
+                               klass = field->parent;
+                       }
+                       else
+                               field = mono_field_from_token (image, token, &klass, generic_context);
                        if (!field)
                                goto load_error;
                        mono_class_init (klass);
@@ -5381,6 +5831,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;
@@ -5524,9 +5975,46 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ip += 5;
                                break;
                        }
-                       *sp++ = handle_box (cfg, bblock, val, ip, klass);
-                       ip += 5;
-                       inline_costs += 1;
+                       if (klass == mono_defaults.void_class)
+                               goto unverified;
+                       if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
+                               goto 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)) {
+                               /*g_print ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
+                               MONO_INST_NEW (cfg, ins, CEE_POP);
+                               MONO_ADD_INS (bblock, ins);
+                               ins->cil_code = ip;
+                               ins->inst_i0 = *sp;
+                               ip += 5;
+                               MONO_INST_NEW (cfg, ins, CEE_BR);
+                               ins->cil_code = ip;
+                               MONO_ADD_INS (bblock, ins);
+                               if (*ip == CEE_BRTRUE_S) {
+                                       CHECK_OPSIZE (2);
+                                       ip++;
+                                       target = ip + 1 + (signed char)(*ip);
+                                       ip++;
+                               } else {
+                                       CHECK_OPSIZE (5);
+                                       ip++;
+                                       target = ip + 4 + (gint)(read32 (ip));
+                                       ip += 4;
+                               }
+                               GET_BBLOCK (cfg, bbhash, tblock, target);
+                               link_bblock (cfg, bblock, tblock);
+                               CHECK_BBLOCK (target, ip, tblock);
+                               ins->inst_target_bb = tblock;
+                               if (sp != stack_start) {
+                                       handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
+                                       sp = stack_start;
+                               }
+                               start_new_bblock = 1;
+                               break;
+                       }
+                       *sp++ = handle_box (cfg, bblock, val, ip, klass);
+                       ip += 5;
+                       inline_costs += 1;
                        break;
                }
                case CEE_NEWARR:
@@ -5575,9 +6063,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_LDLEN:
                        CHECK_STACK (1);
+                       --sp;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
                        MONO_INST_NEW (cfg, ins, *ip);
                        ins->cil_code = ip++;
-                       --sp;
                        ins->inst_left = *sp;
                        ins->type = STACK_PTR;
                        *sp++ = ins;
@@ -5586,6 +6076,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK (2);
                        sp -= 2;
                        CHECK_OPSIZE (5);
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
 
                        klass = mini_get_class (method, read32 (ip + 1), generic_context);
                        if (!klass)
@@ -5614,6 +6106,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MonoInst *load;
                        CHECK_STACK (2);
                        sp -= 2;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
@@ -5649,6 +6143,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        CHECK_STACK (2);
                        sp -= 2;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
                        klass = array_access_to_klass (*ip);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -5675,6 +6171,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        CHECK_STACK (3);
                        sp -= 3;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
                        klass = array_access_to_klass (*ip);
                        NEW_LDELEMA (cfg, load, sp, klass);
                        load->cil_code = ip;
@@ -5697,6 +6195,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                         */
                        CHECK_STACK (3);
                        sp -= 3;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
                        CHECK_OPSIZE (5);
                        token = read32 (ip + 1);
                        klass = mono_class_get_full (image, token, generic_context);
@@ -5739,6 +6239,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        CHECK_STACK (3);
                        sp -= 3;
+                       if (sp [0]->type != STACK_OBJ)
+                               goto unverified;
+                       if (sp [2]->type != STACK_OBJ)
+                               goto unverified;
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
 
@@ -5841,6 +6345,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
                                handle = mono_method_get_wrapper_data (method, n);
                                handle_class = mono_method_get_wrapper_data (method, n + 1);
+                               if (handle_class == mono_defaults.typehandle_class)
+                                       handle = &((MonoClass*)handle)->byval_arg;
                        }
                        else {
                                handle = mono_ldtoken (image, n, &handle_class, generic_context);
@@ -5964,7 +6470,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;
 
@@ -6342,6 +6854,8 @@ 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))
+                                       goto unverified;
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_ARGLOADA (cfg, ins, n);
                                        handle_stobj (cfg, bblock, ins, *sp, ip, ins->klass, FALSE, FALSE);
@@ -6377,6 +6891,8 @@ 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))
+                                       goto unverified;
                                ins->cil_code = ip;
                                if (ins->opcode == CEE_STOBJ) {
                                        NEW_LOCLOADA (cfg, ins, n);
@@ -6401,7 +6917,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)
@@ -6546,6 +7062,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                handler_offset = clause->handler_offset;
                                }
 
+                               bblock->flags |= BB_EXCEPTION_UNSAFE;
+
                                g_assert (handler_offset != -1);
 
                                NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
@@ -6568,7 +7086,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                /* FIXXME: handle generics. */
                                if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
                                        MonoType *type = mono_type_create_from_typespec (image, token);
-                                       token = mono_type_size (type, &align);
+                                       token = mono_type_size (type, &ialign);
                                } else {
                                        MonoClass *klass = mono_class_get_full (image, token, generic_context);
                                        if (!klass)
@@ -6660,7 +7178,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_LOCSTORE (cfg, store, i, ins);
                                MONO_ADD_INS (init_localsbb, store);
                        } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
-                                  ((t == MONO_TYPE_GENERICINST) && mono_metadata_generic_class_is_valuetype (ptype->data.generic_class))) {
+                                  ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
                                NEW_LOCLOADA (cfg, ins, i);
                                handle_initobj (cfg, init_localsbb, ins, NULL, mono_class_from_mono_type (ptype), NULL, NULL);
                        } else {
@@ -6702,6 +7220,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:
@@ -6716,15 +7246,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
        dont_inline = g_list_remove (dont_inline, method);
+       cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
        return -1;
 
  unverified:
        if (cfg->method != method) 
                g_hash_table_destroy (bbhash);
        g_slist_free (class_inits);
-       g_error ("Invalid IL code at IL%04x in %s: %s\n", (int)(ip - header->code), 
-                mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
        dont_inline = g_list_remove (dont_inline, method);
+       cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+       cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n",
+                mono_method_full_name (method, TRUE), mono_disasm_code_one (NULL, method, ip, NULL));
        return -1;
 }
 
@@ -6877,24 +7409,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
@@ -7013,10 +7543,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);
@@ -7029,7 +7558,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
@@ -7043,6 +7572,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)
@@ -7161,7 +7696,8 @@ typedef struct {
 gint32*
 mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stack_size, guint32 *stack_align)
 {
-       int i, slot, offset, size, align;
+       int i, slot, offset, size;
+       guint32 align;
        MonoMethodVar *vmv;
        MonoInst *inst;
        gint32 *offsets;
@@ -7199,11 +7735,21 @@ mono_allocate_stack_slots_full (MonoCompile *m, gboolean backward, guint32 *stac
                * pinvoke wrappers when they call functions returning structures */
                if (inst->unused && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
                        size = mono_class_native_size (inst->inst_vtype->data.klass, &align);
-               else
-                       size = mono_type_size (inst->inst_vtype, &align);
+               else {
+                       int ialign;
+
+                       size = mono_type_size (inst->inst_vtype, &ialign);
+                       align = ialign;
+               }
 
                t = mono_type_get_underlying_type (inst->inst_vtype);
                switch (t->type) {
+               case MONO_TYPE_GENERICINST:
+                       if (!mono_type_generic_inst_is_valuetype (t)) {
+                               slot_info = &scalar_stack_slots [t->type];
+                               break;
+                       }
+                       /* Fall through */
                case MONO_TYPE_VALUETYPE:
                        for (i = 0; i < nvtypes; ++i)
                                if (t->data.klass == vtype_stack_slots [i].vtype)
@@ -7277,7 +7823,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) {
@@ -7520,6 +8066,7 @@ mono_destroy_compile (MonoCompile *cfg)
 
        g_free (cfg->varinfo);
        g_free (cfg->vars);
+       g_free (cfg->exception_message);
        g_free (cfg);
 }
 
@@ -7663,13 +8210,13 @@ mini_thread_cleanup (MonoThread *thread)
 
        if (jit_tls) {
                mono_arch_free_jit_tls_data (jit_tls);
-               g_free (jit_tls->first_lmf);
-               g_free (jit_tls);
-               thread->jit_data = NULL;
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
                mono_free_altstack (jit_tls);
 #endif
+               g_free (jit_tls->first_lmf);
+               g_free (jit_tls);
+               thread->jit_data = NULL;
        }
 }
 
@@ -7972,39 +8519,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;
@@ -8084,7 +8598,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) {
@@ -8094,6 +8611,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;
                }
        }
@@ -8126,17 +8644,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) ||
@@ -8216,6 +8733,109 @@ move_basic_block_to_end (MonoCompile *cfg, MonoBasicBlock *bb)
        }               
 }
 
+/* checks that a and b represent the same instructions, conservatively,
+ * it can return FALSE also for two trees that are equal.
+ * FIXME: also make sure there are no side effects.
+ */
+static int
+same_trees (MonoInst *a, MonoInst *b)
+{
+       int arity;
+       if (a->opcode != b->opcode)
+               return FALSE;
+       arity = mono_burg_arity [a->opcode];
+       if (arity == 1) {
+               if (a->ssa_op == b->ssa_op && a->ssa_op == MONO_SSA_LOAD && a->inst_i0 == b->inst_i0)
+                       return TRUE;
+               return same_trees (a->inst_left, b->inst_left);
+       } else if (arity == 2) {
+               return same_trees (a->inst_left, b->inst_left) && same_trees (a->inst_right, b->inst_right);
+       } else if (arity == 0) {
+               switch (a->opcode) {
+               case OP_ICONST:
+                       return a->inst_c0 == b->inst_c0;
+               default:
+                       return FALSE;
+               }
+       }
+       return FALSE;
+}
+
+static int
+get_unsigned_condbranch (int opcode)
+{
+       switch (opcode) {
+       case CEE_BLE: return CEE_BLE_UN;
+       case CEE_BLT: return CEE_BLT_UN;
+       case CEE_BGE: return CEE_BGE_UN;
+       case CEE_BGT: return CEE_BGT_UN;
+       }
+       g_assert_not_reached ();
+       return 0;
+}
+
+static int
+tree_is_unsigned (MonoInst* ins) {
+       switch (ins->opcode) {
+       case OP_ICONST:
+               return (int)ins->inst_c0 >= 0;
+       /* array lengths are positive as are string sizes */
+       case CEE_LDLEN:
+       case OP_STRLEN:
+               return TRUE;
+       case CEE_CONV_U1:
+       case CEE_CONV_U2:
+       case CEE_CONV_U4:
+       case CEE_CONV_OVF_U1:
+       case CEE_CONV_OVF_U2:
+       case CEE_CONV_OVF_U4:
+               return TRUE;
+       case CEE_LDIND_U1:
+       case CEE_LDIND_U2:
+       case CEE_LDIND_U4:
+               return TRUE;
+       default:
+               return FALSE;
+       }
+}
+
+/* check if an unsigned compare can be used instead of two signed compares
+ * for (val < 0 || val > limit) conditionals.
+ * Returns TRUE if the optimization has been applied.
+ * Note that this can't be applied if the second arg is not positive...
+ */
+static int
+try_unsigned_compare (MonoCompile *cfg, MonoBasicBlock *bb)
+{
+       MonoBasicBlock *truet, *falset;
+       MonoInst *cmp_inst = bb->last_ins->inst_left;
+       MonoInst *condb;
+       if (!cmp_inst->inst_right->inst_c0 == 0)
+               return FALSE;
+       truet = bb->last_ins->inst_true_bb;
+       falset = bb->last_ins->inst_false_bb;
+       if (falset->in_count != 1)
+               return FALSE;
+       condb = falset->last_ins;
+       /* target bb must have one instruction */
+       if (!condb || (condb != falset->code))
+               return FALSE;
+       if ((((condb->opcode == CEE_BLE || condb->opcode == CEE_BLT) && (condb->inst_false_bb == truet))
+                       || ((condb->opcode == CEE_BGE || condb->opcode == CEE_BGT) && (condb->inst_true_bb == truet)))
+                       && same_trees (cmp_inst->inst_left, condb->inst_left->inst_left)) {
+               if (!tree_is_unsigned (condb->inst_left->inst_right))
+                       return FALSE;
+               condb->opcode = get_unsigned_condbranch (condb->opcode);
+               /* change the original condbranch to just point to the new unsigned check */
+               bb->last_ins->opcode = CEE_BR;
+               bb->last_ins->inst_target_bb = falset;
+               replace_out_block (bb, truet, NULL);
+               replace_in_block (truet, bb, NULL);
+               return TRUE;
+       }
+       return FALSE;
+}
+
 /*
  * Optimizes the branches on the Control Flow Graph
  *
@@ -8236,6 +8856,7 @@ optimize_branches (MonoCompile *cfg)
                niterations = cfg->num_bblocks * 2;
        else
                niterations = 1000;
+
        do {
                MonoBasicBlock *previous_bb;
                changed = FALSE;
@@ -8248,7 +8869,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;
                        }
@@ -8303,27 +8924,13 @@ 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);
                                        }
-                               }                               
+                               }
                        }
-               }
-       } while (changed && (niterations > 0));
-
-       niterations = 1000;
-       do {
-               changed = FALSE;
-               niterations --;
-
-               /* we skip the entry block (exit is handled specially instead ) */
-               for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
-
-                       /* dont touch code inside exception clauses */
-                       if (bb->region != -1)
-                               continue;
-
                        if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
                                if (cfg->verbose_level > 2) {
                                        g_print ("nullify block triggered %d\n", bbn->block_num);
@@ -8335,10 +8942,9 @@ optimize_branches (MonoCompile *cfg)
 
                                nullify_basic_block (bbn);                      
                                changed = TRUE;
-                               break;
+                               continue;
                        }
 
-
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
@@ -8356,7 +8962,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) {
@@ -8376,10 +8982,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 &&
@@ -8389,17 +8994,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;
@@ -8410,17 +9019,25 @@ optimize_branches (MonoCompile *cfg)
                                                                 bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
                                                                 bbn->code->opcode);
 
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
+
                                                bb->last_ins->inst_false_bb = bbn->code->inst_target_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);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+                                               changed = TRUE;
+                                               continue;
+                                       }
+                               }
 
+                               /* detect and optimize to unsigned compares checks like: if (v < 0 || v > limit */
+                               if (bb->last_ins && bb->last_ins->opcode == CEE_BLT && bb->last_ins->inst_left->inst_right->opcode == OP_ICONST) {
+                                       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;
                                        }
                                }
 
@@ -8518,7 +9135,7 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
 {
        MBState *kids [10];
        int ern = mono_burg_rule (state, goal);
-       const guint16 *nts = mono_burg_nts [ern];
+       const guint16 *nts = mono_burg_nts_data + mono_burg_nts [ern];
        MBEmitFunc emit;
 
        //g_print ("rule: %s\n", mono_burg_rule_string [ern]);
@@ -8757,8 +9374,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 {
@@ -8797,9 +9421,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);
        }
 
@@ -8822,190 +9446,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) {
-                       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) {
@@ -9135,6 +9576,18 @@ remove_critical_edges (MonoCompile *cfg) {
        }
 }
 
+/*
+ * mini_method_compile:
+ * @method: the method to compile
+ * @opts: the optimization flags to use
+ * @domain: the domain where the method will be compiled in
+ * @run_cctors: whether we should run type ctors if possible
+ * @compile_aot: whether this is an AOT compilation
+ * @parts: debug flag
+ *
+ * Returns: a MonoCompile* pointer. Caller must check the exception_type
+ * field in the returned struct to see if compilation succeded.
+ */
 MonoCompile*
 mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gboolean run_cctors, gboolean compile_aot, int parts)
 {
@@ -9143,11 +9596,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        MonoCompile *cfg;
        MonoJitInfo *jinfo;
        int dfn = 0, i, code_size_ratio;
-
-       if (!header)
-               return NULL;
-
-       ip = (guint8 *)header->code;
+       gboolean deadce_has_run = FALSE;
 
        mono_jit_stats.methods_compiled++;
        if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
@@ -9163,9 +9612,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->domain = domain;
        cfg->verbose_level = mini_verbose;
        cfg->compile_aot = compile_aot;
-       cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
-                                           mono_method_get_header (method)->max_stack);
+       if (!header) {
+               cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
+               cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
+               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
+                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
+               return cfg;
+       }
+
+       ip = (guint8 *)header->code;
 
+       cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * header->max_stack);
+       cfg->aliasing_info = NULL;
+       
        if (cfg->verbose_level > 2)
                g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
 
@@ -9176,9 +9635,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
                if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
-                       mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
-               mono_destroy_compile (cfg);
-               return NULL;
+                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED);
+               /* cfg contains the details of the failure, so let the caller cleanup */
+               return cfg;
        }
 
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
@@ -9220,7 +9679,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 {
@@ -9250,7 +9709,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #else 
 
        /* fixme: add all optimizations which requires SSA */
-       if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
+       if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
                        mono_local_cprop (cfg);
                        mono_ssa_compute (cfg);
@@ -9275,16 +9734,23 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        if (cfg->comp_done & MONO_COMP_SSA) {                   
-               mono_ssa_deadce (cfg);
+               //mono_ssa_deadce (cfg);
 
                //mono_ssa_strength_reduction (cfg);
 
+               if (cfg->opt & MONO_OPT_SSAPRE) {
+                       mono_perform_ssapre (cfg);
+                       //mono_local_cprop (cfg);
+               }
+               
+               if (cfg->opt & MONO_OPT_DEADCE) {
+                       mono_ssa_deadce (cfg);
+                       deadce_has_run = TRUE;
+               }
+               
                if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
                        mono_perform_abc_removal (cfg);
                
-               if (cfg->opt & MONO_OPT_SSAPRE)
-                       mono_perform_ssapre (cfg);
-               
                mono_ssa_remove (cfg);
 
                if (cfg->opt & MONO_OPT_BRANCH)
@@ -9320,18 +9786,33 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if (cfg->opt & MONO_OPT_LINEARS) {
                GList *vars, *regs;
+               
+               /* For now, compute aliasing info only if needed for deadce... */
+               if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
+                       cfg->aliasing_info = mono_build_aliasing_information (cfg);
+               }
 
                /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
                cfg->comp_done &= ~MONO_COMP_LIVENESS;
                if (!(cfg->comp_done & MONO_COMP_LIVENESS))
                        mono_analyze_liveness (cfg);
 
+               if (cfg->aliasing_info != NULL) {
+                       mono_aliasing_deadce (cfg->aliasing_info);
+                       deadce_has_run = TRUE;
+               }
+               
                if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
                        regs = mono_arch_get_global_int_regs (cfg);
                        if (cfg->got_var)
                                regs = g_list_delete_link (regs, regs);
                        mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
                }
+               
+               if (cfg->aliasing_info != NULL) {
+                       mono_destroy_aliasing_information (cfg->aliasing_info);
+                       cfg->aliasing_info = NULL;
+               }
        }
 
        //mono_print_code (cfg);
@@ -9434,42 +9915,19 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_jit_stats.native_code_size += cfg->code_len;
 
        if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
-               mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
-
-       /* this can only be set if the security manager is active */
-       if (cfg->exception_type == MONO_EXCEPTION_SECURITY_LINKDEMAND) {
-               MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
-               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (domain, assembly);
-               MonoReflectionMethod *refmet = mono_method_get_object (domain, method, NULL);
-               MonoSecurityManager* secman = mono_security_manager_get_methods ();
-               MonoObject *exc = NULL;
-               gpointer args [3];
-
-               args [0] = &cfg->exception_data;
-               args [1] = refass;
-               args [2] = refmet;
-               mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
-
-               mono_destroy_compile (cfg);
-               cfg = NULL;
-
-               mono_raise_exception ((MonoException*)exc);
-       }
+               mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
 
        return cfg;
 }
 
 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);
@@ -9538,17 +9996,56 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
 
        cfg = mini_method_compile (method, opt, target_domain, TRUE, FALSE, 0);
 
-       if (!cfg) {
+       switch (cfg->exception_type) {
+       case MONO_EXCEPTION_NONE: break;
+       case MONO_EXCEPTION_TYPE_LOAD:
+       case MONO_EXCEPTION_MISSING_FIELD:
+       case MONO_EXCEPTION_MISSING_METHOD: {
                /* Throw a type load exception if needed */
                MonoLoaderError *error = mono_loader_get_last_error ();
 
+               mono_destroy_compile (cfg);
                if (error) {
                        MonoException *ex = mini_loader_error_to_exception (error);
                        mono_loader_clear_error ();
                        mono_raise_exception (ex);
-               }
-               else
+               } else {
                        g_assert_not_reached ();
+               }
+       }
+       case MONO_EXCEPTION_INVALID_PROGRAM: {
+               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System", "InvalidProgramException", cfg->exception_message);
+               mono_destroy_compile (cfg);
+               mono_raise_exception (ex);
+               break;
+       }
+       case MONO_EXCEPTION_UNVERIFIABLE_IL: {
+               MonoException *ex = mono_exception_from_name_msg (mono_defaults.corlib, "System.Security", "VerificationException", cfg->exception_message);
+               mono_destroy_compile (cfg);
+               mono_raise_exception (ex);
+               break;
+       }
+       /* this can only be set if the security manager is active */
+       case MONO_EXCEPTION_SECURITY_LINKDEMAND: {
+               MonoAssembly *assembly = mono_image_get_assembly (method->klass->image);
+               MonoReflectionAssembly *refass = (MonoReflectionAssembly*) mono_assembly_get_object (target_domain, assembly);
+               MonoReflectionMethod *refmet = mono_method_get_object (target_domain, method, NULL);
+               MonoSecurityManager* secman = mono_security_manager_get_methods ();
+               MonoObject *exc = NULL;
+               gpointer args [3];
+
+               args [0] = &cfg->exception_data;
+               args [1] = refass;
+               args [2] = refmet;
+               mono_runtime_invoke (secman->linkdemandsecurityexception, NULL, args, &exc);
+
+               mono_destroy_compile (cfg);
+               cfg = NULL;
+
+               mono_raise_exception ((MonoException*)exc);
+       }
+       default:
+               g_assert_not_reached ();
        }
 
        mono_domain_lock (target_domain);
@@ -9596,10 +10093,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 ();
@@ -9614,13 +10127,24 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
                        mono_domain_unlock (target_domain);
                        mono_jit_stats.methods_lookups++;
                        mono_runtime_class_init (mono_class_vtable (domain, method->klass));
-                       return mono_create_ftnptr (domain, info->code_start);
+                       return mono_create_ftnptr (target_domain, info->code_start);
                }
        }
 
        mono_domain_unlock (target_domain);
-       p = mono_jit_compile_method_inner (method, target_domain);
-       return mono_create_ftnptr (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
@@ -9759,7 +10283,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 #define GET_CONTEXT \
     ucontext_t *uctx = context; \
     struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
-#elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
+#elif defined (MONO_ARCH_USE_SIGACTION)
 #define GET_CONTEXT \
     void *ctx = context;
 #else
@@ -9800,7 +10324,8 @@ static void
 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
 {
        MonoException *exc;
-       GET_CONTEXT
+       GET_CONTEXT;
+
        exc = mono_get_exception_execution_engine ("SIGILL");
        
        mono_arch_handle_exception (ctx, exc, FALSE);
@@ -9818,10 +10343,12 @@ static void
 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 {
        MonoException *exc = NULL;
+       MonoJitInfo *ji;
+
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
 #endif
-       GET_CONTEXT
+       GET_CONTEXT;
 
 #ifdef MONO_ARCH_USE_SIGACTION
        if (debug_options.collect_pagefault_stats) {
@@ -9846,27 +10373,42 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
                exc = mono_domain_get ()->null_reference_ex;
 #endif
 
-       if (debug_options.abort_on_sigsegv) {
-               MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
-               if (!ji) {
-                       fprintf (stderr, "Got SIGSEGV while in unmanaged code, and the 'abort-on-sigsegv' MONO_DEBUG option is set. Aborting...\n");
-                       /* Segfault in unmanaged code */
-                       abort ();
-               }
+       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+       if (!ji) {
+               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)
 {
        gboolean running_managed;
        MonoException *exc;
+       MonoThread *thread = mono_thread_current ();
        void *ji;
        
        GET_CONTEXT;
 
+       if (thread->thread_dump_requested) {
+               thread->thread_dump_requested = FALSE;
+
+               mono_print_thread_dump (ctx);
+       }
+
        /*
         * FIXME:
         * This is an async signal, so the code below must not call anything which
@@ -9893,19 +10435,26 @@ SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
 static void
 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
 {
-       MonoException *exc;
-       GET_CONTEXT
+       GET_CONTEXT;
 
-       exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
-       
-       mono_arch_handle_exception (ctx, exc, FALSE);
+       printf ("Full thread dump:\n");
+
+       mono_threads_request_thread_dump ();
+
+       /*
+        * print_thread_dump () skips the current thread, since sending a signal
+        * to it would invoke the signal handler below the sigquit signal handler,
+        * and signal handlers don't create an lmf, so the stack walk could not
+        * be performed.
+        */
+       mono_print_thread_dump (ctx);
 }
 
 static void
 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
 {
        MonoException *exc;
-       GET_CONTEXT
+       GET_CONTEXT;
 
        exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
        
@@ -9974,6 +10523,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;
@@ -9983,7 +10534,6 @@ mono_runtime_install_handlers (void)
 #else
        add_signal_handler (SIGSEGV, sigsegv_signal_handler);
 #endif
-
 #endif /* PLATFORM_WIN32 */
 }
 
@@ -10112,13 +10662,11 @@ mini_parse_debug_options (void)
                        debug_options.handle_sigint = TRUE;
                else if (!strcmp (arg, "keep-delegates"))
                        debug_options.keep_delegates = TRUE;
-               else if (!strcmp (arg, "abort-on-sigsegv"))
-                       debug_options.abort_on_sigsegv = TRUE;
                else if (!strcmp (arg, "collect-pagefault-stats"))
                        debug_options.collect_pagefault_stats = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv', 'collect-pagefault-stats'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats'\n");
                        exit (1);
                }
        }
@@ -10150,12 +10698,44 @@ mini_init (const char *filename)
        if (getenv ("MONO_DEBUG") != NULL)
                mini_parse_debug_options ();
 
-       if (mono_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)
+#if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK)
+       {
+               size_t size;
+               void *sstart;
+               pthread_attr_t attr;
+               pthread_getattr_np (pthread_self (), &attr);
+               pthread_attr_getstack (&attr, &sstart, &size);
+               /*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 ());
+#else
+       {
                gsize stack_bottom = (gsize)&domain;
                stack_bottom += 4095;
                stack_bottom &= ~4095;
+               /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/
                GC_stackbottom = (char*)stack_bottom;
        }
+#endif
+#endif
        MONO_GC_PRE_INIT ();
 
        mono_jit_tls_id = TlsAlloc ();
@@ -10402,6 +10982,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 ();
@@ -10420,8 +11003,9 @@ 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_counters_dump (-1, stdout);
 }
 
 void