2005-12-11 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index 2585d73c959382b89ba21a06e201b2b05df7aa32..194f58b034e674dbdd99a0030631e4628cb27110 100644 (file)
@@ -49,6 +49,7 @@
 #include <mono/metadata/monitor.h>
 #include <mono/metadata/security-manager.h>
 #include <mono/metadata/threads-types.h>
+#include <mono/metadata/rawbuffer.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/os/gc_wrapper.h>
@@ -61,6 +62,8 @@
 
 #include "jit-icalls.c"
 
+#include "aliasing.h"
+
 /* 
  * this is used to determine when some branch optimizations are possible: we exclude FP compares
  * because they have weird semantics with NaNs.
@@ -102,6 +105,8 @@ gboolean mono_use_security_manager = FALSE;
 
 static int mini_verbose = 0;
 
+#define mono_jit_lock() EnterCriticalSection (&jit_mutex)
+#define mono_jit_unlock() LeaveCriticalSection (&jit_mutex)
 static CRITICAL_SECTION jit_mutex;
 
 static GHashTable *class_init_hash_addr = NULL;
@@ -181,6 +186,12 @@ get_method_from_ip (void *ip)
        return res;
 }
 
+G_GNUC_UNUSED char *
+mono_pmip (void *ip)
+{
+       return get_method_from_ip (ip);
+}
+
 /* debug function */
 G_GNUC_UNUSED static void
 print_method_from_ip (void *ip)
@@ -255,9 +266,9 @@ void *mono_global_codeman_reserve (int size)
                return mono_code_manager_reserve (global_codeman, size);
        }
        else {
-               EnterCriticalSection (&jit_mutex);
+               mono_jit_lock ();
                ptr = mono_code_manager_reserve (global_codeman, size);
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
                return ptr;
        }
 }
