Merge pull request #832 from xplicit/webperf1
[mono.git] / mono / mini / mini.c
index 6d7de6f3b8104b13d468a9d77a090ab9513a4fee..7a431b78b5f7b44e2bfd284be761b1e9759eecde 100644 (file)
@@ -49,6 +49,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
 #include <mono/metadata/runtime.h>
+#include <mono/metadata/mono-debug-debugger.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
 
 #include "jit-icalls.h"
 
-#include "debug-mini.h"
 #include "mini-gc.h"
 #include "debugger-agent.h"
 
-/* this macro is used for a runtime check done in mini_init () */
-#ifdef MONO_ARCH_EMULATE_MUL_DIV
-#define EMUL_MUL_DIV 1
-#else
-#define EMUL_MUL_DIV 0
-#endif
-
 static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
 
 
@@ -94,20 +87,12 @@ MonoNativeTlsKey mono_jit_tls_id;
 MONO_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_compile_aot = FALSE;
 /* If this is set, no code is generated dynamically, everything is taken from AOT files */
 gboolean mono_aot_only = FALSE;
 /* Whenever to use IMT */
-#ifdef MONO_ARCH_HAVE_IMT
-gboolean mono_use_imt = TRUE;
-#else
-gboolean mono_use_imt = FALSE;
-#endif
+gboolean mono_use_imt = ARCH_HAVE_IMT;
 MonoMethodDesc *mono_inject_async_exc_method = NULL;
 int mono_inject_async_exc_pos;
 MonoMethodDesc *mono_break_at_bb_method = NULL;
@@ -912,6 +897,8 @@ mono_type_to_store_membase (MonoCompile *cfg, MonoType *type)
        if (type->byref)
                return OP_STORE_MEMBASE_REG;
 
