Wed Aug 20 13:04:53 CEST 2003 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index 6fc7e321809239fd87ea86dcebf55adaa04374df..fec74a8337a9c1b90b13616b8e8f52e4b103baf3 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_IS_COND_BRANCH(op) ((op >= CEE_BEQ && op <= CEE_BLT_UN) || (op >= OP_LBEQ && op <= OP_LBLT_UN) || (op >= OP_FBEQ && op <= OP_FBLT_UN))
+
 #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;
 static MonoMethodSignature *helper_sig_long_long_int = NULL;
 static MonoMethodSignature *helper_sig_newarr = NULL;
+static MonoMethodSignature *helper_sig_newarr_specific = NULL;
 static MonoMethodSignature *helper_sig_ldstr = NULL;
 static MonoMethodSignature *helper_sig_domain_get = NULL;
 static MonoMethodSignature *helper_sig_object_new = NULL;
+static MonoMethodSignature *helper_sig_object_new_specific = NULL;
 static MonoMethodSignature *helper_sig_compile = NULL;
 static MonoMethodSignature *helper_sig_compile_virt = NULL;
 static MonoMethodSignature *helper_sig_obj_ptr = NULL;
@@ -67,6 +77,7 @@ static MonoMethodSignature *helper_sig_void_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_void_ptr_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_ptr_ptr_ptr = NULL;
 static MonoMethodSignature *helper_sig_ptr_obj = NULL;
+static MonoMethodSignature *helper_sig_ptr_int = NULL;
 static MonoMethodSignature *helper_sig_initobj = NULL;
 static MonoMethodSignature *helper_sig_memcpy = NULL;
 static MonoMethodSignature *helper_sig_memset = NULL;
@@ -74,6 +85,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;
 
@@ -81,11 +93,6 @@ guint32 mono_jit_tls_id = 0;
 gboolean mono_jit_trace_calls = FALSE;
 gboolean mono_break_on_exc = FALSE;
 gboolean mono_compile_aot = FALSE;
-gboolean mono_trace_coverage = FALSE;
-gboolean mono_jit_profile = FALSE;
-MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
-
-CRITICAL_SECTION *metadata_section = NULL;
 
 static int mini_verbose = 0;
 
@@ -110,6 +117,7 @@ mono_type_blittable (MonoType *type)
        case MONO_TYPE_R8:
        case MONO_TYPE_I:
        case MONO_TYPE_U:
+       case MONO_TYPE_OBJECT:
                return TRUE;
        case MONO_TYPE_VALUETYPE:
        case MONO_TYPE_CLASS:
@@ -151,25 +159,32 @@ mono_method_blittable (MonoMethod *method)
 }
 #endif
 
-#if 0
 /* debug function */
-static void
+G_GNUC_UNUSED static void
 print_method_from_ip (void *ip)
 {
        MonoJitInfo *ji;
        char *method;
+       char *source;
+       MonoDomain *domain = mono_domain_get ();
        
-       ji = mono_jit_info_table_find (mono_domain_get (), ip);
+       ji = mono_jit_info_table_find (domain, ip);
        if (!ji) {
                g_print ("No method at %p\n", ip);
                return;
        }
        method = mono_method_full_name (ji->method, TRUE);
-       g_print ("IP at offset 0x%x of method %s (%p %p)\n", (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
+       source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
+
+       g_print ("IP %p at offset 0x%x of method %s (%p %p)\n", ip, (char*)ip - (char*)ji->code_start, method, ji->code_start, (char*)ji->code_start + ji->code_size);
+
+       if (source)
+               g_print ("%s\n", source);
+
+       g_free (source);
        g_free (method);
 
 }
-#endif
 
 #define MONO_INIT_VARINFO(vi,id) do { \
        (vi)->range.first_use.pos.bid = 0xffff; \
@@ -255,7 +270,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,34 +491,13 @@ print_method_from_ip (void *ip)
                (dest)->klass = (k);    \
        } while (0)
 
-static GHashTable *coverage_hash = NULL;
-
-MonoCoverageInfo *
-mono_allocate_coverage_info (MonoMethod *method, int size)
-{
-       MonoCoverageInfo *res;
-
-       if (!coverage_hash)
-               coverage_hash = g_hash_table_new (NULL, NULL);
-
-       res = g_malloc0 (sizeof (MonoCoverageInfo) + sizeof (int) * size * 2);
-
-       res->entries = size;
-
-       g_hash_table_insert (coverage_hash, method, res);
-
-       return res;
-}
-
-MonoCoverageInfo *
-mono_get_coverage_info (MonoMethod *method)
-{
-       if (!coverage_hash)
-               return NULL;
+#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)
 
-       return g_hash_table_lookup (coverage_hash, method);
-}
-               
 #if 0
 static gint
 compare_bblock (gconstpointer a, gconstpointer b)
@@ -593,10 +587,13 @@ mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
                clause = &header->clauses [i];
                if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->token_or_filter) &&
                    (offset < (clause->token_or_filter + filter_lengths [i])))
-                       return (i << 8) | 128 | clause->flags;
+                       return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
                           
                if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
-                       return (i << 8) | 64 | clause->flags;
+                       if (clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)
+                               return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
+                       else
+                               return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
                }
        }
 
@@ -604,13 +601,13 @@ mono_find_block_region (MonoCompile *cfg, int offset, int *filter_lengths)
        for (i = 0; i < header->num_clauses; ++i) {
                clause = &header->clauses [i];
                if (MONO_OFFSET_IN_CLAUSE (clause, offset))
-                       return (i << 8) | clause->flags;
+                       return ((i + 1) << 8) | clause->flags;
        }
 
        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 +615,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;
 }
 
 
@@ -778,6 +776,12 @@ handle_enum:
                        goto handle_enum;
                }
                return CEE_LDOBJ;
+       case MONO_TYPE_TYPEDBYREF:
+               return CEE_LDOBJ;
+       case MONO_TYPE_GENERICINST:
+               if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
+                       return CEE_LDOBJ;
+               return CEE_LDIND_REF;
        default:
                g_error ("unknown type 0x%02x in type_to_ldind", type->type);
        }
@@ -829,9 +833,14 @@ handle_enum:
                        goto handle_enum;
                }
                return CEE_STOBJ;
-               /* fail right now */
+       case MONO_TYPE_TYPEDBYREF:
+               return CEE_STOBJ;
+       case MONO_TYPE_GENERICINST:
+               if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE)
+                       return CEE_STOBJ;
+               return CEE_STIND_REF;
        default:
-               g_error ("unknown type %02x in type_to_stind", type->type);
+               g_error ("unknown type 0x%02x in type_to_stind", type->type);
        }
        return -1;
 }
@@ -891,6 +900,18 @@ handle_enum:
                        inst->type = STACK_VTYPE;
                        return;
                }
+       case MONO_TYPE_TYPEDBYREF:
+               inst->klass = mono_defaults.typed_reference_class;
+               inst->type = STACK_VTYPE;
+               return;
+       case MONO_TYPE_GENERICINST:
+               if (type->data.generic_inst->generic_type->type == MONO_TYPE_VALUETYPE) {
+                       inst->klass = mono_class_from_mono_type (type);
+                       inst->type = STACK_VTYPE;
+               } else {
+                       inst->type = STACK_OBJ;
+               }
+               return;
        default:
                g_error ("unknown type 0x%02x in eval stack type", type->type);
        }
@@ -934,10 +955,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},
 };
 
@@ -1268,36 +1289,19 @@ 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);      
+       }
 
+       /*g_print ("created temp %d of type 0x%x\n", num, type->type);*/
        mono_jit_stats.allocate_var++;
 
        MONO_INST_NEW (cfg, inst, opcode);
@@ -1433,6 +1437,39 @@ mono_add_varcopy_to_end (MonoCompile *cfg, MonoBasicBlock *bb, int src, int dest
        }
 }
 
+/*
+ * We try to share variables when possible
+ */
+static MonoInst *
+mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
+{
+       MonoInst *res;
+       int pos, vnum;
+
+       /* inlining can result in deeper stacks */ 
+       if (slot >= ((MonoMethodNormal *)cfg->method)->header->max_stack)
+               return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+
+       pos = ins->type - 1 + slot * STACK_MAX;
+
+       switch (ins->type) {
+       case STACK_I4:
+       case STACK_I8:
+       case STACK_R8:
+       case STACK_PTR:
+       case STACK_MP:
+       case STACK_OBJ:
+               if ((vnum = cfg->intvars [pos]))
+                       return cfg->varinfo [vnum];
+               res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+               cfg->intvars [pos] = res->inst_c0;
+               break;
+       default:
+               res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
+       }
+       return res;
+}
+
 /*
  * 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
@@ -1468,12 +1505,13 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                if (!found) {
                        bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
                        for (i = 0; i < count; ++i) {
-                               /* 
-                                * dietmar suggests that we can reuse temps already allocated 
-                                * for this purpouse, if they occupy the same stack slot and if 
-                                * they are of the same type.
-                                */
+#if 1
+                               /* try to reuse temps already allocated for this purpouse, if they occupy the same 
+                                * stack slot and if they are of the same type. */
+                               bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
+#else
                                bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
+#endif
                        }
                }
        }
@@ -1545,8 +1583,10 @@ handle_enum:
                        goto handle_enum;
                } else
                        return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
+       case MONO_TYPE_TYPEDBYREF:
+               return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
        default:
-               g_error ("unknown type %02x in ret_type_to_call_opcode", type->type);
+               g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
        }
        return -1;
 }
@@ -1597,6 +1637,108 @@ handle_loaded_temps (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst **stack,
        }
 }
 
+/*
+ * Prepare arguments for passing to a function call.
+ * Return a non-zero value if the arguments can't be passed to the given
+ * signature.
+ * The type checks are not yet complete and some conversions may need
+ * casts on 32 or 64 bit architectures.
+ */
+static int
+check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
+{
+       int i, simple_type;
+
+       if (sig->hasthis) {
+               if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
+                       return 1;
+               args++;
+       }
+       for (i = 0; i < sig->param_count; ++i) {
+               if (sig->params [i]->byref) {
+                       /* 
+                        * check the result of ldelema is only passed as an argument if the byref
+                        * type matches exactly the array element type.
+                        * FIXME: if the argument as been saved on the stack as part of the
+                        * interface variable code (the value was on the stack at a basic block boundary)
+                        * we need to add the check in that case, too.
+                        */
+                       if (args [i]->opcode == CEE_LDELEMA) {
+                               MonoInst *check;
+                               MonoClass *exact_class = mono_class_from_mono_type (sig->params [i]);
+                               if (!exact_class->valuetype) {
+                                       MONO_INST_NEW (cfg, check, OP_CHECK_ARRAY_TYPE);
+                                       check->cil_code = args [i]->cil_code;
+                                       check->klass = exact_class;
+                                       check->inst_left = args [i]->inst_left;
+                                       check->type = STACK_OBJ;
+                                       args [i]->inst_left = check;
+                               }
+                       }
+                       if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
+                               return 1;
+                       continue;
+               }
+               simple_type = sig->params [i]->type;
+handle_enum:
+               switch (simple_type) {
+               case MONO_TYPE_VOID:
+                       return 1;
+                       continue;
+               case MONO_TYPE_I1:
+               case MONO_TYPE_U1:
+               case MONO_TYPE_BOOLEAN:
+               case MONO_TYPE_I2:
+               case MONO_TYPE_U2:
+               case MONO_TYPE_CHAR:
+               case MONO_TYPE_I4:
+               case MONO_TYPE_U4:
+                       if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
+                               return 1;
+                       continue;
+               case MONO_TYPE_I:
+               case MONO_TYPE_U:
+               case MONO_TYPE_PTR:
+                       if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
+                               return 1;
+                       continue;
+               case MONO_TYPE_CLASS:
+               case MONO_TYPE_STRING:
+               case MONO_TYPE_OBJECT:
+               case MONO_TYPE_SZARRAY:
+               case MONO_TYPE_ARRAY:    
+                       if (args [i]->type != STACK_OBJ)
+                               return 1;
+                       continue;
+               case MONO_TYPE_I8:
+               case MONO_TYPE_U8:
+                       if (args [i]->type != STACK_I8)
+                               return 1;
+                       continue;
+               case MONO_TYPE_R4:
+               case MONO_TYPE_R8:
+                       if (args [i]->type != STACK_R8)
+                               return 1;
+                       continue;
+               case MONO_TYPE_VALUETYPE:
+                       if (sig->params [i]->data.klass->enumtype) {
+                               simple_type = sig->params [i]->data.klass->enum_basetype->type;
+                               goto handle_enum;
+                       }
+                       if (args [i]->type != STACK_VTYPE)
+                               return 1;
+                       continue;
+               case MONO_TYPE_TYPEDBYREF:
+                       if (args [i]->type != STACK_VTYPE)
+                               return 1;
+                       continue;
+               default:
+                       g_error ("unknown type 0x%02x in check_call_signature", simple_type);
+               }
+       }
+       return 0;
+}
+
 inline static int
 mono_spill_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoCallInst *call, MonoMethodSignature *sig, gboolean ret_object, 
                 const guint8 *ip, gboolean to_end)
