Merge pull request #1603 from iainx/coverage-null-protect
[mono.git] / mono / mini / mini.c
index 71da4bda58ad96f2b12bc4e8a4d1124a975704a7..ca734ad3e2252313216a5d557c906d99b2bd4c7a 100755 (executable)
@@ -22,6 +22,9 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
 
 #include <mono/utils/memcheck.h>
 
@@ -138,9 +141,6 @@ mono_breakpoint_info_index [MONO_BREAKPOINT_ARRAY_SIZE];
 /* Whenever to check for pending exceptions in managed-to-native wrappers */
 gboolean check_for_pending_exc = TRUE;
 
-/* Whenever to disable passing/returning small valuetypes in registers for managed methods */
-gboolean disable_vtypes_in_regs = FALSE;
-
 static GSList *tramp_infos;
 
 static void register_icalls (void);
@@ -1380,6 +1380,20 @@ mono_compile_make_var_load (MonoCompile *cfg, MonoInst *dest, gssize var_index)
        dest->klass = dest->inst_i0->klass;
 }
 
+MonoInst*
+mini_get_int_to_float_spill_area (MonoCompile *cfg)
+{
+#ifdef TARGET_X86
+       if (!cfg->iconv_raw_var) {
+               cfg->iconv_raw_var = mono_compile_create_var (cfg, &mono_defaults.int32_class->byval_arg, OP_LOCAL);
+               cfg->iconv_raw_var->flags |= MONO_INST_VOLATILE; /*FIXME, use the don't regalloc flag*/
+       }
+       return cfg->iconv_raw_var;
+#else
+       return NULL;
+#endif
+}
+
 #endif
 
 void
@@ -1493,7 +1507,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
                                /* Only two instructions */
                                opcode = bb->code->opcode;
 
