Improve unwind support on Windows x64.
[mono.git] / mono / mini / mini-runtime.c
index 0c67814f126135e9e89b8a59f6204a26b1539e8e..22d9a5cd227a889fe2192431f7357b12f972e822 100644 (file)
@@ -66,7 +66,7 @@
 #include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/checked-build.h>
 #include <mono/metadata/w32handle.h>
-#include <mono/io-layer/io-layer.h>
+#include <mono/metadata/threadpool.h>
 
 #include "mini.h"
 #include "seq-points.h"
@@ -81,6 +81,7 @@
 #include "mini-gc.h"
 #include "mini-llvm.h"
 #include "debugger-agent.h"
+#include "lldb.h"
 
 #ifdef MONO_ARCH_LLVM_SUPPORTED
 #ifdef ENABLE_LLVM
 #endif
 #endif
 
+#ifdef ENABLE_INTERPRETER
+#include "interpreter/interp.h"
+#endif
+
 static guint32 default_opt = 0;
 static gboolean default_opt_set = FALSE;
 
@@ -110,6 +115,8 @@ int mini_verbose = 0;
  */
 gboolean mono_use_llvm = FALSE;
 
+gboolean mono_use_interpreter = FALSE;
+
 #define mono_jit_lock() mono_os_mutex_lock (&jit_mutex)
 #define mono_jit_unlock() mono_os_mutex_unlock (&jit_mutex)
 static mono_mutex_t jit_mutex;
@@ -121,11 +128,18 @@ MonoDebugOptions debug_options;
 #ifdef VALGRIND_JIT_REGISTER_MAP
 int valgrind_register;
 #endif
+GList* mono_aot_paths;
+
+static gboolean mini_enable_profiler = FALSE;
+static char* mini_profiler_options = NULL;
 
 static GSList *tramp_infos;
 
 static void register_icalls (void);
 
+static gboolean mini_profiler_enabled (void) { return mini_enable_profiler; }
+static const char* mini_profiler_get_options (void) {  return mini_profiler_options;  }
+
 gboolean
 mono_running_on_valgrind (void)
 {
@@ -233,7 +247,7 @@ mono_pmip (void *ip)
  */
 #ifdef __GNUC__
 /* Prevent the linker from optimizing this away in embedding setups to help debugging */
- __attribute__((used))
+ __attribute__ ((__used__))
 #endif
 void
 mono_print_method_from_ip (void *ip)
@@ -352,6 +366,15 @@ void *mono_global_codeman_reserve (int size)
        }
 }
 
+/* The callback shouldn't take any locks */
+void
+mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data)
+{
+       mono_jit_lock ();
+       mono_code_manager_foreach (global_codeman, func, user_data);
+       mono_jit_unlock ();
+}
+
 #if defined(__native_client_codegen__) && defined(__native_client__)
 void
 mono_nacl_gc()
@@ -480,6 +503,11 @@ mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
        mono_jit_unlock ();
 
        mono_save_trampoline_xdebug_info (info);
+       mono_lldb_save_trampoline_info (info);
+
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+       mono_arch_unwindinfo_install_tramp_unwind_info (info->unwind_ops, info->code, info->code_size);
+#endif
 
        /* Only register trampolines that have unwind infos */
        if (mono_get_root_domain () && copy->uw_info)