@@ -1653,6 +1795,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
                     MonoInst **args, int calli, int virtual, const guint8 *ip, gboolean to_end)
 {
        MonoCallInst *call;
+       MonoInst *arg;
        int i;
 
        MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual));
@@ -1662,13 +1805,16 @@ mono_emit_call_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignatu
        call->signature = sig;
        call = mono_arch_call_opcode (cfg, bblock, call, virtual);
 
-       for (i = 0; i < (sig->param_count + sig->hasthis); ++i) {
-               if (call->args [i]) {
-                       if (to_end)
-                               mono_add_ins_to_end (bblock, call->args [i]);
-                       else
-                               MONO_ADD_INS (bblock, call->args [i]);
-               }
+       for (arg = call->out_args; arg;) {
+               MonoInst *narg = arg->next;
+               arg->next = NULL;
+               if (!arg->cil_code)
+                       arg->cil_code = ip;
+               if (to_end)
+                       mono_add_ins_to_end (bblock, arg);
+               else
+                       MONO_ADD_INS (bblock, arg);
+               arg = narg;
        }
        return call;
 }
@@ -1708,11 +1854,11 @@ mono_emit_method_call (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *met
 
 inline static int
 mono_emit_method_call_spilled (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *method,  
-                      MonoInst **args, const guint8 *ip, MonoInst *this)
+                      MonoMethodSignature *signature, MonoInst **args, const guint8 *ip, MonoInst *this)
 {
-       MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, method->signature, args, ip, this);
+       MonoCallInst *call = mono_emit_method_call (cfg, bblock, method, signature, args, ip, this);
 
-       return mono_spill_call (cfg, bblock, call, method->signature, method->string_ctor, ip, FALSE);
+       return mono_spill_call (cfg, bblock, call, signature, method->string_ctor, ip, FALSE);
 }
 
 inline static int
@@ -1745,6 +1891,7 @@ static void
 mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJitICallInfo *info)
 {
        MonoInst *ins, *temp = NULL, *store, *load;
+       MonoInst *last_arg = NULL;
        int i, nargs;
        MonoCallInst *call;
 
@@ -1770,23 +1917,21 @@ mono_emulate_opcode (MonoCompile *cfg, MonoInst *tree, MonoInst **iargs, MonoJit
 
        nargs = info->sig->param_count + info->sig->hasthis;
 
-       for (i = 1; i < nargs; i++) {
-               call->args [i - 1]->next = call->args [i];
-       }
+       for (last_arg = call->out_args; last_arg && last_arg->next; last_arg = last_arg->next) ;
 
        if (nargs)
-               call->args [nargs - 1]->next = store;
+               last_arg->next = store;
 
        if (cfg->prev_ins) {
                store->next = cfg->prev_ins->next;
                if (nargs)
-                       cfg->prev_ins->next =  call->args [0];
+                       cfg->prev_ins->next = call->out_args;
                else
                        cfg->prev_ins->next = store;
        } else {
                store->next = cfg->cbb->code;
                if (nargs)              
-                       cfg->cbb->code = call->args [0];
+                       cfg->cbb->code = call->out_args;
                else
                        cfg->cbb->code = store;
        }
@@ -1832,6 +1977,7 @@ static void
 handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst *src, const unsigned char *ip, MonoClass *klass, gboolean to_end, gboolean native) {
        MonoInst *iargs [3];
        int n;
+       guint32 align = 0;
 
        g_assert (klass);
        /*
@@ -1840,10 +1986,20 @@ handle_stobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, MonoInst
         */
 
        if (native)
-               n = mono_class_native_size (klass, NULL);
+               n = mono_class_native_size (klass, &align);
        else
-               n = mono_class_value_size (klass, NULL);
-
+               n = mono_class_value_size (klass, &align);
+
+       if ((cfg->opt & MONO_OPT_INTRINS) && !to_end && n <= sizeof (gpointer) * 5) {
+               MonoInst *inst;
+               MONO_INST_NEW (cfg, inst, OP_MEMCPY);
+               inst->inst_left = dest;
+               inst->inst_right = src;
+               inst->cil_code = ip;
+               inst->unused = n;
+               MONO_ADD_INS (bblock, inst);
+               return;
+       }
        iargs [0] = dest;
        iargs [1] = src;
        NEW_ICONST (cfg, iargs [2], n);
@@ -1880,6 +2036,13 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
                MONO_ADD_INS (bblock, ins);
                break;
        default:
+               if (n <= sizeof (gpointer) * 5) {
+                       ins->opcode = OP_MEMSET;
+                       ins->inst_imm = 0;
+                       ins->unused = n;
+                       MONO_ADD_INS (bblock, ins);
+                       break;
+               }
                handle_loaded_temps (cfg, bblock, stack_start, sp);
                NEW_ICONST (cfg, ins, n);
                iargs [0] = dest;
@@ -1891,20 +2054,36 @@ handle_initobj (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *dest, const
 
 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
 
+static gboolean 
+needs_cctor_run (MonoClass *klass, MonoMethod *caller)
+{
+       int i;
+       MonoMethod *method;
+       
+       for (i = 0; i < klass->method.count; ++i) {
+               method = klass->methods [i];
+               if ((method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME) && 
+                   (strcmp (".cctor", method->name) == 0)) {
+                       if (caller == method)
+                               return FALSE;
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
 static gboolean
-mono_method_check_inlining (MonoMethod *method)
+mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
 {
        MonoMethodHeader *header = ((MonoMethodNormal *)method)->header;
        MonoMethodSignature *signature = method->signature;
+       MonoVTable *vtable;
        int i;
 
-       /* fixme: we should inline wrappers */
-       if (method->wrapper_type != MONO_WRAPPER_NONE)
-               return FALSE;
-
        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 ||
@@ -1919,6 +2098,27 @@ mono_method_check_inlining (MonoMethod *method)
                }
        }
 
+       /* 
+        * if we can initialize the class of the method right away, we do,
+        * otherwise we don't allow inlining if the class needs initialization,
+        * since it would mean inserting a call to mono_runtime_class_init()
+        * inside the inlined code
+        */
+       if (!(cfg->opt & MONO_OPT_SHARED)) {
+               vtable = mono_class_vtable (cfg->domain, method->klass);
+               if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
+                       mono_runtime_class_init (vtable);
+               else if (!vtable->initialized && needs_cctor_run (method->klass, NULL))
+                       return FALSE;
+       } else {
+               /* 
+                * If we're compiling for shared code
+                * the cctor will need to be run at aot method load time, for example,
+                * or at the end of the compilation of the inlining method.
+                */
+               if (needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
+                       return FALSE;
+       }
        //if (!MONO_TYPE_IS_VOID (signature->ret)) return FALSE;
 
        /* also consider num_locals? */
@@ -1928,6 +2128,87 @@ mono_method_check_inlining (MonoMethod *method)
        return FALSE;
 }
 
+static MonoInst*
+mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
+{
+       int temp, rank;
+       MonoInst *addr;
+       MonoMethodSignature *esig;
+
+       rank = cmethod->signature->param_count - (is_set? 1: 0);
+       /* 
+        * FIXME: handle TypeMismatch for set or use the slow path
+        * for that.
+        */
+       if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
+               MonoInst *indexes;
+               NEW_GROUP (cfg, indexes, sp [1], sp [2]);
+               MONO_INST_NEW (cfg, addr, OP_LDELEMA2D);
+               addr->inst_left = sp [0];
+               addr->inst_right = indexes;
+               addr->cil_code = ip;
+               addr->type = STACK_MP;
+               addr->klass = cmethod->klass;
+               return addr;
+       }
+       esig = mono_get_element_address_signature (rank);
+       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
+       NEW_TEMPLOAD (cfg, addr, temp);
+       return addr;
+}
+
+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;
+#if 0
+               /* OP_FREM is not IEEE compatible */
+               else if (strcmp (cmethod->name, "IEEERemainder") == 0)
+                       op = OP_FREM;
+#endif
+               else
+                       return NULL;
+       } else if (cmethod->klass == mono_defaults.array_class) {
+               if (strcmp (cmethod->name, "get_Rank") == 0)
+                       op = OP_ARRAY_RANK;
+               else if (strcmp (cmethod->name, "get_Length") == 0)
+                       op = CEE_LDLEN;
+               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)
 {
@@ -1956,7 +2237,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;
@@ -1971,6 +2252,72 @@ 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 
@@ -2001,16 +2348,105 @@ mono_save_args (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethodSignature *s
 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) goto unverified
 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) goto unverified
 
+#define TYPE_PARAM_TO_TYPE(num) (method->klass->generic_inst->data.generic_inst->type_argv [(num)])
+#define TYPE_PARAM_TO_CLASS(num) (mono_class_from_mono_type (TYPE_PARAM_TO_TYPE ((num))))
+
 /* offset from br.s -> br like opcodes */
 #define BIG_BRANCH_OFFSET 13
 
+static int
+get_basic_blocks (MonoCompile *cfg, GHashTable *bbhash, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end)
+{
+       unsigned char *ip = start;
+       unsigned char *target;
+       int i;
+       guint cli_addr;
+       MonoBasicBlock *bblock;
+       const MonoOpcode *opcode;
+
+       while (ip < end) {
+               cli_addr = ip - start;
+               i = mono_opcode_value ((const guint8 **)&ip);
+               opcode = &mono_opcodes [i];
+               switch (opcode->argument) {
+               case MonoInlineNone:
+                       ip++; 
+                       break;
+               case MonoInlineString:
+               case MonoInlineType:
+               case MonoInlineField:
+               case MonoInlineMethod:
+               case MonoInlineTok:
+               case MonoInlineSig:
+               case MonoShortInlineR:
+               case MonoInlineI:
+                       ip += 5;
+                       break;
+               case MonoInlineVar:
+                       ip += 3;
+                       break;
+               case MonoShortInlineVar:
+               case MonoShortInlineI:
+                       ip += 2;
+                       break;
+               case MonoShortInlineBrTarget:
+                       target = start + cli_addr + 2 + (signed char)ip [1];
+                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       ip += 2;
+                       break;
+               case MonoInlineBrTarget:
+                       target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
+                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       ip += 5;
+                       break;
+               case MonoInlineSwitch: {
+                       guint32 n = read32 (ip + 1);
+                       guint32 j;
+                       ip += 5;
+                       cli_addr += 5 + 4 * n;
+                       target = start + cli_addr;
+                       GET_BBLOCK (cfg, bbhash, bblock, target);
+                       
+                       for (j = 0; j < n; ++j) {
+                               target = start + cli_addr + (gint32)read32 (ip);
+                               GET_BBLOCK (cfg, bbhash, bblock, target);
+                               ip += 4;
+                       }
+                       break;
+               }
+               case MonoInlineR:
+               case MonoInlineI8:
+                       ip += 9;
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+       }
+       return 0;
+unverified:
+       return 1;
+}
+
+static MonoClassField *
+get_generic_field_inst (MonoClassField *field, MonoClass *klass, MonoClass **retclass)
+{
+       int i;
+       for (i = 0; i < field->parent->field.count; ++i) {
+               if (field == &field->parent->fields [i]) {
+                       *retclass = klass;
+                       return &klass->fields [i];
+               }
+       }
+       return NULL;
+}
+
 /*
  * mono_method_to_ir: translates IL into basic blocks containing trees
  */
 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;
@@ -2030,6 +2466,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;
@@ -2047,6 +2484,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                bbhash = g_hash_table_new (g_direct_hash, NULL);
        }
 
+       if (cfg->verbose_level > 2)
+               g_print ("method to IR %s\n", mono_method_full_name (method, TRUE));
+
+       if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
+               cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
+
+       dont_inline = g_list_prepend (dont_inline, method);
        if (cfg->method == method) {
 
                /* ENTRY BLOCK */
@@ -2067,12 +2511,16 @@ 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;
                        filter_lengths = alloca (size);
                        memset (filter_lengths, 0, size);
+
+                       cfg->spvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+                       /* prevent it from being register allocated */
+                       cfg->spvar->flags |= MONO_INST_INDIRECT;
                }
                /* handle exception clauses */
                for (i = 0; i < header->num_clauses; ++i) {
@@ -2082,6 +2530,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        tblock->real_offset = clause->try_offset;
                        GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
+
+                       if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
+                           clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
+                               MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
+                               MONO_ADD_INS (tblock, ins);
+                       }
+
                        /*g_print ("clause try IL_%04x to IL_%04x handler %d at IL_%04x to IL_%04x\n", clause->try_offset, clause->try_offset + clause->try_len, clause->flags, clause->handler_offset, clause->handler_offset + clause->handler_len);
                          while (p < end) {
                          g_print ("%s", mono_disasm_code_one (NULL, method, p, &p));
@@ -2099,12 +2554,15 @@ 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] = cfg->exvar;
+                               
                                if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
                                        GET_BBLOCK (cfg, bbhash, tblock, ip + clause->token_or_filter);
                                        tblock->real_offset = clause->token_or_filter;
                                        tblock->in_scount = 1;
                                        tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
                                        tblock->in_stack [0] = cfg->exvar;
+                                       MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
+                                       MONO_ADD_INS (tblock, ins);
                                }
                        }
                }
@@ -2121,13 +2579,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;
@@ -2141,7 +2600,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                link_bblock (cfg, start_bblock, bblock);
        }
 
-       mono_debug_init_method (cfg, bblock);
+       if (get_basic_blocks (cfg, bbhash, header, real_offset, ip, end))
+               goto unverified;
+
+       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)
@@ -2162,7 +2624,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;
@@ -2211,6 +2673,26 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                }
 
+               if (cfg->coverage_info) {
+                       MonoInst *store, *one;
+                       guint32 cil_offset = ip - header->code;
+                       cfg->coverage_info->data [cil_offset].cil_code = ip;
+
+                       /* TODO: Use an increment here */
+                       NEW_ICONST (cfg, one, 1);
+                       one->cil_code = ip;
+
+                       NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
+                       ins->cil_code = ip;
+
+                       MONO_INST_NEW (cfg, store, CEE_STIND_I);
+                       store->cil_code = ip;
+                       store->inst_left = ins;
+                       store->inst_right = one;
+
+                       MONO_ADD_INS (bblock, store);
+               }
+
                if (cfg->verbose_level > 3)
                        g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, sp-stack_start, mono_disasm_code_one (NULL, method, ip, NULL));
 
@@ -2445,12 +2927,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        token = read32 (ip + 1);
                        /* FIXME: check the signature matches */
                        cmethod = mono_get_method (image, token, NULL);
-                       /*
-                        * The current magic trampoline can't handle this
-                        * apparently, so we compile the method right away.
-                        * Later, we may need to fix the trampoline or use a different one.
-                        */
-                       ins->inst_p0 = mono_compile_method (cmethod);
+                       ins->inst_p0 = cmethod;
                        MONO_ADD_INS (bblock, ins);
                        ip += 5;
                        start_new_bblock = 1;
@@ -2460,15 +2937,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;
@@ -2480,8 +2955,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                n = fsig->param_count + fsig->hasthis;
 
                        } else {
-                               cmethod = mono_get_method (image, token, NULL);
-                               cheader = ((MonoMethodNormal *)cmethod)->header;
+                               if (method->wrapper_type != MONO_WRAPPER_NONE) {
+                                       cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
+                               } else {
+                                       cmethod = mono_get_method (image, token, NULL);
+                               }
 
                                if (!cmethod->klass->inited)
                                        mono_class_init (cmethod->klass);
@@ -2498,7 +2976,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
 #endif
                                } else {
-                                       fsig = cmethod->signature;
+                                       fsig = mono_method_get_signature (cmethod, image, token);
                                }
 
                                n = fsig->param_count + fsig->hasthis;
