2003-05-05 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / mini / mini.c
index 66610b19a5bc2555c1948fc4f68ec57e5fe67ede..f8d812630e388ebeab7b1a6435c6a01aff1f9549 100644 (file)
 
 #define MONO_CHECK_THIS(ins) (cfg->method->signature->hasthis && (ins)->ssa_op == MONO_SSA_LOAD && (ins)->inst_left->inst_c0 == 0)
 
+gboolean  mono_arch_handle_exception (struct sigcontext *ctx, gpointer obj, gboolean test_only);
 static gpointer mono_jit_compile_method (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);
 
+static int mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
+                  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_long_long_long = NULL;
@@ -75,6 +80,7 @@ static MonoMethodSignature *helper_sig_ulong_double = NULL;
 static MonoMethodSignature *helper_sig_long_double = NULL;
 static MonoMethodSignature *helper_sig_uint_double = NULL;
 static MonoMethodSignature *helper_sig_int_double = NULL;
+static MonoMethodSignature *helper_sig_stelem_ref = NULL;
 
 static guint32 default_opt = MONO_OPT_PEEPHOLE;
 
@@ -255,7 +261,7 @@ print_method_from_ip (void *ip)
        } while (0)
 
 #define NEW_DOMAINCONST(cfg,dest) do { \
-               if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) { \
+               if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) { \
                        NEW_TEMPLOAD (cfg, dest, mono_get_domainvar (cfg)->inst_c0); \
                } else { \
                        NEW_PCONST (cfg, dest, (cfg)->domain); \
@@ -476,6 +482,13 @@ print_method_from_ip (void *ip)
                (dest)->klass = (k);    \
        } while (0)
 
+#define NEW_GROUP(cfg,dest,el1,el2) do {       \
+               (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
+               (dest)->opcode = OP_GROUP;      \
+               (dest)->inst_left = (el1);      \
+               (dest)->inst_right = (el2);     \
+       } while (0)
+
 static GHashTable *coverage_hash = NULL;
 
 MonoCoverageInfo *
@@ -610,7 +623,7 @@ mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
        return -1;
 }
 
-static MonoBasicBlock *
+static GList*
 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
 {
        MonoMethod *method = cfg->method;
@@ -618,19 +631,20 @@ mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *targe
        MonoExceptionClause *clause;
        MonoBasicBlock *handler;
        int i;
+       GList *res = NULL;
 
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
                if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
                    (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
-                       if (clause->flags & type) {
+                       if (clause->flags == type) {
                                handler = g_hash_table_lookup (cfg->bb_hash, header->code + clause->handler_offset);
                                g_assert (handler);
-                               return handler;
+                               res = g_list_append (res, handler);
                        }
                }
        }
-       return NULL;
+       return res;
 }
 
 
@@ -934,10 +948,10 @@ bin_comp_table [STACK_MAX] [STACK_MAX] = {
        {0},
        {0, 1, 0, 1, 0, 0, 4, 0},
        {0, 0, 1, 0, 0, 0, 0, 0},
-       {0, 1, 0, 1, 0, 2, 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, 0, 0, 0, 3, 0},
+       {0, 4, 0, 4, 0, 0, 3, 0},
        {0, 0, 0, 0, 0, 0, 0, 0},
 };
 
@@ -1979,7 +1993,7 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
                if (sp [0]->opcode == OP_ICONST) {
                        *args++ = sp [0];
                } else {
-                       temp = mono_compile_create_var (cfg, type_from_stack_type (*sp), OP_LOCAL);
+                       temp = mono_compile_create_var (cfg, sig->params [i], OP_LOCAL);
                        *args++ = temp;
                        NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
                        store->cil_code = sp [0]->cil_code;
@@ -1994,6 +2008,71 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
        }
 }
 
