2006-04-19 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 3c4281ec5fcae3a5f379150065fe30c65b60370c..f8239ccc7207f35592b4c60234935307b99345a0 100644 (file)
 
 #include "aliasing.h"
 
+#define BRANCH_COST 100
+#define INLINE_LENGTH_LIMIT 20
+#define INLINE_FAILURE do {\
+               if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
+                       goto inline_failure;\
+       } while (0)
+
 /* 
  * this is used to determine when some branch optimizations are possible: we exclude FP compares
  * because they have weird semantics with NaNs.
@@ -161,6 +168,20 @@ mono_create_ftnptr (MonoDomain *domain, gpointer addr)
 #endif
 }
 
+typedef struct {
+       void *ip;
+       MonoMethod *method;
+} FindTrampUserData;
+
+static void
+find_tramp (gpointer key, gpointer value, gpointer user_data)
+{
+       FindTrampUserData *ud = (FindTrampUserData*)user_data;
+
+       if (value == ud->ip)
+               ud->method = (MonoMethod*)key;
+}
+
 /* debug function */
 G_GNUC_UNUSED static char*
 get_method_from_ip (void *ip)
@@ -170,10 +191,23 @@ get_method_from_ip (void *ip)
        char *source;
        char *res;
        MonoDomain *domain = mono_domain_get ();
+       FindTrampUserData user_data;
        
        ji = mono_jit_info_table_find (domain, ip);
        if (!ji) {
-               return NULL;
+               user_data.ip = ip;
+               user_data.method = NULL;
+               mono_domain_lock (domain);
+               g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+               mono_domain_unlock (domain);
+               if (user_data.method) {
+                       char *mname = mono_method_full_name (user_data.method, TRUE);
+                       res = g_strdup_printf ("<%p - JIT trampoline for %s>", ip, mname);
+                       g_free (mname);
+                       return res;
+               }
+               else
+                       return NULL;
        }
        method = mono_method_full_name (ji->method, TRUE);
        source = mono_debug_source_location_from_address (ji->method, (guint32)((guint8*)ip - (guint8*)ji->code_start), NULL, domain);
@@ -193,17 +227,29 @@ mono_pmip (void *ip)
 }
 
 /* debug function */
-G_GNUC_UNUSED static void
-print_method_from_ip (void *ip)
+void
+mono_print_method_from_ip (void *ip)
 {
        MonoJitInfo *ji;
        char *method;
        char *source;
        MonoDomain *domain = mono_domain_get ();
+       FindTrampUserData user_data;
        
        ji = mono_jit_info_table_find (domain, ip);
        if (!ji) {
-               g_print ("No method at %p\n", ip);
+               user_data.ip = ip;
+               user_data.method = NULL;
+               mono_domain_lock (domain);
+               g_hash_table_foreach (domain->jit_trampoline_hash, find_tramp, &user_data);
+               mono_domain_unlock (domain);
+               if (user_data.method) {
+                       char *mname = mono_method_full_name (user_data.method, TRUE);
+                       printf ("IP %p is a JIT trampoline for %s\n", ip, mname);
+                       g_free (mname);
+               }
+               else
+                       g_print ("No method at %p\n", ip);
                return;
        }
        method = mono_method_full_name (ji->method, TRUE);
@@ -217,12 +263,6 @@ print_method_from_ip (void *ip)
        g_free (source);
        g_free (method);
 }
