Merge pull request #3749 from BrzVlad/fix-mips-fix
[mono.git] / mono / mini / mini.c
index 0dcda64a378eafd968056c96d79fe1c67b70f84c..51ca3d5c79cc415a49c4f92c14bccba3c6be9bec 100644 (file)
@@ -58,6 +58,7 @@
 #include <mono/utils/mono-hwcap.h>
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include <mono/io-layer/io-layer.h>
 
 #include "mini.h"
@@ -1051,7 +1052,7 @@ mini_method_verify (MonoCompile *cfg, MonoMethod *method, gboolean fail_compile)
                                        else if (info->exception_type == MONO_EXCEPTION_FIELD_ACCESS)
                                                mono_error_set_generic_error (&cfg->error, "System", "FieldAccessException", "%s", msg);
                                        else if (info->exception_type == MONO_EXCEPTION_UNVERIFIABLE_IL)
-                                               mono_error_set_generic_error (&cfg->error, "System.Security", "VerificationException", msg);
+                                               mono_error_set_generic_error (&cfg->error, "System.Security", "VerificationException", "%s", msg);
                                        if (!mono_error_ok (&cfg->error)) {
                                                mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
                                                g_free (msg);
@@ -1168,7 +1169,7 @@ mono_allocate_stack_slots2 (MonoCompile *cfg, gboolean backward, guint32 *stack_
                vars = g_list_prepend (vars, vmv);
        }
 
-       vars = g_list_sort (g_list_copy (vars), compare_by_interval_start_pos_func);
+       vars = g_list_sort (vars, compare_by_interval_start_pos_func);
 
        /* Sanity check */
        /*
@@ -1885,28 +1886,59 @@ mono_verify_cfg (MonoCompile *cfg)
                mono_verify_bblock (bb);
 }
 
+// This will free many fields in cfg to save
+// memory. Note that this must be safe to call
+// multiple times. It must be idempotent. 
+void
+mono_empty_compile (MonoCompile *cfg)
+{
+       mono_free_loop_info (cfg);
+
+       // These live in the mempool, and so must be freed
+       // first
+       for (GSList *l = cfg->headers_to_free; l; l = l->next) {
+               mono_metadata_free_mh ((MonoMethodHeader *)l->data);
+       }
+       cfg->headers_to_free = NULL;
+
+       if (cfg->mempool) {
+       //mono_mempool_stats (cfg->mempool);
+               mono_mempool_destroy (cfg->mempool);
+               cfg->mempool = NULL;
+       }
+
+       g_free (cfg->varinfo);
+       cfg->varinfo = NULL;
+
+       g_free (cfg->vars);
+       cfg->vars = NULL;
+
+       if (cfg->rs) {
+               mono_regstate_free (cfg->rs);
+               cfg->rs = NULL;
+       }
+}
+
 void
 mono_destroy_compile (MonoCompile *cfg)
 {
-       GSList *l;
+       mono_empty_compile (cfg);
 
        if (cfg->header)
                mono_metadata_free_mh (cfg->header);
-       //mono_mempool_stats (cfg->mempool);
-       mono_free_loop_info (cfg);
-       if (cfg->rs)
-               mono_regstate_free (cfg->rs);
+
        if (cfg->spvars)
                g_hash_table_destroy (cfg->spvars);
        if (cfg->exvars)
                g_hash_table_destroy (cfg->exvars);
-       for (l = cfg->headers_to_free; l; l = l->next)
-               mono_metadata_free_mh ((MonoMethodHeader *)l->data);
+
        g_list_free (cfg->ldstr_list);
-       g_hash_table_destroy (cfg->token_info_hash);
+
+       if (cfg->token_info_hash)
+               g_hash_table_destroy (cfg->token_info_hash);
+
        if (cfg->abs_patches)
                g_hash_table_destroy (cfg->abs_patches);
-       mono_mempool_destroy (cfg->mempool);
 
        mono_debug_free_method (cfg);
 
@@ -1951,6 +1983,18 @@ mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
        if (!cfg->backend->have_tls_get)
                return NULL;
 
+#ifdef HAVE_KW_THREAD
+       /*
+        * MONO_THREAD_VAR_OFFSET definitions don't work when loading mono as a
+        * dynamic library. This means that we need to be conservative and don't
+        * aot code that contains these tls chunks.
+        *
+        * FIXME Remove HAVE_KW_THREAD altogether and use only pthread since it
+        * simplifies the code alot.
+        */
+       if (!cfg->full_aot)
+               cfg->disable_aot = TRUE;
+#endif
        /*
         * TLS offsets might be different at AOT time, so load them from a GOT slot and
         * use a different opcode.
@@ -2895,6 +2939,17 @@ is_open_method (MonoMethod *method)
        return FALSE;
 }
 
+static void mono_insert_nop_in_empty_bb (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb;
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               if (bb->code)
+                       continue;
+               MonoInst *nop;
+               MONO_INST_NEW (cfg, nop, OP_NOP);
+               MONO_ADD_INS (bb, nop);
+       }
+}
 static void
 mono_create_gc_safepoint (MonoCompile *cfg, MonoBasicBlock *bblock)
 {
@@ -3081,8 +3136,8 @@ init_backend (MonoBackend *backend)
 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
        backend->have_objc_get_selector = 1;
 #endif
-#ifdef MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK
-       backend->have_generalized_imt_thunk = 1;
+#ifdef MONO_ARCH_HAVE_GENERALIZED_IMT_TRAMPOLINE
+       backend->have_generalized_imt_trampoline = 1;
 #endif
 #ifdef MONO_ARCH_GSHARED_SUPPORTED
        backend->gshared_supported = 1;
@@ -3120,6 +3175,9 @@ init_backend (MonoBackend *backend)
 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
        backend->dyn_call_param_area = MONO_ARCH_DYN_CALL_PARAM_AREA;
 #endif
+#ifdef MONO_ARCH_NO_DIV_WITH_MUL
+       backend->disable_div_with_mul = 1;
+#endif
 }
 
 /*
@@ -3229,7 +3287,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        cfg->disable_omit_fp = debug_options.disable_omit_fp;
        cfg->skip_visibility = method->skip_visibility;
        cfg->orig_method = method;
-       cfg->gen_seq_points = debug_options.gen_seq_points_compact_data || debug_options.gen_sdb_seq_points;
+       cfg->gen_seq_points = !debug_options.no_seq_points_compact_data || debug_options.gen_sdb_seq_points;
        cfg->gen_sdb_seq_points = debug_options.gen_sdb_seq_points;
        cfg->llvm_only = (flags & JIT_FLAG_LLVM_ONLY) != 0;
        cfg->backend = current_backend;
@@ -3241,6 +3299,11 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                cfg->gen_sdb_seq_points = FALSE;
        }
 #endif
+       if (cfg->method->wrapper_type == MONO_WRAPPER_ALLOC) {
+               /* We can't have seq points inside gc critical regions */
+               cfg->gen_seq_points = FALSE;
+               cfg->gen_sdb_seq_points = FALSE;
+       }
        /* coop / nacl requires loop detection to happen */
 #if defined(__native_client_codegen__)
        cfg->opt |= MONO_OPT_LOOP;
