Implement DefType.IsUnsafeValueType (#56790)
authorJakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>
Thu, 5 Aug 2021 17:35:30 +0000 (19:35 +0200)
committerGitHub <noreply@github.com>
Thu, 5 Aug 2021 17:35:30 +0000 (19:35 +0200)
Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com>
src/coreclr/tools/Common/Compiler/VectorFieldLayoutAlgorithm.cs
src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs
src/coreclr/tools/Common/TypeSystem/Common/FieldLayoutAlgorithm.cs
src/coreclr/tools/Common/TypeSystem/Common/MetadataFieldLayoutAlgorithm.cs
src/coreclr/tools/Common/TypeSystem/Common/UniversalCanonLayoutAlgorithm.cs
src/coreclr/tools/Common/TypeSystem/RuntimeDetermined/RuntimeDeterminedFieldLayoutAlgorithm.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCompilerContext.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/SystemObjectFieldLayoutAlgorithm.cs

index 95bbf35..a4e49bd 100644 (file)
@@ -90,6 +90,12 @@ namespace ILCompiler
             return false;
         }
 
+        public override bool ComputeIsUnsafeValueType(DefType type)
+        {
+            Debug.Assert(!_fallbackAlgorithm.ComputeIsUnsafeValueType(type));
+            return false;
+        }
+
         public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
         {
             if (type.Context.Target.Architecture == TargetArchitecture.ARM64 &&
index d5dc33b..8cf79f8 100644 (file)
@@ -1875,9 +1875,8 @@ namespace Internal.JitInterface
                 if (metadataType.IsExplicitLayout || (metadataType.IsSequentialLayout && metadataType.GetClassLayout().Size != 0) || metadataType.IsWellKnownType(WellKnownType.TypedReference))
                     result |= CorInfoFlag.CORINFO_FLG_CUSTOMLAYOUT;
 
-                // TODO
-                // if (type.IsUnsafeValueType)
-                //    result |= CorInfoFlag.CORINFO_FLG_UNSAFE_VALUECLASS;
+                if (metadataType.IsUnsafeValueType)
+                    result |= CorInfoFlag.CORINFO_FLG_UNSAFE_VALUECLASS;
             }
 
             if (type.IsCanonicalSubtype(CanonicalFormKind.Any))
index 3e73dcf..71c7423 100644 (file)
@@ -53,6 +53,16 @@ namespace Internal.TypeSystem
             /// True if the layout of the type is not stable for use in the ABI
             /// </summary>
             public const int ComputedInstanceLayoutAbiUnstable = 0x80;
+
+            /// <summary>
+            /// True if IsUnsafeValueType has been computed
+            /// </summary>
+            public const int ComputedIsUnsafeValueType = 0x100;
+
+            /// <summary>
+            /// True if type transitively has UnsafeValueTypeAttribute
+            /// </summary>
+            public const int IsUnsafeValueType = 0x200;
         }
 
         private class StaticBlockInfo
@@ -91,6 +101,22 @@ namespace Internal.TypeSystem
         }
 
         /// <summary>
+        /// Does a type transitively have any fields which are marked with System.Runtime.CompilerServices.UnsafeValueTypeAttribute
+        /// </summary>
+        public bool IsUnsafeValueType
+        {
+            get
+            {
+                if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedIsUnsafeValueType))
+                {
+                    ComputeIsUnsafeValueType();
+                }
+                return _fieldLayoutFlags.HasFlags(FieldLayoutFlags.IsUnsafeValueType);
+            }
+        }
+
+
+        /// <summary>
         /// The number of bytes required to hold a field of this type
         /// </summary>
         public LayoutInt InstanceFieldSize
@@ -449,5 +475,20 @@ namespace Internal.TypeSystem
 
             _fieldLayoutFlags.AddFlags(flagsToAdd);
         }
