Merge pull request #2531 from esdrubal/systemweb
[mono.git] / mono / mini / mini-runtime.c
index c26cc91073ab8106f6f559ceeac70bf796456f0d..4640672dd5428c48a861892c3e4888b87b4d4fe4 100644 (file)
@@ -47,6 +47,7 @@
 #include <mono/metadata/mempool-internals.h>
 #include <mono/metadata/attach.h>
 #include <mono/metadata/runtime.h>
+#include <mono/metadata/reflection-internals.h>
 #include <mono/utils/mono-math.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-counters.h>
@@ -1262,6 +1263,8 @@ mono_patch_info_hash (gconstpointer data)
        }
        case MONO_PATCH_INFO_JIT_ICALL_ADDR:
                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);
        default:
                printf ("info type: %d\n", ji->type);
                mono_print_ji (ji); printf ("\n");
@@ -1326,6 +1329,8 @@ mono_patch_info_equal (gconstpointer ka, gconstpointer kb)
                if (ji1->data.target == ji2->data.target)
                        return 1;
                return strcmp (ji1->data.target, ji2->data.target) == 0 ? 1 : 0;
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               return mono_metadata_signature_equal (ji1->data.sig, ji2->data.sig) ? 1 : 0;
        default:
                if (ji1->data.target != ji2->data.target)
                        return 0;
@@ -1562,8 +1567,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
                mono_class_init (handle_class);
                mono_class_init (mono_class_from_mono_type ((MonoType *)handle));
 
-               target =
-                       mono_type_get_object (domain, (MonoType *)handle);
+               target = mono_type_get_object_checked (domain, (MonoType *)handle, &error);
+               mono_error_raise_exception (&error);
+
                break;
        }
        case MONO_PATCH_INFO_LDTOKEN: {
@@ -1698,6 +1704,9 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
 
                break;
        }
+       case MONO_PATCH_INFO_GSHAREDVT_IN_WRAPPER:
+               target = mini_get_gsharedvt_wrapper (TRUE, NULL, patch_info->data.sig, NULL, -1, FALSE);
+               break;
        default:
                g_assert_not_reached ();
        }
@@ -1837,7 +1846,7 @@ no_gsharedvt_in_wrapper (void)
 }
 
 static gpointer
-mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex)
+mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoError *error)
 {
        MonoDomain *target_domain, *domain = mono_domain_get ();
        MonoJitInfo *info;
@@ -1846,6 +1855,8 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
        MonoJitICallInfo *callinfo = NULL;
        WrapperInfo *winfo = NULL;
 
+       mono_error_init (error);
+
        /*
         * ICALL wrappers are handled specially, since there is only one copy of them
         * shared by all appdomains.
@@ -1878,9 +1889,8 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                                ctx = mono_method_get_context (method);
                        method = info->d.synchronized_inner.method;
                        if (ctx) {
-                               MonoError error;
-                               method = mono_class_inflate_generic_method_checked (method, ctx, &error);
-                               g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+                               method = mono_class_inflate_generic_method_checked (method, ctx, error);
+                               g_assert (mono_error_ok (error)); /* FIXME don't swallow the error */
                        }
                }
        }
@@ -1895,9 +1905,9 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
                        mono_jit_stats.methods_lookups++;
                        vtable = mono_class_vtable (domain, method->klass);
                        g_assert (vtable);
-                       tmpEx = mono_runtime_class_init_full (vtable, ex == NULL);
+                       tmpEx = mono_runtime_class_init_full (vtable, FALSE);
                        if (tmpEx) {
-                               *ex = tmpEx;
+                               mono_error_set_exception_instance (error, tmpEx);
                                return NULL;
                        }
                        return mono_create_ftnptr (target_domain, info->code_start);
@@ -1928,7 +1938,9 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
 #endif
 
        if (!code)
