Port IsBlittable fix and related changes from single-exe (dotnet/coreclr#27746)
authorJan Vorlicek <janvorli@microsoft.com>
Thu, 7 Nov 2019 22:46:38 +0000 (23:46 +0100)
committerGitHub <noreply@github.com>
Thu, 7 Nov 2019 22:46:38 +0000 (23:46 +0100)
* Port set of changes from single-exe branch

* Enable precompilation of marshalling IL stubs in crossgen2 dotnet/coreclr#26767
* P/invoke pregeneration fixes dotnet/coreclr#27389
* Fixes to array marshalling pregeneration dotnet/coreclr#27425
* Fix IsBlittableType dotnet/coreclr#27436

* Fix stack overflow issue and m_alignpad==0 assert

I've found that the changes from single-exe had issues - it was causing
stack overflow during compilation of a couple of runtime assemblies.
After I've fixed that, there was about 15 tests failing at runtime failing
with assert failure: m_alignpad == 0. This is a well known indication of a
problem where JIT and crossgen get different field offsets, resulting in
writing beyond the end of an object.
The problem was caused by incorrect usage of sequential layout for class
without LayoutSequential attribute.
I've added a commit with fix for those to this PR.

Commit migrated from https://github.com/dotnet/coreclr/commit/0e97c7389d70551ff4179b922b700d9ff41eded3

12 files changed:
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaField.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaSignatureParser.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Ecma/EcmaType.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/FieldDesc.Interop.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalHelpers.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalUtils.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/Marshaller.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InteropTypes.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MarshalAsDescriptor.cs
src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/MetadataType.Interop.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
src/coreclr/src/tools/crossgen2/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj

index fca4d9f9e6664e566796aa0ce3a8c1dc4c0554b4..ee492d03de3a8d79fcf0d41ea397f5569fab649a 100644 (file)
@@ -259,6 +259,20 @@ namespace Internal.TypeSystem.Ecma
             return !MetadataReader.GetCustomAttributeHandle(MetadataReader.GetFieldDefinition(_handle).GetCustomAttributes(),
                 attributeNamespace, attributeName).IsNil;
         }
+
+        public override MarshalAsDescriptor GetMarshalAsDescriptor()
+        {
+            MetadataReader reader = MetadataReader;
+            FieldDefinition definition = reader.GetFieldDefinition(_handle);
+            if ((definition.Attributes & FieldAttributes.HasFieldMarshal) != 0)
+            {
+                BlobReader marshalAsReader = reader.GetBlobReader(definition.GetMarshallingDescriptor());
+                EcmaSignatureParser parser = new EcmaSignatureParser(_type.EcmaModule, marshalAsReader);
+                return parser.ParseMarshalAsDescriptor();
+            }
+
+            return null;
+        }
     }
 
     public static class EcmaFieldExtensions
index aa691a2d371544424f9dbfce07a81ada5ce9f542..99272d61a841033598ad9581f0c1611aca07ee4d 100644 (file)
@@ -397,7 +397,7 @@ namespace Internal.TypeSystem.Ecma
             Debug.Assert(_reader.RemainingBytes != 0);
 
             NativeTypeKind type = (NativeTypeKind)_reader.ReadByte();
-            NativeTypeKind arraySubType = NativeTypeKind.Invalid;
+            NativeTypeKind arraySubType = NativeTypeKind.Default;
             uint? paramNum = null, numElem = null;
 
             switch (type)
index a0d06b48da15388ee4c21e3927fb3787706c64d9..24cf0c8a43f70c66eb5424541f3bca65fc783519 100644 (file)
@@ -539,40 +539,6 @@ namespace Internal.TypeSystem.Ecma
             return result;
         }
 