-
-G_GNUC_UNUSED void
-mono_print_method_from_ip (void *ip)
-{
-       print_method_from_ip (ip);
-}
        
 /* 
  * mono_method_same_domain:
@@ -745,7 +785,6 @@ link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
 void
 mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
 {
-       MonoBasicBlock **newa;
        int i, pos;
        gboolean found;
 
@@ -757,14 +796,13 @@ mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
                }
        }
        if (found) {
-               newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count - 1));
                pos = 0;
                for (i = 0; i < from->out_count; ++i) {
                        if (from->out_bb [i] != to)
-                               newa [pos ++] = from->out_bb [i];
+                               from->out_bb [pos ++] = from->out_bb [i];
                }
+               g_assert (pos == from->out_count - 1);
                from->out_count--;
-               from->out_bb = newa;
        }
 
        found = FALSE;
@@ -775,14 +813,13 @@ mono_unlink_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
                }
        }
        if (found) {
-               newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count - 1));
                pos = 0;
                for (i = 0; i < to->in_count; ++i) {
                        if (to->in_bb [i] != from)
-                               newa [pos ++] = to->in_bb [i];
+                               to->in_bb [pos ++] = to->in_bb [i];
                }
+               g_assert (pos == to->in_count - 1);
                to->in_count--;
-               to->in_bb = newa;
        }
 }
 
@@ -1153,13 +1190,12 @@ type_to_eval_stack_type (MonoType *type, MonoInst *inst)
 {
        MonoClass *klass;
 
+       inst->klass = klass = mono_class_from_mono_type (type);
        if (type->byref) {
                inst->type = STACK_MP;
                return;
        }
 
-       klass = mono_class_from_mono_type (type);
-
 handle_enum:
        switch (type->type) {
        case MONO_TYPE_VOID:
@@ -2919,7 +2955,7 @@ mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
                if (header->code_size < atoi (getenv ("MONO_INLINELIMIT"))) {
                        return TRUE;
                }
-       } else if (header->code_size < 20)
+       } else if (header->code_size < INLINE_LENGTH_LIMIT)
                return TRUE;
 
        return FALSE;
@@ -3003,9 +3039,9 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
        return addr;
 }
 
-static MonoJitICallInfo **emul_opcode_map = NULL;
+MonoJitICallInfo **emul_opcode_map = NULL;
 
-static inline MonoJitICallInfo *
+MonoJitICallInfo *
 mono_find_jit_opcode_emulation (int opcode)
 {
        if  (emul_opcode_map)
@@ -3488,7 +3524,7 @@ can_access_internals (MonoAssembly *accessing, MonoAssembly* accessed)
                if (friend->public_key_token [0]) {
                        if (!accessing->aname.public_key_token [0])
                                continue;
-                       if (strcmp (friend->public_key_token, accessing->aname.public_key_token))
+                       if (strcmp ((char*)friend->public_key_token, (char*)accessing->aname.public_key_token))
                                continue;
                }
                return TRUE;
@@ -3612,6 +3648,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
        dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
+       dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
 
        /* still some type unsefety issues in marshal wrappers... (unknown is PtrToStructure) */
        dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
@@ -4380,6 +4417,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                MonoInst *iargs [3];
 
                                g_assert (mono_method_signature (cmethod)->is_inflated);
+                               /* Prevent inlining of methods that contain indirect calls */
+                               INLINE_FAILURE;
 
                                this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
                                this_temp->cil_code = ip;