@@ -2519,17 +2997,28 @@ 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);
-                               ins->cil_code = ip;
-                               g_assert (n <= 2);
+                       if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
+                               goto unverified;
 
-                               if (fsig->param_count > 0) {
-                                       ins->inst_i0 = sp [0];
-                                       if (fsig->param_count > 1)
-                                               ins->inst_i1 = sp [1];
+                       if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL)) {
+                               int i;
+                               for (i = 0; i < n; ++i) {
+                                       NEW_ARGSTORE (cfg, ins, i, sp [i]);
+                                       ins->cil_code = ip;
+                                       MONO_ADD_INS (bblock, ins);
                                }
+                               MONO_INST_NEW (cfg, ins, CEE_JMP);
+                               ins->cil_code = ip;
+                               ins->inst_p0 = cmethod;
+                               MONO_ADD_INS (bblock, ins);
+                               start_new_bblock = 1;
+                               /* skip CEE_RET as well */
+                               ip += 6;
+                               ins_flag = 0;
+                               break;
+                       }
+                       if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_get_opcode_for_method (cfg, cmethod, fsig, sp))) {
+                               ins->cil_code = ip;
 
                                if (MONO_TYPE_IS_VOID (fsig->ret)) {
                                        MONO_ADD_INS (bblock, ins);
@@ -2543,83 +3032,36 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
-                       if ((cfg->opt & MONO_OPT_INLINE) && 
+                       handle_loaded_temps (cfg, bblock, stack_start, sp);
+
+                       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 (cfg, 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;
-
-                                       ip += 5;
-                                       real_offset += 5;
-
-                                       bblock->next_bb = sbblock;
-                                       link_bblock (cfg, bblock, sbblock);
+                               if ((costs = inline_method (cfg, cmethod, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
+                                       ip += 5;
+                                       real_offset += 5;
 
                                        GET_BBLOCK (cfg, bbhash, bblock, ip);
                                        ebblock->next_bb = bblock;
                                        link_bblock (cfg, ebblock, bblock);
 
-                                       if (rvar) {
-                                               NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
-                                               *sp++ = ins;
-                                       }
-                                       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)); }
+                                       if (!MONO_TYPE_IS_VOID (fsig->ret))
+                                               sp++;
+
+                                       /* indicates start of a new block, and triggers a load of all 
+                                          stack arguments at bb boundarie */
+                                       bblock = ebblock;
 
                                        inline_costs += costs;
                                        break;
-                               } else {
-
-                                       if (cfg->verbose_level > 2)
-                                               g_print ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
-
                                }
                        }
                        
                        inline_costs += 10 * num_calls++;
-                       handle_loaded_temps (cfg, bblock, stack_start, sp);
 
                        /* tail recursion elimination */
                        if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == cfg->method && ip [5] == CEE_RET) {
@@ -2666,14 +3108,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                                        
                        } else if (array_rank) {
-                               MonoMethodSignature *esig;
                                MonoInst *addr;
 
                                if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
-                                       esig = mono_get_element_address_signature (fsig->param_count - 1);
-                                       
-                                       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
-                                       NEW_TEMPLOAD (cfg, addr, temp);
+                                       addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, TRUE);
                                        NEW_INDSTORE (cfg, ins, addr, sp [fsig->param_count], fsig->params [fsig->param_count - 1]);
                                        ins->cil_code = ip;
                                        if (ins->opcode == CEE_STOBJ) {
@@ -2683,21 +3121,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        }
 
                                } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
-                                       esig = mono_get_element_address_signature (fsig->param_count);
-
-                                       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
-                                       NEW_TEMPLOAD (cfg, addr, temp);
+                                       addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
                                        NEW_INDLOAD (cfg, ins, addr, fsig->ret);
                                        ins->cil_code = ip;
 
                                        *sp++ = ins;
                                } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
-                                       /* implement me */
-                                       esig = mono_get_element_address_signature (fsig->param_count);
-
-                                       temp = mono_emit_native_call (cfg, bblock, ves_array_element_address, esig, sp, ip, FALSE);
-                                       NEW_TEMPLOAD (cfg, *sp, temp);
-                                       sp++;
+                                       addr = mini_get_ldelema_ins (cfg, bblock, cmethod, sp, ip, FALSE);
+                                       *sp++ = addr;
                                } else {
                                        g_assert_not_reached ();
                                }
@@ -2708,7 +3139,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins = (MonoInst*)mono_emit_method_call (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL);
                                        *sp++ = ins;
                                } else {
-                                       if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, virtual ? sp [0] : NULL)) != -1) {
+                                       if ((temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, virtual ? sp [0] : NULL)) != -1) {
                                                NEW_TEMPLOAD (cfg, *sp, temp);
                                                sp++;
                                        }
@@ -2958,17 +3389,17 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_CONV_I1:
                case CEE_CONV_I2:
                case CEE_CONV_I4:
-               case CEE_CONV_I8:
                case CEE_CONV_R4:
                case CEE_CONV_R8:
                case CEE_CONV_U4:
+               case CEE_CONV_I8:
                case CEE_CONV_U8:
                case CEE_CONV_OVF_I8:
                case CEE_CONV_OVF_U8:
                case CEE_CONV_R_UN:
                        CHECK_STACK (1);
                        ADD_UNOP (*ip);
-                       ip++;
+                       ip++;                   
                        break;
                case CEE_CONV_OVF_I4:
                case CEE_CONV_OVF_I1:
@@ -3015,7 +3446,53 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip++;
                        break;
                case CEE_CPOBJ:
-                       g_error ("opcode 0x%02x not handled", *ip);
+                       CHECK_STACK (2);
+                       token = read32 (ip + 1);
+                       if (method->wrapper_type != MONO_WRAPPER_NONE)
+                               klass = mono_method_get_wrapper_data (method, token);
+                       else
+                               klass = mono_class_get (image, token);
+
+                       mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+                       sp -= 2;
+                       if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               MonoInst *store, *load;
+                               MONO_INST_NEW (cfg, load, CEE_LDIND_REF);
+                               load->cil_code = ip;
+                               load->inst_i0 = sp [1];
+                               load->type = ldind_type [CEE_LDIND_REF];
+                               load->flags |= ins_flag;
+                               MONO_INST_NEW (cfg, store, CEE_STIND_REF);
+                               store->cil_code = ip;
+                               handle_loaded_temps (cfg, bblock, stack_start, sp);
+                               MONO_ADD_INS (bblock, store);
+                               store->inst_i0 = sp [0];
+                               store->inst_i1 = load;
+                               store->flags |= ins_flag;
+                       } else {
+                               n = mono_class_value_size (klass, NULL);
+                               if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
+                                       MonoInst *copy;
+                                       MONO_INST_NEW (cfg, copy, OP_MEMCPY);
+                                       copy->inst_left = sp [0];
+                                       copy->inst_right = sp [1];
+                                       copy->cil_code = ip;
+                                       copy->unused = n;
+                                       MONO_ADD_INS (bblock, copy);
+                               } else {
+                                       MonoInst *iargs [3];
+                                       iargs [0] = sp [0];
+                                       iargs [1] = sp [1];
+                                       NEW_ICONST (cfg, iargs [2], n);
+                                       iargs [2]->cil_code = ip;
+
+                                       mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+                               }
+                       }
+                       ins_flag = 0;
+                       ip += 5;
                        break;
                case CEE_LDOBJ: {
                        MonoInst *iargs [3];
@@ -3026,16 +3503,43 @@ 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);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+                       if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               MONO_INST_NEW (cfg, ins, CEE_LDIND_REF);
+                               ins->cil_code = ip;
+                               ins->inst_i0 = sp [0];
+                               ins->type = ldind_type [CEE_LDIND_REF];
+                               ins->flags |= ins_flag;
+                               ins_flag = 0;
+                               *sp++ = ins;
+                               ip += 5;
+                               break;
+                       }
                        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);
-                       mono_emit_jit_icall (cfg, bblock, helper_memcpy, iargs, ip);
+                       if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
+                               MonoInst *copy;
+                               MONO_INST_NEW (cfg, copy, OP_MEMCPY);
+                               copy->inst_left = iargs [0];
+                               copy->inst_right = *sp;
+                               copy->cil_code = ip;
+                               copy->unused = n;
+                               MONO_ADD_INS (bblock, copy);
+                       } else {
+                               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;
                        ip += 5;
+                       ins_flag = 0;
                        inline_costs += 1;
                        break;
                }
