2003-05-05 Dietmar Maurer <dietmar@ximian.com>
[mono.git] / mono / mini / mini.c
index b6086c39d50744cda733b4e83e80defe3edd3bd3..f8d812630e388ebeab7b1a6435c6a01aff1f9549 100644 (file)
 #include <mono/metadata/profiler-private.h>
 #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 "mini.h"
 #include <string.h>
 #include <ctype.h>
 #include "inssel.h"
-#include "debug.h"
 
 #include "jit-icalls.c"
 
 #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;
@@ -74,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;
 
@@ -152,7 +159,6 @@ mono_method_blittable (MonoMethod *method)
 }
 #endif
 
-#if 0
 /* debug function */
 static void
 print_method_from_ip (void *ip)
@@ -170,7 +176,6 @@ print_method_from_ip (void *ip)
        g_free (method);
 
 }
-#endif
 
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
@@ -256,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); \
@@ -477,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 *
@@ -611,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;
@@ -619,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;
 }
 
 
@@ -935,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},
 };
 
@@ -1269,35 +1282,17 @@ mono_get_domainvar (MonoCompile *cfg)
        return cfg->domainvar;
 }
 
-static void
-realloc_var_info (MonoCompile *cfg, int count)
-{
-       gpointer data;
-       int num = cfg->varinfo_count;
-
-       g_assert (count > num);
-
-       cfg->varinfo_count = count;
-
-       data = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * cfg->varinfo_count);
-       if (num)
-               memcpy (data, cfg->varinfo, sizeof (MonoInst*) * num);
-       cfg->varinfo = (MonoInst **)data;
-
-       data = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoMethodVar*) * cfg->varinfo_count);
-       if (num)
-               memcpy (data, cfg->vars, sizeof (MonoMethodVar*) * num);
-       cfg->vars = (MonoMethodVar **)data;             
-}
-
 MonoInst*
 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
 {
        MonoInst *inst;
        int num = cfg->num_varinfo;
 
-       if ((num + 1) >= cfg->varinfo_count)
-               realloc_var_info (cfg, cfg->varinfo_count + 16);
+       if ((num + 1) >= cfg->varinfo_count) {
+               cfg->varinfo_count = (cfg->varinfo_count + 2) * 2;
+               cfg->varinfo = (MonoInst **)g_realloc (cfg->varinfo, sizeof (MonoInst*) * cfg->varinfo_count);
+               cfg->vars = (MonoMethodVar **)g_realloc (cfg->vars, sizeof (MonoMethodVar*) * cfg->varinfo_count);      
+       }
 
        mono_jit_stats.allocate_var++;
 
@@ -1906,6 +1901,7 @@ mono_method_check_inlining (MonoMethod *method)
        if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
            (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
+           (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
            (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
            (method->klass->marshalbyref) ||
            !header || header->num_clauses ||
@@ -1929,6 +1925,46 @@ mono_method_check_inlining (MonoMethod *method)
        return FALSE;
 }
 
+static MonoInst*
+mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+       int pc, op;
+       MonoInst *ins;
+
+       if (cmethod->klass == mono_defaults.string_class) {
+               if (cmethod->name [0] != 'g' || strcmp (cmethod->name, "get_Chars"))
+                       return NULL;
+               op = OP_GETCHR;
+       } else if (cmethod->klass == mono_defaults.math_class) {
+               if (strcmp (cmethod->name, "Sin") == 0)
+                       op = OP_SIN;
+               else if (strcmp (cmethod->name, "Cos") == 0)
+                       op = OP_COS;
+               else if (strcmp (cmethod->name, "Tan") == 0)
+                       op = OP_TAN;
+               else if (strcmp (cmethod->name, "Atan") == 0)
+                       op = OP_ATAN;
+               else if (strcmp (cmethod->name, "Sqrt") == 0)
+                       op = OP_SQRT;
+               else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8)
+                       op = OP_ABS;
+               else
+                       return NULL;
+       } else {
+               return NULL;
+       }
+       pc = fsig->param_count + fsig->hasthis;
+       MONO_INST_NEW (cfg, ins, op);
+
+       if (pc > 0) {
+               ins->inst_i0 = args [0];
+               if (pc > 1)
+                       ins->inst_i1 = args [1];
+       }
+
+       return ins;
+}
+
 static void
 mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
 {
@@ -1957,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;
@@ -1972,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 
@@ -2011,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;
@@ -2031,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;
@@ -2048,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 */
@@ -2068,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;
@@ -2122,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_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;
@@ -2142,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)
@@ -2163,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;
@@ -2461,15 +2565,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_CALLVIRT: {
                        MonoInst *addr = NULL;
                        MonoMethodSignature *fsig = NULL;
-                       MonoMethodHeader *cheader;
-                       int mop, temp, array_rank = 0;
+                       int temp, array_rank = 0;
                        int virtual = *ip == CEE_CALLVIRT;
 
                        token = read32 (ip + 1);
 
                        if (*ip == CEE_CALLI) {
                                cmethod = NULL;
-                               cheader = NULL;
                                CHECK_STACK (1);
                                --sp;
                                addr = *sp;
@@ -2482,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);
@@ -2520,17 +2621,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        sp -= n;
 
-                       if (cmethod && (mop = mono_find_method_opcode (cmethod))) {
-
-                               MONO_INST_NEW (cfg, ins, mop);
+                       if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
                                ins->cil_code = ip;
-                               g_assert (n <= 2);
-
-                               if (fsig->param_count > 0) {
-                                       ins->inst_i0 = sp [0];
-                                       if (fsig->param_count > 1)
-                                               ins->inst_i1 = sp [1];
-                               }
 
                                if (MONO_TYPE_IS_VOID (fsig->ret)) {
                                        MONO_ADD_INS (bblock, ins);
@@ -2544,78 +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;
-                               
-                               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);
+                           mono_method_check_inlining (cmethod) &&
+                           !g_list_find (dont_inline, cmethod)) {
+                               int costs;
+                               MonoBasicBlock *ebblock;
                                
-                               /* 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;
                                        }
-                                       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)); }
+                                       start_new_bblock = 1;
 
                                        inline_costs += costs;
                                        break;
-                               } else {
-
-                                       if (cfg->verbose_level > 2)
-                                               g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
-
                                }
                        }
                        
@@ -3027,12 +3072,15 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                klass = mono_method_get_wrapper_data (method, token);
                        else
                                klass = mono_class_get (image, token);
+
                        mono_class_init (klass);
                        n = mono_class_value_size (klass, NULL);
                        ins = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
                        NEW_TEMPLOADA (cfg, iargs [0], ins->inst_c0);
                        iargs [1] = *sp;
                        NEW_ICONST (cfg, iargs [2], n);
+                       iargs [2]->cil_code = ip;
+
                        mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
                        NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
                        ++sp;
@@ -3048,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);
@@ -3113,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);
@@ -3139,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);
@@ -3148,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:
@@ -3293,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);
@@ -3406,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)
@@ -3477,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:
@@ -3502,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);
@@ -3541,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];
 
@@ -3601,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 {
@@ -3619,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);
@@ -3642,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);
@@ -3891,9 +4005,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = read32 (ip + 2);
                                if (method->wrapper_type != MONO_WRAPPER_NONE)
                                        cmethod = mono_method_get_wrapper_data (method, n);
-                               else
+                               else {
                                        cmethod = mono_get_method (image, n, NULL);
-                               
+
+                                       /*
+                                        * We can't do this in mono_ldftn, since it is used in
+                                        * the synchronized wrapper, leading to an infinite loop.
+                                        */
+                                       if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)
+                                               cmethod = mono_marshal_get_synchronized_wrapper (cmethod);
+                               }
+
                                mono_class_init (cmethod->klass);
                                handle_loaded_temps (cfg, bblock, stack_start, sp);
 
@@ -4203,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:
@@ -4215,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;
 }
 