-        public override MarshalAsDescriptor[] GetFieldMarshalAsDescriptors()
-        {
-            var fieldDefinitionHandles = _typeDefinition.GetFields();
-
-            MarshalAsDescriptor[] marshalAsDescriptors = new MarshalAsDescriptor[fieldDefinitionHandles.Count];
-            int index = 0;
-            foreach (var handle in fieldDefinitionHandles)
-            {
-                var fieldDefinition = MetadataReader.GetFieldDefinition(handle);
-
-                if ((fieldDefinition.Attributes & FieldAttributes.Static) != 0)
-                    continue;
-
-                MarshalAsDescriptor marshalAsDescriptor = GetMarshalAsDescriptor(fieldDefinition);
-                marshalAsDescriptors[index++] = marshalAsDescriptor;
-            }
-
-            return marshalAsDescriptors;
-        }
-
-        private MarshalAsDescriptor GetMarshalAsDescriptor(FieldDefinition fieldDefinition)
-        {
-            if ((fieldDefinition.Attributes & FieldAttributes.HasFieldMarshal) == FieldAttributes.HasFieldMarshal)
-            {
-                MetadataReader metadataReader = MetadataReader;
-                BlobReader marshalAsReader = metadataReader.GetBlobReader(fieldDefinition.GetMarshallingDescriptor());
-                EcmaSignatureParser parser = new EcmaSignatureParser(EcmaModule, marshalAsReader);
-                MarshalAsDescriptor marshalAs =  parser.ParseMarshalAsDescriptor();
-                Debug.Assert(marshalAs != null);
-                return marshalAs;
-            }
-            return null;
-        }
-
         public override bool IsExplicitLayout
         {
             get
diff --git a/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/FieldDesc.Interop.cs b/src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/FieldDesc.Interop.cs
new file mode 100644 (file)
index 0000000..1e7a3e3
--- /dev/null
@@ -0,0 +1,25 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace Internal.TypeSystem
+{
+    partial class FieldDesc
+    {
+        /// <summary>
+        /// Returns description of how the field should be marshalled to native code.
+        /// </summary>
+        public virtual MarshalAsDescriptor GetMarshalAsDescriptor()
+        {
+            return null;
+        }
+    }
+
+    partial class FieldForInstantiatedType
+    {
+        public override MarshalAsDescriptor GetMarshalAsDescriptor()
+        {
+            return _fieldDef.GetMarshalAsDescriptor();
+        }
+    }
+}
index f6abfbb54119e923f5e2c57f4236d3e419b35c55..c605b6f14ce91e02bf6c65df4ed0d6eaf98bd4ae 100644 (file)
@@ -21,7 +21,7 @@ namespace Internal.TypeSystem.Interop
                 bool isArrayElement = false)
         {
             TypeSystemContext context = type.Context;
-            NativeTypeKind nativeType = NativeTypeKind.Invalid;
+            NativeTypeKind nativeType = NativeTypeKind.Default;
             if (marshalAs != null)
             {
                 nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type;
@@ -172,19 +172,25 @@ namespace Internal.TypeSystem.Interop
              MarshallerType marshallerType,
              out MarshallerKind elementMarshallerKind)
         {
+            elementMarshallerKind = MarshallerKind.Invalid;
+
+            bool isByRef = false;
             if (type.IsByRef)
             {
+                isByRef = true;
+
                 type = type.GetParameterType();
+
+                // Compat note: CLR allows ref returning blittable structs for IJW
+                if (isReturn)
+                    return MarshallerKind.Invalid;
             }
             TypeSystemContext context = type.Context;
-            NativeTypeKind nativeType = NativeTypeKind.Invalid;
+            NativeTypeKind nativeType = NativeTypeKind.Default;
             bool isField = marshallerType == MarshallerType.Field;
 
             if (marshalAs != null)
-                nativeType = (NativeTypeKind)marshalAs.Type;
-
-
-            elementMarshallerKind = MarshallerKind.Invalid;
+                nativeType = marshalAs.Type;
 
             //
             // Determine MarshalerKind
@@ -201,7 +207,7 @@ namespace Internal.TypeSystem.Interop
                     case TypeFlags.Boolean:
                         switch (nativeType)
                         {
-                            case NativeTypeKind.Invalid:
+                            case NativeTypeKind.Default:
                             case NativeTypeKind.Boolean:
                                 return MarshallerKind.Bool;
 
@@ -224,7 +230,7 @@ namespace Internal.TypeSystem.Interop
                             case NativeTypeKind.U2:
                                 return MarshallerKind.UnicodeChar;
 
-                            case NativeTypeKind.Invalid:
+                            case NativeTypeKind.Default:
                                 if (isAnsi)
                                     return MarshallerKind.AnsiChar;
                                 else
@@ -235,47 +241,47 @@ namespace Internal.TypeSystem.Interop
 
                     case TypeFlags.SByte:
                     case TypeFlags.Byte:
-                        if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
 
                     case TypeFlags.Int16:
                     case TypeFlags.UInt16:
-                        if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
 
                     case TypeFlags.Int32:
                     case TypeFlags.UInt32:
-                        if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
 
                     case TypeFlags.Int64:
                     case TypeFlags.UInt64:
-                        if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
 
                     case TypeFlags.IntPtr:
                     case TypeFlags.UIntPtr:
-                        if (nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.SysInt || nativeType == NativeTypeKind.SysUInt || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
 
                     case TypeFlags.Single:
-                        if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
 
                     case TypeFlags.Double:
-                        if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Invalid)
+                        if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Default)
                             return MarshallerKind.BlittableValue;
                         else
                             return MarshallerKind.Invalid;
@@ -291,7 +297,7 @@ namespace Internal.TypeSystem.Interop
 
                 if (InteropTypes.IsSystemDateTime(context, type))
                 {
-                    if (nativeType == NativeTypeKind.Invalid ||
+                    if (nativeType == NativeTypeKind.Default ||
                         nativeType == NativeTypeKind.Struct)
                         return MarshallerKind.OleDateTime;
                     else
@@ -299,58 +305,71 @@ namespace Internal.TypeSystem.Interop
                 }
                 else if (InteropTypes.IsHandleRef(context, type))
                 {
-                    if (nativeType == NativeTypeKind.Invalid)
+                    if (nativeType == NativeTypeKind.Default)
                         return MarshallerKind.HandleRef;
                     else
                         return MarshallerKind.Invalid;
                 }
-
-                switch (nativeType)
+                else if (InteropTypes.IsSystemDecimal(context, type))
                 {
-                    case NativeTypeKind.Invalid:
-                    case NativeTypeKind.Struct:
-                        if (InteropTypes.IsSystemDecimal(context, type))
-                            return MarshallerKind.Decimal;
-                        break;
-
-                    case NativeTypeKind.LPStruct:
-                        if (InteropTypes.IsSystemGuid(context, type) ||
-                            InteropTypes.IsSystemDecimal(context, type))
-                        {
-                            if (isField || isReturn)
-                                return MarshallerKind.Invalid;
-                            else
-                                return MarshallerKind.BlittableStructPtr;
-                        }
-                        break;
-
-                    default:
+                    if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
+                        return MarshallerKind.Decimal;
+                    else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn)
+                        return MarshallerKind.BlittableStructPtr;
+                    else
                         return MarshallerKind.Invalid;
                 }
+                else if (InteropTypes.IsSystemGuid(context, type))
+                {
+                    if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
+                        return MarshallerKind.BlittableStruct;
+                    else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn)
+                        return MarshallerKind.BlittableStructPtr;
+                    else
+                        return MarshallerKind.Invalid;
+                }
+                else if (InteropTypes.IsSystemArgIterator(context, type))
+                {
+                    // Don't want to fall through to the blittable/haslayout case
+                    return MarshallerKind.Invalid;
+                }
 
-                if (type is MetadataType)
+                if (type.HasInstantiation)
                 {
-                    MetadataType metadataType = (MetadataType)type;
-                    // the struct type need to be either sequential or explicit. If it is
-                    // auto layout we will throw exception.
-                    if (!metadataType.HasLayout())
-                    {
-                        throw new InvalidProgramException("The specified structure " + metadataType.Name + " has invalid StructLayout information. It must be either Sequential or Explicit.");
-                    }
+                    // Generic types cannot be marshaled.
+                    return MarshallerKind.Invalid;
                 }
 
                 if (MarshalUtils.IsBlittableType(type))
                 {
+                    if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
+                        return MarshallerKind.Invalid;
+
                     return MarshallerKind.BlittableStruct;
                 }
-                else
+                else if (((MetadataType)type).HasLayout())
                 {
+                    if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
+                        return MarshallerKind.Invalid;
+
                     return MarshallerKind.Struct;
                 }
+                else
+                {
+                    return MarshallerKind.Invalid;
+                }
             }
             else if (type.IsSzArray)
             {
-                if (nativeType == NativeTypeKind.Invalid)
+#if READYTORUN
+                // We don't want the additional test/maintenance cost of this in R2R.
+                if (isByRef)
+                    return MarshallerKind.Invalid;
+#else
+                _ = isByRef;
+#endif
+
+                if (nativeType == NativeTypeKind.Default)
                     nativeType = NativeTypeKind.Array;
 
                 switch (nativeType)
@@ -403,16 +422,40 @@ namespace Internal.TypeSystem.Interop
                         return MarshallerKind.Invalid;
                 }
             }