@@ -3043,27 +3547,44 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        CHECK_STACK_OVF (1);
                        n = read32 (ip + 1);
 
-                       if ((cfg->opt & MONO_OPT_SAHRED) || mono_compile_aot) {
+                       if (method->wrapper_type != MONO_WRAPPER_NONE) {
                                int temp;
-                               MonoInst *iargs [3];
-                               NEW_TEMPLOAD (cfg, iargs [0], mono_get_domainvar (cfg)->inst_c0);
-                               NEW_IMAGECONST (cfg, iargs [1], image);
-                               NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
-                               temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
+                               MonoInst *iargs [1];
+
+                               NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                          
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_string_new_wrapper, iargs, ip);
                                NEW_TEMPLOAD (cfg, *sp, temp);
-                               mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+
                        } else {
-                               NEW_PCONST (cfg, ins, NULL);
-                               ins->cil_code = ip;
-                               ins->type = STACK_OBJ;
-                               ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
-                               *sp = ins;
+
+                               if (mono_compile_aot) {
+                                       cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, (gpointer)n);
+                               }
+
+                               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);
+                                       NEW_IMAGECONST (cfg, iargs [1], image);
+                                       NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_ldstr, iargs, ip);
+                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                       mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+                               } else {
+                                       NEW_PCONST (cfg, ins, NULL);
+                                       ins->cil_code = ip;
+                                       ins->type = STACK_OBJ;
+                                       ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
+                                       *sp = ins;
+                               }
                        }
+
                        sp++;
                        ip += 5;
                        break;
                case CEE_NEWOBJ: {
                        MonoInst *iargs [2];
+                       MonoMethodSignature *fsig;
                        int temp;
 
                        token = read32 (ip + 1);
@@ -3071,10 +3592,11 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                cmethod = mono_method_get_wrapper_data (method, token);
                        } else
                                cmethod = mono_get_method (image, token, NULL);
+                       fsig = mono_method_get_signature (cmethod, image, token);
 
                        mono_class_init (cmethod->klass);
 
-                       n = cmethod->signature->param_count;
+                       n = fsig->param_count;
                        CHECK_STACK (n);
 
                        /* move the args to allow room for 'this' in the first position */
@@ -3088,28 +3610,67 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        if (cmethod->klass->parent == mono_defaults.array_class) {
                                NEW_METHODCONST (cfg, *sp, cmethod);
-                               temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, cmethod->signature, sp, ip, FALSE);
+                               temp = mono_emit_native_call (cfg, bblock, mono_array_new_va, fsig, sp, ip, FALSE);
 
                        } else if (cmethod->string_ctor) {
                                /* we simply pass a null pointer */
                                NEW_PCONST (cfg, *sp, NULL); 
                                /* now call the string ctor */
-                               temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
+                               temp = mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, NULL);
                        } else {
                                if (cmethod->klass->valuetype) {
                                        iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
                                        temp = iargs [0]->inst_c0;
                                        NEW_TEMPLOADA (cfg, *sp, temp);
                                } else {
-                                       NEW_DOMAINCONST (cfg, iargs [0]);
-                                       NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
+                                       if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+                                               NEW_DOMAINCONST (cfg, iargs [0]);
+                                               NEW_CLASSCONST (cfg, iargs [1], cmethod->klass);
 
-                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+                                               temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+                                       } else {
+                                               MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
+                                               NEW_PCONST (cfg, iargs [0], vtable);
+                                               if (cmethod->klass->has_finalize || cmethod->klass->marshalbyref || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
+                                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
+                                               else
+                                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
+                                       }
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                }
 
-                               /* now call the actual ctor */
-                               mono_emit_method_call_spilled (cfg, bblock, cmethod, sp, ip, NULL);
+                               if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
+                                   mono_method_check_inlining (cfg, 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, fsig, bblock, sp, ip, real_offset, dont_inline, &ebblock))) {
+
+                                               ip += 5;
+                                               real_offset += 5;
+                                               
+                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               ebblock->next_bb = bblock;
+                                               link_bblock (cfg, ebblock, bblock);
+
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
+                                               sp++;
+
+                                               /* indicates start of a new block, and triggers a load 
+                                                  of all stack arguments at bb boundarie */
+                                               bblock = ebblock;
+
+                                               inline_costs += costs;
+                                               break;
+                                               
+                                       } else {
+                                               mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+                                       }
+                               } else {
+                                       /* now call the actual ctor */
+                                       mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, sp[0]);
+                               }
                        }
 
                        NEW_TEMPLOAD (cfg, *sp, temp);
@@ -3132,9 +3693,76 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ip += 5;
                        *sp++ = ins;
                        break;
+               case CEE_UNBOX_ANY: {
+                       MonoInst *add, *vtoffset;
+                       MonoInst *iargs [3];
+
+                       CHECK_STACK (1);
+                       --sp;
+                       token = read32 (ip + 1);
+                       if (method->wrapper_type != MONO_WRAPPER_NONE)
+                               klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
+                       else 
+                               klass = mono_class_get (image, token);
+                       mono_class_init (klass);
+
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+
+                       if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               /* CASTCLASS */
+                               MONO_INST_NEW (cfg, ins, CEE_CASTCLASS);
+                               ins->type = STACK_OBJ;
+                               ins->inst_left = *sp;
+                               ins->klass = klass;
+                               ins->inst_newa_class = klass;
+                               ins->cil_code = ip;
+                               *sp++ = ins;
+                               ip += 5;
+                               break;
+                       }
+
+                       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 = ins;
+                       add->inst_right = vtoffset;
+                       add->type = STACK_MP;
+                       *sp = add;
+                       ip += 5;
+                       /* LDOBJ impl */
+                       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);
+                       if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
+                               MonoInst *copy;
+                               MONO_INST_NEW (cfg, copy, OP_MEMCPY);
+                               copy->inst_left = iargs [0];
+                               copy->inst_right = *sp;
+                               copy->cil_code = ip;
+                               copy->unused = n;
+                               MONO_ADD_INS (bblock, copy);
+                       } else {
+                               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;
+                       inline_costs += 2;
+                       break;
+               }
                case CEE_UNBOX: {
                        MonoInst *add, *vtoffset;
-                       /* FIXME: need to check class: move to inssel.brg? */
+
                        CHECK_STACK (1);
                        --sp;
                        token = read32 (ip + 1);
@@ -3143,14 +3771,25 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else 
                                klass = mono_class_get (image, token);
                        mono_class_init (klass);
+
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+
+                       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:
@@ -3159,6 +3798,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        --sp;
                        klass = mono_class_get (image, read32 (ip + 1));
                        mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
                        ins->type = STACK_OBJ;
                        ins->inst_left = *sp;
                        ins->klass = klass;
@@ -3182,6 +3823,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_STFLD: {
                        MonoInst *offset_ins;
                        MonoClassField *field;
+                       MonoBasicBlock *ebblock;
+                       int costs;
                        guint foffset;
 
                        if (*ip == CEE_STFLD) {
@@ -3196,20 +3839,45 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        //      goto unverified;
                        token = read32 (ip + 1);
                        field = mono_field_from_token (image, token, &klass);
+                       if (field->parent->gen_params)
+                               field = get_generic_field_inst (field, method->klass, &klass);
                        mono_class_init (klass);
+
                        foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
                        /* FIXME: mark instructions for use in SSA */
                        if (*ip == CEE_STFLD) {
                                if (klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) {
-                                       /* fixme: we need to inline that call somehow */
                                        MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
                                        MonoInst *iargs [5];
+
                                        iargs [0] = sp [0];
                                        NEW_CLASSCONST (cfg, iargs [1], klass);
                                        NEW_FIELDCONST (cfg, iargs [2], field);
-                                       NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
+                                       NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
+                                                   field->offset);
                                        iargs [4] = sp [1];
-                                       mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, iargs, ip, NULL);
+
+                                       if (cfg->opt & MONO_OPT_INLINE) {
+                                               costs = inline_method (cfg, stfld_wrapper, stfld_wrapper->signature, bblock, 
+                                                                      iargs, ip, real_offset, dont_inline, &ebblock);
+                                               g_assert (costs > 0);
+                                                     
+                                               ip += 5;
+                                               real_offset += 5;
+
+                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               ebblock->next_bb = bblock;
+                                               link_bblock (cfg, ebblock, bblock);
+
+                                               /* indicates start of a new block, and triggers a load 
+                                                  of all stack arguments at bb boundarie */
+                                               bblock = ebblock;
+
+                                               inline_costs += costs;
+                                               break;
+                                       } else {
+                                               mono_emit_method_call_spilled (cfg, bblock, stfld_wrapper, stfld_wrapper->signature, iargs, ip, NULL);
+                                       }
                                } else {
                                        MonoInst *store;
                                        NEW_ICONST (cfg, offset_ins, foffset);
@@ -3238,18 +3906,49 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
                                        MonoInst *iargs [4];
                                        int temp;
+                                       
                                        iargs [0] = sp [0];
                                        NEW_CLASSCONST (cfg, iargs [1], klass);
                                        NEW_FIELDCONST (cfg, iargs [2], field);
                                        NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
-                                       temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, iargs, ip, NULL);
-                                       if (*ip == CEE_LDFLDA) {
-                                               /* not sure howto handle this */
-                                               NEW_TEMPLOADA (cfg, *sp, temp);
+                                       if (cfg->opt & MONO_OPT_INLINE) {
+                                               costs = inline_method (cfg, ldfld_wrapper, ldfld_wrapper->signature, bblock, 
+                                                                      iargs, ip, real_offset, dont_inline, &ebblock);
+                                               g_assert (costs > 0);
+                                                     
+                                               ip += 5;
+                                               real_offset += 5;
+
+                                               GET_BBLOCK (cfg, bbhash, bblock, ip);
+                                               ebblock->next_bb = bblock;
+                                               link_bblock (cfg, ebblock, bblock);
+
+                                               temp = iargs [0]->inst_i0->inst_c0;
+
+                                               if (*ip == CEE_LDFLDA) {
+                                                       /* not sure howto handle this */
+                                                       NEW_TEMPLOADA (cfg, *sp, temp);
+                                               } else {
+                                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                               }
+                                               sp++;
+
+                                               /* indicates start of a new block, and triggers a load of
+                                                  all stack arguments at bb boundarie */
+                                               bblock = ebblock;
+                                               
+                                               inline_costs += costs;
+                                               break;
                                        } else {
-                                               NEW_TEMPLOAD (cfg, *sp, temp);
+                                               temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, ldfld_wrapper->signature, iargs, ip, NULL);
+                                               if (*ip == CEE_LDFLDA) {
+                                                       /* not sure howto handle this */
+                                                       NEW_TEMPLOADA (cfg, *sp, temp);
+                                               } else {
+                                                       NEW_TEMPLOAD (cfg, *sp, temp);
+                                               }
+                                               sp++;
                                        }
-                                       sp++;
                                } else {
                                        NEW_ICONST (cfg, offset_ins, foffset);
                                        MONO_INST_NEW (cfg, ins, CEE_ADD);
@@ -3279,7 +3978,6 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                case CEE_LDSFLDA:
                case CEE_STSFLD: {
                        MonoClassField *field;
-                       MonoVTable *vtable;
 
                        token = read32 (ip + 1);
 
@@ -3288,7 +3986,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);
@@ -3297,9 +3995,34 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                temp = mono_emit_jit_icall (cfg, bblock, mono_class_static_field_address, iargs, ip);
                                NEW_TEMPLOAD (cfg, ins, temp);
                        } else {
+                               gpointer addr;
+                               MonoVTable *vtable;
                                vtable = mono_class_vtable (cfg->domain, klass);
-                               NEW_PCONST (cfg, ins, (char*)vtable->data + field->offset);
-                               ins->cil_code = ip;
+                               if (!cfg->domain->thread_static_fields || !(addr = g_hash_table_lookup (cfg->domain->thread_static_fields, field))) {
+                                       if (!vtable->initialized && !(klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) && needs_cctor_run (klass, method)) {
+                                               MonoInst *iargs [1];
+                                               NEW_PCONST (cfg, iargs [0], vtable);
+                                               mono_emit_jit_icall (cfg, bblock, mono_runtime_class_init, iargs, ip);
+                                               if (cfg->verbose_level > 2)
+                                                       g_print ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
+                                       } else {
+                                               mono_runtime_class_init (vtable);
+                                       }
+                                       addr = (char*)vtable->data + field->offset;
+                                       NEW_PCONST (cfg, ins, addr);
+                                       ins->cil_code = ip;
+                               } else {
+                                       /* 
+                                        * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
+                                        * This could be later optimized to do just a couple of
+                                        * memory dereferences with constant offsets.
+                                        */
+                                       int temp;
+                                       MonoInst *iargs [1];
+                                       NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_threads_get_static_data, iargs, ip);
+                                       NEW_TEMPLOAD (cfg, ins, temp);
+                               }
                        }
 
                        /* FIXME: mark instructions for use in SSA */
