2009-03-02 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini.c
index bc3e00b6ac64636221a19dac4cd12e8172c65a09..ddb9f6929b1854b87cd7c7625fd5685132271e81 100644 (file)
 #include <sys/time.h>
 #endif
 
-#ifdef PLATFORM_MACOSX
-#include <mach/mach.h>
-#include <mach/mach_error.h>
-#include <mach/exception.h>
-#include <mach/task.h>
-#include <pthread.h>
-#endif
-
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
 #endif
@@ -72,7 +64,6 @@
 
 #include "debug-mini.h"
 
-static void setup_stat_profiler (void);
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt);
 static gpointer mono_jit_compile_method (MonoMethod *method);
 
@@ -110,6 +101,7 @@ MonoMethodDesc *mono_break_at_bb_method = NULL;
 int mono_break_at_bb_bb_num;
 gboolean mono_do_x86_stack_align = TRUE;
 const char *mono_build_date;
+gboolean mono_do_signal_chaining;
 
 static int mini_verbose = 0;
 
@@ -560,7 +552,7 @@ handle_enum:
                return OP_STORER8_MEMBASE_REG;
        case MONO_TYPE_VALUETYPE:
                if (type->data.klass->enumtype) {
-                       type = type->data.klass->enum_basetype;
+                       type = mono_class_enum_basetype (type->data.klass);
                        goto handle_enum;
                }
                if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
@@ -814,6 +806,16 @@ set_vreg_to_inst (MonoCompile *cfg, int vreg, MonoInst *inst)
 #define mono_type_is_long(type) (!(type)->byref && ((mono_type_get_underlying_type (type)->type == MONO_TYPE_I8) || (mono_type_get_underlying_type (type)->type == MONO_TYPE_U8)))
 #define mono_type_is_float(type) (!(type)->byref && (((type)->type == MONO_TYPE_R8) || ((type)->type == MONO_TYPE_R4)))
 
+#ifdef DISABLE_JIT
+
+MonoInst*
+mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
+{
+       return NULL;
+}
+
+#else
+
 MonoInst*
 mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode, int vreg)
 {
@@ -843,6 +845,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        cfg->varinfo [num] = inst;
 
        MONO_INIT_VARINFO (&cfg->vars [num], num);
+       MONO_VARINFO (cfg, num)->vreg = vreg;
 
        if (vreg != -1)
                set_vreg_to_inst (cfg, vreg, inst);
@@ -942,6 +945,8 @@ mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index)
        dest->klass = dest->inst_i0->klass;
 }
 
+#endif
+
 static MonoType*
 type_from_stack_type (MonoInst *ins) {
        switch (ins->type) {
@@ -1242,10 +1247,12 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
         * We use the lock on the root domain instead of the JIT lock to protect 
         * callinfo->trampoline, since we do a lot of stuff inside the critical section.
         */
+       mono_loader_lock (); /*FIXME mono_compile_method requires the loader lock, by large.*/
        mono_domain_lock (domain);
 
        if (callinfo->trampoline) {
                mono_domain_unlock (domain);
+               mono_loader_unlock ();
                return callinfo->trampoline;
        }
 
@@ -1262,6 +1269,7 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
        callinfo->trampoline = trampoline;
 
        mono_domain_unlock (domain);
+       mono_loader_unlock ();
        
        return callinfo->trampoline;
 }
@@ -1801,12 +1809,6 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
        return offsets;
 }
 
-gint32*
-mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
-{
-       return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
-}
-
 #else
 
 gint32*
@@ -1818,6 +1820,12 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
 
 #endif /* DISABLE_JIT */
 
+gint32*
+mono_allocate_stack_slots (MonoCompile *m, guint32 *stack_size, guint32 *stack_align)
+{
+       return mono_allocate_stack_slots_full (m, TRUE, stack_size, stack_align);
+}
+
 void
 mono_register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpointer func, gboolean no_throw)
 {
@@ -2215,7 +2223,7 @@ mono_thread_attach_cb (gsize tid, gpointer stack_start)
        if (thread)
                thread->jit_data = jit_tls;
        if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
-               setup_stat_profiler ();
+               mono_runtime_setup_stat_profiler ();
 }
 
 static void
@@ -2231,7 +2239,24 @@ mini_thread_cleanup (MonoThread *thread)
                g_free (jit_tls->first_lmf);
                g_free (jit_tls);
                thread->jit_data = NULL;
-               TlsSetValue (mono_jit_tls_id, NULL);
+
+               /* We can't clean up tls information if we are on another thread, it will clean up the wrong stuff
+                * It would be nice to issue a warning when this happens outside of the shutdown sequence. but it's
+                * not a trivial thing.
+                *
+                * The current offender is mono_thread_manage which cleanup threads from the outside.
+                */
+               if (thread == mono_thread_current ()) {
+                       TlsSetValue (mono_jit_tls_id, NULL);
+
+#ifdef HAVE_KW_THREAD
+                       mono_jit_tls = NULL;
+                       mono_lmf_addr = NULL;
+#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+                       mono_lmf = NULL;
+#endif
+#endif         
+               }
        }
 }
 