@@ -3351,6 +3414,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                                        //g_free (nm);
                                }
                                if (cfg->llvm_only) {
+                                       g_free (cfg->exception_message);
                                        cfg->disable_aot = TRUE;
                                        return cfg;
                                }
@@ -3498,6 +3562,12 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
        MONO_TIME_TRACK (mono_jit_stats.jit_method_to_ir, i = mono_method_to_ir (cfg, method_to_compile, NULL, NULL, NULL, NULL, 0, FALSE));
        mono_cfg_dump_ir (cfg, "method-to-ir");
 
+       if (cfg->gdump_ctx != NULL) {
+               /* workaround for graph visualization, as it doesn't handle empty basic blocks properly */
+               mono_insert_nop_in_empty_bb (cfg);
+               mono_cfg_dump_ir (cfg, "mono_insert_nop_in_empty_bb");
+       }
+
        if (i < 0) {
                if (try_generic_shared && cfg->exception_type == MONO_EXCEPTION_GENERIC_SHARING_FAILED) {
                        if (compile_aot) {
@@ -3576,6 +3646,15 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl
                mono_cfg_dump_ir (cfg, "local_cprop");
        }
 
+       if (cfg->flags & MONO_CFG_HAS_TYPE_CHECK) {
+               MONO_TIME_TRACK (mono_jit_stats.jit_decompose_typechecks, mono_decompose_typechecks (cfg));
+               if (cfg->gdump_ctx != NULL) {
+                       /* workaround for graph visualization, as it doesn't handle empty basic blocks properly */
+                       mono_insert_nop_in_empty_bb (cfg);
+               }
+               mono_cfg_dump_ir (cfg, "decompose_typechecks");
+       }
+
        /*
         * Should be done after cprop which can do strength reduction on
         * some of these ops, after propagating immediates.
@@ -3977,7 +4056,7 @@ void
 mono_cfg_set_exception_invalid_program (MonoCompile *cfg, char *msg)
 {
        mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
-       mono_error_set_generic_error (&cfg->error, "System", "InvalidProgramException", msg);
+       mono_error_set_generic_error (&cfg->error, "System", "InvalidProgramException", "%s", msg);
 }
 
 #endif /* DISABLE_JIT */
@@ -4165,13 +4244,9 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        if (mono_aot_only) {
                char *fullname = mono_method_full_name (method, TRUE);
-               char *msg = g_strdup_printf ("Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
-
-               ex = mono_get_exception_execution_engine (msg);
-               mono_error_set_exception_instance (error, ex);
+               mono_error_set_execution_engine (error, "Attempting to JIT compile method '%s' while running with --aot-only. See http://docs.xamarin.com/ios/about/limitations for more information.\n", fullname);
                g_free (fullname);
-               g_free (msg);
-               
+
                return NULL;
        }
 
@@ -4325,9 +4400,8 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
 
        vtable = mono_class_vtable (target_domain, method->klass);
        if (!vtable) {
-               ex = mono_class_get_exception_for_failure (method->klass);
-               g_assert (ex);
-               mono_error_set_exception_instance (error, ex);
+               g_assert (mono_class_has_failure (method->klass));
+               mono_error_set_for_class_failure (error, method->klass);
                return NULL;
        }