-                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
+                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM) || (opcode == OP_RCOMPARE)) {
                                        /* NEW IR */
                                        mono_bblock_insert_before_ins (bb, bb->code, inst);
                                } else {
@@ -1502,7 +1516,7 @@ mono_add_ins_to_end (MonoBasicBlock *bb, MonoInst *inst)
                        } else {
                                opcode = bb->last_ins->prev->opcode;
 
-                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM)) {
+                               if ((opcode == OP_COMPARE) || (opcode == OP_COMPARE_IMM) || (opcode == OP_ICOMPARE) || (opcode == OP_ICOMPARE_IMM) || (opcode == OP_FCOMPARE) || (opcode == OP_LCOMPARE) || (opcode == OP_LCOMPARE_IMM) || (opcode == OP_RCOMPARE)) {
                                        /* NEW IR */
                                        mono_bblock_insert_before_ins (bb, bb->last_ins->prev, inst);
                                } else {
@@ -1706,6 +1720,7 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
        MonoMethod *wrapper;
        gconstpointer trampoline;
        MonoDomain *domain = mono_get_root_domain ();
+       gboolean check_exc = check_for_pending_exc;
        
        if (callinfo->wrapper) {
                return callinfo->wrapper;
@@ -1727,8 +1742,12 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
                return callinfo->trampoline;
        }
 
+       if (!strcmp (callinfo->name, "mono_thread_interruption_checkpoint"))
+               /* This icall is used to check for exceptions, so don't check in the wrapper */
+               check_exc = FALSE;
+
        name = g_strdup_printf ("__icall_wrapper_%s", callinfo->name);
-       wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_for_pending_exc);
+       wrapper = mono_marshal_get_icall_wrapper (callinfo->sig, name, callinfo->func, check_exc);
        g_free (name);
 
        if (do_compile)
@@ -2398,7 +2417,8 @@ register_opcode_emulation (int opcode, const char *name, const char *sigstr, gpo
        g_assert (!sig->hasthis);
        g_assert (sig->param_count < 3);
 
-       info = mono_register_jit_icall_full (func, name, sig, no_throw, symbol);
+       /* Opcode emulation functions are assumed to don't call mono_raise_exception () */
+       info = mono_register_jit_icall_full (func, name, sig, no_throw, TRUE, symbol);
 
        if (emul_opcode_num >= emul_opcode_alloced) {
                int incr = emul_opcode_alloced? emul_opcode_alloced/2: 16;
@@ -2428,7 +2448,21 @@ register_icall (gpointer func, const char *name, const char *sigstr, gboolean sa
        else
                sig = NULL;
 
-       mono_register_jit_icall_full (func, name, sig, save, save ? name : NULL);
+       mono_register_jit_icall_full (func, name, sig, save, FALSE, save ? name : NULL);
+}
+
+/* Register a jit icall which doesn't throw exceptions through mono_raise_exception () */
+static void
+register_icall_noraise (gpointer func, const char *name, const char *sigstr)
+{
+       MonoMethodSignature *sig;
+
+       if (sigstr)
+               sig = mono_create_icall_signature (sigstr);
+       else
+               sig = NULL;
+
+       mono_register_jit_icall_full (func, name, sig, TRUE, TRUE, name);
 }
 
 static void
@@ -3980,6 +4014,9 @@ mono_codegen (MonoCompile *cfg)
 
                if (cfg->opt & MONO_OPT_PEEPHOLE)
                        mono_arch_peephole_pass_2 (cfg, bb);
+
+               if (cfg->gen_seq_points && !cfg->gen_seq_points_debug_data)
+                       bb_deduplicate_op_il_seq_points (cfg, bb);
        }
 
        if (cfg->prof_options & MONO_PROFILE_COVERAGE)
@@ -4879,6 +4916,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->compile_llvm = try_llvm;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
 
+       if (!mono_debug_count ())
+               cfg->opt &= ~MONO_OPT_FLOAT32;
+       cfg->r4fp = (cfg->opt & MONO_OPT_FLOAT32) ? 1 : 0;
+       cfg->r4_stack_type = cfg->r4fp ? STACK_R4 : STACK_R8;
+
        if (cfg->gen_seq_points)
                cfg->seq_points = g_ptr_array_new ();
        mono_error_init (&cfg->error);
@@ -6689,11 +6731,13 @@ MONO_SIG_HANDLER_FUNC (, mono_sigsegv_signal_handler)
 #endif
 
 #if defined(HAVE_SIG_INFO)
+#if !defined(HOST_WIN32)
        fault_addr = info->si_addr;
        if (mono_aot_is_pagefault (info->si_addr)) {
                mono_aot_handle_pagefault (info->si_addr);
                return;
        }
+#endif
 
        /* The thread might no be registered with the runtime */
        if (!mono_domain_get () || !jit_tls) {
@@ -7449,7 +7493,8 @@ register_icalls (void)
        register_dyn_icall (mono_get_rethrow_exception (), "mono_arch_rethrow_exception", "void object", TRUE);
        register_dyn_icall (mono_get_throw_corlib_exception (), "mono_arch_throw_corlib_exception", "void ptr", TRUE);
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", FALSE);
-       register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "void", FALSE);
+       register_icall (mono_thread_interruption_checkpoint, "mono_thread_interruption_checkpoint", "object", FALSE);
+       register_icall (mono_thread_force_interruption_checkpoint_noraise, "mono_thread_force_interruption_checkpoint_noraise", "object", FALSE);
        register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
 #ifndef DISABLE_REMOTING
        register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
@@ -7508,9 +7553,12 @@ register_icalls (void)
        register_opcode_emulation (OP_FCONV_TO_U4, "__emul_fconv_to_u4", "uint32 double", mono_fconv_u4, "mono_fconv_u4", FALSE);
        register_opcode_emulation (OP_FCONV_TO_OVF_I8, "__emul_fconv_to_ovf_i8", "long double", mono_fconv_ovf_i8, "mono_fconv_ovf_i8", FALSE);
        register_opcode_emulation (OP_FCONV_TO_OVF_U8, "__emul_fconv_to_ovf_u8", "ulong double", mono_fconv_ovf_u8, "mono_fconv_ovf_u8", FALSE);
+       register_opcode_emulation (OP_RCONV_TO_OVF_I8, "__emul_rconv_to_ovf_i8", "long float", mono_rconv_ovf_i8, "mono_rconv_ovf_i8", FALSE);
+       register_opcode_emulation (OP_RCONV_TO_OVF_U8, "__emul_rconv_to_ovf_u8", "ulong float", mono_rconv_ovf_u8, "mono_rconv_ovf_u8", FALSE);
 
 #ifdef MONO_ARCH_EMULATE_FCONV_TO_I8
        register_opcode_emulation (OP_FCONV_TO_I8, "__emul_fconv_to_i8", "long double", mono_fconv_i8, "mono_fconv_i8", FALSE);
+       register_opcode_emulation (OP_RCONV_TO_I8, "__emul_rconv_to_i8", "long float", mono_rconv_i8, "mono_rconv_i8", FALSE);
 #endif
 #ifdef MONO_ARCH_EMULATE_CONV_R8_UN
        register_opcode_emulation (OP_ICONV_TO_R_UN, "__emul_iconv_to_r_un", "double int32", mono_conv_to_r8_un, "mono_conv_to_r8_un", FALSE);