Add support for delegates which call methods which require an rgctx argument.
authorZoltan Varga <vargaz@gmail.com>
Fri, 17 Jul 2015 02:15:44 +0000 (22:15 -0400)
committerZoltan Varga <vargaz@gmail.com>
Fri, 9 Oct 2015 02:41:33 +0000 (22:41 -0400)
mono/metadata/marshal.c
mono/mini/aot-compiler.c
mono/mini/jit-icalls.c
mono/mini/jit-icalls.h
mono/mini/method-to-ir.c
mono/mini/mini-generic-sharing.c
mono/mini/mini-llvm.c
mono/mini/mini-runtime.c

index 2157bc7b5668013e1088d468dfe9d5eff4af0ba3..f8d0f8def7489eb480e27c51c4585a8931cfafb3 100644 (file)
@@ -3008,6 +3008,22 @@ free_signature_pointer_pair (SignaturePointerPair *pair)
        g_free (pair);
 }
 
+static MonoMethodSignature*
+sig_to_rgctx_sig (MonoMethodSignature *sig)
+{
+       // FIXME: memory allocation
+       MonoMethodSignature *res;
+       int i;
+
+       res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
+       memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
+       res->param_count = sig->param_count + 1;
+       res->params [0] = &mono_defaults.int_class->byval_arg;
+       for (i = 0; i < sig->param_count; ++i)
+               res->params [i + 1] = sig->params [i];
+       return res;
+}
+
 MonoMethod *
 mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt, gboolean static_method_with_first_arg_bound, MonoMethod *target_method)
 {
@@ -3020,7 +3036,7 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
        SignaturePointerPair key;
        SignaturePointerPair *new_key;
        int local_i, local_len, local_delegates, local_d, local_target, local_res;
-       int pos0, pos1, pos2;
+       int pos0, pos1, pos2, pos3, pos4;
        char *name;
        MonoClass *target_class = NULL;
        gboolean closed_over_null = FALSE;
@@ -3208,6 +3224,31 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                        // FIXME:
                        mono_mb_emit_exception_full (mb, "System", "NotImplementedException", "");
                } else {
+                       MonoMethodSignature *rgctx_sig;
+
+                       // FIXME: Support this for the other cases as well
+                       mono_mb_emit_ldarg (mb, 0);
+                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
+                       mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+                       /* Rgctx case */
+                       rgctx_sig = sig_to_rgctx_sig (sig);
+
+                       mono_mb_emit_ldloc (mb, local_target);
+                       mono_mb_emit_ldarg (mb, 0);
+                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
+                       mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       for (i = 0; i < sig->param_count; ++i)
+                               mono_mb_emit_ldarg (mb, i + 1);
+                       mono_mb_emit_ldarg (mb, 0);
+                       mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+                       mono_mb_emit_byte (mb, CEE_LDIND_I);
+                       mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
+                       pos4 = mono_mb_emit_branch (mb, CEE_BR);
+
+                       /* Non-rgctx case */
+                       mono_mb_patch_branch (mb, pos3);
                        mono_mb_emit_ldloc (mb, local_target);
                        for (i = 0; i < sig->param_count; ++i)
                                mono_mb_emit_ldarg (mb, i + 1);
@@ -3216,6 +3257,8 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                        mono_mb_emit_byte (mb, CEE_LDIND_I );
                        mono_mb_emit_op (mb, CEE_CALLI, sig);
 
+                       mono_mb_patch_branch (mb, pos4);
+
                        mono_mb_emit_byte (mb, CEE_RET);
                }
        
