2006-07-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 897aee24747fbf92eaf2b7d7356077b0ff7a431d..10f42e6e2bbca395e8a9b2de8e1e629813256313 100644 (file)
 #include <math.h>
 #include <sys/time.h>
 
-#ifdef sun    // Solaris x86
-#include <sys/types.h>
-#include <sys/ucontext.h>
-#endif
-
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
@@ -79,6 +74,8 @@
 #define MONO_IS_COND_BRANCH_OP(ins) (((ins)->opcode >= CEE_BEQ && (ins)->opcode <= CEE_BLT_UN) || ((ins)->opcode >= OP_LBEQ && (ins)->opcode <= OP_LBLT_UN) || ((ins)->opcode >= OP_FBEQ && (ins)->opcode <= OP_FBLT_UN) || ((ins)->opcode >= OP_IBEQ && (ins)->opcode <= OP_IBLT_UN))
 #define MONO_IS_COND_BRANCH_NOFP(ins) (MONO_IS_COND_BRANCH_OP(ins) && (ins)->inst_left->inst_left->type != STACK_R8)
 
+#define MONO_IS_BRANCH_OP(ins) (MONO_IS_COND_BRANCH_OP(ins) || ((ins)->opcode == CEE_BR) || ((ins)->opcode == OP_BR_REG) || ((ins)->opcode == CEE_SWITCH))
+
 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
 static void setup_stat_profiler (void);
@@ -102,6 +99,7 @@ static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
 static MonoMethodSignature *helper_sig_domain_get = NULL;
 
 static guint32 default_opt = 0;
+static gboolean default_opt_set = FALSE;
 
 guint32 mono_jit_tls_id = -1;
 MonoTraceSpec *mono_jit_trace_calls = NULL;
@@ -404,7 +402,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_PTR;                               \
        } while (0)
 
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do { \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
                MonoInst *group, *got_var, *got_loc;                    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst)); \
                (dest)->opcode = OP_GOT_ENTRY;                          \
@@ -414,7 +412,8 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                group->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token)); \
                (dest)->inst_p0 = got_var;                              \
                (dest)->inst_p1 = group;                                \
-               (dest)->type = (stack_type);                            \
+               (dest)->type = (stack_type);                    \
+        (dest)->klass = (stack_class);          \
        } while (0)
 
 #else
@@ -427,12 +426,13 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
                (dest)->type = STACK_PTR;       \
     } while (0)
 
-#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type) do {    \
+#define NEW_AOTCONST_TOKEN(cfg,dest,patch_type,image,token,stack_type,stack_class) do { \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
                (dest)->opcode = OP_AOTCONST;   \
                (dest)->inst_p0 = mono_jump_info_token_new ((cfg)->mempool, (image), (token));  \
                (dest)->inst_p1 = (gpointer)(patch_type); \
                (dest)->type = (stack_type);    \
+        (dest)->klass = (stack_class);          \
     } while (0)
 
 #endif
@@ -449,15 +449,15 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_SFLDACONST(cfg,dest,val) NEW_AOTCONST ((cfg), (dest), MONO_PATCH_INFO_SFLDA, (val))
 
-#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ)
+#define NEW_LDSTRCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDSTR, (image), (token), STACK_OBJ, mono_defaults.string_class)
 
-#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ)
+#define NEW_TYPE_FROM_HANDLE_CONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_TYPE_FROM_HANDLE, (image), (token), STACK_OBJ, mono_defaults.monotype_class)
 
-#define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR)
+#define NEW_LDTOKENCONST(cfg,dest,image,token) NEW_AOTCONST_TOKEN ((cfg), (dest), MONO_PATCH_INFO_LDTOKEN, (image), (token), STACK_PTR, NULL)
 
 #define NEW_DECLSECCONST(cfg,dest,image,entry) do { \
                if (cfg->compile_aot) { \
-                       NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ); \
+                       NEW_AOTCONST_TOKEN (cfg, dest, MONO_PATCH_INFO_DECLSEC, image, (entry).index, STACK_OBJ, NULL); \
                } else { \
                        NEW_PCONST (cfg, args [0], (entry).blob); \
                } \