@@ -2259,6 +2284,18 @@ mono_get_jit_tls_intrinsic (MonoCompile *cfg)
        return mono_create_tls_get (cfg, mono_get_jit_tls_offset ());
 }
 
+MonoInst*
+mono_get_domain_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_domain_get_tls_offset ());
+}
+
+MonoInst*
+mono_get_thread_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, mono_thread_get_tls_offset ());
+}
+
 void
 mono_add_patch_info (MonoCompile *cfg, int ip, MonoJumpInfoType type, gconstpointer target)
 {
@@ -2458,12 +2495,11 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                if (method && method->dynamic) {
                        jump_table = mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                } else {
-                       mono_domain_lock (domain);
-                       if (mono_aot_only)
+                       if (mono_aot_only) {
                                jump_table = mono_domain_alloc (domain, sizeof (gpointer) * patch_info->data.table->table_size);
-                       else
-                               jump_table = mono_code_manager_reserve (domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
-                       mono_domain_unlock (domain);
+                       } else {
+                               jump_table = mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
+                       }
                }
 
                for (i = 0; i < patch_info->data.table->table_size; i++)
@@ -2793,9 +2829,7 @@ mono_codegen (MonoCompile *cfg)
 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
                unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
 #endif
-               mono_domain_lock (cfg->domain);
-               code = mono_code_manager_reserve (cfg->domain->code_mp, cfg->code_size + unwindlen);
-               mono_domain_unlock (cfg->domain);
+               code = mono_domain_code_reserve (cfg->domain, cfg->code_size + unwindlen);
        }
 
        memcpy (code, cfg->native_code, cfg->code_len);
@@ -2856,9 +2890,7 @@ mono_codegen (MonoCompile *cfg)
                        if (cfg->method->dynamic) {
                                table = mono_code_manager_reserve (cfg->dynamic_info->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
                        } else {
-                               mono_domain_lock (cfg->domain);
-                               table = mono_code_manager_reserve (cfg->domain->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
-                               mono_domain_unlock (cfg->domain);
+                               table = mono_domain_code_reserve (cfg->domain, sizeof (gpointer) * patch_info->data.table->table_size);
                        }
 
                        for (i = 0; i < patch_info->data.table->table_size; i++) {
@@ -2930,9 +2962,7 @@ if (valgrind_register){
        if (cfg->method->dynamic) {
                mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
        } else {
-               mono_domain_lock (cfg->domain);
-               mono_code_manager_commit (cfg->domain->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
-               mono_domain_unlock (cfg->domain);
+               mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len);
        }
        
        mono_arch_flush_icache (cfg->native_code, cfg->code_len);
@@ -2943,20 +2973,6 @@ if (valgrind_register){
 #endif
 }
 
-static MonoGenericInst*
-get_object_generic_inst (int type_argc)
-{
-       MonoType **type_argv;
-       int i;
-
-       type_argv = alloca (sizeof (MonoType*) * type_argc);
-
-       for (i = 0; i < type_argc; ++i)
-               type_argv [i] = &mono_defaults.object_class->byval_arg;
-
-       return mono_metadata_get_generic_inst (type_argc, type_argv);
-}
-
 static void
 compute_reachable (MonoBasicBlock *bb)
 {
@@ -2969,34 +2985,6 @@ compute_reachable (MonoBasicBlock *bb)
        }
 }
 
-static MonoGenericContext
-construct_object_context_for_method (MonoMethod *method)
-{
-       MonoGenericContext object_context;
-
-       g_assert (method->wrapper_type == MONO_WRAPPER_NONE);
-       g_assert (!method->klass->generic_class);
-       if (method->klass->generic_container) {
-               int type_argc = method->klass->generic_container->type_argc;
-
-               object_context.class_inst = get_object_generic_inst (type_argc);
-       } else {
-               object_context.class_inst = NULL;
-       }
-
-       if (mini_method_get_context (method)->method_inst) {
-               int type_argc = mini_method_get_context (method)->method_inst->type_argc;
-
-               object_context.method_inst = get_object_generic_inst (type_argc);
-       } else {
-               object_context.method_inst = NULL;
-       }
-
-       g_assert (object_context.class_inst || object_context.method_inst);
-
-       return object_context;
-}
-
 /*
  * mini_method_compile:
  * @method: the method to compile
@@ -3106,6 +3094,10 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                /* The debugger needs all locals to be on the stack or in a global register */
                cfg->disable_vreg_to_lvreg = TRUE;
 
+               /* Don't remove unused variables when running inside the debugger since the user
+                * may still want to view them. */
+               cfg->disable_deadce_vars = TRUE;
+
                // cfg->opt |= MONO_OPT_SHARED;
                cfg->opt &= ~MONO_OPT_DEADCE;
                cfg->opt &= ~MONO_OPT_INLINE;
@@ -3546,16 +3538,13 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                jinfo = g_malloc0 (sizeof (MonoJitInfo) + (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
                                generic_info_size);
        } else {
-               /* we access cfg->domain->mp */
-               mono_domain_lock (cfg->domain);
                jinfo = mono_domain_alloc0 (cfg->domain, sizeof (MonoJitInfo) +
                                (header->num_clauses * sizeof (MonoJitExceptionInfo)) +
                                generic_info_size);
-               mono_domain_unlock (cfg->domain);
        }
 
        if (cfg->generic_sharing_context) {
-               MonoGenericContext object_context = construct_object_context_for_method (method_to_compile);
+               MonoGenericContext object_context = mono_method_construct_object_context (method_to_compile);
 
                method_to_register = mono_class_inflate_generic_method (method_to_compile, &object_context);
        } else {
@@ -3663,12 +3652,26 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
                }
        }
 
+       /* 
+        * Its possible to generate dwarf unwind info for xdebug etc, but not actually
+        * using it during runtime, hence the define.
+        */
+#ifdef MONO_ARCH_HAVE_XP_UNWIND
+       if (cfg->unwind_ops) {
+               guint32 info_len;
+               guint8 *unwind_info = mono_unwind_ops_encode (cfg->unwind_ops, &info_len);
+
+               jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len);
+               g_free (unwind_info);
+       }
+#endif
+
        cfg->jit_info = jinfo;
 #if defined(__arm__)
        mono_arch_fixup_jinfo (cfg);
 #endif
 
-       mono_save_xdebug_info (method_to_register, jinfo->code_start, jinfo->code_size, cfg->args, cfg->unwind_ops);
+       mono_save_xdebug_info (cfg);
 
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
@@ -3716,25 +3719,17 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
 #endif /* DISABLE_JIT */
 
-MonoJitInfo*
-mono_domain_lookup_shared_generic (MonoDomain *domain, MonoMethod *method)
+static MonoJitInfo*
+lookup_generic_method (MonoDomain *domain, MonoMethod *method)
 {
-       MonoGenericContext object_context;
-       MonoMethod *open_method, *object_method;
-       MonoJitInfo *ji;
+       MonoMethod *open_method;
 
        if (!mono_method_is_generic_sharable_impl (method, FALSE))
                return NULL;
 
-       open_method = mono_method_get_declaring_generic_method (method);
-       object_context = construct_object_context_for_method (open_method);
-       object_method = mono_class_inflate_generic_method (open_method, &object_context);
-
-       ji = mono_internal_hash_table_lookup (&domain->jit_code_hash, object_method);
-       if (ji && !ji->has_generic_jit_info)
-               ji = NULL;
+       open_method = mono_method_get_declaring_generic_method (method);
 
-       return ji;
+       return mono_domain_lookup_shared_generic (domain, open_method);
 }
 
 /*
@@ -3748,7 +3743,7 @@ lookup_method_inner (MonoDomain *domain, MonoMethod *method)
        if (ji)
                return ji;
 
-       return mono_domain_lookup_shared_generic (domain, method);
+       return lookup_generic_method (domain, method);
 }
 
 static MonoJitInfo*
@@ -3756,9 +3751,11 @@ lookup_method (MonoDomain *domain, MonoMethod *method)
 {
        MonoJitInfo *info;
 
+       mono_loader_lock (); /*FIXME lookup_method_inner acquired it*/
        mono_domain_jit_code_hash_lock (domain);
        info = lookup_method_inner (domain, method);
        mono_domain_jit_code_hash_unlock (domain);
+       mono_loader_unlock ();
 
        return info;
 }
@@ -3936,6 +3933,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                g_assert_not_reached ();
        }
 
