#include <mono/metadata/threads.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/debug-helpers.h>
-#include "mono/metadata/profiler.h"
#include <mono/metadata/profiler-private.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/environment.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/checked-build.h>
+#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-proclib.h>
#include <mono/metadata/w32handle.h>
#include <mono/metadata/threadpool.h>
#endif
GList* mono_aot_paths;
-static gboolean mini_enable_profiler = FALSE;
-static char* mini_profiler_options = NULL;
+static GPtrArray *profile_options;
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_jit_unlock ();
}
-#if defined(__native_client_codegen__) && defined(__native_client__)
-void
-mono_nacl_gc()
-{
-#ifdef __native_client_gc__
- __nacl_suspend_thread_if_needed();
-#endif
-}
-#endif /* __native_client__ */
-
/**
* mono_create_unwind_op:
*
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);
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);
G_GNUC_UNUSED gboolean
mono_debug_count (void)
{
- static int count = 0;
- static gboolean inited;
- static char *value;
+ static int count = 0, int_val = 0;
+ static gboolean inited, has_value = FALSE;
count ++;
if (!inited) {
- value = g_getenv ("COUNT");
+ char *value = g_getenv ("COUNT");
+ if (value) {
+ int_val = atoi (value);
+ g_free (value);
+ has_value = TRUE;
+ }
inited = TRUE;
}
- if (!value)
+ if (!has_value)
return TRUE;
- int int_val = atoi (value);
- g_free (value);
-
if (count == int_val)
break_count ();
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:
*
MonoDomain *orig;
gboolean attached;
- g_assert (!mono_threads_is_coop_enabled ());
+ g_assert (!mono_threads_is_blocking_transition_enabled ());
if (!domain) {
/* Happens when called from AOTed code which is only used in the root domain. */
void
mono_jit_set_domain (MonoDomain *domain)
{
- g_assert (!mono_threads_is_coop_enabled ());
+ g_assert (!mono_threads_is_blocking_transition_enabled ());
if (domain)
mono_domain_set (domain, TRUE);
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);*/
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
case MONO_PATCH_INFO_AOT_MODULE:
case MONO_PATCH_INFO_JIT_THREAD_ATTACH:
+ case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
return (ji->type << 8);
case MONO_PATCH_INFO_CASTCLASS_CACHE:
return (ji->type << 8) | (ji->data.index);
return (ji->type << 8) | (gssize)info->klass | (gssize)info->method;
}
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+ case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
return (ji->type << 8) | g_str_hash (ji->data.target);
case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
return (ji->type << 8) | mono_signature_hash (ji->data.sig);
case MONO_PATCH_INFO_VIRT_METHOD:
return ji1->data.virt_method->klass == ji2->data.virt_method->klass && ji1->data.virt_method->method == ji2->data.virt_method->method;
case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+ case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL:
if (ji1->data.target == ji2->data.target)
return 1;
return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
target = mono_icall_get_wrapper (mi);
break;
}
- case MONO_PATCH_INFO_JIT_ICALL_ADDR: {
+ case MONO_PATCH_INFO_JIT_ICALL_ADDR:
+ case MONO_PATCH_INFO_JIT_ICALL_ADDR_NOCALL: {
MonoJitICallInfo *mi = mono_find_jit_icall_by_name (patch_info->data.name);
if (!mi) {
g_warning ("unknown MONO_PATCH_INFO_JIT_ICALL_ADDR %s", patch_info->data.name);
break;
}
case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG:
-#if defined(__native_client_codegen__)
- target = (gpointer)&__nacl_thread_suspension_needed;
-#else
g_assert (mono_threads_is_coop_enabled ());
target = (gpointer)&mono_polling_required;
-#endif
break;
case MONO_PATCH_INFO_SWITCH: {
gpointer *jump_table;
int i;
-#if defined(__native_client__) && defined(__native_client_codegen__)
- /* This memory will leak, but we don't care if we're */
- /* not deleting JIT'd methods anyway */
- jump_table = g_malloc0 (sizeof(gpointer) * patch_info->data.table->table_size);
-#else
if (method && method->dynamic) {
jump_table = (void **)mono_code_manager_reserve (mono_dynamic_code_hash_lookup (domain, method)->code_mp, sizeof (gpointer) * patch_info->data.table->table_size);
} else {
jump_table = (void **)mono_domain_code_reserve (domain, sizeof (gpointer) * patch_info->data.table->table_size);
}
}
-#endif
for (i = 0; i < patch_info->data.table->table_size; i++) {
jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
target = mi->func;
break;
}
+ case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: {
+ target = (gpointer) &mono_profiler_state.gc_allocation_count;
+ break;
+ }
default:
g_assert_not_reached ();
}
return ji;
}
-MonoJitInfo *
-mono_get_jit_info_from_method (MonoDomain *domain, MonoMethod *method)
+MonoClass*
+mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
{
- return lookup_method (domain, method);
+ MonoError error;
+ MonoClass *klass;
+
+ if (method->wrapper_type != MONO_WRAPPER_NONE) {
+ klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
+ if (context) {
+ klass = mono_class_inflate_generic_class_checked (klass, context, &error);
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ }
+ } else {
+ klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
+ mono_error_cleanup (&error); /* FIXME don't swallow the error */
+ }
+ if (klass)
+ mono_class_init (klass);
+ return klass;
}
#if ENABLE_JIT_MAP
/*
Overall algorithm:
-Limit JITing to mono_cpu_count
- This ensures there's always room for application progress and not just JITing.
-
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 invocatio from within the JIT, it increases JIT duration and complicates things A LOT.
- Verify that we don't have too many spurious wakeups.
- Experiment with limiting to values around mono_cpu_count +/- 1 as this would enable progress during warmup.
+ 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 count;
+ 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*
- int active_threads;
- int threads_waiting;
MonoCoopMutex lock;
- MonoCoopCond cond;
} JitCompilationData;
static JitCompilationData compilation_data;
mini_jit_init_job_control (void)
{
mono_coop_mutex_init (&compilation_data.lock);
- mono_coop_cond_init (&compilation_data.cond);
compilation_data.in_flight_methods = g_ptr_array_new ();
}
lock_compilation_data (void)
{
mono_coop_mutex_lock (&compilation_data.lock);
- fflush (stdout);
}
static void
unlock_compilation_data (void)
{
- fflush (stdout);
mono_coop_mutex_unlock (&compilation_data.lock);
}
static void
add_current_thread (MonoJitTlsData *jit_tls)
{
- if (jit_tls->active_jit_methods == 0)
- ++compilation_data.active_threads;
++jit_tls->active_jit_methods;
}
-//Returns true if this thread should wait
-static gboolean
-should_wait_for_available_cpu_capacity (void)
+static void
+unref_jit_entry (JitCompilationEntry *entry)
{
- MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
-
- //We can't suspend threads that are already JIT'ing something or we risk deadlocking
- if (jit_tls->active_jit_methods > 0)
- return FALSE;
-
- //If there are as many active threads as cores, JITing more will cause thrashing
- if (compilation_data.active_threads >= mono_cpu_count ()) {
- ++jit_methods_overload;
- return TRUE;
- }
- return FALSE;
+ --entry->ref_count;
+ if (entry->ref_count)
+ return;
+ if (entry->has_cond)
+ mono_coop_cond_destroy (&entry->cond);
+ g_free (entry);
}
/*
static gboolean
wait_or_register_method_to_compile (MonoMethod *method, MonoDomain *domain)
{
- MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+ 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);
lock_compilation_data ();
- int waits = 0;
- while (should_wait_for_available_cpu_capacity ()) {
- fflush (stdout);
- ++compilation_data.threads_waiting;
- mono_coop_cond_wait (&compilation_data.cond, &compilation_data.lock);
- --compilation_data.threads_waiting;
- if (waits)
- ++jit_spurious_wakeups;
- ++waits;
- }
-
if (!(entry = find_method (method, domain))) {
- entry = g_new (JitCompilationEntry, 1);
+ entry = g_new0 (JitCompilationEntry, 1);
entry->method = method;
entry->domain = domain;
- entry->count = 1;
+ 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->count;
+ ++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) {
- fflush (stdout);
- ++compilation_data.threads_waiting;
- mono_coop_cond_wait (&compilation_data.cond, &compilation_data.lock);
- --compilation_data.threads_waiting;
+ ++entry->threads_waiting;
- if (!find_method (method, domain)) {
+ 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 {
static void
unregister_method_for_compile (MonoMethod *method, MonoDomain *target_domain)
{
- MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id);
+ 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;
- if (jit_tls->active_jit_methods == 0)
- --compilation_data.active_threads;
JitCompilationEntry *entry = find_method (method, target_domain);
g_assert (entry); // It would be weird to fail
- if (--entry->count == 0) {
+ 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);
- g_free (entry);
+ unref_jit_entry (entry);
}
- if (compilation_data.threads_waiting)
- mono_coop_cond_broadcast (&compilation_data.cond);
unlock_compilation_data ();
}
#ifdef MONO_USE_AOT_COMPILER
if (opt & MONO_OPT_AOT) {
- MonoDomain *domain = mono_domain_get ();
+ MonoDomain *domain = NULL;
+
+ if (mono_aot_mode == MONO_AOT_MODE_INTERP && method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
+ WrapperInfo *info = mono_marshal_get_wrapper_info (method);
+ g_assert (info);
+ if (info->subtype == WRAPPER_SUBTYPE_INTERP_IN)
+ /* AOT'd wrappers for interp must be owned by root domain */
+ domain = mono_get_root_domain ();
+ }
+
+ if (!domain)
+ domain = mono_domain_get ();
mono_class_init (method->klass);
if ((code = mono_aot_get_method_checked (domain, method, error))) {
MonoVTable *vtable;
- if (mono_runtime_is_critical_method (method) || mono_gc_is_critical_method (method)) {
+ if (mono_gc_is_critical_method (method)) {
/*
* The suspend code needs to be able to lookup these methods by ip in async context,
* so preload their jit info.
#endif
error_init (error);
+ if (exc)
+ *exc = NULL;
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");
static gpointer
mini_create_ftnptr (MonoDomain *domain, gpointer addr)
{
-#if !defined(__ia64__) && (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
+#if (!defined(__ppc64__) && !defined(__powerpc64__) || _CALL_ELF == 2)
return addr;
#else
gpointer* desc = NULL;
if ((desc = g_hash_table_lookup (domain->ftnptrs_hash, addr)))
return desc;
-# ifdef __ia64__
- desc = mono_domain_code_reserve (domain, 2 * sizeof (gpointer));
-
- desc [0] = addr;
- desc [1] = NULL;
-# elif defined(__ppc64__) || defined(__powerpc64__)
+# if defined(__ppc64__) || defined(__powerpc64__)
desc = mono_domain_alloc0 (domain, 3 * sizeof (gpointer));
static gpointer
mini_get_addr_from_ftnptr (gpointer descr)
{
-#if defined(__ia64__) || ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
+#if ((defined(__ppc64__) || defined(__powerpc64__)) && _CALL_ELF != 2)
return *(gpointer*)descr;
#else
return descr;
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
}
void
-mini_profiler_enable_with_options (const char* profile_options)
+mini_add_profiler_argument (const char *desc)
{
- mini_enable_profiler = TRUE;
- mini_profiler_options = g_strdup (profile_options);
+ if (!profile_options)
+ profile_options = g_ptr_array_new ();
+
+ g_ptr_array_add (profile_options, (gpointer) desc);
}
MonoDomain *
CHECKED_MONO_INIT ();
-#if defined(__linux__) && !defined(__native_client__)
+#if defined(__linux__)
if (access ("/proc/self/maps", F_OK) != 0) {
g_print ("Mono requires /proc to be mounted.\n");
exit (1);
}
#endif
+#ifdef ENABLE_INTERPRETER
+ mono_interp_init ();
+#endif
+
mono_os_mutex_init_recursive (&jit_mutex);
mono_cross_helpers_run ();
mono_w32handle_init ();
#endif
- mono_threads_runtime_init (&ticallbacks);
+ mono_thread_info_runtime_init (&ticallbacks);
if (g_hasenv ("MONO_DEBUG")) {
mini_parse_debug_options ();
mono_set_generic_sharing_supported (TRUE);
#endif
- mono_threads_signals_init ();
+ mono_thread_info_signals_init ();
#ifndef MONO_CROSS_COMPILE
mono_runtime_install_handlers ();
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");
- }
+ mono_profiler_state.context_enable = mini_profiler_context_enable;
+ mono_profiler_state.context_get_this = mini_profiler_context_get_this;
+ mono_profiler_state.context_get_argument = mini_profiler_context_get_argument;
+ mono_profiler_state.context_get_local = mini_profiler_context_get_local;
+ mono_profiler_state.context_get_result = mini_profiler_context_get_result;
+ mono_profiler_state.context_free_buffer = mini_profiler_context_free_buffer;
+
+ if (profile_options)
+ for (guint i = 0; i < profile_options->len; i++)
+ mono_profiler_load ((const char *) g_ptr_array_index (profile_options, i));
+
+ mono_profiler_started ();
if (debug_options.collect_pagefault_stats)
mono_aot_set_make_unreadable (TRUE);
mono_runtime_init_checked (domain, mono_thread_start_cb, mono_thread_attach_cb, &error);
mono_error_assert_ok (&error);
mono_thread_attach (domain);
+ MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"));
#endif
- if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+ if (mono_profiler_sampling_enabled ())
mono_runtime_setup_stat_profiler ();
- mono_profiler_runtime_initialized ();
+ MONO_PROFILER_RAISE (runtime_initialized, ());
MONO_VES_INIT_END ();
mono_add_internal_call ("Mono.Runtime::mono_runtime_cleanup_handlers",
mono_runtime_cleanup_handlers);
-#if defined(PLATFORM_ANDROID) || defined(TARGET_ANDROID)
+#if defined(HOST_ANDROID) || defined(TARGET_ANDROID)
mono_add_internal_call ("System.Diagnostics.Debugger::Mono_UnhandledException_internal",
mono_debugger_agent_unhandled_exception);
#endif
* the wrapper would call the icall which would call the wrapper and
* so on.
*/
- register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE);
- register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE);
+ register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
+ register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
+ register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
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_self_abort, "mono_thread_self_abort", "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);
-#if defined(__native_client__) || defined(__native_client_codegen__)
- register_icall (mono_nacl_gc, "mono_nacl_gc", "void", FALSE);
-#endif
-
if (mono_threads_is_coop_enabled ())
register_icall (mono_threads_state_poll, "mono_threads_state_poll", "void", FALSE);
register_opcode_emulation (OP_LCONV_TO_R_UN, "__emul_lconv_to_r8_un", "double long", mono_lconv_to_r8_un, "mono_lconv_to_r8_un", FALSE);
#endif
#ifdef MONO_ARCH_EMULATE_FREM
-#if !defined(__native_client__)
register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", fmod, "fmod", FALSE);
register_opcode_emulation (OP_RREM, "__emul_rrem", "float float float", fmodf, "fmodf", FALSE);
-#else
- register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
-#endif
#endif
#ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
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);
+ //WARNING We do runtime selection here but the string *MUST* be to a fallback function that has same signature and behavior
+ register_icall_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_wbarrier_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);
MonoJitStats mono_jit_stats = {0};
+/**
+ * Counters of mono_stats can be read without locking here.
+ * MONO_NO_SANITIZE_THREAD tells Clang's ThreadSanitizer to hide all reports of these (known) races.
+ */
+MONO_NO_SANITIZE_THREAD
static void
print_jit_stats (void)
{
g_print ("Biggest method: %ld (%s)\n", mono_jit_stats.biggest_method_size,
mono_jit_stats.biggest_method);
- g_print ("Delegates created: %ld\n", mono_stats.delegate_creations);
- g_print ("Initialized classes: %ld\n", mono_stats.initialized_class_count);
- g_print ("Used classes: %ld\n", mono_stats.used_class_count);
- g_print ("Generic vtables: %ld\n", mono_stats.generic_vtable_count);
- g_print ("Methods: %ld\n", mono_stats.method_count);
- g_print ("Static data size: %ld\n", mono_stats.class_static_data_size);
- g_print ("VTable data size: %ld\n", mono_stats.class_vtable_size);
+ g_print ("Delegates created: %" G_GINT32_FORMAT "\n", mono_stats.delegate_creations);
+ g_print ("Initialized classes: %" G_GINT32_FORMAT "\n", mono_stats.initialized_class_count);
+ g_print ("Used classes: %" G_GINT32_FORMAT "\n", mono_stats.used_class_count);
+ g_print ("Generic vtables: %" G_GINT32_FORMAT "\n", mono_stats.generic_vtable_count);
+ g_print ("Methods: %" G_GINT32_FORMAT "\n", mono_stats.method_count);
+ g_print ("Static data size: %" G_GINT32_FORMAT "\n", mono_stats.class_static_data_size);
+ g_print ("VTable data size: %" G_GINT32_FORMAT "\n", mono_stats.class_vtable_size);
g_print ("Mscorlib mempool size: %d\n", mono_mempool_get_allocated (mono_defaults.corlib->mempool));
- g_print ("\nInitialized classes: %ld\n", mono_stats.generic_class_count);
- g_print ("Inflated types: %ld\n", mono_stats.inflated_type_count);
+ g_print ("\nInitialized classes: %" G_GINT32_FORMAT "\n", mono_stats.generic_class_count);
+ g_print ("Inflated types: %" G_GINT32_FORMAT "\n", mono_stats.inflated_type_count);
g_print ("Generics virtual invokes: %ld\n", mono_jit_stats.generic_virtual_invocations);
- g_print ("Sharable generic methods: %ld\n", mono_stats.generics_sharable_methods);
- g_print ("Unsharable generic methods: %ld\n", mono_stats.generics_unsharable_methods);
- g_print ("Shared generic methods: %ld\n", mono_stats.generics_shared_methods);
- g_print ("Shared vtype generic methods: %ld\n", mono_stats.gsharedvt_methods);
+ g_print ("Sharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_sharable_methods);
+ g_print ("Unsharable generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_unsharable_methods);
+ g_print ("Shared generic methods: %" G_GINT32_FORMAT "\n", mono_stats.generics_shared_methods);
+ g_print ("Shared vtype generic methods: %" G_GINT32_FORMAT "\n", mono_stats.gsharedvt_methods);
- g_print ("IMT tables size: %ld\n", mono_stats.imt_tables_size);
- g_print ("IMT number of tables: %ld\n", mono_stats.imt_number_of_tables);
- g_print ("IMT number of methods: %ld\n", mono_stats.imt_number_of_methods);
- g_print ("IMT used slots: %ld\n", mono_stats.imt_used_slots);
- g_print ("IMT colliding slots: %ld\n", mono_stats.imt_slots_with_collisions);
- g_print ("IMT max collisions: %ld\n", mono_stats.imt_max_collisions_in_slot);
- g_print ("IMT methods at max col: %ld\n", mono_stats.imt_method_count_when_max_collisions);
- g_print ("IMT trampolines size: %ld\n", mono_stats.imt_trampolines_size);
+ g_print ("IMT tables size: %" G_GINT32_FORMAT "\n", mono_stats.imt_tables_size);
+ g_print ("IMT number of tables: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_tables);
+ g_print ("IMT number of methods: %" G_GINT32_FORMAT "\n", mono_stats.imt_number_of_methods);
+ g_print ("IMT used slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_used_slots);
+ g_print ("IMT colliding slots: %" G_GINT32_FORMAT "\n", mono_stats.imt_slots_with_collisions);
+ g_print ("IMT max collisions: %" G_GINT32_FORMAT "\n", mono_stats.imt_max_collisions_in_slot);
+ g_print ("IMT methods at max col: %" G_GINT32_FORMAT "\n", mono_stats.imt_method_count_when_max_collisions);
+ g_print ("IMT trampolines size: %" G_GINT32_FORMAT "\n", mono_stats.imt_trampolines_size);
- g_print ("JIT info table inserts: %ld\n", mono_stats.jit_info_table_insert_count);
- g_print ("JIT info table removes: %ld\n", mono_stats.jit_info_table_remove_count);
- g_print ("JIT info table lookups: %ld\n", mono_stats.jit_info_table_lookup_count);
+ g_print ("JIT info table inserts: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_insert_count);
+ g_print ("JIT info table removes: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_remove_count);
+ g_print ("JIT info table lookups: %" G_GINT32_FORMAT "\n", mono_stats.jit_info_table_lookup_count);
g_free (mono_jit_stats.max_ratio_method);
mono_jit_stats.max_ratio_method = NULL;
void
mini_cleanup (MonoDomain *domain)
{
- if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL)
+ if (mono_profiler_sampling_enabled ())
mono_runtime_shutdown_stat_profiler ();
+ MONO_PROFILER_RAISE (runtime_shutdown_begin, ());
+
#ifndef DISABLE_COM
cominterop_release_all_rcws ();
#endif
mono_threadpool_cleanup ();
- mono_profiler_shutdown ();
+ MONO_PROFILER_RAISE (runtime_shutdown_end, ());
+
+ mono_profiler_cleanup ();
+
+ if (profile_options)
+ g_ptr_array_free (profile_options, TRUE);
free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
g_assert_not_reached ();
}
+
+static MonoBreakPolicy
+always_insert_breakpoint (MonoMethod *method)
+{
+ return MONO_BREAK_POLICY_ALWAYS;
+}
+
+static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
+
+/**
+ * mono_set_break_policy:
+ * \param policy_callback the new callback function
+ *
+ * Allow embedders to decide whether to actually obey breakpoint instructions
+ * (both break IL instructions and \c Debugger.Break method calls), for example
+ * to not allow an app to be aborted by a perfectly valid IL opcode when executing
+ * untrusted or semi-trusted code.
+ *
+ * \p policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls \c Debugger.Break
+ * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
+ * if it wants the breakpoint to not be effective in the given method.
+ * \c MONO_BREAK_POLICY_ALWAYS is the default.
+ */
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+ if (policy_callback)
+ break_policy_func = policy_callback;
+ else
+ break_policy_func = always_insert_breakpoint;
+}
+
+gboolean
+mini_should_insert_breakpoint (MonoMethod *method)
+{
+ switch (break_policy_func (method)) {
+ case MONO_BREAK_POLICY_ALWAYS:
+ return TRUE;
+ case MONO_BREAK_POLICY_NEVER:
+ return FALSE;
+ case MONO_BREAK_POLICY_ON_DBG:
+ g_warning ("mdb no longer supported");
+ return FALSE;
+ default:
+ g_warning ("Incorrect value returned from break policy callback");
+ return FALSE;
+ }
+}
+
// Custom handlers currently only implemented by Windows.
#ifndef HOST_WIN32
gboolean