@@ -3321,17 +4044,83 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                } else
                                        MONO_ADD_INS (bblock, store);
                        } else {
-                               MonoInst *load;
-                               CHECK_STACK_OVF (1);
-                               MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
-                               type_to_eval_stack_type (field->type, load);
-                               load->cil_code = ip;
-                               load->inst_left = ins;
-                               *sp++ = load;
-                               load->flags |= ins_flag;
-                               ins_flag = 0;
-                       /* fixme: dont see the problem why this does not work */
-                               //cfg->disable_aot = TRUE;
+                               gboolean is_const = FALSE;
+                               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+                               if (!((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) && 
+                                   vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
+                                       gpointer addr = (char*)vtable->data + field->offset;
+                                       /* g_print ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
+                                       is_const = TRUE;
+                                       switch (field->type->type) {
+                                       case MONO_TYPE_BOOLEAN:
+                                       case MONO_TYPE_U1:
+                                               NEW_ICONST (cfg, *sp, *((guint8 *)addr));
+                                               sp++;
+                                               break;
+                                       case MONO_TYPE_I1:
+                                               NEW_ICONST (cfg, *sp, *((gint8 *)addr));
+                                               sp++;
+                                               break;                                          
+                                       case MONO_TYPE_CHAR:
+                                       case MONO_TYPE_U2:
+                                               NEW_ICONST (cfg, *sp, *((guint16 *)addr));
+                                               sp++;
+                                               break;
+                                       case MONO_TYPE_I2:
+                                               NEW_ICONST (cfg, *sp, *((gint16 *)addr));
+                                               sp++;
+                                               break;
+                                               break;
+                                       case MONO_TYPE_I4:
+                                               NEW_ICONST (cfg, *sp, *((gint32 *)addr));
+                                               sp++;
+                                               break;                                          
+                                       case MONO_TYPE_U4:
+                                               NEW_ICONST (cfg, *sp, *((guint32 *)addr));
+                                               sp++;
+                                               break;
+                                       case MONO_TYPE_I:
+                                       case MONO_TYPE_U:
+                                       case MONO_TYPE_STRING:
+                                       case MONO_TYPE_OBJECT:
+                                       case MONO_TYPE_CLASS:
+                                       case MONO_TYPE_SZARRAY:
+                                       case MONO_TYPE_PTR:
+                                       case MONO_TYPE_FNPTR:
+                                       case MONO_TYPE_ARRAY:
+                                               NEW_PCONST (cfg, *sp, *((gpointer *)addr));
+                                               type_to_eval_stack_type (field->type, *sp);
+                                               sp++;
+                                               break;
+                                       case MONO_TYPE_I8:
+                                       case MONO_TYPE_U8:
+                                               MONO_INST_NEW (cfg, *sp, OP_I8CONST);
+                                               sp [0]->type = STACK_I8;
+                                               sp [0]->inst_l = *((gint64 *)addr);
+                                               sp++;
+                                               break;
+                                       case MONO_TYPE_R4:
+                                       case MONO_TYPE_R8:
+                                       case MONO_TYPE_VALUETYPE:
+                                       default:
+                                               is_const = FALSE;
+                                               break;
+                                       }
+                               }
+
+                               if (!is_const) {
+                                       MonoInst *load;
+                                       CHECK_STACK_OVF (1);
+                                       MONO_INST_NEW (cfg, load, mono_type_to_ldind (field->type));
+                                       type_to_eval_stack_type (field->type, load);
+                                       load->cil_code = ip;
+                                       load->inst_left = ins;
+                                       *sp++ = load;
+                                       load->flags |= ins_flag;
+                                       ins_flag = 0;
+                                       /* fixme: dont see the problem why this does not work */
+                                       //cfg->disable_aot = TRUE;
+                               }
                        }
                        ip += 5;
                        break;
@@ -3345,7 +4134,22 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                klass = mono_class_get (image, token);
                        mono_class_init (klass);
-                       handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+                       n = mono_type_to_stind (&klass->byval_arg);
+                       if (n == CEE_STOBJ) {
+                               handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
+                       } else {
+                               /* FIXME: should check item at sp [1] is compatible with the type of the store. */
+                               MonoInst *store;
+                               MONO_INST_NEW (cfg, store, n);
+                               store->cil_code = ip;
+                               store->inst_left = sp [0];
+                               store->inst_right = sp [1];
+                               store->flags |= ins_flag;
+                               MONO_ADD_INS (bblock, store);
+                       }
+                       ins_flag = 0;
                        ip += 5;
                        inline_costs += 1;
                        break;
@@ -3362,12 +4166,28 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        else
                                klass = mono_class_get (image, token);
                        mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
 
+                       if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               *sp = val;
+                               ip += 5;
+                               break;
+                       }
                        /* much like NEWOBJ */
-                       NEW_DOMAINCONST (cfg, iargs [0]);
-                       NEW_CLASSCONST (cfg, iargs [1], klass);
-                       
-                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+                       if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+                               NEW_DOMAINCONST (cfg, iargs [0]);
+                               NEW_CLASSCONST (cfg, iargs [1], klass);
+
+                               temp = mono_emit_jit_icall (cfg, bblock, mono_object_new, iargs, ip);
+                       } else {
+                               MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
+                               NEW_PCONST (cfg, iargs [0], vtable);
+                               if (1 || klass->has_finalize || (cfg->prof_options & MONO_PROFILE_ALLOCATIONS))
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
+                               else
+                                       temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_fast, iargs, ip);
+                       }
                        NEW_TEMPLOAD (cfg, load, temp);
                        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
                        MONO_INST_NEW (cfg, add, CEE_ADD);
@@ -3401,7 +4221,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)
@@ -3410,6 +4230,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                klass = mono_class_get (image, token);
 
                        mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
                        ins->inst_newa_class = klass;
                        ins->inst_newa_len = *sp;
                        ins->type = STACK_OBJ;
@@ -3431,11 +4253,32 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        sp -= 2;
                        klass = mono_class_get (image, read32 (ip + 1));
                        mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
                        NEW_LDELEMA (cfg, ins, sp, klass);
                        ins->cil_code = ip;
                        *sp++ = ins;
                        ip += 5;
                        break;
+               case CEE_LDELEM: {
+                       MonoInst *load;
+                       CHECK_STACK (2);
+                       sp -= 2;
+                       token = read32 (ip + 1);
+                       klass = mono_class_get (image, token);
+                       mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+                       NEW_LDELEMA (cfg, load, sp, klass);
+                       load->cil_code = ip;
+                       MONO_INST_NEW (cfg, ins, mono_type_to_ldind (&klass->byval_arg));
+                       ins->cil_code = ip;
+                       ins->inst_left = load;
+                       *sp++ = ins;
+                       type_to_eval_stack_type (&klass->byval_arg, ins);
+                       ip += 5;
+                       break;
+               }
                case CEE_LDELEM_I1:
                case CEE_LDELEM_U1:
                case CEE_LDELEM_I2:
@@ -3472,8 +4315,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:
@@ -3492,7 +4334,73 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ++ip;
                        handle_loaded_temps (cfg, bblock, stack_start, sp);
                        MONO_ADD_INS (bblock, ins);
-                       /* FIXME: add the implicit STELEM_REF castclass */
+                       inline_costs += 1;
+                       cfg->disable_ssa = TRUE;
+                       break;
+               }
+               case CEE_STELEM: {
+                       MonoInst *load;
+                       /*
+                        * translate to:
+                        * stind.x (ldelema (array, index), val)
+                        * ldelema does the bounds check
+                        */
+                       CHECK_STACK (3);
+                       sp -= 3;
+                       token = read32 (ip + 1);
+                       klass = mono_class_get (image, token);
+                       mono_class_init (klass);
+                       if (klass->byval_arg.type == MONO_TYPE_VAR)
+                               klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+                       if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                               MonoInst *iargs [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);
+                       } else {
+                               NEW_LDELEMA (cfg, load, sp, klass);
+                               load->cil_code = ip;
+                               MONO_INST_NEW (cfg, ins, mono_type_to_stind (&klass->byval_arg));
+                               ins->cil_code = ip;
+                               ins->inst_left = load;
+                               ins->inst_right = sp [2];
+                               handle_loaded_temps (cfg, bblock, stack_start, sp);
+                               MONO_ADD_INS (bblock, ins);
+                       }
+                       ip += 5;
+                       inline_costs += 1;
+                       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;
@@ -3536,7 +4444,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];
 
@@ -3596,7 +4504,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 {
@@ -3614,14 +4523,18 @@ 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_CALL_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;
@@ -3637,8 +4550,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);
@@ -3852,9 +4765,24 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
                case CEE_PREFIX1: {
                        switch (ip [1]) {
-                       case CEE_ARGLIST:
-                               g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
+                       case CEE_ARGLIST: {
+                               /* somewhat similar to LDTOKEN */
+                               MonoInst *addr, *vtvar;
+                               CHECK_STACK_OVF (1);
+                               vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
+
+                               NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
+                               addr->cil_code = ip;
+                               MONO_INST_NEW (cfg, ins, OP_ARGLIST);
+                               ins->cil_code = ip;
+                               ins->inst_left = addr;
+                               MONO_ADD_INS (bblock, ins);
+                               NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
+                               ins->cil_code = ip;
+                               *sp++ = ins;
+                               ip += 2;
                                break;
+                       }
                        case CEE_CEQ:
                        case CEE_CGT:
                        case CEE_CGT_UN:
@@ -3886,9 +4814,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);
 
@@ -4048,10 +4984,31 @@ 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);
-                               handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
+                               if (klass->byval_arg.type == MONO_TYPE_VAR)
+                                       klass = TYPE_PARAM_TO_CLASS (klass->byval_arg.data.type_param);
+                               if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
+                                       MonoInst *store, *load;
+                                       NEW_PCONST (cfg, load, NULL);
+                                       load->cil_code = ip;
+                                       load->type = STACK_OBJ;
+                                       MONO_INST_NEW (cfg, store, CEE_STIND_REF);
+                                       store->cil_code = ip;
+                                       handle_loaded_temps (cfg, bblock, stack_start, sp);
+                                       MONO_ADD_INS (bblock, store);
+                                       store->inst_i0 = sp [0];
+                                       store->inst_i1 = load;
+                                       break;
+                               } else {
+                                       handle_initobj (cfg, bblock, *sp, NULL, klass, stack_start, sp);
+                               }
                                ip += 6;
                                inline_costs += 1;
                                break;
+                       case CEE_CONSTRAINED_:
+                               /* FIXME: implement */
+                               token = read32 (ip + 2);
+                               ip += 6;
+                               break;
                        case CEE_CPBLK:
                        case CEE_INITBLK: {
                                MonoInst *iargs [3];
@@ -4070,6 +5027,16 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                inline_costs += 1;
                                break;
                        }
+                       case CEE_NO_:
+                               if (ip [2] & 0x1)
+                                       ins_flag |= MONO_INST_NOTYPECHECK;
+                               if (ip [2] & 0x2)
+                                       ins_flag |= MONO_INST_NORANGECHECK;
+                               /* we ignore the no-nullcheck for now since we
+                                * really do it explicitly only when doing callvirt->call
+                                */
+                               ip += 3;
+                               break;
                        case CEE_RETHROW: {
                                MonoInst *load;
                                /* FIXME: check we are in a catch handler */
@@ -4087,6 +5054,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_SIZEOF:
                                CHECK_STACK_OVF (1);
                                token = read32 (ip + 2);
+                               /* FIXXME: handle generics. */
                                if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
                                        MonoType *type = mono_type_create_from_typespec (image, token);
                                        token = mono_type_size (type, &align);
@@ -4104,6 +5072,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_REFANYTYPE:
                                g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
                                break;
+                       case CEE_READONLY_:
+                               ip += 2;
+                               break;
                        default:
                                g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
                        }