+       mono_loader_lock (); /*FIXME lookup_method_inner requires the loader lock*/
        mono_domain_lock (target_domain);
 
        /* Check if some other thread already did the job. In this case, we can
@@ -3982,6 +3980,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
        }
 
        mono_domain_unlock (target_domain);
+       mono_loader_unlock ();
 
        vtable = mono_class_vtable (target_domain, method->klass);
        if (!vtable) {
@@ -4191,39 +4190,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        return runtime_invoke (obj, params, exc, compiled_method);
 }
 
-#ifdef MONO_GET_CONTEXT
-#define GET_CONTEXT MONO_GET_CONTEXT
-#endif
-
-#ifndef GET_CONTEXT
-#ifdef PLATFORM_WIN32
-#define GET_CONTEXT \
-       struct sigcontext *ctx = (struct sigcontext*)_dummy;
-#else
-#ifdef MONO_ARCH_USE_SIGACTION
-#define GET_CONTEXT \
-    void *ctx = context;
-#elif defined(__sparc__)
-#define GET_CONTEXT \
-    void *ctx = sigctx;
-#else
-#define GET_CONTEXT \
-       void **_p = (void **)&_dummy; \
-       struct sigcontext *ctx = (struct sigcontext *)++_p;
-#endif
-#endif
-#endif
-
-#ifdef MONO_ARCH_USE_SIGACTION
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, siginfo_t *info, void *context)
-#elif defined(__sparc__)
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy, void *sigctx)
-#else
-#define SIG_HANDLER_SIGNATURE(ftn) ftn (int _dummy)
-#endif
-
-static void
-SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
+void
+SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler)
 {
        MonoException *exc = NULL;
 #ifndef MONO_ARCH_USE_SIGACTION
@@ -4243,8 +4211,8 @@ SIG_HANDLER_SIGNATURE (sigfpe_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
-static void
-SIG_HANDLER_SIGNATURE (sigill_signal_handler)
+void
+SIG_HANDLER_SIGNATURE (mono_sigill_signal_handler)
 {
        MonoException *exc;
        GET_CONTEXT;
@@ -4254,8 +4222,8 @@ SIG_HANDLER_SIGNATURE (sigill_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
-static void
-SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
+void
+SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
 {
 #ifndef MONO_ARCH_SIGSEGV_ON_ALTSTACK
        MonoException *exc = NULL;
@@ -4266,8 +4234,11 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
        GET_CONTEXT;
 
        /* The thread might no be registered with the runtime */