@@ -4408,6 +4447,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if ((ins_flag & MONO_INST_TAILCALL) && cmethod && (*ip == CEE_CALL) &&
                                 (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
                                int i;
+                               /* Prevent inlining of methods with tail calls (the call stack would be altered) */
+                               INLINE_FAILURE;
                                /* FIXME: This assumes the two methods has the same number and type of arguments */
                                for (i = 0; i < n; ++i) {
                                        /* Check if argument is the same */
@@ -4465,6 +4506,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
                                        (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
+                                       /* Prevent inlining of methods that call wrappers */
+                                       INLINE_FAILURE;
                                        cmethod = mono_marshal_get_native_wrapper (cmethod);
                                        allways = TRUE;
                                }
@@ -4496,6 +4539,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                gboolean has_vtargs = FALSE;
                                int i;
                                
+                               /* Prevent inlining of methods with tail calls (the call stack would be altered) */
+                               INLINE_FAILURE;
                                /* keep it simple */
                                for (i =  fsig->param_count - 1; i >= 0; i--) {
                                        if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
@@ -4527,12 +4572,12 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
 
                        if (*ip == CEE_CALLI) {
-
+                               /* Prevent inlining of methods with indirect calls */
+                               INLINE_FAILURE;
                                if ((temp = mono_emit_calli (cfg, bblock, fsig, sp, addr, ip)) != -1) {
                                        NEW_TEMPLOAD (cfg, *sp, temp);
                                        sp++;
-                               }
-                                       
+                               }                                       
                        } else if (array_rank) {
                                MonoInst *addr;
 
@@ -4590,6 +4635,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
 
                        } else {
+                               /* Prevent inlining of methods which call other methods */
+                               INLINE_FAILURE;
                                if (ip_in_bb (cfg, bblock, ip + 5) 
                                    && (!MONO_TYPE_ISSTRUCT (fsig->ret))
                                    && (!MONO_TYPE_IS_VOID (fsig->ret) || cmethod->string_ctor)
@@ -4669,7 +4716,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp = stack_start;
                        }
                        start_new_bblock = 1;
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BRFALSE_S:
                case CEE_BRTRUE_S:
@@ -4686,7 +4733,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BEQ_S:
                case CEE_BGE_S:
@@ -4709,7 +4756,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BR:
                        CHECK_OPSIZE (5);
@@ -4727,7 +4774,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                sp = stack_start;
                        }
                        start_new_bblock = 1;
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BRFALSE:
                case CEE_BRTRUE:
@@ -4744,7 +4791,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_BEQ:
                case CEE_BGE:
@@ -4767,7 +4814,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                handle_stack_args (cfg, bblock, stack_start, sp - stack_start);
                                sp = stack_start;
                        }
-                       inline_costs += 10;
+                       inline_costs += BRANCH_COST;
                        break;
                case CEE_SWITCH:
                        CHECK_OPSIZE (5);
@@ -4801,7 +4848,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        }
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
-                       inline_costs += 20;
+                       inline_costs += (BRANCH_COST * 2);
                        break;
                case CEE_LDIND_I1:
                case CEE_LDIND_U1:
@@ -5257,9 +5304,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                break;
                                                
                                        } else {
+                                               /* Prevent inlining of methods which call other methods */
+                                               INLINE_FAILURE;
                                                mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                        }
                                } else {
+                                       /* Prevent inlining of methods which call other methods */
+                                       INLINE_FAILURE;
                                        /* now call the actual ctor */
                                        mono_emit_method_call_spilled (cfg, bblock, cmethod, fsig, sp, ip, callvirt_this_arg);
                                }
