Merge pull request #3262 from lindenlab/add_continuations_test
[mono.git] / mono / mini / mini-runtime.c
index a887fc67fe35a0cf3a1b54504398be23050603b6..dfce66481ea8db4cef11787384c1f03ad25ac634 100644 (file)
@@ -63,6 +63,7 @@
 #include <mono/utils/dtrace.h>
 #include <mono/utils/mono-signal-handler.h>
 #include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-coop.h>
 #include <mono/utils/checked-build.h>
 #include <mono/io-layer/io-layer.h>
 
@@ -837,20 +838,20 @@ mono_set_lmf_addr (gpointer lmf_addr)
 }
 
 /*
- * mono_jit_thread_attach: called by native->managed wrappers
+ * mono_jit_thread_attach:
  *
- * In non-coop mode:
- *  - @dummy: is NULL
- *  - @return: the original domain which needs to be restored, or NULL.
+ * Called by Xamarin.Mac and other products. Attach thread to runtime if
+ * needed and switch to @domain.
  *
- * In coop mode:
- *  - @dummy: contains the original domain
- *  - @return: a cookie containing current MonoThreadInfo*.
+ * @return the original domain which needs to be restored, or NULL.
  */
-gpointer
-mono_jit_thread_attach (MonoDomain *domain, gpointer *dummy)
+MonoDomain*
+mono_jit_thread_attach (MonoDomain *domain)
 {
        MonoDomain *orig;
+       gboolean attached;
+
+       g_assert (!mono_threads_is_coop_enabled ());
 
        if (!domain) {
                /* Happens when called from AOTed code which is only used in the root domain. */
@@ -859,92 +860,38 @@ mono_jit_thread_attach (MonoDomain *domain, gpointer *dummy)
 
        g_assert (domain);
 
-       /* On coop, when we detached, we moved the thread from  RUNNING->BLOCKING.  If we try to
-        * reattach we do a BLOCKING->RUNNING transition.  If the thread is fresh,
-        * mono_thread_attach() will do a STARTING->RUNNING transition so we're only responsible
-        * for making the cookie. */
-       gboolean fresh_thread = FALSE;
-       {
-               MonoThreadInfo *info;
-
-               info = mono_thread_info_current_unchecked ();
-               fresh_thread = !info || !mono_thread_info_is_live (info);
-       }
-       {
-               gboolean attached;
-
 #ifdef MONO_HAVE_FAST_TLS
-               attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
+       attached = MONO_FAST_TLS_GET (mono_lmf_addr) != NULL;
 #else
-               attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
+       attached = mono_native_tls_get_value (mono_jit_tls_id) != NULL;
 #endif
 
-               if (!attached) {
-                       mono_thread_attach (domain);
+       if (!attached) {
+               mono_thread_attach (domain);
 
-                       // #678164
-                       mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
-               }
+               // #678164
+               mono_thread_set_state (mono_thread_internal_current (), ThreadState_Background);
+       }
 
-               orig = mono_domain_get ();
-               if (orig != domain)
-                       mono_domain_set (domain, TRUE);
+       orig = mono_domain_get ();
+       if (orig != domain)
+               mono_domain_set (domain, TRUE);
 
-       }
-       if (!mono_threads_is_coop_enabled ()) {
-               return orig != domain ? orig : NULL;
-       } else {
-               if (fresh_thread) {
-                       *dummy = NULL;
-                       /* mono_thread_attach put the thread in RUNNING mode from STARTING, but we need to
-                        * return the right cookie. */
-                       return mono_threads_enter_gc_unsafe_region_cookie (mono_thread_info_current ());
-               } else {
-                       *dummy = orig;
-                       /* thread state (BLOCKING|RUNNING) -> RUNNING */
-                       return mono_threads_enter_gc_unsafe_region (dummy);
-               }
-       }
+       return orig != domain ? orig : NULL;
 }
 
 /*
- * mono_jit_thread_detach: called by native->managed wrappers
- *
- * In non-coop mode:
- *  - @cookie: the original domain which needs to be restored, or NULL.
- *  - @dummy: is NULL
+ * mono_jit_set_domain:
  *
- * In coop mode:
- *  - @cookie: contains current MonoThreadInfo* if it was in BLOCKING mode, NULL otherwise
- *  - @dummy: contains the original domain
+ * Set domain to @domain if @domain is not null
  */
 void
-mono_jit_thread_detach (gpointer cookie, gpointer *dummy)
+mono_jit_set_domain (MonoDomain *domain)
 {
-       MonoDomain *domain, *orig;
+       g_assert (!mono_threads_is_coop_enabled ());
 
-       if (!mono_threads_is_coop_enabled ()) {
-               orig = (MonoDomain*) cookie;
-
-               if (orig)
-                       mono_domain_set (orig, TRUE);
-       } else {
-               orig = (MonoDomain*) *dummy;
-
-               domain = mono_domain_get ();
-               g_assert (domain);
-
-               /* it won't do anything if cookie is NULL
-                * thread state RUNNING -> (RUNNING|BLOCKING) */
-               mono_threads_exit_gc_unsafe_region (cookie, dummy);
-
-               if (orig != domain) {
-                       if (!orig)
-                               mono_domain_unset ();
-                       else
-                               mono_domain_set (orig, TRUE);
-               }
-       }
+       if (domain)
+               mono_domain_set (domain, TRUE);
 }
 
 /**
@@ -1557,8 +1504,8 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                break;
        case MONO_PATCH_INFO_LDSTR:
                target =
-                       mono_ldstr (domain, patch_info->data.token->image,
-                                               mono_metadata_token_index (patch_info->data.token->token));
+                       mono_ldstr_checked (domain, patch_info->data.token->image,
+                                           mono_metadata_token_index (patch_info->data.token->token), error);
                break;
        case MONO_PATCH_INFO_TYPE_FROM_HANDLE: {
                gpointer handle;
@@ -1567,7 +1514,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                handle = mono_ldtoken_checked (patch_info->data.token->image,
                                                           patch_info->data.token->token, &handle_class, patch_info->data.token->has_context ? &patch_info->data.token->context : NULL, error);
                if (!mono_error_ok (error))
-                       g_error ("Could not patch ldtoken due to %s", mono_error_get_message (error));
+                       return NULL;
                mono_class_init (handle_class);
                mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
 
@@ -1863,6 +1810,10 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *er
 
        mono_error_init (error);
 
+       if (mono_llvm_only)
+               /* Should be handled by the caller */
+               g_assert (!(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED));
+
        /*
         * ICALL wrappers are handled specially, since there is only one copy of them
         * shared by all appdomains.
@@ -2211,7 +2162,10 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
 
        info = g_new0 (RuntimeInvokeInfo, 1);
        info->compiled_method = compiled_method;
-       info->sig = mono_method_signature (method);
+       if (mono_llvm_only && method->string_ctor)
+               info->sig = mono_marshal_get_string_ctor_signature (method);
+       else
+               info->sig = mono_method_signature (method);
 
        invoke = mono_marshal_get_runtime_invoke (method, FALSE);
        info->vtable = mono_class_vtable_full (domain, method->klass, error);
@@ -2219,7 +2173,7 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
                return NULL;
        g_assert (info->vtable);
 
-       MonoMethodSignature *sig = mono_method_signature (method);
+       MonoMethodSignature *sig = info->sig;
        MonoType *ret_type;
 
        /*
@@ -2401,8 +2355,10 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
        runtime_invoke = (MonoObject *(*)(MonoObject *, void **, MonoObject **, void *))info->runtime_invoke;
 
        runtime_invoke (NULL, args, exc, info->compiled_method);
-       if (exc && *exc)
+       if (exc && *exc) {
                mono_error_set_exception_instance (error, (MonoException*) *exc);
+               return NULL;
+       }
 
        if (sig->ret->type != MONO_TYPE_VOID && info->ret_box_class)
                return mono_value_box_checked (domain, info->ret_box_class, retval, error);
@@ -2574,11 +2530,13 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                mono_arch_start_dyn_call (info->dyn_call_info, (gpointer**)args, retval, buf, sizeof (buf));
 
                dyn_runtime_invoke (buf, exc, info->compiled_method);
-               if (catchExcInMonoError && *exc != NULL)
-                       mono_error_set_exception_instance (error, (MonoException*) *exc);
-
                mono_arch_finish_dyn_call (info->dyn_call_info, buf);
 
+               if (catchExcInMonoError && *exc != NULL) {
+                       mono_error_set_exception_instance (error, (MonoException*) *exc);
+                       return NULL;
+               }
+
                if (info->ret_box_class)
                        return mono_value_box_checked (domain, info->ret_box_class, retval, error);
                else
@@ -2821,9 +2779,16 @@ MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
        MonoException *exc;
        MONO_SIG_HANDLER_GET_CONTEXT;
 
+       if (mono_runtime_get_no_exec ())
+               exit (1);
+
+       MONO_ENTER_GC_UNSAFE_UNBALANCED;
+
        exc = mono_get_exception_execution_engine ("SIGILL");
 
        mono_arch_handle_exception (ctx, exc);
+
+       MONO_EXIT_GC_UNSAFE_UNBALANCED;
 }
 
 #if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)
@@ -2944,27 +2909,25 @@ MONO_SIG_HANDLER_FUNC (, mono_sigint_signal_handler)
  * Returns: a pointer to the newly created code
  */
 static gpointer
-mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target)
+mono_jit_create_remoting_trampoline (MonoDomain *domain, MonoMethod *method, MonoRemotingTarget target, MonoError *error)
 {
-       MonoError error;
        MonoMethod *nm;
        guint8 *addr = NULL;
 
+       mono_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,
                        domain, NULL);
        }
 
        if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