@@ -4198,11 +5169,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:
@@ -4210,6 +5183,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;
 }
 
@@ -4334,12 +5308,25 @@ create_helper_signature (void)
        helper_sig_newarr->params [2] = &mono_defaults.int32_class->byval_arg;
        helper_sig_newarr->pinvoke = 1;
 
+       /* MonoArray * mono_array_new_specific (MonoVTable *vtable, guint32 len) */
+       helper_sig_newarr_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
+       helper_sig_newarr_specific->params [0] = &mono_defaults.int_class->byval_arg;
+       helper_sig_newarr_specific->params [1] = &mono_defaults.int32_class->byval_arg;
+       helper_sig_newarr_specific->ret = &mono_defaults.object_class->byval_arg;
+       helper_sig_newarr_specific->pinvoke = 1;
+
        /* MonoObject * mono_object_new (MonoDomain *domain, MonoClass *klass) */
        helper_sig_object_new = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
        helper_sig_object_new->params [0] = helper_sig_object_new->params [1] = &mono_defaults.int_class->byval_arg;
        helper_sig_object_new->ret = &mono_defaults.object_class->byval_arg;
        helper_sig_object_new->pinvoke = 1;
 
+       /* MonoObject * mono_object_new_specific (MonoVTable *vtable) */
+       helper_sig_object_new_specific = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+       helper_sig_object_new_specific->params [0] = &mono_defaults.int_class->byval_arg;
+       helper_sig_object_new_specific->ret = &mono_defaults.object_class->byval_arg;
+       helper_sig_object_new_specific->pinvoke = 1;
+
        /* void* mono_method_compile (MonoMethod*) */
        helper_sig_compile = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
        helper_sig_compile->params [0] = helper_sig_compile->ret = &mono_defaults.int_class->byval_arg;
@@ -4363,6 +5350,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] = 
@@ -4421,6 +5416,12 @@ create_helper_signature (void)
        helper_sig_ptr_obj->ret = &mono_defaults.int_class->byval_arg;
        helper_sig_ptr_obj->pinvoke = 1;
 
+       /* IntPtr  amethod (int) */
+       helper_sig_ptr_int = mono_metadata_signature_alloc (mono_defaults.corlib, 1);
+       helper_sig_ptr_int->params [0] = &mono_defaults.int32_class->byval_arg;
+       helper_sig_ptr_int->ret = &mono_defaults.int_class->byval_arg;
+       helper_sig_ptr_int->pinvoke = 1;
+
        /* long amethod (long, guint32) */
        helper_sig_long_long_int = mono_metadata_signature_alloc (mono_defaults.corlib, 2);
        helper_sig_long_long_int->params [0] = &mono_defaults.int64_class->byval_arg;
@@ -4476,27 +5477,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;
 
@@ -4517,12 +5497,25 @@ mono_find_jit_icall_by_addr (gconstpointer addr)
        return g_hash_table_lookup (jit_icall_hash_addr, (gpointer)addr);
 }
 
+gconstpointer
+mono_icall_get_wrapper (MonoJitICallInfo* callinfo)
+{
+       char *name;
+       MonoMethod *wrapper;
+       
+       if (callinfo->wrapper)
+               return callinfo->wrapper;
+       name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
+       wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func);
+       callinfo->wrapper = mono_jit_compile_method (wrapper);
+       g_free (name);
+       return callinfo->wrapper;
+}
+
 MonoJitICallInfo *
 mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignature *sig, gboolean is_save)
 {
        MonoJitICallInfo *info;
-       MonoMethod *wrapper;
-       char *n;
        
        g_assert (func);
        g_assert (name);
@@ -4539,7 +5532,7 @@ mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignatu
 
        info = g_new (MonoJitICallInfo, 1);
        
-       info->name = g_strdup (name);
+       info->name = name;
        info->func = func;
        info->sig = sig;
                
@@ -4550,14 +5543,11 @@ mono_register_jit_icall (gconstpointer func, const char *name, MonoMethodSignatu
            ) {
                info->wrapper = func;
        } else {
-               g_assert (sig);
-               n = g_strdup_printf ("__icall_wrapper_%s", name);       
-               wrapper = mono_marshal_get_icall_wrapper (sig, n, func);
-               info->wrapper = mono_jit_compile_method (wrapper);
-               g_free (n);
+               info->wrapper = NULL;
+               mono_icall_get_wrapper (info);
        }
 
-       g_hash_table_insert (jit_icall_hash_name, info->name, info);
+       g_hash_table_insert (jit_icall_hash_name, (gpointer)info->name, info);
        g_hash_table_insert (jit_icall_hash_addr, (gpointer)func, info);
        if (func != info->wrapper)
                g_hash_table_insert (jit_icall_hash_addr, (gpointer)info->wrapper, info);
@@ -4577,10 +5567,9 @@ mono_find_jit_opcode_emulation (int opcode)
 }
 
 void
