[xbuild] Make Engine.DefaultToolsVersion 2.0 .
[mono.git] / mono / mini / mini.c
index 7e6c446a24bb567edffeb9b7815731aa500d7470..c50c35970f67669446a4416508495e5160ab5d46 100644 (file)
@@ -6,7 +6,7 @@
  *   Dietmar Maurer (dietmar@ximian.com)
  *
  * Copyright 2002-2003 Ximian, Inc.
- * Coprygith 2003-2010 Novell, Inc.
+ * Copyright 2003-2010 Novell, Inc.
  */
 
 #define MONO_LLVM_IN_MINI 1
 #include "mini-gc.h"
 #include "debugger-agent.h"
 
-#if defined(HAVE_KW_THREAD)
-#define MINI_FAST_TLS_SET(x,y) x = y
-#define MINI_FAST_TLS_GET(x) x
-#define MINI_FAST_TLS_INIT(x)
-#define MINI_FAST_TLS_DECLARE(x) static __thread gpointer x MONO_TLS_FAST;
-#define MINI_HAVE_FAST_TLS
-#define MINI_THREAD_VAR_OFFSET(x,y) MONO_THREAD_VAR_OFFSET(x,y)
-#elif (defined(__APPLE__) && defined(__i386__))
-#define MINI_FAST_TLS_SET(x,y) pthread_setspecific(x, y)
-#define MINI_FAST_TLS_GET(x) pthread_getspecific(x)
-#define MINI_FAST_TLS_INIT(x) pthread_key_create(&x, NULL)
-#define MINI_FAST_TLS_DECLARE(x) static pthread_key_t x;
-#define MINI_HAVE_FAST_TLS
-#define MINI_THREAD_VAR_OFFSET(x,y) y = (gint32) x
-#else
-#define MINI_THREAD_VAR_OFFSET(x,y) MONO_THREAD_VAR_OFFSET(x,y)
-#endif
-
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
 
@@ -95,8 +77,10 @@ static gboolean default_opt_set = FALSE;
 
 guint32 mono_jit_tls_id = -1;
 
-#ifdef MINI_HAVE_FAST_TLS
-MINI_FAST_TLS_DECLARE(mono_jit_tls);
+MONO_FAST_TLS_DECLARE(mono_jit_tls);
+
+#ifndef MONO_ARCH_MONITOR_ENTER_ADJUSTMENT
+#define MONO_ARCH_MONITOR_ENTER_ADJUSTMENT 1
 #endif
 
 MonoTraceSpec *mono_jit_trace_calls = NULL;
@@ -364,6 +348,10 @@ mono_pmip (void *ip)
  * output.  Unlike mono_pmip which returns a string, this routine
  * prints the value on the standard output. 
  */
+#ifdef __GNUC__
+/* Prevent the linker from optimizing this away in embedding setups to help debugging */
+ __attribute__((used))
+#endif
 void
 mono_print_method_from_ip (void *ip)
 {
@@ -388,6 +376,7 @@ mono_print_method_from_ip (void *ip)
                }
                else
                        g_print ("No method at %p\n", ip);
+               fflush (stdout);
                return;
        }
        method = mono_method_full_name (ji->method, TRUE);
@@ -397,6 +386,7 @@ mono_print_method_from_ip (void *ip)
 
        if (source)
                g_print ("%s:%d\n", source->source_file, source->row);
+       fflush (stdout);
 
        mono_debug_free_source_location (source);
        g_free (method);
@@ -1128,6 +1118,18 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        inst->backend.is_pinvoke = 0;
        inst->dreg = vreg;
 
+       if (cfg->compute_gc_maps) {
+               if (type->byref) {
+                       mono_mark_vreg_as_mp (cfg, vreg);
+               } else {
+                       MonoType *t = mini_type_get_underlying_type (NULL, type);
+                       if ((MONO_TYPE_ISSTRUCT (t) && inst->klass->has_references) || MONO_TYPE_IS_REFERENCE (t)) {
+                               inst->flags |= MONO_INST_GC_TRACK;
+                               mono_mark_vreg_as_ref (cfg, vreg);
+                       }
+               }
+       }
+       
        cfg->varinfo [num] = inst;
 
        MONO_INIT_VARINFO (&cfg->vars [num], num);
@@ -1232,6 +1234,38 @@ mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index)
 
 #endif
 