@@ -1614,7 +1614,19 @@ type_from_stack_type (MonoInst *ins) {
        case STACK_I8: return &mono_defaults.int64_class->byval_arg;
        case STACK_PTR: return &mono_defaults.int_class->byval_arg;
        case STACK_R8: return &mono_defaults.double_class->byval_arg;
-       case STACK_MP: return &mono_defaults.int_class->byval_arg;
+       case STACK_MP:
+               /* 
+                * FIXME: This doesn't work because mono_class_from_mono_type ()
+                * returns the original klass for a byref type, not a 'byref' class,
+                * causing the JIT to create variables with the wrong type, for
+                * example.
+                */
+               /*
+               if (ins->klass)
+                       return &ins->klass->this_arg;
+               else
+               */
+                       return &mono_defaults.object_class->this_arg;
        case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
        case STACK_VTYPE: return &ins->klass->byval_arg;
        default:
@@ -1762,6 +1774,66 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
        return res;
 }
 
+/*
+ * merge_stacks:
+ *
+ * Merge stack state between two basic blocks according to Ecma 335, Partition III,
+ * section 1.8.1.1. Store the resulting stack state into stack_2.
+ * Returns: TRUE, if verification succeeds, FALSE otherwise.
+ * FIXME: We should store the stack state in a dedicated structure instead of in
+ * MonoInst's.
+ */
+static gboolean
+merge_stacks (MonoCompile *cfg, MonoStackSlot *state_1, MonoStackSlot *state_2, guint32 size)
+{
+       int i;
+
+       if (cfg->dont_verify_stack_merge)
+               return TRUE;
+
+       /* FIXME: Implement all checks from the spec */
+
+       for (i = 0; i < size; ++i) {
+               MonoStackSlot *slot1 = &state_1 [i];
+               MonoStackSlot *slot2 = &state_2 [i];
+
+               if (slot1->type != slot2->type)
+                       return FALSE;
+
+               switch (slot1->type) {
+               case STACK_PTR:
+                       /* FIXME: Perform merge ? */
+                       /* klass == NULL means a native int */
+                       if (slot1->klass && slot2->klass) {
+                               if (slot1->klass != slot2->klass)
+                                       return FALSE;
+                       }
+                       break;
+               case STACK_MP:
+                       /* FIXME: Change this to an assert and fix the JIT to allways fill this */
+                       if (slot1->klass && slot2->klass) {
+                               if (slot1->klass != slot2->klass)
+                                       return FALSE;
+                       }
+                       break;
+               case STACK_OBJ: {
+                       MonoClass *klass1 = slot1->klass;
+                       MonoClass *klass2 = slot2->klass;
+
+                       if (!klass1) {
+                               /* slot1 is ldnull */
+                       } else if (!klass2) {
+                               /* slot2 is ldnull */
+                               slot2->klass = slot1->klass;
+                       }
+                       break;
+               }
+               }
+       }
+
+       return TRUE;
+}
+
 /*
  * This function is called to handle items that are left on the evaluation stack
  * at basic block boundaries. What happens is that we save the values to local variables
@@ -1772,18 +1844,64 @@ mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
  * which case its old value should be used.
  * A single joint point will use the same variables (stored in the array bb->out_stack or
  * bb->in_stack, if the basic block is before or after the joint point).
+ * If the stack merge fails at a join point, cfg->unverifiable is set.
  */
 static int
 handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int count) {
        int i, bindex;
        MonoBasicBlock *outb;
        MonoInst *inst, **locals;
+       MonoStackSlot *stack_state;
        gboolean found;
 
        if (!count)
                return 0;
        if (cfg->verbose_level > 3)
                g_print ("%d item(s) on exit from B%d\n", count, bb->block_num);
+
+       stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
+       for (i = 0; i < count; ++i) {
+               stack_state [i].type = sp [i]->type;
+               stack_state [i].klass = sp [i]->klass;
+
+               /* Check that instructions other than ldnull have ins->klass set */
+               if (!cfg->dont_verify_stack_merge && (sp [i]->type == STACK_OBJ) && !((sp [i]->opcode == OP_PCONST) && sp [i]->inst_c0 == 0))
+                       g_assert (sp [i]->klass);
+       }
+
+       /* Perform verification and stack state merge */
+       for (i = 0; i < bb->out_count; ++i) {
+               outb = bb->out_bb [i];
+
+               /* exception handlers are linked, but they should not be considered for stack args */
+               if (outb->flags & BB_EXCEPTION_HANDLER)
+                       continue;
+               if (outb->stack_state) {
+                       gboolean verified;
+
+                       if (count != outb->in_scount) {
+                               cfg->unverifiable = TRUE;
+                               return 0;
+                       }
+                       verified = merge_stacks (cfg, stack_state, outb->stack_state, count);
+                       if (!verified) {
+                               cfg->unverifiable = TRUE;
+                               return 0;
+                       }
+
+                       if (cfg->verbose_level > 3) {
+                               int j;
+
+                               for (j = 0; j < count; ++j)
+                                       printf ("\tStack state of BB%d, slot %d=%d\n", outb->block_num, j, outb->stack_state [j].type);
+                       }
+               } else {
+                       /* Make a copy of the stack state */
+                       outb->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot) * count);
+                       memcpy (outb->stack_state, stack_state, sizeof (MonoStackSlot) * count);
+               }
+       }
+
        if (!bb->out_scount) {
                bb->out_scount = count;
                //g_print ("bblock %d has out:", bb->block_num);
@@ -2832,8 +2950,14 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
        if (!(cfg->opt & MONO_OPT_SHARED)) {
                vtable = mono_class_vtable (cfg->domain, method->klass);
                if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
-                       if (cfg->run_cctors)
+                       if (cfg->run_cctors) {
+                               /* This makes so that inline cannot trigger */
+                               /* .cctors: too many apps depend on them */
+                               /* running with a specific order... */
+                               if (! vtable->initialized)
+                                       return FALSE;
                                mono_runtime_class_init (vtable);
+                       }
                }
                else if (!vtable->initialized && mono_class_needs_cctor_run (method->klass, NULL))
                        return FALSE;
@@ -3094,8 +3218,8 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                sp++;
        }
 }