-           (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))) {
+           (mono_method_signature (method)->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class)))
                nm = mono_marshal_get_remoting_invoke_for_target (method, target);
-               addr = (guint8 *)mono_compile_method_checked (nm, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
-       } else
-       {
-               addr = (guint8 *)mono_compile_method_checked (method, &error);
-               mono_error_raise_exception (&error); /* FIXME don't raise here */
-       }
+       else
+               nm = method;
+       addr = (guint8 *)mono_compile_method_checked (nm, error);
+       return_val_if_nok (error, NULL);
        return mono_get_addr_from_ftnptr (addr);
 }
 #endif
@@ -3093,6 +3056,17 @@ mini_init_delegate (MonoDelegate *del)
                del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
 }
 
+char*
+mono_get_delegate_virtual_invoke_impl_name (gboolean load_imt_reg, int offset)
+{
+       int abs_offset;
+
+       abs_offset = offset;
+       if (abs_offset < 0)
+               abs_offset = - abs_offset;
+       return g_strdup_printf ("delegate_virtual_invoke%s_%s%d", load_imt_reg ? "_imt" : "", offset < 0 ? "m_" : "", abs_offset / SIZEOF_VOID_P);
+}
+
 gpointer
 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
 {
@@ -3144,12 +3118,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
 
        /* FIXME Support more cases */
        if (mono_aot_only) {
-               char tramp_name [256];
-               const char *imt = load_imt_reg ? "_imt" : "";
-               int ind = (load_imt_reg ? (-offset) : offset) / SIZEOF_VOID_P;
-
-               sprintf (tramp_name, "delegate_virtual_invoke%s_%d", imt, ind);
-               cache [idx] = (guint8 *)mono_aot_get_trampoline (tramp_name);
+               cache [idx] = (guint8 *)mono_aot_get_trampoline (mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset));
                g_assert (cache [idx]);
        } else {
                cache [idx] = (guint8 *)mono_arch_get_delegate_virtual_invoke_impl (sig, method, offset, load_imt_reg);
@@ -3197,7 +3166,9 @@ mini_parse_debug_option (const char *option)
        else if (!strcmp (option, "gen-seq-points"))
                debug_options.gen_sdb_seq_points = TRUE;
        else if (!strcmp (option, "gen-compact-seq-points"))
-               debug_options.gen_seq_points_compact_data = TRUE;
+               fprintf (stderr, "Mono Warning: option gen-compact-seq-points is deprecated.\n");
+       else if (!strcmp (option, "no-compact-seq-points"))
+               debug_options.no_seq_points_compact_data = TRUE;
        else if (!strcmp (option, "single-imm-size"))
                debug_options.single_imm_size = TRUE;
        else if (!strcmp (option, "init-stacks"))
@@ -3242,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', 'gen-compact-seq-points', 'single-imm-size', 'init-stacks', 'casts', 'soft-breakpoints', 'check-pinvoke-callconv', 'arm-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-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', 'arm-use-fallback-tls', 'debug-domain-unload', 'partial-sharing', 'align-small-structs', 'native-debugger-break'\n");
                        exit (1);
                }
        }
