X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmini%2Fmini-runtime.c;h=8f0f7dd5395b6471f9fec9ef9df7fdc9d688a124;hb=e91a66fc94957b893cc896e32439fc957059a2de;hp=55275e0cade3f739c4a800bc1bda10f6e571f48a;hpb=d24633b39c15ae89e5b0e67e425438c3d59751de;p=mono.git diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 55275e0cade..8f0f7dd5395 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -39,7 +39,6 @@ #include #include #include -#include "mono/metadata/profiler.h" #include #include #include @@ -131,16 +130,12 @@ int valgrind_register; #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) { @@ -372,16 +367,6 @@ mono_global_codeman_foreach (MonoCodeManagerFunc func, void *user_data) 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: * @@ -496,6 +481,13 @@ mono_tramp_info_register_internal (MonoTrampInfo *info, MonoDomain *domain, gboo 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; @@ -576,23 +568,24 @@ break_count (void) 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 (); @@ -843,7 +836,7 @@ mono_jit_thread_attach (MonoDomain *domain) 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. */ @@ -876,7 +869,7 @@ mono_jit_thread_attach (MonoDomain *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); @@ -1220,6 +1213,7 @@ mono_patch_info_hash (gconstpointer data) 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); @@ -1240,6 +1234,7 @@ mono_patch_info_hash (gconstpointer data) 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); @@ -1304,6 +1299,7 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb) 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; @@ -1356,7 +1352,8 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, 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); @@ -1396,21 +1393,12 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, 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 { @@ -1420,7 +1408,6 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, 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]); @@ -1657,6 +1644,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, 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 (); } @@ -1744,10 +1735,25 @@ lookup_method (MonoDomain *domain, MonoMethod *method) 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 @@ -2055,14 +2061,25 @@ lookup_start: #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. @@ -3467,19 +3484,14 @@ mini_get_debug_options (void) 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)); @@ -3495,7 +3507,7 @@ mini_create_ftnptr (MonoDomain *domain, gpointer addr) 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; @@ -3742,10 +3754,12 @@ mini_llvm_init (void) } 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 * @@ -3761,7 +3775,7 @@ mini_init (const char *filename, const char *runtime_version) 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); @@ -3838,7 +3852,7 @@ mini_init (const char *filename, const char *runtime_version) mono_w32handle_init (); #endif - mono_threads_runtime_init (&ticallbacks); + mono_thread_info_runtime_init (&ticallbacks); if (g_hasenv ("MONO_DEBUG")) { mini_parse_debug_options (); @@ -3903,7 +3917,7 @@ mini_init (const char *filename, const char *runtime_version) mono_set_generic_sharing_supported (TRUE); #endif - mono_threads_signals_init (); + mono_thread_info_signals_init (); #ifndef MONO_CROSS_COMPILE mono_runtime_install_handlers (); @@ -3918,10 +3932,18 @@ 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"); - } + 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); @@ -3998,12 +4020,13 @@ mini_init (const char *filename, const char *runtime_version) 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 (); @@ -4022,7 +4045,7 @@ register_icalls (void) 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 @@ -4034,8 +4057,9 @@ register_icalls (void) * 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); @@ -4062,13 +4086,10 @@ register_icalls (void) 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); @@ -4137,12 +4158,8 @@ register_icalls (void) 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 @@ -4236,7 +4253,8 @@ register_icalls (void) 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_no_wrapper (mono_gc_get_range_copy_func (), "mono_gc_range_copy", "void ptr ptr int"); + //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); @@ -4338,9 +4356,11 @@ print_jit_stats (void) 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 @@ -4362,7 +4382,12 @@ mini_cleanup (MonoDomain *domain) 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 ()); @@ -4545,6 +4570,56 @@ mono_personality (void) 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