@@ -5679,6 +5730,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->type = STACK_MP;
 
                                        if (*ip == CEE_LDFLDA) {
+                                               ins->klass = mono_class_from_mono_type (field->type);
                                                *sp++ = ins;
                                        } else {
                                                MonoInst *load;
@@ -5779,6 +5831,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                        /* FIXME: mark instructions for use in SSA */
                        if (*ip == CEE_LDSFLDA) {
+                               ins->klass = mono_class_from_mono_type (field->type);
                                *sp++ = ins;
                        } else if (*ip == CEE_STSFLD) {
                                MonoInst *store;
@@ -6417,7 +6470,13 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        for (i = 0; i < header->num_clauses; ++i) {
                                MonoExceptionClause *clause = &header->clauses [i];
 
-                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) == (clause->handler_offset + clause->handler_len)) {
+                               /* 
+                                * Use <= in the final comparison to handle clauses with multiple
+                                * leave statements, like in bug #78024.
+                                * The ordering of the exception clauses guarantees that we find the
+                                * innermost clause.
+                                */
+                               if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
                                        int temp;
                                        MonoInst *load;
 
@@ -8460,39 +8519,6 @@ replace_in_block (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl
        }
 }
 
-static void 
-replace_or_add_in_block (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl)
-{
-       gboolean found = FALSE;
-       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;
-                       }
-                       found = TRUE;
-               }
-       }
-       
-       if (! found) {
-               MonoBasicBlock **new_in_bb = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * (bb->in_count + 1));
-               for (i = 0; i < bb->in_count; i++) {
-                       new_in_bb [i] = bb->in_bb [i];
-               }
-               new_in_bb [i] = repl;
-               bb->in_count++;
-               bb->in_bb = new_in_bb;
-       }
-}
-
-
 static void
 replace_out_block_in_code (MonoBasicBlock *bb, MonoBasicBlock *orig, MonoBasicBlock *repl) {
        MonoInst *inst;
@@ -8618,17 +8644,14 @@ remove_block_if_useless (MonoCompile *cfg, MonoBasicBlock *bb, MonoBasicBlock *p
                        printf ("remove_block_if_useless %s, removed BB%d\n", mono_method_full_name (cfg->method, TRUE), bb->block_num);
                }
                
-               for (i = 0; i < bb->in_count; i++) {
-                       MonoBasicBlock *in_bb = bb->in_bb [i];
-                       replace_out_block (in_bb, bb, target_bb);
+               /* unlink_bblock () modifies the bb->in_bb array so can't use a for loop here */
+               while (bb->in_count) {
+                       MonoBasicBlock *in_bb = bb->in_bb [0];
+                       mono_unlink_bblock (cfg, in_bb, bb);
+                       link_bblock (cfg, in_bb, target_bb);
                        replace_out_block_in_code (in_bb, bb, target_bb);
-                       if (bb->in_count == 1) {
-                               replace_in_block (target_bb, bb, in_bb);
-                       } else {
-                               replace_or_add_in_block (cfg, target_bb, bb, in_bb);
-                       }
                }
-
+               
                mono_unlink_bblock (cfg, bb, target_bb);
                
                if ((previous_bb != cfg->bb_entry) &&
@@ -8959,8 +8982,7 @@ optimize_branches (MonoCompile *cfg)
                                                 */
                                                bb->last_ins->opcode = CEE_BR;
                                                bb->last_ins->inst_target_bb = taken_branch_target;
-                                               replace_out_block (bb, untaken_branch_target, NULL);
-                                               replace_in_block (untaken_branch_target, bb, NULL);
+                                               mono_unlink_bblock (cfg, bb, untaken_branch_target);
                                                changed = TRUE;
                                                continue;
                                        }
@@ -8972,12 +8994,18 @@ optimize_branches (MonoCompile *cfg)
                                                                 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;
+                                               /* 
+                                                * Unlink, then relink bblocks to avoid various
+                                                * tricky situations when the two targets of the branch
+                                                * are equal, or will become equal after the change.
+                                                */
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               replace_in_block (bbn, bb, NULL);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+                                               bb->last_ins->inst_true_bb = bbn->code->inst_target_bb;
 
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
                                                changed = TRUE;
                                                continue;
@@ -8991,12 +9019,13 @@ optimize_branches (MonoCompile *cfg)
                                                                 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;
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               mono_unlink_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
-                                               replace_in_block (bbn, bb, NULL);
-                                               replace_out_block (bb, bbn, bbn->code->inst_target_bb);
+                                               bb->last_ins->inst_false_bb = bbn->code->inst_target_bb;
 
-                                               link_bblock (cfg, bb, bbn->code->inst_target_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_true_bb);
+                                               link_bblock (cfg, bb, bb->last_ins->inst_false_bb);
 
                                                changed = TRUE;
                                                continue;
@@ -9345,8 +9374,15 @@ mono_codegen (MonoCompile *cfg)
                                         */
                                        ;
                                else {
-                                       patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
-                                       patch_info->data.name = info->name;
+                                       /* for these array methods we currently register the same function pointer
+                                        * since it's a vararg function. But this means that mono_find_jit_icall_by_addr ()
+                                        * will return the incorrect one depending on the order they are registered.
+                                        * See tests/test-arr.cs
+                                        */
+                                       if (strstr (info->name, "ves_array_new_va_") == NULL && strstr (info->name, "ves_array_element_address_") == NULL) {
+                                               patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
+                                               patch_info->data.name = info->name;
+                                       }
                                }
                        }
                        else {
@@ -9385,9 +9421,9 @@ mono_codegen (MonoCompile *cfg)
        
        if (cfg->verbose_level > 0) {
                char* nm = mono_method_full_name (cfg->method, TRUE);
-               g_print ("Method %s emitted at %p to %p [%s]\n", 
+               g_print ("Method %s emitted at %p to %p (code length %d) [%s]\n", 
                                 nm, 
-                                cfg->native_code, cfg->native_code + cfg->code_len, cfg->domain->friendly_name);
+                                cfg->native_code, cfg->native_code + cfg->code_len, cfg->code_len, cfg->domain->friendly_name);
                g_free (nm);
        }
 
@@ -9410,190 +9446,7 @@ mono_codegen (MonoCompile *cfg)
        mono_debug_close_method (cfg);
 }
 
-static void
-mono_cprop_copy_values (MonoCompile *cfg, MonoInst *tree, MonoInst **acp)
-{
-       MonoInst *cp;
-       int arity;
-
-       if (tree->ssa_op == MONO_SSA_LOAD && (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG) && 
-           (cp = acp [tree->inst_i0->inst_c0]) && !tree->inst_i0->flags) {
-
-               if (cp->opcode == OP_ICONST) {
-                       if (cfg->opt & MONO_OPT_CONSPROP) {
-                               //{ static int c = 0; printf ("CCOPY %d %d %s\n", c++, cp->inst_c0, mono_method_full_name (cfg->method, TRUE)); }
-                               *tree = *cp;
-                       }
-               } else {
-                       if (tree->inst_i0->inst_vtype->type == cp->inst_vtype->type) {
-                               if (cfg->opt & MONO_OPT_COPYPROP) {
-                                       //{ static int c = 0; printf ("VCOPY %d\n", ++c); }
-                                       tree->inst_i0 = cp;
-                               } 
-                       }
-               } 
-       } else {
-               arity = mono_burg_arity [tree->opcode];
 
-               if (arity) {
-                       mono_cprop_copy_values (cfg, tree->inst_i0, acp);
-                       if (cfg->opt & MONO_OPT_CFOLD)
-                               mono_constant_fold_inst (tree, NULL); 
-                       /* The opcode may have changed */
-                       if (mono_burg_arity [tree->opcode] > 1) {
-                               mono_cprop_copy_values (cfg, tree->inst_i1, acp);
-                               if (cfg->opt & MONO_OPT_CFOLD)
-                                       mono_constant_fold_inst (tree, NULL); 
-                       }
-                       mono_constant_fold_inst (tree, NULL); 
-               }
-       }
-}
-
-static void
-mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
-{
-       int arity;
-
-       switch (tree->opcode) {
-       case CEE_STIND_I:
-       case CEE_STIND_I1:
-       case CEE_STIND_I2:
-       case CEE_STIND_I4:
-       case CEE_STIND_REF:
-       case CEE_STIND_I8:
-       case CEE_STIND_R4:
-       case CEE_STIND_R8:
-       case CEE_STOBJ:
-               if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
-                       memset (acp, 0, sizeof (MonoInst *) * acp_size);
-                       return;
-               }
-
-               break;
-       case CEE_CALL:
-       case OP_CALL_REG:
-       case CEE_CALLVIRT:
-       case OP_LCALL_REG:
-       case OP_LCALLVIRT:
-       case OP_LCALL:
-       case OP_FCALL_REG:
-       case OP_FCALLVIRT:
-       case OP_FCALL:
-       case OP_VCALL_REG:
-       case OP_VCALLVIRT:
-       case OP_VCALL:
-       case OP_VOIDCALL_REG:
-       case OP_VOIDCALLVIRT:
-       case OP_VOIDCALL: {
-               MonoCallInst *call = (MonoCallInst *)tree;
-               MonoMethodSignature *sig = call->signature;
-               int i, byref = FALSE;
-
-               for (i = 0; i < sig->param_count; i++) {
-                       if (sig->params [i]->byref) {
-                               byref = TRUE;
-                               break;
-                       }
-               }
-
-               if (byref)
-                       memset (acp, 0, sizeof (MonoInst *) * acp_size);
-
-               return;
-       }
-       default:
-               break;
-       }
-
-       arity = mono_burg_arity [tree->opcode];
-
-       switch (arity) {
-       case 0:
-               break;
-       case 1:
-               mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
-               break;
-       case 2:
-               mono_cprop_invalidate_values (tree->inst_i0, acp, acp_size);
-               mono_cprop_invalidate_values (tree->inst_i1, acp, acp_size);
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-}
-
-static void
-mono_local_cprop_bb (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **acp, int acp_size)
-{
-       MonoInst *tree = bb->code;      
-       int i;
-
-       if (!tree)
-               return;
-
-       for (; tree; tree = tree->next) {
-
-               mono_cprop_copy_values (cfg, tree, acp);
-
-               mono_cprop_invalidate_values (tree, acp, acp_size);
-
-               if (tree->ssa_op == MONO_SSA_STORE  && 
-                   (tree->inst_i0->opcode == OP_LOCAL || tree->inst_i0->opcode == OP_ARG)) {
-                       MonoInst *i1 = tree->inst_i1;
-
-                       acp [tree->inst_i0->inst_c0] = NULL;
-
-                       for (i = 0; i < acp_size; i++) {
-                               if (acp [i] && acp [i]->opcode != OP_ICONST && 
-                                   acp [i]->inst_c0 == tree->inst_i0->inst_c0) {
-                                       acp [i] = NULL;
-                               }
-                       }
-
-                       if (i1->opcode == OP_ICONST) {
-                               acp [tree->inst_i0->inst_c0] = i1;
-                               //printf ("DEF1 BB%d %d\n", bb->block_num,tree->inst_i0->inst_c0);
-                       }
-                       if (i1->ssa_op == MONO_SSA_LOAD && 
-                           (i1->inst_i0->opcode == OP_LOCAL || i1->inst_i0->opcode == OP_ARG) &&
-                           (i1->inst_i0->inst_c0 != tree->inst_i0->inst_c0)) {
-                               acp [tree->inst_i0->inst_c0] = i1->inst_i0;
-                               //printf ("DEF2 BB%d %d %d\n", bb->block_num,tree->inst_i0->inst_c0,i1->inst_i0->inst_c0);
-                       }
-               }
-
-               /*
-                 if (tree->opcode == CEE_BEQ) {
-                 g_assert (tree->inst_i0->opcode == OP_COMPARE);
-                 if (tree->inst_i0->inst_i0->opcode == OP_ICONST &&
-                 tree->inst_i0->inst_i1->opcode == OP_ICONST) {
-                 
-                 tree->opcode = CEE_BR;
-                 if (tree->inst_i0->inst_i0->opcode == tree->inst_i0->inst_i1->opcode) {
-                 tree->inst_target_bb = tree->inst_true_bb;
-                 } else {
-                 tree->inst_target_bb = tree->inst_false_bb;
-                 }
-                 }
-                 }
-               */
-       }
-}
-
-static void
-mono_local_cprop (MonoCompile *cfg)
-{
-       MonoBasicBlock *bb;
-       MonoInst **acp;
-
-       acp = alloca (sizeof (MonoInst *) * cfg->num_varinfo);
-
-       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
-               memset (acp, 0, sizeof (MonoInst *) * cfg->num_varinfo);
-               mono_local_cprop_bb (cfg, bb, acp, cfg->num_varinfo);
-       }
-}
 
 static void
 remove_critical_edges (MonoCompile *cfg) {
@@ -10522,12 +10375,24 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 
        ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
        if (!ji) {
-               mono_handle_native_sigsegv (ctx);
+               mono_handle_native_sigsegv (SIGSEGV, ctx);
        }
                        
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
+static void
+SIG_HANDLER_SIGNATURE (sigabrt_signal_handler)
+{
+       MonoJitInfo *ji;
+       GET_CONTEXT;
+
+       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+       if (!ji) {
+               mono_handle_native_sigsegv (SIGABRT, ctx);
+       }
+}
+
 static void
 SIG_HANDLER_SIGNATURE (sigusr1_signal_handler)
 {
@@ -10658,6 +10523,8 @@ mono_runtime_install_handlers (void)
        add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
        signal (SIGPIPE, SIG_IGN);
 
+       add_signal_handler (SIGABRT, sigabrt_signal_handler);
+
        /* catch SIGSEGV */
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        sa.sa_sigaction = sigsegv_signal_handler;
@@ -10667,7 +10534,6 @@ mono_runtime_install_handlers (void)
 #else
        add_signal_handler (SIGSEGV, sigsegv_signal_handler);
 #endif
-
 #endif /* PLATFORM_WIN32 */
 }
 
@@ -11116,6 +10982,9 @@ mini_cleanup (MonoDomain *domain)
         */
        mono_domain_finalize (domain, 2000);
 
+       /* This accesses metadata so needs to be called before runtime shutdown */
+       print_jit_stats ();
+
        mono_runtime_cleanup (domain);
 
        mono_profiler_shutdown ();
@@ -11134,8 +11003,8 @@ mini_cleanup (MonoDomain *domain)
        g_hash_table_destroy (jit_icall_name_hash);
        if (class_init_hash_addr)
                g_hash_table_destroy (class_init_hash_addr);
+       g_free (emul_opcode_map);
 
-       print_jit_stats ();
        mono_counters_dump (-1, stdout);
 }