-               code = mono_jit_compile_method_inner (method, target_domain, opt, ex);
+               code = mono_jit_compile_method_inner (method, target_domain, opt, error);
+       if (!mono_error_ok (error))
+               return NULL;
 
        if (!code && mono_llvm_only) {
                if (method->wrapper_type == MONO_WRAPPER_UNKNOWN) {
@@ -1979,17 +1991,11 @@ mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException
 }
 
 gpointer
-mono_jit_compile_method (MonoMethod *method)
+mono_jit_compile_method (MonoMethod *method, MonoError *error)
 {
-       MonoException *ex = NULL;
        gpointer code;
 
-       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), &ex);
-       if (!code) {
-               g_assert (ex);
-               mono_raise_exception (ex);
-       }
-
+       code = mono_jit_compile_method_with_opt (method, mono_get_optimizations_for_method (method, default_opt), error);
        return code;
 }
 
@@ -2190,7 +2196,7 @@ typedef struct {
 } RuntimeInvokeInfo;
 
 static RuntimeInvokeInfo*
-create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt)
+create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer compiled_method, gboolean callee_gsharedvt, MonoError *error)
 {
        MonoMethod *invoke;
        RuntimeInvokeInfo *info;
@@ -2280,34 +2286,40 @@ create_runtime_invoke_info (MonoDomain *domain, MonoMethod *method, gpointer com
 #ifndef ENABLE_GSHAREDVT
                        g_assert_not_reached ();
 #endif
+                       info->gsharedvt_invoke = TRUE;
                        if (!callee_gsharedvt) {
                                /* Invoke a gsharedvt out wrapper instead */
                                MonoMethod *wrapper = mini_get_gsharedvt_out_sig_wrapper (sig);
                                MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
 
-                               info->gsharedvt_invoke = TRUE;
                                info->wrapper_arg = g_malloc0 (2 * sizeof (gpointer));
-                               info->wrapper_arg [0] = info->compiled_method;
-                               info->wrapper_arg [1] = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
+                               info->wrapper_arg [0] = mini_add_method_wrappers_llvmonly (method, info->compiled_method, FALSE, FALSE, &(info->wrapper_arg [1]));
 
                                /* Pass has_rgctx == TRUE since the wrapper has an extra arg */
                                invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
                                g_free (wrapper_sig);
 
-                               info->compiled_method = mono_jit_compile_method (wrapper);
+                               info->compiled_method = mono_jit_compile_method (wrapper, error);
+                               if (!mono_error_ok (error)) {
+                                       g_free (info);
+                                       return NULL;
+                               }
                        } else {
                                /* Gsharedvt methods can be invoked the same way */
                                /* The out wrapper has the same signature as the compiled gsharedvt method */
                                MonoMethodSignature *wrapper_sig = mini_get_gsharedvt_out_sig_wrapper_signature (sig->hasthis, sig->ret->type != MONO_TYPE_VOID, sig->param_count);
 
-                               info->gsharedvt_invoke = TRUE;
                                info->wrapper_arg = mono_method_needs_static_rgctx_invoke (method, TRUE) ? mini_method_get_rgctx (method) : NULL;
 
                                invoke = mono_marshal_get_runtime_invoke_for_sig (wrapper_sig);
                                g_free (wrapper_sig);
                        }
                }
-               info->runtime_invoke = mono_jit_compile_method (invoke);
+               info->runtime_invoke = mono_jit_compile_method (invoke, error);
+               if (!mono_error_ok (error)) {
+                       g_free (info);
+                       return NULL;
+               }
        }
 
        return info;
@@ -2365,7 +2377,7 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
                        params [i] = nullable_buf;
                }
 
