Update NativeAOT codegen and Crossgen2 for CreateSpan (#63977)
authorDavid Wrighton <davidwr@microsoft.com>
Sun, 23 Jan 2022 22:23:32 +0000 (14:23 -0800)
committerGitHub <noreply@github.com>
Sun, 23 Jan 2022 22:23:32 +0000 (14:23 -0800)
- Make sure FieldRVA pointers remain aligned as required by the code generator
  - Use the same Packing Size approach as the IL Linker will use (See jbevain/cecil#817 for details)
  - Compilers that generate CreateSpan will need to follow that trick to be compatible with rewriters.
- Provide ECMA spec augment describing packing size detail

docs/design/specs/Ecma-335-Augments.md
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/CopiedFieldRvaNode.cs
src/tests/JIT/Intrinsics/CreateSpan_il.il

index 1c52fed..6e1900c 100644 (file)
@@ -13,6 +13,7 @@ This is a list of additions and edits to be made in ECMA-335 specifications. It
 - [Static Interface Methods](#static-interface-methods)
 - [Covariant Return Types](#covariant-return-types)
 - [Unsigned data conversion with overflow detection](#unsigned-data-conversion-with-overflow-detection)
+- [Rules for IL rewriters](#rules-for-il-rewriters)
 
 ## Signatures
 
@@ -948,3 +949,12 @@ Conversions from floating-point numbers to integral values truncate the number t
 on the top of the stack is reinterpreted as an unsigned value before the conversion.
 Note that integer values of less than 4 bytes are extended to int32 (not native int) on the
 evaluation stack.
+
+## Rules for IL Rewriters
+
+There are apis such as `System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan<T>(...)` which require that the PE file have a particular structure. In particular, that api requires that the associated RVA of a FieldDef which is used to create a span must be naturally aligned over the data type that `CreateSpan` is instantiated over. There are 2 major concerns.
+
+1. That the RVA be aligned when the PE file is constructed. This may be achieved by whatever means is most convenient for the compiler.
+2. That in the presence of IL rewriters that the RVA remains aligned. This section descibes metadata which will be processed by IL rewriters in order to maintain the required alignment.
+
+In order to maintain alignment, if the field needs alignment to be preserved, the field must be of a type locally defined within the module which has a Pack (§II.10.7) value of the desired alignment. Unlike other uses of the .pack directive, in this circumstance the .pack specifies a minimum alignment.
index f3f780e..d19b60b 100644 (file)
@@ -143,8 +143,9 @@ namespace ILCompiler
             {
                 // Use the typical field definition in case this is an instantiated generic type
                 field = field.GetTypicalFieldDefinition();
+                int fieldTypePack = (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1;
                 return NodeFactory.ReadOnlyDataBlob(NameMangler.GetMangledFieldName(field),
-                    ((EcmaField)field).GetFieldRvaData(), NodeFactory.Target.PointerSize);
+                    ((EcmaField)field).GetFieldRvaData(), Math.Max(NodeFactory.Target.PointerSize, fieldTypePack));
             }
         }
 
index e8596cf..a8ff518 100644 (file)
@@ -46,15 +46,17 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
             }
 
             ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
-            builder.RequireInitialPointerAlignment();
+            byte[] rvaData = GetRvaData(factory.Target.PointerSize, out int requiredAlignment);
+            builder.RequireInitialAlignment(requiredAlignment);
             builder.AddSymbol(this);
-            builder.EmitBytes(GetRvaData(factory.Target.PointerSize));
+            builder.EmitBytes(rvaData);
             return builder.ToObjectData();
         }
 
-        private unsafe byte[] GetRvaData(int targetPointerSize)
+        private unsafe byte[] GetRvaData(int targetPointerSize, out int requiredAlignment)
         {
             int size = 0;
+            requiredAlignment = targetPointerSize;
 
             MetadataReader metadataReader = _module.MetadataReader;
             BlobReader metadataBlob = new BlobReader(_module.PEReader.GetMetadata().Pointer, _module.PEReader.GetMetadata().Length);
@@ -80,6 +82,7 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
                 Debug.Assert(field.HasRva);
 
                 int currentSize = field.FieldType.GetElementSize().AsInt;
+                requiredAlignment = Math.Max(requiredAlignment, (field.FieldType as MetadataType)?.GetClassLayout().PackingSize ?? 1);
                 if (currentSize > size)
                 {
                     // We need to handle overlapping fields by reusing blobs based on the rva, and just update
index d6a269b..cd95029 100644 (file)
   .class explicit ansi sealed nested private '__StaticArrayInitTypeSize=16'
          extends [System.Runtime]System.ValueType
   {
-    .pack 1
+    .pack 4
     .size 16
   } // end of class '__StaticArrayInitTypeSize=16'