-            else if (type.IsPointer || type.IsFunctionPointer)
+            else if (type.IsPointer)
+            {
+                TypeDesc parameterType = ((PointerType)type).ParameterType;
+
+                if ((!parameterType.IsEnum
+                    && !parameterType.IsPrimitive
+                    && !MarshalUtils.IsBlittableType(parameterType))
+                    || parameterType.IsGCPointer)
+                {
+                    // Pointers cannot reference marshaled structures.  Use ByRef instead.
+                    return MarshallerKind.Invalid;
+                }
+
+                if (nativeType == NativeTypeKind.Default)
+                    return MarshallerKind.BlittableValue;
+                else
+                    return MarshallerKind.Invalid;
+            }
+            else if (type.IsFunctionPointer)
             {
-                if (nativeType == NativeTypeKind.Invalid)
+                if (nativeType == NativeTypeKind.Func || nativeType == NativeTypeKind.Default)
                     return MarshallerKind.BlittableValue;
                 else
                     return MarshallerKind.Invalid;
             }
             else if (type.IsDelegate)
             {
-                if (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Func)
+                if (type.HasInstantiation)
+                {
+                    // Generic types cannot be marshaled.
+                    return MarshallerKind.Invalid;
+                }
+
+                if (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Func)
                     return MarshallerKind.FunctionPointer;
                 else
                     return MarshallerKind.Invalid;
@@ -445,7 +488,7 @@ namespace Internal.TypeSystem.Interop
                             return MarshallerKind.ByValUnicodeString;
                         }
 