+void
+mono_mark_vreg_as_ref (MonoCompile *cfg, int vreg)
+{
+       if (vreg >= cfg->vreg_is_ref_len) {
+               gboolean *tmp = cfg->vreg_is_ref;
+               int size = cfg->vreg_is_ref_len;
+
+               while (vreg >= cfg->vreg_is_ref_len)
+                       cfg->vreg_is_ref_len = cfg->vreg_is_ref_len ? cfg->vreg_is_ref_len * 2 : 32;
+               cfg->vreg_is_ref = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * cfg->vreg_is_ref_len);
+               if (size)
+                       memcpy (cfg->vreg_is_ref, tmp, size * sizeof (gboolean));
+       }
+       cfg->vreg_is_ref [vreg] = TRUE;
+}      
+
+void
+mono_mark_vreg_as_mp (MonoCompile *cfg, int vreg)
+{
+       if (vreg >= cfg->vreg_is_mp_len) {
+               gboolean *tmp = cfg->vreg_is_mp;
+               int size = cfg->vreg_is_mp_len;
+
+               while (vreg >= cfg->vreg_is_mp_len)
+                       cfg->vreg_is_mp_len = cfg->vreg_is_mp_len ? cfg->vreg_is_mp_len * 2 : 32;
+               cfg->vreg_is_mp = mono_mempool_alloc0 (cfg->mempool, sizeof (gboolean) * cfg->vreg_is_mp_len);
+               if (size)
+                       memcpy (cfg->vreg_is_mp, tmp, size * sizeof (gboolean));
+       }
+       cfg->vreg_is_mp [vreg] = TRUE;
+}      
+
 static MonoType*
 type_from_stack_type (MonoInst *ins) {
        switch (ins->type) {
@@ -1959,7 +1993,7 @@ mono_allocate_stack_slots_full (MonoCompile *cfg, gboolean backward, guint32 *st
 
        vars = mono_varlist_sort (cfg, vars, 0);
        offset = 0;
-       *stack_align = SIZEOF_REGISTER;
+       *stack_align = sizeof(mgreg_t);
        for (l = vars; l; l = l->next) {
                vmv = l->data;
                inst = cfg->varinfo [vmv->idx];
@@ -2403,14 +2437,14 @@ mono_destroy_compile (MonoCompile *cfg)
        g_free (cfg);
 }
 
-#ifdef MINI_HAVE_FAST_TLS
-MINI_FAST_TLS_DECLARE(mono_lmf_addr);
+#ifdef MONO_HAVE_FAST_TLS
+MONO_FAST_TLS_DECLARE(mono_lmf_addr);
 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
 /* 
  * When this is defined, the current lmf is stored in this tls variable instead of in 
  * jit_tls->lmf.
  */
-MINI_FAST_TLS_DECLARE(mono_lmf);
+MONO_FAST_TLS_DECLARE(mono_lmf);
 #endif
 #endif
 
@@ -2423,21 +2457,17 @@ mono_get_jit_tls_key (void)
 gint32
 mono_get_jit_tls_offset (void)
 {
-#ifdef MINI_HAVE_FAST_TLS
        int offset;
-       MINI_THREAD_VAR_OFFSET (mono_jit_tls, offset);
+       MONO_THREAD_VAR_OFFSET (mono_jit_tls, offset);
        return offset;
-#else
-       return -1;
-#endif
 }
 
 gint32
 mono_get_lmf_tls_offset (void)
 {
-#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
        int offset;
-       MINI_THREAD_VAR_OFFSET(mono_lmf,offset);
+       MONO_THREAD_VAR_OFFSET(mono_lmf,offset);
        return offset;
 #else
        return -1;
@@ -2448,22 +2478,25 @@ gint32
 mono_get_lmf_addr_tls_offset (void)
 {
        int offset;
-       MINI_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
+       MONO_THREAD_VAR_OFFSET(mono_lmf_addr,offset);
        return offset;
 }
 
 MonoLMF *
 mono_get_lmf (void)
 {
-#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
-       return MINI_FAST_TLS_GET (mono_lmf);
+#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       return MONO_FAST_TLS_GET (mono_lmf);
 #else
        MonoJitTlsData *jit_tls;
 
        if ((jit_tls = TlsGetValue (mono_jit_tls_id)))
                return jit_tls->lmf;
-
-       g_assert_not_reached ();
+       /*
+        * We do not assert here because this function can be called from
+        * mini-gc.c on a thread that has not executed any managed code, yet
+        * (the thread object allocation can trigger a collection).
+        */
        return NULL;
 #endif
 }
@@ -2471,8 +2504,8 @@ mono_get_lmf (void)
 MonoLMF **
 mono_get_lmf_addr (void)
 {
-#ifdef MINI_HAVE_FAST_TLS
-       return MINI_FAST_TLS_GET (mono_lmf_addr);
+#ifdef MONO_HAVE_FAST_TLS
+       return MONO_FAST_TLS_GET (mono_lmf_addr);
 #else
        MonoJitTlsData *jit_tls;
 
@@ -2500,8 +2533,8 @@ mono_get_lmf_addr (void)
 void
 mono_set_lmf (MonoLMF *lmf)
 {
-#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
-       MINI_FAST_TLS_SET (mono_lmf, lmf);
+#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       MONO_FAST_TLS_SET (mono_lmf, lmf);
 #endif
 
        (*mono_get_lmf_addr ()) = lmf;
@@ -2512,16 +2545,16 @@ mono_set_jit_tls (MonoJitTlsData *jit_tls)
 {
        TlsSetValue (mono_jit_tls_id, jit_tls);
 
-#ifdef MINI_HAVE_FAST_TLS
-       MINI_FAST_TLS_SET (mono_jit_tls, jit_tls);
+#ifdef MONO_HAVE_FAST_TLS
+       MONO_FAST_TLS_SET (mono_jit_tls, jit_tls);
 #endif
 }
 
 static void
 mono_set_lmf_addr (gpointer lmf_addr)
 {
-#ifdef MINI_HAVE_FAST_TLS
-       MINI_FAST_TLS_SET (mono_lmf_addr, lmf_addr);
+#ifdef MONO_HAVE_FAST_TLS
+       MONO_FAST_TLS_SET (mono_lmf_addr, lmf_addr);
 #endif
 }
 
@@ -2536,8 +2569,8 @@ mono_jit_thread_attach (MonoDomain *domain)
                 */
                domain = mono_get_root_domain ();
 
-#ifdef MINI_HAVE_FAST_TLS
-       if (!MINI_FAST_TLS_GET (mono_lmf_addr)) {
+#ifdef MONO_HAVE_FAST_TLS
+       if (!MONO_FAST_TLS_GET (mono_lmf_addr)) {
                mono_thread_attach (domain);
        }
 #else
@@ -2592,9 +2625,9 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 
        jit_tls->first_lmf = lmf;
 
-#if defined(MINI_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+#if defined(MONO_HAVE_FAST_TLS) && defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
        /* jit_tls->lmf is unused */
-       MINI_FAST_TLS_SET (mono_lmf, lmf);
+       MONO_FAST_TLS_SET (mono_lmf, lmf);
        mono_set_lmf_addr (&mono_lmf);
 #else
        mono_set_lmf_addr (&jit_tls->lmf);
@@ -2805,10 +2838,11 @@ mono_patch_info_hash (gconstpointer data)
        switch (ji->type) {
        case MONO_PATCH_INFO_RVA:
        case MONO_PATCH_INFO_LDSTR:
-       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
        case MONO_PATCH_INFO_LDTOKEN:
        case MONO_PATCH_INFO_DECLSEC:
                return (ji->type << 8) | ji->data.token->token;
+       case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
+               return (ji->type << 8) | ji->data.token->token | (ji->data.token->has_context ? (gsize)ji->data.token->context.class_inst : 0);
        case MONO_PATCH_INFO_INTERNAL_METHOD:
                return (ji->type << 8) | g_str_hash (ji->data.name);
        case MONO_PATCH_INFO_VTABLE:
@@ -3175,6 +3209,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
                break;
        }
+       case MONO_PATCH_INFO_CASTCLASS_CACHE: {
+               target = mono_domain_alloc0 (domain, sizeof (gpointer));
+               break;
+       }
        default:
                g_assert_not_reached ();
        }
@@ -3347,7 +3385,7 @@ mono_postprocess_patches (MonoCompile *cfg)
                        break;
                }
                case MONO_PATCH_INFO_METHOD_JUMP: {
-                       GSList *list;
+                       MonoJumpList *jlist;
                        MonoDomain *domain = cfg->domain;
                        unsigned char *ip = cfg->native_code + patch_info->ip.i;
 #if defined(__native_client__) && defined(__native_client_codegen__)
@@ -3358,11 +3396,12 @@ mono_postprocess_patches (MonoCompile *cfg)
 #endif
 
                        mono_domain_lock (domain);
-                       if (!domain_jit_info (domain)->jump_target_hash)
-                               domain_jit_info (domain)->jump_target_hash = g_hash_table_new (NULL, NULL);
-                       list = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
-                       list = g_slist_prepend (list, ip);
-                       g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, list);
+                       jlist = g_hash_table_lookup (domain_jit_info (domain)->jump_target_hash, patch_info->data.method);
+                       if (!jlist) {
+                               jlist = mono_domain_alloc0 (domain, sizeof (MonoJumpList));
+                               g_hash_table_insert (domain_jit_info (domain)->jump_target_hash, patch_info->data.method, jlist);
+                       }
+                       jlist->list = g_slist_prepend (jlist->list, ip);
                        mono_domain_unlock (domain);
                        break;
                }
@@ -3494,6 +3533,17 @@ mono_codegen (MonoCompile *cfg)
        MonoBasicBlock *bb;
        int max_epilog_size;
        guint8 *code;
+       MonoDomain *code_domain;
+
+       if (mono_using_xdebug)
+               /*
+                * Recent gdb versions have trouble processing symbol files containing
+                * overlapping address ranges, so allocate all code from the code manager
+                * of the root domain. (#666152).
+                */
+               code_domain = mono_get_root_domain ();
+       else
+               code_domain = cfg->domain;
 
 #if defined(__native_client_codegen__) && defined(__native_client__)
        void *code_dest;
@@ -3537,6 +3587,7 @@ mono_codegen (MonoCompile *cfg)
        /* emit code all basic blocks */
        for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
                bb->native_offset = cfg->code_len;
+               bb->real_native_offset = cfg->code_len;
                //if ((bb == cfg->bb_entry) || !(bb->region == -1 && !bb->dfn))
                        mono_arch_output_basic_block (cfg, bb);
                bb->native_length = cfg->code_len - bb->native_offset;
@@ -3580,13 +3631,17 @@ mono_codegen (MonoCompile *cfg)
                mono_dynamic_code_hash_insert (cfg->domain, cfg->method, cfg->dynamic_info);
                mono_domain_unlock (cfg->domain);
 
-               code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
+               if (mono_using_xdebug)
+                       /* See the comment for cfg->code_domain */
+                       code = mono_domain_code_reserve (code_domain, cfg->code_size + unwindlen);
+               else
+                       code = mono_code_manager_reserve (cfg->dynamic_info->code_mp, cfg->code_size + unwindlen);
        } else {
                guint unwindlen = 0;
 #ifdef MONO_ARCH_HAVE_UNWIND_TABLE
                unwindlen = mono_arch_unwindinfo_get_size (cfg->arch.unwindinfo);
 #endif
-               code = mono_domain_code_reserve (cfg->domain, cfg->code_size + unwindlen);
+               code = mono_domain_code_reserve (code_domain, cfg->code_size + unwindlen);
        }
 #if defined(__native_client_codegen__) && defined(__native_client__)
        nacl_allow_target_modification (TRUE);
@@ -3656,12 +3711,15 @@ if (valgrind_register){
        mono_nacl_fix_patches (cfg->native_code, cfg->patch_info);
 #endif
 
-       mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->run_cctors);
+       mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, cfg->dynamic_info ? cfg->dynamic_info->code_mp : NULL, cfg->run_cctors);
 
        if (cfg->method->dynamic) {
-               mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
+               if (mono_using_xdebug)
+                       mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len);
+               else
+                       mono_code_manager_commit (cfg->dynamic_info->code_mp, cfg->native_code, cfg->code_size, cfg->code_len);
        } else {
-               mono_domain_code_commit (cfg->domain, cfg->native_code, cfg->code_size, cfg->code_len);
+               mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len);
        }
 #if defined(__native_client_codegen__) && defined(__native_client__)
        cfg->native_code = code_dest;