-mono_register_opcode_emulation (int opcode, MonoMethodSignature *sig, gpointer func)
+mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
 {
        MonoJitICallInfo *info;
-       char *name;
 
        if (!emul_opcode_hash)
                emul_opcode_hash = g_hash_table_new (NULL, NULL);
@@ -4588,11 +5577,7 @@ mono_register_opcode_emulation (int opcode, MonoMethodSignature *sig, gpointer f
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
 
-       name = g_strdup_printf ("__emulate_%s",  mono_inst_name (opcode));
-
-       info = mono_register_jit_icall (func, name, sig, FALSE);
-
-       g_free (name);
+       info = mono_register_jit_icall (func, name, sig, no_throw);
 
        g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
 }
@@ -4601,22 +5586,38 @@ static void
 decompose_foreach (MonoInst *tree, gpointer data) 
 {
        static MonoJitICallInfo *newarr_info = NULL;
+       static MonoJitICallInfo *newarr_specific_info = NULL;
+       MonoJitICallInfo *info;
 
        switch (tree->opcode) {
        case CEE_NEWARR: {
                MonoCompile *cfg = data;
                MonoInst *iargs [3];
 
-               NEW_DOMAINCONST (cfg, iargs [0]);
-               NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
-               iargs [2] = tree->inst_newa_len;
-
                if (!newarr_info) {
-                       newarr_info =  mono_find_jit_icall_by_addr (mono_array_new);
+                       newarr_info = mono_find_jit_icall_by_addr (mono_array_new);
                        g_assert (newarr_info);
+                       newarr_specific_info = mono_find_jit_icall_by_addr (mono_array_new_specific);
+                       g_assert (newarr_specific_info);
+               }
+
+               if ((cfg->opt & MONO_OPT_SHARED) || mono_compile_aot) {
+                       NEW_DOMAINCONST (cfg, iargs [0]);
+                       NEW_CLASSCONST (cfg, iargs [1], tree->inst_newa_class);
+                       iargs [2] = tree->inst_newa_len;
+
+                       info = newarr_info;
+               }
+               else {
+                       MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (tree->inst_newa_class, 1));
+
+                       NEW_PCONST (cfg, iargs [0], vtable);
+                       iargs [1] = tree->inst_newa_len;
+
+                       info = newarr_specific_info;
                }
 
-               mono_emulate_opcode (cfg, tree, iargs, newarr_info);
+               mono_emulate_opcode (cfg, tree, iargs, info);
                break;
        }
 
@@ -4764,10 +5765,15 @@ mono_bblock_add_inst (MonoBasicBlock *bb, MonoInst *inst)
 void
 mono_destroy_compile (MonoCompile *cfg)
 {
-
        //mono_mempool_stats (cfg->mempool);
        g_hash_table_destroy (cfg->bb_hash);
+       if (cfg->rs)
+               mono_regstate_free (cfg->rs);
        mono_mempool_destroy (cfg->mempool);
+       g_list_free (cfg->ldstr_list);
+
+       g_free (cfg->varinfo);
+       g_free (cfg->vars);
        g_free (cfg);
 }
 
@@ -4794,28 +5800,40 @@ mono_thread_abort (MonoObject *obj)
 {
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
        
-       g_free (jit_tls);
+       /* handle_remove should be eventually called for this thread, too
+       g_free (jit_tls);*/
 
        ExitThread (-1);
 }
 
 static void
-mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
+setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 {
        MonoJitTlsData *jit_tls;
        MonoLMF *lmf;
+       MonoThread *thread;
 
        jit_tls = g_new0 (MonoJitTlsData, 1);
 
        TlsSetValue (mono_jit_tls_id, jit_tls);
 
-       jit_tls->abort_func = mono_thread_abort;
+       jit_tls->abort_func = abort_func;
        jit_tls->end_of_stack = stack_start;
 
        lmf = g_new0 (MonoLMF, 1);
        lmf->ebp = -1;
 
-       jit_tls->lmf = lmf;
+       jit_tls->lmf = jit_tls->first_lmf = lmf;
+
+       thread = mono_thread_current ();
+       if (thread)
+               thread->jit_data = jit_tls;
+}
+
+static void
+mono_thread_start_cb (guint32 tid, gpointer stack_start, gpointer func)
+{
+       setup_jit_tls_data (stack_start, mono_thread_abort);
 }
 
 void (*mono_thread_attach_aborted_cb ) (MonoObject *obj) = NULL;
@@ -4832,20 +5850,19 @@ mono_thread_abort_dummy (MonoObject *obj)
 static void
 mono_thread_attach_cb (guint32 tid, gpointer stack_start)
 {
-       MonoJitTlsData *jit_tls;
-       MonoLMF *lmf;
-
-       jit_tls = g_new0 (MonoJitTlsData, 1);
-
-       TlsSetValue (mono_jit_tls_id, jit_tls);
-
-       jit_tls->abort_func = mono_thread_abort_dummy;
-       jit_tls->end_of_stack = stack_start;
+       setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
+}
 
-       lmf = g_new0 (MonoLMF, 1);
-       lmf->ebp = -1;
+static void
+mini_thread_cleanup (MonoThread *thread)
+{
+       MonoJitTlsData *jit_tls = thread->jit_data;
 
-       jit_tls->lmf = lmf;
+       if (jit_tls) {
+               g_free (jit_tls->first_lmf);
+               g_free (jit_tls);
+               thread->jit_data = NULL;
+       }
 }
 
 void
@@ -4893,8 +5910,20 @@ dec_foreach (MonoInst *tree, MonoCompile *cfg) {
                }
 
                break;
-       case 2: 
-               if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
+       case 2:
+               if (tree->opcode == OP_LMUL
+                               && (cfg->opt & MONO_OPT_INTRINS)
+                               && (tree->inst_left->opcode == CEE_CONV_I8 
+                                       || tree->inst_left->opcode == CEE_CONV_U8)
+                               && tree->inst_left->inst_left->type == STACK_I4
+                               && (tree->inst_right->opcode == CEE_CONV_I8 
+                                       || tree->inst_right->opcode == CEE_CONV_U8)
+                               && tree->inst_right->inst_left->type == STACK_I4) {
+                       tree->opcode = (tree->inst_left->opcode == CEE_CONV_I8 ? OP_BIGMUL: OP_BIGMUL_UN);
+                       tree->inst_left = tree->inst_left->inst_left;
+                       tree->inst_right = tree->inst_right->inst_left;
+                       dec_foreach (tree, cfg);
+               } else if ((info = mono_find_jit_opcode_emulation (tree->opcode))) {
                        MonoInst *iargs [2];
                
                        iargs [0] = tree->inst_i0;
@@ -4940,6 +5969,47 @@ nullify_basic_block (MonoBasicBlock *bb)
        bb->out_bb = NULL;
        bb->next_bb = NULL;
        bb->code = bb->last_ins = NULL;
+       bb->cil_code = NULL;
+}
+
+static void 
+replace_out_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *repl)
+{
+       int i;
+
+       for (i = 0; i < bb->out_count; i++) {
+               MonoBasicBlock *ob = bb->out_bb [i];
+               if (ob == orig) {
+                       if (!repl) {
+                               if (bb->out_count > 1) {
+                                       bb->out_bb [i] = bb->out_bb [bb->out_count - 1];
+                               }
+                               bb->out_count--;
+                       } else {
+                               bb->out_bb [i] = repl;
+                       }
+               }
+       }
+}
+
+static void 
+replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
+{
+       int i;
+
+       for (i = 0; i < bb->in_count; i++) {
+               MonoBasicBlock *ib = bb->in_bb [i];
+               if (ib == orig) {
+                       if (!repl) {
+                               if (bb->in_count > 1) {
+                                       bb->in_bb [i] = bb->in_bb [bb->in_count - 1];
+                               }
+                               bb->in_count--;
+                       } else {
+                               bb->in_bb [i] = repl;
+                       }
+               }
+       }
 }
 
 static void 
@@ -4950,13 +6020,15 @@ replace_basic_block (MonoBasicBlock *bb, MonoBasicBlock *orig,  MonoBasicBlock *
        for (i = 0; i < bb->out_count; i++) {
                MonoBasicBlock *ob = bb->out_bb [i];
                for (j = 0; j < ob->in_count; j++) {
-                       if (ob->in_bb [j] == orig)
+                       if (ob->in_bb [j] == orig) {
                                ob->in_bb [j] = repl;
+                       }
                }
        }
 
 }
 
+
 static void
 merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn) 
 {
@@ -4980,7 +6052,7 @@ merge_basic_blocks (MonoBasicBlock *bb, MonoBasicBlock *bbn)
 
 static void
 optimize_branches (MonoCompile *cfg) {
-       int changed = FALSE;
+       int i, changed = FALSE;
        MonoBasicBlock *bb, *bbn;
 
        do {
@@ -4989,27 +6061,46 @@ 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 ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
+                               if (cfg->verbose_level > 2)
+                                       g_print ("nullify block triggered %d\n", bbn->block_num);
+
+                               bb->next_bb = bbn->next_bb;
+
+                               for (i = 0; i < bbn->out_count; i++)
+                                       replace_in_block (bbn->out_bb [i], bbn, NULL);
+
+                               nullify_basic_block (bbn);                      
+                               changed = TRUE;
+                       }
+
                        if (bb->out_count == 1) {
                                bbn = bb->out_bb [0];
 
+                               /* conditional branches where true and false targets are the same can be also replaced with CEE_BR */
+                               if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
+                                       bb->last_ins->opcode = CEE_BR;
+                                       bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
+                                       changed = TRUE;
+                                       if (cfg->verbose_level > 2)
+                                               g_print ("cond branch removal triggered in %d %d\n", bb->block_num, bb->out_count);
+                               }
+
                                if (bb->region == bbn->region && bb->next_bb == bbn) {
-                               /* the block are in sequence anyway ... */
+                                       /* the block are in sequence anyway ... */
 
-                                       /* 
-                                        * miguel: I do not understand what the test below does, could we
-                                        * use a macro, or a comment here?  opcode > CEE_BEQ && <= BLT_UN
-                                        *
-                                        * It could also test for bb->last_in only once, and the value
-                                        * could be cached (last_ins->opcode)
-                                        */
-                                       if (bb->last_ins && (bb->last_ins->opcode == CEE_BR || (
-                                               (bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN)))) {
+                                       /* branches to the following block can be removed */
+                                       if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
                                                bb->last_ins->opcode = CEE_NOP;
                                                changed = TRUE;
                                                if (cfg->verbose_level > 2)
                                                        g_print ("br removal triggered %d -> %d\n", bb->block_num, bbn->block_num);
                                        }
-                                       /* fixme: this causes problems with inlining */
+
                                        if (bbn->in_count == 1) {
 
                                                if (bbn != cfg->bb_exit) {
@@ -5021,39 +6112,102 @@ optimize_branches (MonoCompile *cfg) {
 
                                                //mono_print_bb_code (bb);
                                        }
-                               } else {
-                                       if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
-                                               bbn = bb->last_ins->inst_target_bb;
-                                               if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
-                                                       /*
-                                                       if (cfg->verbose_level > 2)
-                                                               g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, bb->block_num, bbn->block_num);
-                                                       bb->out_bb [0] = bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
-                                                       changed = TRUE;*/
-                                               }
+                               }                               
+                       }
+               }
+       } while (changed);
+
+       do {
+               changed = FALSE;
+
+               /* we skip the entry block (exit is handled specially instead ) */
+               for (bb = cfg->bb_entry->next_bb; bb; bb = bb->next_bb) {
+
+                       /* dont touch code inside exception clauses */
+                       if (bb->region != -1)
+                               continue;
+
+                       if ((bbn = bb->next_bb) && bbn->in_count == 0 && bb->region == bbn->region) {
+                               if (cfg->verbose_level > 2) {
+                                       g_print ("nullify block triggered %d\n", bbn->block_num);
+                               }
+                               bb->next_bb = bbn->next_bb;
+
+                               for (i = 0; i < bbn->out_count; i++)
+                                       replace_in_block (bbn->out_bb [i], bbn, NULL);
+
+                               nullify_basic_block (bbn);                      
+                               changed = TRUE;
+                               break;
+                       }
+
+
+                       if (bb->out_count == 1) {
+                               bbn = bb->out_bb [0];
+
+                               if (bb->last_ins && bb->last_ins->opcode == CEE_BR) {
+                                       bbn = bb->last_ins->inst_target_bb;
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                           bbn->code->inst_target_bb->region == bb->region) {
+                                               
+                                               if (cfg->verbose_level > 2)
+                                                       g_print ("in %s branch to branch triggered %d -> %d\n", cfg->method->name, 
+                                                                bb->block_num, bbn->block_num);
+                                               
+                                               replace_basic_block (bb, bb->out_bb [0], bbn->code->inst_target_bb);
+                                               bb->last_ins->inst_target_bb = bbn->code->inst_target_bb;
+                                               changed = TRUE;
+                                               break;
                                        }
                                }
                        } else if (bb->out_count == 2) {
-                               /* fixme: this does not correctly unlink the blocks, so we get serious problems in idom code */
-                               if (0 && bb->last_ins && bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
+                               if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode)) {
                                        bbn = bb->last_ins->inst_true_bb;
-                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR) {
-                                               if (cfg->verbose_level > 2)
-                                                       g_print ("cbranch to branch triggered %d -> %d (0x%02x)\n", bb->block_num, 
-                                                                bbn->block_num, bbn->code->opcode);
-                                                
-                                               if (bb->out_bb [0] == bbn) {
-                                                       bb->out_bb [0] = bbn->code->inst_target_bb;
-                                               } else if (bb->out_bb [1] == bbn) {
-                                                       bb->out_bb [1] = bbn->code->inst_target_bb;
-                                               }
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                           bbn->code->inst_target_bb->region == bb->region) {
+                                               if (cfg->verbose_level > 2)             
+                                                       g_print ("cbranch1 to branch triggered %d -> (%d) %d (0x%02x)\n", 
+                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
+                                                                bbn->code->opcode);
+
                                                bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
+
+                                               replace_in_block (bbn, bb, NULL);
+                                               if (!bbn->in_count)
+                                                       replace_in_block (bbn->code->inst_target_bb, bbn, bb);
+                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+
+                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+
+                                               changed = TRUE;
+                                               break;
+                                       }
+
+                                       bbn = bb->last_ins->inst_false_bb;
+                                       if (bb->region == bbn->region && bbn->code && bbn->code->opcode == CEE_BR &&
+                                           bbn->code->inst_target_bb->region == bb->region) {
+                                               if (cfg->verbose_level > 2)
+                                                       g_print ("cbranch2 to branch triggered %d -> (%d) %d (0x%02x)\n", 
+                                                                bb->block_num, bbn->block_num, bbn->code->inst_target_bb->block_num, 
+                                                                bbn->code->opcode);
+
+                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
+
+                                               replace_in_block (bbn, bb, NULL);
+                                               if (!bbn->in_count)
+                                                       replace_in_block (bbn->code->inst_target_bb, bbn, bb);
+                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+
+                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+
                                                changed = TRUE;
+                                               break;
                                        }
                                }
                        }
                }
        } while (changed);
+
 }
 
 static void
@@ -5073,6 +6227,8 @@ mono_compile_create_vars (MonoCompile *cfg)
                cfg->ret->inst_vtype = sig->ret;
                cfg->ret->klass = mono_class_from_mono_type (sig->ret);
        }
+       if (cfg->verbose_level > 2)
+               g_print ("creating vars\n");
 
        if (sig->hasthis)
                mono_compile_create_var (cfg, &cfg->method->klass->this_arg, OP_ARG);
@@ -5082,8 +6238,12 @@ mono_compile_create_vars (MonoCompile *cfg)
 
        cfg->locals_start = cfg->num_varinfo;
 
+       if (cfg->verbose_level > 2)
+               g_print ("creating locals\n");
        for (i = 0; i < header->num_locals; ++i)
                mono_compile_create_var (cfg, header->locals [i], OP_LOCAL);
+       if (cfg->verbose_level > 2)
+               g_print ("locals done\n");
 }
 
 #if 0
@@ -5164,11 +6324,49 @@ emit_state (MonoCompile *cfg, MBState *state, int goal)
 static void 
 mini_select_instructions (MonoCompile *cfg)
 {
+       static int reverse_map [] = {
+               CEE_BNE_UN, CEE_BLT, CEE_BLE, CEE_BGT, CEE_BGE,
+               CEE_BEQ, CEE_BLT_UN, CEE_BLE_UN, CEE_BGT_UN, CEE_BGE_UN
+       };
+       static int reverse_fmap [] = {
+               OP_FBNE_UN, OP_FBLT, OP_FBLE, OP_FBGT, OP_FBGE,
+               OP_FBEQ, OP_FBLT_UN, OP_FBLE_UN, OP_FBGT_UN, OP_FBGE_UN
+       };
+       static int reverse_lmap [] = {
+               OP_LBNE_UN, OP_LBLT, OP_LBLE, OP_LBGT, OP_LBGE,
+               OP_LBEQ, OP_LBLT_UN, OP_LBLE_UN, OP_LBGT_UN, OP_LBGE_UN
+       };
+
        MonoBasicBlock *bb;
        
        cfg->state_pool = mono_mempool_new ();
        cfg->rs = mono_regstate_new ();
 
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (bb->last_ins && MONO_IS_COND_BRANCH (bb->last_ins->opcode) &&
+                   bb->next_bb != bb->last_ins->inst_false_bb) {
+
+                       if (bb->next_bb ==  bb->last_ins->inst_true_bb) {
+                               MonoBasicBlock *tmp =  bb->last_ins->inst_true_bb;
+                               bb->last_ins->inst_true_bb = bb->last_ins->inst_false_bb;
+                               bb->last_ins->inst_false_bb = tmp;
+                               
+                               if (bb->last_ins->opcode >= CEE_BEQ && bb->last_ins->opcode <= CEE_BLT_UN) {
+                                       bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
+                               } else if (bb->last_ins->opcode >= OP_FBEQ && bb->last_ins->opcode <= OP_FBLT_UN) {
+                                       bb->last_ins->opcode = reverse_fmap [bb->last_ins->opcode - OP_FBEQ];
+                               } else if (bb->last_ins->opcode >= OP_LBEQ && bb->last_ins->opcode <= OP_LBLT_UN) {
+                                       bb->last_ins->opcode = reverse_lmap [bb->last_ins->opcode - OP_LBEQ];
+                               }
+                       } else {                        
+                               MonoInst *inst = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst));
+                               inst->opcode = CEE_BR;
+                               inst->inst_target_bb = bb->last_ins->inst_false_bb;
+                               mono_bblock_add_inst (bb, inst);
+                       }
+               }
+       }
+
 #ifdef DEBUG_SELECTION
        if (cfg->verbose_level >= 4) {
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
@@ -5243,12 +6441,12 @@ mono_codegen (MonoCompile *cfg)
                mono_arch_local_regalloc (cfg, bb);
        }
 
-       if (mono_trace_coverage)
-               mono_allocate_coverage_info (cfg->method, cfg->num_bblocks);
+       if (cfg->prof_options & MONO_PROFILE_COVERAGE)
+               cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks);
 
        code = mono_arch_emit_prolog (cfg);
 
-       if (mono_jit_profile)
+       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
                code = mono_arch_instrument_prolog (cfg, mono_profiler_method_enter, code, FALSE);
 
        cfg->code_len = code - cfg->native_code;
@@ -5279,8 +6477,8 @@ mono_codegen (MonoCompile *cfg)
        /* g_assert (((int)cfg->native_code & (MONO_ARCH_CODE_ALIGNMENT - 1)) == 0); */
 
        cfg->epilog_begin = cfg->code_len;
