Don't block specific generic types in field marshalling scenar… (#31679)
authorJeremy Koritzinsky <jekoritz@microsoft.com>
Wed, 5 Feb 2020 00:10:30 +0000 (16:10 -0800)
committerGitHub <noreply@github.com>
Wed, 5 Feb 2020 00:10:30 +0000 (16:10 -0800)
Don't block specific generic types in field marshalling scenarios.

src/coreclr/src/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs
src/coreclr/src/tools/Common/TypeSystem/Interop/InteropTypes.cs
src/coreclr/src/vm/mlinfo.cpp
src/libraries/System.Runtime.InteropServices/tests/System/Runtime/InteropServices/Marshal/SizeOfTests.cs

index 3febee8..8635957 100644 (file)
@@ -340,10 +340,13 @@ namespace Internal.TypeSystem.Interop
                 // * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
                 // * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
                 // * Vector256<T>: Represents the __m256 ABI primitive which requires currently unimplemented handling
-                // * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios
+                // * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for interop scenarios
+                // We can't block these types for field scenarios for back-compat reasons.
 
-                if (type.HasInstantiation && (!isBlittable
+                if (type.HasInstantiation && !isField && (!isBlittable
                     || InteropTypes.IsSystemByReference(context, type)
+                    || InteropTypes.IsSystemSpan(context, type)
+                    || InteropTypes.IsSystemReadOnlySpan(context, type)
                     || InteropTypes.IsSystemNullable(context, type)
                     || InteropTypes.IsSystemRuntimeIntrinsicsVector64T(context, type)
                     || InteropTypes.IsSystemRuntimeIntrinsicsVector128T(context, type)
index 8c15035..2530f1b 100644 (file)
@@ -113,6 +113,16 @@ namespace Internal.TypeSystem.Interop
             return IsCoreNamedType(context, type, "System", "ByReference`1");
         }
 
+        public static bool IsSystemSpan(TypeSystemContext context, TypeDesc type)
+        {
+            return IsCoreNamedType(context, type, "System", "Span`1");
+        }
+
+        public static bool IsSystemReadOnlySpan(TypeSystemContext context, TypeDesc type)
+        {
+            return IsCoreNamedType(context, type, "System", "ReadOnlySpan`1");
+        }
+
         public static bool IsSystemNullable(TypeSystemContext context, TypeDesc type)
         {
             return IsCoreNamedType(context, type, "System", "Nullable`1");
index cb4b7f3..a50b2e3 100644 (file)
@@ -2784,19 +2784,22 @@ MarshalInfo::MarshalInfo(Module* pModule,
                 // * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
                 // * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
                 // * Vector256<T>: Represents the __m256 ABI primitive which requires currently unimplemented handling
-                // * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios
-
-                if (m_pMT->HasInstantiation() && (!m_pMT->IsBlittable()
-                    || m_pMT->HasSameTypeDefAs(g_pByReferenceClass)
-                    || m_pMT->HasSameTypeDefAs(g_pNullableClass)
-                    || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR64T))
-                    || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR128T))
-                    || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR256T))
+                // * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for interop scenarios
+                // We can't block these types for field scenarios for back-compat reasons.
+                if (m_pMT->HasInstantiation() && !IsFieldScenario()
+                    && (!m_pMT->IsBlittable()
+                        || (m_pMT->HasSameTypeDefAs(g_pNullableClass)
+                        || m_pMT->HasSameTypeDefAs(g_pByReferenceClass)
+                        || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__SPAN))
+                        || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__READONLY_SPAN))
+                        || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR64T))
+                        || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR128T))
+                        || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR256T))
 #ifndef CROSSGEN_COMPILE
-                    // Crossgen scenarios block Vector<T> from even being loaded
-                    || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTORT))
+                            // Crossgen scenarios block Vector<T> from even being loaded
+                            || m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTORT))
 #endif // !CROSSGEN_COMPILE
-                    ))
+                    )))
                 {
                     m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
                     IfFailGoto(E_FAIL, lFail);
index d5555d3..576e6db 100644 (file)
@@ -52,6 +52,14 @@ namespace System.Runtime.InteropServices.Tests
             AssertExtensions.Throws<ArgumentNullException>("structure", () => Marshal.SizeOf<string>(null));
         }
 
+        [Fact]
+        public void SizeOf_Struct_With_GenericValueTypeField_ReturnsExpected()
+        {
+            Assert.Equal(8, Marshal.SizeOf<TestStructWithGenericStructField>());
+            Assert.Equal(8, Marshal.SizeOf<TestStructWithNullable>());
+            Assert.Equal(8, Marshal.SizeOf<TestStructWithVector64>());
+        }
+
         public static IEnumerable<object[]> SizeOf_InvalidType_TestData()
         {
             yield return new object[] { typeof(int).MakeByRefType(), null };
@@ -106,5 +114,26 @@ namespace System.Runtime.InteropServices.Tests
             [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPStr, SizeConst = 0)]
             public string[] Arr;
         }
+
+        public struct GenericStruct<T>
+        {
+            public T t;
+            public bool b;
+        }
+
+        public struct TestStructWithGenericStructField
+        {
+            public GenericStruct<int> i;
+        }
+
+        public struct TestStructWithNullable
+        {
+            public int? i;
+        }
+
+        public struct TestStructWithVector64
+        {
+            public System.Runtime.Intrinsics.Vector64<double> v;
+        }
     }
 }