@@ -3881,9 +3939,8 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                                /*
                                 * Extend the try block backwards to include parts of the previous call
                                 * instruction.
-                                * FIXME: This is arch specific.
                                 */
-                               ei->try_start = (guint8*)ei->try_start - 1;
+                               ei->try_start = (guint8*)ei->try_start - MONO_ARCH_MONITOR_ENTER_ADJUSTMENT;
                        }
                        tblock = cfg->cil_offset_to_bb [ec->try_offset + ec->try_len];
                        g_assert (tblock);
@@ -4781,12 +4838,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        else
                InterlockedIncrement (&mono_jit_stats.methods_without_llvm);
 
-       if (cfg->verbose_level >= 2) {
-               char *id =  mono_method_full_name (cfg->method, FALSE);
-               mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
-               g_free (id);
-       }
-
        cfg->jit_info = create_jit_info (cfg, method_to_compile);
 
 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
@@ -4804,6 +4855,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
  
        mono_save_seq_point_info (cfg);
 
+       if (cfg->verbose_level >= 2) {
+               char *id =  mono_method_full_name (cfg->method, FALSE);
+               mono_disassemble_code (cfg, cfg->native_code, cfg->code_len, id + 3);
+               g_free (id);
+       }
+
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
                mono_jit_info_table_add (cfg->domain, cfg->jit_info);