+       type = mini_replace_type (type);
+
 handle_enum:
        switch (type->type) {
        case MONO_TYPE_I1:
@@ -974,7 +961,7 @@ mono_type_to_load_membase (MonoCompile *cfg, MonoType *type)
        if (type->byref)
                return OP_LOAD_MEMBASE;
 
-       type = mono_type_get_underlying_type (type);
+       type = mini_replace_type (type);
 
        switch (type->type) {
        case MONO_TYPE_I1:
@@ -1052,6 +1039,8 @@ mini_type_to_ldind (MonoCompile* cfg, MonoType *type)
 guint
 mini_type_to_stind (MonoCompile* cfg, MonoType *type)
 {
+       type = mini_replace_type (type);
+
        if (cfg->generic_sharing_context && !type->byref) {
                if (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR) {
                        if (mini_type_var_is_vt (cfg, type))
@@ -1231,6 +1220,8 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
        int num = cfg->num_varinfo;
        gboolean regpair;
 
+       type = mini_replace_type (type);
+
        if ((num + 1) >= cfg->varinfo_count) {
                int orig_count = cfg->varinfo_count;
                cfg->varinfo_count = cfg->varinfo_count ? (cfg->varinfo_count * 2) : 64;
@@ -1257,7 +1248,7 @@ mono_compile_create_var_for_vreg (MonoCompile *cfg, MonoType *type, int opcode,
                if (type->byref) {
                        mono_mark_vreg_as_mp (cfg, vreg);
                } else {
-                       MonoType *t = mini_type_get_underlying_type (NULL, type);
+                       MonoType *t = mini_replace_type (type);
                        if ((MONO_TYPE_ISSTRUCT (t) && inst->klass->has_references) || mini_type_is_reference (cfg, t)) {
                                inst->flags |= MONO_INST_GC_TRACK;
                                mono_mark_vreg_as_ref (cfg, vreg);
@@ -1339,6 +1330,7 @@ MonoInst*
 mono_compile_create_var (MonoCompile *cfg, MonoType *type, int opcode)
 {
        int dreg;
+       type = mini_replace_type (type);
 
        if (mono_type_is_long (type))
                dreg = mono_alloc_dreg (cfg, STACK_I8);
@@ -1535,10 +1527,9 @@ mono_get_array_new_va_signature (int arity)
        res = mono_metadata_signature_alloc (mono_defaults.corlib, arity + 1);
 
        res->pinvoke = 1;
-#ifdef MONO_ARCH_VARARG_ICALLS
-       /* Only set this only some archs since not all backends can handle varargs+pinvoke */
-       res->call_convention = MONO_CALL_VARARG;
-#endif
+       if (ARCH_VARARG_ICALLS)
+               /* Only set this only some archs since not all backends can handle varargs+pinvoke */
+               res->call_convention = MONO_CALL_VARARG;
 
 #ifdef TARGET_WIN32
        res->call_convention = MONO_CALL_C;
@@ -2854,7 +2845,6 @@ mono_thread_start_cb (intptr_t tid, gpointer stack_start, gpointer func)
        MonoInternalThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort);
        thread = mono_thread_internal_current ();
-       mono_debugger_thread_created (tid, thread->root_domain_thread, jit_tls, func);
        if (thread)
                thread->jit_data = jit_tls;
 
@@ -2878,7 +2868,6 @@ mono_thread_attach_cb (intptr_t tid, gpointer stack_start)
        MonoInternalThread *thread;
        void *jit_tls = setup_jit_tls_data (stack_start, mono_thread_abort_dummy);
        thread = mono_thread_internal_current ();
-       mono_debugger_thread_created (tid, thread->root_domain_thread, (MonoJitTlsData *) jit_tls, NULL);
        if (thread)
                thread->jit_data = jit_tls;
        if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
@@ -2893,8 +2882,6 @@ mini_thread_cleanup (MonoInternalThread *thread)
        MonoJitTlsData *jit_tls = thread->jit_data;
 
        if (jit_tls) {
-               mono_debugger_thread_cleanup (jit_tls);
-
                /* 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.
@@ -2942,6 +2929,7 @@ mini_get_tls_offset (MonoTlsKey key)
                g_assert (offset != -1);
                break;
        }
+
        return offset;
 }
 
@@ -2964,6 +2952,18 @@ mono_create_tls_get_offset (MonoCompile *cfg, int offset)
        return ins;
 }
 
+gboolean
+mini_tls_get_supported (MonoCompile *cfg, MonoTlsKey key)
+{
+       if (!MONO_ARCH_HAVE_TLS_GET)
+               return FALSE;
+
+       if (cfg->compile_aot)
+               return ARCH_HAVE_TLS_GET_REG;
+       else
+               return mini_get_tls_offset (key) != -1;
+}
+
 MonoInst*
 mono_create_tls_get (MonoCompile *cfg, MonoTlsKey key)
 {
@@ -3012,6 +3012,12 @@ mono_get_lmf_intrinsic (MonoCompile* cfg)
        return mono_create_tls_get (cfg, TLS_KEY_LMF);
 }
 
+MonoInst*
+mono_get_lmf_addr_intrinsic (MonoCompile* cfg)
+{
+       return mono_create_tls_get (cfg, TLS_KEY_LMF_ADDR);
+}
+
 #endif /* !DISABLE_JIT */
 
 void
@@ -3166,6 +3172,7 @@ mono_patch_info_hash (gconstpointer data)
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE:
        case MONO_PATCH_INFO_SIGNATURE:
        case MONO_PATCH_INFO_TLS_OFFSET:
+       case MONO_PATCH_INFO_METHOD_CODE_SLOT:
                return (ji->type << 8) | (gssize)ji->data.target;
        case MONO_PATCH_INFO_GSHAREDVT_CALL:
                return (ji->type << 8) | (gssize)ji->data.gsharedvt->method;
@@ -3330,6 +3337,21 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                }
 #endif
                break;
+       case MONO_PATCH_INFO_METHOD_CODE_SLOT: {
+               gpointer code_slot;
+
+               mono_domain_lock (domain);
+               if (!domain_jit_info (domain)->method_code_hash)
+                       domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
+               code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, patch_info->data.method);
+               if (!code_slot) {
+                       code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
+                       g_hash_table_insert (domain_jit_info (domain)->method_code_hash, patch_info->data.method, code_slot);
+               }
+               mono_domain_unlock (domain);
+               target = code_slot;
+               break;
+       }
        case MONO_PATCH_INFO_SWITCH: {
                gpointer *jump_table;
                int i;
@@ -3602,9 +3624,16 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = (gpointer) (size_t) mono_jit_tls_id;
                break;
        }
-       case MONO_PATCH_INFO_TLS_OFFSET:
-               target = GINT_TO_POINTER (mini_get_tls_offset (GPOINTER_TO_INT (patch_info->data.target)));
+       case MONO_PATCH_INFO_TLS_OFFSET: {
+               int offset;
+
+               offset = mini_get_tls_offset (GPOINTER_TO_INT (patch_info->data.target));
+#ifdef MONO_ARCH_HAVE_TRANSLATE_TLS_OFFSET
+               offset = mono_arch_translate_tls_offset (offset);
+#endif
+               target = GINT_TO_POINTER (offset);
                break;
+       }
        case MONO_PATCH_INFO_OBJC_SELECTOR_REF: {
                target = NULL;
                break;
@@ -3707,6 +3736,13 @@ mono_compile_create_vars (MonoCompile *cfg)
                g_print ("locals done\n");
 
        mono_arch_create_vars (cfg);
+
+       if (cfg->method->save_lmf && cfg->create_lmf_var) {
+               MonoInst *lmf_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
+               lmf_var->flags |= MONO_INST_VOLATILE;
+               lmf_var->flags |= MONO_INST_LMF;
+               cfg->lmf_var = lmf_var;
+       }
 }
 
 void
@@ -4541,7 +4577,6 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
         * 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->encoded_unwind_ops) {
                jinfo->used_regs = mono_cache_unwind_info (cfg->encoded_unwind_ops, cfg->encoded_unwind_ops_len);
                g_free (cfg->encoded_unwind_ops);
@@ -4552,7 +4587,6 @@ create_jit_info (MonoCompile *cfg, MonoMethod *method_to_compile)
                jinfo->used_regs = mono_cache_unwind_info (unwind_info, info_len);
                g_free (unwind_info);
        }
-#endif
 
        return jinfo;
 }
@@ -4958,7 +4992,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #endif
 
        /* The debugger has no liveness information, so avoid sharing registers/stack slots */
-       if (mono_debug_using_mono_debugger () || debug_options.mdb_optimizations) {
+       if (debug_options.mdb_optimizations) {
                cfg->disable_reuse_registers = TRUE;
                cfg->disable_reuse_stack_slots = TRUE;
                /* 
@@ -5211,6 +5245,8 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        mono_handle_global_vregs (cfg);
        if (cfg->opt & MONO_OPT_DEADCE)
                mono_local_deadce (cfg);
+       if (cfg->opt & MONO_OPT_ALIAS_ANALYSIS)
+               mono_local_alias_analysis (cfg);
        /* Disable this for LLVM to make the IR easier to handle */
        if (!COMPILE_LLVM (cfg))
                mono_if_conversion (cfg);
@@ -5365,6 +5401,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 #endif
 
        if (cfg->comp_done & MONO_COMP_SSA && COMPILE_LLVM (cfg)) {
+               mono_ssa_loop_invariant_code_motion (cfg);
                /* This removes MONO_INST_FAULT flags too so perform it unconditionally */
                if (cfg->opt & MONO_OPT_ABCREM)
                        mono_perform_abc_removal (cfg);
@@ -5381,7 +5418,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        if (COMPILE_SOFT_FLOAT (cfg))
                mono_decompose_soft_float (cfg);
 #endif
-       if (!COMPILE_LLVM (cfg))
+       if (COMPILE_LLVM (cfg))
+               mono_decompose_vtype_opts_llvm (cfg);
+       else
                mono_decompose_vtype_opts (cfg);
        if (cfg->flags & MONO_CFG_HAS_ARRAY_ACCESS)
                mono_decompose_array_access_opts (cfg);
@@ -5782,9 +5821,6 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                if (jinfo)
                        mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
                return code;
-
-               //if (mono_debug_format != MONO_DEBUG_FORMAT_NONE) 
-               //mono_debug_add_wrapper (method, nm);
        } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) {
                const char *name = method->name;
                char *full_name, *msg;
@@ -6169,7 +6205,6 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                if (!callinfo->wrapper) {
                        callinfo->wrapper = p;
                        mono_register_jit_icall_wrapper (callinfo, p);
-                       mono_debug_add_icall_wrapper (method, callinfo);
                }
                mono_jit_unlock ();
                mono_loader_unlock ();
@@ -6446,6 +6481,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                 */
 #ifdef MONO_ARCH_DYN_CALL_SUPPORTED
                if (mono_aot_only || debug_options.dyn_runtime_invoke) {
+                       MonoType *ret_type;
                        MonoMethodSignature *sig = mono_method_signature (method);
                        gboolean supported = TRUE;
                        int i;
@@ -6466,8 +6502,9 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                        if (supported)
                                info->dyn_call_info = mono_arch_dyn_call_prepare (sig);
 
+                       ret_type = mini_replace_type (sig->ret);
                        if (info->dyn_call_info) {
-                               switch (sig->ret->type) {
+                               switch (ret_type->type) {
                                case MONO_TYPE_VOID:
                                        break;
                                case MONO_TYPE_I1:
@@ -6484,7 +6521,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                case MONO_TYPE_CHAR:
                                case MONO_TYPE_R4:
                                case MONO_TYPE_R8:
-                                       info->ret_box_class = mono_class_from_mono_type (sig->ret);
+                                       info->ret_box_class = mono_class_from_mono_type (ret_type);
                                        break;
                                case MONO_TYPE_PTR:
                                        info->ret_box_class = mono_defaults.int_class;
@@ -6496,11 +6533,11 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                                case MONO_TYPE_OBJECT:
                                        break;
                                case MONO_TYPE_GENERICINST:
-                                       if (!MONO_TYPE_IS_REFERENCE (sig->ret))
-                                               info->ret_box_class = mono_class_from_mono_type (sig->ret);
+                                       if (!MONO_TYPE_IS_REFERENCE (ret_type))
+                                               info->ret_box_class = mono_class_from_mono_type (ret_type);
                                        break;
                                case MONO_TYPE_VALUETYPE:
-                                       info->ret_box_class = mono_class_from_mono_type (sig->ret);
+                                       info->ret_box_class = mono_class_from_mono_type (ret_type);
                                        break;
                                default:
                                        g_assert_not_reached ();
@@ -6562,7 +6599,7 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                if (sig->hasthis)
                        args [pindex ++] = &obj;
                for (i = 0; i < sig->param_count; ++i) {
-                       MonoType *t = sig->params [i];
+                       MonoType *t = mini_replace_type (sig->params [i]);
 
                        if (t->byref) {
                                args [pindex ++] = &params [i];
@@ -6922,6 +6959,10 @@ register_jit_stats (void)
        mono_counters_register ("Method cache lookups", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.methods_lookups);
        mono_counters_register ("Compiled CIL code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.cil_code_size);
        mono_counters_register ("Native code size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.native_code_size);
+       mono_counters_register ("Aliases found", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_found);
+       mono_counters_register ("Aliases eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.alias_removed);
+       mono_counters_register ("Aliased loads eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.loads_eliminated);
+       mono_counters_register ("Aliased stores eliminated", MONO_COUNTER_JIT | MONO_COUNTER_INT, &mono_jit_stats.stores_eliminated);
 }
 
 static void runtime_invoke_info_free (gpointer value);
@@ -7048,11 +7089,6 @@ mini_init (const char *filename, const char *runtime_version)
 
        InitializeCriticalSection (&jit_mutex);
 
-#ifdef MONO_DEBUGGER_SUPPORTED
-       if (mini_debug_running_inside_mdb ())
-               mini_debugger_init ();
-#endif
-
 #ifdef MONO_HAVE_FAST_TLS
        MONO_FAST_TLS_INIT (mono_jit_tls);
        MONO_FAST_TLS_INIT (mono_lmf_addr);
@@ -7308,7 +7344,7 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
 
 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_SOFT_FLOAT_FALLBACK)
-       if (EMUL_MUL_DIV || mono_arch_is_soft_float ()) {
+       if (ARCH_EMULATE_MUL_DIV || mono_arch_is_soft_float ()) {
                register_opcode_emulation (OP_FDIV, "__emul_fdiv", "double double double", mono_fdiv, "mono_fdiv", FALSE);
        }
 #endif
@@ -7390,6 +7426,8 @@ mini_init (const char *filename, const char *runtime_version)
 
 #if SIZEOF_REGISTER == 4
        register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "uint32 double", mono_fconv_u4, "mono_fconv_u4", TRUE);
+#else
+       register_opcode_emulation (OP_FCONV_TO_U, "__emul_fconv_to_u", "ulong double", mono_fconv_u8, "mono_fconv_u8", TRUE);
 #endif
 
        /* other jit icalls */
@@ -7572,8 +7610,6 @@ mini_cleanup (MonoDomain *domain)
        mono_domain_free (domain, TRUE);
 #endif
 
-       mono_debugger_cleanup ();
-
 #ifdef ENABLE_LLVM
        if (mono_use_llvm)
                mono_llvm_cleanup ();
@@ -7890,3 +7926,14 @@ mono_jumptable_get_entry (guint8 *code_ptr)
        return mono_arch_jumptable_entry_from_code (code_ptr);
 }
 #endif
+
+/*
+ * mini_replace_type:
+ *
+ * Replace the type used in the metadata stream with what the JIT will actually use during compilation.
+*/
+MonoType*
+mini_replace_type (MonoType *type)
+{
+       return mono_type_get_underlying_type (type);
+}