From 804a997fcab587ff4c6e2bd90a3b8df0c39d7da9 Mon Sep 17 00:00:00 2001 From: Petr Onderka Date: Thu, 14 Oct 2021 15:24:24 +0200 Subject: [PATCH] Fixed generated IL --- .../CodeGen/EmitStackAllocInitializer.cs | 26 ++++++- .../Portable/Emitter/Model/PEModuleBuilder.cs | 12 ---- .../CodeGenStackAllocInitializerTests.cs | 71 +++++++++++-------- .../Core/Portable/CodeGen/ILBuilderEmit.cs | 16 ----- .../Core/Portable/CodeGen/ITokenDeferral.cs | 1 - .../Portable/Emit/CommonPEModuleBuilder.cs | 2 - .../Portable/Emit/PEModuleBuilder.vb | 11 --- 7 files changed, 65 insertions(+), 74 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs index 58b842a4915fc..a32e39ab63cfd 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs @@ -75,7 +75,7 @@ private void EmitStackAlloc(TypeSymbol type, BoundArrayInitialization? inits, Bo } else { - _builder.EmitStackAllocBlockMultiByteInitializer(data, elementType.GetPublicSymbol(), inits.Syntax, _diagnostics); + EmitStackAllocBlockMultiByteInitializer(data, elementType, inits.Syntax, _diagnostics); } } @@ -94,6 +94,30 @@ void emitLocalloc() } } + private void EmitStackAllocBlockMultiByteInitializer(ImmutableArray data, TypeSymbol elementType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + { + // get helpers + var definition = (MethodSymbol)_module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__GetPinnableReference)!; + var getPinnableReference = definition.AsMember(definition.ContainingType.Construct(elementType)).GetCciAdapter(); + var readOnlySpan = ((NamedTypeSymbol)_module.Compilation.CommonGetWellKnownType(WellKnownType.System_ReadOnlySpan_T)).GetCciAdapter(); + + // emit call to the helper + _builder.EmitOpCode(ILOpCode.Dup); + _builder.EmitCreateSpan(data, elementType.GetPublicSymbol(), syntaxNode, diagnostics); + + var temp = _builder.LocalSlotManager.AllocateSlot(readOnlySpan, LocalSlotConstraints.None); + _builder.EmitLocalStore(temp); + _builder.EmitLocalAddress(temp); + _builder.LocalSlotManager.FreeSlot(temp); + + // TODO: is this safe without pinning? + _builder.EmitOpCode(ILOpCode.Call, 0); + _builder.EmitToken(getPinnableReference, syntaxNode, diagnostics); + _builder.EmitIntConstant(data.Length); + // TODO: is this correct without unaligned.? + _builder.EmitOpCode(ILOpCode.Cpblk, -3); + } + internal static bool UseCreateSpanForReadOnlySpanInitialization( bool hasCreateSpanHelper, bool considerInitblk, TypeSymbol elementType, BoundArrayInitialization? inits, bool supportsPrivateImplClass) => hasCreateSpanHelper && inits?.Initializers is { } initExprs && diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index 8eaa92965f0ee..45a960f192fb7 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -827,18 +827,6 @@ public sealed override Cci.IMethodReference GetCreateSpanHelper(ITypeSymbol elem ?.Construct(csharpElementType).GetCciAdapter(); } - public sealed override Cci.IMethodReference GetReadOnlySpanGetPinnableReference(ITypeSymbol elementType) - { - if ((elementType as Symbols.PublicModel.TypeSymbol)?.UnderlyingTypeSymbol is not { } csharpElementType) - { - return null; - } - - var definition = (MethodSymbol)Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__GetPinnableReference); - - return definition?.AsMember(definition.ContainingType.Construct(csharpElementType)).GetCciAdapter(); - } - public sealed override bool IsPlatformType(Cci.ITypeReference typeRef, Cci.PlatformType platformType) { var namedType = typeRef.GetInternalSymbol() as NamedTypeSymbol; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs index 3c4f6463edf01..065417aaf7bb3 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs @@ -853,21 +853,24 @@ static void Write(Span span) {} .VerifyIL("C.Main", @" { - // Code size 37 (0x25) + // Code size 40 (0x28) .maxstack 4 + .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 12 IL_0002: conv.u IL_0003: localloc IL_0005: dup IL_0006: ldtoken "".__StaticArrayInitTypeSize=12 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_000b: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_0010: call ""ref readonly int System.ReadOnlySpan.GetPinnableReference()"" - IL_0015: ldc.i4.s 12 - IL_0017: cpblk - IL_0019: ldc.i4.3 - IL_001a: newobj ""System.Span..ctor(void*, int)"" - IL_001f: call ""void C.Write(System.Span)"" - IL_0024: ret + IL_0010: stloc.0 + IL_0011: ldloca.s V_0 + IL_0013: call ""ref readonly int System.ReadOnlySpan.GetPinnableReference()"" + IL_0018: ldc.i4.s 12 + IL_001a: cpblk + IL_001c: ldc.i4.3 + IL_001d: newobj ""System.Span..ctor(void*, int)"" + IL_0022: call ""void C.Write(System.Span)"" + IL_0027: ret } "); } @@ -922,19 +925,22 @@ static void Write(int* span) {} .VerifyIL("C.Main", @" { - // Code size 31 (0x1f) + // Code size 34 (0x22) .maxstack 4 + .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 12 IL_0002: conv.u IL_0003: localloc IL_0005: dup IL_0006: ldtoken "".__StaticArrayInitTypeSize=12 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" IL_000b: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_0010: call ""ref readonly int System.ReadOnlySpan.GetPinnableReference()"" - IL_0015: ldc.i4.s 12 - IL_0017: cpblk - IL_0019: call ""void C.Write(int*)"" - IL_001e: ret + IL_0010: stloc.0 + IL_0011: ldloca.s V_0 + IL_0013: call ""ref readonly int System.ReadOnlySpan.GetPinnableReference()"" + IL_0018: ldc.i4.s 12 + IL_001a: cpblk + IL_001c: call ""void C.Write(int*)"" + IL_0021: ret } "); } @@ -959,30 +965,33 @@ static void Write(ReadOnlySpan span) {} .VerifyIL("C.Main", @" { - // Code size 50 (0x32) + // Code size 53 (0x35) .maxstack 4 + .locals init (System.ReadOnlySpan V_0) IL_0000: ldc.i4.s 16 IL_0002: conv.u IL_0003: localloc IL_0005: dup IL_0006: ldtoken "".__StaticArrayInitTypeSize=16 .81C1A5A2F482E82CA2C66653482AB24E6D90944BF183C8164E8F8F8D72DB60DB"" IL_000b: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" - IL_0010: call ""ref readonly int System.ReadOnlySpan.GetPinnableReference()"" - IL_0015: ldc.i4.s 16 - IL_0017: cpblk - IL_0019: dup - IL_001a: ldc.i4.3 - IL_001b: conv.i - IL_001c: ldc.i4.4 - IL_001d: mul - IL_001e: add - IL_001f: ldarg.0 - IL_0020: stind.i4 - IL_0021: ldc.i4.4 - IL_0022: newobj ""System.Span..ctor(void*, int)"" - IL_0027: call ""System.ReadOnlySpan System.Span.op_Implicit(System.Span)"" - IL_002c: call ""void C.Write(System.ReadOnlySpan)"" - IL_0031: ret + IL_0010: stloc.0 + IL_0011: ldloca.s V_0 + IL_0013: call ""ref readonly int System.ReadOnlySpan.GetPinnableReference()"" + IL_0018: ldc.i4.s 16 + IL_001a: cpblk + IL_001c: dup + IL_001d: ldc.i4.3 + IL_001e: conv.i + IL_001f: ldc.i4.4 + IL_0020: mul + IL_0021: add + IL_0022: ldarg.0 + IL_0023: stind.i4 + IL_0024: ldc.i4.4 + IL_0025: newobj ""System.Span..ctor(void*, int)"" + IL_002a: call ""System.ReadOnlySpan System.Span.op_Implicit(System.Span)"" + IL_002f: call ""void C.Write(System.ReadOnlySpan)"" + IL_0034: ret } "); } diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 31f6c854841e4..65ee569438f40 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -119,22 +119,6 @@ internal void EmitStackAllocBlockSingleByteInitializer(ImmutableArray data } } - internal void EmitStackAllocBlockMultiByteInitializer(ImmutableArray data, ITypeSymbol elementType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) - { - // get helpers - var getPinnableReference = module.GetReadOnlySpanGetPinnableReference(elementType); - - // emit call to the helper - EmitOpCode(ILOpCode.Dup); - EmitCreateSpan(data, elementType, syntaxNode, diagnostics); - // TODO: is this safe without pinning? - EmitOpCode(ILOpCode.Call, 0); - EmitToken(getPinnableReference, syntaxNode, diagnostics); - EmitIntConstant(data.Length); - // TODO: is this correct without unaligned.? - EmitOpCode(ILOpCode.Cpblk, -3); - } - internal void EmitCreateSpan(ImmutableArray data, ITypeSymbol elementType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { // get helpers diff --git a/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs b/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs index b9d12e2f83c71..f9be61bdb428f 100644 --- a/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs +++ b/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs @@ -16,7 +16,6 @@ internal interface ITokenDeferral Cci.IFieldReference GetFieldForData(ImmutableArray data, SyntaxNode syntaxNode, DiagnosticBag diagnostics); Cci.IMethodReference GetInitArrayHelper(); Cci.IMethodReference GetCreateSpanHelper(ITypeSymbol elementType); - Cci.IMethodReference GetReadOnlySpanGetPinnableReference(ITypeSymbol elementType); string GetStringFromToken(uint token); /// diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index e37f0f98c6b59..10a1261f36813 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -995,8 +995,6 @@ Cci.IFieldReference ITokenDeferral.GetFieldForData(ImmutableArray data, Sy public abstract Cci.IMethodReference GetCreateSpanHelper(ITypeSymbol elementType); - public abstract Cci.IMethodReference GetReadOnlySpanGetPinnableReference(ITypeSymbol elementType); - public ArrayMethods ArrayMethods { get diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index c5d766411bcff..e0ce5041c678e 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -616,17 +616,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return DirectCast(Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpan_T), MethodSymbol)?.Construct(vbElementType).GetCciAdapter() End Function - Public NotOverridable Overrides Function GetReadOnlySpanGetPinnableReference(elementType As ITypeSymbol) As Cci.IMethodReference - Dim vbElementType = TryCast(elementType, TypeSymbol) - If vbElementType Is Nothing Then - Return Nothing - End If - - Dim definition = DirectCast(Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__GetPinnableReference), MethodSymbol) - - Return definition?.AsMember(definition.ContainingType.Construct(vbElementType)).GetCciAdapter() - End Function - Public NotOverridable Overrides Function IsPlatformType(typeRef As Cci.ITypeReference, platformType As Cci.PlatformType) As Boolean Dim namedType = TryCast(typeRef.GetInternalSymbol(), NamedTypeSymbol)