@@ -4368,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] = 
@@ -4481,27 +4614,6 @@ create_helper_signature (void)
        helper_sig_memset->pinvoke = 1;
 }
 
-static GHashTable *method_opcode_hash = NULL;
-
-static void
-mono_register_method_opcode (MonoMethod *method, int opcode)
-{
-
-       if (!method_opcode_hash)
-               method_opcode_hash = g_hash_table_new (NULL, NULL);
-
-       g_hash_table_insert (method_opcode_hash, method, (gpointer)opcode);
-
-}
-
-int
-mono_find_method_opcode (MonoMethod *method)
-{
-       g_assert (method_opcode_hash);
-
-       return (int)g_hash_table_lookup (method_opcode_hash, method);
-}
-
 static GHashTable *jit_icall_hash_name = NULL;
 static GHashTable *jit_icall_hash_addr = NULL;
 
@@ -4776,6 +4888,8 @@ mono_destroy_compile (MonoCompile *cfg)
        mono_mempool_destroy (cfg->mempool);
        g_list_free (cfg->ldstr_list);
 
+       g_free (cfg->varinfo);
+       g_free (cfg->vars);
        g_free (cfg);
 }
 
@@ -4997,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];
 
@@ -5524,6 +5642,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        int dfn = 0, i, code_size_ratio;
 
        mono_jit_stats.methods_compiled++;