-#define MONO_INLINE_CALLED_LIMITED_METHODS 1
-#define MONO_INLINE_CALLER_LIMITED_METHODS 1
+#define MONO_INLINE_CALLED_LIMITED_METHODS 0
+#define MONO_INLINE_CALLER_LIMITED_METHODS 0
 
 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
 static char*
@@ -3256,7 +3380,7 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
-
+#define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
 
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
@@ -3411,12 +3535,22 @@ mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
        return klass;
 }
 
+/*
+ * Returns TRUE if the JIT should abort inlining because "callee"
+ * is influenced by security attributes.
+ */
 static
-void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
+gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee, MonoBasicBlock *bblock, unsigned char *ip)
 {
-       guint32 result = mono_declsec_linkdemand (cfg->domain, caller, callee);
+       guint32 result;
+       
+       if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
+               return TRUE;
+       }
+       
+       result = mono_declsec_linkdemand (cfg->domain, caller, callee);
        if (result == MONO_JIT_SECURITY_OK)
-               return;
+               return FALSE;
 
        if (result == MONO_JIT_LINKDEMAND_ECMA) {
                /* Generate code to throw a SecurityException before the actual call/link */
@@ -3435,6 +3569,8 @@ void check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
                cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
                cfg->exception_data = result;
        }
+       
+       return FALSE;
 }
 
 static gboolean
@@ -3580,12 +3716,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
 
-       /* still some type unsefety issues in marshal wrappers... (unknown is PtrToStructure) */
+       /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
        dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
        dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
        dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
 
+       /* Not turned on yet */
+       cfg->dont_verify_stack_merge = TRUE;
+
        image = method->klass->image;
        header = mono_method_get_header (method);
        generic_container = method->generic_container;
@@ -3680,6 +3820,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                tblock->in_scount = 1;
                                tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
                                tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