@@ -5181,18 +5238,19 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 #ifndef DISABLE_JIT
        if (domain_jit_info (target_domain)->jump_target_hash) {
                MonoJumpInfo patch_info;
-               GSList *list, *tmp;
-               list = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method);
-               if (list) {
+               MonoJumpList *jlist;
+               GSList *tmp;
+               jlist = g_hash_table_lookup (domain_jit_info (target_domain)->jump_target_hash, method);
+               if (jlist) {
                        patch_info.next = NULL;
                        patch_info.ip.i = 0;
                        patch_info.type = MONO_PATCH_INFO_METHOD_JUMP;
                        patch_info.data.method = method;
                        g_hash_table_remove (domain_jit_info (target_domain)->jump_target_hash, method);
+
+                       for (tmp = jlist->list; tmp; tmp = tmp->next)
+                               mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, NULL, TRUE);
                }
-               for (tmp = list; tmp; tmp = tmp->next)
-                       mono_arch_patch_code (NULL, target_domain, tmp->data, &patch_info, TRUE);
-               g_slist_free (list);
        }
 
        mono_emit_jit_map (jinfo);
@@ -5332,6 +5390,8 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
 {
        MonoJitDynamicMethodInfo *ji;
        gboolean destroy = TRUE;
+       GHashTableIter iter;
+       MonoJumpList *jlist;
 
        g_assert (method->dynamic);
 
@@ -5341,11 +5401,31 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
 
        if (!ji)
                return;
+
        mono_domain_lock (domain);
        g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
        mono_internal_hash_table_remove (&domain->jit_code_hash, method);
        g_hash_table_remove (domain_jit_info (domain)->jump_trampoline_hash, method);
        g_hash_table_remove (domain_jit_info (domain)->runtime_invoke_hash, method);
+
+       /* Remove jump targets in this method */
+       g_hash_table_iter_init (&iter, domain_jit_info (domain)->jump_target_hash);
+       while (g_hash_table_iter_next (&iter, NULL, (void**)&jlist)) {
+               GSList *tmp, *remove;
+
+               remove = NULL;
+               for (tmp = jlist->list; tmp; tmp = tmp->next) {
+                       guint8 *ip = tmp->data;
+
+                       if (ip >= (guint8*)ji->ji->code_start && ip < (guint8*)ji->ji->code_start + ji->ji->code_size)
+                               remove = g_slist_prepend (remove, tmp);
+               }
+               for (tmp = remove; tmp; tmp = tmp->next) {
+                       jlist->list = g_slist_delete_link (jlist->list, tmp->data);
+               }
+               g_slist_free (remove);
+       }
+
        mono_domain_unlock (domain);
 
 #ifdef MONO_ARCH_HAVE_INVALIDATE_METHOD
@@ -5746,20 +5826,14 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
        }
 #endif
 