-               if (MONO_TYPE_IS_REFERENCE (t)) {
+               if (!t->byref && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) {
                        param_refs [i] = params [i];
                        params [i] = &(param_refs [i]);
                }
@@ -2389,10 +2401,11 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void
  * @method: the method to invoke
  * @obj: this pointer
  * @params: array of parameter values.
+ * @error: error
  * @exc: used to catch exceptions objects
  */
 static MonoObject*
-mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
+mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoError *error, MonoObject **exc)
 {
        MonoMethod *invoke, *callee;
        MonoObject *(*runtime_invoke) (MonoObject *this_obj, void **params, MonoObject **exc, void* compiled_method);
@@ -2402,6 +2415,8 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
        MonoJitInfo *ji = NULL;
        gboolean callee_gsharedvt = FALSE;
 
+       mono_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");
                return NULL;
@@ -2451,23 +2466,17 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                }
 
                if (callee) {
-                       MonoException *jit_ex = NULL;
-
-                       compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), &jit_ex);
+                       compiled_method = mono_jit_compile_method_with_opt (callee, mono_get_optimizations_for_method (callee, default_opt), error);
                        if (!compiled_method) {
-                               g_assert (jit_ex);
-                               if (exc) {
-                                       *exc = (MonoObject*)jit_ex;
-                                       return NULL;
-                               } else {
-                                       mono_raise_exception (jit_ex);
-                                       /* coverity[unreachable] */
-                               }
+                               g_assert (!mono_error_ok (error));
+                               return NULL;
                        }
 
                        if (mono_llvm_only) {
                                ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (compiled_method), NULL);
                                callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+                               if (callee_gsharedvt)
+                                       callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
                        }
 
                        if (!callee_gsharedvt)
@@ -2476,7 +2485,9 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
                        compiled_method = NULL;
                }
 
-               info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt);
+               info = create_runtime_invoke_info (domain, method, compiled_method, callee_gsharedvt, error);
+               if (!mono_error_ok (error))
+                       return NULL;
 
                mono_domain_lock (domain);
                info2 = (RuntimeInvokeInfo *)mono_conc_hashtable_insert (domain_info->runtime_invoke_hash, method, info);
@@ -2514,7 +2525,9 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 
                if (!dyn_runtime_invoke) {
                        invoke = mono_marshal_get_runtime_invoke_dynamic ();
-                       dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke);
+                       dyn_runtime_invoke = (RuntimeInvokeDynamicFunction)mono_jit_compile_method (invoke, error);
+                       if (!mono_error_ok (error))
+                               return NULL;
                }
 
                /* Convert the arguments to the format expected by start_dyn_call () */
@@ -2638,14 +2651,14 @@ mono_llvmonly_imt_thunk_3 (gpointer *arg, MonoMethod *imt_method)
 }
 
 /*
- * A version of the imt thunk used for generic virtual methods.
+ * A version of the imt thunk used for generic virtual/variant iface methods.
  * Unlikely a normal imt thunk, its possible that IMT_METHOD is not found
  * in the search table. The original JIT code had a 'fallback' trampoline it could
  * call, but we can't do that, so we just return NULL, and the compiled code
  * will handle it.
  */
 static gpointer
-mono_llvmonly_generic_virtual_imt_thunk (gpointer *arg, MonoMethod *imt_method)
+mono_llvmonly_fallback_imt_thunk (gpointer *arg, MonoMethod *imt_method)
 {
        int i = 0;
 
@@ -2733,8 +2746,8 @@ mono_llvmonly_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTChec
                res [0] = mono_llvmonly_imt_thunk;
                break;
        }
-       if (virtual_generic)
-               res [0] = mono_llvmonly_generic_virtual_imt_thunk;
+       if (virtual_generic || fail_tramp)
+               res [0] = mono_llvmonly_fallback_imt_thunk;
        res [1] = buf;
 
        return res;
@@ -3008,6 +3021,48 @@ mini_imt_entry_inited (MonoVTable *vt, int imt_slot_index)
        return (imt [imt_slot_index] != mini_get_imt_trampoline (vt, imt_slot_index));
 }
 