+                               tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
+                               tblock->stack_state [0].type = STACK_OBJ;
+                               /* FIXME? */
+                               tblock->stack_state [0].klass = mono_defaults.object_class;
 
                                /* 
                                 * Add a dummy use for the exvar so its liveness info will be
@@ -3694,6 +3838,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        tblock->real_offset = clause->data.filter_offset;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
+                                       tblock->stack_state = mono_mempool_alloc (cfg->mempool, sizeof (MonoStackSlot));
+                                       tblock->stack_state [0].type = STACK_OBJ;
+                                       /* FIXME? */
+                                       tblock->stack_state [0].klass = mono_defaults.object_class;
+
                                        /* The filter block shares the exvar with the handler block */
                                        tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
                                        MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
@@ -3880,6 +4029,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                        sp = stack_start;
+                                       CHECK_UNVERIFIABLE (cfg);
                                }
                                bblock->next_bb = tblock;
                                bblock = tblock;
@@ -4195,7 +4345,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
 
                        if (mono_use_security_manager) {
-                               check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                       INLINE_FAILURE;
                        }
 
                        ins->inst_p0 = cmethod;
@@ -4261,7 +4412,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = fsig->param_count + fsig->hasthis;
 
                                if (mono_use_security_manager) {
-                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                                       if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                               INLINE_FAILURE;
                                }
 
                                if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
@@ -4314,6 +4466,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->cil_code = ip;
                                        ins->inst_i0 = sp [0];
                                        ins->type = STACK_OBJ;
+                                       ins->klass = mono_class_from_mono_type (&constrained_call->byval_arg);
                                        sp [0] = ins;
                                } else if (cmethod->klass->valuetype)
                                        virtual = 0;
@@ -4356,12 +4509,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                ip += 5;
+                               ins_flag = 0;
                                break;
                        }
 
                        if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
                                 (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
                                int i;
+
                                /* Prevent inlining of methods with tail calls (the call stack would be altered) */
                                INLINE_FAILURE;
                                /* FIXME: This assumes the two methods has the same number and type of arguments */
@@ -4406,6 +4561,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                                ip += 5;
+                               ins_flag = 0;
                                break;
                        }
 
@@ -4443,6 +4599,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        bblock = ebblock;
 
                                        inline_costs += costs;
+                                       ins_flag = 0;
                                        break;
                                }
                        }
@@ -4481,7 +4638,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ip += 6;
                                        else
                                                ip += 5;
-
+                                       ins_flag = 0;
                                        break;
                                }
                        }
@@ -4568,6 +4725,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        ip += 5;
+                       ins_flag = 0;
                        break;
                }
                case CEE_RET:
@@ -4631,6 +4789,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        start_new_bblock = 1;
                        inline_costs += BRANCH_COST;
@@ -4649,6 +4808,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4672,6 +4832,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4689,6 +4850,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        start_new_bblock = 1;
                        inline_costs += BRANCH_COST;
@@ -4707,6 +4869,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4730,6 +4893,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        inline_costs += BRANCH_COST;
                        break;
@@ -4762,6 +4926,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (sp != stack_start) {
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
+                               CHECK_UNVERIFIABLE (cfg);
                        }
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
@@ -4787,6 +4952,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->type = ldind_type [*ip - CEE_LDIND_I1];
                        ins->flags |= ins_flag;
                        ins_flag = 0;
+                       if (ins->type == STACK_OBJ)
+                               ins->klass = mono_defaults.object_class;
                        ++ip;
                        break;
                case CEE_STIND_REF:
@@ -4956,6 +5123,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                load->cil_code = ip;
                                load->inst_i0 = sp [1];
                                load->type = STACK_OBJ;
+                               load->klass = klass;
                                load->flags |= ins_flag;
                                MONO_INST_NEW (cfg, store, CEE_STIND_REF);
                                store->cil_code = ip;
@@ -5004,6 +5172,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                ins->cil_code = ip;
                                ins->inst_i0 = sp [0];
                                ins->type = STACK_OBJ;
+                               ins->klass = klass;
                                ins->flags |= ins_flag;
                                ins_flag = 0;
                                *sp++ = ins;
@@ -5079,6 +5248,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
                                ins->cil_code = ip;
                                ins->type = STACK_OBJ;