@@ -3305,6 +3276,7 @@ register_jit_stats (void)
        mono_counters_register ("JIT/liveness_handle_exception_clauses (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_liveness_handle_exception_clauses);
        mono_counters_register ("JIT/handle_out_of_line_bblock (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_handle_out_of_line_bblock);
        mono_counters_register ("JIT/decompose_long_opts (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_long_opts);
+       mono_counters_register ("JIT/decompose_typechecks (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_decompose_typechecks);
        mono_counters_register ("JIT/local_cprop (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_cprop);
        mono_counters_register ("JIT/local_emulate_ops (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_local_emulate_ops);
        mono_counters_register ("JIT/optimize_branches (sec)", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, &mono_jit_stats.jit_optimize_branches);
@@ -3723,9 +3695,7 @@ mini_init (const char *filename, const char *runtime_version)
        mono_simd_intrinsics_init ();
 #endif
 
-#if MONO_SUPPORT_TASKLETS
        mono_tasklets_init ();
-#endif
 
        register_trampolines (domain);
 
@@ -3782,8 +3752,8 @@ register_icalls (void)
        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_icall (mono_get_lmf_addr, "mono_get_lmf_addr", "ptr", TRUE);
-       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr ptr", TRUE);
-       register_icall (mono_jit_thread_detach, "mono_jit_thread_detach", "void ptr ptr", TRUE);
+       register_icall (mono_jit_thread_attach, "mono_jit_thread_attach", "ptr ptr", TRUE);
+       register_icall (mono_jit_set_domain, "mono_jit_set_domain", "void ptr", TRUE);
        register_icall (mono_domain_get, "mono_domain_get", "ptr", TRUE);
 
        register_icall (mono_llvm_throw_exception, "mono_llvm_throw_exception", "void object", TRUE);
@@ -3807,7 +3777,6 @@ register_icalls (void)
        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);
 #ifndef DISABLE_REMOTING
-       register_icall (mono_load_remote_field_new_icall, "mono_load_remote_field_new_icall", "object object ptr ptr", FALSE);
        register_icall (mono_store_remote_field_new_icall, "mono_store_remote_field_new_icall", "void object ptr ptr object", FALSE);
 #endif
 
@@ -3946,14 +3915,14 @@ register_icalls (void)
 #endif
 
        /* other jit icalls */
-       register_icall (mono_delegate_ctor, "mono_delegate_ctor", "void object object ptr", FALSE);
+       register_icall (ves_icall_mono_delegate_ctor, "ves_icall_mono_delegate_ctor", "void object object ptr", FALSE);
        register_icall (mono_class_static_field_address , "mono_class_static_field_address",
                                 "ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper, "mono_ldtoken_wrapper", "ptr ptr ptr ptr", FALSE);
        register_icall (mono_ldtoken_wrapper_generic_shared, "mono_ldtoken_wrapper_generic_shared",
                "ptr ptr ptr ptr", FALSE);
        register_icall (mono_get_special_static_data, "mono_get_special_static_data", "ptr int", FALSE);
-       register_icall (mono_ldstr, "mono_ldstr", "object ptr ptr int32", FALSE);
+       register_icall (ves_icall_mono_ldstr, "ves_icall_mono_ldstr", "object ptr ptr int32", FALSE);
        register_icall (mono_helper_stelem_ref_check, "mono_helper_stelem_ref_check", "void object object", FALSE);
        register_icall (ves_icall_object_new, "ves_icall_object_new", "object ptr ptr", FALSE);
        register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
@@ -3987,8 +3956,8 @@ register_icalls (void)
        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 (mono_generic_class_init, "mono_generic_class_init", "void ptr", FALSE);
-       register_icall (mono_fill_class_rgctx, "mono_class_fill_rgctx", "ptr ptr int", FALSE);
-       register_icall (mono_fill_method_rgctx, "mono_method_fill_rgctx", "ptr ptr int", FALSE);
+       register_icall (mono_fill_class_rgctx, "mono_fill_class_rgctx", "ptr ptr int", FALSE);
+       register_icall (mono_fill_method_rgctx, "mono_fill_method_rgctx", "ptr ptr int", FALSE);
 
        register_icall (mono_debugger_agent_user_break, "mono_debugger_agent_user_break", "void", FALSE);
 
@@ -4007,6 +3976,7 @@ register_icalls (void)
        register_icall (mono_llvmonly_init_delegate_virtual, "mono_llvmonly_init_delegate_virtual", "void object object ptr", TRUE);
        register_icall (mono_get_assembly_object, "mono_get_assembly_object", "object ptr", TRUE);
        register_icall (mono_get_method_object, "mono_get_method_object", "object ptr", TRUE);
+       register_icall (mono_throw_method_access, "mono_throw_method_access", "void ptr ptr", FALSE);
 
        register_icall_with_wrapper (mono_monitor_enter, "mono_monitor_enter", "void obj");
        register_icall_with_wrapper (mono_monitor_enter_v4, "mono_monitor_enter_v4", "void obj ptr");