+static int
+inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoBasicBlock *bblock, MonoInst **sp,
+               guchar *ip, guint real_offset, GList *dont_inline, MonoBasicBlock **last_b)
+{
+       MonoInst *ins, *rvar = NULL;
+       MonoMethodHeader *cheader;
+       MonoBasicBlock *ebblock, *sbblock;
+       int i, costs, new_locals_offset;
+                               
+       if (cfg->verbose_level > 2)
+               g_print ("INLINE START %p %s\n", cmethod,  mono_method_full_name (cmethod, TRUE));
+
+       cheader = ((MonoMethodNormal *)cmethod)->header;
+
+       if (!cmethod->inline_info) {
+               mono_jit_stats.inlineable_methods++;
+               cmethod->inline_info = 1;
+       }
+       /* allocate space to store the return value */
+       if (!MONO_TYPE_IS_VOID (fsig->ret)) 
+               rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
+
+       /* allocate local variables */
+       new_locals_offset = cfg->num_varinfo;
+       for (i = 0; i < cheader->num_locals; ++i)
+               mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
+       
+       /* allocate starte and end blocks */
+       sbblock = NEW_BBLOCK (cfg);
+       sbblock->block_num = cfg->num_bblocks++;
+       sbblock->real_offset = real_offset;
+
+       ebblock = NEW_BBLOCK (cfg);
+       ebblock->block_num = cfg->num_bblocks++;
+       ebblock->real_offset = real_offset;
+       
+       costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
+       
+       if (costs >= 0 && costs < 60) {
+               if (cfg->verbose_level > 2)
+                       g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
+               
+               mono_jit_stats.inlined_methods++;
+
+               /* always add some code to avoid block split failures */
+               MONO_INST_NEW (cfg, ins, CEE_NOP);
+               MONO_ADD_INS (bblock, ins);
+               ins->cil_code = ip;
+
+               bblock->next_bb = sbblock;
+               link_bblock (cfg, bblock, sbblock);
+
+               if (rvar) {
+                       NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
+                       *sp++ = ins;
+               }
+               *last_b = ebblock;
+               return costs + 1;
+       } else {
+               if (cfg->verbose_level > 2)
+                       g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
+       }
+       return 0;
+}
+
 /*
  * Some of these comments may well be out-of-date.
  * Design decisions: we do a single pass over the IL code (and we do bblock 
@@ -2033,7 +2112,7 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
 static int
 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
                   int locals_offset, MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
-                  guint inline_offset)
+                  guint inline_offset, gboolean is_virtual_call)
 {
        MonoInst *zero_int32, *zero_int64, *zero_ptr, *zero_obj, *zero_r8;
        MonoInst *ins, **sp, **stack_start;
@@ -2053,6 +2132,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        int i, n, start_new_bblock, align;
        int num_calls = 0, inline_costs = 0;
        int *filter_lengths = NULL;
+       int breakpoint_id = 0;
        guint real_offset;
 
        image = method->klass->image;
@@ -2070,6 +2150,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                bbhash = g_hash_table_new (g_direct_hash, NULL);
        }
 
+       dont_inline = g_list_prepend (dont_inline, method);
        if (cfg->method == method) {
 
                /* ENTRY BLOCK */
@@ -2090,7 +2171,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        arg_array [i] = cfg->varinfo [i];
 
                if (mono_compile_aot) 
-                       cfg->opt |= MONO_OPT_SAHRED;
+                       cfg->opt |= MONO_OPT_SHARED;
 
                if (header->num_clauses) {
                        int size = sizeof (int) * header->num_clauses;
@@ -2144,13 +2225,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        ADD_BBLOCK (cfg, bbhash, bblock);
 
        if (cfg->method == method) {
-               if (mono_debugger_method_has_breakpoint (method, FALSE)) {
+               breakpoint_id = mono_debugger_method_has_breakpoint (method);
+               if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
                        MONO_INST_NEW (cfg, ins, CEE_BREAK);
                        MONO_ADD_INS (bblock, ins);
                }
        }
        
-       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SAHRED)))) {
+       if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED)))) {
                /* we use a separate basic block for the initialization code */
                cfg->bb_init = init_localsbb = NEW_BBLOCK (cfg);
                init_localsbb->real_offset = real_offset;
@@ -2164,7 +2246,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                link_bblock (cfg, start_bblock, bblock);
        }
 