+                               ins->klass = mono_defaults.string_class;
                                *sp = ins;
                        }
                        else if (method->wrapper_type != MONO_WRAPPER_NONE) {
@@ -5137,6 +5307,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                ins->cil_code = ip;
                                                ins->type = STACK_OBJ;
                                                ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+                                               ins->klass = mono_defaults.string_class;
                                                *sp = ins;
                                        }
                                }
@@ -5161,7 +5332,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                goto load_error;
 
                        if (mono_use_security_manager) {
-                               check_linkdemand (cfg, method, cmethod, bblock, ip);
+                               if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                       INLINE_FAILURE;
                        }
 
                        n = fsig->param_count;
@@ -5384,6 +5556,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        add->inst_left = ins;
                        add->inst_right = vtoffset;
                        add->type = STACK_MP;
+                       add->klass = mono_defaults.object_class;
                        *sp = add;
                        ip += 5;
                        /* LDOBJ impl */
@@ -5603,6 +5776,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->inst_left = *sp;
                                        ins->inst_right = offset_ins;
                                        ins->type = STACK_MP;
+                                       ins->klass = mono_defaults.object_class;
                                        iargs [0] = ins;
                                        iargs [1] = sp [1];
                                        mono_emit_method_call_spilled (cfg, bblock, write_barrier, mono_method_signature (write_barrier), iargs, ip, NULL);
@@ -5751,8 +5925,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                        g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
                                                class_inits = g_slist_prepend (class_inits, vtable);
                                        } else {
-                                               if (cfg->run_cctors)
+                                               if (cfg->run_cctors) {
+                                                       /* This makes so that inline cannot trigger */
+                                                       /* .cctors: too many apps depend on them */
+                                                       /* running with a specific order... */
+                                                       if (! vtable->initialized)
+                                                               INLINE_FAILURE;
                                                        mono_runtime_class_init (vtable);
+                                               }
                                        }
                                        addr = (char*)vtable->data + field->offset;
 
@@ -5957,6 +6137,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                if (sp != stack_start) {
                                        handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                        sp = stack_start;
+                                       CHECK_UNVERIFIABLE (cfg);
                                }
                                start_new_bblock = 1;
                                break;
