Merge pull request #3040 from xmcclure/debugger-step-recursive
[mono.git] / mono / mini / mini-runtime.c
index ac123365f90fd3e8dd1a0c02f624c89502c41e99..6f4082905c5687bf4679fffe2550815663475880 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>
 
@@ -362,65 +363,6 @@ mono_nacl_gc()
        __nacl_suspend_thread_if_needed();
 #endif
 }
-
-/* Given the temporary buffer (allocated by mono_global_codeman_reserve) into
- * which we are generating code, return a pointer to the destination in the
- * dynamic code segment into which the code will be copied when
- * mono_global_codeman_commit is called.
- * LOCKING: Acquires the jit lock.
- */
-void*
-nacl_global_codeman_get_dest (void *data)
-{
-       void *dest;
-       mono_jit_lock ();
-       dest = nacl_code_manager_get_code_dest (global_codeman, data);
-       mono_jit_unlock ();
-       return dest;
-}
-
-void
-mono_global_codeman_commit (void *data, int size, int newsize)
-{
-       mono_jit_lock ();
-       mono_code_manager_commit (global_codeman, data, size, newsize);
-       mono_jit_unlock ();
-}
-
-/*
- * Convenience function which calls mono_global_codeman_commit to validate and
- * copy the code. The caller sets *buf_base and *buf_size to the start and size
- * of the buffer (allocated by mono_global_codeman_reserve), and *code_end to
- * the byte after the last instruction byte. On return, *buf_base will point to
- * the start of the copied in the code segment, and *code_end will point after
- * the end of the copied code.
- */
-void
-nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
-{
-       guint8 *tmp = nacl_global_codeman_get_dest (*buf_base);
-       mono_global_codeman_commit (*buf_base, buf_size, *code_end - *buf_base);
-       *code_end = tmp + (*code_end - *buf_base);
-       *buf_base = tmp;
-}
-#else
-/* no-op versions of Native Client functions */
-void*
-nacl_global_codeman_get_dest (void *data)
-{
-       return data;
-}
-
-void
-mono_global_codeman_commit (void *data, int size, int newsize)
-{
-}
-
-void
-nacl_global_codeman_validate (guint8 **buf_base, int buf_size, guint8 **code_end)
-{
-}
-
 #endif /* __native_client__ */
 
 /**
@@ -616,6 +558,7 @@ mono_debug_count (void)
 gconstpointer
 mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
 {
+       MonoError error;
        char *name;
        MonoMethod *wrapper;
        gconstpointer trampoline;
@@ -637,9 +580,9 @@ mono_icall_get_wrapper_full (MonoJitICallInfo* callinfo, gboolean do_compile)
        g_free (name);
 
        if (do_compile) {
-               trampoline = mono_compile_method (wrapper);
+               trampoline = mono_compile_method_checked (wrapper, &error);
+               mono_error_assert_ok (&error);
        } else {
-               MonoError error;
 
                trampoline = mono_create_jit_trampoline (domain, wrapper, &error);
                mono_error_assert_ok (&error);
@@ -895,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. */
@@ -917,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);
 }
 
 /**
@@ -1454,13 +1343,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = patch_info->data.inst->inst_c0 + code;
                break;
        case MONO_PATCH_INFO_IP:
-#if defined(__native_client__) && defined(__native_client_codegen__)
-               /* Need to transform to the destination address, it's */
-               /* emitted as an immediate in the code. */
-               target = nacl_inverse_modify_patch_target(ip);
-#else
                target = ip;
-#endif
                break;
        case MONO_PATCH_INFO_METHOD_REL:
                target = code + patch_info->data.offset;
@@ -1487,13 +1370,6 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                target = mono_create_jump_trampoline (domain, patch_info->data.method, FALSE, error);
                if (!mono_error_ok (error))
                        return NULL;
-#if defined(__native_client__) && defined(__native_client_codegen__)
-# if defined(TARGET_AMD64)
-               /* This target is an absolute address, not relative to the */
-               /* current code being emitted on AMD64. */
-               target = nacl_inverse_modify_patch_target(target);
-# endif
-#endif
                break;
        case MONO_PATCH_INFO_METHOD:
                if (patch_info->data.method == method) {
@@ -1548,24 +1424,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 #endif
 
                for (i = 0; i < patch_info->data.table->table_size; i++) {
-#if defined(__native_client__) && defined(__native_client_codegen__)
-                       /* 'code' is relative to the current code blob, we */
-                       /* need to do this transform on it to make the     */
-                       /* pointers in this table absolute                 */
-                       jump_table [i] = nacl_inverse_modify_patch_target (code) + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-#else
                        jump_table [i] = code + GPOINTER_TO_INT (patch_info->data.table->table [i]);
-#endif
                }
 
-#if defined(__native_client__) && defined(__native_client_codegen__)
-               /* jump_table is in the data section, we need to transform */
-               /* it here so when it gets modified in amd64_patch it will */
-               /* then point back to the absolute data address            */
-               target = nacl_inverse_modify_patch_target (jump_table);
-#else
                target = jump_table;
-#endif
                break;
        }
        case MONO_PATCH_INFO_METHODCONST:
@@ -1642,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;
@@ -2906,9 +2768,13 @@ MONO_SIG_HANDLER_FUNC (, mono_sigill_signal_handler)
        MonoException *exc;
        MONO_SIG_HANDLER_GET_CONTEXT;
 
+       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)
@@ -3029,24 +2895,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)
 {
        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 (nm);
-       } else
-       {
-               addr = (guint8 *)mono_compile_method (method);
-       }
+       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
@@ -3864,8 +3731,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);
@@ -3965,10 +3832,10 @@ 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(__default_codegen__)
+#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);
-#elif defined(__native_client_codegen__)
+#else
        register_opcode_emulation (OP_FREM, "__emul_frem", "double double double", mono_fmod, "mono_fmod", FALSE);
 #endif
 #endif
@@ -4028,14 +3895,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);
@@ -4089,6 +3956,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");
@@ -4308,15 +4176,21 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                        g_print ("Compiling %d %s\n", count, desc);
                        g_free (desc);
                }
-               mono_compile_method (method);
+               mono_compile_method_checked (method, &error);
+               if (!is_ok (&error)) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                       continue;
+               }
                if (strcmp (method->name, "Finalize") == 0) {
                        invoke = mono_marshal_get_runtime_invoke (method, FALSE);
-                       mono_compile_method (invoke);
+                       mono_compile_method_checked (invoke, &error);
+                       mono_error_assert_ok (&error);
                }
 #ifndef DISABLE_REMOTING
                if (mono_class_is_marshalbyref (method->klass) && mono_method_signature (method)->hasthis) {
                        invoke = mono_marshal_get_remoting_invoke_with_check (method);
-                       mono_compile_method (invoke);
+                       mono_compile_method_checked (invoke, &error);
+                       mono_error_assert_ok (&error);
                }
 #endif
        }