-                    case NativeTypeKind.Invalid:
+                    case NativeTypeKind.Default:
                         if (isAnsi)
                             return MarshallerKind.AnsiString;
                         else
@@ -466,7 +509,7 @@ namespace Internal.TypeSystem.Interop
             {
                 switch (nativeType)
                 {
-                    case NativeTypeKind.Invalid:
+                    case NativeTypeKind.Default:
                         if (isAnsi)
                         {
                             return MarshallerKind.AnsiStringBuilder;
@@ -487,23 +530,29 @@ namespace Internal.TypeSystem.Interop
             }
             else if (InteropTypes.IsSafeHandle(context, type))
             {
-                if (nativeType == NativeTypeKind.Invalid)
+                if (nativeType == NativeTypeKind.Default)
                     return MarshallerKind.SafeHandle;
                 else
                     return MarshallerKind.Invalid;
             }
             else if (InteropTypes.IsCriticalHandle(context, type))
             {
-                if (nativeType == NativeTypeKind.Invalid)
+                if (nativeType == NativeTypeKind.Default)
                     return MarshallerKind.CriticalHandle;
                 else
                     return MarshallerKind.Invalid;
             }
             else if (type is MetadataType mdType && mdType.HasLayout())
             {
-                if (!isField && nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.LPStruct)
+                if (type.HasInstantiation)
+                {
+                    // Generic types cannot be marshaled.
+                    return MarshallerKind.Invalid;
+                }
+
+                if (!isField && nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.LPStruct)
                     return MarshallerKind.LayoutClassPtr;
-                else if (isField && (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Struct))
+                else if (isField && (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Struct))
                     return MarshallerKind.LayoutClass;
                 else
                     return MarshallerKind.Invalid;
@@ -518,7 +567,7 @@ namespace Internal.TypeSystem.Interop
                    bool isAnsi)
         {
             TypeDesc elementType = arrayType.ElementType;
-            NativeTypeKind nativeType = NativeTypeKind.Invalid;
+            NativeTypeKind nativeType = NativeTypeKind.Default;
             TypeSystemContext context = arrayType.Context;
 
             if (marshalAs != null)
@@ -552,7 +601,7 @@ namespace Internal.TypeSystem.Interop
                             case NativeTypeKind.I1:
                             case NativeTypeKind.U1:
                                 return MarshallerKind.CBool;
-                            case NativeTypeKind.Invalid:
+                            case NativeTypeKind.Default:
                             default:
                                 return MarshallerKind.Bool;
                         }
@@ -587,7 +636,7 @@ namespace Internal.TypeSystem.Interop
                 {
                     switch (nativeType)
                     {
-                        case NativeTypeKind.Invalid:
+                        case NativeTypeKind.Default:
                         case NativeTypeKind.Struct:
                             return MarshallerKind.Decimal;
 
@@ -602,7 +651,7 @@ namespace Internal.TypeSystem.Interop
                 {
                     switch (nativeType)
                     {
-                        case NativeTypeKind.Invalid:
+                        case NativeTypeKind.Default:
                         case NativeTypeKind.Struct:
                             return MarshallerKind.BlittableValue;
 
@@ -615,7 +664,7 @@ namespace Internal.TypeSystem.Interop
                 }
                 else if (InteropTypes.IsSystemDateTime(context, elementType))
                 {
-                    if (nativeType == NativeTypeKind.Invalid ||
+                    if (nativeType == NativeTypeKind.Default ||
                         nativeType == NativeTypeKind.Struct)
                     {
                         return MarshallerKind.OleDateTime;
@@ -627,7 +676,7 @@ namespace Internal.TypeSystem.Interop
                 }
                 else if (InteropTypes.IsHandleRef(context, elementType))
                 {
-                    if (nativeType == NativeTypeKind.Invalid)
+                    if (nativeType == NativeTypeKind.Default)
                         return MarshallerKind.HandleRef;
                     else
                         return MarshallerKind.Invalid;
@@ -638,7 +687,7 @@ namespace Internal.TypeSystem.Interop
                     {
                         switch (nativeType)
                         {
-                            case NativeTypeKind.Invalid:
+                            case NativeTypeKind.Default:
                             case NativeTypeKind.Struct:
                                 return MarshallerKind.BlittableStruct;
 
@@ -655,7 +704,7 @@ namespace Internal.TypeSystem.Interop
             }
             else if (elementType.IsPointer || elementType.IsFunctionPointer)
             {
-                if (nativeType == NativeTypeKind.Invalid)
+                if (nativeType == NativeTypeKind.Default)
                     return MarshallerKind.BlittableValue;
                 else
                     return MarshallerKind.Invalid;
@@ -664,7 +713,7 @@ namespace Internal.TypeSystem.Interop
             {
                 switch (nativeType)
                 {
-                    case NativeTypeKind.Invalid:
+                    case NativeTypeKind.Default:
                         if (isAnsi)
                             return MarshallerKind.AnsiString;
                         else
index fde1aae6e1668ad7a7425f6022d022b686c44ad8..ce0897a117715565e17f8f774a858f7b61f25c4c 100644 (file)
@@ -9,51 +9,66 @@ namespace Internal.TypeSystem.Interop
     public static class MarshalUtils
     {
         /// <summary>
-        /// Returns true if this is a type that doesn't require marshalling.
+        /// Returns true if this type has a common representation in both managed and unmanaged memory
+        /// and does not require special handling by the interop marshaler.
         /// </summary>
         public static bool IsBlittableType(TypeDesc type)
         {
-            type = type.UnderlyingType;
+            if (!type.IsDefType)
+            {
+                return false;
+            }
+
+            TypeDesc baseType = type.BaseType;
+            bool hasNonTrivialParent = baseType != null
+                && !baseType.IsWellKnownType(WellKnownType.Object)
+                && !baseType.IsWellKnownType(WellKnownType.ValueType);
+
+            if (hasNonTrivialParent && !IsBlittableType(baseType))
+            {
+                return false;
+            }
+
+            var mdType = (MetadataType)type;
 
-            if (type.IsValueType)
+            if (!mdType.IsSequentialLayout && !mdType.IsExplicitLayout)
             {
-                if (type.IsPrimitive)
+                return false;
+            }
+
+            foreach (FieldDesc field in type.GetFields())
+            {
+                if (field.IsStatic)
                 {
-                    // All primitive types except char and bool are blittable
-                    TypeFlags category = type.Category;
-                    if (category == TypeFlags.Boolean || category == TypeFlags.Char)
-                        return false;
+                    continue;
+                }
 
-                    return true;
+                if (!field.FieldType.IsValueType)
+                {
+                    // Types with fields of non-value types cannot be blittable
+                    // This check prevents possible infinite recursion where GetMarshallerKind would call back to IsBlittable e.g. for
+                    // the case of classes with pointer members to the class itself.
+                    return false;
                 }
 
-                foreach (FieldDesc field in type.GetFields())
+                MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(
+                    field.FieldType,
+                    field.GetMarshalAsDescriptor(),
+                    isReturn: false,
+                    isAnsi: mdType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass,
+                    MarshallerType.Field,
+                    elementMarshallerKind: out var _);
+
+                if (marshallerKind != MarshallerKind.Enum
+                    && marshallerKind != MarshallerKind.BlittableValue
+                    && marshallerKind != MarshallerKind.BlittableStruct
+                    && marshallerKind != MarshallerKind.UnicodeChar)
                 {
-                    if (field.IsStatic)
-                        continue;
-
-                    TypeDesc fieldType = field.FieldType;
-
-                    // TODO: we should also reject fields that specify custom marshalling
-                    if (!MarshalUtils.IsBlittableType(fieldType))
-                    {
-                        // This field can still be blittable if it's a Char and marshals as Unicode
-                        var owningType = field.OwningType as MetadataType;
-                        if (owningType == null)
-                            return false;
-
-                        if (fieldType.Category != TypeFlags.Char ||
-                            owningType.PInvokeStringFormat == PInvokeStringFormat.AnsiClass)
-                            return false;
-                    }
+                    return false;
                 }
-                return true;
             }
 
-            if (type.IsPointer || type.IsFunctionPointer)
-                return true;
-
-            return false;
+            return true;
         }
     }
 }
index dcd4c20acbbd2800d27b90255cab2e9bbbc40e25..624ff457e07ed330f831e6555edf9a300447d59a 100644 (file)
@@ -1062,8 +1062,9 @@ namespace Internal.TypeSystem.Interop
             ILEmitter emitter = _ilCodeStreams.Emitter;
             ILCodeLabel lNullArray = emitter.NewCodeLabel();
 
-            LoadNativeAddr(codeStream);
-            codeStream.Emit(ILOpcode.initobj, emitter.NewToken(NativeType));
+            codeStream.EmitLdc(0);
+            codeStream.Emit(ILOpcode.conv_u);
+            StoreNativeValue(codeStream);
 
             // Check for null array
             LoadManagedValue(codeStream);
@@ -1081,7 +1082,7 @@ namespace Internal.TypeSystem.Interop
             codeStream.Emit(ILOpcode.mul_ovf);
 
             codeStream.Emit(ILOpcode.call, emitter.NewToken(
-                                Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemAllocAndZeroMemory")));
+                InteropTypes.GetMarshal(Context).GetKnownMethod("AllocCoTaskMem", null)));
             StoreNativeValue(codeStream);
 
             codeStream.EmitLabel(lNullArray);
@@ -1162,15 +1163,25 @@ namespace Internal.TypeSystem.Interop
             ILCodeLabel lRangeCheck = emitter.NewCodeLabel();
             ILCodeLabel lLoopHeader = emitter.NewCodeLabel();
             var lNullArray = emitter.NewCodeLabel();
-            
-            // Check for null array
-            LoadManagedValue(codeStream);
-            codeStream.Emit(ILOpcode.brfalse, lNullArray);
 
+            // Check for null array
+            if (!IsManagedByRef)
+            {
+                LoadManagedValue(codeStream);
+                codeStream.Emit(ILOpcode.brfalse, lNullArray);
+            }
 
             EmitElementCount(codeStream, MarshalDirection.Reverse);
 
             codeStream.EmitStLoc(vLength);
+
+            if (IsManagedByRef)
+            {
+                codeStream.EmitLdLoc(vLength);
+                codeStream.Emit(ILOpcode.newarr, emitter.NewToken(ManagedElementType));
+                StoreManagedValue(codeStream);
+            }
+
             codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType));
 
             codeStream.EmitStLoc(vSizeOf);
@@ -1307,31 +1318,42 @@ namespace Internal.TypeSystem.Interop
         protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream)
         {
             ILEmitter emitter = _ilCodeStreams.Emitter;
-            var arrayType = (ArrayType)ManagedType;
-            Debug.Assert(arrayType.IsSzArray);
-
-            ILLocalVariable vPinnedFirstElement = emitter.NewLocal(arrayType.ParameterType.MakeByRefType(), true);
             ILCodeLabel lNullArray = emitter.NewCodeLabel();
 
-            // Check for null array, or 0 element array.
-            LoadManagedValue(codeStream);
-            codeStream.Emit(ILOpcode.brfalse, lNullArray);
+            MethodDesc getRawSzArrayDataMethod = InteropTypes.GetRuntimeHelpers(Context).GetKnownMethod("GetRawSzArrayData", null);
+
+            // Check for null array
             LoadManagedValue(codeStream);
-            codeStream.Emit(ILOpcode.ldlen);
-            codeStream.Emit(ILOpcode.conv_i4);
             codeStream.Emit(ILOpcode.brfalse, lNullArray);
+            
+            if (IsManagedByRef)
+            {
+                base.AllocManagedToNative(codeStream);
 
-            // Array has elements.
-            LoadManagedValue(codeStream);
-            codeStream.EmitLdc(0);
-            codeStream.Emit(ILOpcode.ldelema, emitter.NewToken(arrayType.ElementType));
-            codeStream.EmitStLoc(vPinnedFirstElement);
+                LoadNativeValue(codeStream);
+                LoadManagedValue(codeStream);
+                codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod));
+                EmitElementCount(codeStream, MarshalDirection.Forward);
+                codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(ManagedElementType));
+                codeStream.Emit(ILOpcode.mul_ovf);
+                codeStream.Emit(ILOpcode.cpblk);
 
-            // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit.
-            codeStream.EmitLabel(lNullArray);
-            codeStream.EmitLdLoc(vPinnedFirstElement);
-            codeStream.Emit(ILOpcode.conv_i);
-            StoreNativeValue(codeStream);
+                codeStream.EmitLabel(lNullArray);
+            }
+            else
+            {
+                ILLocalVariable vPinnedFirstElement = emitter.NewLocal(ManagedElementType.MakeByRefType(), true);
+
+                LoadManagedValue(codeStream);
+                codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod));
+                codeStream.EmitStLoc(vPinnedFirstElement);
+
+                // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit.
+                codeStream.EmitLabel(lNullArray);
+                codeStream.EmitLdLoc(vPinnedFirstElement);
+                codeStream.Emit(ILOpcode.conv_i);
+                StoreNativeValue(codeStream);
+            }
         }
 
         protected override void ReInitNativeTransform(ILCodeStream codeStream)
@@ -1343,13 +1365,13 @@ namespace Internal.TypeSystem.Interop
 
         protected override void TransformNativeToManaged(ILCodeStream codeStream)
         {
-            if ((IsManagedByRef && !In) || (MarshalDirection == MarshalDirection.Reverse && MarshallerType == MarshallerType.Argument))
+            if (IsManagedByRef || (MarshalDirection == MarshalDirection.Reverse && MarshallerType == MarshallerType.Argument))
                 base.TransformNativeToManaged(codeStream);
         }
 
         protected override void EmitCleanupManaged(ILCodeStream codeStream)
         {
-            if (IsManagedByRef && !In)
+            if (IsManagedByRef)
                 base.EmitCleanupManaged(codeStream);
         }
     }
index 5d7d0fde445b050d618b92267c3d8a9bc29d393f..63f2f2e1f2818fbf08c0e743f5223a1feb33a617 100644 (file)
@@ -45,6 +45,11 @@ namespace Internal.TypeSystem.Interop
             return context.SystemModule.GetKnownType("System.Runtime.InteropServices", "Marshal");
         }
 
+        public static MetadataType GetRuntimeHelpers(TypeSystemContext context)
+        {
+            return context.SystemModule.GetKnownType("System.Runtime.CompilerServices", "RuntimeHelpers");
+        }
+
         public static MetadataType GetStubHelpers(TypeSystemContext context)
         {
             return context.SystemModule.GetKnownType("System.StubHelpers", "StubHelpers");
@@ -98,6 +103,11 @@ namespace Internal.TypeSystem.Interop
             return IsCoreNamedType(context, type, "System", "Guid");
         }
 
+        public static bool IsSystemArgIterator(TypeSystemContext context, TypeDesc type)
+        {
+            return IsCoreNamedType(context, type, "System", "ArgIterator");
+        }
+
         private static bool IsOrDerivesFromType(TypeDesc type, MetadataType targetType)
         {
             while (type != null)
index 9d5510b17651b65ab2004385906d682d6a55a52c..afb1b66c401c0bd522c17968a9705ba1dbf0eeb4 100644 (file)
@@ -36,7 +36,7 @@ namespace Internal.TypeSystem
         Array = 0x2a,
         LPStruct = 0x2b,    // This is not  defined in Ecma-335(II.23.4)
         LPUTF8Str = 0x30,
-        Invalid = 0x50,      // This is the default value
+        Default = 0x50,      // This is the default value
         Variant = 0x51,
     }
 
index 2f1cfb7f4d7277a2f3c26729c31158f7eba5216a..3f586dcb3f5e75380414b59da0fc617a1e7ebb09 100644 (file)
@@ -33,13 +33,5 @@ namespace Internal.TypeSystem
         {
             get;
         }
-
-        /// <summary>
-        /// Retrieves the MarshalAsDescriptor of each field of the type
-        /// </summary>
-        public virtual MarshalAsDescriptor[] GetFieldMarshalAsDescriptors()
-        {
-            return Array.Empty<MarshalAsDescriptor>();
-        }
     }
 }