-       
-       if (mono_jit_profile)
+
+       if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
                code = mono_arch_instrument_epilog (cfg, mono_profiler_method_leave, code, FALSE);
 
        cfg->code_len = code - cfg->native_code;
@@ -5516,24 +6714,31 @@ 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_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)
+               mono_profiler_method_jit (method);
 
        cfg = g_new0 (MonoCompile, 1);
        cfg->method = method;
        cfg->mempool = mono_mempool_new ();
        cfg->opt = opts;
+       cfg->prof_options = mono_profiler_get_events ();
        cfg->bb_hash = g_hash_table_new (g_direct_hash, NULL);
        cfg->domain = domain;
        cfg->verbose_level = mini_verbose;
+       cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
+                                           ((MonoMethodNormal *)method)->header->max_stack);
+
+       if (cfg->verbose_level > 2)
+               g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
 
        /*
         * create MonoInst* which represents arguments and local variables
         */
        mono_compile_create_vars (cfg);
 
-       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) {
+               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
+                       mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
                mono_destroy_compile (cfg);
                return NULL;
        }
@@ -5541,6 +6746,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        mono_jit_stats.basic_blocks += cfg->num_bblocks;
        mono_jit_stats.max_basic_blocks = MAX (cfg->num_bblocks, mono_jit_stats.max_basic_blocks);
 
+       if (cfg->num_varinfo > 2000) {
+               /* 
+                * we disable some optimizations if there are too many variables
+                * because JIT time may become too expensive. The actual number needs 
+                * to be tweaked and eventually the non-linear algorithms should be fixed.
+                */
+               cfg->opt &= ~ (MONO_OPT_LINEARS | MONO_OPT_COPYPROP | MONO_OPT_CONSPROP);
+               cfg->disable_ssa = TRUE;
+       }
        /*g_print ("numblocks = %d\n", cfg->num_bblocks);*/
 
        /* Depth-first ordering on basic blocks */
@@ -5551,9 +6765,26 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
 
        df_visit (cfg->bb_entry, &dfn, cfg->bblocks);
        if (cfg->num_bblocks != dfn + 1) {
-               if (cfg->verbose_level > 1)
-                       g_print ("unreachable code?\n");
+               MonoBasicBlock *bb;
+
                cfg->num_bblocks = dfn + 1;
+
+               if (!header->clauses) {
+                       /* remove unreachable code, because the code in them may be 
+                        * inconsistent  (access to dead variables for example) */
+                       for (bb = cfg->bb_entry; bb;) {
+                               MonoBasicBlock *bbn = bb->next_bb;
+
+                               if (bbn && bbn->region == -1 && !bbn->dfn) {
+                                       if (cfg->verbose_level > 1)
+                                               g_print ("found unreachabel code in BB%d\n", bbn->block_num);
+                                       bb->next_bb = bbn->next_bb;
+                                       nullify_basic_block (bbn);                      
+                               } else {
+                                       bb = bb->next_bb;
+                               }
+                       }
+               }
        }
 
        if (cfg->opt & MONO_OPT_LOOP) {
@@ -5619,14 +6850,15 @@ 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 ? */
                cfg->comp_done &= ~MONO_COMP_LIVENESS;
                if (!(cfg->comp_done & MONO_COMP_LIVENESS))
                        mono_analyze_liveness (cfg);
-               
+
                if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
                        regs = mono_arch_get_global_int_regs (cfg);
                        mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
@@ -5634,9 +6866,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        }
 
        //mono_print_code (cfg);
-       
-       //print_dfn (cfg);
 
+       //print_dfn (cfg);
+       
        /* variables are allocated after decompose, since decompose could create temps */
        mono_arch_allocate_vars (cfg);
 
@@ -5686,13 +6918,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;
-
                }
        }
 
@@ -5712,6 +6945,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        }
        mono_jit_stats.native_code_size += cfg->code_len;
 
+       if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
+               mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
+
        return cfg;
 }
 
@@ -5724,7 +6960,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;
@@ -5796,8 +7032,23 @@ mono_jit_compile_method (MonoMethod *method)
 
        g_hash_table_insert (jit_code_hash, method, code);
 
+       if (target_domain->jump_target_hash) {
+               MonoJumpInfo patch_info;
+               GSList *list, *tmp;
+               list = g_hash_table_lookup (target_domain->jump_target_hash, method);
+               if (list) {
+                       patch_info.next = NULL;
+                       patch_info.ip.i = 0;
+                       patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
+                       patch_info.data.method = method;
+                       g_hash_table_remove (target_domain->jump_target_hash, method);
+               }
+               for (tmp = list; tmp; tmp = tmp->next)
+                       mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info);
+               g_slist_free (list);
+       }
        /* make sure runtime_init is called */
-       mono_class_vtable (target_domain, method->klass);
+       mono_runtime_class_init (mono_class_vtable (target_domain, method->klass));
 
        return code;
 }
@@ -5873,6 +7124,18 @@ sigusr1_signal_handler (int _dummy)
        mono_arch_handle_exception (ctx, thread->abort_exc, FALSE);
 }
 
+static void
+sigquit_signal_handler (int _dummy)
+{
+       MonoException *exc;
+       GET_CONTEXT
+
+       exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
+       
+       mono_arch_handle_exception (ctx, exc, FALSE);
+}
+
+
 static void
 mono_runtime_install_handlers (void)
 {
@@ -5899,6 +7162,12 @@ mono_runtime_install_handlers (void)
        //g_assert (syscall (SYS_sigaction, SIGFPE, &sa, NULL) != -1);
        g_assert (sigaction (SIGFPE, &sa, NULL) != -1);
 
+       /* catch SIGQUIT */
+       sa.sa_handler = sigquit_signal_handler;
+       sigemptyset (&sa.sa_mask);
+       sa.sa_flags = 0;
+       g_assert (sigaction (SIGQUIT, &sa, NULL) != -1);
+
        /* catch SIGILL */
        sa.sa_handler = sigill_signal_handler;
        sigemptyset (&sa.sa_mask);
@@ -5938,7 +7207,8 @@ mono_jit_create_remoting_trampoline (MonoMethod *method)
        MonoMethod *nm;
        guint8 *addr = NULL;
 
-       if (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class)) {
+       if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || 
+           (method->signature->hasthis && (method->klass->marshalbyref || method->klass == mono_defaults.object_class))) {
                nm = mono_marshal_get_remoting_invoke (method);
                addr = mono_compile_method (nm);
        } else {
@@ -5947,36 +7217,15 @@ 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;
-       
+
+       mono_arch_cpu_init ();
+
        metadata_section = &ms;
        InitializeCriticalSection (metadata_section);
 
@@ -5986,6 +7235,7 @@ mini_init (const char *filename)
        mono_burg_init ();
 
        mono_runtime_install_handlers ();
+       mono_threads_install_cleanup (mini_thread_cleanup);
 
        mono_install_compile_method (mono_jit_compile_method);
        mono_install_trampoline (mono_arch_create_jit_trampoline);
@@ -6023,46 +7273,30 @@ 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
         * rule to the burg files, because we need the arity information to be correct.
         */
-       mono_register_opcode_emulation (OP_LMUL, helper_sig_long_long_long, mono_llmult);
-       mono_register_opcode_emulation (OP_LMUL_OVF_UN, helper_sig_long_long_long, mono_llmult_ovf_un);
-       mono_register_opcode_emulation (OP_LMUL_OVF, helper_sig_long_long_long, mono_llmult_ovf);
-       mono_register_opcode_emulation (OP_LDIV, helper_sig_long_long_long, mono_lldiv);
-       mono_register_opcode_emulation (OP_LDIV_UN, helper_sig_long_long_long, mono_lldiv_un);
-       mono_register_opcode_emulation (OP_LREM, helper_sig_long_long_long, mono_llrem);
-       mono_register_opcode_emulation (OP_LREM_UN, helper_sig_long_long_long, mono_llrem_un);
-
-       mono_register_opcode_emulation (OP_LSHL, helper_sig_long_long_int, mono_lshl);
-       mono_register_opcode_emulation (OP_LSHR, helper_sig_long_long_int, mono_lshr);
-       mono_register_opcode_emulation (OP_LSHR_UN, helper_sig_long_long_int, mono_lshr_un);
-
-       mono_register_opcode_emulation (OP_FCONV_TO_U8, helper_sig_ulong_double, mono_fconv_u8);
-       mono_register_opcode_emulation (OP_FCONV_TO_U4, helper_sig_uint_double, mono_fconv_u4);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, helper_sig_long_double, mono_fconv_ovf_i8);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, helper_sig_ulong_double, mono_fconv_ovf_u8);
+       mono_register_opcode_emulation (OP_LMUL, "__emul_lmul", helper_sig_long_long_long, mono_llmult, TRUE);
+       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un, FALSE);
+       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf, FALSE);
+       mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv, FALSE);
+       mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un, FALSE);
+       mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem, FALSE);
+       mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un, FALSE);
+
+       mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl, TRUE);
+       mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr, TRUE);
+       mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un, TRUE);
+
+       mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4, FALSE);
+       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8, TRUE);
+       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", helper_sig_ulong_double, mono_fconv_ovf_u8, TRUE);
 
 #if SIZEOF_VOID_P == 4
-       mono_register_opcode_emulation (OP_FCONV_TO_U, helper_sig_uint_double, mono_fconv_u4);
+       mono_register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", helper_sig_uint_double, mono_fconv_u4, TRUE);
 #else
 #warning "fixme: add opcode emulation"
 #endif
@@ -6071,12 +7305,17 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_class_static_field_address , "mono_class_static_field_address", 
                                 helper_sig_ptr_ptr_ptr, FALSE);
        mono_register_jit_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", helper_sig_ptr_ptr_ptr, FALSE);
+       mono_register_jit_icall (mono_threads_get_static_data, "mono_threads_get_static_data", helper_sig_ptr_int, FALSE);
        mono_register_jit_icall (mono_ldstr, "mono_ldstr", helper_sig_ldstr, FALSE);
        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_object_new_specific, "mono_object_new_specific", helper_sig_object_new_specific, FALSE);
+       mono_register_jit_icall (mono_object_new_fast, "mono_object_new_fast", helper_sig_object_new_specific, FALSE);
        mono_register_jit_icall (mono_array_new, "mono_array_new", helper_sig_newarr, FALSE);
+       mono_register_jit_icall (mono_array_new_specific, "mono_array_new_specific", helper_sig_newarr_specific, FALSE);
        mono_register_jit_icall (mono_string_to_utf16, "mono_string_to_utf16", helper_sig_ptr_obj, FALSE);
        mono_register_jit_icall (mono_string_from_utf16, "mono_string_from_utf16", helper_sig_obj_ptr, FALSE);
        mono_register_jit_icall (mono_string_new_wrapper, "mono_string_new_wrapper", helper_sig_obj_ptr, FALSE);
@@ -6093,11 +7332,12 @@ mini_init (const char *filename)
        mono_register_jit_icall (mono_string_to_byvalstr, "mono_string_to_byvalstr", helper_sig_void_ptr_ptr_ptr, FALSE);
        mono_register_jit_icall (mono_string_to_byvalwstr, "mono_string_to_byvalwstr", helper_sig_void_ptr_ptr_ptr, FALSE);
        mono_register_jit_icall (g_free, "g_free", helper_sig_void_ptr, FALSE);
+       mono_register_jit_icall (mono_runtime_class_init, "mono_runtime_class_init", helper_sig_void_ptr, FALSE);
        mono_register_jit_icall (mono_ldftn, "mono_ldftn", helper_sig_compile, FALSE);
        mono_register_jit_icall (mono_ldvirtfn, "mono_ldvirtfn", helper_sig_compile_virt, FALSE);
 
-       mono_runtime_init (domain, mono_thread_start_cb,
-                          mono_thread_attach_cb);
+       mono_runtime_install_cleanup ((MonoDomainFunc)mini_cleanup);
+       mono_runtime_init (domain, mono_thread_start_cb, mono_thread_attach_cb);
 
        //mono_thread_attach (domain);
        return domain;
@@ -6141,17 +7381,19 @@ 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 ();
+
 #ifdef PLATFORM_WIN32
        win32_seh_cleanup();
 #endif
@@ -6163,7 +7405,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;