-       if (!mono_domain_get () || !jit_tls)
+       if (!mono_domain_get () || !jit_tls) {
+               if (mono_chain_signal (SIG_HANDLER_PARAMS))
+                       return;
                mono_handle_native_sigsegv (SIGSEGV, ctx);
+       }
 
        ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context (ctx));
 
@@ -4290,11 +4261,18 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
                fprintf (stderr, "At %s\n", method);
                _exit (1);
        } else {
+               /* The original handler might not like that it is executed on an altstack... */
+               if (!ji && mono_chain_signal (SIG_HANDLER_PARAMS))
+                       return;
+
                mono_arch_handle_altstack_exception (ctx, info->si_addr, FALSE);
        }
 #else
 
        if (!ji) {
+               if (mono_chain_signal (SIG_HANDLER_PARAMS))
+                       return;
+
                mono_handle_native_sigsegv (SIGSEGV, ctx);
        }
                        
@@ -4302,179 +4280,8 @@ SIG_HANDLER_SIGNATURE (sigsegv_signal_handler)
 #endif
 }
 
-#ifndef PLATFORM_WIN32
-
-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)
-{
-       gboolean running_managed;
-       MonoException *exc;
-       MonoThread *thread = mono_thread_current ();
-       void *ji;
-       
-       GET_CONTEXT;
-
-       if (thread->thread_dump_requested) {
-               thread->thread_dump_requested = FALSE;
-
-               mono_print_thread_dump (ctx);
-       }
-
-       /*
-        * FIXME:
-        * This is an async signal, so the code below must not call anything which
-        * is not async safe. That includes the pthread locking functions. If we
-        * know that we interrupted managed code, then locking is safe.
-        */
-       ji = mono_jit_info_table_find (mono_domain_get (), mono_arch_ip_from_context(ctx));
-       running_managed = ji != NULL;
-       
-       exc = mono_thread_request_interruption (running_managed); 
-       if (!exc) return;
-
-       mono_arch_handle_exception (ctx, exc, FALSE);
-}
-
-#if defined(__i386__) || defined(__x86_64__)
-#define FULL_STAT_PROFILER_BACKTRACE 1
-#define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f))
-#define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1))
-#if MONO_ARCH_STACK_GROWS_UP
-#define IS_BEFORE_ON_STACK <
-#define IS_AFTER_ON_STACK >
-#else
-#define IS_BEFORE_ON_STACK >
-#define IS_AFTER_ON_STACK <
-#endif
-#else
-#define FULL_STAT_PROFILER_BACKTRACE 0
-#endif
-
-#if defined(__ia64__) || defined(__sparc__) || defined(sparc) || defined(__s390__) || defined(s390)
-
-static void
-SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
-{
-       NOT_IMPLEMENTED;
-}
-
-#else
-
-static void
-SIG_HANDLER_SIGNATURE (sigprof_signal_handler)
-{
-       int call_chain_depth = mono_profiler_stat_get_call_chain_depth ();
-       GET_CONTEXT;
-       
-       if (call_chain_depth == 0) {
-               mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx);
-       } else {
-               MonoJitTlsData *jit_tls = TlsGetValue (mono_jit_tls_id);
-               int current_frame_index = 1;
-               MonoContext mono_context;
-#if FULL_STAT_PROFILER_BACKTRACE
-               guchar *current_frame;
-               guchar *stack_bottom;
-               guchar *stack_top;
-#else
-               MonoDomain *domain;
-#endif
-               guchar *ips [call_chain_depth + 1];
-
-               mono_arch_sigctx_to_monoctx (ctx, &mono_context);
-               ips [0] = MONO_CONTEXT_GET_IP (&mono_context);
-               
-               if (jit_tls != NULL) {
-#if FULL_STAT_PROFILER_BACKTRACE
-                       stack_bottom = jit_tls->end_of_stack;
-                       stack_top = MONO_CONTEXT_GET_SP (&mono_context);
-                       current_frame = MONO_CONTEXT_GET_BP (&mono_context);
-                       
-                       while ((current_frame_index <= call_chain_depth) &&
-                                       (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) &&
-                                       ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) {
-                               ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame);
-                               current_frame_index ++;
-                               stack_top = current_frame;
-                               current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame);
-                       }
-#else
-                       domain = mono_domain_get ();
-                       if (domain != NULL) {
-                               MonoLMF *lmf = NULL;
-                               MonoJitInfo *ji;
-                               MonoJitInfo res;
-                               MonoContext new_mono_context;
-                               int native_offset;
-                               ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
-                                               &new_mono_context, NULL, &lmf, &native_offset, NULL);
-                               while ((ji != NULL) && (current_frame_index <= call_chain_depth)) {
-                                       ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context);
-                                       current_frame_index ++;
-                                       mono_context = new_mono_context;
-                                       ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context,
-                                                       &new_mono_context, NULL, &lmf, &native_offset, NULL);
-                               }
-                       }
-#endif
-               }
-               
-               
-               mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx);
-       }
-}
-
-#endif
-
-static void
-SIG_HANDLER_SIGNATURE (sigquit_signal_handler)
-{
-       gboolean res;
-
-       GET_CONTEXT;
-
-       /* We use this signal to start the attach agent too */
-       res = mono_attach_start ();
-       if (res)
-               return;
-
-       printf ("Full thread dump:\n");
-
-       mono_threads_request_thread_dump ();
-
-       /*
-        * print_thread_dump () skips the current thread, since sending a signal
-        * to it would invoke the signal handler below the sigquit signal handler,
-        * and signal handlers don't create an lmf, so the stack walk could not
-        * be performed.
-        */
-       mono_print_thread_dump (ctx);
-}
-
-static void
-SIG_HANDLER_SIGNATURE (sigusr2_signal_handler)
-{
-       gboolean enabled = mono_trace_is_enabled ();
-
-       mono_trace_enable (!enabled);
-}
-
-#endif
-
-static void
-SIG_HANDLER_SIGNATURE (sigint_signal_handler)
+void
+SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler)
 {
        MonoException *exc;
        GET_CONTEXT;
@@ -4484,357 +4291,6 @@ SIG_HANDLER_SIGNATURE (sigint_signal_handler)
        mono_arch_handle_exception (ctx, exc, FALSE);
 }
 