-       /* The hard-guard page has been hit: there is not much we can do anymore
-        * Print a hopefully clear message and abort.
-        */
        if (jit_tls->stack_size && 
                ABS ((guint8*)fault_addr - ((guint8*)jit_tls->end_of_stack - jit_tls->stack_size)) < 8192 * sizeof (gpointer)) {
-               const char *method;
-               /* we don't do much now, but we can warn the user with a useful message */
-               fprintf (stderr, "Stack overflow: IP: %p, fault addr: %p\n", mono_arch_ip_from_context (ctx), (gpointer)info->si_addr);
-               if (ji && ji->method)
-                       method = mono_method_full_name (ji->method, TRUE);
-               else
-                       method = "Unmanaged";
-               fprintf (stderr, "At %s\n", method);
-               _exit (1);
+               /*
+                * The hard-guard page has been hit: there is not much we can do anymore
+                * Print a hopefully clear message and abort.
+                */
+               mono_handle_hard_stack_ovf (jit_tls, ji, ctx, (guint8*)info->si_addr);
+               g_assert_not_reached ();
        } else {
                /* The original handler might not like that it is executed on an altstack... */
                if (!ji && mono_chain_signal (SIG_HANDLER_PARAMS))
@@ -5889,6 +5963,8 @@ mini_parse_debug_options (void)
                        debug_options.no_gdb_backtrace = TRUE;
                else if (!strcmp (arg, "suspend-on-sigsegv"))
                        debug_options.suspend_on_sigsegv = TRUE;
+               else if (!strcmp (arg, "suspend-on-unhandled"))
+                       debug_options.suspend_on_unhandled = TRUE;
                else if (!strcmp (arg, "dont-free-domains"))
                        mono_dont_free_domains = TRUE;
                else if (!strcmp (arg, "dyn-runtime-invoke"))
@@ -5905,7 +5981,7 @@ mini_parse_debug_options (void)
                        debug_options.better_cast_details = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
-                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'suspend-on-unhandled', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'init-stacks'\n");
                        exit (1);
                }
        }
