[delegate-trampoline] Update invoke_impl and method_ptr cache value
authorLudovic Henry <ludovic.henry@xamarin.com>
Mon, 7 Jul 2014 17:35:34 +0000 (13:35 -0400)
committerLudovic Henry <ludovic.henry@xamarin.com>
Wed, 9 Jul 2014 18:56:02 +0000 (14:56 -0400)
With this patch, we see a 3x execution speed improvement in the following micro-benchmark :

using System;

class Foo {
public int Test () { return 10; }
}

class Program {
public static int Main (String[] args) {
long n = 50000000;
if (args.Length > 0)
n = Math.Max (n, Int64.Parse (args [0]));

var a = new Foo ();

for (long i = 0; i < n; i++) {
var f = new Func<int> (a.Test);
if (f () != 10)
return 1;
}
return 0;
}
}

mono/metadata/object-offsets.h
mono/mini/method-to-ir.c
mono/mini/mini-trampolines.c
mono/mini/mini.c

index fb39056d8756cf3e06a1b0937b891abf60ca1da4..6f71525d39c00f8e4f1ac7472d5da4ccff6f6067 100644 (file)
@@ -219,6 +219,9 @@ DECL_OFFSET(MonoLMFTramp, regs)
 DECL_OFFSET(MonoLMFTramp, lmf_addr)
 
 #endif
+       
+DECL_OFFSET(MonoDelegateTrampInfo, invoke_impl)
+DECL_OFFSET(MonoDelegateTrampInfo, method_ptr)
 
 #endif
 
index 9e7d8282655dd057a5ba6e53c31566a752b7848f..62e7cca239973da805e2f4ca4f0cd6637e19bcde 100644 (file)
@@ -4501,7 +4501,7 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
 {
        MonoInst *ptr;
        int dreg;
-       gpointer *trampoline;
+       MonoDelegateTrampInfo *trampoline;
        MonoInst *obj, *method_ins, *tramp_ins;
        MonoDomain *domain;
        guint8 **code_slot;
@@ -4565,10 +4565,17 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
                del_tramp->method = context_used ? NULL : method;
                EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
        } else {
-               trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method)->invoke_impl;
+               trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
                EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
        }
-       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
+
+       dreg = alloc_preg (cfg);
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
+
+       dreg = alloc_preg (cfg);
+       MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
 
        /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
 
index f225d3d2119d856ed5051ac715ae268313f6e7b1..99c050e0e73b7b39df638ebc1a7ba1b1899074a7 100644 (file)
@@ -1151,6 +1151,9 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                        delegate->method_ptr = mono_create_static_rgctx_trampoline (method, delegate->method_ptr);
        }
 
+       /* Necessary for !code condition to fallback to slow path */
+       code = NULL;
+
        multicast = ((MonoMulticastDelegate*)delegate)->prev != NULL;
        if (!multicast && !callvirt) {
                if (method && (method->flags & METHOD_ATTRIBUTE_STATIC) && mono_method_signature (method)->param_count == mono_method_signature (invoke)->param_count + 1)
@@ -1158,18 +1161,20 @@ mono_delegate_trampoline (mgreg_t *regs, guint8 *code, gpointer *arg, guint8* tr
                        code = impl_this;
                else
                        code = delegate->target ? impl_this : impl_nothis;
+       }
 
-               if (code) {
-                       delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
-                       return code;
-               }
+       if (!code) {
+               /* The general, unoptimized case */
+               m = mono_marshal_get_delegate_invoke (invoke, delegate);
+               code = mono_compile_method (m);
+               code = mini_add_method_trampoline (NULL, m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
        }
 
-       /* The general, unoptimized case */
-       m = mono_marshal_get_delegate_invoke (invoke, delegate);
-       code = mono_compile_method (m);
-       code = mini_add_method_trampoline (NULL, m, code, mono_method_needs_static_rgctx_invoke (m, FALSE), FALSE);
        delegate->invoke_impl = mono_get_addr_from_ftnptr (code);
+       if (enable_caching && !callvirt && tramp_info->method) {
+               tramp_info->method_ptr = delegate->method_ptr;
+               tramp_info->invoke_impl = delegate->invoke_impl;
+       }
 
        return code;
 }
index dca40c000de8f2cfedc9fa4f70bf826493d278e8..2052b1c6801e9f066711bcc083144d7d8ee5ac68 100644 (file)
@@ -3469,7 +3469,7 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        case MONO_PATCH_INFO_DELEGATE_TRAMPOLINE: {
                MonoClassMethodPair *del_tramp = patch_info->data.del_tramp;
 
-               target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method)->invoke_impl;
+               target = mono_create_delegate_trampoline_info (domain, del_tramp->klass, del_tramp->method);
                break;
        }
        case MONO_PATCH_INFO_SFLDA: {