index eea1c44a9992681c094c2ff969c0db12fbc91b1e..49afbe7fb49341133d778e666186c81aa88f74f2 100644 (file)
@@ -43,6 +43,7 @@
     <Compile Include="..\Common\TypeSystem\IL\Stubs\PInvokeILCodeStreams.cs" Link="IL\Stubs\PInvokeILCodeStreams.cs" />
     <Compile Include="..\Common\TypeSystem\Interop\IL\Marshaller.cs" Link="Interop\IL\Marshaller.cs" />
     <Compile Include="..\Common\TypeSystem\Interop\IL\MarshalHelpers.cs" Link="Interop\IL\MarshalHelpers.cs" />
+    <Compile Include="..\Common\TypeSystem\Interop\IL\MarshalUtils.cs" Link="Interop\IL\MarshalUtils.cs" />
     <Compile Include="..\Common\Compiler\CodeGenerationFailedException.cs" Link="Compiler\CodeGenerationFailedException.cs" />
     <Compile Include="..\Common\Compiler\CompilationBuilder.cs" Link="Compiler\CompilationBuilder.cs" />
     <Compile Include="..\Common\Compiler\CompilationModuleGroup.cs" Link="Compiler\CompilationModuleGroup.cs" />
index 0fe25e26ec521400de895b05cf0074ed16d4e6d1..df1d68c0de758b3ac11454a5f028e4cec9346954 100644 (file)
     <Compile Include="..\Common\TypeSystem\IL\ILOpcodeHelper.cs">
       <Link>IL\ILOpcodeHelper.cs</Link>
     </Compile>
-    <Compile Include="..\Common\TypeSystem\Interop\IL\MarshalUtils.cs">
-      <Link>Interop\IL\MarshalUtils.cs</Link>
-    </Compile>
     <Compile Include="..\Common\TypeSystem\IL\Stubs\ILEmitter.cs">
       <Link>IL\Stubs\ILEmitter.cs</Link>
     </Compile>
     <Compile Include="..\Common\TypeSystem\Sorting\MethodForInstantiatedType.Sorting.cs">
       <Link>TypeSystem\Sorting\MethodForInstantiatedType.Sorting.cs</Link>
     </Compile>
+    <Compile Include="..\Common\TypeSystem\Interop\FieldDesc.Interop.cs">
+      <Link>TypeSystem\Interop\FieldDesc.Interop.cs</Link>
+    </Compile>
     <Compile Include="..\Common\TypeSystem\Interop\InstantiatedType.Interop.cs">
       <Link>TypeSystem\Interop\InstantiatedType.Interop.cs</Link>
     </Compile>