@@ -5981,6 +6057,7 @@ mini_create_jit_domain_info (MonoDomain *domain)
        info->runtime_invoke_hash = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, runtime_invoke_info_free);
        info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, g_free);
        info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
+       info->jump_target_hash = g_hash_table_new (NULL, NULL);
 
        domain->runtime_info = info;
 }
@@ -5988,7 +6065,8 @@ mini_create_jit_domain_info (MonoDomain *domain)
 static void
 delete_jump_list (gpointer key, gpointer value, gpointer user_data)
 {
-       g_slist_free (value);
+       MonoJumpList *jlist = value;
+       g_slist_free (jlist->list);
 }
 
 static void
@@ -6016,10 +6094,8 @@ mini_free_jit_domain_info (MonoDomain *domain)
 {
        MonoJitDomainInfo *info = domain_jit_info (domain);
 
-       if (info->jump_target_hash) {
-               g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
-               g_hash_table_destroy (info->jump_target_hash);
-       }
+       g_hash_table_foreach (info->jump_target_hash, delete_jump_list, NULL);
+       g_hash_table_destroy (info->jump_target_hash);
        if (info->jump_target_got_slot_hash) {
                g_hash_table_foreach (info->jump_target_got_slot_hash, delete_jump_list, NULL);
                g_hash_table_destroy (info->jump_target_got_slot_hash);
@@ -6074,11 +6150,11 @@ mini_init (const char *filename, const char *runtime_version)
                mini_debugger_init ();
 #endif
 
-#ifdef MINI_HAVE_FAST_TLS
-       MINI_FAST_TLS_INIT (mono_jit_tls);
-       MINI_FAST_TLS_INIT (mono_lmf_addr);
+#ifdef MONO_HAVE_FAST_TLS
+       MONO_FAST_TLS_INIT (mono_jit_tls);
+       MONO_FAST_TLS_INIT (mono_lmf_addr);
 #ifdef MONO_ARCH_ENABLE_MONO_LMF_VAR
-       MINI_FAST_TLS_INIT (mono_lmf);
+       MONO_FAST_TLS_INIT (mono_lmf);
 #endif
 #endif
 
@@ -6096,6 +6172,7 @@ mini_init (const char *filename, const char *runtime_version)
        callbacks.create_ftnptr = mini_create_ftnptr;
        callbacks.get_addr_from_ftnptr = mini_get_addr_from_ftnptr;
        callbacks.get_runtime_build_info = mono_get_runtime_build_info;
+       callbacks.set_cast_details = mono_set_cast_details;
 
 #ifdef MONO_ARCH_HAVE_IMT
        if (mono_use_imt) {
@@ -6115,8 +6192,6 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_unwind_init ();
 
-       mini_gc_init ();
-
        if (getenv ("MONO_XDEBUG")) {
                char *xdebug_opts = getenv ("MONO_XDEBUG");
                mono_xdebug_init (xdebug_opts);
@@ -6221,6 +6296,9 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_icall_init ();
 
+       /* This should come after mono_init () too */
+       mini_gc_init ();
+
        mono_add_internal_call ("System.Diagnostics.StackFrame::get_frame_info", 
                                ves_icall_get_frame_info);
        mono_add_internal_call ("System.Diagnostics.StackTrace::get_trace",