+
+        public void ComputeIsUnsafeValueType()
+        {
+            if (_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedIsUnsafeValueType))
+                return;
+
+            int flagsToAdd = FieldLayoutFlags.ComputedIsUnsafeValueType;
+
+            if (this.Context.GetLayoutAlgorithmForType(this).ComputeIsUnsafeValueType(this))
+            {
+                flagsToAdd |= FieldLayoutFlags.IsUnsafeValueType;
+            }
+
+            _fieldLayoutFlags.AddFlags(flagsToAdd);
+        }
     }
 }
index 47c8638..863e857 100644 (file)
@@ -32,6 +32,11 @@ namespace Internal.TypeSystem
         public abstract bool ComputeContainsGCPointers(DefType type);
 
         /// <summary>
+        /// Compute whether the specified type is a value type that transitively has UnsafeValueTypeAttribute
+        /// </summary>
+        public abstract bool ComputeIsUnsafeValueType(DefType type);
+
+        /// <summary>
         /// Compute the shape of a value type. The shape information is used to control code generation and allocation
         /// (such as vectorization, passing the value type by value across method calls, or boxing alignment).
         /// </summary>
index 4109bb7..f445bb1 100644 (file)
@@ -1014,6 +1014,31 @@ namespace Internal.TypeSystem
             return NotHA;
         }
 
+        public override bool ComputeIsUnsafeValueType(DefType type)
+        {
+            if (!type.IsValueType)
+                return false;
+
+            MetadataType metadataType = (MetadataType)type;
+            if (metadataType.HasCustomAttribute("System.Runtime.CompilerServices", "UnsafeValueTypeAttribute"))
+                return true;
+
+            foreach (FieldDesc field in metadataType.GetFields())
+            {
+                if (field.IsStatic)
+                    continue;
+
+                TypeDesc fieldType = field.FieldType;
+                if (!fieldType.IsValueType || fieldType.IsPrimitive)
+                    continue;
+
+                if (((DefType)fieldType).IsUnsafeValueType)
+                    return true;
+            }
+
+            return false;
+        }
+
         private struct SizeAndAlignment
         {
             public LayoutInt Size;
index 9b58069..196aef8 100644 (file)
@@ -34,6 +34,11 @@ namespace Internal.TypeSystem
             };
         }
 
+        public override bool ComputeIsUnsafeValueType(DefType type)
+        {
+            throw new NotSupportedException();
+        }
+
         public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType type, StaticLayoutKind layoutKind)
         {
             return new ComputedStaticFieldLayout()
index 5985768..2d26f45 100644 (file)
@@ -58,5 +58,13 @@ namespace Internal.TypeSystem
 
             return canonicalType.ValueTypeShapeCharacteristics;
         }
+
+        public override bool ComputeIsUnsafeValueType(DefType type)
+        {
+            RuntimeDeterminedType runtimeDeterminedType = (RuntimeDeterminedType)type;
+            DefType canonicalType = runtimeDeterminedType.CanonicalType;
+
+            return canonicalType.IsUnsafeValueType;
+        }
     }
 }
index 5790516..44bddc1 100644 (file)
@@ -154,6 +154,11 @@ namespace ILCompiler
             return false;
         }
 
+        public override bool ComputeIsUnsafeValueType(DefType type)
+        {
+            return false;
+        }
+
         public override ComputedInstanceFieldLayout ComputeInstanceLayout(DefType type, InstanceLayoutKind layoutKind)
         {
             DefType similarSpecifiedVector = GetSimilarVector(type);
index 2d04a02..a0d68d1 100644 (file)
@@ -50,6 +50,11 @@ namespace ILCompiler
             return false;
         }
 
+        public override bool ComputeIsUnsafeValueType(DefType type)
+        {
+            return false;
+        }
+
         public override ValueTypeShapeCharacteristics ComputeValueTypeShapeCharacteristics(DefType type)
         {
             return _fallbackAlgorithm.ComputeValueTypeShapeCharacteristics(type);