Wed Aug 20 13:04:53 CEST 2003 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / mini / mini.c
index 8973f2c90649d549643a4082437d061b739c5431..fec74a8337a9c1b90b13616b8e8f52e4b103baf3 100644 (file)
@@ -43,6 +43,8 @@
 
 #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);
@@ -91,10 +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;
-
-CRITICAL_SECTION *metadata_section = NULL;
 
 static int mini_verbose = 0;
 
@@ -178,7 +176,7 @@ print_method_from_ip (void *ip)
        method = mono_method_full_name (ji->method, TRUE);
        source = mono_debug_source_location_from_address (ji->method, (int) ip, NULL, domain);
 
-       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);
+       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);
@@ -500,34 +498,6 @@ print_method_from_ip (void *ip)
                (dest)->inst_right = (el2);     \
        } 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;
-
-       return g_hash_table_lookup (coverage_hash, method);
-}
-               
 #if 0
 static gint
 compare_bblock (gconstpointer a, gconstpointer b)
@@ -808,6 +778,10 @@ 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);
        }
@@ -861,6 +835,10 @@ handle_enum:
                return CEE_STOBJ;
        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 0x%02x in type_to_stind", type->type);
        }
@@ -926,6 +904,14 @@ handle_enum:
                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);
        }
@@ -1315,6 +1301,7 @@ mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
                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);
@@ -1808,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));
@@ -1817,15 +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 (!call->args [i]->cil_code)
-                               call->args [i]->cil_code = ip;
-                       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;
 }
@@ -1902,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;
 
@@ -1927,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;
        }
@@ -2048,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;
@@ -2192,6 +2187,13 @@ mini_get_opcode_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
 #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;
        }
@@ -2346,6 +2348,9 @@ inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig,
 #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
 
@@ -2422,6 +2427,19 @@ 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
  */
@@ -2466,6 +2484,12 @@ 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) {
 
@@ -2649,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));
 
@@ -3402,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];
@@ -3415,6 +3505,19 @@ 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);
+                       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);
@@ -3436,6 +3539,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        NEW_TEMPLOAD (cfg, *sp, ins->inst_c0);
                        ++sp;
                        ip += 5;
+                       ins_flag = 0;
                        inline_costs += 1;
                        break;
                }
@@ -3527,7 +3631,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        } else {
                                                MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
                                                NEW_PCONST (cfg, iargs [0], vtable);
-                                               temp = mono_emit_jit_icall (cfg, bblock, mono_object_new_specific, iargs, ip);
+                                               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);
                                }
@@ -3586,6 +3693,73 @@ 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;
 
@@ -3598,6 +3772,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);
 
                        MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
                        ins->type = STACK_OBJ;
@@ -3622,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;
@@ -3661,6 +3839,8 @@ 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;
@@ -3954,6 +4134,8 @@ 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);
                        n = mono_type_to_stind (&klass->byval_arg);
                        if (n == CEE_STOBJ) {
                                handle_stobj (cfg, bblock, sp [0], sp [1], ip, klass, FALSE, FALSE);
@@ -3984,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);
@@ -4032,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;
@@ -4053,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:
@@ -4113,7 +4334,44 @@ 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;
@@ -4510,7 +4768,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        case CEE_ARGLIST: {
                                /* somewhat similar to LDTOKEN */
                                MonoInst *addr, *vtvar;
-                               CHECK_STACK (1);
+                               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);
@@ -4726,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];
@@ -4748,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 */
@@ -4765,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);
@@ -4782,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]);
                        }
@@ -5274,7 +5567,7 @@ mono_find_jit_opcode_emulation (int opcode)
 }
 
 void
-mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func)
+mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignature *sig, gpointer func, gboolean no_throw)
 {
        MonoJitICallInfo *info;
 
@@ -5284,7 +5577,7 @@ mono_register_opcode_emulation (int opcode, const char *name, MonoMethodSignatur
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
 
-       info = mono_register_jit_icall (func, name, sig, FALSE);
+       info = mono_register_jit_icall (func, name, sig, no_throw);
 
        g_hash_table_insert (emul_opcode_hash, (gpointer)opcode, info);
 }
@@ -5316,8 +5609,7 @@ decompose_foreach (MonoInst *tree, gpointer data)
                        info = newarr_info;
                }
                else {
-                       MonoVTable *vtable = mono_class_vtable (cfg->domain, 
-                                                                                                       mono_array_class_get (&tree->inst_newa_class->byval_arg, 1));
+                       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;
@@ -5508,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;
@@ -5546,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
@@ -5616,7 +5919,7 @@ dec_foreach (MonoInst *tree, MonoCompile *cfg) {
                                && (tree->inst_right->opcode == CEE_CONV_I8 
                                        || tree->inst_right->opcode == CEE_CONV_U8)
                                && tree->inst_right->inst_left->type == STACK_I4) {
-                       tree->opcode = OP_BIGMUL;
+                       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);
@@ -5779,7 +6082,7 @@ optimize_branches (MonoCompile *cfg) {
                                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 && 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)) {
                                        bb->last_ins->opcode = CEE_BR;
                                        bb->last_ins->inst_target_bb = bb->last_ins->inst_true_bb;
                                        changed = TRUE;
@@ -5858,7 +6161,7 @@ optimize_branches (MonoCompile *cfg) {
                                        }
                                }
                        } else if (bb->out_count == 2) {
-                               if (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 &&
                                            bbn->code->inst_target_bb->region == bb->region) {
@@ -5924,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);
@@ -5933,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
@@ -6019,6 +6328,14 @@ mini_select_instructions (MonoCompile *cfg)
                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;
        
@@ -6026,14 +6343,21 @@ mini_select_instructions (MonoCompile *cfg)
        cfg->rs = mono_regstate_new ();
 
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               if (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) &&
                    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;
-                               bb->last_ins->opcode = reverse_map [bb->last_ins->opcode - CEE_BEQ];
+                               
+                               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;
@@ -6117,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;
@@ -6154,7 +6478,7 @@ mono_codegen (MonoCompile *cfg)
 
        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;
@@ -6390,37 +6714,47 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        int dfn = 0, i, code_size_ratio;
 
        mono_jit_stats.methods_compiled++;
-       if (mono_jit_profile)
+       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, FALSE)) < 0) {
-               mono_destroy_compile (cfg);
-               if (mono_jit_profile)
+               if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                        mono_profiler_method_end_jit (method, MONO_PROFILE_FAILED);
+               mono_destroy_compile (cfg);
                return NULL;
        }
 
        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 */
@@ -6532,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);
 
@@ -6611,7 +6945,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, int p
        }
        mono_jit_stats.native_code_size += cfg->code_len;
 
-       if (mono_jit_profile)
+       if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION)
                mono_profiler_method_end_jit (method, MONO_PROFILE_OK);
 
        return cfg;
@@ -6790,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)
 {
@@ -6816,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);
@@ -6871,7 +7223,9 @@ MonoDomain *
 mini_init (const char *filename)
 {
        MonoDomain *domain;
-       
+
+       mono_arch_cpu_init ();
+
        metadata_section = &ms;
        InitializeCriticalSection (metadata_section);
 
@@ -6881,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);
@@ -6923,25 +7278,25 @@ mini_init (const char *filename)
         * 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, "__emul_lmul", helper_sig_long_long_long, mono_llmult);
-       mono_register_opcode_emulation (OP_LMUL_OVF_UN, "__emul_lmul_ovf_un", helper_sig_long_long_long, mono_llmult_ovf_un);
-       mono_register_opcode_emulation (OP_LMUL_OVF, "__emul_lmul_ovf", helper_sig_long_long_long, mono_llmult_ovf);
-       mono_register_opcode_emulation (OP_LDIV, "__emul_ldiv", helper_sig_long_long_long, mono_lldiv);
-       mono_register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", helper_sig_long_long_long, mono_lldiv_un);
-       mono_register_opcode_emulation (OP_LREM, "__emul_lrem", helper_sig_long_long_long, mono_llrem);
-       mono_register_opcode_emulation (OP_LREM_UN, "__emul_lrem_un", helper_sig_long_long_long, mono_llrem_un);
-
-       mono_register_opcode_emulation (OP_LSHL, "__emul_lshl", helper_sig_long_long_int, mono_lshl);
-       mono_register_opcode_emulation (OP_LSHR, "__emul_lshr", helper_sig_long_long_int, mono_lshr);
-       mono_register_opcode_emulation (OP_LSHR_UN, "__emul_lshr_un", helper_sig_long_long_int, mono_lshr_un);
-
-       mono_register_opcode_emulation (OP_FCONV_TO_U8, "__emul_fconv_to_u8", helper_sig_ulong_double, mono_fconv_u8);
-       mono_register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", helper_sig_uint_double, mono_fconv_u4);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", helper_sig_long_double, mono_fconv_ovf_i8);
-       mono_register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_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, "__emul_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
@@ -6958,6 +7313,7 @@ mini_init (const char *filename)
        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);
@@ -6980,8 +7336,8 @@ mini_init (const char *filename)
        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;
@@ -7037,6 +7393,7 @@ mini_cleanup (MonoDomain *domain)
        mono_profiler_shutdown ();
 
        mono_debug_cleanup ();
+
 #ifdef PLATFORM_WIN32
        win32_seh_cleanup();
 #endif