@@ -440,7 +451,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_LOCLOADA(cfg,dest,num) do {        \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [locals_offset + (num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -452,7 +463,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_RETLOADA(cfg,dest) do {    \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->ret;   \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = cfg->ret_var_is_local ? OP_LDADDR : CEE_LDIND_I;       \
@@ -464,7 +475,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 #define NEW_ARGLOADA(cfg,dest,num) do {        \
                 if (arg_array [(num)]->opcode == OP_ICONST) goto inline_failure; \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = arg_array [(num)];    \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -484,7 +495,7 @@ mono_jump_info_token_new (MonoMemPool *mp, MonoImage *image, guint32 token)
 
 #define NEW_TEMPLOADA(cfg,dest,num) do {       \
                (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
-               (dest)->ssa_op = MONO_SSA_MAYBE_LOAD;   \
+               (dest)->ssa_op = MONO_SSA_ADDRESS_TAKEN;        \
                (dest)->inst_i0 = (cfg)->varinfo [(num)];       \
                (dest)->inst_i0->flags |= MONO_INST_INDIRECT;   \
                (dest)->opcode = OP_LDADDR;     \
@@ -849,7 +860,7 @@ df_visit (MonoBasicBlock *start, int *dfn, MonoBasicBlock **array)
        int i;
 
        array [*dfn] = start;
-       /*g_print ("visit %d at %p\n", *dfn, start->cil_code);*/
+       /*g_print ("visit %d at %p (BB%ld)\n", *dfn, start->cil_code, start->block_num);*/
        for (i = 0; i < start->out_count; ++i) {
                if (start->out_bb [i]->dfn)
                        continue;
@@ -1799,6 +1810,9 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                found = FALSE;
                for (i = 0; i < bb->out_count; ++i) {
                        outb = bb->out_bb [i];
+                       /* exception handlers are linked, but they should not be considered for stack args */
+                       if (outb->flags & BB_EXCEPTION_HANDLER)
+                               continue;
                        //g_print (" %d", outb->block_num);
                        if (outb->in_stack) {
                                found = TRUE;
@@ -1832,8 +1846,14 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
 
        for (i = 0; i < bb->out_count; ++i) {
                outb = bb->out_bb [i];
-               if (outb->in_scount)
+               /* exception handlers are linked, but they should not be considered for stack args */
+               if (outb->flags & BB_EXCEPTION_HANDLER)
+                       continue;
+               if (outb->in_scount) {
+                       if (outb->in_scount != bb->out_scount)
+                               G_BREAKPOINT ();
                        continue; /* check they are the same locals */
+               }
                outb->in_scount = count;
                outb->in_stack = bb->out_stack;
        }
@@ -1866,6 +1886,11 @@ handle_stack_args (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst **sp, int coun
                found = FALSE;
                while (bindex < bb->out_count) {
                        outb = bb->out_bb [bindex];
+                       /* exception handlers are linked, but they should not be considered for stack args */
+                       if (outb->flags & BB_EXCEPTION_HANDLER) {
+                               bindex++;
+                               continue;
+                       }
                        if (outb->in_stack != locals) {
                                /* 
                                 * Instead of storing sp [i] to locals [i], we need to store
@@ -2338,7 +2363,7 @@ mono_get_element_address_signature (int arity)
        MonoMethodSignature *res;
        int i;
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
        }
@@ -2362,7 +2387,7 @@ mono_get_element_address_signature (int arity)
        res->ret = &mono_defaults.int_class->byval_arg;
 
        g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
 
        return res;
 }
@@ -2374,12 +2399,12 @@ mono_get_array_new_va_signature (int arity)
        MonoMethodSignature *res;
        int i;
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (!sighash) {
                sighash = g_hash_table_new (NULL, NULL);
        }
        else if ((res = g_hash_table_lookup (sighash, GINT_TO_POINTER (arity)))) {
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
                return res;
        }
 
@@ -2398,7 +2423,7 @@ mono_get_array_new_va_signature (int arity)
        res->ret = &mono_defaults.int_class->byval_arg;
 
        g_hash_table_insert (sighash, GINT_TO_POINTER (arity), res);
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
 
        return res;
 }
@@ -2543,13 +2568,35 @@ handle_alloc (MonoCompile *cfg, MonoBasicBlock *bblock, MonoClass *klass, gboole
 
        return mono_emit_jit_icall (cfg, bblock, alloc_ftn, iargs, ip);
 }
+
+/**
+ * Handles unbox of a Nullable<T>, returning a temp variable
+ * where the result is stored
+ */
+static int
+handle_unbox_nullable (MonoCompile* cfg, MonoBasicBlock* bblock, MonoInst* val, const guchar *ip, MonoClass* klass)
+{
+       MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
+       return mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
        
+}
+
+
+
 static MonoInst *
 handle_box (MonoCompile *cfg, MonoBasicBlock *bblock, MonoInst *val, const guchar *ip, MonoClass *klass)
 {
        MonoInst *dest, *vtoffset, *add, *vstore;
        int temp;
 
+       if (mono_class_is_nullable (klass)) {
+               MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
+               temp = mono_emit_method_call_spilled (cfg, bblock, method, mono_method_signature (method), &val, ip, NULL);
+               NEW_TEMPLOAD (cfg, dest, temp);
+               return dest;
+       }
+
+
        temp = handle_alloc (cfg, bblock, klass, TRUE, ip);
        NEW_TEMPLOAD (cfg, dest, temp);
        NEW_ICONST (cfg, vtoffset, sizeof (MonoObject));
@@ -2590,9 +2637,9 @@ handle_array_new (MonoCompile *cfg, MonoBasicBlock *bblock, int rank, MonoInst *
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (mono_array_new_va, name, esig, FALSE);
 
-               EnterCriticalSection (&jit_mutex);
+               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
        }
 
        cfg->flags |= MONO_CFG_HAS_VARARGS;
@@ -2778,9 +2825,9 @@ mini_get_ldelema_ins (MonoCompile *cfg, MonoBasicBlock *bblock, MonoMethod *cmet
                name = g_strdup (icall_name);
                info = mono_register_jit_icall (ves_array_element_address, name, esig, FALSE);
 
-               EnterCriticalSection (&jit_mutex);
+               mono_jit_lock ();
                g_hash_table_insert (jit_icall_name_hash, name, name);
-               LeaveCriticalSection (&jit_mutex);
+               mono_jit_unlock ();
        }
 
        temp = mono_emit_native_call (cfg, bblock, mono_icall_get_wrapper (info), info->sig, sp, ip, FALSE, FALSE);
@@ -2876,7 +2923,7 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
                        return ins;
                } else
                        return NULL;
-       } else if (mini_class_is_system_array (cmethod->klass)) {
+       } else if (cmethod->klass == mono_defaults.array_class) {
                if (cmethod->name [0] != 'g')
                        return NULL;
 
@@ -2899,7 +2946,6 @@ mini_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSigna
        } else if (cmethod->klass == mono_defaults.thread_class) {
                if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg)))
                        return ins;
-               return NULL;
        }
 
        return mono_arch_get_inst_for_method (cfg, cmethod, fsig, args);
@@ -3270,7 +3316,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
        image = method->klass->image;
        header = mono_method_get_header (method);
-       generic_container = ((MonoMethodNormal *)method)->generic_container;
+       generic_container = method->generic_container;
        sig = mono_method_signature (method);
        num_args = sig->hasthis + sig->param_count;
        ip = (unsigned char*)header->code;
@@ -3328,19 +3374,30 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                }
                /* handle exception clauses */
                for (i = 0; i < header->num_clauses; ++i) {
-                       //unsigned char *p = ip;
+                       MonoBasicBlock *try_bb;
                        MonoExceptionClause *clause = &header->clauses [i];
-                       GET_BBLOCK (cfg, bbhash, tblock, ip + clause->try_offset);
-                       tblock->real_offset = clause->try_offset;
+                       GET_BBLOCK (cfg, bbhash, try_bb, ip + clause->try_offset);
+                       try_bb->real_offset = clause->try_offset;
                        GET_BBLOCK (cfg, bbhash, tblock, ip + clause->handler_offset);
                        tblock->real_offset = clause->handler_offset;
+                       tblock->flags |= BB_EXCEPTION_HANDLER;
+
+                       link_bblock (cfg, try_bb, tblock);
+
+                       if (*(ip + clause->handler_offset) == CEE_POP)
+                               tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
 
                        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);
+
+                               /* todo: is a fault block unsafe to optimize? */
+                               if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
+                                       tblock->flags |= BB_EXCEPTION_UNSAFE;
                        }
 
+
                        /*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));
@@ -4479,6 +4536,10 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        ins->opcode = OP_IMUL_IMM;
                                        ins->inst_imm = ins->inst_right->inst_c0;
                                        break;
+                               case OP_LMUL:
+                                       ins->opcode = OP_LMUL_IMM;
+                                       ins->inst_imm = ins->inst_right->inst_c0;
+                                       break;
                                default:
                                        g_assert_not_reached ();
                                }
@@ -5000,6 +5061,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                break;
                        }
 
+                       if (mono_class_is_nullable (klass)) {
+                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               NEW_TEMPLOAD (cfg, *sp, v);
+                               sp ++;
+                               ip += 5;
+                               break;
+                       }
+
                        MONO_INST_NEW (cfg, ins, OP_UNBOXCAST);
                        ins->type = STACK_OBJ;
                        ins->inst_left = *sp;
@@ -5050,6 +5119,14 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (!klass)
                                goto load_error;
 
+                       if (mono_class_is_nullable (klass)) {
+                               int v = handle_unbox_nullable (cfg, bblock, *sp, ip, klass);
+                               NEW_TEMPLOAD (cfg, *sp, v);
+                               sp ++;
+                               ip += 5;
+                               break;
+                       }
+
                        /* Needed by the code generated in inssel.brg */
                        mono_get_got_var (cfg);
 
@@ -5135,6 +5212,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        ins->cil_code = ip - 1;
                        MONO_ADD_INS (bblock, ins);
                        sp = stack_start;
+                       
                        link_bblock (cfg, bblock, end_bblock);
                        start_new_bblock = 1;
                        mono_get_got_var (cfg);
@@ -5224,7 +5302,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                }
                        } else {
                                if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
-                                       MonoMethod *ldfld_wrapper = mono_marshal_get_ldfld_wrapper (field->type); 
+                                       MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
                                        MonoInst *iargs [4];
                                        int temp;
                                        
@@ -5232,8 +5310,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        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);
-                                       if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (ldfld_wrapper)->ret)) {
-                                               costs = inline_method (cfg, ldfld_wrapper, mono_method_signature (ldfld_wrapper), bblock, 
+                                       if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
+                                               costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), bblock, 
                                                                       iargs, ip, real_offset, dont_inline, &ebblock, TRUE);
                                                g_assert (costs > 0);
                                                      
@@ -5246,12 +5324,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
 
                                                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);