-#ifdef PLATFORM_MACOSX
-
-/*
- * This code disables the CrashReporter of MacOS X by installing
- * a dummy Mach exception handler.
- */
-
-/*
- * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/exc_server.html
- */
-extern
-boolean_t
-exc_server (mach_msg_header_t *request_msg,
-           mach_msg_header_t *reply_msg);
-
-/*
- * The exception message
- */
-typedef struct {
-       mach_msg_base_t msg;  /* common mach message header */
-       char payload [1024];  /* opaque */
-} mach_exception_msg_t;
-
-/* The exception port */
-static mach_port_t mach_exception_port = VM_MAP_NULL;
-
-/*
- * Implicitly called by exc_server. Must be public.
- *
- * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/catch_exception_raise.html
- */
-kern_return_t
-catch_exception_raise (
-       mach_port_t exception_port,
-       mach_port_t thread,
-       mach_port_t task,
-       exception_type_t exception,
-       exception_data_t code,
-       mach_msg_type_number_t code_count)
-{
-       /* consume the exception */
-       return KERN_FAILURE;
-}
-
-/*
- * Exception thread handler.
- */
-static
-void *
-mach_exception_thread (void *arg)
-{
-       for (;;) {
-               mach_exception_msg_t request;
-               mach_exception_msg_t reply;
-               mach_msg_return_t result;
-
-               /* receive from "mach_exception_port" */
-               result = mach_msg (&request.msg.header,
-                                  MACH_RCV_MSG | MACH_RCV_LARGE,
-                                  0,
-                                  sizeof (request),
-                                  mach_exception_port,
-                                  MACH_MSG_TIMEOUT_NONE,
-                                  MACH_PORT_NULL);
-
-               g_assert (result == MACH_MSG_SUCCESS);
-
-               /* dispatch to catch_exception_raise () */
-               exc_server (&request.msg.header, &reply.msg.header);
-
-               /* send back to sender */
-               result = mach_msg (&reply.msg.header,
-                                  MACH_SEND_MSG,
-                                  reply.msg.header.msgh_size,
-                                  0,
-                                  MACH_PORT_NULL,
-                                  MACH_MSG_TIMEOUT_NONE,
-                                  MACH_PORT_NULL);
-
-               g_assert (result == MACH_MSG_SUCCESS);
-       }
-       return NULL;
-}
-
-static void
-macosx_register_exception_handler ()
-{
-       mach_port_t task;
-       pthread_attr_t attr;
-       pthread_t thread;
-
-       if (mach_exception_port != VM_MAP_NULL)
-               return;
-
-       task = mach_task_self ();
-
-       /* create the "mach_exception_port" with send & receive rights */
-       g_assert (mach_port_allocate (task, MACH_PORT_RIGHT_RECEIVE,
-                                     &mach_exception_port) == KERN_SUCCESS);
-       g_assert (mach_port_insert_right (task, mach_exception_port, mach_exception_port,
-                                         MACH_MSG_TYPE_MAKE_SEND) == KERN_SUCCESS);
-
-       /* create the exception handler thread */
-       g_assert (!pthread_attr_init (&attr));
-       g_assert (!pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED));
-       g_assert (!pthread_create (&thread, &attr, mach_exception_thread, NULL));
-       pthread_attr_destroy (&attr);
-
-       /*
-        * register "mach_exception_port" as a receiver for the
-        * EXC_BAD_ACCESS exception
-        *
-        * http://darwinsource.opendarwin.org/10.4.3/xnu-792.6.22/osfmk/man/task_set_exception_ports.html
-        */
-       g_assert (task_set_exception_ports (task, EXC_MASK_BAD_ACCESS,
-                                           mach_exception_port,
-                                           EXCEPTION_DEFAULT,
-                                           MACHINE_THREAD_STATE) == KERN_SUCCESS);
-}
-#endif
-
-#ifndef PLATFORM_WIN32
-static void
-add_signal_handler (int signo, gpointer handler)
-{
-       struct sigaction sa;
-
-#ifdef MONO_ARCH_USE_SIGACTION
-       sa.sa_sigaction = handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = SA_SIGINFO;
-#ifdef MONO_ARCH_SIGSEGV_ON_ALTSTACK
-       if (signo == SIGSEGV)
-               sa.sa_flags |= SA_ONSTACK;
-#endif
-#else
-       sa.sa_handler = handler;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-#endif
-       g_assert (sigaction (signo, &sa, NULL) != -1);
-}
-
-static void
-remove_signal_handler (int signo)
-{
-       struct sigaction sa;
-
-       sa.sa_handler = SIG_DFL;
-       sigemptyset (&sa.sa_mask);
-       sa.sa_flags = 0;
-
-       sigaction (signo, &sa, NULL);
-}
-#endif
-
-static void
-mono_runtime_install_handlers (void)
-{
-#ifdef PLATFORM_WIN32
-       win32_seh_init();
-       win32_seh_set_handler(SIGFPE, sigfpe_signal_handler);
-       win32_seh_set_handler(SIGILL, sigill_signal_handler);
-       win32_seh_set_handler(SIGSEGV, sigsegv_signal_handler);
-       if (debug_options.handle_sigint)
-               win32_seh_set_handler(SIGINT, sigint_signal_handler);
-
-#else /* !PLATFORM_WIN32 */
-
-       sigset_t signal_set;
-
-#if defined(PLATFORM_MACOSX) && !defined(__arm__)
-       macosx_register_exception_handler ();
-#endif
-
-       if (debug_options.handle_sigint)
-               add_signal_handler (SIGINT, sigint_signal_handler);
-
-       add_signal_handler (SIGFPE, sigfpe_signal_handler);
-       add_signal_handler (SIGQUIT, sigquit_signal_handler);
-       add_signal_handler (SIGILL, sigill_signal_handler);
-       add_signal_handler (SIGBUS, sigsegv_signal_handler);
-       if (mono_jit_trace_calls != NULL)
-               add_signal_handler (SIGUSR2, sigusr2_signal_handler);
-
-       add_signal_handler (mono_thread_get_abort_signal (), sigusr1_signal_handler);
-       /* it seems to have become a common bug for some programs that run as parents
-        * of many processes to block signal delivery for real time signals.
-        * We try to detect and work around their breakage here.
-        */
-       sigemptyset (&signal_set);
-       sigaddset (&signal_set, mono_thread_get_abort_signal ());
-       sigprocmask (SIG_UNBLOCK, &signal_set, NULL);
-
-       signal (SIGPIPE, SIG_IGN);
-
-       add_signal_handler (SIGABRT, sigabrt_signal_handler);
-
-       /* catch SIGSEGV */
-       add_signal_handler (SIGSEGV, sigsegv_signal_handler);
-#endif /* PLATFORM_WIN32 */
-}
-
-static void
-mono_runtime_cleanup_handlers (void)
-{
-#ifdef PLATFORM_WIN32
-       win32_seh_cleanup();
-#else
-       if (debug_options.handle_sigint)
-               remove_signal_handler (SIGINT);
-
-       remove_signal_handler (SIGFPE);
-       remove_signal_handler (SIGQUIT);
-       remove_signal_handler (SIGILL);
-       remove_signal_handler (SIGBUS);
-       if (mono_jit_trace_calls != NULL)
-               remove_signal_handler (SIGUSR2);
-
-       remove_signal_handler (mono_thread_get_abort_signal ());
-
-       remove_signal_handler (SIGABRT);
-
-       remove_signal_handler (SIGSEGV);
-#endif /* PLATFORM_WIN32 */
-}
-
-
-#ifdef HAVE_LINUX_RTC_H
-#include <linux/rtc.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-static int rtc_fd = -1;
-
-static int
-enable_rtc_timer (gboolean enable)
-{
-       int flags;
-       flags = fcntl (rtc_fd, F_GETFL);
-       if (flags < 0) {
-               perror ("getflags");
-               return 0;
-       }
-       if (enable)
-               flags |= FASYNC;
-       else
-               flags &= ~FASYNC;
-       if (fcntl (rtc_fd, F_SETFL, flags) == -1) {
-               perror ("setflags");
-               return 0;
-       }
-       return 1;
-}
-#endif
-
-#ifdef PLATFORM_WIN32
-static HANDLE win32_main_thread;
-static MMRESULT win32_timer;
-
-static void CALLBACK
-win32_time_proc (UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
-{
-       CONTEXT context;
-
-       context.ContextFlags = CONTEXT_CONTROL;
-       if (GetThreadContext (win32_main_thread, &context)) {
-#ifdef _WIN64
-               mono_profiler_stat_hit ((guchar *) context.Rip, &context);
-#else
-               mono_profiler_stat_hit ((guchar *) context.Eip, &context);
-#endif
-       }
-}
-#endif
-
-static void
-setup_stat_profiler (void)
-{
-#ifdef ITIMER_PROF
-       struct itimerval itval;
-       static int inited = 0;
-#ifdef HAVE_LINUX_RTC_H
-       const char *rtc_freq;
-       if (!inited && (rtc_freq = g_getenv ("MONO_RTC"))) {
-               int freq = 0;
-               inited = 1;
-               if (*rtc_freq)
-                       freq = atoi (rtc_freq);
-               if (!freq)
-                       freq = 1024;
-               rtc_fd = open ("/dev/rtc", O_RDONLY);
-               if (rtc_fd == -1) {
-                       perror ("open /dev/rtc");
-                       return;
-               }
-               add_signal_handler (SIGPROF, sigprof_signal_handler);
-               if (ioctl (rtc_fd, RTC_IRQP_SET, freq) == -1) {
-                       perror ("set rtc freq");
-                       return;
-               }
-               if (ioctl (rtc_fd, RTC_PIE_ON, 0) == -1) {
-                       perror ("start rtc");
-                       return;
-               }
-               if (fcntl (rtc_fd, F_SETSIG, SIGPROF) == -1) {
-                       perror ("setsig");
-                       return;
-               }
-               if (fcntl (rtc_fd, F_SETOWN, getpid ()) == -1) {
-                       perror ("setown");
-                       return;
-               }
-               enable_rtc_timer (TRUE);
-               return;
-       }
-       if (rtc_fd >= 0)
-               return;
-#endif
-
-       itval.it_interval.tv_usec = 999;
-       itval.it_interval.tv_sec = 0;
-       itval.it_value = itval.it_interval;
-       setitimer (ITIMER_PROF, &itval, NULL);
-       if (inited)
-               return;
-       inited = 1;
-       add_signal_handler (SIGPROF, sigprof_signal_handler);
-#elif defined (PLATFORM_WIN32)
-       static int inited = 0;
-       TIMECAPS timecaps;
-
-       if (inited)
-               return;
-
-       inited = 1;
-       if (timeGetDevCaps (&timecaps, sizeof (timecaps)) != TIMERR_NOERROR)
-               return;
-
-       if ((win32_main_thread = OpenThread (READ_CONTROL | THREAD_GET_CONTEXT, FALSE, GetCurrentThreadId ())) == NULL)
-               return;
-
-       if (timeBeginPeriod (1) != TIMERR_NOERROR)
-               return;
-
-       if ((win32_timer = timeSetEvent (1, 0, win32_time_proc, 0, TIME_PERIODIC)) == 0) {
-               timeEndPeriod (1);
-               return;
-       }
-#endif
-}
-
 /* mono_jit_create_remoting_trampoline:
  * @method: pointer to the method info
  *
@@ -4910,11 +4366,13 @@ mini_parse_debug_options (void)
                        debug_options.break_on_unverified = TRUE;
                else if (!strcmp (arg, "no-gdb-backtrace"))
                        debug_options.no_gdb_backtrace = TRUE;
+               else if (!strcmp (arg, "suspend-on-sigsegv"))
+                       debug_options.suspend_on_sigsegv = TRUE;
                else if (!strcmp (arg, "dont-free-domains"))
                        mono_dont_free_domains = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv'\n");
                        exit (1);
                }
        }
@@ -5011,8 +4469,13 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_arch_init ();
 
-       if (getenv ("MONO_XDEBUG"))
+       mono_unwind_init ();
+
+       if (getenv ("MONO_XDEBUG")) {
                mono_xdebug_init ();
+               /* So methods for multiple domains don't have the same address */
+               mono_dont_free_domains = TRUE;
+       }
 
        mono_trampolines_init ();
 