@@ -3244,6 +3287,19 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                        mono_mb_emit_op (mb, CEE_CALL, target_method);
                }
        } else {
+               MonoMethodSignature *rgctx_sig;
+
+               mono_mb_emit_ldarg (mb, 0);
+               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               pos3 = mono_mb_emit_branch (mb, CEE_BRFALSE);
+
+               /* Rgctx case */
+               rgctx_sig = sig_to_rgctx_sig (invoke_sig);
+
+               mono_mb_emit_ldarg (mb, 0);
+               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, rgctx));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
                if (static_method_with_first_arg_bound) {
                        mono_mb_emit_ldloc (mb, local_target);
                        if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
@@ -3253,8 +3309,25 @@ mono_marshal_get_delegate_invoke_internal (MonoMethod *method, gboolean callvirt
                        mono_mb_emit_ldarg (mb, i + 1);
                mono_mb_emit_ldarg (mb, 0);
                mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
-               mono_mb_emit_byte (mb, CEE_LDIND_I );
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
+               mono_mb_emit_op (mb, CEE_CALLI, rgctx_sig);
+               pos4 = mono_mb_emit_branch (mb, CEE_BR);
+
+               /* Non-rgctx case */
+               mono_mb_patch_branch (mb, pos3);
+               if (static_method_with_first_arg_bound) {
+                       mono_mb_emit_ldloc (mb, local_target);
+                       if (!MONO_TYPE_IS_REFERENCE (invoke_sig->params[0]))
+                               mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type (invoke_sig->params[0]));
+               }
+               for (i = 0; i < sig->param_count; ++i)
+                       mono_mb_emit_ldarg (mb, i + 1);
+               mono_mb_emit_ldarg (mb, 0);
+               mono_mb_emit_ldflda (mb, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr));
+               mono_mb_emit_byte (mb, CEE_LDIND_I);
                mono_mb_emit_op (mb, CEE_CALLI, invoke_sig);
+
+               mono_mb_patch_branch (mb, pos4);
        }
 
        mono_mb_emit_byte (mb, CEE_RET);
@@ -3787,22 +3860,6 @@ emit_runtime_invoke_body (MonoMethodBuilder *mb, MonoClass *target_klass, MonoMe
 }
 #endif
 
-static MonoMethodSignature*
-sig_to_rgctx_sig (MonoMethodSignature *sig)
-{
-       // FIXME: memory allocation
-       MonoMethodSignature *res;
-       int i;
-
-       res = g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
-       memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
-       res->param_count = sig->param_count + 1;
-       res->params [0] = &mono_defaults.int_class->byval_arg;
-       for (i = 0; i < sig->param_count; ++i)
-               res->params [i + 1] = sig->params [i];
-       return res;
-}
-
 /*
  * generates IL code for the runtime invoke function 
  * MonoObject *runtime_invoke (MonoObject *this, void **params, MonoObject **exc, void* method)
index cd34fb0c4e1ac3c12e0a2a42f48d3430654168ae..14d1a48bf03a7dc682c3f7dd774b0ce3592b618e 100644 (file)
@@ -7407,7 +7407,7 @@ emit_llvm_file (MonoAotCompile *acfg)
        g_free (tempbc);
 
 #ifdef TARGET_MACH
-       if (acfg->aot_opts.llvm_only) {
+       if (FALSE && acfg->aot_opts.llvm_only) {
                /* Use the stock clang from xcode */
                // FIXME: arch
                // FIXME: -O2
index 9cec1a2d4a5df78d03eae4356406fdf8aa7ee953..3bdd9dbbf47368c85accfb7a0cf447bc7c020699 100644 (file)
@@ -29,6 +29,10 @@ mono_ldftn (MonoMethod *method)
                addr = mono_compile_method (method);
                g_assert (addr);
 
+               if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+                       /* The caller doesn't pass it */
+                       g_assert_not_reached ();
+
                addr = mini_add_method_trampoline (method, addr, mono_method_needs_static_rgctx_invoke (method, FALSE), FALSE);
                return addr;
        }
@@ -1477,3 +1481,19 @@ mono_resolve_vcall (MonoObject *this, int slot, MonoMethod *imt_method)
 
        return addr;
 }