-                                               }
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
                                                sp++;
 
                                                /* indicates start of a new block, and triggers a load of
@@ -5261,13 +5334,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                inline_costs += costs;
                                                break;
                                        } else {
-                                               temp = mono_emit_method_call_spilled (cfg, bblock, ldfld_wrapper, mono_method_signature (ldfld_wrapper), iargs, ip, NULL);
-                                               if (*ip == CEE_LDFLDA) {
-                                                       /* not sure howto handle this */
-                                                       NEW_TEMPLOADA (cfg, *sp, temp);
-                                               } else {
-                                                       NEW_TEMPLOAD (cfg, *sp, temp);
-                                               }
+                                               temp = mono_emit_method_call_spilled (cfg, bblock, wrapper, mono_method_signature (wrapper), iargs, ip, NULL);
+                                               NEW_TEMPLOAD (cfg, *sp, temp);
                                                sp++;
                                        }
                                } else {
@@ -6540,6 +6608,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                                handler_offset = clause->handler_offset;
                                }
 
+                               bblock->flags |= BB_EXCEPTION_UNSAFE;
+
                                g_assert (handler_offset != -1);
 
                                NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
@@ -6908,11 +6978,12 @@ mono_init_trampolines (void)
 static void
 mono_init_exceptions (void)
 {
+#ifndef CUSTOM_EXCEPTION_HANDLING
        mono_arch_get_restore_context ();
        mono_arch_get_call_filter ();
        mono_arch_get_throw_exception ();
        mono_arch_get_rethrow_exception ();
-       mono_arch_get_throw_exception_by_name ();
+#endif
 }
 
 guint8 *