-       mono_debug_init_method (cfg, bblock);
+       mono_debug_init_method (cfg, bblock, breakpoint_id);
 
        param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * (sig->hasthis + sig->param_count));
        if (sig->hasthis)
@@ -2185,7 +2267,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        zero_r8->inst_p0 = &r8_0;
 
        /* add a check for this != NULL to inlined methods */
-       if (cfg->method != method && sig->hasthis) {
+       if (is_virtual_call) {
                MONO_INST_NEW (cfg, ins, OP_CHECK_THIS);
                NEW_ARGLOAD (cfg, ins->inst_left, 0);
                ins->cil_code = ip;
@@ -2483,7 +2565,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_CALLVIRT: {
                        MonoInst *addr = NULL;
                        MonoMethodSignature *fsig = NULL;
-                       MonoMethodHeader *cheader;
                        int temp, array_rank = 0;
                        int virtual = *ip == CEE_CALLVIRT;
 
@@ -2491,7 +2572,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (*ip == CEE_CALLI) {
                                cmethod = NULL;
-                               cheader = NULL;
                                CHECK_STACK (1);
                                --sp;
                                addr = *sp;
@@ -2504,7 +2584,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        } else {
                                cmethod = mono_get_method (image, token, NULL);
-                               cheader = ((MonoMethodNormal *)cmethod)->header;
 
                                if (!cmethod->klass->inited)
                                        mono_class_init (cmethod->klass);
@@ -2557,83 +2636,31 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
-                       if ((cfg->opt & MONO_OPT_INLINE) && 
+                       if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
                            (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
-                           cmethod && cheader && mono_method_check_inlining (cmethod) &&
-                           method != cmethod && !g_list_find (dont_inline, cmethod)) {
-                               MonoInst *rvar = NULL;
-                               MonoBasicBlock *ebblock, *sbblock;
-                               int costs, new_locals_offset;
+                           mono_method_check_inlining (cmethod) &&
+                           !g_list_find (dont_inline, cmethod)) {
+                               int costs;
+                               MonoBasicBlock *ebblock;
                                
-                               if (cfg->verbose_level > 2)
-                                       g_print ("INLINE START %p %s\n", cmethod,  mono_method_full_name (cmethod, TRUE));
-
-                               if (!cmethod->inline_info) {
-                                       mono_jit_stats.inlineable_methods++;
-                                       cmethod->inline_info = 1;
-                               }
-                               /* allocate space to store the return value */
-                               if (!MONO_TYPE_IS_VOID (fsig->ret)) 
-                                       rvar =  mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
-
-                               /* allocate local variables */
-                               new_locals_offset = cfg->num_varinfo;
-                               for (i = 0; i < cheader->num_locals; ++i)
-                                       mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
-                               
-                               /* allocate starte and end blocks */
-                               sbblock = NEW_BBLOCK (cfg);
-                               sbblock->block_num = cfg->num_bblocks++;
-                               sbblock->real_offset = real_offset;
-
-                               ebblock = NEW_BBLOCK (cfg);
-                               ebblock->block_num = cfg->num_bblocks++;
-                               ebblock->real_offset = real_offset;
-                               
-                               dont_inline = g_list_prepend (dont_inline, method);
-                               costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, new_locals_offset, rvar, dont_inline, sp, real_offset);
-                               dont_inline = g_list_remove (dont_inline, method);
-                               
-                               if (costs >= 0 && costs < 60) {
-
-                                       mono_jit_stats.inlined_methods++;
-
-                                       /* always add some code to avoid block split failures */
-                                       MONO_INST_NEW (cfg, ins, CEE_NOP);
-                                       MONO_ADD_INS (bblock, ins);
-                                       ins->cil_code = ip;
-
+                               if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
                                        ip += 5;
                                        real_offset += 5;
 
-                                       bblock->next_bb = sbblock;
-                                       link_bblock (cfg, bblock, sbblock);
-
                                        GET_BBLOCK (cfg, bbhash, bblock, ip);
                                        ebblock->next_bb = bblock;
                                        link_bblock (cfg, ebblock, bblock);
+                                       if (!MONO_TYPE_IS_VOID (fsig->ret))
+                                               sp++;
 
-                                       if (rvar) {
-                                               NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
-                                               *sp++ = ins;
-                                       }
                                        if (sp != stack_start) {
                                                handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
                                                sp = stack_start;
                                        }
                                        start_new_bblock = 1;
-                                       if (cfg->verbose_level > 2)
-                                               g_print ("INLINE END %s\n", mono_method_full_name (cmethod, TRUE));
-                                       
-                                       // { static int c = 0; printf ("ICOUNT %d %d %s\n", c++, costs, mono_method_full_name (cmethod, TRUE)); }
 
                                        inline_costs += costs;
                                        break;
-                               } else {
-
-                                       if (cfg->verbose_level > 2)
-                                               g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
-
                                }
                        }
                        
@@ -3069,7 +3096,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
                        }
 
-                       if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) {
+                       if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
                                int temp;
                                MonoInst *iargs [3];
                                NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
@@ -3134,8 +3161,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                }
 
-                               /* now call the actual ctor */
-                               mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
+                               /* FIXME: currently disabled because of bug #42175 */
+                               if (0 && (cfg->opt & MONO_OPT_INLINE) && cmethod &&
+                                   mono_method_check_inlining (cmethod) &&
+                                   !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
+                                   !g_list_find (dont_inline, cmethod)) {
+                                       int costs;
+                                       MonoBasicBlock *ebblock;
+                                       if ((costs = inline_method (cfg, cmethod, cmethod->signature, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
+
+                                               GET_BBLOCK (cfg, bbhash, bblock, ip + 5);
+                                               ebblock->next_bb = bblock;
+                                               link_bblock (cfg, ebblock, bblock);
+
+                                               /*if (sp != stack_start) {
+                                                       handle_stack_args (cfg, ebblock, stack_start, sp - stack_start);
+                                                       sp = stack_start;
+                                               }
+                                               start_new_bblock = 1;*/
+
+                                               inline_costs += costs;
+                                               /*g_print ("inlined newobj for %s\n", cmethod->klass->name);*/
+                                       }
+                               } else {
+                                       /* now call the actual ctor */
+                                       mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
+                               }
                        }
 
                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -3160,7 +3211,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                case CEE_UNBOX: {
                        MonoInst *add, *vtoffset;
-                       /* FIXME: need to check class: move to inssel.brg? */
+
                        CHECK_STACK (1);
                        --sp;
                        token = read32 (ip + 1);
@@ -3169,14 +3220,23 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else 
                                klass = mono_class_get (image, token);
                        mono_class_init (klass);
+
+
+                       MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
+                       ins->type = STACK_OBJ;
+                       ins->inst_left = *sp;
+                       ins->klass = klass;
+                       ins->inst_newa_class = klass;
+                       ins->cil_code = ip;
+
                        MONO_INST_NEW (cfg, add, CEE_ADD);
                        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
-                       add->inst_left = *sp;
+                       add->inst_left = ins;
                        add->inst_right = vtoffset;
                        add->type = STACK_MP;
                        *sp++ = add;
                        ip += 5;
-                       inline_costs += 1;
+                       inline_costs += 2;
                        break;
                }
                case CEE_CASTCLASS:
@@ -3314,7 +3374,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                                
-                       if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
+                       if (((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)) {
                                int temp;
                                MonoInst *iargs [2];
                                g_assert (field->parent);
@@ -3427,7 +3487,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
 
                        /* allocate the domainvar - becaus this is used in decompose_foreach */
-                       if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)
+                       if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)
                                mono_get_domainvar (cfg);
                        
                        if (method->wrapper_type != MONO_WRAPPER_NONE)
@@ -3498,8 +3558,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_STELEM_I4:
                case CEE_STELEM_I8:
                case CEE_STELEM_R4:
-               case CEE_STELEM_R8:
-               case CEE_STELEM_REF: {
+               case CEE_STELEM_R8: {
                        MonoInst *load;
                        /*
                         * translate to:
@@ -3523,6 +3582,35 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        cfg->disable_ssa = TRUE;
                        break;
                }
+               case CEE_STELEM_REF: {
+                       MonoInst *iargs [3];
+
+                       CHECK_STACK (3);
+                       sp -= 3;
+
+                       handle_loaded_temps (cfg, bblock, stack_start, sp);
+
+                       iargs [2] = sp [2];
+                       iargs [1] = sp [1];
+                       iargs [0] = sp [0];
+                       
+                       mono_emit_jit_icall (cfg, bblock, helper_stelem_ref, iargs, ip);
+
+                       /*
+                       MonoInst *group;
+                       NEW_GROUP (cfg, group, sp [0], sp [1]);
+                       MONO_INST_NEW (cfg, ins, CEE_STELEM_REF);
+                       ins->cil_code = ip;
+                       ins->inst_left = group;
+                       ins->inst_right = sp [2];
+                       MONO_ADD_INS (bblock, ins);
+                       */
+
+                       ++ip;
+                       inline_costs += 1;
+                       cfg->disable_ssa = TRUE;
+                       break;
+               }
                case CEE_CKFINITE: {
                        MonoInst *store, *temp;
                        CHECK_STACK (1);
@@ -3562,7 +3650,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        handle = mono_ldtoken (image, n, &handle_class);
                        mono_class_init (handle_class);
 
-                       if (((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot)) {
+                       if (((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot)) {
                                int temp;
                                MonoInst *res, *store, *addr, *vtvar, *iargs [2];
 
@@ -3622,7 +3710,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        start_new_bblock = 1;
                        break;
                case CEE_LEAVE:
-               case CEE_LEAVE_S:
+               case CEE_LEAVE_S: {
+                       GList *handlers;
                        if (*ip == CEE_LEAVE) {
                                target = ip + 5 + (gint32)read32(ip + 1);
                        } else {
@@ -3640,15 +3729,19 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        /* fixme: call fault handler ? */
 
-                       if ((tblock = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
-                               link_bblock (cfg, bblock, tblock);
-                               MONO_INST_NEW (cfg, ins, OP_HANDLER);
-                               ins->cil_code = ip;
-                               ins->inst_target_bb = tblock;
-                               MONO_ADD_INS (bblock, ins);
+                       if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
+                               GList *tmp;
+                               for (tmp = handlers; tmp; tmp = tmp->next) {
+                                       tblock = tmp->data;
+                                       link_bblock (cfg, bblock, tblock);
+                                       MONO_INST_NEW (cfg, ins, OP_HANDLER);
+                                       ins->cil_code = ip;
+                                       ins->inst_target_bb = tblock;
+                                       MONO_ADD_INS (bblock, ins);
+                               }
+                               g_list_free (handlers);
                        } 
 
-
                        MONO_INST_NEW (cfg, ins, CEE_BR);
                        ins->cil_code = ip;
                        MONO_ADD_INS (bblock, ins);
@@ -3663,8 +3756,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                ip += 2;
 
-
                        break;
+               }
                case CEE_STIND_I:
                        CHECK_STACK (2);
                        MONO_INST_NEW (cfg, ins, *ip);
@@ -4232,11 +4325,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                g_hash_table_destroy (bbhash);
        }
 
+       dont_inline = g_list_remove (dont_inline, method);
        return inline_costs;
 
  inline_failure:
        if (cfg->method != method) 
                g_hash_table_destroy (bbhash);
+       dont_inline = g_list_remove (dont_inline, method);
        return -1;
 
  unverified:
@@ -4244,6 +4339,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                g_hash_table_destroy (bbhash);
        g_error ("Invalid IL code at IL%04x in %s: %s\n", 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);
        return -1;
 }
 
@@ -4397,6 +4493,14 @@ create_helper_signature (void)
        helper_sig_domain_get->ret = &mono_defaults.int_class->byval_arg;
        helper_sig_domain_get->pinvoke = 1;
 
+       /* void* stelem_ref (MonoArray *, int index, MonoObject *) */
+       helper_sig_stelem_ref = mono_metadata_signature_alloc (mono_defaults.corlib, 3);
+       helper_sig_stelem_ref->params [0] = &mono_defaults.array_class->byval_arg;
+       helper_sig_stelem_ref->params [1] = &mono_defaults.int32_class->byval_arg;
+       helper_sig_stelem_ref->params [2] = &mono_defaults.object_class->byval_arg;
+       helper_sig_stelem_ref->ret = &mono_defaults.void_class->byval_arg;
+       helper_sig_stelem_ref->pinvoke = 1;
+
        /* long amethod (long, long) */
        helper_sig_long_long_long = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
        helper_sig_long_long_long->params [0] = helper_sig_long_long_long->params [1] = 
@@ -5007,6 +5111,10 @@ optimize_branches (MonoCompile *cfg) {
                /* 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 (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
@@ -5553,7 +5661,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        if (cfg->verbose_level > 2)
                g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
 
-       if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0)) < 0) {
+       if ((i = mono_method_to_ir (cfg, method, NULL, NULL, cfg->locals_start, NULL, NULL, NULL, 0, FALSE)) < 0) {
                mono_destroy_compile (cfg);
                if (mono_jit_profile)
                        mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
@@ -5641,7 +5749,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        
        decompose_pass (cfg);
 
-       if (cfg->opt & MONO_OPT_LINEARS) {
+       /* FIXME: disabled with exception clauses: bug #42136 */
+       if ((!header->num_clauses) && (cfg->opt & MONO_OPT_LINEARS)) {
                GList *vars, *regs;
 
                /* fixme: maybe we can avoid to compute livenesss here if already computed ? */
@@ -5708,13 +5817,14 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
                        tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset);
                        g_assert (tblock);
                        ei->try_start = cfg->native_code + tblock->native_offset;
+                       g_assert (tblock->native_offset);
                        tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->try_offset + ec->try_len);
                        g_assert (tblock);
                        ei->try_end = cfg->native_code + tblock->native_offset;
+                       g_assert (tblock->native_offset);
                        tblock = g_hash_table_lookup (cfg->bb_hash, ip + ec->handler_offset);
                        g_assert (tblock);
                        ei->handler_start = cfg->native_code + tblock->native_offset;
-
                }
        }
 
@@ -5749,7 +5859,7 @@ mono_jit_compile_method (MonoMethod *method)
        GHashTable *jit_code_hash;
        gpointer code;
 
-       if (default_opt & MONO_OPT_SAHRED)
+       if (default_opt & MONO_OPT_SHARED)
                target_domain = mono_root_domain;
        else 
                target_domain = domain;
@@ -6061,6 +6171,7 @@ mini_init (const char *filename)
        mono_register_jit_icall (helper_memcpy, "helper_memcpy", helper_sig_memcpy, FALSE);
        mono_register_jit_icall (helper_memset, "helper_memset", helper_sig_memset, FALSE);
        mono_register_jit_icall (helper_initobj, "helper_initobj", helper_sig_initobj, FALSE);
+       mono_register_jit_icall (helper_stelem_ref, "helper_stelem_ref", helper_sig_stelem_ref, FALSE);
        mono_register_jit_icall (mono_object_new, "mono_object_new", helper_sig_object_new, FALSE);
        mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
        mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
@@ -6150,7 +6261,7 @@ mini_cleanup (MonoDomain *domain)
 }
 
 void
-mini_set_defaults (int verbose_level, guint32 opts)
+mono_set_defaults (int verbose_level, guint32 opts)
 {
        mini_verbose = verbose_level;
        default_opt = opts;