@@ -5991,6 +6172,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
+                       ins->klass = klass;
                        ip += 5;
                        *sp++ = ins;
                        /* 
@@ -6042,6 +6224,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                check->klass = klass;
                                check->inst_left = sp [0];
                                check->type = STACK_OBJ;
+                               check->klass = klass;
                                sp [0] = check;
                        }
                        
@@ -6102,6 +6285,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->inst_left = load;
                        *sp++ = ins;
                        ins->type = ldind_type [ins->opcode - CEE_LDIND_I1];
+                       ins->klass = klass;
                        ++ip;
                        break;
                }
@@ -6727,7 +6911,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
-                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                                       if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                               INLINE_FAILURE;
                                }
 
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -6757,7 +6942,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                mono_class_init (cmethod->klass);
 
                                if (mono_use_security_manager) {
-                                       check_linkdemand (cfg, method, cmethod, bblock, ip);
+                                       if (check_linkdemand (cfg, method, cmethod, bblock, ip))
+                                               INLINE_FAILURE;
                                }
 
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -6937,6 +7123,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_PCONST (cfg, load, NULL);
                                        load->cil_code = ip;
                                        load->type = STACK_OBJ;
+                                       load->klass = klass;
                                        MONO_INST_NEW (cfg, store, CEE_STIND_REF);
                                        store->cil_code = ip;
                                        handle_loaded_temps (cfg, bblock, stack_start, sp);
@@ -8197,6 +8384,36 @@ mono_remove_patch_info (MonoCompile *cfg, int ip)
        }
 }
 
+/**
+ * mono_patch_info_dup_mp:
+ *
+ * Make a copy of PATCH_INFO, allocating memory from the mempool MP.
+ */
+MonoJumpInfo*
+mono_patch_info_dup_mp (MonoMemPool *mp, MonoJumpInfo *patch_info)
+{
+       MonoJumpInfo *res = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
+       memcpy (res, patch_info, sizeof (MonoJumpInfo));
+
+       switch (patch_info->type) {
+       case MONO_PATCH_INFO_LDSTR:
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+       case MONO_PATCH_INFO_LDTOKEN:
+       case MONO_PATCH_INFO_DECLSEC:
+               res->data.token = mono_mempool_alloc (mp, sizeof (MonoJumpInfoToken));
+               memcpy (res->data.token, patch_info->data.token, sizeof (MonoJumpInfoToken));
+               break;
+       case MONO_PATCH_INFO_SWITCH:
+               res->data.table = mono_mempool_alloc (mp, sizeof (MonoJumpInfoBBTable));
+               memcpy (res->data.table, patch_info->data.table, sizeof (MonoJumpInfoBBTable));
+               break;
+       default:
+               break;
+       }
+
+       return res;
+}
+
 gpointer
 mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *patch_info, gboolean run_cctors)
 {
@@ -8590,6 +8807,13 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
        if ((previous_bb == cfg->bb_entry) && (bb->next_bb != target_bb)) {
                return FALSE;
        }
+
+       /* 
+        * Do not touch BBs following a try block as the code in 
+        * mini_method_compile needs them to compute the length of the try block.
+        */
+       if (MONO_BBLOCK_IS_IN_REGION (previous_bb, MONO_REGION_TRY))
+               return FALSE;
        
        /* Check that there is a target BB, and that bb is not an empty loop (Bug 75061) */
        if ((target_bb != NULL) && (target_bb != bb)) {
@@ -8644,6 +8868,11 @@ merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
 
        replace_basic_block (bb, bbn, bb);
 
+       /* Nullify branch at the end of bb */
+       if (bb->last_ins && MONO_IS_BRANCH_OP (bb->last_ins)) {
+               bb->last_ins->opcode = CEE_NOP;
+       }               
+
        if (bb->last_ins) {
                if (bbn->code) {
                        bb->last_ins->next = bbn->code;
@@ -9716,6 +9945,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (parts == 3)
                return cfg;
 
+       if (cfg->verbose_level > 4) {
+               printf ("BEFORE DECOMPSE START\n");
+               mono_print_code (cfg);
+               printf ("BEFORE DECOMPSE END\n");
+       }
+       
        decompose_pass (cfg);
 
        if (cfg->got_var) {
@@ -9911,7 +10146,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                MonoMethod *nm;
                MonoMethodPInvoke* piinfo = (MonoMethodPInvoke *) method;
 
-               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE)
+               if (method->iflags & METHOD_IMPL_ATTRIBUTE_NATIVE && !MONO_CLASS_IS_IMPORT(method->klass))
                        g_error ("Method '%s' in assembly '%s' contains native code and mono can't run it. The assembly was probably created by Managed C++.\n", mono_method_full_name (method, TRUE), method->klass->image->name);
 
                if (!piinfo->addr) {
@@ -10234,10 +10469,6 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 #ifdef __sparc
 #define GET_CONTEXT \
     void *ctx = context;
-#elif defined(sun)    // Solaris x86
-#define GET_CONTEXT \
-    ucontext_t *uctx = context; \
-    struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
 #elif defined (MONO_ARCH_USE_SIGACTION)
 #define GET_CONTEXT \
     void *ctx = context;
@@ -10633,7 +10864,7 @@ mini_init (const char *filename)
        MonoDomain *domain;
 
        /* Happens when using the embedding interface */
-       if (default_opt == 0)
+       if (!default_opt_set)
                default_opt = mono_parse_default_optimizations (NULL);
 
        InitializeCriticalSection (&jit_mutex);
@@ -10969,6 +11200,12 @@ mini_cleanup (MonoDomain *domain)
        mono_trace_cleanup ();
 
        mono_counters_dump (-1, stdout);
+
+       TlsFree(mono_jit_tls_id);
+
+       DeleteCriticalSection (&jit_mutex);
+
+       DeleteCriticalSection (&mono_delegate_section);
 }
 
 void
@@ -10976,6 +11213,7 @@ mono_set_defaults (int verbose_level, guint32 opts)
 {
        mini_verbose = verbose_level;
        default_opt = opts;
+       default_opt_set = TRUE;
 }
 
 static void