[cominterop] Get function ptr from interface before switching to blocking
authorAleksey Kliger <aleksey@xamarin.com>
Tue, 29 Aug 2017 23:02:24 +0000 (19:02 -0400)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Thu, 31 Aug 2017 14:42:19 +0000 (10:42 -0400)
The cominterop_get_function_pointer icall has a wrapper which has a
trampoline.  When we enter the trampoline mono_marshal_emit_native_wrapper
already switched us to blocking.

mono/metadata/cominterop.c
mono/metadata/cominterop.h
mono/metadata/marshal.c

index d57cb52796be252c94d86cffbbc96db8bab7167c..b00ab355d6ecd3c9736d316c0ba167fb3890a521 100644 (file)
@@ -640,14 +640,21 @@ mono_cominterop_cleanup (void)
 }
 
 void
-mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
+mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod *method)
 {
 #ifndef DISABLE_JIT
        // get function pointer from 1st arg, the COM interface pointer
        mono_mb_emit_ldarg (mb, 0);
        mono_mb_emit_icon (mb, cominterop_get_com_slot_for_method (method));
        mono_mb_emit_icall (mb, cominterop_get_function_pointer);
+       /* Leaves the function pointer on top of the stack */
+#endif
+}
 
+void
+mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig)
+{
+#ifndef DISABLE_JIT
        mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX);
        mono_mb_emit_byte (mb, CEE_MONO_SAVE_LMF);
        mono_mb_emit_calli (mb, sig);
@@ -656,6 +663,16 @@ mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, M
 #endif /* DISABLE_JIT */
 }
 
+void
+mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method)
+{
+#ifndef DISABLE_JIT
+       mono_mb_emit_cominterop_get_function_pointer (mb, method);
+
+       mono_mb_emit_cominterop_call_function_pointer (mb, sig);
+#endif /* DISABLE_JIT */
+}
+
 void
 mono_cominterop_emit_ptr_to_object_conv (MonoMethodBuilder *mb, MonoType *type, MonoMarshalConv conv, MonoMarshalSpec *mspec)
 {
index 04abc6e5fab1015ee3698302894f9f4abd5ac1b1..6f93ec191dfb1dc16b9b4c6d03a815fa5a01ad1c 100644 (file)
@@ -19,6 +19,12 @@ mono_cominterop_init (void);
 void
 mono_cominterop_cleanup (void);
 
+void
+mono_mb_emit_cominterop_get_function_pointer (MonoMethodBuilder *mb, MonoMethod* method);
+
+void
+mono_mb_emit_cominterop_call_function_pointer (MonoMethodBuilder *mb, MonoMethodSignature *sig);
+
 void
 mono_mb_emit_cominterop_call (MonoMethodBuilder *mb, MonoMethodSignature *sig, MonoMethod* method);
 
index 069964cff6c934740c87b7beb3bd50a55aed7bc0..05b23fddf3feae116697913694a6033b94c022df 100644 (file)
@@ -7658,6 +7658,9 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
        int i, argnum, *tmp_locals;
        int type, param_shift = 0;
        int coop_gc_stack_dummy, coop_gc_var;
+#ifndef DISABLE_COM
+       int coop_cominterop_fnptr;
+#endif
 
        memset (&m, 0, sizeof (m));
        m.mb = mb;
@@ -7700,6 +7703,11 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                coop_gc_stack_dummy = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
                /* local 5, the local to be used when calling the suspend funcs */
                coop_gc_var = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+#ifndef DISABLE_COM
+               if (!func_param && MONO_CLASS_IS_IMPORT (mb->method->klass)) {
+                       coop_cominterop_fnptr = mono_mb_add_local (mb, &mono_defaults.int_class->byval_arg);
+               }
+#endif
        }
 
        /*
@@ -7745,6 +7753,13 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                        mono_mb_emit_byte (mb, CEE_POP); // Result not needed yet
                }
 
+#ifndef DISABLE_COM
+               if (!func_param && MONO_CLASS_IS_IMPORT (mb->method->klass)) {
+                       mono_mb_emit_cominterop_get_function_pointer (mb, &piinfo->method);
+                       mono_mb_emit_stloc (mb, coop_cominterop_fnptr);
+               }
+#endif
+
                mono_mb_emit_ldloc_addr (mb, coop_gc_stack_dummy);
                mono_mb_emit_icall (mb, mono_threads_enter_gc_safe_region_unbalanced);
                mono_mb_emit_stloc (mb, coop_gc_var);
@@ -7767,7 +7782,12 @@ mono_marshal_emit_native_wrapper (MonoImage *image, MonoMethodBuilder *mb, MonoM
                mono_mb_emit_calli (mb, csig);
        } else if (MONO_CLASS_IS_IMPORT (mb->method->klass)) {
 #ifndef DISABLE_COM
-               mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
+               if (!mono_threads_is_blocking_transition_enabled ()) {
+                       mono_mb_emit_cominterop_call (mb, csig, &piinfo->method);
+               } else {
+                       mono_mb_emit_ldloc (mb, coop_cominterop_fnptr);
+                       mono_mb_emit_cominterop_call_function_pointer (mb, csig);
+               }
 #else
                g_assert_not_reached ();
 #endif