+static gboolean
+is_callee_gsharedvt_variable (gpointer addr)
+{
+       MonoJitInfo *ji;
+       gboolean callee_gsharedvt;
+
+       ji = mini_jit_info_table_find (mono_domain_get (), (char *)mono_get_addr_from_ftnptr (addr), NULL);
+       g_assert (ji);
+       callee_gsharedvt = mini_jit_info_is_gsharedvt (ji);
+       if (callee_gsharedvt)
+               callee_gsharedvt = mini_is_gsharedvt_variable_signature (mono_method_signature (jinfo_get_method (ji)));
+       return callee_gsharedvt;
+}
+
+gpointer
+mini_get_delegate_arg (MonoMethod *method, gpointer method_ptr)
+{
+       gpointer arg = NULL;
+
+       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+               arg = mini_method_get_rgctx (method);
+
+       /*
+        * Avoid adding gsharedvt in wrappers since they might not exist if
+        * this delegate is called through a gsharedvt delegate invoke wrapper.
+        * Instead, encode that the method is gsharedvt in del->extra_arg,
+        * the CEE_MONO_CALLI_EXTRA_ARG implementation in the JIT depends on this.
+        */
+       if (method->is_inflated && is_callee_gsharedvt_variable (method_ptr)) {
+               g_assert ((((mgreg_t)arg) & 1) == 0);
+               arg = (gpointer)(((mgreg_t)arg) | 1);
+       }
+       return arg;
+}
+
+void
+mini_init_delegate (MonoDelegate *del)
+{
+       if (mono_llvm_only)
+               del->extra_arg = mini_get_delegate_arg (del->method, del->method_ptr);
+}
+
 gpointer
 mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *method)
 {
@@ -3436,10 +3491,18 @@ mini_init (const char *filename, const char *runtime_version)
        callbacks.debug_log = mono_debugger_agent_debug_log;
        callbacks.debug_log_is_enabled = mono_debugger_agent_debug_log_is_enabled;
        callbacks.tls_key_supported = mini_tls_key_supported;
-
        callbacks.get_vtable_trampoline = mini_get_vtable_trampoline;
        callbacks.get_imt_trampoline = mini_get_imt_trampoline;
        callbacks.imt_entry_inited = mini_imt_entry_inited;
+       callbacks.init_delegate = mini_init_delegate;
+#define JIT_INVOKE_WORKS
+#ifdef JIT_INVOKE_WORKS
+       callbacks.runtime_invoke = mono_jit_runtime_invoke;
+#endif
+#define JIT_TRAMPOLINES_WORK
+#ifdef JIT_TRAMPOLINES_WORK
+       callbacks.compile_method = mono_jit_compile_method;
+#endif
 
        mono_install_callbacks (&callbacks);
 
@@ -3509,9 +3572,7 @@ mini_init (const char *filename, const char *runtime_version)
 #endif
        mono_threads_install_cleanup (mini_thread_cleanup);
 
-#define JIT_TRAMPOLINES_WORK
 #ifdef JIT_TRAMPOLINES_WORK
-       mono_install_compile_method (mono_jit_compile_method);
        mono_install_free_method (mono_jit_free_method);
        mono_install_trampoline (mono_create_jit_trampoline);
        mono_install_jump_trampoline (mono_create_jump_trampoline);
@@ -3521,10 +3582,6 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_delegate_trampoline (mono_create_delegate_trampoline);
        mono_install_create_domain_hook (mini_create_jit_domain_info);
        mono_install_free_domain_hook (mini_free_jit_domain_info);
-#endif
-#define JIT_INVOKE_WORKS
-#ifdef JIT_INVOKE_WORKS
-       mono_install_runtime_invoke (mono_jit_runtime_invoke);
 #endif
        mono_install_get_cached_class_info (mono_aot_get_cached_class_info);
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
@@ -3665,7 +3722,6 @@ register_icalls (void)
        register_icall (mono_thread_get_undeniable_exception, "mono_thread_get_undeniable_exception", "object", 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);
-       register_icall (mono_thread_force_interruption_checkpoint, "mono_thread_force_interruption_checkpoint", "void", FALSE);
 #ifndef DISABLE_REMOTING
        register_icall (mono_load_remote_field_new, "mono_load_remote_field_new", "object object ptr ptr", FALSE);
        register_icall (mono_store_remote_field_new, "mono_store_remote_field_new", "void object ptr ptr object", FALSE);
@@ -3816,9 +3872,9 @@ register_icalls (void)
        register_icall (mono_ldstr, "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 (mono_object_new, "mono_object_new", "object ptr ptr", FALSE);
-       register_icall (mono_object_new_specific, "mono_object_new_specific", "object ptr", FALSE);
+       register_icall (ves_icall_object_new_specific, "ves_icall_object_new_specific", "object ptr", FALSE);
        register_icall (mono_array_new, "mono_array_new", "object ptr ptr int32", FALSE);
-       register_icall (mono_array_new_specific, "mono_array_new_specific", "object ptr int32", FALSE);
+       register_icall (ves_icall_array_new_specific, "ves_icall_array_new_specific", "object ptr int32", FALSE);
        register_icall (mono_runtime_class_init, "mono_runtime_class_init", "void ptr", FALSE);
        register_icall (mono_ldftn, "mono_ldftn", "ptr ptr", FALSE);
        register_icall (mono_ldvirtfn, "mono_ldvirtfn", "ptr object ptr", FALSE);
@@ -3854,17 +3910,21 @@ register_icalls (void)
 
        register_icall (mono_aot_init_llvm_method, "mono_aot_init_llvm_method", "void ptr int", TRUE);
        register_icall (mono_aot_init_gshared_method_this, "mono_aot_init_gshared_method_this", "void ptr int object", TRUE);
-       register_icall (mono_aot_init_gshared_method_rgctx, "mono_aot_init_gshared_method_rgctx", "void ptr int ptr", TRUE);
+       register_icall (mono_aot_init_gshared_method_mrgctx, "mono_aot_init_gshared_method_mrgctx", "void ptr int ptr", TRUE);
+       register_icall (mono_aot_init_gshared_method_vtable, "mono_aot_init_gshared_method_vtable", "void ptr int ptr", TRUE);
 
        register_icall_no_wrapper (mono_resolve_iface_call_gsharedvt, "mono_resolve_iface_call_gsharedvt", "ptr object int ptr ptr");
        register_icall_no_wrapper (mono_resolve_vcall_gsharedvt, "mono_resolve_vcall_gsharedvt", "ptr object int ptr ptr");
        register_icall_no_wrapper (mono_resolve_generic_virtual_call, "mono_resolve_generic_virtual_call", "ptr ptr int ptr");
        register_icall_no_wrapper (mono_resolve_generic_virtual_iface_call, "mono_resolve_generic_virtual_iface_call", "ptr ptr int ptr");
+       register_icall_no_wrapper (mono_llvmonly_set_calling_assembly, "mono_llvmonly_set_calling_assembly", "void ptr");
+       register_icall_no_wrapper (mono_llvmonly_get_calling_assembly, "mono_llvmonly_get_calling_assembly", "object");
        /* This needs a wrapper so it can have a preserveall cconv */
        register_icall (mono_init_vtable_slot, "mono_init_vtable_slot", "ptr ptr int", FALSE);
-       register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
-       register_icall (mono_init_delegate_virtual, "mono_init_delegate_virtual", "void object object ptr", TRUE);
+       register_icall (mono_llvmonly_init_delegate, "mono_llvmonly_init_delegate", "void object", TRUE);
+       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);
 
 #ifdef TARGET_IOS
        register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);
@@ -4064,7 +4124,13 @@ mono_precompile_assembly (MonoAssembly *ass, void *user_data)
                printf ("PRECOMPILE: %s.\n", mono_image_get_filename (image));
 
        for (i = 0; i < mono_image_get_table_rows (image, MONO_TABLE_METHOD); ++i) {
-               method = mono_get_method (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL);
+               MonoError error;
+
+               method = mono_get_method_checked (image, MONO_TOKEN_METHOD_DEF | (i + 1), NULL, NULL, &error);
+               if (!method) {
+                       mono_error_cleanup (&error); /* FIXME don't swallow the error */
+                       continue;
+               }
                if (method->flags & METHOD_ATTRIBUTE_ABSTRACT)
                        continue;
                if (method->is_generic || method->klass->generic_container)