@@ -5167,13 +4630,17 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 
 #ifdef MONO_ARCH_EMULATE_MUL_DIV
-       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
-       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
        mono_register_opcode_emulation (CEE_MUL, "__emul_imul", "int32 int32 int32", mono_imul, TRUE);
        mono_register_opcode_emulation (OP_IMUL, "__emul_op_imul", "int32 int32 int32", mono_imul, TRUE);
+#endif
+
+#if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_MUL_OVF)
+       mono_register_opcode_emulation (CEE_MUL_OVF, "__emul_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
+       mono_register_opcode_emulation (CEE_MUL_OVF_UN, "__emul_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
        mono_register_opcode_emulation (OP_IMUL_OVF, "__emul_op_imul_ovf", "int32 int32 int32", mono_imul_ovf, FALSE);
        mono_register_opcode_emulation (OP_IMUL_OVF_UN, "__emul_op_imul_ovf_un", "int32 int32 int32", mono_imul_ovf_un, FALSE);
 #endif
+
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT)
        mono_register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, FALSE);
 #endif
@@ -5218,6 +4685,9 @@ mini_init (const char *filename, const char *runtime_version)
        mono_register_opcode_emulation (OP_FCONV_TO_I4, "__emul_fconv_to_i4", "int32 double", mono_fconv_i4, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_U1, "__emul_fconv_to_u1", "uint8 double", mono_fconv_u1, FALSE);
        mono_register_opcode_emulation (OP_FCONV_TO_U2, "__emul_fconv_to_u2", "uint16 double", mono_fconv_u2, FALSE);