+
+/*
+ * mono_init_delegate:
+ *
+ *   Initialize a MonoDelegate object.
+ * Similar to mono_delegate_ctor ().
+ */
+void
+mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method)
+{
+       MONO_OBJECT_SETREF (del, target, target);
+       del->method = method;
+       del->method_ptr = mono_compile_method (method);
+       if (mono_method_needs_static_rgctx_invoke (method, FALSE))
+               del->rgctx = mini_method_get_rgctx (method);
+}
index 509b481018a2be5bd51cc8899defbecf99eedcac..317b114158b4264b95208a61009fd71574e89e99 100644 (file)
@@ -199,5 +199,7 @@ gpointer mono_resolve_iface_call (MonoObject *this, int imt_slot, MonoMethod *im
 
 gpointer mono_resolve_vcall (MonoObject *this, int slot, MonoMethod *imt_method);
 
+void mono_init_delegate (MonoDelegate *del, MonoObject *target, MonoMethod *method);
+
 #endif /* __MONO_JIT_ICALLS_H__ */
 
index 17182f8fc4095cc541ca867475d53e05806362b1..f3499c10139b14c5e309e601d5d68388304c40b2 100644 (file)
@@ -4980,10 +4980,6 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        MonoDomain *domain;
        guint8 **code_slot;
 
-       if (cfg->llvm_only)
-               /* FIXME: Optimize this */
-               return NULL;
-
        if (virtual) {
                MonoMethod *invoke = mono_get_delegate_invoke (klass);
                g_assert (invoke);
@@ -4996,6 +4992,22 @@ handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, Mono
        if (!obj)
                return NULL;
 
+       if (cfg->llvm_only) {
+               MonoInst *args [16];
+
+               /*
+                * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
+                * the address of a gshared method. So use a JIT icall.
+                * FIXME: Optimize this.
+                */
+               args [0] = obj;
+               args [1] = target;
+               args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
+               mono_emit_jit_icall (cfg, mono_init_delegate, args);
+
+               return obj;
+       }
+
        /* Inline the contents of mono_delegate_ctor */
 
        /* Set target field */
index ada106c61ad763a9ce425c1272dcb4e1096da0d5..420b9aac36eb669795755da219ed5c6445576e44 100644 (file)
@@ -2300,6 +2300,13 @@ mono_method_is_generic_sharable (MonoMethod *method, gboolean allow_type_vars)
        return mono_method_is_generic_sharable_full (method, allow_type_vars, partial_sharing_supported (), TRUE);
 }
 
+/*
+ * mono_method_needs_static_rgctx_invoke:
+ *
+ *   Return whenever METHOD needs an rgctx argument.
+ * An rgctx argument is needed when the method is generic sharable, but it doesn't
+ * have a this argument which can be used to load the rgctx.
+ */
 gboolean
 mono_method_needs_static_rgctx_invoke (MonoMethod *method, gboolean allow_type_vars)
 {
index 9a5f7207843082c7179d5f79cc972296bcdd2230..f47b7c958f0857c0dbe72703a24c054749ce588e 100644 (file)
@@ -6591,7 +6591,7 @@ emit_aot_file_info (MonoLLVMModule *lmodule)
        fields [tindex ++] = AddJitGlobal (lmodule, eltype, "jit_got");
        fields [tindex ++] = lmodule->got_var;
        /* llc defines this directly */
-       if (!lmodule->llvm_only)
+       if (TRUE) //(!lmodule->llvm_only)
                fields [tindex ++] = LLVMAddGlobal (lmodule->module, eltype, lmodule->eh_frame_symbol);
        else
                fields [tindex ++] = LLVMConstNull (eltype);
index df863328edea32327531d4997dd42101a35b4496..45cf5933afc7b5026c82f7579e71e096c272e0c7 100644 (file)
@@ -3447,6 +3447,7 @@ register_icalls (void)
 
        register_icall_no_wrapper (mono_resolve_iface_call, "mono_resolve_iface_call", "ptr object int ptr ptr");
        register_icall_no_wrapper (mono_resolve_vcall, "mono_resolve_vcall", "ptr object int ptr");
+       register_icall (mono_init_delegate, "mono_init_delegate", "void object object ptr", TRUE);
 
 #ifdef TARGET_IOS
        register_icall (pthread_getspecific, "pthread_getspecific", "ptr ptr", TRUE);