-
-/*
- * mini-runtime.c: Runtime code for the JIT
+/**
+ * \file
+ * Runtime code for the JIT
*
* Authors:
* Paolo Molaro (lupus@ximian.com)
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/checked-build.h>
+#include <mono/utils/mono-proclib.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"
#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 "interp/interp.h"
+#endif
+
static guint32 default_opt = 0;
static gboolean default_opt_set = FALSE;
*/
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;
#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)
{
/**
* mono_pmip:
- * @ip: an instruction pointer address
+ * \param ip an instruction pointer address
*
* This method is used from a debugger to get the name of the
- * method at address @ip. This routine is typically invoked from
+ * method at address \p ip. This routine is typically invoked from
* a debugger like this:
*
* (gdb) print mono_pmip ($pc)
*
- * Returns: the name of the method at address @ip.
+ * \returns the name of the method at address \p ip.
*/
G_GNUC_UNUSED char *
mono_pmip (void *ip)
}
/**
- * mono_print_method_from_ip
- * @ip: an instruction pointer address
+ * mono_print_method_from_ip:
+ * \param ip an instruction pointer address
*
* This method is used from a debugger to get the name of the
- * method at address @ip.
+ * method at address \p ip.
*
- * This prints the name of the method at address @ip in the standard
- * output. Unlike mono_pmip which returns a string, this routine
+ * This prints the name of the method at address \p ip in the standard
+ * output. Unlike \c 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_ATTR_USED void
mono_print_method_from_ip (void *ip)
{
MonoJitInfo *ji;
}
}
+/* 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()
// FIXME: ji
mono_free_unwind_info (info->unwind_ops);
+ if (info->owns_uw_info)
+ g_free (info->uw_info);
g_free (info);
}
* INFO can be NULL.
* Frees INFO.
*/
-void
-mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
+static void
+mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboolean aot)
{
MonoTrampInfo *copy;
if (!domain)
domain = mono_get_root_domain ();
- copy = g_new0 (MonoTrampInfo, 1);
+ if (domain)
+ copy = mono_domain_alloc0 (domain, sizeof (MonoTrampInfo));
+ else
+ copy = g_new0 (MonoTrampInfo, 1);
+
copy->code = info->code;
copy->code_size = info->code_size;
copy->name = g_strdup (info->name);
if (info->unwind_ops) {
copy->uw_info = mono_unwind_ops_encode (info->unwind_ops, ©->uw_info_len);
+ copy->owns_uw_info = TRUE;
+ if (domain) {
+ /* Move unwind info into the domain's memory pool so that it is removed once the domain is released. */
+ guint8 *temp = copy->uw_info;
+ copy->uw_info = mono_domain_alloc (domain, copy->uw_info_len);
+ memcpy (copy->uw_info, temp, copy->uw_info_len);
+ g_free (temp);
+ }
} else {
/* Trampolines from aot have the unwind ops already encoded */
copy->uw_info = info->uw_info;
copy->uw_info_len = info->uw_info_len;
}
- mono_jit_lock ();
- tramp_infos = g_slist_prepend (tramp_infos, copy);
- mono_jit_unlock ();
-
mono_save_trampoline_xdebug_info (info);
+ mono_lldb_save_trampoline_info (info);
+
+#ifdef MONO_ARCH_HAVE_UNWIND_TABLE
+ if (!aot)
+ 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)
+ if (!domain) {
+ /* If no root domain has been created yet, postpone the registration. */
+ mono_jit_lock ();
+ tramp_infos = g_slist_prepend (tramp_infos, copy);
+ mono_jit_unlock ();
+ } else if (copy->uw_info) {
+ /* Only register trampolines that have unwind infos */
register_trampoline_jit_info (domain, copy);
+ }
if (mono_jit_map_is_enabled ())
mono_emit_jit_tramp (info->code, info->code_size, info->name);
mono_tramp_info_free (info);
}
+void
+mono_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
+{
+ mono_tramp_info_register_internal (info, domain, FALSE);
+}
+
+void
+mono_aot_tramp_info_register (MonoTrampInfo *info, MonoDomain *domain)
+{
+ mono_tramp_info_register_internal (info, domain, TRUE);
+}
+
static void
mono_tramp_info_cleanup (void)
{
{
static int count = 0;
static gboolean inited;
- static const char *value;
+ static char *value;
count ++;
if (!value)
return TRUE;
- if (count == atoi (value))
+ int int_val = atoi (value);
+ g_free (value);
+
+ if (count == int_val)
break_count ();
- if (count > atoi (value))
+ if (count > int_val)
return FALSE;
return TRUE;
MonoLMF *
mono_get_lmf (void)
{
-#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) && defined(HAVE_GET_TLS_ADDR)
- return (MonoLMF *)mono_tls_get_lmf ();
-#else
MonoJitTlsData *jit_tls;
if ((jit_tls = mono_tls_get_jit_tls ()))
* (the thread object allocation can trigger a collection).
*/
return NULL;
-#endif
}
MonoLMF **
void
mono_set_lmf (MonoLMF *lmf)
{
-#if defined(MONO_ARCH_ENABLE_MONO_LMF_VAR) && defined(HAVE_GET_TLS_ADDR)
- mono_tls_set_lmf (lmf);
-#else
(*mono_get_lmf_addr ()) = lmf;
-#endif
}
MonoJitTlsData*
mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr);
}
+/*
+ * mono_push_lmf:
+ *
+ * Push an MonoLMFExt frame on the LMF stack.
+ */
+void
+mono_push_lmf (MonoLMFExt *ext)
+{
+#ifdef MONO_ARCH_HAVE_INIT_LMF_EXT
+ MonoLMF **lmf_addr;
+
+ lmf_addr = mono_get_lmf_addr ();
+
+ mono_arch_init_lmf_ext (ext, *lmf_addr);
+
+ mono_set_lmf ((MonoLMF*)ext);
+#else
+ NOT_IMPLEMENTED;
+#endif
+}
+
+/*
+ * mono_push_lmf:
+ *
+ * Pop the last frame from the LMF stack.
+ */
+void
+mono_pop_lmf (MonoLMF *lmf)
+{
+ mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3));
+}
+
/*
* mono_jit_thread_attach:
*
/**
* mono_thread_abort:
- * @obj: exception object
- *
- * abort the thread, print exception information and stack trace
+ * \param obj exception object
+ * Abort the thread, print exception information and stack trace
*/
static void
mono_thread_abort (MonoObject *obj)
{
- /* MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); */
+ /* MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); */
/* handle_remove should be eventually called for this thread, too
g_free (jit_tls);*/
jit_tls->first_lmf = lmf;
- /*
- * 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));
-#else
mono_set_lmf_addr (&jit_tls->lmf);
jit_tls->lmf = lmf;
-#endif
#ifdef MONO_ARCH_HAVE_TLS_INIT
mono_arch_tls_init ();
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:
g_assert_not_reached ();
}
+/*
+Overall algorithm:
+
+When a JIT request is made, we check if there's an outstanding one for that method and, if it exits, put the thread to sleep.
+ If the current thread is already JITing another method, don't wait as it might cause a deadlock.
+ Dependency management in this case is too complex to justify implementing it.
+
+If there are no outstanding requests, the current thread is doing nothing and there are already mono_cpu_count threads JITing, go to sleep.
+
+TODO:
+ Get rid of cctor invocations from within the JIT, it increases JIT duration and complicates things A LOT.
+ Can we get rid of ref_count and use `done && threads_waiting == 0` as the equivalent of `ref_count == 0`?
+ Reduce amount of dynamically allocated - possible once the JIT is no longer reentrant
+ Maybe pool JitCompilationEntry, specially those with an inited cond var;
+*/
+typedef struct {
+ MonoMethod *method;
+ MonoDomain *domain;
+ int compilation_count; /* Number of threads compiling this method - This happens due to the JIT being reentrant */
+ int ref_count; /* Number of threads using this JitCompilationEntry, roughtly 1 + threads_waiting */
+ int threads_waiting; /* Number of threads waiting on this job */
+ gboolean has_cond; /* True if @cond was initialized */
+ gboolean done; /* True if the method finished JIT'ing */
+ MonoCoopCond cond; /* Cond sleeping threads wait one */
+} JitCompilationEntry;
+
+typedef struct {
+ GPtrArray *in_flight_methods; //JitCompilationEntry*
+ MonoCoopMutex lock;
+} JitCompilationData;
+
+static JitCompilationData compilation_data;
+static int jit_methods_waited, jit_methods_multiple, jit_methods_overload, jit_spurious_wakeups;
+
+static void
+mini_jit_init_job_control (void)
+{
+ mono_coop_mutex_init (&compilation_data.lock);
+ compilation_data.in_flight_methods = g_ptr_array_new ();
+}
+
+static void
+lock_compilation_data (void)
+{
+ mono_coop_mutex_lock (&compilation_data.lock);
+}
+
+static void
+unlock_compilation_data (void)
+{
+ mono_coop_mutex_unlock (&compilation_data.lock);
+}
+
+static JitCompilationEntry*
+find_method (MonoMethod *method, MonoDomain *domain)
+{
+ int i;
+ for (i = 0; i < compilation_data.in_flight_methods->len; ++i){
+ JitCompilationEntry *e = compilation_data.in_flight_methods->pdata [i];
+ if (e->method == method && e->domain == domain)
+ return e;
+ }
+
+ return NULL;
+}
+
+static void
+add_current_thread (MonoJitTlsData *jit_tls)
+{
+ ++jit_tls->active_jit_methods;
+}
+
+static void
+unref_jit_entry (JitCompilationEntry *entry)
+{
+ --entry->ref_count;
+ if (entry->ref_count)
+ return;
+ if (entry->has_cond)
+ mono_coop_cond_destroy (&entry->cond);
+ g_free (entry);
+}
+
+/*
+ * Returns true if this method waited successfully for another thread to JIT it
+ */
+static gboolean
+wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
+{
+ MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
+ JitCompilationEntry *entry;
+
+ static gboolean inited;
+ if (!inited) {
+ mono_counters_register ("JIT compile waited others", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_waited);
+ mono_counters_register ("JIT compile 1+ jobs", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_multiple);
+ mono_counters_register ("JIT compile overload wait", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_methods_overload);
+ mono_counters_register ("JIT compile spurious wakeups", MONO_COUNTER_INT|MONO_COUNTER_JIT, &jit_spurious_wakeups);
+ inited = TRUE;
+ }
+
+ lock_compilation_data ();
+
+ if (!(entry = find_method (method, domain))) {
+ entry = g_new0 (JitCompilationEntry, 1);
+ entry->method = method;
+ entry->domain = domain;
+ entry->compilation_count = entry->ref_count = 1;
+ g_ptr_array_add (compilation_data.in_flight_methods, entry);
+ g_assert (find_method (method, domain) == entry);
+ add_current_thread (jit_tls);
+
+ unlock_compilation_data ();
+ return FALSE;
+ } else if (jit_tls->active_jit_methods > 0) {
+ //We can't suspend the current thread if it's already JITing a method.
+ //Dependency management is too compilated and we want to get rid of this anyways.
+ ++entry->compilation_count;
+ ++jit_methods_multiple;
+ ++jit_tls->active_jit_methods;
+
+ unlock_compilation_data ();
+ return FALSE;
+ } else {
+ ++jit_methods_waited;
+ ++entry->ref_count;
+
+ if (!entry->has_cond) {
+ mono_coop_cond_init (&entry->cond);
+ entry->has_cond = TRUE;
+ }
+
+ while (TRUE) {
+ ++entry->threads_waiting;
+
+ g_assert (entry->has_cond);
+ mono_coop_cond_wait (&entry->cond, &compilation_data.lock);
+ --entry->threads_waiting;
+
+ if (entry->done) {
+ unref_jit_entry (entry);
+ unlock_compilation_data ();
+ return TRUE;
+ } else {
+ ++jit_spurious_wakeups;
+ }
+ }
+ }
+}
+
+static void
+unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
+{
+ MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls ();
+
+ lock_compilation_data ();
+
+ g_assert (jit_tls->active_jit_methods > 0);
+ --jit_tls->active_jit_methods;
+
+ JitCompilationEntry *entry = find_method (method, target_domain);
+ g_assert (entry); // It would be weird to fail
+ entry->done = TRUE;
+
+ if (entry->threads_waiting) {
+ g_assert (entry->has_cond);
+ mono_coop_cond_broadcast (&entry->cond);
+ }
+
+ if (--entry->compilation_count == 0) {
+ g_ptr_array_remove (compilation_data.in_flight_methods, entry);
+ unref_jit_entry (entry);
+ }
+
+ unlock_compilation_data ();
+}
+
+
static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, gboolean jit_only, MonoError *error)
{
MonoDomain *target_domain, *domain = mono_domain_get ();
MonoJitInfo *info;
MonoJitICallInfo *callinfo = NULL;
WrapperInfo *winfo = NULL;
- mono_error_init (error);
+ error_init (error);
+
+#ifdef ENABLE_INTERPRETER
+ if (mono_use_interpreter && !jit_only) {
+ code = mono_interp_create_method_pointer (method, error);
+ if (code)
+ return code;
+ }
+#endif
if (mono_llvm_only)
/* Should be handled by the caller */
}
}
+lookup_start:
info = lookup_method (target_domain, method);
if (info) {
/* We can't use a domain specific method in another domain */
}
}
- if (!code)
+ if (!code) {
+ if (wait_or_register_method_to_compile (method, target_domain))
+ goto lookup_start;
code = mono_jit_compile_method_inner (method, target_domain, opt, error);
+ unregister_method_for_compile (method, target_domain);
+ }
if (!mono_error_ok (error))
return NULL;
{
gpointer code;
- code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error);
+ code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), FALSE, error);
+ return code;
+}
+
+/*
+ * mono_jit_compile_method_jit_only:
+ *
+ * Compile METHOD using the JIT/AOT, even in interpreted mode.
+ */
+gpointer
+mono_jit_compile_method_jit_only (MonoMethod *method, MonoError *error)
+{
+ gpointer code;
+
+ code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), TRUE, error);
return code;
}
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);
gpointer *param_refs;
int i, pindex;
- mono_error_init (error);
+ error_init (error);
g_assert (info->gsharedvt_invoke);
/**
* mono_jit_runtime_invoke:
- * @method: the method to invoke
- * @obj: this pointer
- * @params: array of parameter values.
- * @exc: Set to the exception raised in the managed method. If NULL, error is thrown instead.
- * If coop is enabled, this argument is ignored - all exceptoins are caught and propagated
- * through @error
- * @error: error or caught exception object
+ * \param method: the method to invoke
+ * \param obj: this pointer
+ * \param params: array of parameter values.
+ * \param exc: Set to the exception raised in the managed method.
+ * \param error: error or caught exception object
+ * If \p exc is NULL, \p error is thrown instead.
+ * If coop is enabled, \p exc argument is ignored -
+ * all exceptions are caught and propagated through \p error
*/
static MonoObject*
mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc, MonoError *error)
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");
}
if (callee) {
- compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error);
+ compiled_method = mono_jit_compile_method (callee, error);
if (!compiled_method) {
g_assert (!mono_error_ok (error));
return NULL;
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,
{
if (mono_llvm_only)
del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
+#ifdef ENABLE_INTERPRETER
+ if (mono_use_interpreter)
+ mono_interp_init_delegate (del);
+#endif
}
char*
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"))
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"))
static void
mini_parse_debug_options (void)
{
- const char *options = g_getenv ("MONO_DEBUG");
+ char *options = g_getenv ("MONO_DEBUG");
gchar **args, **ptr;
if (!options)
return;
args = g_strsplit (options, ",", -1);
+ g_free (options);
for (ptr = args; ptr && *ptr; ptr++) {
const char *arg = *ptr;
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);
}
}
info->seq_points = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, mono_seq_point_info_free);
info->arch_seq_points = g_hash_table_new (mono_aligned_addr_hash, NULL);
info->jump_target_hash = g_hash_table_new (NULL, NULL);
+ mono_jit_code_hash_init (&info->interp_code_hash);
domain->runtime_info = info;
}
g_hash_table_foreach (info->llvm_jit_callees, free_jit_callee_list, NULL);
g_hash_table_destroy (info->llvm_jit_callees);
}
+ mono_internal_hash_table_destroy (&info->interp_code_hash);
#ifdef ENABLE_LLVM
mono_llvm_free_domain_info (domain);
#endif
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)
#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)
{
MonoDomain *domain;
MonoRuntimeCallbacks callbacks;
MonoThreadInfoRuntimeCallbacks ticallbacks;
+ MonoCodeManagerCallbacks code_manager_callbacks;
MONO_VES_INIT_BEGIN ();
}
#endif
+#ifdef ENABLE_INTERPRETER
+ mono_interp_init ();
+#endif
+
mono_os_mutex_init_recursive (&jit_mutex);
mono_cross_helpers_run ();
mini_jit_init ();
+ mini_jit_init_job_control ();
+
/* Happens when using the embedding interface */
if (!default_opt_set)
default_opt = mono_parse_default_optimizations (NULL);
mono_threads_runtime_init (&ticallbacks);
- if (g_getenv ("MONO_DEBUG") != NULL)
+ if (g_hasenv ("MONO_DEBUG")) {
mini_parse_debug_options ();
+ }
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 ();
mono_unwind_init ();
+ if (mini_get_debug_options ()->lldb || g_hasenv ("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");
- mono_xdebug_init (xdebug_opts);
+ char *mono_xdebug = g_getenv ("MONO_XDEBUG");
+ if (mono_xdebug) {
+ mono_xdebug_init (mono_xdebug);
+ g_free (mono_xdebug);
/* So methods for multiple domains don't have the same address */
mono_dont_free_domains = TRUE;
mono_using_xdebug = TRUE;
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);
register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
#ifndef MONO_ARCH_NO_EMULATE_LONG_MUL_OPTS
- register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", TRUE);
+ register_opcode_emulation (OP_LMUL, "__emul_lmul", "long long long", mono_llmult, "mono_llmult", FALSE);
register_opcode_emulation (OP_LDIV, "__emul_ldiv", "long long long", mono_lldiv, "mono_lldiv", FALSE);
register_opcode_emulation (OP_LDIV_UN, "__emul_ldiv_un", "long long long", mono_lldiv_un, "mono_lldiv_un", FALSE);
register_opcode_emulation (OP_LREM, "__emul_lrem", "long long long", mono_llrem, "mono_llrem", FALSE);
register_icall (mono_gsharedvt_constrained_call, "mono_gsharedvt_constrained_call", "object ptr ptr ptr ptr ptr", FALSE);
register_icall (mono_gsharedvt_value_copy, "mono_gsharedvt_value_copy", "void ptr ptr ptr", TRUE);
- register_icall (mono_gc_wbarrier_value_copy_bitmap, "mono_gc_wbarrier_value_copy_bitmap", "void ptr ptr int int", FALSE);
+ register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int");
register_icall (mono_object_castclass_with_cache, "mono_object_castclass_with_cache", "object object ptr ptr", FALSE);
register_icall (mono_object_isinst_with_cache, "mono_object_isinst_with_cache", "object object ptr ptr", FALSE);
register_icall_no_wrapper (mono_tls_get_thread, "mono_tls_get_thread", "ptr");
register_icall_no_wrapper (mono_tls_get_jit_tls, "mono_tls_get_jit_tls", "ptr");
register_icall_no_wrapper (mono_tls_get_domain, "mono_tls_get_domain", "ptr");
- register_icall_no_wrapper (mono_tls_get_lmf, "mono_tls_get_lmf", "ptr");
register_icall_no_wrapper (mono_tls_get_sgen_thread_info, "mono_tls_get_sgen_thread_info", "ptr");
register_icall_no_wrapper (mono_tls_get_lmf_addr, "mono_tls_get_lmf_addr", "ptr");
register_icall_no_wrapper (mono_tls_set_thread, "mono_tls_set_thread", "void ptr");
register_icall_no_wrapper (mono_tls_set_jit_tls, "mono_tls_set_jit_tls", "void ptr");
register_icall_no_wrapper (mono_tls_set_domain, "mono_tls_set_domain", "void ptr");
- register_icall_no_wrapper (mono_tls_set_lmf, "mono_tls_set_lmf", "void ptr");
register_icall_no_wrapper (mono_tls_set_sgen_thread_info, "mono_tls_set_sgen_thread_info", "void ptr");
register_icall_no_wrapper (mono_tls_set_lmf_addr, "mono_tls_set_lmf_addr", "void ptr");
}
mono_runtime_cleanup (domain);
#endif
+ mono_threadpool_cleanup ();
+
mono_profiler_shutdown ();
free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
/**
* mono_get_runtime_build_info:
- *
- * Return the runtime version + build date in string format.
* The returned string is owned by the caller. The returned string
- * format is "VERSION (FULL_VERSION BUILD_DATE)" and build date is optional.
+ * format is <code>VERSION (FULL_VERSION BUILD_DATE)</code> and build date is optional.
+ * \returns the runtime version + build date in string format.
*/
char*
mono_get_runtime_build_info (void)