@@ -691,7 +719,7 @@ register_dyn_icall (gpointer func, const char *name, const char *sigstr, gboolea
 MonoLMF *
 mono_get_lmf (void)
 {
-#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) && defined(HAVE_GET_TLS_ADDR)
        return (MonoLMF *)mono_tls_get_lmf ();
 #else
        MonoJitTlsData *jit_tls;
@@ -716,11 +744,11 @@ mono_get_lmf_addr (void)
 void
 mono_set_lmf (MonoLMF *lmf)
 {
-#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) && defined(HAVE_GET_TLS_ADDR)
        mono_tls_set_lmf (lmf);
-#endif
-
+#else
        (*mono_get_lmf_addr ()) = lmf;
+#endif
 }
 
 MonoJitTlsData*
@@ -852,7 +880,15 @@ setup_jit_tls_data (gpointer stack_start, gpointer abort_func)
 
        jit_tls->first_lmf = lmf;
 
-#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR)
+       /*
+        * We can have 2 configurations for accessing lmf.
+        * We can use only the tls_lmf_addr variable, which will store the address of
+        * jit_tls->lmf, or, if we have MONO_ARCH_ENABLE_MONO_LMF_VAR enabled, we can
+        * use both tls_lmf_addr and tls_lmf variables (in this case we need to have
+        * means of getting the address of a tls variable; this can be done always
+        * when using __thread or, on osx, even when using pthread)
+        */
+#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) && defined(HAVE_GET_TLS_ADDR)
        /* jit_tls->lmf is unused */
        mono_tls_set_lmf (lmf);
        mono_set_lmf_addr (mono_tls_get_tls_addr (TLS_KEY_LMF));
@@ -1257,7 +1293,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        unsigned char *ip = patch_info->ip.i + code;
        gconstpointer target = NULL;
 
-       mono_error_init (error);
+       error_init (error);
 
        switch (patch_info->type) {
        case MONO_PATCH_INFO_BB:
@@ -1738,7 +1774,12 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *er
        MonoJitICallInfo *callinfo = NULL;
        WrapperInfo *winfo = NULL;
 
-       mono_error_init (error);
+       error_init (error);
+
+#ifdef ENABLE_INTERPRETER
+       if (mono_use_interpreter)
+               return mono_interp_create_method_pointer (method, error);
+#endif
 
        if (mono_llvm_only)
                /* Should be handled by the caller */
@@ -1931,6 +1972,7 @@ mono_jit_free_method (MonoDomain *domain, MonoMethod *method)
                return;
 
        mono_debug_remove_method (method, domain);
+       mono_lldb_remove_method (domain, method, ji);
 
        mono_domain_lock (domain);
        g_hash_table_remove (domain_jit_info (domain)->dynamic_code_hash, method);
@@ -2240,7 +2282,7 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
        gpointer *param_refs;
        int i, pindex;
 
-       mono_error_init (error);
+       error_init (error);
 
        g_assert (info->gsharedvt_invoke);
 
@@ -2324,7 +2366,12 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        MonoJitInfo *ji = NULL;
        gboolean callee_gsharedvt = FALSE;
 
-       mono_error_init (error);
+#ifdef ENABLE_INTERPRETER
+       if (mono_use_interpreter)
+               return mono_interp_runtime_invoke (method, obj, params, exc, error);
+#endif
+
+       error_init (error);
 
        if (obj == NULL && !(method->flags & METHOD_ATTRIBUTE_STATIC) && !method->string_ctor && (method->wrapper_type == 0)) {
                g_warning ("Ignoring invocation of an instance method on a NULL instance.\n");
@@ -2688,6 +2735,8 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
 
        ji = mono_jit_info_table_find_internal (mono_domain_get (), (char *)mono_arch_ip_from_context (ctx), TRUE, TRUE);
 
+       MONO_ENTER_GC_UNSAFE_UNBALANCED;
+
 #if defined(MONO_ARCH_HAVE_IS_INT_OVERFLOW)
        if (mono_arch_is_int_overflow (ctx, info))
                /*
@@ -2703,16 +2752,19 @@ MONO_SIG_HANDLER_FUNC (, mono_sigfpe_signal_handler)
 
        if (!ji) {
                if (!mono_do_crash_chaining && mono_chain_signal (MONO_SIG_HANDLER_PARAMS))
-                       return;
+                       goto exit;
 
                mono_handle_native_crash ("SIGFPE", ctx, info);
                if (mono_do_crash_chaining) {
                        mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
-                       return;
+                       goto exit;
                }
        }
 
        mono_arch_handle_exception (ctx, exc);
+
+exit:
+       MONO_EXIT_GC_UNSAFE_UNBALANCED;
 }
 
 MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
@@ -2836,9 +2888,13 @@ MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
        MonoException *exc;
        MONO_SIG_HANDLER_GET_CONTEXT;
 
+       MONO_ENTER_GC_UNSAFE_UNBALANCED;
+
        exc = mono_get_exception_execution_engine ("Interrupted (SIGINT).");
 
        mono_arch_handle_exception (ctx, exc);
+
+       MONO_EXIT_GC_UNSAFE_UNBALANCED;
 }
 
 #ifndef DISABLE_REMOTING
@@ -2856,7 +2912,7 @@ mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, Mon
        MonoMethod *nm;
        guint8 *addr = NULL;
 
-       mono_error_init (error);
+       error_init (error);
 
        if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && mono_method_signature (method)->generic_param_count) {
                return mono_create_specific_trampoline (method, MONO_TRAMPOLINE_GENERIC_VIRTUAL_REMOTING,
@@ -3091,8 +3147,8 @@ mini_parse_debug_option (const char *option)
                debug_options.break_on_unverified = TRUE;
        else if (!strcmp (option, "no-gdb-backtrace"))
                debug_options.no_gdb_backtrace = TRUE;
-       else if (!strcmp (option, "suspend-on-sigsegv"))
-               debug_options.suspend_on_sigsegv = TRUE;
+       else if (!strcmp (option, "suspend-on-native-crash") || !strcmp (option, "suspend-on-sigsegv"))
+               debug_options.suspend_on_native_crash = TRUE;
        else if (!strcmp (option, "suspend-on-exception"))
                debug_options.suspend_on_exception = TRUE;
        else if (!strcmp (option, "suspend-on-unhandled"))
@@ -3103,6 +3159,8 @@ mini_parse_debug_option (const char *option)
                debug_options.dyn_runtime_invoke = TRUE;
        else if (!strcmp (option, "gdb"))
                debug_options.gdb = TRUE;
+       else if (!strcmp (option, "lldb"))
+               debug_options.lldb = TRUE;
        else if (!strcmp (option, "explicit-null-checks"))
                debug_options.explicit_null_checks = TRUE;
        else if (!strcmp (option, "gen-seq-points"))
@@ -3155,7 +3213,7 @@ mini_parse_debug_options (void)
 
                if (!mini_parse_debug_option (arg)) {
                        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', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
+                       fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'reverse-pinvoke-exceptions', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'suspend-on-native-crash', 'suspend-on-sigsegv', 'suspend-on-exception', 'suspend-on-unhandled', 'dont-free-domains', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks', 'gen-seq-points', 'no-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
                        exit (1);
                }
        }
@@ -3391,6 +3449,22 @@ mini_free_jit_domain_info (MonoDomain *domain)
        domain->runtime_info = NULL;
 }
 
+#ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
+
+static void
+code_manager_chunk_new (void *chunk, int size)
+{
+       mono_arch_code_chunk_new (chunk, size);
+}
+
+static void
+code_manager_chunk_destroy (void *chunk)
+{
+       mono_arch_code_chunk_destroy (chunk);
+}
+
+#endif
+
 #ifdef ENABLE_LLVM
 static gboolean
 llvm_init_inner (void)
@@ -3428,6 +3502,13 @@ mini_llvm_init (void)
 #endif
 }
 
+void
+mini_profiler_enable_with_options (const char* profile_options)
+{
+       mini_enable_profiler = TRUE;
+       mini_profiler_options = g_strdup (profile_options);
+}
+
 MonoDomain *
 mini_init (const char *filename, const char *runtime_version)
 {
@@ -3435,6 +3516,7 @@ mini_init (const char *filename, const char *runtime_version)
        MonoDomain *domain;
        MonoRuntimeCallbacks callbacks;
        MonoThreadInfoRuntimeCallbacks ticallbacks;
+       MonoCodeManagerCallbacks code_manager_callbacks;
 
        MONO_VES_INIT_BEGIN ();
 
@@ -3518,6 +3600,13 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_code_manager_init ();
 
+       memset (&code_manager_callbacks, 0, sizeof (code_manager_callbacks));
+#ifdef MONO_ARCH_HAVE_CODE_CHUNK_TRACKING
+       code_manager_callbacks.chunk_new = code_manager_chunk_new;
+       code_manager_callbacks.chunk_destroy = code_manager_chunk_destroy;
+#endif
+       mono_code_manager_install_callbacks (&code_manager_callbacks);
+
        mono_hwcap_init ();
 
        mono_arch_cpu_init ();
@@ -3526,6 +3615,11 @@ mini_init (const char *filename, const char *runtime_version)
 
        mono_unwind_init ();
 
+       if (mini_get_debug_options ()->lldb || g_getenv ("MONO_LLDB")) {
+               mono_lldb_init ("");
+               mono_dont_free_domains = TRUE;
+       }
+
 #ifdef XDEBUG_ENABLED
        if (g_getenv ("MONO_XDEBUG")) {
                const char *xdebug_opts = g_getenv ("MONO_XDEBUG");
@@ -3577,6 +3671,11 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
+       if (mini_profiler_enabled ()) {
+               mono_profiler_load (mini_profiler_get_options ());
+               mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main");
+       }
+
        if (debug_options.collect_pagefault_stats)
                mono_aot_set_make_unreadable (TRUE);
 
@@ -4016,6 +4115,8 @@ mini_cleanup (MonoDomain *domain)
        mono_runtime_cleanup (domain);
 #endif
 
+       mono_threadpool_cleanup ();
+
        mono_profiler_shutdown ();
 
        free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());