From 08521a1c43780a711113ef42043f664f256e8978 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 16 Sep 2019 20:42:43 +0300 Subject: [PATCH] [cominterop] Default to [in] parameter direction when not specified explicitly. Treat [In, Out], [In] and unspecified as input arguments. Important change from current behavior is to allow parameter without directional attributes. Use case example is _MethodInfo.Invoke() method called from native client. --- mono/metadata/cominterop.c | 174 ++++++++++++++++++++++----------------------- mono/tests/cominterop.cs | 16 +++++ mono/tests/libtest.c | 10 +++ 3 files changed, 113 insertions(+), 87 deletions(-) diff --git a/mono/metadata/cominterop.c b/mono/metadata/cominterop.c index e656c65edb6..804f675f731 100644 --- a/mono/metadata/cominterop.c +++ b/mono/metadata/cominterop.c @@ -3064,118 +3064,118 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT #ifndef DISABLE_JIT switch (action) { case MARSHAL_ACTION_CONV_IN: { - if (t->attrs & PARAM_ATTRIBUTE_IN) { + if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT) + break; - /* Generates IL code for the following algorithm: + /* Generates IL code for the following algorithm: - SafeArray safearray; // safearray_var - IntPtr indices; // indices_var - int empty; // empty_var - if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) { - if (!empty) { - int index=0; // index_var - do { // label3 - variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index)); - mono_marshal_safearray_set_value (safearray, indices, elem); - ++index; - } - while (mono_marshal_safearray_next (safearray, indices)); - } // label2 - mono_marshal_safearray_free_indices (indices); - } // label1 - */ + SafeArray safearray; // safearray_var + IntPtr indices; // indices_var + int empty; // empty_var + if (mono_marshal_safearray_create (array, out safearray, out indices, out empty)) { + if (!empty) { + int index=0; // index_var + do { // label3 + variant elem = Marshal.GetNativeVariantForObject (array.GetValueImpl(index)); + mono_marshal_safearray_set_value (safearray, indices, elem); + ++index; + } + while (mono_marshal_safearray_next (safearray, indices)); + } // label2 + mono_marshal_safearray_free_indices (indices); + } // label1 + */ - int safearray_var, indices_var, empty_var, elem_var, index_var; - guint32 label1 = 0, label2 = 0, label3 = 0; - static MonoMethod *get_native_variant_for_object = NULL; - static MonoMethod *get_value_impl = NULL; - static MonoMethod *variant_clear = NULL; + int safearray_var, indices_var, empty_var, elem_var, index_var; + guint32 label1 = 0, label2 = 0, label3 = 0; + static MonoMethod *get_native_variant_for_object = NULL; + static MonoMethod *get_value_impl = NULL; + static MonoMethod *variant_clear = NULL; - MonoType *int_type = mono_get_int_type (); - conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ()); - indices_var = mono_mb_add_local (mb, int_type); - empty_var = mono_mb_add_local (mb, int_type); + MonoType *int_type = mono_get_int_type (); + conv_arg = safearray_var = mono_mb_add_local (mb, mono_get_object_type ()); + indices_var = mono_mb_add_local (mb, int_type); + empty_var = mono_mb_add_local (mb, int_type); - if (t->byref) { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - } else - mono_mb_emit_ldarg (mb, argnum); + if (t->byref) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + } else + mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc_addr (mb, safearray_var); - mono_mb_emit_ldloc_addr (mb, indices_var); - mono_mb_emit_ldloc_addr (mb, empty_var); - mono_mb_emit_icall (mb, mono_marshal_safearray_create); + mono_mb_emit_ldloc_addr (mb, safearray_var); + mono_mb_emit_ldloc_addr (mb, indices_var); + mono_mb_emit_ldloc_addr (mb, empty_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_create); - label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + label1 = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); - mono_mb_emit_ldloc (mb, empty_var); + mono_mb_emit_ldloc (mb, empty_var); - label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); + label2 = mono_mb_emit_short_branch (mb, CEE_BRTRUE_S); - index_var = mono_mb_add_local (mb, mono_get_int32_type ()); - mono_mb_emit_byte (mb, CEE_LDC_I4_0); - mono_mb_emit_stloc (mb, index_var); + index_var = mono_mb_add_local (mb, mono_get_int32_type ()); + mono_mb_emit_byte (mb, CEE_LDC_I4_0); + mono_mb_emit_stloc (mb, index_var); - label3 = mono_mb_get_label (mb); + label3 = mono_mb_get_label (mb); - if (!get_value_impl) { - ERROR_DECL (error); - get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error); - mono_error_assert_ok (error); - } - g_assert (get_value_impl); + if (!get_value_impl) { + ERROR_DECL (error); + get_value_impl = mono_class_get_method_from_name_checked (mono_defaults.array_class, "GetValueImpl", 1, 0, error); + mono_error_assert_ok (error); + } + g_assert (get_value_impl); - if (t->byref) { - mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_byte (mb, CEE_LDIND_REF); - } else - mono_mb_emit_ldarg (mb, argnum); + if (t->byref) { + mono_mb_emit_ldarg (mb, argnum); + mono_mb_emit_byte (mb, CEE_LDIND_REF); + } else + mono_mb_emit_ldarg (mb, argnum); - mono_mb_emit_ldloc (mb, index_var); + mono_mb_emit_ldloc (mb, index_var); - mono_mb_emit_managed_call (mb, get_value_impl, NULL); + mono_mb_emit_managed_call (mb, get_value_impl, NULL); - if (!get_native_variant_for_object) { - ERROR_DECL (error); - get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error); - mono_error_assert_ok (error); - } - g_assert (get_native_variant_for_object); + if (!get_native_variant_for_object) { + ERROR_DECL (error); + get_native_variant_for_object = mono_class_get_method_from_name_checked (mono_defaults.marshal_class, "GetNativeVariantForObject", 2, 0, error); + mono_error_assert_ok (error); + } + g_assert (get_native_variant_for_object); - elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ())); - mono_mb_emit_ldloc_addr (mb, elem_var); + elem_var = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_get_variant_class ())); + mono_mb_emit_ldloc_addr (mb, elem_var); - mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); + mono_mb_emit_managed_call (mb, get_native_variant_for_object, NULL); - mono_mb_emit_ldloc (mb, safearray_var); - mono_mb_emit_ldloc (mb, indices_var); - mono_mb_emit_ldloc_addr (mb, elem_var); - mono_mb_emit_icall (mb, mono_marshal_safearray_set_value); + mono_mb_emit_ldloc (mb, safearray_var); + mono_mb_emit_ldloc (mb, indices_var); + mono_mb_emit_ldloc_addr (mb, elem_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_set_value); - if (!variant_clear) { - ERROR_DECL (error); - variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error); - mono_error_assert_ok (error); - } + if (!variant_clear) { + ERROR_DECL (error); + variant_clear = mono_class_get_method_from_name_checked (mono_class_get_variant_class (), "Clear", 0, 0, error); + mono_error_assert_ok (error); + } - mono_mb_emit_ldloc_addr (mb, elem_var); - mono_mb_emit_managed_call (mb, variant_clear, NULL); + mono_mb_emit_ldloc_addr (mb, elem_var); + mono_mb_emit_managed_call (mb, variant_clear, NULL); - mono_mb_emit_add_to_local (mb, index_var, 1); + mono_mb_emit_add_to_local (mb, index_var, 1); - mono_mb_emit_ldloc (mb, safearray_var); - mono_mb_emit_ldloc (mb, indices_var); - mono_mb_emit_icall (mb, mono_marshal_safearray_next); - mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3); + mono_mb_emit_ldloc (mb, safearray_var); + mono_mb_emit_ldloc (mb, indices_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_next); + mono_mb_emit_branch_label (mb, CEE_BRTRUE, label3); - mono_mb_patch_short_branch (mb, label2); + mono_mb_patch_short_branch (mb, label2); - mono_mb_emit_ldloc (mb, indices_var); - mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices); + mono_mb_emit_ldloc (mb, indices_var); + mono_mb_emit_icall (mb, mono_marshal_safearray_free_indices); - mono_mb_patch_short_branch (mb, label1); - } + mono_mb_patch_short_branch (mb, label1); break; } @@ -3309,7 +3309,7 @@ mono_cominterop_emit_marshal_safearray (EmitMarshalContext *m, int argnum, MonoT break; } case MARSHAL_ACTION_MANAGED_CONV_IN: { - if (!(t->attrs & PARAM_ATTRIBUTE_IN)) + if ((t->attrs & (PARAM_ATTRIBUTE_IN | PARAM_ATTRIBUTE_OUT)) == PARAM_ATTRIBUTE_OUT) break; /* Generates IL code for the following algorithm: diff --git a/mono/tests/cominterop.cs b/mono/tests/cominterop.cs index 89ae03b0183..604fe4fb3b4 100644 --- a/mono/tests/cominterop.cs +++ b/mono/tests/cominterop.cs @@ -882,6 +882,8 @@ public class Tests [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] void ArrayIn2 ([In] object[] array); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + void ArrayIn3 (object[] array); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] [return: MarshalAs (UnmanagedType.Interface)] TestDefaultInterfaceClass1 GetDefInterface1(); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] @@ -947,6 +949,8 @@ public class Tests int ArrayIn ([In, MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_VARIANT)] object[] array); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] int ArrayIn2 ([In] object[] array); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + int ArrayIn3 (object[] array); } [System.Runtime.InteropServices.GuidAttribute ("00000000-0000-0000-0000-000000000002")] @@ -995,6 +999,8 @@ public class Tests [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public virtual extern void ArrayIn2 ([In] object[] array); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + public virtual extern void ArrayIn3 (object[] array); + [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public virtual extern TestDefaultInterfaceClass1 GetDefInterface1(); [MethodImplAttribute (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] public virtual extern TestDefaultInterfaceClass2 GetDefInterface2(); @@ -1181,6 +1187,11 @@ public class Tests { return ArrayIn(array); } + + public int ArrayIn3(object[] array) + { + return ArrayIn(array); + } } public class ManagedTest : ITest @@ -1310,6 +1321,11 @@ public class Tests ArrayIn(array); } + public void ArrayIn3(object[] array) + { + ArrayIn(array); + } + public TestDefaultInterfaceClass1 GetDefInterface1() { return new TestDefaultInterfaceClass1(); diff --git a/mono/tests/libtest.c b/mono/tests/libtest.c index d5e9a9d895d..22b26314afe 100644 --- a/mono/tests/libtest.c +++ b/mono/tests/libtest.c @@ -3401,6 +3401,7 @@ typedef struct int (STDCALL *IntOut)(MonoComObject* pUnk, int *a); int (STDCALL *ArrayIn)(MonoComObject* pUnk, void *array); int (STDCALL *ArrayIn2)(MonoComObject* pUnk, void *array); + int (STDCALL *ArrayIn3)(MonoComObject* pUnk, void *array); int (STDCALL *GetDefInterface1)(MonoComObject* pUnk, MonoDefItfObject **iface); int (STDCALL *GetDefInterface2)(MonoComObject* pUnk, MonoDefItfObject **iface); } MonoIUnknown; @@ -3550,6 +3551,12 @@ ArrayIn2(MonoComObject* pUnk, void *array) } LIBTEST_API int STDCALL +ArrayIn3(MonoComObject* pUnk, void *array) +{ + return S_OK; +} + +LIBTEST_API int STDCALL GetDefInterface1(MonoComObject* pUnk, MonoDefItfObject **obj) { return S_OK; @@ -3596,6 +3603,7 @@ static void create_com_object (MonoComObject** pOut) (*pOut)->vtbl->IntOut = IntOut; (*pOut)->vtbl->ArrayIn = ArrayIn; (*pOut)->vtbl->ArrayIn2 = ArrayIn2; + (*pOut)->vtbl->ArrayIn3 = ArrayIn3; (*pOut)->vtbl->GetDefInterface1 = GetDefInterface1; (*pOut)->vtbl->GetDefInterface2 = GetDefInterface2; } @@ -5657,6 +5665,8 @@ mono_test_marshal_safearray_in_ccw(MonoComObject *pUnk) ret = pUnk->vtbl->ArrayIn (pUnk, (void *)array); if (!ret) ret = pUnk->vtbl->ArrayIn2 (pUnk, (void *)array); + if (!ret) + ret = pUnk->vtbl->ArrayIn3 (pUnk, (void *)array); SafeArrayDestroy(array); -- 2.11.4.GIT