@@ -6949,11 +7020,11 @@ mono_create_class_init_trampoline (MonoVTable *vtable)
                                                          vtable, ptr);
        mono_domain_unlock (vtable->domain);
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (!class_init_hash_addr)
                class_init_hash_addr = g_hash_table_new (NULL, NULL);
        g_hash_table_insert (class_init_hash_addr, ptr, vtable);
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
 
        return ptr;
 }
@@ -7107,12 +7178,12 @@ mono_find_class_init_trampoline_by_addr (gconstpointer addr)
 {
        MonoVTable *res;
 
-       EnterCriticalSection (&jit_mutex);
+       mono_jit_lock ();
        if (class_init_hash_addr)
                res = g_hash_table_lookup (class_init_hash_addr, addr);
        else
                res = NULL;
-       LeaveCriticalSection (&jit_mutex);
+       mono_jit_unlock ();
        return res;
 }
 
@@ -7609,6 +7680,10 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 
        mono_arch_setup_jit_tls_data (jit_tls);
 
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+       mono_setup_altstack (jit_tls);
+#endif
+
        return jit_tls;
 }
 
@@ -7652,6 +7727,10 @@ mini_thread_cleanup (MonoThread *thread)
 
        if (jit_tls) {
                mono_arch_free_jit_tls_data (jit_tls);
+
+#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
+               mono_free_altstack (jit_tls);
+#endif
                g_free (jit_tls->first_lmf);
                g_free (jit_tls);
                thread->jit_data = NULL;
@@ -8862,7 +8941,7 @@ mono_cprop_invalidate_values (MonoInst *tree, MonoInst **acp, int acp_size)
        case CEE_STIND_R4:
        case CEE_STIND_R8:
        case CEE_STOBJ:
-               if (tree->ssa_op == MONO_SSA_NOP) {
+               if ((tree->ssa_op == MONO_SSA_NOP) || (tree->ssa_op & MONO_SSA_ADDRESS_TAKEN)) {
                        memset (acp, 0, sizeof (MonoInst *) * acp_size);
                        return;
                }
@@ -9128,6 +9207,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        MonoCompile *cfg;
        MonoJitInfo *jinfo;
        int dfn = 0, i, code_size_ratio;
+       gboolean deadce_has_run = FALSE;
 
        if (!header)
                return NULL;
@@ -9150,7 +9230,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->compile_aot = compile_aot;
        cfg->intvars = mono_mempool_alloc0 (cfg->mempool, sizeof (guint16) * STACK_MAX * 
                                            mono_method_get_header (method)->max_stack);
-
+       cfg->aliasing_info = NULL;
+       
        if (cfg->verbose_level > 2)
                g_print ("converting method %s\n", mono_method_full_name (method, TRUE));
 
@@ -9235,7 +9316,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #else 
 
        /* fixme: add all optimizations which requires SSA */
-       if (cfg->opt & (MONO_OPT_DEADCE | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
+       if (cfg->opt & (MONO_OPT_SSA | MONO_OPT_ABCREM | MONO_OPT_SSAPRE)) {
                if (!(cfg->comp_done & MONO_COMP_SSA) && !header->num_clauses && !cfg->disable_ssa) {
                        mono_local_cprop (cfg);
                        mono_ssa_compute (cfg);
@@ -9260,16 +9341,23 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        }
 
        if (cfg->comp_done & MONO_COMP_SSA) {                   
-               mono_ssa_deadce (cfg);
+               //mono_ssa_deadce (cfg);
 
                //mono_ssa_strength_reduction (cfg);
 
+               if (cfg->opt & MONO_OPT_SSAPRE) {
+                       mono_perform_ssapre (cfg);
+                       //mono_local_cprop (cfg);
+               }
+               
+               if (cfg->opt & MONO_OPT_DEADCE) {
+                       mono_ssa_deadce (cfg);
+                       deadce_has_run = TRUE;
+               }
+               
                if ((cfg->flags & MONO_CFG_HAS_LDELEMA) && (cfg->opt & MONO_OPT_ABCREM))
                        mono_perform_abc_removal (cfg);
                
-               if (cfg->opt & MONO_OPT_SSAPRE)
-                       mono_perform_ssapre (cfg);
-               
                mono_ssa_remove (cfg);
 
                if (cfg->opt & MONO_OPT_BRANCH)
@@ -9305,18 +9393,33 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        if (cfg->opt & MONO_OPT_LINEARS) {
                GList *vars, *regs;
+               
+               /* For now, compute aliasing info only if needed for deadce... */
+               if ((cfg->opt & MONO_OPT_DEADCE) && (! deadce_has_run) && (header->num_clauses == 0)) {
+                       cfg->aliasing_info = mono_build_aliasing_information (cfg);
+               }
 
                /* 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 (cfg->aliasing_info != NULL) {
+                       mono_aliasing_deadce (cfg->aliasing_info);
+                       deadce_has_run = TRUE;
+               }
+               
                if ((vars = mono_arch_get_allocatable_int_vars (cfg))) {
                        regs = mono_arch_get_global_int_regs (cfg);
                        if (cfg->got_var)
                                regs = g_list_delete_link (regs, regs);
                        mono_linear_scan (cfg, vars, regs, &cfg->used_int_regs);
                }
+               
+               if (cfg->aliasing_info != NULL) {
+                       mono_destroy_aliasing_information (cfg->aliasing_info);
+                       cfg->aliasing_info = NULL;
+               }
        }
 
        //mono_print_code (cfg);
@@ -9460,7 +9563,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain)
        method = mono_get_inflated_method (method);
 
 #ifdef MONO_USE_AOT_COMPILER
-       if (!mono_compile_aot && (opt & MONO_OPT_AOT)) {
+       if (!mono_compile_aot && (opt & MONO_OPT_AOT) && !(mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION)) {
                MonoJitInfo *info;
                MonoDomain *domain = mono_domain_get ();
 
@@ -9599,13 +9702,13 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt)
                        mono_domain_unlock (target_domain);
                        mono_jit_stats.methods_lookups++;
                        mono_runtime_class_init (mono_class_vtable (domain, method->klass));
-                       return mono_create_ftnptr (domain, info->code_start);
+                       return mono_create_ftnptr (target_domain, info->code_start);
                }
        }
 
        mono_domain_unlock (target_domain);
        p = mono_jit_compile_method_inner (method, target_domain);
-       return mono_create_ftnptr (domain, p);
+       return mono_create_ftnptr (target_domain, p);
 }
 
 static gpointer
@@ -9744,7 +9847,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 #define GET_CONTEXT \
     ucontext_t *uctx = context; \
     struct sigcontext *ctx = (struct sigcontext *)&(uctx->uc_mcontext);
-#elif defined(__ppc__) || defined (__powerpc__) || defined (__s390__) || defined (MONO_ARCH_USE_SIGACTION)
+#elif defined (MONO_ARCH_USE_SIGACTION)
 #define GET_CONTEXT \
     void *ctx = context;
 #else
@@ -9785,7 +9888,8 @@ static void
 SIG_HANDLER_SIGNATURE (sigill_signal_handler)
 {
        MonoException *exc;
-       GET_CONTEXT
+       GET_CONTEXT;
+
        exc = mono_get_exception_execution_engine ("SIGILL");
        
        mono_arch_handle_exception (ctx, exc, FALSE);
@@ -9803,10 +9907,25 @@ static void
 SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 {
        MonoException *exc = NULL;
+       MonoJitInfo *ji;
+
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
 #endif
-       GET_CONTEXT
+       GET_CONTEXT;
+
+#ifdef MONO_ARCH_USE_SIGACTION
+       if (debug_options.collect_pagefault_stats) {
+               if (mono_raw_buffer_is_pagefault (info->si_addr)) {
+                       mono_raw_buffer_handle_pagefault (info->si_addr);
+                       return;
+               }
+               if (mono_aot_is_pagefault (info->si_addr)) {
+                       mono_aot_handle_pagefault (info->si_addr);
+                       return;
+               }
+       }
+#endif
 
 #ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        /* Can't allocate memory using Boehm GC on altstack */
@@ -9818,13 +9937,9 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
                exc = mono_domain_get ()->null_reference_ex;
 #endif
 
-       if (debug_options.abort_on_sigsegv) {
-               MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
-               if (!ji) {
-                       fprintf (stderr, "Got SIGSEGV while in unmanaged code, and the 'abort-on-sigsegv' MONO_DEBUG option is set. Aborting...\n");
-                       /* Segfault in unmanaged code */
-                       abort ();
-               }
+       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
+       if (!ji) {
+               mono_handle_native_sigsegv (ctx);
        }
                        
        mono_arch_handle_exception (ctx, exc, FALSE);
@@ -9865,19 +9980,19 @@ SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
 static void
 SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
 {
-       MonoException *exc;
-       GET_CONTEXT
+       MonoException *exc;
+       GET_CONTEXT;
 
-       exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
+       exc = mono_get_exception_execution_engine ("Interrupted (SIGQUIT).");
        
-       mono_arch_handle_exception (ctx, exc, FALSE);
+       mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
 static void
 SIG_HANDLER_SIGNATURE (sigint_signal_handler)
 {
        MonoException *exc;
-       GET_CONTEXT
+       GET_CONTEXT;
 
        exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
        
@@ -10084,11 +10199,11 @@ mini_parse_debug_options (void)
                        debug_options.handle_sigint = TRUE;
                else if (!strcmp (arg, "keep-delegates"))
                        debug_options.keep_delegates = TRUE;
-               else if (!strcmp (arg, "abort-on-sigsegv"))
-                       debug_options.abort_on_sigsegv = TRUE;
+               else if (!strcmp (arg, "collect-pagefault-stats"))
+                       debug_options.collect_pagefault_stats = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'abort-on-sigsegv'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats'\n");
                        exit (1);
                }
        }
@@ -10157,6 +10272,11 @@ mini_init (const char *filename)
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
+       if (debug_options.collect_pagefault_stats) {
+               mono_raw_buffer_set_make_unreadable (TRUE);
+               mono_aot_set_make_unreadable (TRUE);
+       }
+
        domain = mono_init_from_assembly (filename, filename);
        mono_icall_init ();
 
@@ -10344,6 +10464,10 @@ print_jit_stats (void)
                        g_print ("LinkDemand (aptc)     : %ld\n", mono_jit_stats.cas_linkdemand_aptc);
                        g_print ("Demand (code gen)     : %ld\n", mono_jit_stats.cas_demand_generation);
                }
+               if (debug_options.collect_pagefault_stats) {
+                       g_print ("Metadata pagefaults   : %d\n", mono_raw_buffer_get_n_pagefaults ());
+                       g_print ("AOT pagefaults        : %d\n", mono_aot_get_n_pagefaults ());
+               }
        }
 }