+       if (mono_jit_profile)
+               mono_profiler_method_jit (method);
 
        cfg = g_new0 (MonoCompile, 1);
        cfg->method = method;
@@ -5541,8 +5661,10 @@ 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);
                return NULL;
        }
 
@@ -5627,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 ? */
@@ -5694,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;
-
                }
        }
 
@@ -5720,6 +5844,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        }
        mono_jit_stats.native_code_size += cfg->code_len;
 
+       if (mono_jit_profile)
+               mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
+
        return cfg;
 }
 
@@ -5732,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;
@@ -5955,35 +6082,12 @@ mono_jit_create_remoting_trampoline (MonoMethod *method)
        return addr;
 }
 
-static MonoMethod *
-mono_find_unique_method (MonoClass *klass, const char *name, int param_count)
-{
-       MonoMethod *rval = NULL;
-       int i;
-
-       mono_class_init (klass);
-       for (i = 0; i < klass->method.count; ++i) {
-               if (!strcmp (name, klass->methods [i]->name) &&
-                   klass->methods [i]->signature->param_count == param_count) {
-                       g_assert (rval == NULL);
-                       rval = klass->methods [i];
-                       g_assert (!(rval->flags & METHOD_ATTRIBUTE_VIRTUAL));
-               }
-       }
-
-       return rval;
-}
-
-
 static CRITICAL_SECTION ms;
 
 MonoDomain *
 mini_init (const char *filename)
 {
        MonoDomain *domain;
-       MonoMethod *m;
-       MonoMethodDesc *desc;
        
        metadata_section = &ms;
        InitializeCriticalSection (metadata_section);
@@ -6031,22 +6135,6 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_arch_get_throw_exception_by_name (), "mono_arch_throw_exception_by_name", 
                                 helper_sig_void_ptr, TRUE);
 
-
-       g_assert ((m = mono_find_unique_method (mono_defaults.math_class, "Sin", 1)));
-       mono_register_method_opcode (m, OP_SIN);
-       g_assert ((m = mono_find_unique_method (mono_defaults.math_class, "Cos", 1)));
-       mono_register_method_opcode (m, OP_COS);
-       g_assert ((m = mono_find_unique_method (mono_defaults.math_class, "Tan", 1)));
-       mono_register_method_opcode (m, OP_TAN);
-       g_assert ((m = mono_find_unique_method (mono_defaults.math_class, "Atan", 1)));
-       mono_register_method_opcode (m, OP_ATAN);
-       g_assert ((m = mono_find_unique_method (mono_defaults.math_class, "Sqrt", 1)));
-       mono_register_method_opcode (m, OP_SQRT);
-       
-       g_assert ((desc = mono_method_desc_new ("System.Math:Abs(double)", 0)));
-       g_assert ((m = mono_method_desc_search_in_image (desc, mono_defaults.corlib)));
-       mono_register_method_opcode (m, OP_ABS);
-
        /* 
         * NOTE, NOTE, NOTE, NOTE:
         * when adding emulation for some opcodes, remember to also add a dummy
@@ -6083,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);
@@ -6149,14 +6238,15 @@ void
 mini_cleanup (MonoDomain *domain)
 {
        /* 
-        * mono_runtime_cleanup() needs to be called early since
-        * it needs the execution engine still fully working (it will
-        * wait for other threads to finish).
+        * mono_runtime_cleanup() and mono_domain_finalize () need to
+        * be called early since they need the execution engine still
+        * fully working (mono_domain_finalize may invoke managed finalizers
+        * and mono_runtime_cleanup will wait for other threads to finish).
         */
-       mono_runtime_cleanup (domain);
-
        mono_domain_finalize (domain);
 
+       mono_runtime_cleanup (domain);
+
        mono_profiler_shutdown ();
 
        mono_debug_cleanup ();
@@ -6171,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;