MIPS: Throw OverflowException if Int32.MinValue is divided by -1
[mono.git] / mono / mini / mini.c
index 1d29bf0ecd6202d77cef99443f77db151e04724e..4e221b9d9e0e7808eb67a0d874c4f1c28af159b9 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
@@ -99,6 +99,10 @@ guint32 mono_jit_tls_id = -1;
 MINI_FAST_TLS_DECLARE(mono_jit_tls);
 #endif
 
+#ifndef MONO_ARCH_MONITOR_ENTER_ADJUSTMENT
+#define MONO_ARCH_MONITOR_ENTER_ADJUSTMENT 1
+#endif
+
 MonoTraceSpec *mono_jit_trace_calls = NULL;
 gboolean mono_break_on_exc = FALSE;
 gboolean mono_compile_aot = FALSE;
@@ -364,6 +368,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)
 {
@@ -1128,6 +1136,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 +1252,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) {
@@ -2462,8 +2514,11 @@ mono_get_lmf (void)
 
        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
 }
@@ -2805,10 +2860,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 +3231,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 ();
        }
@@ -3494,6 +3554,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 +3608,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 +3652,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);
@@ -3659,9 +3735,12 @@ if (valgrind_register){
        mono_arch_patch_code (cfg->method, cfg->domain, cfg->native_code, cfg->patch_info, 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 +3960,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 +4859,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 +4876,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);
@@ -5746,20 +5824,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 +5961,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 +5979,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);
                }
        }
@@ -6096,6 +6170,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 +6190,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 +6294,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",