From 604beade436b926d8b3261888bde17fc1e127fc5 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Fri, 9 Dec 2022 21:50:35 -0500 Subject: [PATCH 1/3] Fix several issues with CreateSpan support 1. It turns out we can't use the system types (short, int, long) for data fields when there's an alignment requirement, as those types have .pack 1 and thus a rewriter (e.g. illink) might not align fields using those types appropriately. 2. We weren't incorporating the alignment into the name of the ExplicitSizeStruct created, so we could end up with two types both for the same size but for different alignments and with the same name. 3. In looking at the code again, I realized we could simplify it so that EmitArrayBlockInitializer doesn't take an alignment at all, since for array purposes, we always want to use alignment 1. Because it took an alignment, we were unnecessarily specifying one even for the no-CreateSpan fallback. This was functionally correct but unnecessary and resulting in a bit more complicated IL, especially once (1) above was fixed. --- .../Portable/CodeGen/EmitArrayInitializer.cs | 18 +- .../CodeGenReadOnlySpanConstructionTest.cs | 651 ++++++++++++++---- .../Core/Portable/CodeGen/ILBuilderEmit.cs | 20 +- .../CodeGen/PrivateImplementationDetails.cs | 16 +- .../Portable/CodeGen/EmitArrayInitializer.vb | 2 +- 5 files changed, 541 insertions(+), 166 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index c8fe933b78327..5cb2cc8c3b7c3 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -54,20 +54,7 @@ private void EmitArrayInitializers(ArrayTypeSymbol arrayType, BoundArrayInitiali { ImmutableArray data = this.GetRawData(initExprs); - // Emit the call to RuntimeHelpers.InitializeArray, creating the necessary metadata blob if there isn't - // already one for this data. Note that this specifies an alignment of 1. This is valid regardless of - // the kind of data stored in the array, as it's never accessed directly in the blob; rather, InitializeArray - // copies out the data as bytes. The upside to keeping this as 1 is it means no special alignment is required. - // Although the compiler currently always aligns the metadata fields at an 8-byte boundary, the .pack field - // is appropriately set to the alignment value, and a rewriter (e.g. illink) may respect that. If the alignment - // value were to be increased to match the actual alignment requirements of the element type, that could cause - // such rewritten binaries to regress in size due to the extra padding necessary for aligning. The downside - // to keeping this as 1 is that this data won't unify with any blobs created for spans (e.g. RuntimeHelpers.CreateSpan). - // Code typically does directly read from the blobs via spans, and as such alignment there is required to be - // at least what the element type requires. That means if the same data/element type is used with an array - // and separately with a span, the data will exist duplicated in two different blobs. If it turns out that's - // very common, this can be revised in the future to specify the element type's alignment. - _builder.EmitArrayBlockInitializer(data, alignment: 1, inits.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitArrayBlockInitializer(data, inits.Syntax, _diagnostics.DiagnosticBag); if (initializationStyle == ArrayInitializerStyle.Mixed) { @@ -675,7 +662,6 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp // ensure deterministic behavior. arrayType = arrayType.WithElementType(TypeWithAnnotations.Create(elementType.EnumUnderlyingTypeOrSelf())); - ushort alignment = (ushort)specialElementType.SizeInBytes(); var cachingField = _builder.module.GetArrayCachingFieldForData(data, _module.Translate(arrayType), wrappedExpression.Syntax, _diagnostics.DiagnosticBag); var arrayNotNullLabel = new object(); @@ -693,7 +679,7 @@ private bool TryEmitReadonlySpanAsBlobWrapper(NamedTypeSymbol spanType, BoundExp _builder.EmitIntConstant(elementCount); _builder.EmitOpCode(ILOpCode.Newarr); EmitSymbolToken(arrayType.ElementType, wrappedExpression.Syntax); - _builder.EmitArrayBlockInitializer(data, alignment, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitArrayBlockInitializer(data, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitOpCode(ILOpCode.Stsfld); _builder.EmitToken(cachingField, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs index 3aba637b86c54..ef11eb86fa93f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; @@ -976,29 +977,29 @@ public static IEnumerable NonSize1Type_HasCreateSpan_CreateSpanUsed_Me foreach (bool withCtor in new[] { false, true }) { // A primitive can be used for the type of the blob - yield return new object[] { withCtor, "ushort", "1", "short .47DC540C94CEB704A23875C11273E16BB0B8A87AED84DE911F2133568115F2542" }; - yield return new object[] { withCtor, "ushort", "1, 2", "int .7B11C1133330CD161071BF23A0C9B6CE5320A8F3A0F83620035A72BE46DF41042" }; - yield return new object[] { withCtor, "ushort", "1, 2, 3, 4", "long .EA99F710D9D0B8BA192295C969A63ED7CE8FC5743DA20D2057FA2B6D2C404BFB2" }; - yield return new object[] { withCtor, "uint", "1", "int .67ABDD721024F0FF4E0B3F4C2FC13BC5BAD42D0B7851D456D88D203D15AAA4504" }; - yield return new object[] { withCtor, "uint", "1, 2", "long .34FB5C825DE7CA4AEA6E712F19D439C1DA0C92C37B423936C5F618545CA4FA1F4" }; - yield return new object[] { withCtor, "ulong", "1", "long .7C9FA136D4413FA6173637E883B6998D32E1D675F88CDDFF9DCBCF331820F4B88" }; + yield return new object[] { withCtor, "ushort", "1", ".__StaticArrayInitTypeSize=2_Align=2 .47DC540C94CEB704A23875C11273E16BB0B8A87AED84DE911F2133568115F2542" }; + yield return new object[] { withCtor, "ushort", "1, 2", ".__StaticArrayInitTypeSize=4_Align=2 .7B11C1133330CD161071BF23A0C9B6CE5320A8F3A0F83620035A72BE46DF41042" }; + yield return new object[] { withCtor, "ushort", "1, 2, 3, 4", ".__StaticArrayInitTypeSize=8_Align=2 .EA99F710D9D0B8BA192295C969A63ED7CE8FC5743DA20D2057FA2B6D2C404BFB2" }; + yield return new object[] { withCtor, "uint", "1", ".__StaticArrayInitTypeSize=4_Align=4 .67ABDD721024F0FF4E0B3F4C2FC13BC5BAD42D0B7851D456D88D203D15AAA4504" }; + yield return new object[] { withCtor, "uint", "1, 2", ".__StaticArrayInitTypeSize=8_Align=4 .34FB5C825DE7CA4AEA6E712F19D439C1DA0C92C37B423936C5F618545CA4FA1F4" }; + yield return new object[] { withCtor, "ulong", "1", ".__StaticArrayInitTypeSize=8_Align=8 .7C9FA136D4413FA6173637E883B6998D32E1D675F88CDDFF9DCBCF331820F4B88" }; // Require a new type to be synthesized for the blob - yield return new object[] { withCtor, "char", "'a', 'b', 'c'", ".__StaticArrayInitTypeSize=6 .13E228567E8249FCE53337F25D7970DE3BD68AB2653424C7B8F9FD05E33CAEDF2" }; - yield return new object[] { withCtor, "int", "1, 2, 3", ".__StaticArrayInitTypeSize=12 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4" }; - yield return new object[] { withCtor, "uint", "1, 2, 3", ".__StaticArrayInitTypeSize=12 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4" }; - yield return new object[] { withCtor, "short", "1, 2, 3", ".__StaticArrayInitTypeSize=6 .047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF72" }; - yield return new object[] { withCtor, "ushort", "1, 2, 3", ".__StaticArrayInitTypeSize=6 .047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF72" }; - yield return new object[] { withCtor, "long", "1, 2, 3", ".__StaticArrayInitTypeSize=24 .E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF8" }; - yield return new object[] { withCtor, "ulong", "1, 2, 3", ".__StaticArrayInitTypeSize=24 .E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF8" }; - yield return new object[] { withCtor, "float", "1.0f, 2.0f, 3.0f", ".__StaticArrayInitTypeSize=12 .8E628779E6A74EE0B36991C10158F63CAFEC7D340AD4E075592502C8708524DD4" }; - yield return new object[] { withCtor, "double", "1.0, 2.0, 3.0", ".__StaticArrayInitTypeSize=24 .A68DE4B5E96A60C8CEB3C7B7EF93461725BDBBFF3516B136585A743B5C0EC6648" }; - yield return new object[] { withCtor, "MyColor_Int16", "MyColor_Int16.Red, MyColor_Int16.Blue", "int .72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C602" }; - yield return new object[] { withCtor, "MyColor_UInt16", "MyColor_UInt16.Red, MyColor_UInt16.Blue", "int .72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C602" }; - yield return new object[] { withCtor, "MyColor_Int32", "MyColor_Int32.Red, MyColor_Int32.Blue", "long .1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B14" }; - yield return new object[] { withCtor, "MyColor_UInt32", "MyColor_UInt32.Red, MyColor_UInt32.Blue", "long .1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B14" }; - yield return new object[] { withCtor, "MyColor_Int64", "MyColor_Int64.Red, MyColor_Int64.Blue", ".__StaticArrayInitTypeSize=16 .F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E8" }; - yield return new object[] { withCtor, "MyColor_UInt64", "MyColor_UInt64.Red, MyColor_UInt64.Blue", ".__StaticArrayInitTypeSize=16 .F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E8" }; + yield return new object[] { withCtor, "char", "'a', 'b', 'c'", ".__StaticArrayInitTypeSize=6_Align=2 .13E228567E8249FCE53337F25D7970DE3BD68AB2653424C7B8F9FD05E33CAEDF2" }; + yield return new object[] { withCtor, "int", "1, 2, 3", ".__StaticArrayInitTypeSize=12_Align=4 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4" }; + yield return new object[] { withCtor, "uint", "1, 2, 3", ".__StaticArrayInitTypeSize=12_Align=4 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D4" }; + yield return new object[] { withCtor, "short", "1, 2, 3", ".__StaticArrayInitTypeSize=6_Align=2 .047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF72" }; + yield return new object[] { withCtor, "ushort", "1, 2, 3", ".__StaticArrayInitTypeSize=6_Align=2 .047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF72" }; + yield return new object[] { withCtor, "long", "1, 2, 3", ".__StaticArrayInitTypeSize=24_Align=8 .E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF8" }; + yield return new object[] { withCtor, "ulong", "1, 2, 3", ".__StaticArrayInitTypeSize=24_Align=8 .E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF8" }; + yield return new object[] { withCtor, "float", "1.0f, 2.0f, 3.0f", ".__StaticArrayInitTypeSize=12_Align=4 .8E628779E6A74EE0B36991C10158F63CAFEC7D340AD4E075592502C8708524DD4" }; + yield return new object[] { withCtor, "double", "1.0, 2.0, 3.0", ".__StaticArrayInitTypeSize=24_Align=8 .A68DE4B5E96A60C8CEB3C7B7EF93461725BDBBFF3516B136585A743B5C0EC6648" }; + yield return new object[] { withCtor, "MyColor_Int16", "MyColor_Int16.Red, MyColor_Int16.Blue", ".__StaticArrayInitTypeSize=4_Align=2 .72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C602" }; + yield return new object[] { withCtor, "MyColor_UInt16", "MyColor_UInt16.Red, MyColor_UInt16.Blue", ".__StaticArrayInitTypeSize=4_Align=2 .72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C602" }; + yield return new object[] { withCtor, "MyColor_Int32", "MyColor_Int32.Red, MyColor_Int32.Blue", ".__StaticArrayInitTypeSize=8_Align=4 .1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B14" }; + yield return new object[] { withCtor, "MyColor_UInt32", "MyColor_UInt32.Red, MyColor_UInt32.Blue", ".__StaticArrayInitTypeSize=8_Align=4 .1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B14" }; + yield return new object[] { withCtor, "MyColor_Int64", "MyColor_Int64.Red, MyColor_Int64.Blue", ".__StaticArrayInitTypeSize=16_Align=8 .F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E8" }; + yield return new object[] { withCtor, "MyColor_UInt64", "MyColor_UInt64.Red, MyColor_UInt64.Blue", ".__StaticArrayInitTypeSize=16_Align=8 .F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E8" }; } } @@ -1054,7 +1055,7 @@ public static int M() // Code size 21 (0x15) .maxstack 2 .locals init (System.ReadOnlySpan V_0) //span - IL_0000: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" + IL_0000: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" IL_0005: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" IL_000a: stloc.0 IL_000b: ldloca.s V_0 @@ -1094,53 +1095,53 @@ public static int M() var verifier = CompileAndVerify(compilation, verify: Verification.Skipped); verifier.VerifyIL("Test.M", @$" {{ - // Code size 93 (0x5d) - .maxstack 3 - .locals init (System.ReadOnlySpan V_0, //span1 + // Code size 93 (0x5d) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0, //span1 int V_1, //result System.ReadOnlySpan V_2, //span2 System.ReadOnlySpan V_3, //span3 System.ReadOnlySpan V_4) //span4 - IL_0000: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" - IL_0005: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_000a: stloc.0 - IL_000b: ldloca.s V_0 - IL_000d: ldc.i4.1 - IL_000e: call ""ref readonly int System.ReadOnlySpan.this[int].get"" - IL_0013: ldind.i4 - IL_0014: stloc.1 - IL_0015: ldtoken "".__StaticArrayInitTypeSize=32 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F894"" - IL_001a: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_001f: stloc.2 - IL_0020: ldloc.1 - IL_0021: ldloca.s V_2 - IL_0023: ldc.i4.2 - IL_0024: call ""ref readonly int System.ReadOnlySpan.this[int].get"" - IL_0029: ldind.i4 - IL_002a: add - IL_002b: stloc.1 - IL_002c: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" - IL_0031: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_0036: stloc.3 - IL_0037: ldloc.1 - IL_0038: ldloca.s V_3 - IL_003a: ldc.i4.3 - IL_003b: call ""ref readonly int System.ReadOnlySpan.this[int].get"" - IL_0040: ldind.i4 - IL_0041: add - IL_0042: stloc.1 - IL_0043: ldtoken "".__StaticArrayInitTypeSize=32 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F894"" - IL_0048: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_004d: stloc.s V_4 - IL_004f: ldloc.1 - IL_0050: ldloca.s V_4 - IL_0052: ldc.i4.4 - IL_0053: call ""ref readonly int System.ReadOnlySpan.this[int].get"" - IL_0058: ldind.i4 - IL_0059: add - IL_005a: stloc.1 - IL_005b: ldloc.1 - IL_005c: ret + IL_0000: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" + IL_0005: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_000a: stloc.0 + IL_000b: ldloca.s V_0 + IL_000d: ldc.i4.1 + IL_000e: call ""ref readonly int System.ReadOnlySpan.this[int].get"" + IL_0013: ldind.i4 + IL_0014: stloc.1 + IL_0015: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F894"" + IL_001a: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_001f: stloc.2 + IL_0020: ldloc.1 + IL_0021: ldloca.s V_2 + IL_0023: ldc.i4.2 + IL_0024: call ""ref readonly int System.ReadOnlySpan.this[int].get"" + IL_0029: ldind.i4 + IL_002a: add + IL_002b: stloc.1 + IL_002c: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" + IL_0031: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_0036: stloc.3 + IL_0037: ldloc.1 + IL_0038: ldloca.s V_3 + IL_003a: ldc.i4.3 + IL_003b: call ""ref readonly int System.ReadOnlySpan.this[int].get"" + IL_0040: ldind.i4 + IL_0041: add + IL_0042: stloc.1 + IL_0043: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F894"" + IL_0048: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_004d: stloc.s V_4 + IL_004f: ldloc.1 + IL_0050: ldloca.s V_4 + IL_0052: ldc.i4.4 + IL_0053: call ""ref readonly int System.ReadOnlySpan.this[int].get"" + IL_0058: ldind.i4 + IL_0059: add + IL_005a: stloc.1 + IL_005b: ldloc.1 + IL_005c: ret }} "); } @@ -1187,7 +1188,7 @@ .locals init (System.ReadOnlySpan V_0, //span1 IL_0009: ldc.i4.8 IL_000a: newarr ""int"" IL_000f: dup - IL_0010: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" + IL_0010: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A18"" IL_0015: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_001a: dup IL_001b: stsfld ""int[] .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A18_A6"" @@ -1205,7 +1206,7 @@ .locals init (System.ReadOnlySpan V_0, //span1 IL_0039: ldc.i4.8 IL_003a: newarr ""int"" IL_003f: dup - IL_0040: ldtoken "".__StaticArrayInitTypeSize=32 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F894"" + IL_0040: ldtoken "".__StaticArrayInitTypeSize=32 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F89"" IL_0045: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_004a: dup IL_004b: stsfld ""int[] .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F89_A6"" @@ -1225,7 +1226,7 @@ .locals init (System.ReadOnlySpan V_0, //span1 IL_006b: ldc.i4.8 IL_006c: newarr ""int"" IL_0071: dup - IL_0072: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A184"" + IL_0072: ldtoken "".__StaticArrayInitTypeSize=32 .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A18"" IL_0077: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_007c: dup IL_007d: stsfld ""int[] .8B4B2444E57AED8C2D05A1293255DA1B048C63224317D4666230760935FA4A18_A6"" @@ -1245,7 +1246,7 @@ .locals init (System.ReadOnlySpan V_0, //span1 IL_009d: ldc.i4.8 IL_009e: newarr ""int"" IL_00a3: dup - IL_00a4: ldtoken "".__StaticArrayInitTypeSize=32 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F894"" + IL_00a4: ldtoken "".__StaticArrayInitTypeSize=32 .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F89"" IL_00a9: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00ae: dup IL_00af: stsfld ""int[] .71729EA83D1490C8B1B1F870F7CBA7FFBB490C71AF78C9015B49938A22E42F89_A6"" @@ -1266,32 +1267,32 @@ .locals init (System.ReadOnlySpan V_0, //span1 public static IEnumerable NonSize1Types_NoCreateSpan_UsesCachedArray_MemberData() { - yield return new object[] { "ushort", "ushort", "1", 1, "ldind.u2", "short", ".47DC540C94CEB704A23875C11273E16BB0B8A87AED84DE911F2133568115F254", "2", "_A13" }; - yield return new object[] { "ushort", "ushort", "1, 2", 2, "ldind.u2", "int", ".7B11C1133330CD161071BF23A0C9B6CE5320A8F3A0F83620035A72BE46DF4104", "2", "_A13" }; - yield return new object[] { "ushort", "ushort", "1, 2, 3, 4", 4, "ldind.u2", "long", ".EA99F710D9D0B8BA192295C969A63ED7CE8FC5743DA20D2057FA2B6D2C404BFB", "2", "_A13" }; - yield return new object[] { "uint", "uint", "1", 1, "ldind.u4", "int", ".67ABDD721024F0FF4E0B3F4C2FC13BC5BAD42D0B7851D456D88D203D15AAA450", "4", "_A14" }; - yield return new object[] { "uint", "uint", "1, 2", 2, "ldind.u4", "long", ".34FB5C825DE7CA4AEA6E712F19D439C1DA0C92C37B423936C5F618545CA4FA1F", "4", "_A14" }; - yield return new object[] { "ulong", "ulong", "1", 1, "ldind.i8", "long", ".7C9FA136D4413FA6173637E883B6998D32E1D675F88CDDFF9DCBCF331820F4B8", "8", "_A15" }; - yield return new object[] { "char", "char", "'a', 'b', 'c'", 3, "ldind.u2", ".__StaticArrayInitTypeSize=6", ".13E228567E8249FCE53337F25D7970DE3BD68AB2653424C7B8F9FD05E33CAEDF", "2", "_A1" }; - yield return new object[] { "int", "int", "1, 2, 3", 3, "ldind.i4", ".__StaticArrayInitTypeSize=12", ".4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D", "4", "_A6" }; - yield return new object[] { "uint", "uint", "1, 2, 3", 3, "ldind.u4", ".__StaticArrayInitTypeSize=12", ".4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D", "4", "_A14" }; - yield return new object[] { "short", "short", "1, 2, 3", 3, "ldind.i2", ".__StaticArrayInitTypeSize=6", ".047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF7", "2", "_A5" }; - yield return new object[] { "ushort", "ushort", "1, 2, 3", 3, "ldind.u2", ".__StaticArrayInitTypeSize=6", ".047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF7", "2", "_A13" }; - yield return new object[] { "long", "long", "1, 2, 3", 3, "ldind.i8", ".__StaticArrayInitTypeSize=24", ".E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF", "8", "_A7" }; - yield return new object[] { "ulong", "ulong", "1, 2, 3", 3, "ldind.i8", ".__StaticArrayInitTypeSize=24", ".E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF", "8", "_A15" }; - yield return new object[] { "float", "float", "1.0f, 2.0f, 3.0f", 3, "ldind.r4", ".__StaticArrayInitTypeSize=12", ".8E628779E6A74EE0B36991C10158F63CAFEC7D340AD4E075592502C8708524DD", "4", "_A3" }; - yield return new object[] { "double", "double", "1.0, 2.0, 3.0", 3, "ldind.r8", ".__StaticArrayInitTypeSize=24", ".A68DE4B5E96A60C8CEB3C7B7EF93461725BDBBFF3516B136585A743B5C0EC664", "8", "_A4" }; - yield return new object[] { "MyColor_Int16", "short", "MyColor_Int16.Red, MyColor_Int16.Blue", 2, "ldind.i2", "int", ".72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C60", "2", "_A5" }; - yield return new object[] { "MyColor_UInt16", "ushort", "MyColor_UInt16.Red, MyColor_UInt16.Blue", 2, "ldind.u2", "int", ".72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C60", "2", "_A13" }; - yield return new object[] { "MyColor_Int32", "int", "MyColor_Int32.Red, MyColor_Int32.Blue", 2, "ldind.i4", "long", ".1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B1", "4", "_A6" }; - yield return new object[] { "MyColor_UInt32", "uint", "MyColor_UInt32.Red, MyColor_UInt32.Blue", 2, "ldind.u4", "long", ".1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B1", "4", "_A14" }; - yield return new object[] { "MyColor_Int64", "long", "MyColor_Int64.Red, MyColor_Int64.Blue", 2, "ldind.i8", ".__StaticArrayInitTypeSize=16", ".F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E", "8", "_A7" }; - yield return new object[] { "MyColor_UInt64", "ulong", "MyColor_UInt64.Red, MyColor_UInt64.Blue", 2, "ldind.i8", ".__StaticArrayInitTypeSize=16", ".F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E", "8", "_A15" }; + yield return new object[] { "ushort", "ushort", "1", 1, "ldind.u2", "short", ".47DC540C94CEB704A23875C11273E16BB0B8A87AED84DE911F2133568115F254", "_A13" }; + yield return new object[] { "ushort", "ushort", "1, 2", 2, "ldind.u2", "int", ".7B11C1133330CD161071BF23A0C9B6CE5320A8F3A0F83620035A72BE46DF4104", "_A13" }; + yield return new object[] { "ushort", "ushort", "1, 2, 3, 4", 4, "ldind.u2", "long", ".EA99F710D9D0B8BA192295C969A63ED7CE8FC5743DA20D2057FA2B6D2C404BFB", "_A13" }; + yield return new object[] { "uint", "uint", "1", 1, "ldind.u4", "int", ".67ABDD721024F0FF4E0B3F4C2FC13BC5BAD42D0B7851D456D88D203D15AAA450", "_A14" }; + yield return new object[] { "uint", "uint", "1, 2", 2, "ldind.u4", "long", ".34FB5C825DE7CA4AEA6E712F19D439C1DA0C92C37B423936C5F618545CA4FA1F", "_A14" }; + yield return new object[] { "ulong", "ulong", "1", 1, "ldind.i8", "long", ".7C9FA136D4413FA6173637E883B6998D32E1D675F88CDDFF9DCBCF331820F4B8", "_A15" }; + yield return new object[] { "char", "char", "'a', 'b', 'c'", 3, "ldind.u2", ".__StaticArrayInitTypeSize=6", ".13E228567E8249FCE53337F25D7970DE3BD68AB2653424C7B8F9FD05E33CAEDF", "_A1" }; + yield return new object[] { "int", "int", "1, 2, 3", 3, "ldind.i4", ".__StaticArrayInitTypeSize=12", ".4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D", "_A6" }; + yield return new object[] { "uint", "uint", "1, 2, 3", 3, "ldind.u4", ".__StaticArrayInitTypeSize=12", ".4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D", "_A14" }; + yield return new object[] { "short", "short", "1, 2, 3", 3, "ldind.i2", ".__StaticArrayInitTypeSize=6", ".047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF7", "_A5" }; + yield return new object[] { "ushort", "ushort", "1, 2, 3", 3, "ldind.u2", ".__StaticArrayInitTypeSize=6", ".047DBF5366372631BA7E3E02520E651446B899C96C4B64663BAC378A298A7BF7", "_A13" }; + yield return new object[] { "long", "long", "1, 2, 3", 3, "ldind.i8", ".__StaticArrayInitTypeSize=24", ".E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF", "_A7" }; + yield return new object[] { "ulong", "ulong", "1, 2, 3", 3, "ldind.i8", ".__StaticArrayInitTypeSize=24", ".E2E2033AE7E19D680599D4EB0A1359A2B48EC5BAAC75066C317FBF85159C54EF", "_A15" }; + yield return new object[] { "float", "float", "1.0f, 2.0f, 3.0f", 3, "ldind.r4", ".__StaticArrayInitTypeSize=12", ".8E628779E6A74EE0B36991C10158F63CAFEC7D340AD4E075592502C8708524DD", "_A3" }; + yield return new object[] { "double", "double", "1.0, 2.0, 3.0", 3, "ldind.r8", ".__StaticArrayInitTypeSize=24", ".A68DE4B5E96A60C8CEB3C7B7EF93461725BDBBFF3516B136585A743B5C0EC664", "_A4" }; + yield return new object[] { "MyColor_Int16", "short", "MyColor_Int16.Red, MyColor_Int16.Blue", 2, "ldind.i2", "int", ".72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C60", "_A5" }; + yield return new object[] { "MyColor_UInt16", "ushort", "MyColor_UInt16.Red, MyColor_UInt16.Blue", 2, "ldind.u2", "int", ".72034DE8A594B12DE51205FEBA7ADE26899D8425E81EAC7F8C296BF974A51C60", "_A13" }; + yield return new object[] { "MyColor_Int32", "int", "MyColor_Int32.Red, MyColor_Int32.Blue", 2, "ldind.i4", "long", ".1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B1", "_A6" }; + yield return new object[] { "MyColor_UInt32", "uint", "MyColor_UInt32.Red, MyColor_UInt32.Blue", 2, "ldind.u4", "long", ".1B03AB083D0FB41E44D480F48D5BBA181C623C0594BDA1AA8EA71A3B67DBF3B1", "_A14" }; + yield return new object[] { "MyColor_Int64", "long", "MyColor_Int64.Red, MyColor_Int64.Blue", 2, "ldind.i8", ".__StaticArrayInitTypeSize=16", ".F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E", "_A7" }; + yield return new object[] { "MyColor_UInt64", "ulong", "MyColor_UInt64.Red, MyColor_UInt64.Blue", 2, "ldind.i8", ".__StaticArrayInitTypeSize=16", ".F7548C023E431138B11357593F5CCEB9DD35EB0B0A2041F0B1560212EEB6F13E", "_A15" }; } [Theory] [MemberData(nameof(NonSize1Types_NoCreateSpan_UsesCachedArray_MemberData))] - public void NonSize1Types_NoCreateSpan_UsesCachedArray(string type, string underlyingType, string args, int length, string ldind, string fieldType, string fieldName, string dataSuffix, string arraySuffix) + public void NonSize1Types_NoCreateSpan_UsesCachedArray(string type, string underlyingType, string args, int length, string ldind, string fieldType, string fieldName, string arraySuffix) { string csharp = @$" public enum MyColor_Byte : byte {{ Red, Orange, Yellow, Green, Blue }} @@ -1326,7 +1327,7 @@ .locals init (System.ReadOnlySpan<{type}> V_0) //s IL_0009: ldc.i4.{length} IL_000a: newarr ""{underlyingType}"" IL_000f: dup - IL_0010: ldtoken ""{fieldType} {fieldName}{dataSuffix}"" + IL_0010: ldtoken ""{fieldType} {fieldName}"" IL_0015: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_001a: dup IL_001b: stsfld ""{underlyingType}[] {fieldName}{arraySuffix}"" @@ -1380,7 +1381,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_0009: ldc.i4.8 IL_000a: newarr ""int"" IL_000f: dup - IL_0010: ldtoken "".__StaticArrayInitTypeSize=32 .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD404"" + IL_0010: ldtoken "".__StaticArrayInitTypeSize=32 .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD40"" IL_0015: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_001a: dup IL_001b: stsfld ""int[] .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD40_A6"" @@ -1393,7 +1394,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_002f: ldc.i4.8 IL_0030: newarr ""int"" IL_0035: dup - IL_0036: ldtoken "".__StaticArrayInitTypeSize=32 .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD404"" + IL_0036: ldtoken "".__StaticArrayInitTypeSize=32 .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD40"" IL_003b: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0040: dup IL_0041: stsfld ""int[] .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD40_A6"" @@ -1406,7 +1407,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_0055: ldc.i4.8 IL_0056: newarr ""int"" IL_005b: dup - IL_005c: ldtoken "".__StaticArrayInitTypeSize=32 .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD404"" + IL_005c: ldtoken "".__StaticArrayInitTypeSize=32 .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD40"" IL_0061: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0066: dup IL_0067: stsfld ""int[] .FF1F6EE5D67458CFAC950F62E93042E21FCB867E2234DCC8721801231064AD40_A6"" @@ -1613,50 +1614,361 @@ public static void Main() compilation.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpanRuntimeFieldHandle); var verifier = CompileAndVerify(compilation, expectedOutput: "340", verify: Verification.Skipped); verifier.VerifyIL("Test.Main", @$"{{ - // Code size 102 (0x66) - .maxstack 3 - .locals init (System.ReadOnlySpan V_0, //s1 + // Code size 102 (0x66) + .maxstack 3 + .locals init (System.ReadOnlySpan V_0, //s1 System.ReadOnlySpan V_1, //s2 System.ReadOnlySpan V_2) //s3 - IL_0000: ldloca.s V_0 - IL_0002: ldsflda "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" - IL_0007: ldc.i4.3 - IL_0008: call ""System.ReadOnlySpan..ctor(void*, int)"" - IL_000d: ldloc.0 - IL_000e: call ""void Test.Print(System.ReadOnlySpan)"" - IL_0013: ldloca.s V_0 - IL_0015: call ""bool System.ReadOnlySpan.IsEmpty.get"" - IL_001a: pop - IL_001b: ldsfld ""int[] .CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72_A6"" - IL_0020: dup - IL_0021: brtrue.s IL_003b - IL_0023: pop - IL_0024: ldc.i4.4 - IL_0025: newarr ""int"" - IL_002a: dup - IL_002b: ldtoken "".__StaticArrayInitTypeSize=16 .CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B724"" - IL_0030: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" - IL_0035: dup - IL_0036: stsfld ""int[] .CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72_A6"" - IL_003b: newobj ""System.ReadOnlySpan..ctor(int[])"" - IL_0040: dup - IL_0041: stloc.1 - IL_0042: call ""void Test.Print(System.ReadOnlySpan)"" - IL_0047: ldloca.s V_1 - IL_0049: call ""bool System.ReadOnlySpan.IsEmpty.get"" - IL_004e: pop - IL_004f: ldloca.s V_2 - IL_0051: initobj ""System.ReadOnlySpan"" - IL_0057: ldloc.2 - IL_0058: call ""void Test.Print(System.ReadOnlySpan)"" - IL_005d: ldloca.s V_2 - IL_005f: call ""bool System.ReadOnlySpan.IsEmpty.get"" - IL_0064: pop - IL_0065: ret + IL_0000: ldloca.s V_0 + IL_0002: ldsflda "".__StaticArrayInitTypeSize=3 .039058C6F2C0CB492C533B0A4D14EF77CC0F78ABCCCED5287D84A1A2011CFB81"" + IL_0007: ldc.i4.3 + IL_0008: call ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000d: ldloc.0 + IL_000e: call ""void Test.Print(System.ReadOnlySpan)"" + IL_0013: ldloca.s V_0 + IL_0015: call ""bool System.ReadOnlySpan.IsEmpty.get"" + IL_001a: pop + IL_001b: ldsfld ""int[] .CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72_A6"" + IL_0020: dup + IL_0021: brtrue.s IL_003b + IL_0023: pop + IL_0024: ldc.i4.4 + IL_0025: newarr ""int"" + IL_002a: dup + IL_002b: ldtoken "".__StaticArrayInitTypeSize=16 .CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72"" + IL_0030: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_0035: dup + IL_0036: stsfld ""int[] .CF97ADEEDB59E05BFD73A2B4C2A8885708C4F4F70C84C64B27120E72AB733B72_A6"" + IL_003b: newobj ""System.ReadOnlySpan..ctor(int[])"" + IL_0040: dup + IL_0041: stloc.1 + IL_0042: call ""void Test.Print(System.ReadOnlySpan)"" + IL_0047: ldloca.s V_1 + IL_0049: call ""bool System.ReadOnlySpan.IsEmpty.get"" + IL_004e: pop + IL_004f: ldloca.s V_2 + IL_0051: initobj ""System.ReadOnlySpan"" + IL_0057: ldloc.2 + IL_0058: call ""void Test.Print(System.ReadOnlySpan)"" + IL_005d: ldloca.s V_2 + IL_005f: call ""bool System.ReadOnlySpan.IsEmpty.get"" + IL_0064: pop + IL_0065: ret }} "); } + [ConditionalFact(typeof(CoreClrOnly))] + public void MultipleNonSize1Types_EqualDataBlobs_HasCreateSpan_EveryAlignmentGetsUniqueTypeAndBlob() + { + var source = @" +using System; + +class Test +{ + public static void Main() + { + var s1 = (ReadOnlySpan)new sbyte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + var s2 = (ReadOnlySpan)new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; + var s3 = (ReadOnlySpan)new short[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; + var s4 = (ReadOnlySpan)new ushort[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + var s5 = (ReadOnlySpan)new int[] { -1, -1, -1, -1, -1, -1, -1, -1 }; + var s6 = (ReadOnlySpan)new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + var s7 = (ReadOnlySpan)new long[] { -1, -1, -1, -1 }; + var s8 = (ReadOnlySpan)new ulong[] { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; + var s9 = (ReadOnlySpan)new char[] { '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF', '\uFFFF' }; + + long sum = 0; + foreach (var v1 in s1) sum += v1; + foreach (var v2 in s2) sum += v2; + foreach (var v3 in s3) sum += v3; + foreach (var v4 in s4) sum += v4; + foreach (var v5 in s5) sum += v5; + foreach (var v6 in s6) sum += v6; + foreach (var v7 in s7) sum += v7; + foreach (var v8 in s8) sum += (long)v8; + foreach (var v9 in s9) sum += v9; + + Console.Write(sum); + } +} +"; + CompileAndVerify(source, expectedOutput: "34361843576", verify: Verification.Skipped, targetFramework: TargetFramework.Net70).VerifyIL("Test.Main", @" +{ + // Code size 528 (0x210) + .maxstack 2 + .locals init (System.ReadOnlySpan V_0, //s1 + System.ReadOnlySpan V_1, //s2 + System.ReadOnlySpan V_2, //s3 + System.ReadOnlySpan V_3, //s4 + System.ReadOnlySpan V_4, //s5 + System.ReadOnlySpan V_5, //s6 + System.ReadOnlySpan V_6, //s7 + System.ReadOnlySpan V_7, //s8 + System.ReadOnlySpan V_8, //s9 + long V_9, //sum + System.ReadOnlySpan V_10, + int V_11, + sbyte V_12, //v1 + System.ReadOnlySpan V_13, + byte V_14, //v2 + System.ReadOnlySpan V_15, + short V_16, //v3 + System.ReadOnlySpan V_17, + ushort V_18, //v4 + System.ReadOnlySpan V_19, + int V_20, //v5 + System.ReadOnlySpan V_21, + uint V_22, //v6 + System.ReadOnlySpan V_23, + long V_24, //v7 + System.ReadOnlySpan V_25, + ulong V_26, //v8 + System.ReadOnlySpan V_27, + char V_28) //v9 + IL_0000: ldsflda "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" + IL_0005: ldc.i4.s 32 + IL_0007: newobj ""System.ReadOnlySpan..ctor(void*, int)"" + IL_000c: stloc.0 + IL_000d: ldsflda "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" + IL_0012: ldc.i4.s 32 + IL_0014: newobj ""System.ReadOnlySpan..ctor(void*, int)"" + IL_0019: stloc.1 + IL_001a: ldtoken "".__StaticArrayInitTypeSize=32_Align=2 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512"" + IL_001f: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_0024: stloc.2 + IL_0025: ldtoken "".__StaticArrayInitTypeSize=32_Align=2 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512"" + IL_002a: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_002f: stloc.3 + IL_0030: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40514"" + IL_0035: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_003a: stloc.s V_4 + IL_003c: ldtoken "".__StaticArrayInitTypeSize=32_Align=4 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40514"" + IL_0041: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_0046: stloc.s V_5 + IL_0048: ldtoken "".__StaticArrayInitTypeSize=32_Align=8 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40518"" + IL_004d: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_0052: stloc.s V_6 + IL_0054: ldtoken "".__StaticArrayInitTypeSize=32_Align=8 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40518"" + IL_0059: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_005e: stloc.s V_7 + IL_0060: ldtoken "".__StaticArrayInitTypeSize=32_Align=2 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512"" + IL_0065: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_006a: stloc.s V_8 + IL_006c: ldc.i4.0 + IL_006d: conv.i8 + IL_006e: stloc.s V_9 + IL_0070: ldloc.0 + IL_0071: stloc.s V_10 + IL_0073: ldc.i4.0 + IL_0074: stloc.s V_11 + IL_0076: br.s IL_0092 + IL_0078: ldloca.s V_10 + IL_007a: ldloc.s V_11 + IL_007c: call ""ref readonly sbyte System.ReadOnlySpan.this[int].get"" + IL_0081: ldind.i1 + IL_0082: stloc.s V_12 + IL_0084: ldloc.s V_9 + IL_0086: ldloc.s V_12 + IL_0088: conv.i8 + IL_0089: add + IL_008a: stloc.s V_9 + IL_008c: ldloc.s V_11 + IL_008e: ldc.i4.1 + IL_008f: add + IL_0090: stloc.s V_11 + IL_0092: ldloc.s V_11 + IL_0094: ldloca.s V_10 + IL_0096: call ""int System.ReadOnlySpan.Length.get"" + IL_009b: blt.s IL_0078 + IL_009d: ldloc.1 + IL_009e: stloc.s V_13 + IL_00a0: ldc.i4.0 + IL_00a1: stloc.s V_11 + IL_00a3: br.s IL_00bf + IL_00a5: ldloca.s V_13 + IL_00a7: ldloc.s V_11 + IL_00a9: call ""ref readonly byte System.ReadOnlySpan.this[int].get"" + IL_00ae: ldind.u1 + IL_00af: stloc.s V_14 + IL_00b1: ldloc.s V_9 + IL_00b3: ldloc.s V_14 + IL_00b5: conv.u8 + IL_00b6: add + IL_00b7: stloc.s V_9 + IL_00b9: ldloc.s V_11 + IL_00bb: ldc.i4.1 + IL_00bc: add + IL_00bd: stloc.s V_11 + IL_00bf: ldloc.s V_11 + IL_00c1: ldloca.s V_13 + IL_00c3: call ""int System.ReadOnlySpan.Length.get"" + IL_00c8: blt.s IL_00a5 + IL_00ca: ldloc.2 + IL_00cb: stloc.s V_15 + IL_00cd: ldc.i4.0 + IL_00ce: stloc.s V_11 + IL_00d0: br.s IL_00ec + IL_00d2: ldloca.s V_15 + IL_00d4: ldloc.s V_11 + IL_00d6: call ""ref readonly short System.ReadOnlySpan.this[int].get"" + IL_00db: ldind.i2 + IL_00dc: stloc.s V_16 + IL_00de: ldloc.s V_9 + IL_00e0: ldloc.s V_16 + IL_00e2: conv.i8 + IL_00e3: add + IL_00e4: stloc.s V_9 + IL_00e6: ldloc.s V_11 + IL_00e8: ldc.i4.1 + IL_00e9: add + IL_00ea: stloc.s V_11 + IL_00ec: ldloc.s V_11 + IL_00ee: ldloca.s V_15 + IL_00f0: call ""int System.ReadOnlySpan.Length.get"" + IL_00f5: blt.s IL_00d2 + IL_00f7: ldloc.3 + IL_00f8: stloc.s V_17 + IL_00fa: ldc.i4.0 + IL_00fb: stloc.s V_11 + IL_00fd: br.s IL_0119 + IL_00ff: ldloca.s V_17 + IL_0101: ldloc.s V_11 + IL_0103: call ""ref readonly ushort System.ReadOnlySpan.this[int].get"" + IL_0108: ldind.u2 + IL_0109: stloc.s V_18 + IL_010b: ldloc.s V_9 + IL_010d: ldloc.s V_18 + IL_010f: conv.u8 + IL_0110: add + IL_0111: stloc.s V_9 + IL_0113: ldloc.s V_11 + IL_0115: ldc.i4.1 + IL_0116: add + IL_0117: stloc.s V_11 + IL_0119: ldloc.s V_11 + IL_011b: ldloca.s V_17 + IL_011d: call ""int System.ReadOnlySpan.Length.get"" + IL_0122: blt.s IL_00ff + IL_0124: ldloc.s V_4 + IL_0126: stloc.s V_19 + IL_0128: ldc.i4.0 + IL_0129: stloc.s V_11 + IL_012b: br.s IL_0147 + IL_012d: ldloca.s V_19 + IL_012f: ldloc.s V_11 + IL_0131: call ""ref readonly int System.ReadOnlySpan.this[int].get"" + IL_0136: ldind.i4 + IL_0137: stloc.s V_20 + IL_0139: ldloc.s V_9 + IL_013b: ldloc.s V_20 + IL_013d: conv.i8 + IL_013e: add + IL_013f: stloc.s V_9 + IL_0141: ldloc.s V_11 + IL_0143: ldc.i4.1 + IL_0144: add + IL_0145: stloc.s V_11 + IL_0147: ldloc.s V_11 + IL_0149: ldloca.s V_19 + IL_014b: call ""int System.ReadOnlySpan.Length.get"" + IL_0150: blt.s IL_012d + IL_0152: ldloc.s V_5 + IL_0154: stloc.s V_21 + IL_0156: ldc.i4.0 + IL_0157: stloc.s V_11 + IL_0159: br.s IL_0175 + IL_015b: ldloca.s V_21 + IL_015d: ldloc.s V_11 + IL_015f: call ""ref readonly uint System.ReadOnlySpan.this[int].get"" + IL_0164: ldind.u4 + IL_0165: stloc.s V_22 + IL_0167: ldloc.s V_9 + IL_0169: ldloc.s V_22 + IL_016b: conv.u8 + IL_016c: add + IL_016d: stloc.s V_9 + IL_016f: ldloc.s V_11 + IL_0171: ldc.i4.1 + IL_0172: add + IL_0173: stloc.s V_11 + IL_0175: ldloc.s V_11 + IL_0177: ldloca.s V_21 + IL_0179: call ""int System.ReadOnlySpan.Length.get"" + IL_017e: blt.s IL_015b + IL_0180: ldloc.s V_6 + IL_0182: stloc.s V_23 + IL_0184: ldc.i4.0 + IL_0185: stloc.s V_11 + IL_0187: br.s IL_01a2 + IL_0189: ldloca.s V_23 + IL_018b: ldloc.s V_11 + IL_018d: call ""ref readonly long System.ReadOnlySpan.this[int].get"" + IL_0192: ldind.i8 + IL_0193: stloc.s V_24 + IL_0195: ldloc.s V_9 + IL_0197: ldloc.s V_24 + IL_0199: add + IL_019a: stloc.s V_9 + IL_019c: ldloc.s V_11 + IL_019e: ldc.i4.1 + IL_019f: add + IL_01a0: stloc.s V_11 + IL_01a2: ldloc.s V_11 + IL_01a4: ldloca.s V_23 + IL_01a6: call ""int System.ReadOnlySpan.Length.get"" + IL_01ab: blt.s IL_0189 + IL_01ad: ldloc.s V_7 + IL_01af: stloc.s V_25 + IL_01b1: ldc.i4.0 + IL_01b2: stloc.s V_11 + IL_01b4: br.s IL_01cf + IL_01b6: ldloca.s V_25 + IL_01b8: ldloc.s V_11 + IL_01ba: call ""ref readonly ulong System.ReadOnlySpan.this[int].get"" + IL_01bf: ldind.i8 + IL_01c0: stloc.s V_26 + IL_01c2: ldloc.s V_9 + IL_01c4: ldloc.s V_26 + IL_01c6: add + IL_01c7: stloc.s V_9 + IL_01c9: ldloc.s V_11 + IL_01cb: ldc.i4.1 + IL_01cc: add + IL_01cd: stloc.s V_11 + IL_01cf: ldloc.s V_11 + IL_01d1: ldloca.s V_25 + IL_01d3: call ""int System.ReadOnlySpan.Length.get"" + IL_01d8: blt.s IL_01b6 + IL_01da: ldloc.s V_8 + IL_01dc: stloc.s V_27 + IL_01de: ldc.i4.0 + IL_01df: stloc.s V_11 + IL_01e1: br.s IL_01fd + IL_01e3: ldloca.s V_27 + IL_01e5: ldloc.s V_11 + IL_01e7: call ""ref readonly char System.ReadOnlySpan.this[int].get"" + IL_01ec: ldind.u2 + IL_01ed: stloc.s V_28 + IL_01ef: ldloc.s V_9 + IL_01f1: ldloc.s V_28 + IL_01f3: conv.u8 + IL_01f4: add + IL_01f5: stloc.s V_9 + IL_01f7: ldloc.s V_11 + IL_01f9: ldc.i4.1 + IL_01fa: add + IL_01fb: stloc.s V_11 + IL_01fd: ldloc.s V_11 + IL_01ff: ldloca.s V_27 + IL_0201: call ""int System.ReadOnlySpan.Length.get"" + IL_0206: blt.s IL_01e3 + IL_0208: ldloc.s V_9 + IL_020a: call ""void System.Console.Write(long)"" + IL_020f: ret +}"); + } + [Fact] public void MultipleNonSize1Types_EqualDataBlobs_NoCreateSpan_UsesCachedArray_EveryTypeGetsUniqueField() { @@ -1742,7 +2054,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_0023: ldc.i4.s 16 IL_0025: newarr ""short"" IL_002a: dup - IL_002b: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512"" + IL_002b: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_0030: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0035: dup IL_0036: stsfld ""short[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A5"" @@ -1755,7 +2067,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_004a: ldc.i4.s 16 IL_004c: newarr ""ushort"" IL_0051: dup - IL_0052: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512"" + IL_0052: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_0057: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_005c: dup IL_005d: stsfld ""ushort[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A13"" @@ -1768,7 +2080,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_0071: ldc.i4.8 IL_0072: newarr ""int"" IL_0077: dup - IL_0078: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40514"" + IL_0078: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_007d: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_0082: dup IL_0083: stsfld ""int[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A6"" @@ -1781,7 +2093,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_0098: ldc.i4.8 IL_0099: newarr ""uint"" IL_009e: dup - IL_009f: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40514"" + IL_009f: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_00a4: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00a9: dup IL_00aa: stsfld ""uint[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A14"" @@ -1794,7 +2106,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_00bf: ldc.i4.4 IL_00c0: newarr ""long"" IL_00c5: dup - IL_00c6: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40518"" + IL_00c6: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_00cb: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00d0: dup IL_00d1: stsfld ""long[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A7"" @@ -1807,7 +2119,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_00e6: ldc.i4.4 IL_00e7: newarr ""ulong"" IL_00ec: dup - IL_00ed: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40518"" + IL_00ed: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_00f2: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_00f7: dup IL_00f8: stsfld ""ulong[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A15"" @@ -1820,7 +2132,7 @@ .locals init (System.ReadOnlySpan V_0, //s1 IL_010d: ldc.i4.s 16 IL_010f: newarr ""char"" IL_0114: dup - IL_0115: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512"" + IL_0115: ldtoken "".__StaticArrayInitTypeSize=32 .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051"" IL_011a: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" IL_011f: dup IL_0120: stsfld ""char[] .AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051_A1"" @@ -2227,15 +2539,22 @@ .maxstack 1 [Theory] [InlineData("byte", 1)] + [InlineData("sbyte", 1)] [InlineData("short", 2)] + [InlineData("ushort", 2)] [InlineData("int", 4)] + [InlineData("uint", 4)] + [InlineData("float", 4)] [InlineData("long", 8)] + [InlineData("ulong", 8)] + [InlineData("double", 8)] + [InlineData("System.DayOfWeek", 4)] public void Alignment_FieldsAreAlignedAndPackedAccordingToType(string typeName, int expectedAlignment) { string csharp = RuntimeHelpersCreateSpan + $@" public class Test {{ - public static System.ReadOnlySpan<{typeName}> Data => new {typeName}[] {{ 1, 2, 3 }}; + public static System.ReadOnlySpan<{typeName}> Data => new[] {{ ({typeName})1, ({typeName})2, ({typeName})3 }}; }}"; var compilation = CreateCompilation(csharp, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeReleaseDll); @@ -2250,5 +2569,55 @@ public class Test Assert.True(rva % expectedAlignment == 0, $"Expected RVA {rva:X8} to be {expectedAlignment}-byte aligned."); }); } + + [Theory] + [InlineData("byte", 1, false)] + [InlineData("byte", 2, false)] + [InlineData("byte", 3, true)] + [InlineData("byte", 4, false)] + [InlineData("byte", 8, false)] + [InlineData("byte", 9, true)] + [InlineData("sbyte", 1, false)] + [InlineData("sbyte", 2, false)] + [InlineData("sbyte", 4, false)] + [InlineData("short", 1, true)] + [InlineData("short", 2, true)] + [InlineData("short", 3, true)] + [InlineData("short", 4, true)] + [InlineData("ushort", 1, true)] + [InlineData("ushort", 4, true)] + [InlineData("int", 1, true)] + [InlineData("int", 2, true)] + [InlineData("int", 3, true)] + [InlineData("int", 4, true)] + [InlineData("uint", 1, true)] + [InlineData("uint", 2, true)] + [InlineData("System.DayOfWeek", 1, true)] + [InlineData("System.DayOfWeek", 2, true)] + [InlineData("long", 1, true)] + [InlineData("long", 2, true)] + public void AlignmentImpactsStaticArrayTypeCreation_BuiltInTypesOnlyUsedForSize1Types(string typeName, int numValues, bool shouldGenerateType) + { + string values = string.Join(", ", Enumerable.Range(1, numValues).Select(i => $"({typeName}){i}")); + string csharp = RuntimeHelpersCreateSpan + $@" +public class Test +{{ + public static System.ReadOnlySpan<{typeName}> Data => new[] {{ {values} }}; +}}"; + + var compilation = CreateCompilation(csharp, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeReleaseDll); + var verifier = CompileAndVerify(compilation, verify: Verification.Skipped); + verifier.VerifyTypeIL("", il => + { + if (shouldGenerateType) + { + Assert.Contains("__StaticArrayInitTypeSize=", il); + } + else + { + Assert.DoesNotContain("__StaticArrayInitTypeSize=", il); + } + }); + } } } diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index ed5d7a188dd72..e16973f907652 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -80,13 +80,27 @@ internal void EmitSourceDocumentIndexToken(Cci.DebugSourceDocument document) this.GetCurrentWriter().WriteUInt32((module?.GetSourceDocumentIndexForIL(document) ?? 0xFFFF) | Cci.MetadataWriter.SourceDocumentIndex); } - internal void EmitArrayBlockInitializer(ImmutableArray data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics) - { + internal void EmitArrayBlockInitializer(ImmutableArray data, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + { + // Emit the call to RuntimeHelpers.InitializeArray, creating the necessary metadata blob if there isn't + // already one for this data. Note that this specifies an alignment of 1. This is valid regardless of + // the kind of data stored in the array, as it's never accessed directly in the blob; rather, InitializeArray + // copies out the data as bytes. The upside to keeping this as 1 is it means no special alignment is required. + // Although the compiler currently always aligns the metadata fields at an 8-byte boundary, the .pack field + // is appropriately set to the alignment value, and a rewriter (e.g. illink) may respect that. If the alignment + // value were to be increased to match the actual alignment requirements of the element type, that could cause + // such rewritten binaries to regress in size due to the extra padding necessary for aligning. The downside + // to keeping this as 1 is that this data won't unify with any blobs created for spans (RuntimeHelpers.CreateSpan). + // Code typically does directly read from the blobs via spans, and as such alignment there is required to be + // at least what the element type requires. That means if the same data/element type is used with an array + // and separately with a span, the data will exist duplicated in two different blobs. If it turns out that's + // very common, this can be revised in the future to specify the element type's alignment. + // get helpers var initializeArray = module.GetInitArrayHelper(); // map a field to the block (that makes it addressable via a token). - var field = module.GetFieldForData(data, alignment, syntaxNode, diagnostics); + var field = module.GetFieldForData(data, alignment: 1, syntaxNode, diagnostics); // emit call to the helper EmitOpCode(ILOpCode.Dup); //array diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index b268f62a7cf94..c25842e789211 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -147,7 +147,7 @@ internal void Freeze() _orderedSynthesizedMethods = _synthesizedMethods.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value).AsImmutable(); // Sort proxy types. - _orderedProxyTypes = _proxyTypes.OrderBy(kvp => kvp.Key.Size).Select(kvp => kvp.Value).AsImmutable(); + _orderedProxyTypes = _proxyTypes.OrderBy(kvp => kvp.Key.Size).ThenBy(kvp => kvp.Key.Alignment).Select(kvp => kvp.Value).AsImmutable(); } private bool IsFrozen => _frozen != 0; @@ -210,10 +210,14 @@ internal Cci.IFieldReference CreateDataField(ImmutableArray data, ushort a ((uint)data.Length, Alignment: alignment), key => key.Size switch { + // We need a type with the same size as the data. If the size of the data is + // 2, 4, or 8 bytes, we can use short, int, or long rather than creating a custom + // type, but we can only do so if the required alignment is also 1, as these types + // have a .pack value of 1. 1 when _systemInt8Type is not null => _systemInt8Type, - 2 when _systemInt16Type is not null => _systemInt16Type, - 4 when _systemInt32Type is not null => _systemInt32Type, - 8 when _systemInt64Type is not null => _systemInt64Type, + 2 when key.Alignment == 1 && _systemInt16Type is not null => _systemInt16Type, + 4 when key.Alignment == 1 && _systemInt32Type is not null => _systemInt32Type, + 8 when key.Alignment == 1 && _systemInt64Type is not null => _systemInt64Type, _ => new ExplicitSizeStruct(key.Size, key.Alignment, this, _systemValueType) }); @@ -433,7 +437,9 @@ public override void Dispatch(Cci.MetadataVisitor visitor) visitor.Visit(this); } - public string Name => "__StaticArrayInitTypeSize=" + _size; + public string Name => _alignment == 1 ? + $"__StaticArrayInitTypeSize={_size}" : + $"__StaticArrayInitTypeSize={_size}_Align={_alignment}"; public Cci.ITypeDefinition ContainingTypeDefinition => _containingType; diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb index 7088f43d59dcc..b90b95c6c2ccb 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb @@ -41,7 +41,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen If initializationStyle = ArrayInitializerStyle.Element Then Me.EmitElementInitializers(arrayType, initExprs, True) Else - _builder.EmitArrayBlockInitializer(Me.GetRawData(initExprs), 1, inits.Syntax, _diagnostics) ' alignment == 1 as there's no special need for alignment (.pack) here. + _builder.EmitArrayBlockInitializer(Me.GetRawData(initExprs), inits.Syntax, _diagnostics) If initializationStyle = ArrayInitializerStyle.Mixed Then EmitElementInitializers(arrayType, initExprs, False) From 0804eab3e8bed5696682a47a0412083ec3efeba6 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 10 Dec 2022 13:16:15 -0500 Subject: [PATCH 2/3] Address PR feedback --- .../CodeGenReadOnlySpanConstructionTest.cs | 213 ++++++++++++++++++ .../CodeGen/PrivateImplementationDetails.cs | 54 +++-- 2 files changed, 248 insertions(+), 19 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs index ef11eb86fa93f..acdafa884c5b4 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs @@ -2619,5 +2619,218 @@ public class Test } }); } + + [Fact] + public void PrivateImplementationDetails_TypesOrderedBySizeThenAlignment() + { + string csharp = RuntimeHelpersCreateSpan + @" +class Test +{ + public static int M() + { + var s1 = (System.ReadOnlySpan)new ushort[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + var s2 = (System.ReadOnlySpan)new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; + var s3 = (System.ReadOnlySpan)new ulong[] { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; + var s4 = (System.ReadOnlySpan)new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + + var s5 = (System.ReadOnlySpan)new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }; + var s6 = (System.ReadOnlySpan)new ushort[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + var s7 = (System.ReadOnlySpan)new uint[] { 0xFFFFFFFF, 0xFFFFFFFF }; + var s8 = (System.ReadOnlySpan)new ulong[] { 0xFFFFFFFFFFFFFFFF }; + + var s9 = (System.ReadOnlySpan)new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + var s10 = (System.ReadOnlySpan)new ulong[] { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; + var s11 = (System.ReadOnlySpan)new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; + var s12 = (System.ReadOnlySpan)new ushort[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + + var s13 = (System.ReadOnlySpan)new ulong[] { 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF }; + var s14 = (System.ReadOnlySpan)new uint[] { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + var s15 = (System.ReadOnlySpan)new ushort[] { 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }; + var s16 = (System.ReadOnlySpan)new byte[] { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }; + + return + s1.Length + s2.Length + s3.Length + s4.Length + + s5.Length + s6.Length + s7.Length + s8.Length + + s9.Length + s10.Length + s11.Length + s12.Length + + s13.Length + s14.Length + s15.Length + s16.Length; + } +} +"; + var compilation = CreateCompilation(csharp, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeReleaseDll); + var verifier = CompileAndVerify(compilation, verify: Verification.Skipped); + verifier.VerifyTypeIL("", @" +.class private auto ansi sealed '' + extends [System.Runtime]System.Object +{ + .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Nested Types + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=8_Align=2' + extends [System.Runtime]System.ValueType + { + .pack 2 + .size 8 + } // end of class __StaticArrayInitTypeSize=8_Align=2 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=8_Align=4' + extends [System.Runtime]System.ValueType + { + .pack 4 + .size 8 + } // end of class __StaticArrayInitTypeSize=8_Align=4 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=8_Align=8' + extends [System.Runtime]System.ValueType + { + .pack 8 + .size 8 + } // end of class __StaticArrayInitTypeSize=8_Align=8 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16' + extends [System.Runtime]System.ValueType + { + .pack 1 + .size 16 + } // end of class __StaticArrayInitTypeSize=16 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16_Align=2' + extends [System.Runtime]System.ValueType + { + .pack 2 + .size 16 + } // end of class __StaticArrayInitTypeSize=16_Align=2 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16_Align=4' + extends [System.Runtime]System.ValueType + { + .pack 4 + .size 16 + } // end of class __StaticArrayInitTypeSize=16_Align=4 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16_Align=8' + extends [System.Runtime]System.ValueType + { + .pack 8 + .size 16 + } // end of class __StaticArrayInitTypeSize=16_Align=8 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24' + extends [System.Runtime]System.ValueType + { + .pack 1 + .size 24 + } // end of class __StaticArrayInitTypeSize=24 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24_Align=2' + extends [System.Runtime]System.ValueType + { + .pack 2 + .size 24 + } // end of class __StaticArrayInitTypeSize=24_Align=2 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24_Align=4' + extends [System.Runtime]System.ValueType + { + .pack 4 + .size 24 + } // end of class __StaticArrayInitTypeSize=24_Align=4 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24_Align=8' + extends [System.Runtime]System.ValueType + { + .pack 8 + .size 24 + } // end of class __StaticArrayInitTypeSize=24_Align=8 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32' + extends [System.Runtime]System.ValueType + { + .pack 1 + .size 32 + } // end of class __StaticArrayInitTypeSize=32 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32_Align=2' + extends [System.Runtime]System.ValueType + { + .pack 2 + .size 32 + } // end of class __StaticArrayInitTypeSize=32_Align=2 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32_Align=4' + extends [System.Runtime]System.ValueType + { + .pack 4 + .size 32 + } // end of class __StaticArrayInitTypeSize=32_Align=4 + .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32_Align=8' + extends [System.Runtime]System.ValueType + { + .pack 8 + .size 32 + } // end of class __StaticArrayInitTypeSize=32_Align=8 + // Fields + .field assembly static initonly int64 '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA' at I_00003358 + .data cil I_00003358 = bytearray ( + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=8_Align=2' '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA2' at I_00003360 + .data cil I_00003360 = bytearray ( + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=8_Align=4' '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA4' at I_00003368 + .data cil I_00003368 = bytearray ( + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=8_Align=8' '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA8' at I_00003370 + .data cil I_00003370 = bytearray ( + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B6' at I_00003378 + .data cil I_00003378 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24_Align=2' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B62' at I_00003390 + .data cil I_00003390 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24_Align=4' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B64' at I_000033A8 + .data cil I_000033A8 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24_Align=8' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B68' at I_000033C0 + .data cil I_000033C0 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B' at I_000033D8 + .data cil I_000033D8 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16_Align=2' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B2' at I_000033E8 + .data cil I_000033E8 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16_Align=4' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B4' at I_000033F8 + .data cil I_000033F8 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16_Align=8' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B8' at I_00003408 + .data cil I_00003408 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051 at I_00003418 + .data cil I_00003418 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32_Align=2' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512 at I_00003438 + .data cil I_00003438 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32_Align=4' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40514 at I_00003458 + .data cil I_00003458 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) + .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32_Align=8' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40518 at I_00003478 + .data cil I_00003478 = bytearray ( + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff + ) +} // end of class + "); + } } } diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index c25842e789211..11f25f24f1fd6 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -189,15 +189,13 @@ Cci.PrimitiveTypeCode.Int32 or Cci.PrimitiveTypeCode.UInt32 or Cci.PrimitiveType /// The data for the field. /// /// The alignment value is the necessary alignment for addresses for the underlying element type of the array. - /// The data is stored by using a type whose size is equal to the total size of the blob. When the total size - /// of the data is 1, 2, 4, or 8 bytes, a byte, short, int, or long can be used as the type of the field, and - /// regardless of what the element type is for the data, it's guaranteed to have appropriate alignment. For - /// all other sizes, a type is generated of the same size as the data, and that type needs its .pack set to - /// the alignment required for the underlying data. While that .pack value isn't required by anything else - /// in the compiler (the compiler always aligns RVA fields at 8-byte boundaries, which accomodates any - /// element type that's relevant), it is necessary for IL rewriters. Such rewriters also need to ensure - /// an appropriate alignment is maintained for the RVA field, and while they could also simplify by choosing - /// a worst-case alignment as does the compiler, they may instead use the .pack value as the alignment + /// The data is stored by using a type whose size is equal to the total size of the blob. If a built-in system + /// type has an appropriate size and .pack, it can be used. Otherwise, a type is generated of the same size as + /// the data, and that type needs its .pack set to the alignment required for the underlying data. While that + /// .pack value isn't required by anything else in the compiler (the compiler always aligns RVA fields at 8-byte + /// boundaries, which accomodates any element type that's relevant), it is necessary for IL rewriters. Such rewriters + /// also need to ensure an appropriate alignment is maintained for the RVA field, and while they could also simplify + /// by choosing a worst-case alignment as does the compiler, they may instead use the .pack value as the alignment /// to use for that field, since it's an opaque blob with no other indication as to what kind of data is /// stored and what alignment might be required. /// @@ -208,17 +206,35 @@ internal Cci.IFieldReference CreateDataField(ImmutableArray data, ushort a Cci.ITypeReference type = _proxyTypes.GetOrAdd( ((uint)data.Length, Alignment: alignment), key => - key.Size switch { - // We need a type with the same size as the data. If the size of the data is - // 2, 4, or 8 bytes, we can use short, int, or long rather than creating a custom - // type, but we can only do so if the required alignment is also 1, as these types - // have a .pack value of 1. - 1 when _systemInt8Type is not null => _systemInt8Type, - 2 when key.Alignment == 1 && _systemInt16Type is not null => _systemInt16Type, - 4 when key.Alignment == 1 && _systemInt32Type is not null => _systemInt32Type, - 8 when key.Alignment == 1 && _systemInt64Type is not null => _systemInt64Type, - _ => new ExplicitSizeStruct(key.Size, key.Alignment, this, _systemValueType) + // We need a type that's both the same size as the data and that has a .pack + // that matches the data's alignment requirements. + + if (key.Size == 1) + { + // Data of size 1 must be a single element of one-byte-sized type, + // which has no alignment requirements. + Debug.Assert(alignment == 1); + if (_systemInt8Type is not null) + { + return _systemInt8Type; + } + } + else if (key.Alignment == 1) + { + // If the size of the data is 2, 4, or 8 bytes, we can use short, int, or long rather than + // creating a custom type, but we can only do so if the required alignment is also 1, as + // these types have a .pack value of 1. + switch (key.Size) + { + case 2 when _systemInt16Type is not null: return _systemInt16Type; + case 4 when _systemInt32Type is not null: return _systemInt32Type; + case 8 when _systemInt64Type is not null: return _systemInt64Type; + } + } + + // Use a custom type. + return new ExplicitSizeStruct(key.Size, key.Alignment, this, _systemValueType); }); return _mappedFields.GetOrAdd((data, alignment), key => From f90cce27a9c9148b3922f0a20f123c70bc09f972 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Sat, 10 Dec 2022 15:40:40 -0500 Subject: [PATCH 3/3] Address PR feedback and fix test --- .../CodeGenReadOnlySpanConstructionTest.cs | 199 +++--------------- .../CodeGen/PrivateImplementationDetails.cs | 25 +-- 2 files changed, 35 insertions(+), 189 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs index acdafa884c5b4..57ec4e7bbf3a0 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadOnlySpanConstructionTest.cs @@ -2658,179 +2658,32 @@ public static int M() "; var compilation = CreateCompilation(csharp, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.UnsafeReleaseDll); var verifier = CompileAndVerify(compilation, verify: Verification.Skipped); - verifier.VerifyTypeIL("", @" -.class private auto ansi sealed '' - extends [System.Runtime]System.Object -{ - .custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( - 01 00 00 00 - ) - // Nested Types - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=8_Align=2' - extends [System.Runtime]System.ValueType - { - .pack 2 - .size 8 - } // end of class __StaticArrayInitTypeSize=8_Align=2 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=8_Align=4' - extends [System.Runtime]System.ValueType - { - .pack 4 - .size 8 - } // end of class __StaticArrayInitTypeSize=8_Align=4 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=8_Align=8' - extends [System.Runtime]System.ValueType - { - .pack 8 - .size 8 - } // end of class __StaticArrayInitTypeSize=8_Align=8 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16' - extends [System.Runtime]System.ValueType - { - .pack 1 - .size 16 - } // end of class __StaticArrayInitTypeSize=16 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16_Align=2' - extends [System.Runtime]System.ValueType - { - .pack 2 - .size 16 - } // end of class __StaticArrayInitTypeSize=16_Align=2 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16_Align=4' - extends [System.Runtime]System.ValueType - { - .pack 4 - .size 16 - } // end of class __StaticArrayInitTypeSize=16_Align=4 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=16_Align=8' - extends [System.Runtime]System.ValueType - { - .pack 8 - .size 16 - } // end of class __StaticArrayInitTypeSize=16_Align=8 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24' - extends [System.Runtime]System.ValueType - { - .pack 1 - .size 24 - } // end of class __StaticArrayInitTypeSize=24 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24_Align=2' - extends [System.Runtime]System.ValueType - { - .pack 2 - .size 24 - } // end of class __StaticArrayInitTypeSize=24_Align=2 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24_Align=4' - extends [System.Runtime]System.ValueType - { - .pack 4 - .size 24 - } // end of class __StaticArrayInitTypeSize=24_Align=4 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=24_Align=8' - extends [System.Runtime]System.ValueType - { - .pack 8 - .size 24 - } // end of class __StaticArrayInitTypeSize=24_Align=8 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32' - extends [System.Runtime]System.ValueType - { - .pack 1 - .size 32 - } // end of class __StaticArrayInitTypeSize=32 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32_Align=2' - extends [System.Runtime]System.ValueType - { - .pack 2 - .size 32 - } // end of class __StaticArrayInitTypeSize=32_Align=2 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32_Align=4' - extends [System.Runtime]System.ValueType - { - .pack 4 - .size 32 - } // end of class __StaticArrayInitTypeSize=32_Align=4 - .class nested private explicit ansi sealed '__StaticArrayInitTypeSize=32_Align=8' - extends [System.Runtime]System.ValueType - { - .pack 8 - .size 32 - } // end of class __StaticArrayInitTypeSize=32_Align=8 - // Fields - .field assembly static initonly int64 '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA' at I_00003358 - .data cil I_00003358 = bytearray ( - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=8_Align=2' '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA2' at I_00003360 - .data cil I_00003360 = bytearray ( - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=8_Align=4' '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA4' at I_00003368 - .data cil I_00003368 = bytearray ( - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=8_Align=8' '12A3AE445661CE5DEE78D0650D33362DEC29C4F82AF05E7E57FB595BBBACF0CA8' at I_00003370 - .data cil I_00003370 = bytearray ( - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B6' at I_00003378 - .data cil I_00003378 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24_Align=2' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B62' at I_00003390 - .data cil I_00003390 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24_Align=4' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B64' at I_000033A8 - .data cil I_000033A8 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=24_Align=8' '44A5F7891570E5631E8C91C85186E6633F4AB5364F644040B2A00126A07985B68' at I_000033C0 - .data cil I_000033C0 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B' at I_000033D8 - .data cil I_000033D8 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16_Align=2' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B2' at I_000033E8 - .data cil I_000033E8 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16_Align=4' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B4' at I_000033F8 - .data cil I_000033F8 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=16_Align=8' '5AC6A5945F16500911219129984BA8B387A06F24FE383CE4E81A73294065461B8' at I_00003408 - .data cil I_00003408 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C4051 at I_00003418 - .data cil I_00003418 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32_Align=2' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40512 at I_00003438 - .data cil I_00003438 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32_Align=4' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40514 at I_00003458 - .data cil I_00003458 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) - .field assembly static initonly valuetype ''/'__StaticArrayInitTypeSize=32_Align=8' AF9613760F72635FBDB44A5A0A63C39F12AF30F950A6EE5C971BE188E89C40518 at I_00003478 - .data cil I_00003478 = bytearray ( - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff - ) -} // end of class - "); + verifier.VerifyTypeIL("", il => + { + string[] expected = new[] + { + "__StaticArrayInitTypeSize=8_Align=2", + "__StaticArrayInitTypeSize=8_Align=4", + "__StaticArrayInitTypeSize=8_Align=8", + "__StaticArrayInitTypeSize=16", + "__StaticArrayInitTypeSize=16_Align=2", + "__StaticArrayInitTypeSize=16_Align=4", + "__StaticArrayInitTypeSize=16_Align=8", + "__StaticArrayInitTypeSize=24", + "__StaticArrayInitTypeSize=24_Align=2", + "__StaticArrayInitTypeSize=24_Align=4", + "__StaticArrayInitTypeSize=24_Align=8", + "__StaticArrayInitTypeSize=32", + "__StaticArrayInitTypeSize=32_Align=2", + "__StaticArrayInitTypeSize=32_Align=4", + "__StaticArrayInitTypeSize=32_Align=8", + }; + + // .class nested private explicit ansi sealed 'TYPENAME' + string[] actual = Regex.Matches(il, @"\.class nested private explicit ansi sealed '([^']*?)'").Cast().Select(m => m.Groups[1].Value).ToArray(); + + Assert.Equal(expected, actual); + }); } } } diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 11f25f24f1fd6..4601d4b8daedb 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -203,30 +203,23 @@ Cci.PrimitiveTypeCode.Int32 or Cci.PrimitiveTypeCode.UInt32 or Cci.PrimitiveType internal Cci.IFieldReference CreateDataField(ImmutableArray data, ushort alignment) { Debug.Assert(!IsFrozen); + Debug.Assert(alignment is 1 or 2 or 4 or 8); + Debug.Assert(data.Length != 1 || alignment == 1); Cci.ITypeReference type = _proxyTypes.GetOrAdd( ((uint)data.Length, Alignment: alignment), key => { // We need a type that's both the same size as the data and that has a .pack - // that matches the data's alignment requirements. - - if (key.Size == 1) - { - // Data of size 1 must be a single element of one-byte-sized type, - // which has no alignment requirements. - Debug.Assert(alignment == 1); - if (_systemInt8Type is not null) - { - return _systemInt8Type; - } - } - else if (key.Alignment == 1) + // that matches the data's alignment requirements. If the size of the data + // is 1 byte, then the alignment will also be 1, and we can use byte as the type. + // If the size of the data is 2, 4, or 8 bytes, we can use short, int, or long rather than + // creating a custom type, but we can only do so if the required alignment is also 1, as + // these types have a .pack value of 1. + if (key.Alignment == 1) { - // If the size of the data is 2, 4, or 8 bytes, we can use short, int, or long rather than - // creating a custom type, but we can only do so if the required alignment is also 1, as - // these types have a .pack value of 1. switch (key.Size) { + case 1 when _systemInt8Type is not null: return _systemInt8Type; case 2 when _systemInt16Type is not null: return _systemInt16Type; case 4 when _systemInt32Type is not null: return _systemInt32Type; case 8 when _systemInt64Type is not null: return _systemInt64Type;