+#if SIZEOF_VOID_P == 4
+       mono_register_opcode_emulation (OP_FCONV_TO_I, "__emul_fconv_to_i", "int32 double", mono_fconv_i4, FALSE);
+#endif
 
        mono_register_opcode_emulation (OP_FBEQ, "__emul_fcmp_eq", "uint32 double double", mono_fcmp_eq, FALSE);
        mono_register_opcode_emulation (OP_FBLT, "__emul_fcmp_lt", "uint32 double double", mono_fcmp_lt, FALSE);
@@ -5239,6 +4709,7 @@ mini_init (const char *filename, const char *runtime_version)
        register_icall (mono_fload_r4, "mono_fload_r4", "double ptr", FALSE);
        register_icall (mono_fstore_r4, "mono_fstore_r4", "void double ptr", FALSE);
        register_icall (mono_fload_r4_arg, "mono_fload_r4_arg", "uint32 double", FALSE);
+       register_icall (mono_isfinite, "mono_isfinite", "uint32 double", FALSE);
 #endif
 
 #if SIZEOF_REGISTER == 4
@@ -5341,12 +4812,8 @@ print_jit_stats (void)
                g_print ("VTable data size:       %ld\n", mono_stats.class_vtable_size);
                g_print ("Mscorlib mempool size:  %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
 
-               g_print ("\nGeneric instances:      %ld\n", mono_stats.generic_instance_count);
-               g_print ("Initialized classes:    %ld\n", mono_stats.generic_class_count);
-               g_print ("Inflated methods:       %ld / %ld\n", mono_stats.inflated_method_count_2,
-                        mono_stats.inflated_method_count);
+               g_print ("\nInitialized classes:    %ld\n", mono_stats.generic_class_count);
                g_print ("Inflated types:         %ld\n", mono_stats.inflated_type_count);
-               g_print ("Generics metadata size: %ld\n", mono_stats.generics_metadata_size);
                g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
 
                g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
@@ -5373,10 +4840,12 @@ print_jit_stats (void)
                g_print ("Hazardous pointers:     %ld\n", mono_stats.hazardous_pointer_count);
 #ifdef HAVE_SGEN_GC
                g_print ("Minor GC collections:   %ld\n", mono_stats.minor_gc_count);
+#endif
                g_print ("Major GC collections:   %ld\n", mono_stats.major_gc_count);
+#ifdef HAVE_SGEN_GC
                g_print ("Minor GC time in msecs: %lf\n", (double)mono_stats.minor_gc_time_usecs / 1000.0);
-               g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
 #endif
+               g_print ("Major GC time in msecs: %lf\n", (double)mono_stats.major_gc_time_usecs / 1000.0);
                if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
                        g_print ("\nDecl security check   : %ld\n", mono_jit_stats.cas_declsec_check);
                        g_print ("LinkDemand (user)     : %ld\n", mono_jit_stats.cas_linkdemand);
@@ -5396,11 +4865,8 @@ print_jit_stats (void)
 void
 mini_cleanup (MonoDomain *domain)
 {
-#ifdef HAVE_LINUX_RTC_H
-       if (rtc_fd >= 0)
-               enable_rtc_timer (FALSE);
-#endif
-
+       mono_runtime_shutdown_stat_profiler ();
+       
 #ifndef DISABLE_COM
        cominterop_release_all_rcws ();
 #endif
@@ -5430,6 +4896,8 @@ mini_cleanup (MonoDomain *domain)
 
        mono_trampolines_cleanup ();
 
+       mono_unwind_cleanup ();
+
        if (!mono_dont_free_global_codeman)
                mono_code_manager_destroy (global_codeman);
        g_hash_table_destroy (jit_icall_name_hash);