Revert "Revert "Merge branch 'master' of https://github.com/mono/mono""
[mono.git] / mono / mini / mini-trampolines.c
index 2f0cda53743765a9ba13ce8bb248b664a478de8b..537a0bbfdcc22a7e95e355bedd894054188cfb8c 100644 (file)
@@ -673,7 +673,7 @@ common_call_trampoline (mgreg_t *regs, guint8 *code, MonoMethod *m, guint8* tram
                                }
                        }
                        if (!no_patch)
-                               mono_aot_patch_plt_entry (plt_entry, NULL, regs, addr);
+                               mono_aot_patch_plt_entry (code, plt_entry, NULL, regs, addr);
                } else {
                        if (generic_shared) {
                                if (m->wrapper_type != MONO_WRAPPER_NONE)
@@ -869,7 +869,7 @@ mono_aot_trampoline (mgreg_t *regs, guint8 *code, guint8 *token_info,
        plt_entry = mono_aot_get_plt_entry (code);
        g_assert (plt_entry);
 
-       mono_aot_patch_plt_entry (plt_entry, NULL, regs, addr);
+       mono_aot_patch_plt_entry (code, plt_entry, NULL, regs, addr);
 
        return addr;
 }
@@ -917,7 +917,7 @@ mono_class_init_trampoline (mgreg_t *regs, guint8 *code, MonoVTable *vtable, gui
 
        if (vtable->initialized) {
                if (plt_entry)
-                       mono_arch_nullify_plt_entry (plt_entry, regs);
+                       mono_aot_patch_plt_entry (code, plt_entry, NULL, regs, mini_get_nullified_class_init_trampoline ());
                else
                        mono_arch_nullify_class_init_trampoline (code, regs);
        }
@@ -986,6 +986,7 @@ typedef struct {
        gpointer impl_this;
        gpointer impl_nothis;
        MonoMethod *method;
+       MonoMethodSignature *invoke_sig;
        MonoMethodSignature *sig;
        gboolean need_rgctx_tramp;
 } DelegateTrampInfo;
@@ -1007,6 +1008,7 @@ create_delegate_trampoline_data (MonoDomain *domain, MonoClass *klass, MonoMetho
 
        tramp_data = mono_domain_alloc (domain, sizeof (DelegateTrampInfo));
        tramp_data->invoke = invoke;
+       tramp_data->invoke_sig = mono_method_signature (invoke);
        tramp_data->impl_this = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), TRUE);
        tramp_data->impl_nothis = mono_arch_get_delegate_invoke_impl (mono_method_signature (invoke), FALSE);
        tramp_data->method = method;
@@ -1033,7 +1035,7 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
        MonoJitInfo *ji;
        MonoMethod *m;
        MonoMethod *method = NULL;
-       gboolean multicast, callvirt = FALSE;
+       gboolean multicast, callvirt = FALSE, closed_over_null = FALSE;
        gboolean need_rgctx_tramp = FALSE;
        gboolean need_unbox_tramp = FALSE;
        gboolean enable_caching = TRUE;
@@ -1101,6 +1103,25 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                }
 
                callvirt = !delegate->target && sig->hasthis;
+               if (callvirt)
+                       closed_over_null = tramp_info->invoke_sig->param_count == sig->param_count;
+
+               if (callvirt && !closed_over_null) {
+                       /*
+                        * The delegate needs to make a virtual call to the target method using its
+                        * first argument as the receiver. This is hard to support in full-aot, so
+                        * optimize it in some cases if possible.
+                        * If the target method is not virtual or is in a sealed class,
+                        * the vcall will call it directly.
+                        * If the call doesn't return a valuetype, then the vcall uses the same calling
+                        * convention as a normal call.
+                        */
+                       if (((method->klass->flags & TYPE_ATTRIBUTE_SEALED) || !(method->flags & METHOD_ATTRIBUTE_VIRTUAL)) && !MONO_TYPE_ISSTRUCT (sig->ret)) {
+                               callvirt = FALSE;
+                               enable_caching = FALSE;
+                       }
+               }
+
                if (delegate->target && 
                        method->flags & METHOD_ATTRIBUTE_VIRTUAL && 
                        method->flags & METHOD_ATTRIBUTE_ABSTRACT &&