From 0d09a674061c29fb6299a88c982819f657cfe0d3 Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 7 Apr 2025 13:56:14 -0700 Subject: [PATCH 01/21] Add support for FieldRva to EnC delta --- .../Portable/CodeGen/EmitArrayInitializer.cs | 10 +-- .../CodeGen/EmitStackAllocInitializer.cs | 5 +- .../EditAndContinue/CSharpSymbolMatcher.cs | 2 +- .../EditAndContinue/EditAndContinueTests.cs | 89 ++++++++++++++++++- .../Portable/CodeGen/CompilationTestData.cs | 2 + .../Portable/Emit/CommonPEModuleBuilder.cs | 6 ++ .../EditAndContinue/DeltaMetadataWriter.cs | 4 +- .../Core/Portable/PEWriter/MetadataWriter.cs | 35 +++++--- .../Portable/CodeGen/EmitArrayInitializer.vb | 5 +- .../EditAndContinueTest.GenerationVerifier.cs | 7 ++ .../EditAndContinue/EditAndContinueTest.cs | 20 +++-- 11 files changed, 149 insertions(+), 36 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index e35d326e09bb6..fdb16fcfb19c4 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -245,10 +245,9 @@ private bool EnableEnumArrayBlockInitialization private ArrayInitializerStyle ShouldEmitBlockInitializer(TypeSymbol elementType, ImmutableArray inits) { - if (_module.IsEncDelta) + if (!_module.FieldRvaSupported) { - // Avoid using FieldRva table. Can be allowed if tested on all supported runtimes. - // Consider removing: https://github.com/dotnet/roslyn/issues/69480 + // Avoid using FieldRva table when not supported by the runtime. return ArrayInitializerStyle.Element; } @@ -449,10 +448,9 @@ private bool TryEmitOptimizedReadonlySpanCreation(NamedTypeSymbol spanType, Boun return true; } - if (_module.IsEncDelta) + if (!_module.FieldRvaSupported) { - // Avoid using FieldRva table. Can be allowed if tested on all supported runtimes. - // Consider removing: https://github.com/dotnet/roslyn/issues/69480 + // Avoid using FieldRva table when not supported by the runtime. return false; } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs index d6eadf22b4e2c..edeb5512d4cc3 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs @@ -128,10 +128,9 @@ void emitLocalloc() private ArrayInitializerStyle ShouldEmitBlockInitializerForStackAlloc(TypeSymbol elementType, ImmutableArray inits) { - if (_module.IsEncDelta) + if (!_module.FieldRvaSupported) { - // Avoid using FieldRva table. Can be allowed if tested on all supported runtimes. - // Consider removing: https://github.com/dotnet/roslyn/issues/69480 + // Avoid using FieldRva table when not supported by the runtime. return ArrayInitializerStyle.Element; } diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs index 7e7f5a4f29ad0..50dbee6c358d6 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs @@ -57,7 +57,7 @@ public CSharpSymbolMatcher( // For simplicity, PID helpers and no-PIA embedded definitions are not reused across generations, so we don't map them here. // Instead, new ones are regenerated as needed. - Debug.Assert(definition is PrivateImplementationDetails or Cci.IEmbeddedDefinition); + Debug.Assert(definition is PrivateImplementationDetails or Cci.IEmbeddedDefinition or MappedField or ExplicitSizeStruct); return null; } diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index cadd2d351b7b7..a9b3b6280e5c5 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -19129,7 +19129,7 @@ .locals init (System.Span V_0, //x [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] - public void PrivateImplDetails_DataFields_Arrays() + public void PrivateImplDetails_DataFields_Arrays_FieldRvaNotSupported() { using var _ = new EditAndContinueTest() .AddBaseline( @@ -19231,6 +19231,93 @@ .maxstack 5 .Verify(); } + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] + public void PrivateImplDetails_DataFields_Arrays_FieldRvaSupported() + { + using var _ = new EditAndContinueTest() + .AddBaseline( + source: $$""" + class C + { + byte[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C", "", "__StaticArrayInitTypeSize=10"); + g.VerifyFieldDefNames("b", "1F825AA2F0020EF7CF91DFA30DA4668D791C5D4824FC8E41354B89EC05795AB3"); + g.VerifyMethodDefNames(".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + byte[] b = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + } + """, + edits: new[] + { + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetParameterlessConstructor("C")), + }, + validator: g => + { + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=11"); + g.VerifyFieldDefNames("78A6273103D17C39A0B6126E226CEC70E33337F4BC6A38067401B54A33E78EAD"); + g.VerifyMethodDefNames(".ctor"); + + g.VerifyEncLogDefinitions(new[] + { + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.ClassLayout, EditAndContinueOperation.Default), + Row(2, TableIndex.FieldRva, EditAndContinueOperation.Default), + Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default) + }); + + g.VerifyEncMapDefinitions(new[] + { + Handle(5, TableIndex.TypeDef), + Handle(6, TableIndex.TypeDef), + Handle(3, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute), + Handle(2, TableIndex.ClassLayout), + Handle(2, TableIndex.FieldRva), + Handle(2, TableIndex.NestedClass) + }); + + g.VerifyIL("C..ctor", """ + { + // Code size 32 (0x20) + .maxstack 4 + IL_0000: ldarg.0 + IL_0001: ldc.i4.s 11 + IL_0003: newarr "byte" + IL_0008: dup + IL_0009: ldtoken "#1.__StaticArrayInitTypeSize=11 #1.78A6273103D17C39A0B6126E226CEC70E33337F4BC6A38067401B54A33E78EAD" + IL_000e: call "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)" + IL_0013: stfld "byte[] C.b" + IL_0018: ldarg.0 + IL_0019: call "object..ctor()" + IL_001e: nop + IL_001f: ret + } + """); + + // TODO: better test would be to specify FieldDef -> data. + // trailing zeros for alignment: + g.VerifyEncFieldRvaData([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); + }, + withTestData: d => d.EncFieldRvaSupported = true) + .Verify(); + } + [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] public void PrivateImplDetails_DataFields_StackAlloc() diff --git a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs index 3797649644974..b0a41dc4036b0 100644 --- a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs +++ b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs @@ -44,6 +44,8 @@ public MethodData(ILBuilder ilBuilder, IMethodSymbolInternal method) private ImmutableDictionary? _lazyMethodsByName; + public bool EncFieldRvaSupported { get; set; } + public void SetMetadataWriter(MetadataWriter writer) { Debug.Assert(MetadataWriter == null); diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 84be01ad50e1e..4d0e1dc39a755 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -84,6 +84,12 @@ public CommonPEModuleBuilder( /// public bool IsEncDelta => PreviousGeneration != null; + /// + /// True if FieldRVA table is supported by the runtime. + /// TODO: Base on a feature switch in the BCL instead of TestData flag (https://github.com/dotnet/roslyn/issues/69480). + /// + public bool FieldRvaSupported => !IsEncDelta || TestData?.EncFieldRvaSupported == true; + /// /// EnC generation. 0 if the module is not an EnC delta, 1 if it is the first EnC delta, etc. /// diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 797c54af87e97..61e57208e7f8b 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -1359,9 +1359,7 @@ private void PopulateEncMapTableRows(ImmutableArray rowCounts, ArrayBuilder TableIndex.ModuleRef, TableIndex.TypeSpec, TableIndex.ImplMap, - // FieldRva is not needed since we do not emit fields with explicit mapping during EnC. - // https://github.com/dotnet/roslyn/issues/69480 - //TableIndex.FieldRva, + TableIndex.FieldRva, TableIndex.EncLog, TableIndex.EncMap, TableIndex.Assembly, diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index f50496068f91d..9ac8a57318ec9 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -1719,7 +1719,6 @@ public void WriteMetadataAndIL(PdbWriter? nativePdbWriterOpt, Stream metadataStr Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncMap] == 0); PopulateEncTables(typeSystemRowCounts); - Debug.Assert(mappedFieldDataBuilder == null); Debug.Assert(managedResourceDataBuilder == null); Debug.Assert(mvidFixup.IsDefault); Debug.Assert(mvidStringFixup.IsDefault); @@ -1742,9 +1741,13 @@ public void WriteMetadataAndIL(PdbWriter? nativePdbWriterOpt, Stream metadataStr try { ilBuilder.WriteContentTo(ilStream); + + // in EnC delta FieldRVA data are appended to the IL stream: + mappedFieldDataBuilder?.WriteContentTo(ilStream); + metadataBuilder.WriteContentTo(metadataStream); } - catch (Exception e) when (!(e is OperationCanceledException)) + catch (Exception e) when (e is not OperationCanceledException) { throw new PeWritingException(e); } @@ -1844,7 +1847,10 @@ public void BuildMetadataAndIL( _dynamicAnalysisDataWriterOpt.SerializeMetadataTables(dynamicAnalysisData); } - PopulateTypeSystemTables(methodBodyOffsets, out mappedFieldDataBuilder, out managedResourceDataBuilder, dynamicAnalysisData, out mvidFixup); + // in EnC delta the FieldRVA data is stored to IL stream following all the method bodies: + int mappedFieldDataStartOffset = IsFullMetadata ? 0 : ilBuilder.Count; + + PopulateTypeSystemTables(methodBodyOffsets, mappedFieldDataStartOffset, out mappedFieldDataBuilder, out managedResourceDataBuilder, dynamicAnalysisData, out mvidFixup); dynamicAnalysisData?.Free(); } #nullable disable @@ -1907,7 +1913,7 @@ private ImmutableArray GetSortedGenericParameters() } #nullable enable - private void PopulateTypeSystemTables(int[] methodBodyOffsets, out PooledBlobBuilder? mappedFieldDataWriter, out PooledBlobBuilder? resourceWriter, BlobBuilder? dynamicAnalysisData, out Blob mvidFixup) + private void PopulateTypeSystemTables(int[] methodBodyOffsets, int mappedFieldDataStartOffset, out PooledBlobBuilder? mappedFieldDataWriter, out PooledBlobBuilder? resourceWriter, BlobBuilder? dynamicAnalysisData, out Blob mvidFixup) { var sortedGenericParameters = GetSortedGenericParameters(); @@ -1921,7 +1927,7 @@ private void PopulateTypeSystemTables(int[] methodBodyOffsets, out PooledBlobBui this.PopulateExportedTypeTableRows(); this.PopulateFieldLayoutTableRows(); this.PopulateFieldMarshalTableRows(); - this.PopulateFieldRvaTableRows(out mappedFieldDataWriter); + this.PopulateFieldRvaTableRows(mappedFieldDataStartOffset, out mappedFieldDataWriter); this.PopulateFieldTableRows(); this.PopulateFileTableRows(); this.PopulateGenericParameters(sortedGenericParameters); @@ -2329,9 +2335,9 @@ private void PopulateFieldMarshalTableRows() } #nullable enable - private void PopulateFieldRvaTableRows(out PooledBlobBuilder? mappedFieldDataWriter) + private void PopulateFieldRvaTableRows(int mappedFieldDataStartOffset, out PooledBlobBuilder? mappedFieldDataBuilder) { - mappedFieldDataWriter = null; + mappedFieldDataBuilder = null; foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) { @@ -2340,19 +2346,26 @@ private void PopulateFieldRvaTableRows(out PooledBlobBuilder? mappedFieldDataWri continue; } - mappedFieldDataWriter ??= PooledBlobBuilder.GetInstance(); + if (mappedFieldDataBuilder == null) + { + mappedFieldDataBuilder = PooledBlobBuilder.GetInstance(); + + // insert alignment bytes as needed: + var alignedStartOffset = BitArithmeticUtilities.Align(mappedFieldDataStartOffset, ManagedPEBuilder.MappedFieldDataAlignment); + mappedFieldDataBuilder.WriteBytes(0, alignedStartOffset - mappedFieldDataStartOffset); + } // The compiler always aligns each RVA data field to an 8-byte boundary; this accommodates the alignment // needs for all primitive types, regardless of which type is actually being used, at the expense of // potentially wasting up to 7 bytes per field if the alignment needs are less. In the future, this // potentially could be tightened to align each field only as much as is actually required by that // field, saving a few bytes per field. - int offset = mappedFieldDataWriter.Count; + int offset = mappedFieldDataStartOffset + mappedFieldDataBuilder.Count; Debug.Assert(offset % ManagedPEBuilder.MappedFieldDataAlignment == 0, "Expected last write to end at alignment boundary"); Debug.Assert(ManagedPEBuilder.MappedFieldDataAlignment == 8, "Expected alignment to be 8"); - mappedFieldDataWriter.WriteBytes(fieldDef.MappedData); - mappedFieldDataWriter.Align(ManagedPEBuilder.MappedFieldDataAlignment); + mappedFieldDataBuilder.WriteBytes(fieldDef.MappedData); + mappedFieldDataBuilder.Align(ManagedPEBuilder.MappedFieldDataAlignment); metadata.AddFieldRelativeVirtualAddress( field: GetFieldDefinitionHandle(fieldDef), diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb index 2b36682d656a1..521b98d7564e0 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb @@ -188,9 +188,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen End Function Private Function ShouldEmitBlockInitializer(elementType As TypeSymbol, inits As ImmutableArray(Of BoundExpression)) As ArrayInitializerStyle - If _module.IsEncDelta Then - ' Avoid using FieldRva table. Can be allowed if tested on all supported runtimes. - ' Consider removing: https://github.com/dotnet/roslyn/issues/69480 + If Not _module.FieldRvaSupported Then + ' Avoid using FieldRva table if the runtime does not support it. Return ArrayInitializerStyle.Element End If diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs index 17cf4dbc1d53b..f413c28add4fa 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs @@ -202,6 +202,13 @@ internal void VerifyIL(string qualifiedMemberName, string expectedIL) } }); + internal void VerifyEncFieldRvaData(byte[] expected) + => Verify(() => + { + Debug.Assert(generationInfo.CompilationDifference != null); + AssertEx.SequenceEqual(expected, generationInfo.CompilationDifference.ILDelta[^expected.Length..]); + }); + public void VerifyLocalSignature(string qualifiedMethodName, string expectedSignature) => Verify(() => { diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs index d9f5de65aa9bd..d75ef4a6d6f63 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs @@ -10,6 +10,7 @@ using System.Reflection.Metadata; using System.Runtime.InteropServices; using System.Text; +using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -70,16 +71,16 @@ internal TSelf AddBaseline(string source, Action? validator return This; } - internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, Action validator) - => AddGeneration(source, _ => edits, validator); + internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, Action validator, Action? withTestData = null) + => AddGeneration(source, _ => edits, validator, withTestData); - internal TSelf AddGeneration(string source, Func edits, Action validator) - => AddGeneration(source, edits, validator, expectedErrors: []); + internal TSelf AddGeneration(string source, Func edits, Action validator, Action? withTestData = null) + => AddGeneration(source, edits, validator, expectedErrors: [], withTestData); - internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, DiagnosticDescription[] expectedErrors) - => AddGeneration(source, _ => edits, validator: static _ => { }, expectedErrors); + internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, DiagnosticDescription[] expectedErrors, Action? withTestData = null) + => AddGeneration(source, _ => edits, validator: static _ => { }, expectedErrors, withTestData); - private TSelf AddGeneration(string source, Func edits, Action validator, DiagnosticDescription[] expectedErrors) + private TSelf AddGeneration(string source, Func edits, Action validator, DiagnosticDescription[] expectedErrors, Action? withTestData) { _hasVerified = false; @@ -97,7 +98,10 @@ private TSelf AddGeneration(string source, Func d.Severity == DiagnosticSeverity.Error).Verify(expectedErrors); if (expectedErrors is not []) From 34de430f5df656c4ece1c5d3054c7811b743a8a5 Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 7 Apr 2025 15:37:33 -0700 Subject: [PATCH 02/21] Add EmitDifferenceOptions; AddFieldRva capability --- .../Portable/Compilation/CSharpCompilation.cs | 2 ++ .../Emitter/EditAndContinue/EmitHelpers.cs | 2 ++ .../EditAndContinue/PEDeltaAssemblyBuilder.cs | 4 ++++ .../Emitter/Model/PEAssemblyBuilder.cs | 1 + .../Emitter/Model/PENetModuleBuilder.cs | 1 + .../AssemblyReferencesTests.cs | 4 ++-- .../EditAndContinue/EditAndContinueTests.cs | 13 ++++++---- .../Core/Portable/Compilation/Compilation.cs | 24 +++++++++++++++++-- .../Compilation/EmitDifferenceOptions.cs | 19 +++++++++++++++ .../Portable/Emit/CommonPEModuleBuilder.cs | 11 ++++----- .../Core/Portable/PublicAPI.Unshipped.txt | 10 +++++--- .../Core/Compilation/CompilationExtensions.cs | 1 + .../Compilation/VisualBasicCompilation.vb | 2 ++ .../Emit/EditAndContinue/EmitHelpers.vb | 2 ++ .../EditAndContinue/PEDeltaAssemblyBuilder.vb | 9 +++++++ .../Portable/Emit/PEAssemblyBuilder.vb | 6 +++++ .../Portable/Emit/PENetModuleBuilder.vb | 6 +++++ .../ExpressionCompiler/EEAssemblyBuilder.cs | 1 + .../ReferencedModulesTests.cs | 1 + .../ExpressionCompiler/EEAssemblyBuilder.vb | 6 +++++ .../ReferencedModulesTests.vb | 8 ++++++- .../EditAndContinueCapabilities.cs | 10 ++++++++ .../EditAndContinueTestVerifier.cs | 9 ++++++- 23 files changed, 133 insertions(+), 19 deletions(-) create mode 100644 src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index e23c3b07ded64..8d8d92cd0460a 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -3778,6 +3778,7 @@ internal override EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, + EmitDifferenceOptions options, CompilationTestData? testData, CancellationToken cancellationToken) { @@ -3789,6 +3790,7 @@ internal override EmitDifferenceResult EmitDifference( metadataStream, ilStream, pdbStream, + options, testData, cancellationToken); } diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs index 020e601857447..e0b3696c623fa 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs @@ -28,6 +28,7 @@ internal static EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, + EmitDifferenceOptions options, CompilationTestData? testData, CancellationToken cancellationToken) { @@ -94,6 +95,7 @@ internal static EmitDifferenceResult EmitDifference( compilation.SourceAssembly, changes, emitOptions: emitOptions, + options: options, outputKind: compilation.Options.OutputKind, serializationProperties: serializationProperties, manifestResources: manifestResources, diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs index c565c056a507c..1e93bc2a501f8 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs @@ -25,6 +25,7 @@ internal sealed class PEDeltaAssemblyBuilder : PEAssemblyBuilderBase, IPEDeltaAs private readonly SymbolChanges _changes; private readonly CSharpSymbolMatcher.DeepTranslator _deepTranslator; private readonly MethodSymbol? _predefinedHotReloadExceptionConstructor; + private readonly EmitDifferenceOptions _options; /// /// HotReloadException type. May be created even if not used. We might find out @@ -47,6 +48,7 @@ public PEDeltaAssemblyBuilder( SourceAssemblySymbol sourceAssembly, CSharpSymbolChanges changes, EmitOptions emitOptions, + EmitDifferenceOptions options, OutputKind outputKind, Cci.ModulePropertiesForSerialization serializationProperties, IEnumerable manifestResources, @@ -54,6 +56,7 @@ public PEDeltaAssemblyBuilder( : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: []) { _changes = changes; + _options = options; // Workaround for https://github.com/dotnet/roslyn/issues/3192. // When compiling state machine we stash types of awaiters and state-machine hoisted variables, @@ -74,6 +77,7 @@ public PEDeltaAssemblyBuilder( public override SymbolChanges? EncSymbolChanges => _changes; public override EmitBaseline PreviousGeneration => _changes.DefinitionMap.Baseline; + public override bool FieldRvaSupported => _options.EmitFieldRva; internal override Cci.ITypeReference EncTranslateLocalVariableType(TypeSymbol type, DiagnosticBag diagnostics) { diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index 5244d968826cc..b1017b9c61795 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -654,6 +654,7 @@ internal sealed class PEAssemblyBuilder( { public override EmitBaseline? PreviousGeneration => null; public override SymbolChanges? EncSymbolChanges => null; + public override bool FieldRvaSupported => true; public override INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType() => null; diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs index 44acf7e6ee24a..576881232a380 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PENetModuleBuilder.cs @@ -38,6 +38,7 @@ protected override void AddEmbeddedResourcesFromAddedModules(ArrayBuilder null; public override SymbolChanges? EncSymbolChanges => null; + public override bool FieldRvaSupported => true; public override INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType() => null; diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs index 7a67122fa4787..89860a042ddc7 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs @@ -81,7 +81,7 @@ class C compilation1.GlobalNamespace.GetMember("C").GetMember("Main")) }; - compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream); + compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream, EmitDifferenceOptions.Default, CancellationToken.None); var actualIL = ImmutableArray.Create(ilStream.ToArray()).GetMethodIL(); var expectedIL = @" @@ -153,7 +153,7 @@ class C compilation1.GlobalNamespace.GetMember("C").GetMember("Main")) }; - compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream); + compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream, EmitDifferenceOptions.Default, CancellationToken.None); var actualIL = ImmutableArray.Create(ilStream.ToArray()).GetMethodIL(); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index a9b3b6280e5c5..20b1206405283 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Threading; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; @@ -12447,8 +12448,9 @@ static string F() badStream, ilStream, pdbStream, + EmitDifferenceOptions.Default, new CompilationTestData(), - default); + CancellationToken.None); Assert.False(result.Success); result.Diagnostics.Verify( // error CS8104: An error occurred while writing the output file: System.IO.IOException: I/O error occurred. @@ -12462,8 +12464,9 @@ static string F() mdStream, badStream, pdbStream, + EmitDifferenceOptions.Default, new CompilationTestData(), - default); + CancellationToken.None); Assert.False(result.Success); result.Diagnostics.Verify( // error CS8104: An error occurred while writing the output file: System.IO.IOException: I/O error occurred. @@ -12477,8 +12480,9 @@ static string F() mdStream, ilStream, badStream, + EmitDifferenceOptions.Default, new CompilationTestData(), - default); + CancellationToken.None); Assert.False(result.Success); result.Diagnostics.Verify( // error CS0041: Unexpected error writing debug information -- 'I/O error occurred.' @@ -12532,8 +12536,9 @@ static string F() mdStream, ilStream, badStream, + EmitDifferenceOptions.Default, new CompilationTestData(), - default); + CancellationToken.None); Assert.False(result.Success); result.Diagnostics.Verify( // error CS0041: Unexpected error writing debug information -- 'I/O error occurred.' diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 6c8edee429110..5e19a729ff5ba 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -3086,6 +3086,7 @@ public EmitDifferenceResult EmitDifference( /// of the current compilation is returned as an EmitBaseline for use in a /// subsequent Edit and Continue. /// + [Obsolete("UpdatedMethods is now part of EmitDifferenceResult, so you should use an overload that doesn't take it.")] public EmitDifferenceResult EmitDifference( EmitBaseline baseline, IEnumerable edits, @@ -3093,7 +3094,25 @@ public EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, - CancellationToken cancellationToken = default(CancellationToken)) + CancellationToken cancellationToken) + => EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, EmitDifferenceOptions.Default, cancellationToken); + + /// + /// Emit the differences between the compilation and the previous generation + /// for Edit and Continue. The differences are expressed as added and changed + /// symbols, and are emitted as metadata, IL, and PDB deltas. A representation + /// of the current compilation is returned as an EmitBaseline for use in a + /// subsequent Edit and Continue. + /// + public EmitDifferenceResult EmitDifference( + EmitBaseline baseline, + IEnumerable edits, + Func isAddedSymbol, + Stream metadataStream, + Stream ilStream, + Stream pdbStream, + EmitDifferenceOptions options, + CancellationToken cancellationToken) { if (baseline == null) { @@ -3128,7 +3147,7 @@ public EmitDifferenceResult EmitDifference( throw new ArgumentNullException(nameof(pdbStream)); } - return this.EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, testData: null, cancellationToken); + return this.EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, options, testData: null, cancellationToken); } #pragma warning restore RS0026 // Do not add multiple public overloads with optional parameters @@ -3139,6 +3158,7 @@ internal abstract EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, + EmitDifferenceOptions options, CompilationTestData? testData, CancellationToken cancellationToken); diff --git a/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs b/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs new file mode 100644 index 0000000000000..6388a645953d1 --- /dev/null +++ b/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.CodeAnalysis.Emit; + +public readonly struct EmitDifferenceOptions +{ + public static readonly EmitDifferenceOptions Default = new(); + + /// + /// True to emit FieldRva table entries. The runtime must support this feature. + /// + public bool EmitFieldRva { get; init; } + + public EmitDifferenceOptions() + { + } +} diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 4d0e1dc39a755..ddfa79e3bc435 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -74,6 +74,11 @@ public CommonPEModuleBuilder( /// public abstract SymbolChanges? EncSymbolChanges { get; } + /// + /// True if FieldRVA table is supported by the runtime. + /// + public abstract bool FieldRvaSupported { get; } + /// /// Previous EnC generation baseline, or null if this is not EnC delta. /// @@ -84,12 +89,6 @@ public CommonPEModuleBuilder( /// public bool IsEncDelta => PreviousGeneration != null; - /// - /// True if FieldRVA table is supported by the runtime. - /// TODO: Base on a feature switch in the BCL instead of TestData flag (https://github.com/dotnet/roslyn/issues/69480). - /// - public bool FieldRvaSupported => !IsEncDelta || TestData?.EncFieldRvaSupported == true; - /// /// EnC generation. 0 if the module is not an EnC delta, 1 if it is the first EnC delta, etc. /// diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index a093220786c15..a2e4308ced80a 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,13 +1,17 @@ +Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions options, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! +Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions +Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitDifferenceOptions() -> void +Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitFieldRva.get -> bool +Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitFieldRva.init -> void +static readonly Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.Default -> Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions Microsoft.CodeAnalysis.IEventSymbol.IsPartialDefinition.get -> bool Microsoft.CodeAnalysis.IEventSymbol.PartialDefinitionPart.get -> Microsoft.CodeAnalysis.IEventSymbol? Microsoft.CodeAnalysis.IEventSymbol.PartialImplementationPart.get -> Microsoft.CodeAnalysis.IEventSymbol? Microsoft.CodeAnalysis.IncrementalGeneratorPostInitializationContext.AddEmbeddedAttributeDefinition() -> void override Microsoft.CodeAnalysis.Diagnostics.AnalyzerFileReference.ToString() -> string! - Microsoft.CodeAnalysis.ITypeSymbol.IsExtension.get -> bool Microsoft.CodeAnalysis.TypeKind.Extension = 14 -> Microsoft.CodeAnalysis.TypeKind Microsoft.CodeAnalysis.ITypeSymbol.ExtensionParameter.get -> Microsoft.CodeAnalysis.IParameterSymbol? - const Microsoft.CodeAnalysis.WellKnownMemberNames.AdditionAssignmentOperatorName = "op_AdditionAssignment" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.BitwiseAndAssignmentOperatorName = "op_BitwiseAndAssignment" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.BitwiseOrAssignmentOperatorName = "op_BitwiseOrAssignment" -> string! @@ -26,4 +30,4 @@ const Microsoft.CodeAnalysis.WellKnownMemberNames.UnsignedRightShiftAssignmentOp const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedDecrementAssignmentOperatorName = "op_CheckedDecrementAssignment" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.CheckedIncrementAssignmentOperatorName = "op_CheckedIncrementAssignment" -> string! const Microsoft.CodeAnalysis.WellKnownMemberNames.DecrementAssignmentOperatorName = "op_DecrementAssignment" -> string! -const Microsoft.CodeAnalysis.WellKnownMemberNames.IncrementAssignmentOperatorName = "op_IncrementAssignment" -> string! \ No newline at end of file +const Microsoft.CodeAnalysis.WellKnownMemberNames.IncrementAssignmentOperatorName = "op_IncrementAssignment" -> string! diff --git a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs index e2fdfbcc60d5b..b9db193054532 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs @@ -158,6 +158,7 @@ internal static CompilationDifference EmitDifference( mdStream, ilStream, pdbStream, + EmitDifferenceOptions.Default, testData, CancellationToken.None); diff --git a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb index 549049a430208..78216504415db 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/VisualBasicCompilation.vb @@ -2603,6 +2603,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic metadataStream As Stream, ilStream As Stream, pdbStream As Stream, + options As EmitDifferenceOptions, testData As CompilationTestData, cancellationToken As CancellationToken) As EmitDifferenceResult @@ -2614,6 +2615,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic metadataStream, ilStream, pdbStream, + options, testData, cancellationToken) End Function diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb index 11f3d1c93a873..5e6363a8d1a72 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb @@ -25,6 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit metadataStream As Stream, ilStream As Stream, pdbStream As Stream, + options As EmitDifferenceOptions, testData As CompilationTestData, cancellationToken As CancellationToken) As EmitDifferenceResult @@ -86,6 +87,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit compilation.SourceAssembly, changes, emitOpts, + options, compilation.Options.OutputKind, serializationProperties, manifestResources, diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb index 955d149b98831..9c48546f62ffd 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb @@ -25,6 +25,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Private ReadOnly _changes As SymbolChanges Private ReadOnly _deepTranslator As VisualBasicSymbolMatcher.DeepTranslator Private ReadOnly _predefinedHotReloadExceptionConstructor As MethodSymbol + Private ReadOnly _options As EmitDifferenceOptions ''' ''' HotReloadException type. May be created even if not used. We might find out @@ -46,6 +47,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Public Sub New(sourceAssembly As SourceAssemblySymbol, changes As VisualBasicSymbolChanges, emitOptions As EmitOptions, + options As EmitDifferenceOptions, outputKind As OutputKind, serializationProperties As ModulePropertiesForSerialization, manifestResources As IEnumerable(Of ResourceDescription), @@ -54,6 +56,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit MyBase.New(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes:=ImmutableArray(Of NamedTypeSymbol).Empty) _changes = changes + _options = options ' Workaround for https://github.com/dotnet/roslyn/issues/3192. ' When compiling state machine we stash types of awaiters and state-machine hoisted variables, @@ -92,6 +95,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property + Public Overrides ReadOnly Property FieldRvaSupported As Boolean + Get + Return _options.EmitFieldRva + End Get + End Property + Friend Shared Function GetOrCreateMetadataSymbols(initialBaseline As EmitBaseline, compilation As VisualBasicCompilation) As EmitBaseline.MetadataSymbols If initialBaseline.LazyMetadataSymbols IsNot Nothing Then Return initialBaseline.LazyMetadataSymbols diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb index d8c88417719c5..a7bdac55f95b5 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb @@ -198,6 +198,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property + Public Overrides ReadOnly Property FieldRvaSupported As Boolean + Get + Return True + End Get + End Property + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal Return Nothing End Function diff --git a/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb index aad6b5c1be55e..e120c58453b79 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PENetModuleBuilder.vb @@ -45,6 +45,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property + Public Overrides ReadOnly Property FieldRvaSupported As Boolean + Get + Return True + End Get + End Property + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal Return Nothing End Function diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs index 6dfffefaacde8..b0bcd47af9095 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs @@ -67,6 +67,7 @@ protected override Cci.IModuleReference TranslateModule(ModuleSymbol symbol, Dia internal override bool IgnoreAccessibility => true; public override EmitBaseline? PreviousGeneration => null; public override SymbolChanges? EncSymbolChanges => null; + public override bool FieldRvaSupported => true; public override INamedTypeSymbolInternal? TryGetOrCreateSynthesizedHotReloadExceptionType() => null; diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs index 733ed84419182..07102f9c9e0f8 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ReferencedModulesTests.cs @@ -1543,6 +1543,7 @@ public override IEnumerable GetTopLevelSourceTypeDefin public override SymbolChanges EncSymbolChanges => _builder.EncSymbolChanges; public override EmitBaseline PreviousGeneration => _builder.PreviousGeneration; + public override bool FieldRvaSupported => _builder.FieldRvaSupported; public override ISourceAssemblySymbolInternal SourceAssemblyOpt => _builder.SourceAssemblyOpt; diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb index f3837978bc0db..6fb8bc777acec 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb @@ -81,6 +81,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End Get End Property + Public Overrides ReadOnly Property FieldRvaSupported As Boolean + Get + Return True + End Get + End Property + Public Overrides Function TryGetOrCreateSynthesizedHotReloadExceptionType() As INamedTypeSymbolInternal Return Nothing End Function diff --git a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb index 035e5a7d149dc..e2afb96c254f2 100644 --- a/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb +++ b/src/ExpressionEvaluator/VisualBasic/Test/ExpressionCompiler/ReferencedModulesTests.vb @@ -969,7 +969,13 @@ End Class" Public Overrides ReadOnly Property PreviousGeneration As EmitBaseline Get - Return Nothing + Return _builder.PreviousGeneration + End Get + End Property + + Public Overrides ReadOnly Property FieldRvaSupported As Boolean + Get + Return _builder.FieldRvaSupported End Get End Property diff --git a/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs b/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs index 36607b513ff06..5666e53e55810 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditAndContinueCapabilities.cs @@ -70,6 +70,12 @@ internal enum EditAndContinueCapabilities /// The runtime supports adding to InterfaceImpl table. /// AddExplicitInterfaceImplementation = 1 << 10, + + /// + /// The runtime supports adding FieldRva table entry. This allows compiler to emit better code for certain features including + /// array initializers, collection expressions, UTF8 string literals and data section string literals. + /// + AddFieldRva = 1 << 11, } internal static class EditAndContinueCapabilitiesParser @@ -93,6 +99,7 @@ public static EditAndContinueCapabilities Parse(ImmutableArray capabilit nameof(EditAndContinueCapabilities.GenericUpdateMethod) => EditAndContinueCapabilities.GenericUpdateMethod, nameof(EditAndContinueCapabilities.GenericAddFieldToExistingType) => EditAndContinueCapabilities.GenericAddFieldToExistingType, nameof(EditAndContinueCapabilities.AddExplicitInterfaceImplementation) => EditAndContinueCapabilities.AddExplicitInterfaceImplementation, + nameof(EditAndContinueCapabilities.AddFieldRva) => EditAndContinueCapabilities.AddFieldRva, // To make it eaiser for runtimes to specify more broad capabilities "AddDefinitionToExistingType" => EditAndContinueCapabilities.AddMethodToExistingType | EditAndContinueCapabilities.AddStaticFieldToExistingType | EditAndContinueCapabilities.AddInstanceFieldToExistingType, @@ -132,6 +139,9 @@ public static ImmutableArray ToStringArray(this EditAndContinueCapabilit if (capabilities.HasFlag(EditAndContinueCapabilities.AddExplicitInterfaceImplementation)) builder.Add(nameof(EditAndContinueCapabilities.AddExplicitInterfaceImplementation)); + if (capabilities.HasFlag(EditAndContinueCapabilities.AddFieldRva)) + builder.Add(nameof(EditAndContinueCapabilities.AddFieldRva)); + return builder.ToImmutableAndClear(); } } diff --git a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs index 835d7210d8b64..eb7321a98e6f6 100644 --- a/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs +++ b/src/Features/TestUtilities/EditAndContinue/EditAndContinueTestVerifier.cs @@ -40,12 +40,19 @@ internal abstract class EditAndContinueTestVerifier EditAndContinueCapabilities.ChangeCustomAttributes | EditAndContinueCapabilities.UpdateParameters; - public const EditAndContinueCapabilities AllRuntimeCapabilities = + public const EditAndContinueCapabilities Net8RuntimeCapabilities = Net6RuntimeCapabilities | EditAndContinueCapabilities.GenericAddMethodToExistingType | EditAndContinueCapabilities.GenericUpdateMethod | EditAndContinueCapabilities.GenericAddFieldToExistingType; + public const EditAndContinueCapabilities Net10RuntimeCapabilities = + Net8RuntimeCapabilities | + EditAndContinueCapabilities.AddFieldRva; + + public const EditAndContinueCapabilities AllRuntimeCapabilities = + Net10RuntimeCapabilities; + public AbstractEditAndContinueAnalyzer Analyzer { get; } protected EditAndContinueTestVerifier(Action? faultInjector) From 70c212c03dadb71a0fe77bf1f056a359a3bfc257 Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 7 Apr 2025 16:30:08 -0700 Subject: [PATCH 03/21] Fixes, tests --- .../EditAndContinue/EditAndContinueTests.cs | 176 +++++++++++++++++- .../Portable/CodeGen/CompilationTestData.cs | 2 - .../Core/Portable/Compilation/Compilation.cs | 2 +- .../Core/Portable/PublicAPI.Unshipped.txt | 1 + .../Core/Compilation/CompilationExtensions.cs | 3 +- .../VisualBasicSymbolMatcher.vb | 5 +- .../EditAndContinue/EditAndContinueTests.vb | 84 ++++++++- .../Portable/EditAndContinue/EditSession.cs | 1 + .../EditAndContinue/EditAndContinueTest.cs | 19 +- 9 files changed, 273 insertions(+), 20 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 20b1206405283..5a5208393d046 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Text; using System.Threading; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; @@ -19319,13 +19320,13 @@ .maxstack 4 // trailing zeros for alignment: g.VerifyEncFieldRvaData([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); }, - withTestData: d => d.EncFieldRvaSupported = true) + options: new EmitDifferenceOptions() { EmitFieldRva = true }) .Verify(); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] - public void PrivateImplDetails_DataFields_StackAlloc() + public void PrivateImplDetails_DataFields_StackAlloc_FieldRvaNotSupported() { using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net80, verification: Verification.Skipped) .AddBaseline( @@ -19434,7 +19435,96 @@ .locals init (System.ReadOnlySpan V_0, //b [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] - public void PrivateImplDetails_DataFields_Utf8() + public void PrivateImplDetails_DataFields_StackAlloc_FieldRvaSupported() + { + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net80, verification: Verification.Skipped) + .AddBaseline( + source: $$""" + class C + { + void F() { System.ReadOnlySpan b = stackalloc byte[] { 0, 1, 2, 3, 4, 5, 6 }; } + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C", "", "__StaticArrayInitTypeSize=7"); + g.VerifyFieldDefNames("57355AC3303C148F11AEF7CB179456B9232CDE33A818DFDA2C2FCB9325749A6B"); + g.VerifyMethodDefNames("F", ".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + void F() { System.ReadOnlySpan b = stackalloc byte[] { 0, 1, 2, 3, 4, 5, 6, 7 }; } + } + """, + edits: new[] + { + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + }, + validator: g => + { + g.VerifyTypeDefNames("#1"); + g.VerifyFieldDefNames("8A851FF82EE7048AD09EC3847F1DDF44944104D2CBD17EF4E3DB22C6785A0D45"); + g.VerifyMethodDefNames("F"); + + g.VerifyEncLogDefinitions(new[] + { + Row(2, TableIndex.StandAloneSig, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.FieldRva, EditAndContinueOperation.Default) + }); + + g.VerifyEncMapDefinitions(new[] + { + Handle(5, TableIndex.TypeDef), + Handle(2, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute), + Handle(2, TableIndex.StandAloneSig), + Handle(2, TableIndex.FieldRva) + }); + + g.VerifyIL("C.F", """ + { + // Code size 32 (0x20) + .maxstack 4 + .locals init (System.ReadOnlySpan V_0, //b + System.Span V_1) + IL_0000: nop + IL_0001: ldc.i4.8 + IL_0002: conv.u + IL_0003: localloc + IL_0005: dup + IL_0006: ldsflda "long #1.8A851FF82EE7048AD09EC3847F1DDF44944104D2CBD17EF4E3DB22C6785A0D45" + IL_000b: ldc.i4.8 + IL_000c: unaligned. 1 + IL_000f: cpblk + IL_0011: ldc.i4.8 + IL_0012: newobj "System.Span..ctor(void*, int)" + IL_0017: stloc.1 + IL_0018: ldloc.1 + IL_0019: call "System.ReadOnlySpan System.Span.op_Implicit(System.Span)" + IL_001e: stloc.0 + IL_001f: ret + } + """); + + // TODO: better test would be to specify FieldDef -> data. + g.VerifyEncFieldRvaData([0, 1, 2, 3, 4, 5, 6, 7]); + }, + options: new EmitDifferenceOptions() { EmitFieldRva = true }) + .Verify(); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] + public void PrivateImplDetails_DataFields_Utf8_FieldRvaNotSupported() { using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net80, verification: Verification.Skipped) .AddBaseline( @@ -19538,6 +19628,86 @@ .maxstack 4 .Verify(); } + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] + public void PrivateImplDetails_DataFields_Utf8_FieldRvaSupported() + { + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net80, verification: Verification.Skipped) + .AddBaseline( + source: """ + class C + { + System.ReadOnlySpan F() => "0123456789"u8; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C", "", "__StaticArrayInitTypeSize=11"); + g.VerifyFieldDefNames("BEB0DBD1C6FAC1140DD817514F2FBDF501E246BF16C8E877E71187E9EB008189"); + g.VerifyMethodDefNames("F", ".ctor"); + }) + + .AddGeneration( + source: """ + class C + { + System.ReadOnlySpan F() => "0123456789X"u8; + } + """, + edits: new[] + { + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + }, + validator: g => + { + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=12"); + g.VerifyFieldDefNames("AFB1C33C5229BFF7EF739BA44DA795A2B68A49E06001C07C5B026CAA6C6322BB"); + g.VerifyMethodDefNames("F"); + + g.VerifyEncLogDefinitions(new[] + { + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.ClassLayout, EditAndContinueOperation.Default), + Row(2, TableIndex.FieldRva, EditAndContinueOperation.Default), + Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default) + }); + + g.VerifyEncMapDefinitions(new[] + { + Handle(5, TableIndex.TypeDef), + Handle(6, TableIndex.TypeDef), + Handle(2, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute), + Handle(2, TableIndex.ClassLayout), + Handle(2, TableIndex.FieldRva), + Handle(2, TableIndex.NestedClass) + }); + + g.VerifyIL("C.F", """ + { + // Code size 13 (0xd) + .maxstack 2 + IL_0000: ldsflda "#1.__StaticArrayInitTypeSize=12 #1.AFB1C33C5229BFF7EF739BA44DA795A2B68A49E06001C07C5B026CAA6C6322BB" + IL_0005: ldc.i4.s 11 + IL_0007: newobj "System.ReadOnlySpan..ctor(void*, int)" + IL_000c: ret + } + """); + + // TODO: better test would be to specify FieldDef -> data. + // Trailing zeros for alignment. + g.VerifyEncFieldRvaData([.. Encoding.UTF8.GetBytes("0123456789X"), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + }, + options: new EmitDifferenceOptions() { EmitFieldRva = true }) + .Verify(); + } + [Theory] [InlineData("ComputeStringHash", "string")] [InlineData("ComputeSpanHash", "Span")] diff --git a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs index b0a41dc4036b0..3797649644974 100644 --- a/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs +++ b/src/Compilers/Core/Portable/CodeGen/CompilationTestData.cs @@ -44,8 +44,6 @@ public MethodData(ILBuilder ilBuilder, IMethodSymbolInternal method) private ImmutableDictionary? _lazyMethodsByName; - public bool EncFieldRvaSupported { get; set; } - public void SetMetadataWriter(MetadataWriter writer) { Debug.Assert(MetadataWriter == null); diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 5e19a729ff5ba..d0da7ffef3e07 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -3094,7 +3094,7 @@ public EmitDifferenceResult EmitDifference( Stream metadataStream, Stream ilStream, Stream pdbStream, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default(CancellationToken)) => EmitDifference(baseline, edits, isAddedSymbol, metadataStream, ilStream, pdbStream, EmitDifferenceOptions.Default, cancellationToken); /// diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index a2e4308ced80a..9059815b528f6 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,4 +1,5 @@ Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions options, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! +Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitDifferenceOptions() -> void Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitFieldRva.get -> bool diff --git a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs index b9db193054532..32f881abf5f02 100644 --- a/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs +++ b/src/Compilers/Test/Core/Compilation/CompilationExtensions.cs @@ -142,6 +142,7 @@ internal static CompilationDifference EmitDifference( EmitBaseline baseline, ImmutableArray edits, IEnumerable allAddedSymbols = null, + EmitDifferenceOptions? options = null, CompilationTestData testData = null) { testData ??= new CompilationTestData(); @@ -158,7 +159,7 @@ internal static CompilationDifference EmitDifference( mdStream, ilStream, pdbStream, - EmitDifferenceOptions.Default, + options ?? EmitDifferenceOptions.Default, testData, CancellationToken.None); diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb index 6e53bb10ee2c2..be6752e8a4e07 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb @@ -45,7 +45,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ' For simplicity, PID helpers and no-PIA embedded definitions are not reused across generations, so we don't map them here. ' Instead, new ones are regenerated as needed. - Debug.Assert(TypeOf definition Is PrivateImplementationDetails OrElse TypeOf definition Is Cci.IEmbeddedDefinition) + Debug.Assert(TypeOf definition Is PrivateImplementationDetails OrElse + TypeOf definition Is Cci.IEmbeddedDefinition OrElse + TypeOf definition Is MappedField OrElse + TypeOf definition Is ExplicitSizeStruct) Return Nothing End Function diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb index 8e3998babc5e9..c828331b82cff 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb @@ -7436,7 +7436,7 @@ End Class", - Public Sub PrivateImplDetails_DataFields_Arrays() + Public Sub PrivateImplDetails_DataFields_Arrays_FieldRvaNotSupported() Using New EditAndContinueTest(). AddBaseline( source:=" @@ -7536,6 +7536,88 @@ End Class + Public Sub PrivateImplDetails_DataFields_Arrays_FieldRvaSupported() + Using New EditAndContinueTest(). + AddBaseline( + source:=" +Class C + Dim b As Byte() = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } +End Class +", + validator:= + Sub(g) + g.VerifyTypeDefNames("", "C", "", "__StaticArrayInitTypeSize=10") + g.VerifyFieldDefNames("b", "1F825AA2F0020EF7CF91DFA30DA4668D791C5D4824FC8E41354B89EC05795AB3") + g.VerifyMethodDefNames(".ctor") + End Sub). + AddGeneration( + source:=" +Class C + Dim b As Byte() = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } +End Class +", + edits:= + { + Edit(SemanticEditKind.Update, symbolProvider:=Function(c) c.GetMember("C..ctor")) + }, + validator:= + Sub(g) + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=11") + g.VerifyFieldDefNames("78A6273103D17C39A0B6126E226CEC70E33337F4BC6A38067401B54A33E78EAD") + g.VerifyMethodDefNames(".ctor") + + g.VerifyEncLogDefinitions( + { + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.ClassLayout, EditAndContinueOperation.Default), + Row(2, TableIndex.FieldRva, EditAndContinueOperation.Default), + Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default) + }) + + g.VerifyEncMapDefinitions( + { + Handle(5, TableIndex.TypeDef), + Handle(6, TableIndex.TypeDef), + Handle(3, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(5, TableIndex.CustomAttribute), + Handle(2, TableIndex.ClassLayout), + Handle(2, TableIndex.FieldRva), + Handle(2, TableIndex.NestedClass) + }) + + g.VerifyIL("C..ctor", " +{ + // Code size 32 (0x20) + .maxstack 4 + IL_0000: ldarg.0 + IL_0001: call ""Sub Object..ctor()"" + IL_0006: nop + IL_0007: ldarg.0 + IL_0008: ldc.i4.s 11 + IL_000a: newarr ""Byte"" + IL_000f: dup + IL_0010: ldtoken ""#1.__StaticArrayInitTypeSize=11 #1.78A6273103D17C39A0B6126E226CEC70E33337F4BC6A38067401B54A33E78EAD"" + IL_0015: call ""Sub System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_001a: stfld ""C.b As Byte()"" + IL_001f: ret +}") + End Sub, + options:= + New EmitDifferenceOptions() With + { + .EmitFieldRva = True + }). + Verify() + End Using + End Sub + + Public Sub PrivateImplDetails_ComputeStringHash() Using New EditAndContinueTest(). AddBaseline( diff --git a/src/Features/Core/Portable/EditAndContinue/EditSession.cs b/src/Features/Core/Portable/EditAndContinue/EditSession.cs index cfdd757268587..9b7c90fd750ee 100644 --- a/src/Features/Core/Portable/EditAndContinue/EditSession.cs +++ b/src/Features/Core/Portable/EditAndContinue/EditSession.cs @@ -1097,6 +1097,7 @@ void UpdateChangedDocumentsStaleness(bool isStale) metadataStream, ilStream, pdbStream, + new EmitDifferenceOptions() { EmitFieldRva = capabilities.HasFlag(EditAndContinueCapabilities.AddFieldRva) }, cancellationToken); Telemetry.LogEmitDifferenceTime(emitDifferenceTimer.Elapsed); diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs index d75ef4a6d6f63..6734d072eb3db 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.cs @@ -71,16 +71,16 @@ internal TSelf AddBaseline(string source, Action? validator return This; } - internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, Action validator, Action? withTestData = null) - => AddGeneration(source, _ => edits, validator, withTestData); + internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, Action validator, EmitDifferenceOptions? options = null) + => AddGeneration(source, _ => edits, validator, options); - internal TSelf AddGeneration(string source, Func edits, Action validator, Action? withTestData = null) - => AddGeneration(source, edits, validator, expectedErrors: [], withTestData); + internal TSelf AddGeneration(string source, Func edits, Action validator, EmitDifferenceOptions? options = null) + => AddGeneration(source, edits, validator, expectedErrors: [], options); - internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, DiagnosticDescription[] expectedErrors, Action? withTestData = null) - => AddGeneration(source, _ => edits, validator: static _ => { }, expectedErrors, withTestData); + internal TSelf AddGeneration(string source, SemanticEditDescription[] edits, DiagnosticDescription[] expectedErrors, EmitDifferenceOptions? options = null) + => AddGeneration(source, _ => edits, validator: static _ => { }, expectedErrors, options); - private TSelf AddGeneration(string source, Func edits, Action validator, DiagnosticDescription[] expectedErrors, Action? withTestData) + private TSelf AddGeneration(string source, Func edits, Action validator, DiagnosticDescription[] expectedErrors, EmitDifferenceOptions? options = null) { _hasVerified = false; @@ -98,10 +98,7 @@ private TSelf AddGeneration(string source, Func d.Severity == DiagnosticSeverity.Error).Verify(expectedErrors); if (expectedErrors is not []) From 413edff33c3ebcf21b2d6447ae0f891e36ae2290 Mon Sep 17 00:00:00 2001 From: tmat Date: Mon, 7 Apr 2025 17:00:32 -0700 Subject: [PATCH 04/21] Fix --- src/Compilers/Core/Portable/Compilation/Compilation.cs | 2 +- src/Compilers/Core/Portable/PublicAPI.Unshipped.txt | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index d0da7ffef3e07..5541662c31318 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -3112,7 +3112,7 @@ public EmitDifferenceResult EmitDifference( Stream ilStream, Stream pdbStream, EmitDifferenceOptions options, - CancellationToken cancellationToken) + CancellationToken cancellationToken = default(CancellationToken)) { if (baseline == null) { diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 9059815b528f6..d93281dfa3460 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,5 +1,4 @@ -Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions options, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! -Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, System.Threading.CancellationToken cancellationToken) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! +Microsoft.CodeAnalysis.Compilation.EmitDifference(Microsoft.CodeAnalysis.Emit.EmitBaseline! baseline, System.Collections.Generic.IEnumerable! edits, System.Func! isAddedSymbol, System.IO.Stream! metadataStream, System.IO.Stream! ilStream, System.IO.Stream! pdbStream, Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions options, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.Emit.EmitDifferenceResult! Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitDifferenceOptions() -> void Microsoft.CodeAnalysis.Emit.EmitDifferenceOptions.EmitFieldRva.get -> bool From 6d6ec8cc0acef395642a3ff6c6ad4b8c65a63333 Mon Sep 17 00:00:00 2001 From: tmat Date: Tue, 8 Apr 2025 17:16:29 -0700 Subject: [PATCH 05/21] Support for data section string literals --- .../CSharp/Portable/CSharpResources.resx | 3 + .../CSharp/Portable/CodeGen/EmitExpression.cs | 43 ++- .../EditAndContinue/CSharpSymbolMatcher.cs | 10 +- .../CSharp/Portable/Errors/ErrorCode.cs | 2 + .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../EditAndContinue/EditAndContinueTests.cs | 300 ++++++++++++++++++ .../CodeGen/PrivateImplementationDetails.cs | 4 +- .../Emit/EditAndContinue/DeletedMethodBody.cs | 2 +- .../EditAndContinue/DeltaMetadataWriter.cs | 12 +- .../Emit/EditAndContinue/EmitBaseline.cs | 8 + .../Portable/PEWriter/MethodDefinitionBase.cs | 6 +- 23 files changed, 435 insertions(+), 20 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index ebb126ee94926..61cb849a9e4d7 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5314,6 +5314,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + It is not legal to use nullable type '{0}?' in a pattern; use the underlying type '{0}' instead. diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 0b8cfbc2f54b7..5bc562bd0357b 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -11,6 +11,7 @@ using System.Runtime.CompilerServices; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -3491,27 +3492,51 @@ private void EmitConstantExpression(TypeSymbol type, ConstantValue constantValue private bool TryEmitStringLiteralAsUtf8Encoded(ConstantValue constantValue, SyntaxNode syntaxNode) { // Emit long strings into data section so they don't overflow the UserString heap. - if (constantValue.IsString && - constantValue.StringValue.Length > _module.Compilation.DataSectionStringLiteralThreshold) + if (!constantValue.IsString) { - if (Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__get_UTF8, _diagnostics, syntax: syntaxNode) == null | - Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__GetString, _diagnostics, syntax: syntaxNode) == null) - { - return false; - } + return false; + } - Cci.IFieldReference field = _module.TryGetOrCreateFieldForStringValue(constantValue.StringValue, syntaxNode, _diagnostics.DiagnosticBag); - if (field == null) + bool utf8Required = _module.PreviousGeneration != null && _module.PreviousGeneration.UserStringStreamLength > EmitBaseline.UserStringHeapSizeLimit; + if (!utf8Required) + { + var threshold = _module.Compilation.DataSectionStringLiteralThreshold; + if (threshold == null || constantValue.StringValue.Length <= threshold) { return false; } + } + var field = tryGetOrCreateField(); + if (field != null) + { _builder.EmitOpCode(ILOpCode.Ldsfld); _builder.EmitToken(field, syntaxNode, _diagnostics.DiagnosticBag); return true; } + if (utf8Required) + { + _diagnostics.Add(ErrorCode.ERR_TooManyUserStrings_RestartRequired, syntaxNode); + } + return false; + + Cci.IFieldReference tryGetOrCreateField() + { + if (!_module.FieldRvaSupported) + { + return null; + } + + if (GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__get_UTF8, _diagnostics, syntax: syntaxNode) == null | + GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__GetString, _diagnostics, syntax: syntaxNode) == null) + { + return null; + } + + return _module.TryGetOrCreateFieldForStringValue(constantValue.StringValue, syntaxNode, _diagnostics.DiagnosticBag); + } } private void EmitInitObj(TypeSymbol type, bool used, SyntaxNode syntaxNode) diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs index 50dbee6c358d6..c09438b4b510a 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs @@ -57,9 +57,17 @@ public CSharpSymbolMatcher( // For simplicity, PID helpers and no-PIA embedded definitions are not reused across generations, so we don't map them here. // Instead, new ones are regenerated as needed. - Debug.Assert(definition is PrivateImplementationDetails or Cci.IEmbeddedDefinition or MappedField or ExplicitSizeStruct); + + Debug.Assert( + definition is Cci.IEmbeddedDefinition || + isPrivateImplementationDetail(definition), + $"Unexpected definition of type: {definition.GetType()}"); return null; + + static bool isPrivateImplementationDetail(Cci.IDefinition definition) + => definition is PrivateImplementationDetails || + definition is Cci.ITypeDefinitionMember { ContainingTypeDefinition: var container } && isPrivateImplementationDetail(container); } public override Cci.INamespace? MapNamespace(Cci.INamespace @namespace) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 25ba50f1a42e3..870761a8c3a51 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1337,6 +1337,7 @@ internal enum ErrorCode ERR_PublicSignButNoKey = 8102, ERR_TooManyUserStrings = 8103, ERR_PeWritingFailure = 8104, + #endregion diagnostics introduced in Roslyn (C# 6) #region diagnostics introduced in C# 6 updates @@ -2398,6 +2399,7 @@ internal enum ErrorCode ERR_ModifierOnUnnamedReceiverParameter = 9305, ERR_ExtensionTypeNameDisallowed = 9306, ERR_ExpressionTreeContainsNamedArgumentOutOfPosition = 9307, + ERR_TooManyUserStrings_RestartRequired = 9308, ERR_OperatorsMustBePublic = 9308, // available 9309, diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 7b6ef24f74a69..37ae8bfc426e4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -2397,6 +2397,11 @@ Literál nezpracovaného řetězce nezačíná dostatečným počtem uvozovek, aby bylo možné tento počet po sobě jdoucích znaků uvozovek povolit jako obsah. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Příkazy nejvyšší úrovně se musí nacházet před obory názvů a deklaracemi typů. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index ce1baff1c7ab2..e481e2a789344 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -2397,6 +2397,11 @@ Das Rohzeichenfolgenliteral beginnt nicht mit genügend Anführungszeichen, um so viele aufeinanderfolgende Anführungszeichen als Inhalt zuzulassen. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Anweisungen der obersten Ebene müssen vor Namespace- und Typdeklarationen stehen. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index d14f5fbc2aa2d..3dcae73e93f47 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -2397,6 +2397,11 @@ El literal de cadena sin formato no comienza con suficientes comillas para permitir tantas comillas consecutivas como contenido. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Las instrucciones de nivel superior deben preceder a las declaraciones de espacio de nombres y de tipos. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index a0db1f39b8732..73299c0f6772f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -2397,6 +2397,11 @@ Le littéral brut de la chaîne de caractères ne commence pas par un nombre suffisant de caractères de guillemets pour autoriser un tel nombre de caractères de guillemets consécutifs comme contenu. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Les instructions de niveau supérieur doivent précéder les déclarations d'espace de noms et de type. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 4776064d30d8f..ca9c6d183269e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -2397,6 +2397,11 @@ Il valore letterale stringa non elaborato non inizia con un numero sufficiente di virgolette per consentire questo numero di virgolette consecutive come contenuto. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Le istruzioni di primo livello devono precedere le dichiarazioni di tipo e di spazio dei nomi. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 67daf55e4fd5a..64ffd6274eeff 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -2397,6 +2397,11 @@ 生文字列リテラルの先頭に十分な数の引用符文字がないため、連続した引用符文字をコンテンツとして使用できません。 + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. トップレベルのステートメントは、名前空間および型の宣言の前にある必要があります。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 445c283cdecb1..7c16a674e240b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -2397,6 +2397,11 @@ 원시 문자열 리터럴을 시작하는 따옴표 문자가 부족해 이렇게 많은 따옴표 문자를 콘텐츠로 사용할 수 없습니다. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. 최상위 문은 네임스페이스 및 형식 선언 앞에 와야 합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 92320e99565ad..40a51a9d7aba7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -2397,6 +2397,11 @@ Nieprzetworzony literał ciągu nie rozpoczyna się od wystarczającej liczby znaków cudzysłowu, aby umożliwić używanie tak wielu kolejnych znaków cudzysłowu jako zawartości. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Instrukcje najwyższego poziomu muszą poprzedzać deklaracje przestrzeni nazw i typów. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 963929d643cd1..133576185f638 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -2397,6 +2397,11 @@ A literal da cadeia de caracteres bruta não começa com caracteres de aspa suficientes para permitir esse número de caracteres de aspa consecutivos como conteúdo. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. As instruções de nível superior precisam preceder as declarações de namespace e de tipo. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index afe4e0b90bd80..30b7d953160bf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -2397,6 +2397,11 @@ Литерал необработанной строки не начинается с достаточного количества символов кавычек, чтобы разрешить использовать такое же количество последовательных символов кавычек в качестве содержимого. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Инструкции верхнего уровня должны предшествовать объявлениям пространств имен и типов. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 9015530c02117..2c46ca1dae051 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -2397,6 +2397,11 @@ Ham dize sabit değeri, içerik olarak bu kadar çok ardışık tırnak işareti karakterine izin vermek için yeterli sayıda tırnak işareti karakteriyle başlamıyor. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. Üst düzey deyimler ad alanı ve tür bildirimlerinden önce gelmelidir. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index d92f7af8a95a5..8ca0b9a047b72 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -2397,6 +2397,11 @@ 原始字符串字面量的开头没有足够的引号字符以允许将这么多连续的引号字符作为内容。 + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. 顶级语句必须位于命名空间和类型声明之前。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 0688757833c5b..04b102802f385 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -2397,6 +2397,11 @@ 原始字串常值開頭沒有足夠的引號字元,因此無法允許這麼多連續的引號字元做為內容。 + + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + + Top-level statements must precede namespace and type declarations. 最上層陳述式必須在命名空間和型別宣告之前。 diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 5a5208393d046..bbcca3ee80149 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -19708,6 +19708,306 @@ .maxstack 2 .Verify(); } + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] + public void PrivateImplDetails_DataSectionStringLiterals_FieldRvaSupported() + { + var parseOptions = TestOptions.Regular.WithFeature("experimental-data-section-string-literals", "0"); + + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped, parseOptions: parseOptions) + .AddBaseline( + source: """ + class C + { + string F() => "0123456789"; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C", "", "__StaticArrayInitTypeSize=10", "E353667619EC664B49655FC9692165FB"); + g.VerifyFieldDefNames("84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882", "s"); + g.VerifyMethodDefNames("F", ".ctor", "BytesToString", ".cctor"); + }) + .AddGeneration( + source: """ + class C + { + string F() => "0123456789X"; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + ], + validator: g => + { + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=11", "6D2201523542AEFFB91657B2AEBDC84B"); + g.VerifyFieldDefNames("ACE59E7D984CCEB2D860A056A3386344236CE5C42C978E26ECE3F35956DAC3AD", "s"); + g.VerifyMethodDefNames("F", "BytesToString", ".cctor"); + + g.VerifyEncLogDefinitions( + [ + Row(6, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(7, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(8, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(3, TableIndex.Field, EditAndContinueOperation.Default), + Row(8, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(4, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(3, TableIndex.Param, EditAndContinueOperation.Default), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(6, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(2, TableIndex.ClassLayout, EditAndContinueOperation.Default), + Row(2, TableIndex.FieldRva, EditAndContinueOperation.Default), + Row(3, TableIndex.NestedClass, EditAndContinueOperation.Default), + Row(4, TableIndex.NestedClass, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(6, TableIndex.TypeDef), + Handle(7, TableIndex.TypeDef), + Handle(8, TableIndex.TypeDef), + Handle(3, TableIndex.Field), + Handle(4, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(5, TableIndex.MethodDef), + Handle(6, TableIndex.MethodDef), + Handle(3, TableIndex.Param), + Handle(4, TableIndex.Param), + Handle(6, TableIndex.CustomAttribute), + Handle(2, TableIndex.ClassLayout), + Handle(2, TableIndex.FieldRva), + Handle(3, TableIndex.NestedClass), + Handle(4, TableIndex.NestedClass) + ]); + + g.VerifyIL("C.F", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "string #1.6D2201523542AEFFB91657B2AEBDC84B.s" + IL_0005: ret + } + """); + + // TODO: better test would be to specify FieldDef -> data. + // Trailing zero for alignment. + g.VerifyEncFieldRvaData([.. Encoding.UTF8.GetBytes("0123456789X"), 0x00]); + }, + options: new EmitDifferenceOptions() { EmitFieldRva = true }) + .Verify(); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] + public void PrivateImplDetails_DataSectionStringLiterals_FieldRvaNotSupported() + { + var parseOptions = TestOptions.Regular.WithFeature("experimental-data-section-string-literals", "0"); + + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped, parseOptions: parseOptions) + .AddBaseline( + source: """ + class C + { + string F() => "0123456789"; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C", "", "__StaticArrayInitTypeSize=10", "E353667619EC664B49655FC9692165FB"); + g.VerifyFieldDefNames("84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882", "s"); + g.VerifyMethodDefNames("F", ".ctor", "BytesToString", ".cctor"); + }) + .AddGeneration( + source: """ + class C + { + string F() => "0123456789X"; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + ], + validator: g => + { + g.VerifyTypeDefNames(); + g.VerifyFieldDefNames(); + g.VerifyMethodDefNames("F"); + + g.VerifyEncLogDefinitions( + [ + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(1, TableIndex.MethodDef) + ]); + + g.VerifyIL("C.F", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldstr "0123456789X" + IL_0005: ret + } + """); + }) + .Verify(); + } + + [Fact] + [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] + public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaSupported() + { + // The max number of bytes that can fit into #US the heap is 2^29 - 1, + // but each string also needs to have an offset < 0x1000000 (2^24) to be addressable by a token. + // If the string is larger than that the next string can't be emitted. + var baseString = new string('x', 1 << 24); + + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) + .AddBaseline( + source: $$""" + class C + { + string F() => "{{baseString}}"; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyFieldDefNames(); + g.VerifyMethodDefNames("F", ".ctor"); + }) + .AddGeneration( + source: """ + class C + { + string F() => "0123456789"; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + ], + validator: g => + { + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=10", "E353667619EC664B49655FC9692165FB"); + g.VerifyFieldDefNames("84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882", "s"); + g.VerifyMethodDefNames("F", "BytesToString", ".cctor"); + + g.VerifyEncLogDefinitions( + [ + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(1, TableIndex.Param, EditAndContinueOperation.Default), + Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(2, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(1, TableIndex.ClassLayout, EditAndContinueOperation.Default), + Row(1, TableIndex.FieldRva, EditAndContinueOperation.Default), + Row(1, TableIndex.NestedClass, EditAndContinueOperation.Default), + Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(3, TableIndex.TypeDef), + Handle(4, TableIndex.TypeDef), + Handle(5, TableIndex.TypeDef), + Handle(1, TableIndex.Field), + Handle(2, TableIndex.Field), + Handle(1, TableIndex.MethodDef), + Handle(3, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(1, TableIndex.Param), + Handle(2, TableIndex.Param), + Handle(4, TableIndex.CustomAttribute), + Handle(1, TableIndex.ClassLayout), + Handle(1, TableIndex.FieldRva), + Handle(1, TableIndex.NestedClass), + Handle(2, TableIndex.NestedClass) + ]); + + g.VerifyIL("C.F", """ + { + // Code size 6 (0x6) + .maxstack 1 + IL_0000: ldsfld "string #1.E353667619EC664B49655FC9692165FB.s" + IL_0005: ret + } + """); + + // TODO: better test would be to specify FieldDef -> data. + // Trailing zero for alignment. + g.VerifyEncFieldRvaData([.. Encoding.UTF8.GetBytes("0123456789"), 0x00, 0x00]); + }, + options: new EmitDifferenceOptions() { EmitFieldRva = true }) + .Verify(); + } + + [Fact] + public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaNotSupported() + { + // The max number of bytes that can fit into #US the heap is 2^29 - 1, + // but each string also needs to have an offset < 0x1000000 (2^24) to be addressable by a token. + // If the string is larger than that the next string can't be emitted. + var baseString = new string('x', 1 << 24); + + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) + .AddBaseline( + source: $$""" + class C + { + string F() => "{{baseString}}"; + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyFieldDefNames(); + g.VerifyMethodDefNames("F", ".ctor"); + }) + .AddGeneration( + source: """ + class C + { + string F() => "new string that doesn't fit"; + } + """, + edits: + [ + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + ], + expectedErrors: + [ + // (3,19): error CS9307: Combined length of user strings used by the program exceeds allowed limit. Adding a string literal requires restarting the application. + // string F() => "new string that doesn't fit"; + Diagnostic(ErrorCode.ERR_TooManyUserStrings_RestartRequired, @"""new string that doesn't fit""").WithLocation(3, 19) + ]) + .Verify(); + } + [Theory] [InlineData("ComputeStringHash", "string")] [InlineData("ComputeSpanHash", "Span")] diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 87b9df89e731c..e7b8663539510 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -793,7 +793,7 @@ static Cci.IMethodDefinition synthesizeStaticConstructor( public override IEnumerable GetMethods(EmitContext context) => _methods; public override bool IsBeforeFieldInit => true; - private sealed class DataSectionStringField( + internal sealed class DataSectionStringField( string name, Cci.INamedTypeDefinition containingType) : SynthesizedStaticFieldBase(name, containingType) { @@ -1154,7 +1154,7 @@ public sealed override int GetHashCode() /// } /// /// - file sealed class BytesToStringHelper : Cci.MethodDefinitionBase + internal sealed class BytesToStringHelper : Cci.MethodDefinitionBase { private readonly ImmutableArray _parameters; diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs index 72328ce901753..698d0babaf0e7 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs @@ -43,7 +43,7 @@ internal sealed class DeletedMethodBody(IDeletedMethodDefinition methodDef, Immu public DebugId MethodId => default; - public ImmutableArray StateMachineHoistedLocalScopes => ImmutableArray.Empty; + public ImmutableArray StateMachineHoistedLocalScopes => default; public string StateMachineTypeName => null; diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 61e57208e7f8b..7b783bb5a38bd 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -133,10 +133,14 @@ public DeltaMetadataWriter( private static MetadataBuilder MakeTablesBuilder(EmitBaseline previousGeneration) { return new MetadataBuilder( - previousGeneration.UserStringStreamLength, - previousGeneration.StringStreamLength, - previousGeneration.BlobStreamLength, - previousGeneration.GuidStreamLength); + // Any string on the #UserString heap must start at an offset less than 2^24 (limited by token size). + // The baseline #UserString heap size might exceed this limit as long as the last string it contains starts within the limit. + // If the limit is exceeded we can't add any more strings in the delta heap (they would start beyond the limit), but we still can emit deltas. + // The check in MetadataBuilder constructor is enforcing the limit, but it should really only throw when a new string is added. + userStringHeapStartOffset: Math.Min(EmitBaseline.UserStringHeapSizeLimit, previousGeneration.UserStringStreamLength), + stringHeapStartOffset: previousGeneration.StringStreamLength, + blobHeapStartOffset: previousGeneration.BlobStreamLength, + guidHeapStartOffset: previousGeneration.GuidStreamLength); } private ImmutableArray GetDeltaTableSizes(ImmutableArray rowCounts) diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs index 6e5c4a4c69f4f..3c7f9d5cbd386 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs @@ -62,6 +62,14 @@ public override int GetHashCode() /// public sealed class EmitBaseline { + /// + /// Once the baseline #UserString heap reaches this size, we can't emit any more string literals to it. + /// We need to switch to using FieldRVAs for any new string literals, if the runtime supports it. + /// + /// See https://github.com/dotnet/runtime/blob/2bd17019c1c01a6bf17a2de244ff92591fc3c334/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs#L82 + /// + internal const int UserStringHeapSizeLimit = 0xfffffe; + private static readonly ImmutableArray s_emptyTableSizes = ImmutableArray.Create(new int[MetadataTokens.TableCount]); internal sealed class MetadataSymbols( diff --git a/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs b/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs index 712124d888ce8..3e5e4814c3b5b 100644 --- a/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs +++ b/src/Compilers/Core/Portable/PEWriter/MethodDefinitionBase.cs @@ -149,13 +149,13 @@ public MethodDefinitionBase(ITypeDefinition containingTypeDefinition, ushort max public DebugId MethodId => default; - public ImmutableArray StateMachineHoistedLocalScopes => ImmutableArray.Empty; + public ImmutableArray StateMachineHoistedLocalScopes => default; public string StateMachineTypeName => null; - public ImmutableArray StateMachineHoistedLocalSlots => ImmutableArray.Empty; + public ImmutableArray StateMachineHoistedLocalSlots => default; - public ImmutableArray StateMachineAwaiterSlots => ImmutableArray.Empty; + public ImmutableArray StateMachineAwaiterSlots => default; public ImmutableArray ClosureDebugInfo => ImmutableArray.Empty; From bc6eda3ea5e7107b0fe29c0253998b4861cf70bf Mon Sep 17 00:00:00 2001 From: tmat Date: Tue, 8 Apr 2025 17:18:30 -0700 Subject: [PATCH 06/21] Cleanup --- src/Compilers/CSharp/Portable/Errors/ErrorCode.cs | 1 - .../Core/Portable/CodeGen/PrivateImplementationDetails.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 870761a8c3a51..e2279e25d3178 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1337,7 +1337,6 @@ internal enum ErrorCode ERR_PublicSignButNoKey = 8102, ERR_TooManyUserStrings = 8103, ERR_PeWritingFailure = 8104, - #endregion diagnostics introduced in Roslyn (C# 6) #region diagnostics introduced in C# 6 updates diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index e7b8663539510..87b9df89e731c 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -793,7 +793,7 @@ static Cci.IMethodDefinition synthesizeStaticConstructor( public override IEnumerable GetMethods(EmitContext context) => _methods; public override bool IsBeforeFieldInit => true; - internal sealed class DataSectionStringField( + private sealed class DataSectionStringField( string name, Cci.INamedTypeDefinition containingType) : SynthesizedStaticFieldBase(name, containingType) { @@ -1154,7 +1154,7 @@ public sealed override int GetHashCode() /// } /// /// - internal sealed class BytesToStringHelper : Cci.MethodDefinitionBase + file sealed class BytesToStringHelper : Cci.MethodDefinitionBase { private readonly ImmutableArray _parameters; From 7b29ab7110a7fcb24c842bef9c82ea1d1fe539fb Mon Sep 17 00:00:00 2001 From: tmat Date: Tue, 8 Apr 2025 17:47:15 -0700 Subject: [PATCH 07/21] Fixes --- src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs | 1 + .../Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 8a8498acc0013..278cbd4318a8a 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -1726,6 +1726,7 @@ or ErrorCode.ERR_BadAwaitInStaticVariableInitializer or ErrorCode.ERR_InvalidPathMap or ErrorCode.ERR_PublicSignButNoKey or ErrorCode.ERR_TooManyUserStrings + or ErrorCode.ERR_TooManyUserStrings_RestartRequired or ErrorCode.ERR_PeWritingFailure or ErrorCode.WRN_AttributeIgnoredWhenPublicSigning or ErrorCode.ERR_OptionMustBeAbsolutePath diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index bbcca3ee80149..90c48948a93e8 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -19872,7 +19872,7 @@ public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaSu // The max number of bytes that can fit into #US the heap is 2^29 - 1, // but each string also needs to have an offset < 0x1000000 (2^24) to be addressable by a token. // If the string is larger than that the next string can't be emitted. - var baseString = new string('x', 1 << 24); + var baseString = new string('x', 1 << 23); using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) .AddBaseline( @@ -19972,7 +19972,7 @@ public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaNo // The max number of bytes that can fit into #US the heap is 2^29 - 1, // but each string also needs to have an offset < 0x1000000 (2^24) to be addressable by a token. // If the string is larger than that the next string can't be emitted. - var baseString = new string('x', 1 << 24); + var baseString = new string('x', 1 << 23); using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) .AddBaseline( From 1d70265be1bbdd0488d52a2fb4ca3099f6b0bb03 Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 11 Apr 2025 14:41:00 -0700 Subject: [PATCH 08/21] Fix and feedback --- .../Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs | 4 ++-- .../Core/Portable/CodeGen/PrivateImplementationDetails.cs | 4 ++-- src/Compilers/Core/Portable/Compilation/Compilation.cs | 2 +- .../Core/Portable/Compilation/EmitDifferenceOptions.cs | 6 +----- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 90c48948a93e8..38793e0d4cc85 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -19757,7 +19757,7 @@ class C Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(6, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(8, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(6, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(5, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(3, TableIndex.Param, EditAndContinueOperation.Default), @@ -19917,7 +19917,7 @@ class C Row(1, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(3, TableIndex.MethodDef, EditAndContinueOperation.Default), - Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), Row(3, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), Row(1, TableIndex.Param, EditAndContinueOperation.Default), diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 87b9df89e731c..8fe27dc2a801c 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -743,14 +743,14 @@ public DataSectionStringType( var stringField = new DataSectionStringField("s", this); - var staticConstructor = synthesizeStaticConstructor((ITokenDeferral)containingType.ModuleBuilder, containingType, dataField, stringField, bytesToStringHelper, diagnostics); + var staticConstructor = synthesizeStaticConstructor((ITokenDeferral)containingType.ModuleBuilder, this, dataField, stringField, bytesToStringHelper, diagnostics); _fields = [stringField]; _methods = [staticConstructor]; static Cci.IMethodDefinition synthesizeStaticConstructor( ITokenDeferral module, - Cci.INamespaceTypeDefinition containingType, + Cci.ITypeDefinition containingType, MappedField dataField, DataSectionStringField stringField, Cci.IMethodDefinition bytesToStringHelper, diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 5541662c31318..d8723ac2993ac 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -3086,7 +3086,7 @@ public EmitDifferenceResult EmitDifference( /// of the current compilation is returned as an EmitBaseline for use in a /// subsequent Edit and Continue. /// - [Obsolete("UpdatedMethods is now part of EmitDifferenceResult, so you should use an overload that doesn't take it.")] + [Obsolete("Use overload that takes EmitDifferenceOptions")] public EmitDifferenceResult EmitDifference( EmitBaseline baseline, IEnumerable edits, diff --git a/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs b/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs index 6388a645953d1..b793f7cad973c 100644 --- a/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs +++ b/src/Compilers/Core/Portable/Compilation/EmitDifferenceOptions.cs @@ -4,7 +4,7 @@ namespace Microsoft.CodeAnalysis.Emit; -public readonly struct EmitDifferenceOptions +public readonly struct EmitDifferenceOptions() { public static readonly EmitDifferenceOptions Default = new(); @@ -12,8 +12,4 @@ public readonly struct EmitDifferenceOptions /// True to emit FieldRva table entries. The runtime must support this feature. /// public bool EmitFieldRva { get; init; } - - public EmitDifferenceOptions() - { - } } From 0a63b9994d86e13f8e939a7908f7a6730412e79c Mon Sep 17 00:00:00 2001 From: tmat Date: Wed, 16 Apr 2025 12:50:36 -0700 Subject: [PATCH 09/21] Flow syntax node to EmitConstantValue --- .../CSharp/Portable/CodeGen/CodeGenerator.cs | 10 +++++----- .../CSharp/Portable/CodeGen/EmitExpression.cs | 4 ++-- .../CSharp/Portable/CodeGen/EmitOperators.cs | 4 ++-- .../CSharp/Portable/CodeGen/EmitStatement.cs | 17 +++++++++++----- .../Core/Portable/CodeGen/ILBuilderEmit.cs | 15 +++++++++----- .../CodeGen/SwitchIntegralJumpTableEmitter.cs | 15 ++++++++++---- .../CodeGen/SwitchStringJumpTableEmitter.cs | 8 ++++++++ .../Portable/CodeGen/EmitConversion.vb | 2 +- .../Portable/CodeGen/EmitExpression.vb | 2 +- .../Portable/CodeGen/EmitOperators.vb | 8 ++++---- .../Portable/CodeGen/EmitStatement.vb | 20 ++++++++++--------- 11 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs index ce7045499e411..1dc9e15f8e2e6 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs @@ -444,15 +444,15 @@ private void EmitRestorePreviousSequencePoint(BoundRestorePreviousSequencePoint if (_savedSequencePoints is null || !_savedSequencePoints.TryGetValue(node.Identifier, out var span)) return; - EmitStepThroughSequencePoint(node.Syntax.SyntaxTree, span); + EmitStepThroughSequencePoint(node.Syntax, span); } private void EmitStepThroughSequencePoint(BoundStepThroughSequencePoint node) { - EmitStepThroughSequencePoint(node.Syntax.SyntaxTree, node.Span); + EmitStepThroughSequencePoint(node.Syntax, node.Span); } - private void EmitStepThroughSequencePoint(SyntaxTree syntaxTree, TextSpan span) + private void EmitStepThroughSequencePoint(SyntaxNode syntaxNode, TextSpan span) { if (!_emitPdbSequencePoints) return; @@ -460,9 +460,9 @@ private void EmitStepThroughSequencePoint(SyntaxTree syntaxTree, TextSpan span) var label = new object(); // The IL builder is eager to discard unreachable code, so // we fool it by branching on a condition that is always true at runtime. - _builder.EmitConstantValue(ConstantValue.Create(true)); + _builder.EmitConstantValue(ConstantValue.Create(true), syntaxNode); _builder.EmitBranch(ILOpCode.Brtrue, label); - EmitSequencePoint(syntaxTree, span); + EmitSequencePoint(syntaxNode.SyntaxTree, span); _builder.EmitOpCode(ILOpCode.Nop); _builder.MarkLabel(label); EmitHiddenSequencePoint(); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 5bc562bd0357b..8ce24b9f6fb3a 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -3439,7 +3439,7 @@ private void EmitDefaultValue(TypeSymbol type, bool used, SyntaxNode syntaxNode) var constantValue = type.GetDefaultValue(); if (constantValue != null) { - _builder.EmitConstantValue(constantValue); + _builder.EmitConstantValue(constantValue, syntaxNode); return; } } @@ -3484,7 +3484,7 @@ private void EmitConstantExpression(TypeSymbol type, ConstantValue constantValue } else if (!TryEmitStringLiteralAsUtf8Encoded(constantValue, syntaxNode)) { - _builder.EmitConstantValue(constantValue); + _builder.EmitConstantValue(constantValue, syntaxNode); } } } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs index 8e90de620d901..87420dd579565 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs @@ -461,7 +461,7 @@ private void EmitIsNotNullOrZero(BoundExpression comparand, ConstantValue nullOr EmitBox(comparandType, comparand.Syntax); } - _builder.EmitConstantValue(nullOrZero); + _builder.EmitConstantValue(nullOrZero, comparand.Syntax); _builder.EmitOpCode(ILOpCode.Cgt_un); } @@ -475,7 +475,7 @@ private void EmitIsNullOrZero(BoundExpression comparand, ConstantValue nullOrZer EmitBox(comparandType, comparand.Syntax); } - _builder.EmitConstantValue(nullOrZero); + _builder.EmitConstantValue(nullOrZero, comparand.Syntax); _builder.EmitOpCode(ILOpCode.Ceq); } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs index 107a8f02f2481..b780cb70e8b91 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs @@ -1321,7 +1321,7 @@ private void EmitSwitchHeader( } else { - _builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, key, expression.Type.EnumUnderlyingTypeOrSelf().PrimitiveTypeCode); + _builder.EmitIntegerSwitchJumpTable(switchCaseLabels, fallThroughLabel, key, expression.Type.EnumUnderlyingTypeOrSelf().PrimitiveTypeCode, expression.Syntax); } if (temp != null) @@ -1408,7 +1408,10 @@ void emitLengthDispatch(LengthBasedStringSwitchData lengthBasedSwitchInfo, Local // lengthConstant -> corresponding label _builder.EmitIntegerSwitchJumpTable( lengthBasedSwitchInfo.LengthBasedJumpTable.LengthCaseLabels.Select(p => new KeyValuePair(ConstantValue.Create(p.value), p.label)).ToArray(), - fallThroughLabel, stringLength, int32Type.PrimitiveTypeCode); + fallThroughLabel, + stringLength, + int32Type.PrimitiveTypeCode, + syntaxNode); FreeTemp(stringLength); } @@ -1445,7 +1448,10 @@ void emitCharDispatches(LengthBasedStringSwitchData lengthBasedSwitchInfo, Local // charConstant -> corresponding label _builder.EmitIntegerSwitchJumpTable( charJumpTable.CharCaseLabels.Select(p => new KeyValuePair(ConstantValue.Create(p.value), p.label)).ToArray(), - fallThroughLabel, charTemp, charType.PrimitiveTypeCode); + fallThroughLabel, + charTemp, + charType.PrimitiveTypeCode, + syntaxNode); } FreeTemp(charTemp); @@ -1607,6 +1613,7 @@ private void EmitStringSwitchJumpTable( }; _builder.EmitStringSwitchJumpTable( + syntaxNode, caseLabels: switchCaseLabels, fallThroughLabel: fallThroughLabel, key: key, @@ -1702,7 +1709,7 @@ private void EmitStringCompareAndBranch(LocalOrParameter key, SyntaxNode syntaxN // stackAdjustment = (pushCount - popCount) = -1 _builder.EmitLoad(key); - _builder.EmitConstantValue(stringConstant); + _builder.EmitConstantValue(stringConstant, syntaxNode); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: -1); _builder.EmitToken(stringEqualityMethodRef, syntaxNode, _diagnostics.DiagnosticBag); @@ -1729,7 +1736,7 @@ private void EmitCharCompareAndBranch(LocalOrParameter key, SyntaxNode syntaxNod Debug.Assert(asSpanRef != null); _builder.EmitLoad(key); - _builder.EmitConstantValue(stringConstant); + _builder.EmitConstantValue(stringConstant, syntaxNode); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); _builder.EmitToken(asSpanRef, syntaxNode, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: -1); diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 03b1f616d8dda..6796baaa6f53c 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -211,6 +211,7 @@ internal void EmitBranch(ILOpCode code, object label, ILOpCode revOpCode = ILOpC /// /// Primary method for emitting string switch jump table /// + /// Associated syntax for diagnostic reporting. /// switch case labels /// fall through label for the jump table /// Local holding the value to switch on. @@ -227,6 +228,7 @@ internal void EmitBranch(ILOpCode code, object label, ILOpCode revOpCode = ILOpC /// Delegate to compute string hash consistent with value of keyHash. /// internal void EmitStringSwitchJumpTable( + SyntaxNode syntax, KeyValuePair[] caseLabels, object fallThroughLabel, LocalOrParameter key, @@ -238,6 +240,7 @@ internal void EmitStringSwitchJumpTable( var emitter = new SwitchStringJumpTableEmitter( this, + syntax, key, caseLabels, fallThroughLabel, @@ -257,11 +260,13 @@ internal void EmitStringSwitchJumpTable( /// This value has already been loaded onto the execution stack. /// /// Primitive type code of switch key. + /// Associated syntax for error reporting. internal void EmitIntegerSwitchJumpTable( KeyValuePair[] caseLabels, object fallThroughLabel, LocalOrParameter key, - Cci.PrimitiveTypeCode keyTypeCode) + Cci.PrimitiveTypeCode keyTypeCode, + SyntaxNode syntax) { Debug.Assert(caseLabels.Length > 0); Debug.Assert(keyTypeCode != Cci.PrimitiveTypeCode.String); @@ -270,7 +275,7 @@ internal void EmitIntegerSwitchJumpTable( // CONSIDER: Currently, only purpose of creating this caseLabels array is for Emitting the jump table. // CONSIDER: If this requirement changes, we may want to pass in ArrayBuilder> instead. - var emitter = new SwitchIntegralJumpTableEmitter(this, caseLabels, fallThroughLabel, keyTypeCode, key); + var emitter = new SwitchIntegralJumpTableEmitter(this, syntax, caseLabels, fallThroughLabel, keyTypeCode, key); emitter.EmitJumpTable(); } @@ -563,7 +568,7 @@ internal void EmitStoreArgumentOpcode(int argNumber) } } - internal void EmitConstantValue(ConstantValue value) + internal void EmitConstantValue(ConstantValue value, SyntaxNode syntaxNode) { ConstantValueTypeDiscriminator discriminator = value.Discriminator; @@ -608,7 +613,7 @@ internal void EmitConstantValue(ConstantValue value) EmitDoubleConstant(value.DoubleValue); break; case ConstantValueTypeDiscriminator.String: - EmitStringConstant(value.StringValue); + EmitStringConstant(value.StringValue, syntaxNode); break; case ConstantValueTypeDiscriminator.Boolean: EmitBoolConstant(value.BooleanValue); @@ -734,7 +739,7 @@ internal void EmitNullConstant() EmitOpCode(ILOpCode.Ldnull); } - internal void EmitStringConstant(string? value) + internal void EmitStringConstant(string? value, SyntaxNode syntax) { if (value == null) { diff --git a/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs b/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs index 9b57ad3e7bb43..d6cbaed255843 100644 --- a/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs +++ b/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs @@ -19,6 +19,11 @@ internal partial struct SwitchIntegralJumpTableEmitter { private readonly ILBuilder _builder; + /// + /// Associated syntax for diagnostic reporting. + /// + private readonly SyntaxNode _syntax; + /// /// Switch key for the jump table /// @@ -48,12 +53,14 @@ internal partial struct SwitchIntegralJumpTableEmitter internal SwitchIntegralJumpTableEmitter( ILBuilder builder, + SyntaxNode syntax, KeyValuePair[] caseLabels, object fallThroughLabel, Cci.PrimitiveTypeCode keyTypeCode, LocalOrParameter key) { _builder = builder; + _syntax = syntax; _key = key; _keyTypeCode = keyTypeCode; _fallThroughLabel = fallThroughLabel; @@ -423,7 +430,7 @@ private void EmitCondBranchForSwitch(ILOpCode branchCode, ConstantValue constant // branch branchCode targetLabel _builder.EmitLoad(_key); - _builder.EmitConstantValue(constant); + _builder.EmitConstantValue(constant, _syntax); _builder.EmitBranch(branchCode, targetLabel, GetReverseBranchCode(branchCode)); } @@ -443,7 +450,7 @@ private void EmitEqBranchForSwitch(ConstantValue constant, object targetLabel) } else { - _builder.EmitConstantValue(constant); + _builder.EmitConstantValue(constant, _syntax); _builder.EmitBranch(ILOpCode.Beq, targetLabel); } } @@ -458,7 +465,7 @@ private void EmitRangeCheckedBranch(ConstantValue startConstant, ConstantValue e // sub if (!startConstant.IsDefaultValue) { - _builder.EmitConstantValue(startConstant); + _builder.EmitConstantValue(startConstant, _syntax); _builder.EmitOpCode(ILOpCode.Sub); } @@ -521,7 +528,7 @@ private void EmitNormalizedSwitchKey(ConstantValue startConstant, ConstantValue // sub if (!startConstant.IsDefaultValue) { - _builder.EmitConstantValue(startConstant); + _builder.EmitConstantValue(startConstant, _syntax); _builder.EmitOpCode(ILOpCode.Sub); } diff --git a/src/Compilers/Core/Portable/CodeGen/SwitchStringJumpTableEmitter.cs b/src/Compilers/Core/Portable/CodeGen/SwitchStringJumpTableEmitter.cs index d496e0a67be12..939427eac6981 100644 --- a/src/Compilers/Core/Portable/CodeGen/SwitchStringJumpTableEmitter.cs +++ b/src/Compilers/Core/Portable/CodeGen/SwitchStringJumpTableEmitter.cs @@ -19,6 +19,11 @@ internal readonly struct SwitchStringJumpTableEmitter { private readonly ILBuilder _builder; + /// + /// Associated syntax for diagnostic reporting. + /// + private readonly SyntaxNode _syntax; + /// /// Switch key for the jump table /// @@ -65,6 +70,7 @@ internal readonly struct SwitchStringJumpTableEmitter internal SwitchStringJumpTableEmitter( ILBuilder builder, + SyntaxNode syntax, LocalOrParameter key, KeyValuePair[] caseLabels, object fallThroughLabel, @@ -76,6 +82,7 @@ internal SwitchStringJumpTableEmitter( RoslynDebug.Assert(emitStringCondBranchDelegate != null); _builder = builder; + _syntax = syntax; _key = key; _caseLabels = caseLabels; _fallThroughLabel = fallThroughLabel; @@ -148,6 +155,7 @@ private Dictionary EmitHashBucketJumpTable(Dictionary shiftMax Then - _builder.EmitConstantValue(ConstantValue.Create(shiftMax)) + _builder.EmitConstantValue(ConstantValue.Create(shiftMax), expression.Right.Syntax) _builder.EmitOpCode(ILOpCode.And) End If @@ -342,7 +342,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen Dim shiftMax = GetShiftSizeMask(expression.Left.Type) Dim shiftConst = expression.Right.ConstantValueOpt If shiftConst Is Nothing OrElse shiftConst.UInt32Value > shiftMax Then - _builder.EmitConstantValue(ConstantValue.Create(shiftMax)) + _builder.EmitConstantValue(ConstantValue.Create(shiftMax), expression.Right.Syntax) _builder.EmitOpCode(ILOpCode.And) End If @@ -579,7 +579,7 @@ BinaryOperatorKindEqual: EmitBox(comparandType, comparand.Syntax) End If - _builder.EmitConstantValue(nullOrZero) + _builder.EmitConstantValue(nullOrZero, comparand.Syntax) _builder.EmitOpCode(ILOpCode.Cgt_un) End Sub @@ -591,7 +591,7 @@ BinaryOperatorKindEqual: EmitBox(comparandType, comparand.Syntax) End If - _builder.EmitConstantValue(nullOrZero) + _builder.EmitConstantValue(nullOrZero, comparand.Syntax) _builder.EmitOpCode(ILOpCode.Ceq) End Sub diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb index a923f82f0ac79..ba2cff9906326 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb @@ -1048,32 +1048,33 @@ OtherExpressions: Else Dim exprType = selectExpression.Type + Dim syntax As SyntaxNode = selectExpression.Syntax Dim temp As LocalDefinition = Nothing If exprType.SpecialType <> SpecialType.System_String Then If selectExpression.Kind = BoundKind.Local AndAlso Not DirectCast(selectExpression, BoundLocal).LocalSymbol.IsByRef Then - _builder.EmitIntegerSwitchJumpTable(caseLabels, fallThroughLabel, GetLocal(DirectCast(selectExpression, BoundLocal)), keyTypeCode:=exprType.GetEnumUnderlyingTypeOrSelf.PrimitiveTypeCode) + _builder.EmitIntegerSwitchJumpTable(caseLabels, fallThroughLabel, GetLocal(DirectCast(selectExpression, BoundLocal)), keyTypeCode:=exprType.GetEnumUnderlyingTypeOrSelf.PrimitiveTypeCode, syntax) ElseIf selectExpression.Kind = BoundKind.Parameter AndAlso Not DirectCast(selectExpression, BoundParameter).ParameterSymbol.IsByRef Then - _builder.EmitIntegerSwitchJumpTable(caseLabels, fallThroughLabel, ParameterSlot(DirectCast(selectExpression, BoundParameter)), keyTypeCode:=exprType.GetEnumUnderlyingTypeOrSelf.PrimitiveTypeCode) + _builder.EmitIntegerSwitchJumpTable(caseLabels, fallThroughLabel, ParameterSlot(DirectCast(selectExpression, BoundParameter)), keyTypeCode:=exprType.GetEnumUnderlyingTypeOrSelf.PrimitiveTypeCode, syntax) Else EmitExpression(selectExpression, True) - temp = AllocateTemp(exprType, selectExpression.Syntax) + temp = AllocateTemp(exprType, syntax) _builder.EmitLocalStore(temp) - _builder.EmitIntegerSwitchJumpTable(caseLabels, fallThroughLabel, temp, keyTypeCode:=exprType.GetEnumUnderlyingTypeOrSelf.PrimitiveTypeCode) + _builder.EmitIntegerSwitchJumpTable(caseLabels, fallThroughLabel, temp, keyTypeCode:=exprType.GetEnumUnderlyingTypeOrSelf.PrimitiveTypeCode, syntax) End If Else If selectExpression.Kind = BoundKind.Local AndAlso Not DirectCast(selectExpression, BoundLocal).LocalSymbol.IsByRef Then - EmitStringSwitchJumpTable(caseLabels, fallThroughLabel, GetLocal(DirectCast(selectExpression, BoundLocal)), selectExpression.Syntax) + EmitStringSwitchJumpTable(caseLabels, fallThroughLabel, GetLocal(DirectCast(selectExpression, BoundLocal)), syntax) Else EmitExpression(selectExpression, True) - temp = AllocateTemp(exprType, selectExpression.Syntax) + temp = AllocateTemp(exprType, syntax) _builder.EmitLocalStore(temp) - EmitStringSwitchJumpTable(caseLabels, fallThroughLabel, temp, selectExpression.Syntax) + EmitStringSwitchJumpTable(caseLabels, fallThroughLabel, temp, syntax) End If End If @@ -1123,6 +1124,7 @@ OtherExpressions: End Sub _builder.EmitStringSwitchJumpTable( + syntaxNode, caseLabels, fallThroughLabel, key, @@ -1171,8 +1173,8 @@ OtherExpressions: ' NOTE: We generate string switch table only for Option Compare Binary, i.e. TextCompare = False _builder.EmitLoad(key) - _builder.EmitConstantValue(stringConstant) - _builder.EmitConstantValue(ConstantValue.False) + _builder.EmitConstantValue(stringConstant, syntaxNode) + _builder.EmitConstantValue(ConstantValue.False, syntaxNode) _builder.EmitOpCode(ILOpCode.Call, stackAdjustment:=-2) _builder.EmitToken(stringCompareMethodRef, syntaxNode, _diagnostics) From 2ba7f58176c02e5ef314736a17780d7f315afe9d Mon Sep 17 00:00:00 2001 From: tmat Date: Sun, 13 Apr 2025 10:46:34 -0700 Subject: [PATCH 10/21] Delete ITokenDeferral --- .../Core/Portable/CodeGen/ILBuilder.cs | 5 +- .../Core/Portable/CodeGen/ILBuilderEmit.cs | 6 +- .../Core/Portable/CodeGen/ITokenDeferral.cs | 34 ----------- .../CodeGen/PrivateImplementationDetails.cs | 8 +-- .../Portable/Emit/CommonPEModuleBuilder.cs | 57 ++++++++++--------- .../Emit/EditAndContinue/DeletedMethodBody.cs | 9 ++- 6 files changed, 46 insertions(+), 73 deletions(-) delete mode 100644 src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index 2a170dbc2ffa9..e41472b9f8f44 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -11,6 +11,7 @@ using System.Reflection; using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Debugging; +using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; @@ -24,7 +25,7 @@ internal sealed partial class ILBuilder private readonly LocalScopeManager _scopeManager; // internal for testing - internal readonly ITokenDeferral module; + internal readonly CommonPEModuleBuilder module; //leader block is the entry point of the method body internal readonly BasicBlock leaderBlock; @@ -67,7 +68,7 @@ internal sealed partial class ILBuilder // created, in particular for leader blocks in exception handlers. private bool _pendingBlockCreate; - internal ILBuilder(ITokenDeferral module, LocalSlotManager localSlotManager, OptimizationLevel optimizations, bool areLocalsZeroed) + internal ILBuilder(CommonPEModuleBuilder module, LocalSlotManager localSlotManager, OptimizationLevel optimizations, bool areLocalsZeroed) { this.module = module; this.LocalSlotManager = localSlotManager; diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 6796baaa6f53c..ccda8b351d85e 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -365,7 +365,7 @@ private BasicBlock FinishFilterCondition() /// /// Generates code that creates an instance of multidimensional array /// - internal void EmitArrayCreation(Microsoft.Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayCreation(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); @@ -379,7 +379,7 @@ internal void EmitArrayCreation(Microsoft.Cci.IArrayTypeReference arrayType, Syn /// /// Generates code that loads an element of a multidimensional array /// - internal void EmitArrayElementLoad(Microsoft.Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayElementLoad(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); @@ -393,7 +393,7 @@ internal void EmitArrayElementLoad(Microsoft.Cci.IArrayTypeReference arrayType, /// /// Generates code that loads an address of an element of a multidimensional array. /// - internal void EmitArrayElementAddress(Microsoft.Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayElementAddress(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); diff --git a/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs b/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs deleted file mode 100644 index c11dc6c21a3e4..0000000000000 --- a/src/Compilers/Core/Portable/CodeGen/ITokenDeferral.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Immutable; - -namespace Microsoft.CodeAnalysis.CodeGen -{ - internal interface ITokenDeferral - { - uint GetFakeStringTokenForIL(string value); - uint GetFakeSymbolTokenForIL(Cci.IReference value, SyntaxNode? syntaxNode, DiagnosticBag diagnostics); - uint GetFakeSymbolTokenForIL(Cci.ISignature value, SyntaxNode? syntaxNode, DiagnosticBag diagnostics); - uint GetSourceDocumentIndexForIL(Cci.DebugSourceDocument document); - - Cci.IFieldReference GetFieldForData(ImmutableArray data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics); - - /// Gets a field that may be used to lazily cache an array created to store the specified data. - /// This is used to cache an array created with the data passed to . - Cci.IFieldReference GetArrayCachingFieldForData(ImmutableArray data, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics); - - Cci.IFieldReference GetArrayCachingFieldForConstants(ImmutableArray constants, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics); - - Cci.IMethodReference GetInitArrayHelper(); - - string GetStringFromToken(uint token); - /// - /// Gets the or corresponding to this token. - /// - object GetReferenceFromToken(uint token); - - ArrayMethods ArrayMethods { get; } - } -} diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 8fe27dc2a801c..ed8aa9923c77e 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -382,7 +382,7 @@ private Cci.IMethodDefinition GetOrSynthesizeBytesToStringHelper(DiagnosticBag d var encodingGetString = getWellKnownTypeMember(compilation, WellKnownMember.System_Text_Encoding__GetString); TryAddSynthesizedMethod(BytesToStringHelper.Create( - moduleBuilder: (ITokenDeferral)ModuleBuilder, + moduleBuilder: ModuleBuilder, containingType: this, encodingUtf8: encodingUtf8, encodingGetString: encodingGetString, @@ -743,13 +743,13 @@ public DataSectionStringType( var stringField = new DataSectionStringField("s", this); - var staticConstructor = synthesizeStaticConstructor((ITokenDeferral)containingType.ModuleBuilder, this, dataField, stringField, bytesToStringHelper, diagnostics); + var staticConstructor = synthesizeStaticConstructor(containingType.ModuleBuilder, this, dataField, stringField, bytesToStringHelper, diagnostics); _fields = [stringField]; _methods = [staticConstructor]; static Cci.IMethodDefinition synthesizeStaticConstructor( - ITokenDeferral module, + CommonPEModuleBuilder module, Cci.ITypeDefinition containingType, MappedField dataField, DataSectionStringField stringField, @@ -1173,7 +1173,7 @@ private BytesToStringHelper( } public static BytesToStringHelper Create( - ITokenDeferral moduleBuilder, + CommonPEModuleBuilder moduleBuilder, Cci.INamespaceTypeDefinition containingType, Cci.IMethodReference encodingUtf8, Cci.IMethodReference encodingGetString, diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index ddfa79e3bc435..98c962e39de98 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -41,6 +41,7 @@ internal abstract class CommonPEModuleBuilder : Cci.IUnit, Cci.IModuleReference private ImmutableArray _lazyAssemblyReferenceAliases; private ImmutableArray _lazyManagedResources; private IEnumerable _embeddedTexts = SpecializedCollections.EmptyEnumerable(); + private ArrayMethods? _lazyArrayMethods; // Only set when running tests to allow inspection of the emitted data. internal CompilationTestData? TestData { get; private set; } @@ -137,6 +138,11 @@ public CommonPEModuleBuilder( public abstract IEnumerable GetSourceAssemblySecurityAttributes(); public abstract IEnumerable GetSourceModuleAttributes(); internal abstract Cci.ICustomAttribute SynthesizeAttribute(WellKnownMember attributeConstructor); + public abstract Cci.IMethodReference GetInitArrayHelper(); + + public abstract Cci.IFieldReference GetFieldForData(ImmutableArray data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics); + public abstract Cci.IFieldReference GetArrayCachingFieldForData(ImmutableArray data, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics); + public abstract Cci.IFieldReference GetArrayCachingFieldForConstants(ImmutableArray constants, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics); /// /// Public types defined in other modules making up this assembly and to which other assemblies may refer to via this assembly @@ -180,6 +186,26 @@ public CommonPEModuleBuilder( public abstract bool IsPlatformType(Cci.ITypeReference typeRef, Cci.PlatformType platformType); #nullable enable + public ArrayMethods ArrayMethods + { + get + { + ArrayMethods? result = _lazyArrayMethods; + + if (result == null) + { + result = new ArrayMethods(); + + if (Interlocked.CompareExchange(ref _lazyArrayMethods, result, null) != null) + { + result = _lazyArrayMethods; + } + } + + return result; + } + } + public abstract IEnumerable GetTopLevelTypeDefinitions(EmitContext context); public IEnumerable GetTopLevelTypeDefinitionsCore(EmitContext context) @@ -582,7 +608,7 @@ public int GetTypeDefinitionGeneration(Cci.INamedTypeDefinition typeDef) /// /// Common base class for C# and VB PE module builder. /// - internal abstract class PEModuleBuilder : CommonPEModuleBuilder, ITokenDeferral + internal abstract class PEModuleBuilder : CommonPEModuleBuilder where TCompilation : Compilation where TSourceModuleSymbol : class, IModuleSymbolInternal where TAssemblySymbol : class, IAssemblySymbolInternal @@ -597,7 +623,6 @@ internal abstract class PEModuleBuilder _namesOfTopLevelTypes; internal readonly TModuleCompilationState CompilationState; @@ -1023,7 +1048,7 @@ internal override ImmutableDictionary data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + public sealed override Cci.IFieldReference GetFieldForData(ImmutableArray data, ushort alignment, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { RoslynDebug.Assert(alignment is 1 or 2 or 4 or 8, $"Unexpected alignment: {alignment}"); @@ -1033,7 +1058,7 @@ Cci.IFieldReference ITokenDeferral.GetFieldForData(ImmutableArray data, us return privateImpl.GetOrAddDataField(data, alignment); } - Cci.IFieldReference ITokenDeferral.GetArrayCachingFieldForData(ImmutableArray data, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + public sealed override Cci.IFieldReference GetArrayCachingFieldForData(ImmutableArray data, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { var privateImpl = GetPrivateImplClass((TSyntaxNode)syntaxNode, diagnostics); @@ -1043,7 +1068,7 @@ Cci.IFieldReference ITokenDeferral.GetArrayCachingFieldForData(ImmutableArray constants, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + public sealed override Cci.IFieldReference GetArrayCachingFieldForConstants(ImmutableArray constants, Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) { var privateImpl = GetPrivateImplClass((TSyntaxNode)syntaxNode, diagnostics); var emitContext = new EmitContext(this, syntaxNode, diagnostics, metadataOnly: false, includePrivateMembers: true); @@ -1058,28 +1083,6 @@ public Cci.IFieldReference TryGetOrCreateFieldForStringValue(string text, TSynta return PrivateImplementationDetails.TryGetOrCreateFieldForStringValue(text, this, syntaxNode, diagnostics); } - public abstract Cci.IMethodReference GetInitArrayHelper(); - - public ArrayMethods ArrayMethods - { - get - { - ArrayMethods result = _lazyArrayMethods; - - if (result == null) - { - result = new ArrayMethods(); - - if (Interlocked.CompareExchange(ref _lazyArrayMethods, result, null) != null) - { - result = _lazyArrayMethods; - } - } - - return result; - } - } - #endregion #region Private Implementation Details Type diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs index 698d0babaf0e7..0ea10b2b47e45 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs @@ -68,7 +68,7 @@ public static ImmutableArray GetIL(EmitContext context, RuntimeRudeEdit? r { var hotReloadExceptionCtorDef = context.Module.GetOrCreateHotReloadExceptionConstructorDefinition(); - var builder = new ILBuilder((ITokenDeferral)context.Module, null, OptimizationLevel.Debug, false); + var builder = new ILBuilder(context.Module, null, OptimizationLevel.Debug, false); string message; int codeValue; @@ -84,12 +84,15 @@ public static ImmutableArray GetIL(EmitContext context, RuntimeRudeEdit? r codeValue = code.GetExceptionCodeValue(); } - builder.EmitStringConstant(message); + var syntaxNode = context.SyntaxNode; + Debug.Assert(syntaxNode != null); + + builder.EmitStringConstant(message, syntaxNode); builder.EmitIntConstant(codeValue); // consumes message and code, pushes the created exception object: builder.EmitOpCode(ILOpCode.Newobj, stackAdjustment: -1); - builder.EmitToken(hotReloadExceptionCtorDef.GetCciAdapter(), context.SyntaxNode!, context.Diagnostics); + builder.EmitToken(hotReloadExceptionCtorDef.GetCciAdapter(), syntaxNode, context.Diagnostics); builder.EmitThrow(isRethrow: false); builder.Realize(); From 3de7167cf0543518cccaa6b486bcddf0fc77985f Mon Sep 17 00:00:00 2001 From: tmat Date: Sun, 13 Apr 2025 09:56:02 -0700 Subject: [PATCH 11/21] Add DiagnosticBag to ILBuilder --- .../CSharp/Portable/CodeGen/CodeGenerator.cs | 8 ++--- .../CSharp/Portable/CodeGen/EmitAddress.cs | 2 +- .../Portable/CodeGen/EmitArrayInitializer.cs | 16 ++++----- .../CSharp/Portable/CodeGen/EmitExpression.cs | 25 ++++++-------- .../CodeGen/EmitStackAllocInitializer.cs | 6 ++-- .../CSharp/Portable/CodeGen/EmitStatement.cs | 14 ++++---- .../Portable/Compilation/CSharpCompilation.cs | 5 ++- .../Portable/Compiler/MethodCompiler.cs | 13 ++++--- .../Core/Portable/CodeGen/ILBuilder.cs | 5 ++- .../Core/Portable/CodeGen/ILBuilderEmit.cs | 34 +++++++++---------- .../CodeGen/PrivateImplementationDetails.cs | 12 ++++--- .../Emit/EditAndContinue/DeletedMethodBody.cs | 4 +-- .../Portable/CodeGen/CodeGenerator.vb | 6 ++-- .../Portable/CodeGen/EmitAddress.vb | 2 +- .../Portable/CodeGen/EmitArrayInitializer.vb | 2 +- .../Portable/CodeGen/EmitExpression.vb | 10 +++--- .../Portable/CodeGen/EmitStatement.vb | 10 +++--- .../Portable/Compilation/MethodCompiler.vb | 2 +- 18 files changed, 88 insertions(+), 88 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs index 1dc9e15f8e2e6..f1bcf5757fc9e 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/CodeGenerator.cs @@ -338,7 +338,7 @@ private void HandleReturn() private void EmitTypeReferenceToken(Cci.ITypeReference symbol, SyntaxNode syntaxNode) { - _builder.EmitToken(symbol, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(symbol, syntaxNode); } private void EmitSymbolToken(TypeSymbol symbol, SyntaxNode syntaxNode) @@ -349,18 +349,18 @@ private void EmitSymbolToken(TypeSymbol symbol, SyntaxNode syntaxNode) private void EmitSymbolToken(MethodSymbol method, SyntaxNode syntaxNode, BoundArgListOperator optArgList, bool encodeAsRawDefinitionToken = false) { var methodRef = _module.Translate(method, syntaxNode, _diagnostics.DiagnosticBag, optArgList, needDeclaration: encodeAsRawDefinitionToken); - _builder.EmitToken(methodRef, syntaxNode, _diagnostics.DiagnosticBag, encodeAsRawDefinitionToken ? Cci.MetadataWriter.RawTokenEncoding.RowId : 0); + _builder.EmitToken(methodRef, syntaxNode, encodeAsRawDefinitionToken ? Cci.MetadataWriter.RawTokenEncoding.RowId : 0); } private void EmitSymbolToken(FieldSymbol symbol, SyntaxNode syntaxNode) { var fieldRef = _module.Translate(symbol, syntaxNode, _diagnostics.DiagnosticBag); - _builder.EmitToken(fieldRef, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(fieldRef, syntaxNode); } private void EmitSignatureToken(FunctionPointerTypeSymbol symbol, SyntaxNode syntaxNode) { - _builder.EmitToken(_module.Translate(symbol).Signature, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(_module.Translate(symbol).Signature, syntaxNode); } private void EmitSequencePointStatement(BoundSequencePoint node) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs index f6358956bf7d4..c5402c35d4c46 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitAddress.cs @@ -409,7 +409,7 @@ private void EmitArrayElementAddress(BoundArrayAccess arrayAccess, AddressKind a else { _builder.EmitArrayElementAddress(_module.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type), - arrayAccess.Syntax, _diagnostics.DiagnosticBag); + arrayAccess.Syntax); } } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index fdb16fcfb19c4..ef1af66cd6730 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -55,7 +55,7 @@ private void EmitArrayInitializers(ArrayTypeSymbol arrayType, BoundArrayInitiali { ImmutableArray data = this.GetRawData(initExprs); - _builder.EmitArrayBlockInitializer(data, inits.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitArrayBlockInitializer(data, inits.Syntax); if (initializationStyle == ArrayInitializerStyle.Mixed) { @@ -554,7 +554,7 @@ private bool TryEmitOptimizedReadonlySpanCreation(NamedTypeSymbol spanType, Boun // Map a field to the block (that makes it addressable). var field = _builder.module.GetFieldForData(data, alignment: 1, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Ldsflda); - _builder.EmitToken(field, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(field, wrappedExpression.Syntax); _builder.EmitIntConstant(lengthForConstructor); @@ -615,7 +615,7 @@ private bool TryEmitOptimizedReadonlySpanCreation(NamedTypeSymbol spanType, Boun // call ReadOnlySpan RuntimeHelpers::CreateSpan(fldHandle) var field = _builder.module.GetFieldForData(data, alignment: (ushort)specialElementType.SizeInBytes(), wrappedExpression.Syntax, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Ldtoken); - _builder.EmitToken(field, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(field, wrappedExpression.Syntax); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); EmitSymbolToken(createSpan.Construct(elementType), wrappedExpression.Syntax, optArgList: null); return true; @@ -652,7 +652,7 @@ bool tryEmitAsCachedArrayFromBlob(NamedTypeSymbol spanType, BoundExpression wrap // T[]? array = PrivateImplementationDetails.cachingField; // if (array is not null) goto arrayNotNull; _builder.EmitOpCode(ILOpCode.Ldsfld); - _builder.EmitToken(cachingField, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(cachingField, wrappedExpression.Syntax); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitBranch(ILOpCode.Brtrue, arrayNotNullLabel); @@ -663,10 +663,10 @@ bool tryEmitAsCachedArrayFromBlob(NamedTypeSymbol spanType, BoundExpression wrap _builder.EmitIntConstant(elementCount); _builder.EmitOpCode(ILOpCode.Newarr); EmitSymbolToken(arrayType.ElementType, wrappedExpression.Syntax); - _builder.EmitArrayBlockInitializer(data, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitArrayBlockInitializer(data, wrappedExpression.Syntax); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitOpCode(ILOpCode.Stsfld); - _builder.EmitToken(cachingField, wrappedExpression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(cachingField, wrappedExpression.Syntax); // arrayNotNullLabel: // new ReadOnlySpan(array) @@ -712,7 +712,7 @@ bool tryEmitAsCachedArrayOfConstants(BoundArrayCreation arrayCreation, ArrayType // T[]? array = PrivateImplementationDetails.cachingField; // if (array is not null) goto arrayNotNull; _builder.EmitOpCode(ILOpCode.Ldsfld); - _builder.EmitToken(cachingField, arrayCreation.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(cachingField, arrayCreation.Syntax); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitBranch(ILOpCode.Brtrue, arrayNotNullLabel); @@ -722,7 +722,7 @@ bool tryEmitAsCachedArrayOfConstants(BoundArrayCreation arrayCreation, ArrayType EmitExpression(arrayCreation, used: true); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitOpCode(ILOpCode.Stsfld); - _builder.EmitToken(cachingField, arrayCreation.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(cachingField, arrayCreation.Syntax); // arrayNotNullLabel: // new ReadOnlySpan(array) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 8ce24b9f6fb3a..04ad7a1baeb1a 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -16,7 +16,6 @@ using Roslyn.Utilities; using static System.Linq.ImmutableArrayExtensions; -using static Microsoft.CodeAnalysis.CSharp.Binder; namespace Microsoft.CodeAnalysis.CSharp.CodeGen { @@ -1099,7 +1098,7 @@ private void EmitArrayElementLoad(BoundArrayAccess arrayAccess, bool used) } else { - _builder.EmitArrayElementLoad(_module.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type), arrayAccess.Expression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitArrayElementLoad(_module.Translate((ArrayTypeSymbol)arrayAccess.Expression.Type), arrayAccess.Expression.Syntax); } EmitPopIfUnused(used); @@ -2383,7 +2382,7 @@ private void EmitArrayCreationExpression(BoundArrayCreation expression, bool use } else { - _builder.EmitArrayCreation(_module.Translate(arrayType), expression.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitArrayCreation(_module.Translate(arrayType), expression.Syntax); } if (expression.InitializerOpt != null) @@ -3201,7 +3200,7 @@ private void EmitArrayElementStore(ArrayTypeSymbol arrayType, SyntaxNode syntaxN } else { - _builder.EmitArrayElementStore(_module.Translate(arrayType), syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitArrayElementStore(_module.Translate(arrayType), syntaxNode); } } @@ -3511,7 +3510,7 @@ private bool TryEmitStringLiteralAsUtf8Encoded(ConstantValue constantValue, Synt if (field != null) { _builder.EmitOpCode(ILOpCode.Ldsfld); - _builder.EmitToken(field, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(field, syntaxNode); return true; } @@ -3627,7 +3626,7 @@ private void EmitHoistedVariableId(FieldSymbol field, SyntaxNode syntax) var fieldRef = _module.Translate(field, syntax, _diagnostics.DiagnosticBag, needDeclaration: true); _builder.EmitOpCode(ILOpCode.Ldtoken); - _builder.EmitToken(fieldRef, syntax, _diagnostics.DiagnosticBag, Cci.MetadataWriter.RawTokenEncoding.LiftedVariableId); + _builder.EmitToken(fieldRef, syntax, Cci.MetadataWriter.RawTokenEncoding.LiftedVariableId); } private void EmitMaximumMethodDefIndexExpression(BoundMaximumMethodDefIndex node) @@ -3653,8 +3652,7 @@ private void EmitModuleVersionIdToken(BoundModuleVersionId node) { _builder.EmitToken( _module.GetModuleVersionId(_module.Translate(node.Type, node.Syntax, _diagnostics.DiagnosticBag), node.Syntax, _diagnostics.DiagnosticBag), - node.Syntax, - _diagnostics.DiagnosticBag); + node.Syntax); } private void EmitThrowIfModuleCancellationRequested(SyntaxNode syntax) @@ -3664,8 +3662,7 @@ private void EmitThrowIfModuleCancellationRequested(SyntaxNode syntax) _builder.EmitOpCode(ILOpCode.Ldsflda); _builder.EmitToken( _module.GetModuleCancellationToken(_module.Translate(cancellationTokenType, syntax, _diagnostics.DiagnosticBag), syntax, _diagnostics.DiagnosticBag), - syntax, - _diagnostics.DiagnosticBag); + syntax); var throwMethod = (MethodSymbol)_module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Threading_CancellationToken__ThrowIfCancellationRequested); @@ -3675,8 +3672,7 @@ private void EmitThrowIfModuleCancellationRequested(SyntaxNode syntax) _builder.EmitOpCode(ILOpCode.Call, -1); _builder.EmitToken( _module.Translate(throwMethod, syntax, _diagnostics.DiagnosticBag), - syntax, - _diagnostics.DiagnosticBag); + syntax); } private void EmitModuleCancellationTokenLoad(SyntaxNode syntax) @@ -3686,8 +3682,7 @@ private void EmitModuleCancellationTokenLoad(SyntaxNode syntax) _builder.EmitOpCode(ILOpCode.Ldsfld); _builder.EmitToken( _module.GetModuleCancellationToken(_module.Translate(cancellationTokenType, syntax, _diagnostics.DiagnosticBag), syntax, _diagnostics.DiagnosticBag), - syntax, - _diagnostics.DiagnosticBag); + syntax); } private void EmitModuleVersionIdStringLoad() @@ -3710,7 +3705,7 @@ private void EmitInstrumentationPayloadRootStore(BoundInstrumentationPayloadRoot private void EmitInstrumentationPayloadRootToken(BoundInstrumentationPayloadRoot node) { - _builder.EmitToken(_module.GetInstrumentationPayloadRoot(node.AnalysisKind, _module.Translate(node.Type, node.Syntax, _diagnostics.DiagnosticBag), node.Syntax, _diagnostics.DiagnosticBag), node.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(_module.GetInstrumentationPayloadRoot(node.AnalysisKind, _module.Translate(node.Type, node.Syntax, _diagnostics.DiagnosticBag), node.Syntax, _diagnostics.DiagnosticBag), node.Syntax); } private void EmitSourceDocumentIndex(BoundSourceDocumentIndex node) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs index edeb5512d4cc3..b057dfa35f650 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs @@ -59,7 +59,7 @@ private void EmitStackAlloc(TypeSymbol type, BoundArrayInitialization? inits, Bo var field = _builder.module.GetFieldForData(data, alignment: 1, inits.Syntax, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitOpCode(ILOpCode.Ldsflda); - _builder.EmitToken(field, inits.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(field, inits.Syntax); _builder.EmitIntConstant(data.Length); _builder.EmitUnaligned(alignment: 1); _builder.EmitOpCode(ILOpCode.Cpblk, -3); @@ -81,10 +81,10 @@ private void EmitStackAlloc(TypeSymbol type, BoundArrayInitialization? inits, Bo // call ReadOnlySpan RuntimeHelpers::CreateSpan(fldHandle) var field = _builder.module.GetFieldForData(data, alignment: (ushort)sizeInBytes, syntaxNode, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Ldtoken); - _builder.EmitToken(field, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(field, syntaxNode); _builder.EmitOpCode(ILOpCode.Call, 0); var createSpanHelperReference = createSpanHelper.Construct(elementType).GetCciAdapter(); - _builder.EmitToken(createSpanHelperReference, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(createSpanHelperReference, syntaxNode); var temp = AllocateTemp(readOnlySpan, syntaxNode); _builder.EmitLocalStore(temp); diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs index b780cb70e8b91..d2e30eb4e64a2 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs @@ -1096,7 +1096,7 @@ private void EmitCatchBlock(BoundCatchBlock catchBlock) var exceptionType = _module.Translate(catchBlock.ExceptionTypeOpt, catchBlock.Syntax, _diagnostics.DiagnosticBag); _builder.EmitOpCode(ILOpCode.Isinst); - _builder.EmitToken(exceptionType, catchBlock.Syntax, _diagnostics.DiagnosticBag); + _builder.EmitToken(exceptionType, catchBlock.Syntax); _builder.EmitOpCode(ILOpCode.Dup); _builder.EmitBranch(ILOpCode.Brtrue, typeCheckPassedLabel); _builder.EmitOpCode(ILOpCode.Pop); @@ -1475,7 +1475,7 @@ void emitFinalDispatches(LengthBasedStringSwitchData lengthBasedSwitchInfo, Loca void emitMethodRef(Microsoft.Cci.IMethodReference lengthMethodRef) { var diag = DiagnosticBag.GetInstance(); - _builder.EmitToken(lengthMethodRef, syntaxNode: null, diag); + _builder.EmitToken(lengthMethodRef, syntaxNode: null); Debug.Assert(diag.IsEmptyWithoutResolution); diag.Free(); } @@ -1519,7 +1519,7 @@ private void EmitStringSwitchJumpTable( _builder.EmitLoad(key); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); - _builder.EmitToken(stringHashMethodRef, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(stringHashMethodRef, syntaxNode); var UInt32Type = Binder.GetSpecialType(_module.Compilation, SpecialType.System_UInt32, syntaxNode, _diagnostics); keyHash = AllocateTemp(UInt32Type, syntaxNode); @@ -1592,7 +1592,7 @@ private void EmitStringSwitchJumpTable( // Stack: key --> length _builder.EmitOpCode(ILOpCode.Call, 0); var diag = DiagnosticBag.GetInstance(); - _builder.EmitToken(lengthMethodRef, null, diag); + _builder.EmitToken(lengthMethodRef, null); Debug.Assert(diag.IsEmptyWithoutResolution); diag.Free(); @@ -1711,7 +1711,7 @@ private void EmitStringCompareAndBranch(LocalOrParameter key, SyntaxNode syntaxN _builder.EmitLoad(key); _builder.EmitConstantValue(stringConstant, syntaxNode); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: -1); - _builder.EmitToken(stringEqualityMethodRef, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(stringEqualityMethodRef, syntaxNode); // Branch to targetLabel if String.Equals returned true. _builder.EmitBranch(ILOpCode.Brtrue, targetLabel, ILOpCode.Brfalse); @@ -1738,9 +1738,9 @@ private void EmitCharCompareAndBranch(LocalOrParameter key, SyntaxNode syntaxNod _builder.EmitLoad(key); _builder.EmitConstantValue(stringConstant, syntaxNode); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: 0); - _builder.EmitToken(asSpanRef, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(asSpanRef, syntaxNode); _builder.EmitOpCode(ILOpCode.Call, stackAdjustment: -1); - _builder.EmitToken(sequenceEqualsRef, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitToken(sequenceEqualsRef, syntaxNode); // Branch to targetLabel if SequenceEquals returned true. _builder.EmitBranch(ILOpCode.Brtrue, targetLabel, ILOpCode.Brfalse); diff --git a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs index 8d8d92cd0460a..8e04aaa7840d3 100644 --- a/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs +++ b/src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs @@ -3683,7 +3683,7 @@ private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, Diagnos if (_moduleInitializerMethods is object) { - var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: false); + var ilBuilder = new ILBuilder(moduleBeingBuilt, new LocalSlotManager(slotAllocator: null), methodBodyDiagnosticBag, OptimizationLevel.Release, areLocalsZeroed: false); foreach (MethodSymbol method in _moduleInitializerMethods.OrderBy(LexicalOrderSymbolComparer.Instance)) { @@ -3691,8 +3691,7 @@ private void GenerateModuleInitializer(PEModuleBuilder moduleBeingBuilt, Diagnos ilBuilder.EmitToken( moduleBeingBuilt.Translate(method, methodBodyDiagnosticBag, needDeclaration: true), - CSharpSyntaxTree.Dummy.GetRoot(), - methodBodyDiagnosticBag); + CSharpSyntaxTree.Dummy.GetRoot()); } ilBuilder.EmitRet(isVoid: true); diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 1c996f88d1366..96eaad50afac6 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -1392,7 +1392,9 @@ private void EmitSkeletonMethodInExtension(MethodSymbol methodSymbol) return; } - ILBuilder builder = new ILBuilder(_moduleBeingBuiltOpt, new LocalSlotManager(slotAllocator: null), OptimizationLevel.Release, areLocalsZeroed: false); + Debug.Assert(_diagnostics.DiagnosticBag != null); + + ILBuilder builder = new ILBuilder(_moduleBeingBuiltOpt, new LocalSlotManager(slotAllocator: null), _diagnostics.DiagnosticBag, OptimizationLevel.Release, areLocalsZeroed: false); // Emit methods in extensions as skeletons: // => throw null; @@ -1429,8 +1431,7 @@ private void EmitSkeletonMethodInExtension(MethodSymbol methodSymbol) StateMachineStatesDebugInfo.Create(variableSlotAllocator: null, ImmutableArray.Empty), stateMachineMoveNextDebugInfoOpt: null, codeCoverageSpans: ImmutableArray.Empty, - isPrimaryConstructor: false) - ); + isPrimaryConstructor: false)); } private static MethodSymbol GetSymbolForEmittedBody(MethodSymbol methodSymbol) @@ -1604,9 +1605,11 @@ private static MethodBody GenerateMethodBody( var localSlotManager = new LocalSlotManager(variableSlotAllocatorOpt); var optimizations = compilation.Options.OptimizationLevel; - ILBuilder builder = new ILBuilder(moduleBuilder, localSlotManager, optimizations, method.AreLocalsZeroed); - bool hasStackalloc; var diagnosticsForThisMethod = BindingDiagnosticBag.GetInstance(withDiagnostics: true, diagnostics.AccumulatesDependencies); + Debug.Assert(diagnosticsForThisMethod.DiagnosticBag != null); + + ILBuilder builder = new ILBuilder(moduleBuilder, localSlotManager, diagnosticsForThisMethod.DiagnosticBag, optimizations, method.AreLocalsZeroed); + bool hasStackalloc; try { StateMachineMoveNextBodyDebugInfo moveNextBodyDebugInfoOpt = null; diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index e41472b9f8f44..674a530359293 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -22,6 +22,7 @@ internal sealed partial class ILBuilder { private readonly OptimizationLevel _optimizations; internal readonly LocalSlotManager LocalSlotManager; + private readonly DiagnosticBag _diagnostics; private readonly LocalScopeManager _scopeManager; // internal for testing @@ -68,10 +69,12 @@ internal sealed partial class ILBuilder // created, in particular for leader blocks in exception handlers. private bool _pendingBlockCreate; - internal ILBuilder(CommonPEModuleBuilder module, LocalSlotManager localSlotManager, OptimizationLevel optimizations, bool areLocalsZeroed) + internal ILBuilder(CommonPEModuleBuilder module, LocalSlotManager localSlotManager, DiagnosticBag diagnostics, OptimizationLevel optimizations, bool areLocalsZeroed) { this.module = module; this.LocalSlotManager = localSlotManager; + + _diagnostics = diagnostics; _emitState = default(EmitState); _scopeManager = new LocalScopeManager(); diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index ccda8b351d85e..f57baa7baa4bc 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -7,8 +7,6 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Metadata; -using Roslyn.Utilities; -using static System.Linq.ImmutableArrayExtensions; namespace Microsoft.CodeAnalysis.CodeGen { @@ -46,9 +44,9 @@ internal void EmitToken(string value) this.GetCurrentWriter().WriteUInt32(token); } - internal void EmitToken(Cci.IReference value, SyntaxNode? syntaxNode, DiagnosticBag diagnostics, Cci.MetadataWriter.RawTokenEncoding encoding = 0) + internal void EmitToken(Cci.IReference value, SyntaxNode? syntaxNode, Cci.MetadataWriter.RawTokenEncoding encoding = 0) { - uint token = module?.GetFakeSymbolTokenForIL(value, syntaxNode, diagnostics) ?? 0xFFFF; + uint token = module?.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics) ?? 0xFFFF; if (encoding != Cci.MetadataWriter.RawTokenEncoding.None) { token = Cci.MetadataWriter.GetRawToken(encoding, token); @@ -56,9 +54,9 @@ internal void EmitToken(Cci.IReference value, SyntaxNode? syntaxNode, Diagnostic this.GetCurrentWriter().WriteUInt32(token); } - internal void EmitToken(Cci.ISignature value, SyntaxNode? syntaxNode, DiagnosticBag diagnostics) + internal void EmitToken(Cci.ISignature value, SyntaxNode? syntaxNode) { - uint token = module?.GetFakeSymbolTokenForIL(value, syntaxNode, diagnostics) ?? 0xFFFF; + uint token = module?.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics) ?? 0xFFFF; this.GetCurrentWriter().WriteUInt32(token); } @@ -80,7 +78,7 @@ internal void EmitSourceDocumentIndexToken(Cci.DebugSourceDocument document) this.GetCurrentWriter().WriteUInt32(token); } - internal void EmitArrayBlockInitializer(ImmutableArray data, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayBlockInitializer(ImmutableArray data, SyntaxNode syntaxNode) { // 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 @@ -100,14 +98,14 @@ internal void EmitArrayBlockInitializer(ImmutableArray data, SyntaxNode sy var initializeArray = module.GetInitArrayHelper(); // map a field to the block (that makes it addressable via a token). - var field = module.GetFieldForData(data, alignment: 1, syntaxNode, diagnostics); + var field = module.GetFieldForData(data, alignment: 1, syntaxNode, _diagnostics); // emit call to the helper EmitOpCode(ILOpCode.Dup); //array EmitOpCode(ILOpCode.Ldtoken); - EmitToken(field, syntaxNode, diagnostics); //block + EmitToken(field, syntaxNode); //block EmitOpCode(ILOpCode.Call, -2); - EmitToken(initializeArray, syntaxNode, diagnostics); + EmitToken(initializeArray, syntaxNode); } /// @@ -365,7 +363,7 @@ private BasicBlock FinishFilterCondition() /// /// Generates code that creates an instance of multidimensional array /// - internal void EmitArrayCreation(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayCreation(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); @@ -373,13 +371,13 @@ internal void EmitArrayCreation(Cci.IArrayTypeReference arrayType, SyntaxNode sy // idx1, idx2 --> array this.EmitOpCode(ILOpCode.Newobj, 1 - (int)arrayType.Rank); - this.EmitToken(ctor, syntaxNode, diagnostics); + this.EmitToken(ctor, syntaxNode); } /// /// Generates code that loads an element of a multidimensional array /// - internal void EmitArrayElementLoad(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayElementLoad(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); @@ -387,13 +385,13 @@ internal void EmitArrayElementLoad(Cci.IArrayTypeReference arrayType, SyntaxNode // this, idx1, idx2 --> value this.EmitOpCode(ILOpCode.Call, -(int)arrayType.Rank); - this.EmitToken(load, syntaxNode, diagnostics); + this.EmitToken(load, syntaxNode); } /// /// Generates code that loads an address of an element of a multidimensional array. /// - internal void EmitArrayElementAddress(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayElementAddress(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); @@ -401,13 +399,13 @@ internal void EmitArrayElementAddress(Cci.IArrayTypeReference arrayType, SyntaxN // this, idx1, idx2 --> &value this.EmitOpCode(ILOpCode.Call, -(int)arrayType.Rank); - this.EmitToken(address, syntaxNode, diagnostics); + this.EmitToken(address, syntaxNode); } /// /// Generates code that stores an element of a multidimensional array. /// - internal void EmitArrayElementStore(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + internal void EmitArrayElementStore(Cci.IArrayTypeReference arrayType, SyntaxNode syntaxNode) { Debug.Assert(!arrayType.IsSZArray, "should be used only with multidimensional arrays"); @@ -415,7 +413,7 @@ internal void EmitArrayElementStore(Cci.IArrayTypeReference arrayType, SyntaxNod // this, idx1, idx2, value --> void this.EmitOpCode(ILOpCode.Call, -(2 + (int)arrayType.Rank)); - this.EmitToken(store, syntaxNode, diagnostics); + this.EmitToken(store, syntaxNode); } internal void EmitLoad(LocalOrParameter localOrParameter) diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index ed8aa9923c77e..7401cd367443b 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -759,23 +759,24 @@ static Cci.IMethodDefinition synthesizeStaticConstructor( var ilBuilder = new ILBuilder( module, new LocalSlotManager(slotAllocator: null), + diagnostics, OptimizationLevel.Release, areLocalsZeroed: false); // Push the `byte*` field's address. ilBuilder.EmitOpCode(ILOpCode.Ldsflda); - ilBuilder.EmitToken(dataField, null, diagnostics); + ilBuilder.EmitToken(dataField, null); // Push the byte size. ilBuilder.EmitIntConstant(dataField.MappedData.Length); // Call `.BytesToString(byte*, int)`. ilBuilder.EmitOpCode(ILOpCode.Call, -1); - ilBuilder.EmitToken(bytesToStringHelper, null, diagnostics); + ilBuilder.EmitToken(bytesToStringHelper, null); // Store into the corresponding `string` field. ilBuilder.EmitOpCode(ILOpCode.Stsfld); - ilBuilder.EmitToken(stringField, null, diagnostics); + ilBuilder.EmitToken(stringField, null); ilBuilder.EmitRet(isVoid: true); ilBuilder.Realize(); @@ -1182,12 +1183,13 @@ public static BytesToStringHelper Create( var ilBuilder = new ILBuilder( moduleBuilder, new LocalSlotManager(slotAllocator: null), + diagnostics, OptimizationLevel.Release, areLocalsZeroed: false); // Call `Encoding.get_UTF8()`. ilBuilder.EmitOpCode(ILOpCode.Call, 1); - ilBuilder.EmitToken(encodingUtf8, null, diagnostics); + ilBuilder.EmitToken(encodingUtf8, null); // Push the `byte*`. ilBuilder.EmitOpCode(ILOpCode.Ldarg_0); @@ -1197,7 +1199,7 @@ public static BytesToStringHelper Create( // Call `Encoding.GetString(byte*, int)`. ilBuilder.EmitOpCode(ILOpCode.Callvirt, -2); - ilBuilder.EmitToken(encodingGetString, null, diagnostics); + ilBuilder.EmitToken(encodingGetString, null); // Return. ilBuilder.EmitRet(isVoid: false); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs index 0ea10b2b47e45..4d157271d4718 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs @@ -68,7 +68,7 @@ public static ImmutableArray GetIL(EmitContext context, RuntimeRudeEdit? r { var hotReloadExceptionCtorDef = context.Module.GetOrCreateHotReloadExceptionConstructorDefinition(); - var builder = new ILBuilder(context.Module, null, OptimizationLevel.Debug, false); + var builder = new ILBuilder(context.Module, localSlotManager: null, context.Diagnostics, OptimizationLevel.Debug, areLocalsZeroed: false); string message; int codeValue; @@ -92,7 +92,7 @@ public static ImmutableArray GetIL(EmitContext context, RuntimeRudeEdit? r // consumes message and code, pushes the created exception object: builder.EmitOpCode(ILOpCode.Newobj, stackAdjustment: -1); - builder.EmitToken(hotReloadExceptionCtorDef.GetCciAdapter(), syntaxNode, context.Diagnostics); + builder.EmitToken(hotReloadExceptionCtorDef.GetCciAdapter(), syntaxNode); builder.EmitThrow(isRethrow: false); builder.Realize(); diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb b/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb index 479e808325b56..75e96864cf563 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/CodeGenerator.vb @@ -190,16 +190,16 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen End Function Private Sub EmitSymbolToken(symbol As FieldSymbol, syntaxNode As SyntaxNode) - _builder.EmitToken(_module.Translate(symbol, syntaxNode, _diagnostics), syntaxNode, _diagnostics) + _builder.EmitToken(_module.Translate(symbol, syntaxNode, _diagnostics), syntaxNode) End Sub Private Sub EmitSymbolToken(symbol As MethodSymbol, syntaxNode As SyntaxNode, Optional encodeAsRawDefinitionToken As Boolean = False) Dim methodRef = _module.Translate(symbol, syntaxNode, _diagnostics, needDeclaration:=encodeAsRawDefinitionToken) - _builder.EmitToken(methodRef, syntaxNode, _diagnostics, If(encodeAsRawDefinitionToken, Cci.MetadataWriter.RawTokenEncoding.RowId, Cci.MetadataWriter.RawTokenEncoding.None)) + _builder.EmitToken(methodRef, syntaxNode, If(encodeAsRawDefinitionToken, Cci.MetadataWriter.RawTokenEncoding.RowId, Cci.MetadataWriter.RawTokenEncoding.None)) End Sub Private Sub EmitSymbolToken(symbol As TypeSymbol, syntaxNode As SyntaxNode) - _builder.EmitToken(_module.Translate(symbol, syntaxNode, _diagnostics), syntaxNode, _diagnostics) + _builder.EmitToken(_module.Translate(symbol, syntaxNode, _diagnostics), syntaxNode) End Sub Private Sub EmitSequencePointExpression(node As BoundSequencePointExpression, used As Boolean) diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitAddress.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitAddress.vb index 07a97a9f19cbf..dc61bf6aa465f 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitAddress.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitAddress.vb @@ -418,7 +418,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen _builder.EmitOpCode(ILOpCode.Ldelema) EmitSymbolToken(elementType, arrayAccess.Syntax) Else - _builder.EmitArrayElementAddress(_module.Translate(DirectCast(arrayAccess.Expression.Type, ArrayTypeSymbol)), arrayAccess.Syntax, _diagnostics) + _builder.EmitArrayElementAddress(_module.Translate(DirectCast(arrayAccess.Expression.Type, ArrayTypeSymbol)), arrayAccess.Syntax) End If End Sub diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb index 521b98d7564e0..51cc53e794be2 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), inits.Syntax, _diagnostics) + _builder.EmitArrayBlockInitializer(Me.GetRawData(initExprs), inits.Syntax) If initializationStyle = ArrayInitializerStyle.Mixed Then EmitElementInitializers(arrayType, initExprs, False) diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb index 12acce46ad6de..6bfe58eaac5e1 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitExpression.vb @@ -649,7 +649,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen End If End Select Else - _builder.EmitArrayElementLoad(_module.Translate(DirectCast(arrayAccess.Expression.Type, ArrayTypeSymbol)), arrayAccess.Expression.Syntax, _diagnostics) + _builder.EmitArrayElementLoad(_module.Translate(DirectCast(arrayAccess.Expression.Type, ArrayTypeSymbol)), arrayAccess.Expression.Syntax) End If EmitPopIfUnused(used) @@ -1630,7 +1630,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen _builder.EmitOpCode(ILOpCode.Newarr) EmitSymbolToken(arrayType.ElementType, expression.Syntax) Else - _builder.EmitArrayCreation(_module.Translate(arrayType), expression.Syntax, _diagnostics) + _builder.EmitArrayCreation(_module.Translate(arrayType), expression.Syntax) End If If expression.InitializerOpt IsNot Nothing Then @@ -2107,7 +2107,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen If arrayType.IsSZArray Then EmitVectorElementStore(arrayType, syntaxNode) Else - _builder.EmitArrayElementStore(_module.Translate(arrayType), syntaxNode, _diagnostics) + _builder.EmitArrayElementStore(_module.Translate(arrayType), syntaxNode) End If End Sub @@ -2355,7 +2355,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen End Sub Private Sub EmitModuleVersionIdToken(node As BoundModuleVersionId) - _builder.EmitToken(_module.GetModuleVersionId(_module.Translate(node.Type, node.Syntax, _diagnostics), node.Syntax, _diagnostics), node.Syntax, _diagnostics) + _builder.EmitToken(_module.GetModuleVersionId(_module.Translate(node.Type, node.Syntax, _diagnostics), node.Syntax, _diagnostics), node.Syntax) End Sub Private Sub EmitModuleVersionIdStringLoad(node As BoundModuleVersionIdString) @@ -2374,7 +2374,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen End Sub Private Sub EmitInstrumentationPayloadRootToken(node As BoundInstrumentationPayloadRoot) - _builder.EmitToken(_module.GetInstrumentationPayloadRoot(node.AnalysisKind, _module.Translate(node.Type, node.Syntax, _diagnostics), node.Syntax, _diagnostics), node.Syntax, _diagnostics) + _builder.EmitToken(_module.GetInstrumentationPayloadRoot(node.AnalysisKind, _module.Translate(node.Type, node.Syntax, _diagnostics), node.Syntax, _diagnostics), node.Syntax) End Sub Private Sub EmitSourceDocumentIndex(node As BoundSourceDocumentIndex) diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb index ba2cff9906326..d0991f50819a9 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb @@ -227,7 +227,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen 'Determine if the exception object is or inherits from System.Exception _builder.EmitOpCode(ILOpCode.Isinst) - _builder.EmitToken(exceptionType, catchBlock.Syntax, _diagnostics) + _builder.EmitToken(exceptionType, catchBlock.Syntax) _builder.EmitOpCode(ILOpCode.Ldnull) _builder.EmitOpCode(ILOpCode.Cgt_un) @@ -251,7 +251,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen _builder.MarkFilterConditionEnd() _builder.EmitOpCode(ILOpCode.Castclass) - _builder.EmitToken(exceptionType, catchBlock.Syntax, _diagnostics) + _builder.EmitToken(exceptionType, catchBlock.Syntax) If ShouldNoteProjectErrors() Then EmitSetProjectError(catchBlock.Syntax, catchBlock.ErrorLineNumberOpt) @@ -278,7 +278,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen typeCheckFailedLabel = New Object _builder.EmitOpCode(ILOpCode.Isinst) - _builder.EmitToken(exceptionType, catchBlock.Syntax, _diagnostics) + _builder.EmitToken(exceptionType, catchBlock.Syntax) _builder.EmitOpCode(ILOpCode.Dup) _builder.EmitBranch(ILOpCode.Brtrue, typeCheckPassedLabel) _builder.EmitOpCode(ILOpCode.Pop) @@ -1100,7 +1100,7 @@ OtherExpressions: _builder.EmitLocalLoad(key) _builder.EmitOpCode(ILOpCode.[Call], stackAdjustment:=0) - _builder.EmitToken(stringHashMethodRef, syntaxNode, _diagnostics) + _builder.EmitToken(stringHashMethodRef, syntaxNode) Dim UInt32Type = DirectCast(_module.GetSpecialType(SpecialType.System_UInt32, syntaxNode, _diagnostics).GetInternalSymbol(), TypeSymbol) keyHash = AllocateTemp(UInt32Type, syntaxNode) @@ -1176,7 +1176,7 @@ OtherExpressions: _builder.EmitConstantValue(stringConstant, syntaxNode) _builder.EmitConstantValue(ConstantValue.False, syntaxNode) _builder.EmitOpCode(ILOpCode.Call, stackAdjustment:=-2) - _builder.EmitToken(stringCompareMethodRef, syntaxNode, _diagnostics) + _builder.EmitToken(stringCompareMethodRef, syntaxNode) ' CompareString returns 0 if Left and Right strings are equal. ' Branch to targetLabel if CompareString returned 0. diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index f0ace4940ea73..ddb0a586cbc64 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -1611,7 +1611,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic optimizations = OptimizationLevel.Release End If - Dim builder As ILBuilder = New ILBuilder(moduleBuilder, localSlotManager, optimizations, areLocalsZeroed:=True) + Dim builder As ILBuilder = New ILBuilder(moduleBuilder, localSlotManager, diagnostics.DiagnosticBag, optimizations, areLocalsZeroed:=True) Try Debug.Assert(Not diagnostics.HasAnyErrors) From 776e60d0df5c58215a59e9ad47ea3e3aba5c21f0 Mon Sep 17 00:00:00 2001 From: tmat Date: Wed, 16 Apr 2025 12:40:13 -0700 Subject: [PATCH 12/21] Fix/add nullable annotations --- .../Portable/Compiler/MethodCompiler.cs | 35 ++++---- .../Core/Portable/CodeGen/ILBuilder.cs | 85 ++++++++++--------- .../Core/Portable/CodeGen/MethodBody.cs | 26 +++--- 3 files changed, 80 insertions(+), 66 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 96eaad50afac6..480e86c1fd7d6 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -27,17 +27,18 @@ namespace Microsoft.CodeAnalysis.CSharp { internal sealed class MethodCompiler : CSharpSymbolVisitor { +#nullable enable private readonly CSharpCompilation _compilation; private readonly bool _emittingPdb; private readonly CancellationToken _cancellationToken; private readonly BindingDiagnosticBag _diagnostics; private readonly bool _hasDeclarationErrors; private readonly bool _emitMethodBodies; - private readonly PEModuleBuilder _moduleBeingBuiltOpt; // Null if compiling for diagnostics - private readonly Predicate _filterOpt; // If not null, limit analysis to specific symbols - private readonly SynthesizedEntryPointSymbol.AsyncForwardEntryPoint _entryPointOpt; + private readonly PEModuleBuilder? _moduleBeingBuiltOpt; // Null if compiling for diagnostics + private readonly Predicate? _filterOpt; // If not null, limit analysis to specific symbols + private readonly SynthesizedEntryPointSymbol.AsyncForwardEntryPoint? _entryPointOpt; - private DebugDocumentProvider _lazyDebugDocumentProvider; + private DebugDocumentProvider? _lazyDebugDocumentProvider; // // MethodCompiler employs concurrency by following flattened fork/join pattern. @@ -54,7 +55,7 @@ internal sealed class MethodCompiler : CSharpSymbolVisitor _compilerTasks; + private ConcurrentStack? _compilerTasks; // This field tracks whether any bound method body had hasErrors set or whether any constant field had a bad value. // We track it so that we can abort emission in the event that an error occurs without a corresponding diagnostic @@ -83,8 +84,8 @@ private void SetGlobalErrorIfTrue(bool arg) } // Internal for testing only. - internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuiltOpt, bool emittingPdb, bool hasDeclarationErrors, bool emitMethodBodies, - BindingDiagnosticBag diagnostics, Predicate filterOpt, SynthesizedEntryPointSymbol.AsyncForwardEntryPoint entryPointOpt, CancellationToken cancellationToken) + internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder? moduleBeingBuiltOpt, bool emittingPdb, bool hasDeclarationErrors, bool emitMethodBodies, + BindingDiagnosticBag diagnostics, Predicate? filterOpt, SynthesizedEntryPointSymbol.AsyncForwardEntryPoint? entryPointOpt, CancellationToken cancellationToken) { Debug.Assert(compilation != null); Debug.Assert(diagnostics != null); @@ -107,12 +108,12 @@ internal MethodCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBei public static void CompileMethodBodies( CSharpCompilation compilation, - PEModuleBuilder moduleBeingBuiltOpt, + PEModuleBuilder? moduleBeingBuiltOpt, bool emittingPdb, bool hasDeclarationErrors, bool emitMethodBodies, BindingDiagnosticBag diagnostics, - Predicate filterOpt, + Predicate? filterOpt, CancellationToken cancellationToken) { Debug.Assert(compilation != null); @@ -132,7 +133,7 @@ public static void CompileMethodBodies( // TODO: revise to use a loop instead of a recursion } - MethodSymbol entryPoint = null; + MethodSymbol? entryPoint = null; if (filterOpt is null) { entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, hasDeclarationErrors, emitMethodBodies, diagnostics, cancellationToken); @@ -197,7 +198,7 @@ public static void CompileMethodBodies( if (moduleBeingBuiltOpt != null && (methodCompiler._globalHasErrors || moduleBeingBuiltOpt.SourceModule.HasBadAttributes) && !diagnostics.HasAnyErrors() && !hasDeclarationErrors) { var messageResourceName = methodCompiler._globalHasErrors ? nameof(CodeAnalysisResources.UnableToDetermineSpecificCauseOfFailure) : nameof(CodeAnalysisResources.ModuleHasInvalidAttributes); - diagnostics.Add(ErrorCode.ERR_ModuleEmitFailure, NoLocation.Singleton, ((Cci.INamedEntity)moduleBeingBuiltOpt).Name, + diagnostics.Add(ErrorCode.ERR_ModuleEmitFailure, NoLocation.Singleton, ((Cci.INamedEntity)moduleBeingBuiltOpt).Name!, new LocalizableResourceString(messageResourceName, CodeAnalysisResources.ResourceManager, typeof(CodeAnalysisResources))); } @@ -214,7 +215,7 @@ public static void CompileMethodBodies( } } } - +#nullable disable // Returns the MethodSymbol for the assembly entrypoint. If the user has a Task returning main, // this function returns the synthesized Main MethodSymbol. internal static MethodSymbol GetEntryPoint(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool hasDeclarationErrors, bool emitMethodBodies, BindingDiagnosticBag diagnostics, CancellationToken cancellationToken) @@ -1385,6 +1386,7 @@ forSemanticModel.Syntax is { } semanticModelSyntax && } } +#nullable enable private void EmitSkeletonMethodInExtension(MethodSymbol methodSymbol) { if (!_emitMethodBodies) @@ -1393,6 +1395,7 @@ private void EmitSkeletonMethodInExtension(MethodSymbol methodSymbol) } Debug.Assert(_diagnostics.DiagnosticBag != null); + Debug.Assert(_moduleBeingBuiltOpt != null); ILBuilder builder = new ILBuilder(_moduleBeingBuiltOpt, new LocalSlotManager(slotAllocator: null), _diagnostics.DiagnosticBag, OptimizationLevel.Release, areLocalsZeroed: false); @@ -1425,15 +1428,15 @@ private void EmitSkeletonMethodInExtension(MethodSymbol methodSymbol) orderedLambdaRuntimeRudeEdits: ImmutableArray.Empty, closureDebugInfo: ImmutableArray.Empty, stateMachineTypeNameOpt: null, - stateMachineHoistedLocalScopes: default(ImmutableArray), - stateMachineHoistedLocalSlots: default(ImmutableArray), - stateMachineAwaiterSlots: default(ImmutableArray), + stateMachineHoistedLocalScopes: default, + stateMachineHoistedLocalSlots: default, + stateMachineAwaiterSlots: default, StateMachineStatesDebugInfo.Create(variableSlotAllocator: null, ImmutableArray.Empty), stateMachineMoveNextDebugInfoOpt: null, codeCoverageSpans: ImmutableArray.Empty, isPrimaryConstructor: false)); } - +#nullable disable private static MethodSymbol GetSymbolForEmittedBody(MethodSymbol methodSymbol) { return methodSymbol.PartialDefinitionPart ?? methodSymbol; diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index 674a530359293..041fcdce879ad 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -2,12 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Debugging; @@ -21,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CodeGen internal sealed partial class ILBuilder { private readonly OptimizationLevel _optimizations; - internal readonly LocalSlotManager LocalSlotManager; + internal readonly LocalSlotManager? LocalSlotManager; private readonly DiagnosticBag _diagnostics; private readonly LocalScopeManager _scopeManager; @@ -32,10 +30,10 @@ internal sealed partial class ILBuilder internal readonly BasicBlock leaderBlock; private EmitState _emitState; - private BasicBlock _lastCompleteBlock; - private BasicBlock _currentBlock; + private BasicBlock? _lastCompleteBlock; + private BasicBlock? _currentBlock; - private SyntaxTree _lastSeqPointTree; + private SyntaxTree? _lastSeqPointTree; private readonly SmallDictionary _labelInfos; private readonly bool _areLocalsZeroed; @@ -44,11 +42,11 @@ internal sealed partial class ILBuilder // This data is only relevant when builder has been realized. internal ImmutableArray RealizedIL; internal ImmutableArray RealizedExceptionHandlers; - internal SequencePointList RealizedSequencePoints; + internal SequencePointList? RealizedSequencePoints; // debug sequence points from all blocks, note that each // sequence point references absolute IL offset via IL marker - public ArrayBuilder SeqPointsOpt; + public ArrayBuilder? SeqPointsOpt; /// /// In some cases we have to get a final IL offset during emit phase, for example for @@ -62,14 +60,14 @@ internal sealed partial class ILBuilder /// will be put into array. Note that only markers from reachable blocks /// are materialized, the rest will have offset -1. /// - private ArrayBuilder _allocatedILMarkers; + private ArrayBuilder? _allocatedILMarkers; // Since blocks are created lazily in GetCurrentBlock, // pendingBlockCreate is set to true when a block must be // created, in particular for leader blocks in exception handlers. private bool _pendingBlockCreate; - internal ILBuilder(CommonPEModuleBuilder module, LocalSlotManager localSlotManager, DiagnosticBag diagnostics, OptimizationLevel optimizations, bool areLocalsZeroed) + internal ILBuilder(CommonPEModuleBuilder module, LocalSlotManager? localSlotManager, DiagnosticBag diagnostics, OptimizationLevel optimizations, bool areLocalsZeroed) { this.module = module; this.LocalSlotManager = localSlotManager; @@ -99,6 +97,7 @@ private BasicBlock GetCurrentBlock() return _currentBlock; } + [MemberNotNull(nameof(_currentBlock))] private void CreateBlock() { Debug.Assert(_currentBlock == null); @@ -107,6 +106,7 @@ private void CreateBlock() UpdatesForCreatedBlock(block); } + [MemberNotNull(nameof(_currentBlock))] private SwitchBlock CreateSwitchBlock() { // end the current block @@ -117,10 +117,13 @@ private SwitchBlock CreateSwitchBlock() return switchBlock; } + [MemberNotNull(nameof(_currentBlock))] private void UpdatesForCreatedBlock(BasicBlock block) { - _currentBlock = block; + Debug.Assert(_lastCompleteBlock != null); Debug.Assert(_lastCompleteBlock.NextBlock == null); + + _currentBlock = block; _lastCompleteBlock.NextBlock = block; _pendingBlockCreate = false; ReconcileTrailingMarkers(); @@ -157,29 +160,33 @@ private void ReconcileTrailingMarkers() // should be moved to the next block if (_lastCompleteBlock != null && _lastCompleteBlock.BranchCode == ILOpCode.Nop && - _lastCompleteBlock.LastILMarker >= 0 && - _allocatedILMarkers[_lastCompleteBlock.LastILMarker].BlockOffset == _lastCompleteBlock.RegularInstructionsLength) + _lastCompleteBlock.LastILMarker >= 0) { - int startMarker = -1; - int endMarker = -1; + Debug.Assert(_allocatedILMarkers != null); - while (_lastCompleteBlock.LastILMarker >= 0 && - _allocatedILMarkers[_lastCompleteBlock.LastILMarker].BlockOffset == _lastCompleteBlock.RegularInstructionsLength) + if (_allocatedILMarkers[_lastCompleteBlock.LastILMarker].BlockOffset != _lastCompleteBlock.RegularInstructionsLength) { - Debug.Assert((startMarker < 0) || (startMarker == (_lastCompleteBlock.LastILMarker + 1))); - startMarker = _lastCompleteBlock.LastILMarker; - if (endMarker < 0) + int startMarker = -1; + int endMarker = -1; + + while (_lastCompleteBlock.LastILMarker >= 0 && + _allocatedILMarkers[_lastCompleteBlock.LastILMarker].BlockOffset == _lastCompleteBlock.RegularInstructionsLength) { - endMarker = _lastCompleteBlock.LastILMarker; + Debug.Assert((startMarker < 0) || (startMarker == (_lastCompleteBlock.LastILMarker + 1))); + startMarker = _lastCompleteBlock.LastILMarker; + if (endMarker < 0) + { + endMarker = _lastCompleteBlock.LastILMarker; + } + _lastCompleteBlock.RemoveTailILMarker(_lastCompleteBlock.LastILMarker); } - _lastCompleteBlock.RemoveTailILMarker(_lastCompleteBlock.LastILMarker); - } - BasicBlock current = this.GetCurrentBlock(); - for (int marker = startMarker; marker <= endMarker; marker++) - { - current.AddILMarker(marker); - _allocatedILMarkers[marker] = new ILMarker() { BlockOffset = (int)current.RegularInstructionsLength, AbsoluteOffset = -1 }; + BasicBlock current = this.GetCurrentBlock(); + for (int marker = startMarker; marker <= endMarker; marker++) + { + current.AddILMarker(marker); + _allocatedILMarkers[marker] = new ILMarker() { BlockOffset = (int)current.RegularInstructionsLength, AbsoluteOffset = -1 }; + } } } } @@ -373,7 +380,7 @@ private static void RedirectBranchToBlockedDestination(BasicBlock block, object // if branch is blocked by a nonterminating finally, // returns label for a landing block used as a target of blocked branches // Otherwise returns null - private static object BlockedBranchDestination(BasicBlock src, BasicBlock dest) + private static object? BlockedBranchDestination(BasicBlock src, BasicBlock dest) { var srcHandler = src.EnclosingHandler; @@ -386,9 +393,9 @@ private static object BlockedBranchDestination(BasicBlock src, BasicBlock dest) return BlockedBranchDestinationSlow(dest.EnclosingHandler, srcHandler); } - private static object BlockedBranchDestinationSlow(ExceptionHandlerScope destHandler, ExceptionHandlerScope srcHandler) + private static object? BlockedBranchDestinationSlow(ExceptionHandlerScope destHandler, ExceptionHandlerScope srcHandler) { - ScopeInfo destHandlerScope = null; + ScopeInfo? destHandlerScope = null; if (destHandler != null) { destHandlerScope = destHandler.ContainingExceptionScope; @@ -520,11 +527,11 @@ private bool ForwardLabelsNoLeaving() var labelInfo = _labelInfos[label]; var targetBlock = labelInfo.bb; - Debug.Assert(!IsSpecialEndHandlerBlock(targetBlock)); + Debug.Assert(targetBlock != null && !IsSpecialEndHandlerBlock(targetBlock)); if (targetBlock.HasNoRegularInstructions) { - BasicBlock targetsTarget = null; + BasicBlock? targetsTarget = null; switch (targetBlock.BranchCode) { case ILOpCode.Br: @@ -580,11 +587,11 @@ private bool ForwardLabelsAllowLeaving() var targetBlock = labelInfo.bb; - Debug.Assert(!IsSpecialEndHandlerBlock(targetBlock)); + Debug.Assert(targetBlock != null && !IsSpecialEndHandlerBlock(targetBlock)); if (targetBlock.HasNoRegularInstructions) { - BasicBlock targetsTarget = null; + BasicBlock? targetsTarget = null; switch (targetBlock.BranchCode) { case ILOpCode.Br: @@ -902,6 +909,8 @@ private void RealizeBlocks() Debug.Assert(blockLastMarker >= blockFirstMarker); for (int i = blockFirstMarker; i <= blockLastMarker; i++) { + Debug.Assert(_allocatedILMarkers != null); + int blockOffset = _allocatedILMarkers[i].BlockOffset; int absoluteOffset = writer.Count + blockOffset; _allocatedILMarkers[i] = new ILMarker() { BlockOffset = blockOffset, AbsoluteOffset = absoluteOffset }; @@ -1103,7 +1112,7 @@ internal bool IsJustPastLabel() return _emitState.InstructionsEmitted == _instructionCountAtLastLabel; } - internal void OpenLocalScope(ScopeType scopeType = ScopeType.Variable, Cci.ITypeReference exceptionType = null) + internal void OpenLocalScope(ScopeType scopeType = ScopeType.Variable, Cci.ITypeReference? exceptionType = null) { if (scopeType == ScopeType.TryCatchFinally && IsJustPastLabel()) { @@ -1271,7 +1280,7 @@ private string GetDebuggerDisplay() if (visType != null) { var method = visType.GetTypeInfo().GetDeclaredMethod("ILBuilderToString"); - return (string)method.Invoke(null, new object[] { this, null, null }); + return (string)method!.Invoke(null, [this, null, null])!; } #endif diff --git a/src/Compilers/Core/Portable/CodeGen/MethodBody.cs b/src/Compilers/Core/Portable/CodeGen/MethodBody.cs index be2d425d5d0d4..4bc97bba46a32 100644 --- a/src/Compilers/Core/Portable/CodeGen/MethodBody.cs +++ b/src/Compilers/Core/Portable/CodeGen/MethodBody.cs @@ -26,11 +26,11 @@ internal sealed class MethodBody : Cci.IMethodBody // Debug information emitted to Release & Debug PDBs supporting the debugger, EEs and other tools: private readonly ImmutableArray _sequencePoints; private readonly ImmutableArray _localScopes; - private readonly Cci.IImportScope _importScopeOpt; - private readonly string _stateMachineTypeNameOpt; + private readonly Cci.IImportScope? _importScopeOpt; + private readonly string? _stateMachineTypeNameOpt; private readonly ImmutableArray _stateMachineHoistedLocalScopes; private readonly bool _hasDynamicLocalVariables; - private readonly StateMachineMoveNextBodyDebugInfo _stateMachineMoveNextDebugInfoOpt; + private readonly StateMachineMoveNextBodyDebugInfo? _stateMachineMoveNextDebugInfoOpt; // Debug information emitted to Debug PDBs supporting EnC: private readonly DebugId _methodId; @@ -54,23 +54,23 @@ public MethodBody( Cci.IMethodDefinition parent, DebugId methodId, ImmutableArray locals, - SequencePointList sequencePoints, - DebugDocumentProvider debugDocumentProvider, + SequencePointList? sequencePoints, + DebugDocumentProvider? debugDocumentProvider, ImmutableArray exceptionHandlers, bool areLocalsZeroed, bool hasStackalloc, ImmutableArray localScopes, bool hasDynamicLocalVariables, - Cci.IImportScope importScopeOpt, + Cci.IImportScope? importScopeOpt, ImmutableArray lambdaDebugInfo, ImmutableArray orderedLambdaRuntimeRudeEdits, ImmutableArray closureDebugInfo, - string stateMachineTypeNameOpt, + string? stateMachineTypeNameOpt, ImmutableArray stateMachineHoistedLocalScopes, ImmutableArray stateMachineHoistedLocalSlots, ImmutableArray stateMachineAwaiterSlots, StateMachineStatesDebugInfo stateMachineStatesDebugInfo, - StateMachineMoveNextBodyDebugInfo stateMachineMoveNextDebugInfoOpt, + StateMachineMoveNextBodyDebugInfo? stateMachineMoveNextDebugInfoOpt, ImmutableArray codeCoverageSpans, bool isPrimaryConstructor) { @@ -103,13 +103,15 @@ public MethodBody( _isPrimaryConstructor = isPrimaryConstructor; } - private static ImmutableArray GetSequencePoints(SequencePointList? sequencePoints, DebugDocumentProvider debugDocumentProvider) + private static ImmutableArray GetSequencePoints(SequencePointList? sequencePoints, DebugDocumentProvider? debugDocumentProvider) { if (sequencePoints == null || sequencePoints.IsEmpty) { return ImmutableArray.Empty; } + Debug.Assert(debugDocumentProvider != null); + var sequencePointsBuilder = ArrayBuilder.GetInstance(); sequencePoints.GetSequencePoints(debugDocumentProvider, sequencePointsBuilder); return sequencePointsBuilder.ToImmutableAndFree(); @@ -125,7 +127,7 @@ public MethodBody( Cci.IMethodDefinition Cci.IMethodBody.MethodDefinition => _parent; - StateMachineMoveNextBodyDebugInfo Cci.IMethodBody.MoveNextBodyInfo => _stateMachineMoveNextDebugInfoOpt; + StateMachineMoveNextBodyDebugInfo? Cci.IMethodBody.MoveNextBodyInfo => _stateMachineMoveNextDebugInfoOpt; ushort Cci.IMethodBody.MaxStack => _maxStack; @@ -138,9 +140,9 @@ public MethodBody( /// /// This is a list of the using directives that were in scope for this method body. /// - Cci.IImportScope Cci.IMethodBody.ImportScope => _importScopeOpt; + Cci.IImportScope? Cci.IMethodBody.ImportScope => _importScopeOpt; - string Cci.IMethodBody.StateMachineTypeName => _stateMachineTypeNameOpt; + string? Cci.IMethodBody.StateMachineTypeName => _stateMachineTypeNameOpt; ImmutableArray Cci.IMethodBody.StateMachineHoistedLocalScopes => _stateMachineHoistedLocalScopes; From 686347460f7a7566ce4253bc6adf7c34ac86a46e Mon Sep 17 00:00:00 2001 From: tmat Date: Wed, 16 Apr 2025 13:17:52 -0700 Subject: [PATCH 13/21] Fix ITokenDeferal --- .../Test/Core/Metadata/ILBuilderVisualizer.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs b/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs index b002e0c839cac..756c2629984fe 100644 --- a/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs +++ b/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs @@ -8,26 +8,25 @@ using System.Reflection.Emit; using System.Reflection.Metadata; using System.Text; -using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.Emit; +using Microsoft.CodeAnalysis.PooledObjects; +using Microsoft.CodeAnalysis.Symbols; using Microsoft.Metadata.Tools; using Roslyn.Utilities; using Cci = Microsoft.Cci; -using Microsoft.CodeAnalysis.Symbols; -using System.Diagnostics; -using System.Reflection.Metadata.Ecma335; namespace Roslyn.Test.Utilities { internal sealed class ILBuilderVisualizer : ILVisualizer { - private readonly ITokenDeferral _tokenDeferral; + private readonly CommonPEModuleBuilder _module; private readonly SymbolDisplayFormat _symbolDisplayFormat; public ILBuilderVisualizer(ITokenDeferral tokenDeferral, SymbolDisplayFormat? symbolDisplayFormat = null) { - _tokenDeferral = tokenDeferral; + _module = module; _symbolDisplayFormat = symbolDisplayFormat ?? SymbolDisplayFormat.ILVisualizationFormat; } @@ -39,7 +38,7 @@ public override string VisualizeUserString(uint token) return "##MVID##"; } - return "\"" + _tokenDeferral.GetStringFromToken(token) + "\""; + return "\"" + _module.GetStringFromToken(token) + "\""; } public override string VisualizeSymbol(uint token, OperandType operandType) @@ -58,7 +57,7 @@ public override string VisualizeSymbol(uint token, OperandType operandType) token &= 0xffffff; } - object reference = _tokenDeferral.GetReferenceFromToken(token); + object reference = _module.GetReferenceFromToken(token); ISymbol? symbol = ((reference as ISymbolInternal) ?? (reference as Cci.IReference)?.GetInternalSymbol())?.GetISymbol(); return string.Format("\"{0}\"", symbol == null ? (object)reference : symbol.ToDisplayString(_symbolDisplayFormat)); } From 538fd2d1cb93a2bf42a8aa10287bb48ec849dbc2 Mon Sep 17 00:00:00 2001 From: tmat Date: Wed, 16 Apr 2025 13:18:10 -0700 Subject: [PATCH 14/21] Fix annotations --- src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index f57baa7baa4bc..7216e37957e56 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -40,13 +40,13 @@ internal void EmitOpCode(ILOpCode code, int stackAdjustment) internal void EmitToken(string value) { - uint token = module?.GetFakeStringTokenForIL(value) ?? 0xFFFF; + uint token = module.GetFakeStringTokenForIL(value); this.GetCurrentWriter().WriteUInt32(token); } internal void EmitToken(Cci.IReference value, SyntaxNode? syntaxNode, Cci.MetadataWriter.RawTokenEncoding encoding = 0) { - uint token = module?.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics) ?? 0xFFFF; + uint token = module.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics); if (encoding != Cci.MetadataWriter.RawTokenEncoding.None) { token = Cci.MetadataWriter.GetRawToken(encoding, token); @@ -56,7 +56,7 @@ internal void EmitToken(Cci.IReference value, SyntaxNode? syntaxNode, Cci.Metada internal void EmitToken(Cci.ISignature value, SyntaxNode? syntaxNode) { - uint token = module?.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics) ?? 0xFFFF; + uint token = module.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics); this.GetCurrentWriter().WriteUInt32(token); } @@ -74,7 +74,7 @@ internal void EmitModuleVersionIdStringToken() internal void EmitSourceDocumentIndexToken(Cci.DebugSourceDocument document) { - var token = Cci.MetadataWriter.GetRawToken(Cci.MetadataWriter.RawTokenEncoding.DocumentRowId, module?.GetSourceDocumentIndexForIL(document) ?? 0xFFFF); + var token = Cci.MetadataWriter.GetRawToken(Cci.MetadataWriter.RawTokenEncoding.DocumentRowId, module.GetSourceDocumentIndexForIL(document)); this.GetCurrentWriter().WriteUInt32(token); } From b0acc9c8644effe9ee171af58b56b373172e0824 Mon Sep 17 00:00:00 2001 From: tmat Date: Wed, 16 Apr 2025 14:57:52 -0700 Subject: [PATCH 15/21] String token allocation --- .../CSharp/Portable/CodeGen/EmitExpression.cs | 64 ++++------------- .../Emitter/Model/PEAssemblyBuilder.cs | 2 +- .../Portable/Emitter/Model/PEModuleBuilder.cs | 2 +- .../CSharp/Portable/Errors/MessageProvider.cs | 1 + .../EditAndContinue/EditAndContinueTests.cs | 10 +-- .../MetadataHelpersTests.cs | 11 +++ .../Core/Portable/CodeGen/ILBuilderEmit.cs | 65 ++++++++++++++--- .../Core/Portable/CodeGen/StringTokenMap.cs | 72 +++++++++++++++++++ .../Diagnostic/CommonMessageProvider.cs | 1 + .../Portable/Emit/CommonPEModuleBuilder.cs | 32 ++++----- .../EditAndContinue/DeltaMetadataWriter.cs | 2 +- .../Emit/EditAndContinue/EmitBaseline.cs | 8 --- .../MetadataReader/MetadataHelpers.cs | 41 +++++++++++ .../Test/Core/Mocks/TestMessageProvider.cs | 8 +++ .../Portable/Emit/PEAssemblyBuilder.vb | 2 +- .../VisualBasic/Portable/Errors/Errors.vb | 3 +- .../Portable/Errors/MessageProvider.vb | 6 ++ 17 files changed, 233 insertions(+), 97 deletions(-) create mode 100644 src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 04ad7a1baeb1a..7e6f66b982aab 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -3474,67 +3474,27 @@ private void EmitDefaultExpression(BoundDefaultExpression expression, bool used) private void EmitConstantExpression(TypeSymbol type, ConstantValue constantValue, bool used, SyntaxNode syntaxNode) { - if (used) // unused constant has no side-effects - { - // Null type parameter values must be emitted as 'initobj' rather than 'ldnull'. - if (((object)type != null) && (type.TypeKind == TypeKind.TypeParameter) && constantValue.IsNull) - { - EmitInitObj(type, used, syntaxNode); - } - else if (!TryEmitStringLiteralAsUtf8Encoded(constantValue, syntaxNode)) - { - _builder.EmitConstantValue(constantValue, syntaxNode); - } - } - } - - private bool TryEmitStringLiteralAsUtf8Encoded(ConstantValue constantValue, SyntaxNode syntaxNode) - { - // Emit long strings into data section so they don't overflow the UserString heap. - if (!constantValue.IsString) - { - return false; - } - - bool utf8Required = _module.PreviousGeneration != null && _module.PreviousGeneration.UserStringStreamLength > EmitBaseline.UserStringHeapSizeLimit; - if (!utf8Required) - { - var threshold = _module.Compilation.DataSectionStringLiteralThreshold; - if (threshold == null || constantValue.StringValue.Length <= threshold) - { - return false; - } - } - - var field = tryGetOrCreateField(); - if (field != null) + // unused constant has no side-effects + if (!used) { - _builder.EmitOpCode(ILOpCode.Ldsfld); - _builder.EmitToken(field, syntaxNode); - return true; + return; } - if (utf8Required) + // Null type parameter values must be emitted as 'initobj' rather than 'ldnull'. + if (type is { TypeKind: TypeKind.TypeParameter } && constantValue.IsNull) { - _diagnostics.Add(ErrorCode.ERR_TooManyUserStrings_RestartRequired, syntaxNode); + EmitInitObj(type, used, syntaxNode); } - - return false; - - Cci.IFieldReference tryGetOrCreateField() + else { - if (!_module.FieldRvaSupported) - { - return null; - } - - if (GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__get_UTF8, _diagnostics, syntax: syntaxNode) == null | - GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__GetString, _diagnostics, syntax: syntaxNode) == null) + // TODO: use-site dependencies are not reported to UsedAssemblyReferences https://github.com/dotnet/roslyn/issues/78172 + if (constantValue.IsString && constantValue.StringValue.Length <= _module.Compilation.DataSectionStringLiteralThreshold) { - return null; + _ = Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__get_UTF8, _diagnostics, syntax: syntaxNode); + _ = Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__GetString, _diagnostics, syntax: syntaxNode); } - return _module.TryGetOrCreateFieldForStringValue(constantValue.StringValue, syntaxNode, _diagnostics.DiagnosticBag); + _builder.EmitConstantValue(constantValue, syntaxNode); } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index b1017b9c61795..8f884e92d2e00 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -65,7 +65,7 @@ internal abstract class PEAssemblyBuilderBase : PEModuleBuilder, Cci.IAssemblyRe /// private readonly string _metadataName; #nullable enable - public PEAssemblyBuilderBase( + protected PEAssemblyBuilderBase( SourceAssemblySymbol sourceAssembly, EmitOptions emitOptions, OutputKind outputKind, diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index 19cb20430e9bf..38f5669225f37 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -73,7 +73,7 @@ private void SetNeedsGeneratedAttributes(EmbeddableAttributes attributes) ThreadSafeFlagOperations.Set(ref _needsGeneratedAttributes, (int)attributes); } - internal PEModuleBuilder( + protected PEModuleBuilder( SourceModuleSymbol sourceModule, EmitOptions emitOptions, OutputKind outputKind, diff --git a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs index ba05a944c54bd..059ec8b9672e4 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageProvider.cs @@ -245,6 +245,7 @@ public override void ReportDuplicateMetadataReferenceWeak(DiagnosticBag diagnost public override int ERR_MetadataNameTooLong => (int)ErrorCode.ERR_MetadataNameTooLong; public override int ERR_EncReferenceToAddedMember => (int)ErrorCode.ERR_EncReferenceToAddedMember; public override int ERR_TooManyUserStrings => (int)ErrorCode.ERR_TooManyUserStrings; + public override int ERR_TooManyUserStrings_RestartRequired => (int)ErrorCode.ERR_TooManyUserStrings_RestartRequired; public override int ERR_PeWritingFailure => (int)ErrorCode.ERR_PeWritingFailure; public override int ERR_ModuleEmitFailure => (int)ErrorCode.ERR_ModuleEmitFailure; public override int ERR_EncUpdateFailedMissingSymbol => (int)ErrorCode.ERR_EncUpdateFailedMissingSymbol; diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 38793e0d4cc85..f2b301b1e1a58 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -19869,10 +19869,10 @@ .maxstack 1 [WorkItem("https://github.com/dotnet/roslyn/issues/69480")] public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaSupported() { - // The max number of bytes that can fit into #US the heap is 2^29 - 1, - // but each string also needs to have an offset < 0x1000000 (2^24) to be addressable by a token. - // If the string is larger than that the next string can't be emitted. - var baseString = new string('x', 1 << 23); + // The longest string that can fit in the #US heap. The next string would overflow the heap. + var baseString = new string('x', (1 << 23) - 3); + + var size = MetadataHelpers.GetUserStringBlobSize(baseString); using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) .AddBaseline( @@ -19886,7 +19886,7 @@ class C { g.VerifyTypeDefNames("", "C"); g.VerifyFieldDefNames(); - g.VerifyMethodDefNames("F", ".ctor"); + g.VerifyMethodDefNames("G", "F", ".ctor"); }) .AddGeneration( source: """ diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataHelpersTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataHelpersTests.cs index 63341865aa107..b6494e4c279da 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataHelpersTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataHelpersTests.cs @@ -503,5 +503,16 @@ public void ObfuscatedNamespaceNames_02() Assert.Equal("a", nestedNamespaces.ElementAt(0).Key); Assert.Equal("b", nestedNamespaces.ElementAt(1).Key); } + + [Theory] + [InlineData("")] + [InlineData("abc")] + [InlineData("\u1234")] + public static void GetUserStringBlobSize(string str) + { + var builder = new BlobBuilder(); + builder.WriteUserString(str); + Assert.Equal(builder.Count, MetadataHelpers.GetUserStringBlobSize(str)); + } } } diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 7216e37957e56..ae5deb93e90c2 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -38,12 +38,6 @@ internal void EmitOpCode(ILOpCode code, int stackAdjustment) _emitState.InstructionAdded(); } - internal void EmitToken(string value) - { - uint token = module.GetFakeStringTokenForIL(value); - this.GetCurrentWriter().WriteUInt32(token); - } - internal void EmitToken(Cci.IReference value, SyntaxNode? syntaxNode, Cci.MetadataWriter.RawTokenEncoding encoding = 0) { uint token = module.GetFakeSymbolTokenForIL(value, syntaxNode, _diagnostics); @@ -742,11 +736,64 @@ internal void EmitStringConstant(string? value, SyntaxNode syntax) if (value == null) { EmitNullConstant(); + return; } - else + + int? threshold = module.CommonCompilation.DataSectionStringLiteralThreshold; + + // Try allocate token if no threshold is given or the value is within the threshold. + // The token allocation can still fail, if the string doesn't fit to the UserString heap. + if (threshold == null || value.Length <= threshold) + { + if (module.TryGetFakeStringTokenForIL(value, out uint token)) + { + EmitOpCode(ILOpCode.Ldstr); + GetCurrentWriter().WriteUInt32(token); + return; + } + + // If emitting EnC delta we fall back to data section literal + // regardless of whether the feature is enabled or not. + if (module.PreviousGeneration == null) + { + reportError(); + return; + } + } + + // Try to emit the string literal to data section. + var field = tryGetOrCreateField(); + if (field == null) + { + reportError(); + return; + } + + EmitOpCode(ILOpCode.Ldsfld); + EmitToken(field, syntax); + + void reportError() + { + var messageProvider = module.CommonCompilation.MessageProvider; + int code = module.PreviousGeneration != null ? messageProvider.ERR_TooManyUserStrings_RestartRequired : messageProvider.ERR_TooManyUserStrings; + _diagnostics.Add(messageProvider.CreateDiagnostic(code, syntax.Location)); + } + + Cci.IFieldReference? tryGetOrCreateField() { - EmitOpCode(ILOpCode.Ldstr); - EmitToken(value); + if (!module.FieldRvaSupported) + { + return null; + } + + // Binder should have reported use-site errors for these members. + if (module.CommonCompilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Text_Encoding__get_UTF8) == null || + module.CommonCompilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Text_Encoding__GetString) == null) + { + return null; + } + + return module.TryGetOrCreateFieldForStringValue(value, syntax, _diagnostics); } } diff --git a/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs b/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs new file mode 100644 index 0000000000000..88ee01cc58ff3 --- /dev/null +++ b/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs @@ -0,0 +1,72 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Concurrent; +using System.Collections.Generic; +using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; +using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; + +namespace Microsoft.CodeAnalysis.CodeGen; + +/// +/// Handles storage of strings referenced via tokens in metadata. When values are stored +/// they are uniquely "associated" with fake tokens, which are basically sequential numbers. +/// IL gen will use these fake tokens during codegen and later, when actual values +/// are known, the method bodies will be patched. +/// +internal sealed class StringTokenMap(int initialHeapSize) +{ + private readonly ConcurrentDictionary _valueToToken = new ConcurrentDictionary(ReferenceEqualityComparer.Instance); + private readonly ArrayBuilder _uniqueValues = []; + private int _heapSize = initialHeapSize; + + public bool TryGetOrAddToken(string value, out uint token) + { + // NOTE: cannot use GetOrAdd here since _uniqueValues and _valueToToken must be in sync + // so if we do need to add we have to take a lock and modify both collections. + if (_valueToToken.TryGetValue(value, out token)) + { + return true; + } + + lock (_uniqueValues) + { + if (_valueToToken.TryGetValue(value, out token)) + { + return true; + } + + // String can span beyond the heap limit, but must start within the limit. + if (_heapSize > MetadataHelpers.UserStringHeapCapacity) + { + return false; + } + + _heapSize += MetadataHelpers.GetUserStringBlobSize(value); + + token = (uint)_uniqueValues.Count; + _uniqueValues.Add(value); + _valueToToken.Add(value, token); + + return true; + } + } + + public string GetValue(uint token) + { + lock (_uniqueValues) + { + return _uniqueValues[(int)token]; + } + } + + public string[] CopyValues() + { + lock (_uniqueValues) + { + return _uniqueValues.ToArray(); + } + } +} diff --git a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs index b662165fee496..6d3310c771bbb 100644 --- a/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs +++ b/src/Compilers/Core/Portable/Diagnostic/CommonMessageProvider.cs @@ -239,6 +239,7 @@ public string GetIdForErrorCode(int errorCode) public abstract int ERR_MetadataNameTooLong { get; } public abstract int ERR_EncReferenceToAddedMember { get; } public abstract int ERR_TooManyUserStrings { get; } + public abstract int ERR_TooManyUserStrings_RestartRequired { get; } public abstract int ERR_PeWritingFailure { get; } public abstract int ERR_ModuleEmitFailure { get; } public abstract int ERR_EncUpdateFailedMissingSymbol { get; } diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 98c962e39de98..c202123376ed6 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.Contracts; using System.IO; using System.Linq; using System.Security.Cryptography; @@ -35,7 +36,7 @@ internal abstract class CommonPEModuleBuilder : Cci.IUnit, Cci.IModuleReference private readonly ConcurrentDictionary _methodBodyMap; private readonly TokenMap _referencesInILMap = new(); - private readonly ItemTokenMap _stringsInILMap = new(); + private readonly Lazy _stringsInILMap; private readonly ItemTokenMap _sourceDocumentsInILMap = new(); private ImmutableArray _lazyAssemblyReferenceAliases; @@ -48,7 +49,7 @@ internal abstract class CommonPEModuleBuilder : Cci.IUnit, Cci.IModuleReference internal EmitOptions EmitOptions { get; } - public CommonPEModuleBuilder( + protected CommonPEModuleBuilder( IEnumerable manifestResources, EmitOptions emitOptions, OutputKind outputKind, @@ -64,6 +65,7 @@ public CommonPEModuleBuilder( OutputKind = outputKind; SerializationProperties = serializationProperties; _methodBodyMap = new ConcurrentDictionary(ReferenceEqualityComparer.Instance); + _stringsInILMap = new Lazy(() => new StringTokenMap(PreviousGeneration?.UserStringStreamLength ?? 0)); EmitOptions = emitOptions; } @@ -206,6 +208,12 @@ public ArrayMethods ArrayMethods } } + /// + /// + /// + public Cci.IFieldReference? TryGetOrCreateFieldForStringValue(string text, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + => PrivateImplementationDetails.TryGetOrCreateFieldForStringValue(text, this, syntaxNode, diagnostics); + public abstract IEnumerable GetTopLevelTypeDefinitions(EmitContext context); public IEnumerable GetTopLevelTypeDefinitionsCore(EmitContext context) @@ -421,7 +429,7 @@ public Cci.IAssemblyReference GetContainingAssembly(EmitContext context) /// public string[] CopyStrings() { - return _stringsInILMap.CopyItems(); + return _stringsInILMap.Value.CopyValues(); } public uint GetFakeSymbolTokenForIL(Cci.IReference symbol, SyntaxNode syntaxNode, DiagnosticBag diagnostics) @@ -459,15 +467,11 @@ public object GetReferenceFromToken(uint token) return _referencesInILMap.GetItem(token); } - public uint GetFakeStringTokenForIL(string str) - { - return _stringsInILMap.GetOrAddTokenFor(str); - } + public bool TryGetFakeStringTokenForIL(string str, out uint token) + => _stringsInILMap.Value.TryGetOrAddToken(str, out token); public string GetStringFromToken(uint token) - { - return _stringsInILMap.GetItem(token); - } + => _stringsInILMap.Value.GetValue(token); public ReadOnlySpan ReferencesInIL() { @@ -1075,14 +1079,6 @@ public sealed override Cci.IFieldReference GetArrayCachingFieldForConstants(Immu return privateImpl.CreateArrayCachingField(constants, arrayType, emitContext); } - /// - /// - /// - public Cci.IFieldReference TryGetOrCreateFieldForStringValue(string text, TSyntaxNode syntaxNode, DiagnosticBag diagnostics) - { - return PrivateImplementationDetails.TryGetOrCreateFieldForStringValue(text, this, syntaxNode, diagnostics); - } - #endregion #region Private Implementation Details Type diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 7b783bb5a38bd..e054815742b86 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -137,7 +137,7 @@ private static MetadataBuilder MakeTablesBuilder(EmitBaseline previousGeneration // The baseline #UserString heap size might exceed this limit as long as the last string it contains starts within the limit. // If the limit is exceeded we can't add any more strings in the delta heap (they would start beyond the limit), but we still can emit deltas. // The check in MetadataBuilder constructor is enforcing the limit, but it should really only throw when a new string is added. - userStringHeapStartOffset: Math.Min(EmitBaseline.UserStringHeapSizeLimit, previousGeneration.UserStringStreamLength), + userStringHeapStartOffset: Math.Min(MetadataHelpers.UserStringHeapCapacity, previousGeneration.UserStringStreamLength), stringHeapStartOffset: previousGeneration.StringStreamLength, blobHeapStartOffset: previousGeneration.BlobStreamLength, guidHeapStartOffset: previousGeneration.GuidStreamLength); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs index 3c7f9d5cbd386..6e5c4a4c69f4f 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EmitBaseline.cs @@ -62,14 +62,6 @@ public override int GetHashCode() /// public sealed class EmitBaseline { - /// - /// Once the baseline #UserString heap reaches this size, we can't emit any more string literals to it. - /// We need to switch to using FieldRVAs for any new string literals, if the runtime supports it. - /// - /// See https://github.com/dotnet/runtime/blob/2bd17019c1c01a6bf17a2de244ff92591fc3c334/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs#L82 - /// - internal const int UserStringHeapSizeLimit = 0xfffffe; - private static readonly ImmutableArray s_emptyTableSizes = ImmutableArray.Create(new int[MetadataTokens.TableCount]); internal sealed class MetadataSymbols( diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs index 74cec5acf2eec..07349b48ee6b5 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs @@ -19,6 +19,17 @@ namespace Microsoft.CodeAnalysis { internal static class MetadataHelpers { + /// + /// Once the #UserString heap reaches this size, we can't emit any more string literals to it. + /// + /// The max number of bytes that can fit into #US the heap is 2^29 - 1, + /// but each string also needs to have an offset that's at most 0xffffff (2^24 - 1) to be addressable by a token. + /// First byte of the heap is reserved (0), hence there is 2 ^ 24 - 2 bytes available for user strings. + /// + /// See https://github.com/dotnet/runtime/blob/2bd17019c1c01a6bf17a2de244ff92591fc3c334/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs#L82 + /// + internal const int UserStringHeapCapacity = 0xfffffe; + // https://github.com/dotnet/roslyn/issues/73548: // Remove this constant and refer to GenericParameterAttributes.AllowByRefLike directly once the new enum member becomes available. // See // https://github.com/dotnet/runtime/issues/68002#issuecomment-1942166436 for more details. @@ -1066,5 +1077,35 @@ internal static string MangleForTypeNameIfNeeded(string moduleName) return pooledStrBuilder.ToStringAndFree(); } + + /// + /// Calculates the number of bytes written on #UserHeap for the given string. + /// See https://github.com/dotnet/runtime/blob/5bfc0bec9d627c946f154dd99103a393d278f841/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs#L1044 + /// + internal static int GetUserStringBlobSize(string value) + { + var byteLength = value.Length * 2 + 1; + return GetCompressedIntegerSize(byteLength) + byteLength; + } + + /// + /// See https://github.com/dotnet/runtime/blob/5bfc0bec9d627c946f154dd99103a393d278f841/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs#L16 + /// + internal static int GetCompressedIntegerSize(int value) + { + Debug.Assert(value <= 0x1fffffff); + + if (value <= 0x7f) + { + return 1; + } + + if (value <= 0x3fff) + { + return 2; + } + + return 4; + } } } diff --git a/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs b/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs index b3fa3ea6172e3..98fa2e6c6df14 100644 --- a/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs +++ b/src/Compilers/Test/Core/Mocks/TestMessageProvider.cs @@ -400,6 +400,14 @@ public override int ERR_TooManyUserStrings } } + public override int ERR_TooManyUserStrings_RestartRequired + { + get + { + throw new NotImplementedException(); + } + } + public override int ERR_PeWritingFailure { get diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb index a7bdac55f95b5..24e584bb216ae 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb @@ -33,7 +33,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit ''' Private ReadOnly _metadataName As String - Public Sub New(sourceAssembly As SourceAssemblySymbol, + Friend Sub New(sourceAssembly As SourceAssemblySymbol, emitOptions As EmitOptions, outputKind As OutputKind, serializationProperties As Cci.ModulePropertiesForSerialization, diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index 2c425f89a3c2b..712f0a799f7d2 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -1787,8 +1787,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_CannotApplyOverloadResolutionPriorityToMember = 37334 ERR_EmbeddedAttributeMustFollowPattern = 37335 + ERR_TooManyUserStrings_RestartRequired = 37336 - ERR_NextAvailable = 37336 + ERR_NextAvailable = 37337 '// WARNINGS BEGIN HERE WRN_UseOfObsoleteSymbol2 = 40000 diff --git a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb index 0e573eaa217bd..153704ad8e975 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/MessageProvider.vb @@ -558,6 +558,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Get End Property + Public Overrides ReadOnly Property ERR_TooManyUserStrings_RestartRequired As Integer + Get + Return ERRID.ERR_TooManyUserStrings_RestartRequired + End Get + End Property + Public Overrides ReadOnly Property ERR_PeWritingFailure As Integer Get Return ERRID.ERR_PeWritingFailure From b776e1a52cce687175ce4b2d30386a357e5dd3e9 Mon Sep 17 00:00:00 2001 From: tmat Date: Wed, 16 Apr 2025 16:54:25 -0700 Subject: [PATCH 16/21] FIxes --- .../CSharp/Portable/CodeGen/EmitExpression.cs | 2 +- .../CSharp/Test/Emit/Emit/EmitErrorTests.cs | 8 +- .../EditAndContinue/EditAndContinueTests.cs | 108 +++++++++++++++++- .../Core/Portable/CodeGen/ILBuilder.cs | 2 +- .../Core/Portable/CodeGen/ILBuilderEmit.cs | 57 ++++----- .../Emit/EditAndContinue/DeletedMethodBody.cs | 1 - 6 files changed, 144 insertions(+), 34 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs index 7e6f66b982aab..c1191eba65e01 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs @@ -3488,7 +3488,7 @@ private void EmitConstantExpression(TypeSymbol type, ConstantValue constantValue else { // TODO: use-site dependencies are not reported to UsedAssemblyReferences https://github.com/dotnet/roslyn/issues/78172 - if (constantValue.IsString && constantValue.StringValue.Length <= _module.Compilation.DataSectionStringLiteralThreshold) + if (constantValue.IsString && constantValue.StringValue.Length > _module.Compilation.DataSectionStringLiteralThreshold) { _ = Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__get_UTF8, _diagnostics, syntax: syntaxNode); _ = Binder.GetWellKnownTypeMember(_module.Compilation, WellKnownMember.System_Text_Encoding__GetString, _diagnostics, syntax: syntaxNode); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs index d522c10deec21..0c63bf61d1e25 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitErrorTests.cs @@ -341,8 +341,12 @@ public static void Main () var expectedDiagnostics = new[] { - // error CS8103: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. - Diagnostic(ErrorCode.ERR_TooManyUserStrings).WithLocation(1, 1) + // (15,26): error CS8103: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. + // System.Console.WriteLine("J...J"); + Diagnostic(ErrorCode.ERR_TooManyUserStrings, '"' + new string('J', 1000000) + '"').WithLocation(15, 26), + // (16,26): error CS8103: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string literals or try the EXPERIMENTAL feature flag 'experimental-data-section-string-literals'. + // System.Console.WriteLine("K...K"); + Diagnostic(ErrorCode.ERR_TooManyUserStrings, '"' + new string('K', 1000000) + '"').WithLocation(16, 26) }; CreateCompilation(source).VerifyEmitDiagnostics(expectedDiagnostics); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index f2b301b1e1a58..f19f73a1940af 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -19886,7 +19886,7 @@ class C { g.VerifyTypeDefNames("", "C"); g.VerifyFieldDefNames(); - g.VerifyMethodDefNames("G", "F", ".ctor"); + g.VerifyMethodDefNames("F", ".ctor"); }) .AddGeneration( source: """ @@ -19966,6 +19966,112 @@ .maxstack 1 .Verify(); } + [Fact] + public void PrivateImplDetails_DataSectionStringLiterals_StringReuse_FieldRvaSupported() + { + // Literals are currently only reused within generation. + + var baseString = new string('x', (1 << 23) - 100); + var newString1 = new string('1', 40); + var newString2 = new string('2', 80); + + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) + .AddBaseline( + source: $$""" + class C + { + void G(string a, string b, string c) {} + + void F() => G("{{baseString}}", "{{newString1}}", ""); + } + """, + validator: g => + { + g.VerifyTypeDefNames("", "C"); + g.VerifyFieldDefNames(); + g.VerifyMethodDefNames("G", "F", ".ctor"); + }) + .AddGeneration( + source: $$""" + class C + { + void G(string a, string b, string c) {} + + void F() => G("{{newString2}}", "{{newString2}}", "{{newString1}}"); + } + """, + edits: + [ + Edit(SemanticEditKind.Update, symbolProvider: c => c.GetMember("C.F")), + ], + validator: g => + { + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=40", "62CF64E173E5BF9EF5312BB6D57CC26C"); + g.VerifyFieldDefNames("468D019EA81224AECA7EE270B11959D8A187F6F0B6A3FEBFF1C34DC1D66C8D85", "s"); + g.VerifyMethodDefNames("F", "BytesToString", ".cctor"); + + g.VerifyEncLogDefinitions( + [ + Row(3, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(4, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(1, TableIndex.Field, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddField), + Row(2, TableIndex.Field, EditAndContinueOperation.Default), + Row(2, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(3, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(5, TableIndex.TypeDef, EditAndContinueOperation.AddMethod), + Row(5, TableIndex.MethodDef, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(4, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.MethodDef, EditAndContinueOperation.AddParameter), + Row(5, TableIndex.Param, EditAndContinueOperation.Default), + Row(4, TableIndex.CustomAttribute, EditAndContinueOperation.Default), + Row(1, TableIndex.ClassLayout, EditAndContinueOperation.Default), + Row(1, TableIndex.FieldRva, EditAndContinueOperation.Default), + Row(1, TableIndex.NestedClass, EditAndContinueOperation.Default), + Row(2, TableIndex.NestedClass, EditAndContinueOperation.Default) + ]); + + g.VerifyEncMapDefinitions( + [ + Handle(3, TableIndex.TypeDef), + Handle(4, TableIndex.TypeDef), + Handle(5, TableIndex.TypeDef), + Handle(1, TableIndex.Field), + Handle(2, TableIndex.Field), + Handle(2, TableIndex.MethodDef), + Handle(4, TableIndex.MethodDef), + Handle(5, TableIndex.MethodDef), + Handle(4, TableIndex.Param), + Handle(5, TableIndex.Param), + Handle(4, TableIndex.CustomAttribute), + Handle(1, TableIndex.ClassLayout), + Handle(1, TableIndex.FieldRva), + Handle(1, TableIndex.NestedClass), + Handle(2, TableIndex.NestedClass) + ]); + + g.VerifyIL("C.F", """ + { + // Code size 23 (0x17) + .maxstack 4 + IL_0000: ldarg.0 + IL_0001: ldstr "22222222222222222222222222222222222222222222222222222222222222222222222222222222" + IL_0006: ldstr "22222222222222222222222222222222222222222222222222222222222222222222222222222222" + IL_000b: ldsfld "string #1.62CF64E173E5BF9EF5312BB6D57CC26C.s" + IL_0010: call "void C.G(string, string, string)" + IL_0015: nop + IL_0016: ret + } + """); + }, + options: new EmitDifferenceOptions() { EmitFieldRva = true }) + .Verify(); + } + [Fact] public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaNotSupported() { diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index 041fcdce879ad..2337dc9fc7a8c 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -164,7 +164,7 @@ private void ReconcileTrailingMarkers() { Debug.Assert(_allocatedILMarkers != null); - if (_allocatedILMarkers[_lastCompleteBlock.LastILMarker].BlockOffset != _lastCompleteBlock.RegularInstructionsLength) + if (_allocatedILMarkers![_lastCompleteBlock.LastILMarker].BlockOffset == _lastCompleteBlock.RegularInstructionsLength) { int startMarker = -1; int endMarker = -1; diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index ae5deb93e90c2..70de0e2d77c0b 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -560,7 +560,7 @@ internal void EmitStoreArgumentOpcode(int argNumber) } } - internal void EmitConstantValue(ConstantValue value, SyntaxNode syntaxNode) + internal void EmitConstantValue(ConstantValue value, SyntaxNode? syntaxNode) { ConstantValueTypeDiscriminator discriminator = value.Discriminator; @@ -731,7 +731,7 @@ internal void EmitNullConstant() EmitOpCode(ILOpCode.Ldnull); } - internal void EmitStringConstant(string? value, SyntaxNode syntax) + internal void EmitStringConstant(string? value, SyntaxNode? syntax) { if (value == null) { @@ -739,44 +739,45 @@ internal void EmitStringConstant(string? value, SyntaxNode syntax) return; } - int? threshold = module.CommonCompilation.DataSectionStringLiteralThreshold; + // If the length is greater than the specified threshold try lfsfld first and fall back to ldstr. + // Otherwise, try emit ldstr and fall back to ldsfld if emitting EnC delta and the heap is already full. + bool success = (value.Length >= module.CommonCompilation.DataSectionStringLiteralThreshold) + ? tryEmitLoadField() || tryEmitLoadString() + : tryEmitLoadString() || module.PreviousGeneration != null && tryEmitLoadField(); - // Try allocate token if no threshold is given or the value is within the threshold. - // The token allocation can still fail, if the string doesn't fit to the UserString heap. - if (threshold == null || value.Length <= threshold) + if (!success) + { + // emit null to balance eval stack + EmitNullConstant(); + + var messageProvider = module.CommonCompilation.MessageProvider; + int code = module.PreviousGeneration != null ? messageProvider.ERR_TooManyUserStrings_RestartRequired : messageProvider.ERR_TooManyUserStrings; + _diagnostics.Add(messageProvider.CreateDiagnostic(code, syntax?.Location ?? Location.None)); + } + + bool tryEmitLoadString() { if (module.TryGetFakeStringTokenForIL(value, out uint token)) { EmitOpCode(ILOpCode.Ldstr); GetCurrentWriter().WriteUInt32(token); - return; + return true; } - // If emitting EnC delta we fall back to data section literal - // regardless of whether the feature is enabled or not. - if (module.PreviousGeneration == null) - { - reportError(); - return; - } + return false; } - // Try to emit the string literal to data section. - var field = tryGetOrCreateField(); - if (field == null) + bool tryEmitLoadField() { - reportError(); - return; - } - - EmitOpCode(ILOpCode.Ldsfld); - EmitToken(field, syntax); + var field = tryGetOrCreateField(); + if (field != null) + { + EmitOpCode(ILOpCode.Ldsfld); + EmitToken(field, syntax); + return true; + } - void reportError() - { - var messageProvider = module.CommonCompilation.MessageProvider; - int code = module.PreviousGeneration != null ? messageProvider.ERR_TooManyUserStrings_RestartRequired : messageProvider.ERR_TooManyUserStrings; - _diagnostics.Add(messageProvider.CreateDiagnostic(code, syntax.Location)); + return false; } Cci.IFieldReference? tryGetOrCreateField() diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs index 4d157271d4718..4ece9e7aa109b 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeletedMethodBody.cs @@ -85,7 +85,6 @@ public static ImmutableArray GetIL(EmitContext context, RuntimeRudeEdit? r } var syntaxNode = context.SyntaxNode; - Debug.Assert(syntaxNode != null); builder.EmitStringConstant(message, syntaxNode); builder.EmitIntConstant(codeValue); From 05940037998e7dc957126cec55f7c69841b46bd7 Mon Sep 17 00:00:00 2001 From: tmat Date: Thu, 17 Apr 2025 15:48:38 -0700 Subject: [PATCH 17/21] Move generating deleted method bodies before freezing PrivateImplementationDetails. Fix tests. Improve IL/field data validation in EnC tests --- .../Portable/Compiler/MethodCompiler.cs | 5 + .../Emitter/EditAndContinue/EmitHelpers.cs | 1 - .../EditAndContinue/PEDeltaAssemblyBuilder.cs | 2 +- .../Test/Emit/Emit/EmitMetadataTests.cs | 59 +++ .../AssemblyReferencesTests.cs | 10 +- .../EditAndContinue/EditAndContinueTests.cs | 358 +++++++++++++----- .../CodeGen/PrivateImplementationDetails.cs | 4 +- .../Core/Portable/Compilation/Compilation.cs | 6 +- .../Portable/Emit/CommonPEModuleBuilder.cs | 46 ++- .../EditAndContinue/DeltaMetadataWriter.cs | 39 +- .../Core/Compilation/CompilationDifference.cs | 3 +- .../Test/Core/Metadata/ILValidation.cs | 102 +++-- .../Portable/Compilation/MethodCompiler.vb | 5 + .../Emit/EditAndContinue/EmitHelpers.vb | 1 - .../EditAndContinue/PEDeltaAssemblyBuilder.vb | 2 +- .../EditAndContinue/EditAndContinueTests.vb | 104 +++-- .../EditAndContinueTest.GenerationVerifier.cs | 22 +- 17 files changed, 583 insertions(+), 186 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 480e86c1fd7d6..c4ebcd04da684 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -183,6 +183,11 @@ public static void CompileMethodBodies( methodCompiler.WaitForWorkers(); + // Deleted definitions must be emitted before PrivateImplementationDetails are frozen since + // it may add new members to it. All changes to PrivateImplementationDetails are additions, + // so we don't need to create deleted method defs for those. + moduleBeingBuiltOpt.CreateDeletedMethodDefinitions(diagnostics.DiagnosticBag); + // all threads that were adding methods must be finished now, we can freeze the class: var privateImplClass = moduleBeingBuiltOpt.FreezePrivateImplementationDetails(); if (privateImplClass != null) diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs index e0b3696c623fa..03e2185b727f7 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs @@ -132,7 +132,6 @@ internal static EmitDifferenceResult EmitDifference( newBaseline = compilation.SerializeToDeltaStreams( moduleBeingBuilt, definitionMap, - changes, metadataStream, ilStream, pdbStream, diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs index 1e93bc2a501f8..08e1d677504f8 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs @@ -238,7 +238,7 @@ public SynthesizedTypeMaps GetSynthesizedTypes() } public override IEnumerable GetTopLevelTypeDefinitions(EmitContext context) - => GetTopLevelTypeDefinitionsCore(context); + => GetTopLevelTypeDefinitionsExcludingNoPiaAndRootModule(context, includePrivateImplementationDetails: true); public override IEnumerable GetTopLevelSourceTypeDefinitions(EmitContext context) { diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs index c8577b654b471..484d3f8c0f0bc 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadataTests.cs @@ -3144,6 +3144,65 @@ .maxstack 1 Assert.Equal(0, verifier.Compilation.DataSectionStringLiteralThreshold); } + [Fact] + public void DataSectionStringLiterals_Switch() + { + var source = """ + System.Console.Write(args[0] switch + { + "a" => 1, + "bb" => 2, + "ccc" => 3, + _ => 4 + }); + """; + + var verifier = CompileAndVerify( + source, + parseOptions: TestOptions.Regular.WithFeature("experimental-data-section-string-literals", "0"), + verify: Verification.Skipped); + + verifier.VerifyIL("", """ + { + // Code size 66 (0x42) + .maxstack 2 + .locals init (int V_0, + string V_1) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: ldelem.ref + IL_0003: stloc.1 + IL_0004: ldloc.1 + IL_0005: ldsfld "string .A96FAF705AF16834E6C632B61E964E1F.s" + IL_000a: call "bool string.op_Equality(string, string)" + IL_000f: brtrue.s IL_002d + IL_0011: ldloc.1 + IL_0012: ldsfld "string .DB1DE4B3DA6C7871B776D5CB968AA5A4.s" + IL_0017: call "bool string.op_Equality(string, string)" + IL_001c: brtrue.s IL_0031 + IL_001e: ldloc.1 + IL_001f: ldsfld "string .BE20CA004CC2993A396345E0D52DF013.s" + IL_0024: call "bool string.op_Equality(string, string)" + IL_0029: brtrue.s IL_0035 + IL_002b: br.s IL_0039 + IL_002d: ldc.i4.1 + IL_002e: stloc.0 + IL_002f: br.s IL_003b + IL_0031: ldc.i4.2 + IL_0032: stloc.0 + IL_0033: br.s IL_003b + IL_0035: ldc.i4.3 + IL_0036: stloc.0 + IL_0037: br.s IL_003b + IL_0039: ldc.i4.4 + IL_003a: stloc.0 + IL_003b: ldloc.0 + IL_003c: call "void System.Console.Write(int)" + IL_0041: ret + } + """); + } + [Fact] public void DataSectionStringLiterals_InvalidUtf8() { diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs index 89860a042ddc7..60d7d2e5f08cf 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs @@ -83,7 +83,10 @@ class C compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream, EmitDifferenceOptions.Default, CancellationToken.None); - var actualIL = ImmutableArray.Create(ilStream.ToArray()).GetMethodIL(); + var il = ImmutableArray.Create(ilStream.ToArray()); + using var mdReaderProvider = MetadataReaderProvider.FromMetadataStream(mdStream); + + var actualIL = ILValidation.DumpEncDeltaMethodBodies(il, [mdReaderProvider.GetMetadataReader()]); var expectedIL = @" { // Code size 7 (0x7) @@ -155,7 +158,10 @@ class C compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream, EmitDifferenceOptions.Default, CancellationToken.None); - var actualIL = ImmutableArray.Create(ilStream.ToArray()).GetMethodIL(); + var il = ImmutableArray.Create(ilStream.ToArray()); + using var mdReaderProvider = MetadataReaderProvider.FromMetadataStream(mdStream); + + var actualIL = ILValidation.DumpEncDeltaMethodBodies(il, [mdReaderProvider.GetMetadataReader()]); // Symbol matcher should ignore overloads with missing type symbols and match // F(object). diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index f19f73a1940af..9656fa081d8b1 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -102,7 +102,8 @@ public C() Handle(4, TableIndex.CustomAttribute) }); - var expectedIL = """ + g.VerifyIL(""" + .ctor { // Code size 13 (0xd) .maxstack 8 @@ -111,6 +112,7 @@ .maxstack 8 IL_0007: newobj 0x06000003 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -123,10 +125,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -188,6 +187,7 @@ class C }); g.VerifyIL(""" + .ctor { // Code size 13 (0xd) .maxstack 8 @@ -196,6 +196,7 @@ .maxstack 8 IL_0007: newobj 0x06000003 IL_000c: throw } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -204,6 +205,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -2326,6 +2328,7 @@ void F() }); g.VerifyIL(""" + F { // Code size 30 (0x1e) .maxstack 8 @@ -2338,6 +2341,7 @@ .maxstack 8 IL_0018: stsfld 0x04000003 IL_001d: ret } + b__0_0 { // Code size 12 (0xc) .maxstack 8 @@ -2346,6 +2350,7 @@ .maxstack 8 IL_0006: newobj 0x06000007 IL_000b: throw } + b__0_1 { // Code size 8 (0x8) .maxstack 8 @@ -2354,6 +2359,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -2666,6 +2672,7 @@ partial void M() g.VerifyMethodDefNames("M", "b__0", ".ctor", ".ctor", "b__0#1"); g.VerifyIL(""" + M { // Code size 28 (0x1c) .maxstack 2 @@ -2681,6 +2688,7 @@ .maxstack 2 IL_001a: stloc.1 IL_001b: ret } + b__0 { // Code size 12 (0xc) .maxstack 8 @@ -2689,6 +2697,7 @@ .maxstack 8 IL_0006: newobj 0x06000005 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -2701,6 +2710,7 @@ .maxstack 8 IL_000a: stfld 0x04000002 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -2709,6 +2719,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#1 { // Code size 9 (0x9) .maxstack 8 @@ -3993,6 +4004,7 @@ class C }) .AddGeneration( + // 1 source: """ class C { @@ -4033,6 +4045,7 @@ class C }); g.VerifyIL(""" + get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -4041,6 +4054,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -4056,6 +4070,7 @@ .maxstack 8 """); }) .AddGeneration( + // 2 source: """ class C { @@ -4092,7 +4107,8 @@ class C Handle(4, TableIndex.MethodSemantics), }); - var expectedIL = """ + g.VerifyIL(""" + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4100,6 +4116,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -4108,10 +4125,7 @@ .maxstack 8 IL_0002: stfld 0x04000001 IL_0007: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -4135,6 +4149,7 @@ class C }) .AddGeneration( + // 1 source: """ class C { @@ -4177,6 +4192,7 @@ class C ]); g.VerifyIL(""" + get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -4185,6 +4201,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -4200,6 +4217,7 @@ .maxstack 8 """); }) .AddGeneration( + // 2 source: """ class C { @@ -4245,7 +4263,8 @@ class C Handle(4, TableIndex.MethodSemantics) ]); - var expectedIL = """ + g.VerifyIL(""" + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4253,6 +4272,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -4261,10 +4281,7 @@ .maxstack 8 IL_0002: stfld 0x04000002 IL_0007: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -4326,6 +4343,7 @@ class C }); g.VerifyIL(""" + get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -4334,6 +4352,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -4388,6 +4407,7 @@ class C }); g.VerifyIL(""" + get_P { // Code size 11 (0xb) .maxstack 1 @@ -4398,6 +4418,7 @@ .maxstack 1 IL_0009: ldloc.0 IL_000a: ret } + set_P { // Code size 2 (0x2) .maxstack 8 @@ -4462,6 +4483,7 @@ class C }); g.VerifyIL(""" + set_P { // Code size 13 (0xd) .maxstack 8 @@ -4470,6 +4492,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -4523,6 +4546,7 @@ class C }); g.VerifyIL(""" + get_P { // Code size 11 (0xb) .maxstack 1 @@ -4533,6 +4557,7 @@ .maxstack 1 IL_0009: ldloc.0 IL_000a: ret } + set_P { // Code size 2 (0x2) .maxstack 8 @@ -4883,7 +4908,8 @@ class C Handle(4, TableIndex.MethodSemantics) }); - var expectedIL = """ + g.VerifyIL(""" + get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -4892,6 +4918,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4899,6 +4926,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -4907,6 +4935,7 @@ .maxstack 8 IL_0002: stfld 0x04000002 IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -4919,10 +4948,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .AddGeneration( // 2 @@ -4974,6 +5000,7 @@ class C }); g.VerifyIL(""" + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4981,6 +5008,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -4989,6 +5017,7 @@ .maxstack 8 IL_0002: stfld 0x04000001 IL_0007: ret } + get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -5089,6 +5118,7 @@ class C }); g.VerifyIL(""" + get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -5097,6 +5127,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + get_Q { // Code size 7 (0x7) .maxstack 8 @@ -5104,6 +5135,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + set_Q { // Code size 8 (0x8) .maxstack 8 @@ -5112,6 +5144,7 @@ .maxstack 8 IL_0002: stfld 0x04000002 IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5176,6 +5209,7 @@ class C }); g.VerifyIL(""" + get_P { // Code size 7 (0x7) .maxstack 8 @@ -5183,6 +5217,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -5191,6 +5226,7 @@ .maxstack 8 IL_0002: stfld 0x04000001 IL_0007: ret } + get_Q, set_Q { // Code size 13 (0xd) .maxstack 8 @@ -5262,6 +5298,7 @@ class C }); g.VerifyIL(""" + get_Item, set_Item { // Code size 13 (0xd) .maxstack 8 @@ -5270,6 +5307,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5356,7 +5394,8 @@ class C }); g.VerifyIL(""" - { + get_Item + { // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 @@ -5364,6 +5403,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + get_Item { // Code size 7 (0x7) .maxstack 1 @@ -5374,6 +5414,7 @@ .maxstack 1 IL_0005: ldloc.0 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5428,6 +5469,7 @@ class C }); g.VerifyIL(""" + get_Item { // Code size 7 (0x7) .maxstack 1 @@ -5438,6 +5480,7 @@ .maxstack 1 IL_0005: ldloc.0 IL_0006: ret } + get_Item { // Code size 13 (0xd) .maxstack 8 @@ -5487,6 +5530,7 @@ class C }); g.VerifyIL(""" + get_Item { // Code size 7 (0x7) .maxstack 1 @@ -5555,12 +5599,14 @@ class C }); g.VerifyIL(""" + get_Item { // Code size 2 (0x2) .maxstack 8 IL_0000: ldc.i4.1 IL_0001: ret } + set_Item { // Code size 2 (0x2) .maxstack 8 @@ -5769,6 +5815,7 @@ class C }); g.VerifyIL(""" + add_E, remove_E { // Code size 13 (0xd) .maxstack 8 @@ -5777,6 +5824,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5885,6 +5933,7 @@ class C }); g.VerifyIL(""" + add_E, remove_E { // Code size 13 (0xd) .maxstack 8 @@ -5893,6 +5942,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + add_F { // Code size 41 (0x29) .maxstack 3 @@ -5917,6 +5967,7 @@ .maxstack 3 IL_0026: bne.un.s IL_0007 IL_0028: ret } + remove_F { // Code size 41 (0x29) .maxstack 3 @@ -5941,6 +5992,7 @@ .maxstack 3 IL_0026: bne.un.s IL_0007 IL_0028: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6008,6 +6060,7 @@ class C }); g.VerifyIL(""" + add_E { // Code size 41 (0x29) .maxstack 3 @@ -6032,6 +6085,7 @@ .maxstack 3 IL_0026: bne.un.s IL_0007 IL_0028: ret } + remove_E { // Code size 41 (0x29) .maxstack 3 @@ -6056,6 +6110,7 @@ .maxstack 3 IL_0026: bne.un.s IL_0007 IL_0028: ret } + add_F, remove_F { // Code size 13 (0xd) .maxstack 8 @@ -12192,7 +12247,8 @@ class C Handle(4, TableIndex.CustomAttribute) ]); - var expectedIL = """ + g.VerifyIL(""" + op_LogicalNot { // Code size 13 (0xd) .maxstack 8 @@ -12201,6 +12257,7 @@ .maxstack 8 IL_0007: newobj 0x06000003 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -12213,10 +12270,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -15996,6 +16050,7 @@ public void Records_AddPrimaryConstructorParameter() }); g.VerifyIL(""" + .ctor { // Code size 29 (0x1d) .maxstack 8 @@ -16013,6 +16068,7 @@ .maxstack 8 IL_001b: nop IL_001c: ret } + get_Q { // Code size 7 (0x7) .maxstack 8 @@ -16020,6 +16076,7 @@ .maxstack 8 IL_0001: ldfld 0x04000005 IL_0006: ret } + set_Q { // Code size 8 (0x8) .maxstack 8 @@ -16028,6 +16085,7 @@ .maxstack 8 IL_0002: stfld 0x04000005 IL_0007: ret } + Deconstruct { // Code size 25 (0x19) .maxstack 8 @@ -16114,6 +16172,7 @@ public void Records_AddProperty_NonPrimary() }); g.VerifyIL(""" + get_Q { // Code size 7 (0x7) .maxstack 8 @@ -16121,6 +16180,7 @@ .maxstack 8 IL_0001: ldfld 0x04000004 IL_0006: ret } + set_Q { // Code size 8 (0x8) .maxstack 8 @@ -16357,7 +16417,8 @@ class C g.VerifyTypeRefNames("Object"); g.VerifyIL(""" - { + F + { // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 @@ -16365,6 +16426,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -16423,6 +16485,7 @@ void F2() {} g.VerifyTypeRefNames("Object"); g.VerifyIL(""" + F1 { // Code size 13 (0xd) .maxstack 8 @@ -16451,6 +16514,7 @@ class C g.VerifyTypeRefNames("Object"); g.VerifyIL(""" + F2 { // Code size 13 (0xd) .maxstack 8 @@ -16506,6 +16570,7 @@ void F2() {} g.VerifyTypeRefNames("Exception", "Object"); g.VerifyIL(""" + F1 { // Code size 13 (0xd) .maxstack 8 @@ -16514,6 +16579,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 10 (0xa) .maxstack 8 @@ -16544,6 +16610,7 @@ class C g.VerifyTypeRefNames("Object"); g.VerifyIL(""" + F2 { // Code size 13 (0xd) .maxstack 8 @@ -16600,6 +16667,84 @@ void F2() {} .Verify(); } + [Fact] + public void Method_Delete_PredefinedHotReloadException_DataSectionLiterals() + { + var parseOptions = TestOptions.Regular.WithFeature("experimental-data-section-string-literals", "0"); + + var exceptionSource = """ + namespace System.Runtime.CompilerServices + { + public class HotReloadException : Exception + { + public HotReloadException(string message, int code) : base(message) {} + } + } + """; + + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, parseOptions: parseOptions) + .AddBaseline( + source: exceptionSource + """ + class C + { + void F1() {} + void F2() {} + } + """) + .AddGeneration( + // 1 + source: exceptionSource + """ + class C + { + void F2() {} + } + """, + edits: + [ + Edit(SemanticEditKind.Delete, symbolProvider: c => c.GetMember("C.F1"), newSymbolProvider: c => c.GetMember("C")), + ], + validator: g => + { + g.VerifySynthesizedMembers(); + g.VerifyTypeDefNames("#1", "__StaticArrayInitTypeSize=163", "A70F5C822D3106BF474269B4991AB592"); + g.VerifyTypeRefNames("Object", "CompilerGeneratedAttribute", "ValueType", "Encoding"); + + g.VerifyIL(""" + F1 + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldsfld 0x04000002 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000004 + IL_000c: throw + } + BytesToString + { + // Code size 13 (0xd) + .maxstack 8 + IL_0000: call 0x0A000008 + IL_0005: ldarg.0 + IL_0006: ldarg.1 + IL_0007: callvirt 0x0A000009 + IL_000c: ret + } + .cctor + { + // Code size 21 (0x15) + .maxstack 8 + IL_0000: ldsflda 0x04000001 + IL_0005: ldc.i4 0xa3 + IL_000a: call 0x06000005 + IL_000f: stsfld 0x04000002 + IL_0014: ret + } + """); + }, + options: new EmitDifferenceOptions() { EmitFieldRva = true }) + .Verify(); + } + [Theory] [InlineData("void M1() { }")] [InlineData("void M1(string s) { }")] @@ -16671,7 +16816,8 @@ class N Handle(4, TableIndex.CustomAttribute) ]); - var expectedIL = """ + g.VerifyIL(""" + M1 { // Code size 13 (0xd) .maxstack 8 @@ -16680,6 +16826,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -16692,10 +16839,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -16743,17 +16887,15 @@ void M2() { } Handle(3, TableIndex.MethodDef), }); - var expectedIL = """ + g.VerifyIL(""" + M2 { // Code size 2 (0x2) .maxstack 8 IL_0000: nop IL_0001: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .AddGeneration( @@ -16790,7 +16932,8 @@ void M1() { } Handle(4, TableIndex.CustomAttribute) }); - var expectedIL = """ + g.VerifyIL(""" + M2 { // Code size 13 (0xd) .maxstack 8 @@ -16799,6 +16942,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -16811,10 +16955,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -16869,7 +17010,8 @@ class C Handle(4, TableIndex.CustomAttribute) }); - var expectedIL = """ + g.VerifyIL(""" + M1 { // Code size 13 (0xd) .maxstack 8 @@ -16878,6 +17020,7 @@ .maxstack 8 IL_0007: newobj 0x06000003 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -16890,10 +17033,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .AddGeneration( @@ -16920,6 +17060,7 @@ class C }); g.VerifyIL(""" + M1 { // Code size 9 (0x9) .maxstack 8 @@ -16998,8 +17139,9 @@ class C new CustomAttributeRow(Handle(5, TableIndex.TypeDef), Handle(6, TableIndex.MemberRef)) ]); - var expectedIL = """ - { + g.VerifyIL(""" + M1 + { // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000005 @@ -17007,6 +17149,7 @@ .maxstack 8 IL_0007: newobj 0x06000005 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -17019,10 +17162,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .AddGeneration( @@ -17070,17 +17210,15 @@ void M1([B]int x) { } new CustomAttributeRow(Handle(3, TableIndex.MethodDef), Handle(2, TableIndex.MethodDef)) }); - var expectedIL = """ + g.VerifyIL(""" + M1 { // Code size 2 (0x2) .maxstack 8 IL_0000: nop IL_0001: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -17134,7 +17272,8 @@ void Goo() { } Handle(1, TableIndex.StandAloneSig) }); - var expectedIL = """ + g.VerifyIL(""" + M1 { // Code size 7 (0x7) .maxstack 1 @@ -17145,10 +17284,7 @@ .maxstack 1 IL_0005: ldloc.0 IL_0006: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .AddGeneration( @@ -17187,7 +17323,8 @@ void Goo() { } Handle(4, TableIndex.CustomAttribute) }); - var expectedIL = """ + g.VerifyIL(""" + M1 { // Code size 13 (0xd) .maxstack 8 @@ -17196,6 +17333,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -17208,10 +17346,7 @@ .maxstack 8 IL_000a: stfld 0x04000001 IL_000f: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) @@ -17244,7 +17379,8 @@ void Goo() { } Handle(2, TableIndex.StandAloneSig) }); - var expectedIL = """ + g.VerifyIL(""" + M1 { // Code size 14 (0xe) .maxstack 1 @@ -17258,10 +17394,7 @@ .maxstack 1 IL_000c: ldloc.0 IL_000d: ret } - """; - - // Can't verify the IL of individual methods because that requires IMethodSymbolInternal implementations - g.VerifyIL(expectedIL); + """); }) .Verify(); } @@ -17330,6 +17463,7 @@ class C }); g.VerifyIL(""" + F { // Code size 13 (0xd) .maxstack 8 @@ -17338,6 +17472,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + b__0_0 { // Code size 12 (0xc) .maxstack 8 @@ -17346,6 +17481,7 @@ .maxstack 8 IL_0006: newobj 0x06000006 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -17404,6 +17540,7 @@ class C }); g.VerifyIL(""" + F { // Code size 30 (0x1e) .maxstack 8 @@ -17416,6 +17553,7 @@ .maxstack 8 IL_0018: stsfld 0x04000004 IL_001d: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -17424,6 +17562,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#2_0#2 { // Code size 8 (0x8) .maxstack 8 @@ -17473,6 +17612,7 @@ class C }); g.VerifyIL(""" + F { // Code size 13 (0xd) .maxstack 8 @@ -17481,6 +17621,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + b__0#2_0#2 { // Code size 12 (0xc) .maxstack 8 @@ -17582,7 +17723,8 @@ class C }); g.VerifyIL(""" - { + F + { // Code size 13 (0xd) .maxstack 8 IL_0000: ldstr 0x70000009 @@ -17590,6 +17732,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + b__0#1_0#1 { // Code size 12 (0xc) .maxstack 8 @@ -17598,6 +17741,7 @@ .maxstack 8 IL_0006: newobj 0x06000006 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -17760,6 +17904,7 @@ class C }); g.VerifyIL(""" + F { // Code size 13 (0xd) .maxstack 8 @@ -17768,6 +17913,7 @@ .maxstack 8 IL_0007: newobj 0x0600000C IL_000c: throw } + b__0_0, b__0_1#1, b__0_2#2 { // Code size 12 (0xc) .maxstack 8 @@ -17776,6 +17922,7 @@ .maxstack 8 IL_0006: newobj 0x0600000C IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -17822,6 +17969,7 @@ void F<[A]S>([A]T a, S b) where S : struct g.VerifyMemberRefNames(".ctor", "<>9__0#4_0#4", "<>9", "b__0#4_0#4", ".ctor", ".ctor", "<>9", ".ctor", "WriteLine"); g.VerifyIL(""" + F { // Code size 30 (0x1e) .maxstack 8 @@ -17834,6 +17982,7 @@ .maxstack 8 IL_0018: stsfld 0x0A000026 IL_001d: ret } + .cctor { // Code size 11 (0xb) .maxstack 8 @@ -17841,6 +17990,7 @@ .maxstack 8 IL_0005: stsfld 0x0A00002B IL_000a: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -17849,6 +17999,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#4_0#4 { // Code size 8 (0x8) .maxstack 8 @@ -17902,6 +18053,7 @@ class C }); g.VerifyIL(""" + F { // Code size 13 (0xd) .maxstack 8 @@ -17910,6 +18062,7 @@ .maxstack 8 IL_0007: newobj 0x0600000C IL_000c: throw } + b__0#4_0#4 { // Code size 12 (0xc) .maxstack 8 @@ -18035,6 +18188,7 @@ class C }); g.VerifyIL(""" + F { // Code size 13 (0xd) .maxstack 8 @@ -18043,6 +18197,7 @@ .maxstack 8 IL_0007: newobj 0x06000009 IL_000c: throw } + g__L|0_0, g__M|0_1#1 { // Code size 12 (0xc) .maxstack 8 @@ -18051,6 +18206,7 @@ .maxstack 8 IL_0006: newobj 0x06000009 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -18102,6 +18258,7 @@ ref readonly T O(ref readonly T b) g.VerifyMemberRefNames(".ctor", ".ctor", "x", "g__O|0#3", ".ctor", "g__N|0#3_1#3"); g.VerifyIL(""" + F { // Code size 29 (0x1d) .maxstack 2 @@ -18119,12 +18276,14 @@ .maxstack 2 IL_001b: pop IL_001c: ret } + g__N|0#3_1#3 { // Code size 2 (0x2) .maxstack 8 IL_0000: ldarg.0 IL_0001: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -18133,6 +18292,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__O|0#3 { // Code size 9 (0x9) .maxstack 1 @@ -18145,6 +18305,7 @@ .maxstack 1 IL_0007: ldloc.0 IL_0008: ret } + b__2#3 { // Code size 12 (0xc) .maxstack 8 @@ -18193,6 +18354,7 @@ class C ]); g.VerifyIL(""" + F { // Code size 13 (0xd) .maxstack 8 @@ -18201,6 +18363,7 @@ .maxstack 8 IL_0007: newobj 0x06000009 IL_000c: throw } + g__N|0#3_1#3, g__O|0#3, b__2#3 { // Code size 12 (0xc) .maxstack 8 @@ -18340,6 +18503,7 @@ class C }); g.VerifyIL(""" + M { // Code size 13 (0xd) .maxstack 8 @@ -18348,6 +18512,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + M { // Code size 10 (0xa) .maxstack 8 @@ -18357,6 +18522,7 @@ .maxstack 8 IL_0008: pop IL_0009: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -18404,6 +18570,7 @@ class C }); g.VerifyIL(""" + M { // Code size 10 (0xa) .maxstack 8 @@ -18413,6 +18580,7 @@ .maxstack 8 IL_0008: pop IL_0009: ret } + M { // Code size 13 (0xd) .maxstack 8 @@ -18489,6 +18657,7 @@ class C }); g.VerifyIL(""" + M { // Code size 13 (0xd) .maxstack 8 @@ -18497,6 +18666,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + M { // Code size 7 (0x7) .maxstack 1 @@ -18507,6 +18677,7 @@ .maxstack 1 IL_0005: ldloc.0 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -18555,6 +18726,7 @@ class C }); g.VerifyIL(""" + M { // Code size 13 (0xd) .maxstack 1 @@ -18566,6 +18738,7 @@ .maxstack 1 IL_000b: ldloc.0 IL_000c: ret } + M { // Code size 13 (0xd) .maxstack 8 @@ -18643,6 +18816,7 @@ class C }); g.VerifyIL(""" + M { // Code size 13 (0xd) .maxstack 8 @@ -18651,6 +18825,7 @@ .maxstack 8 IL_0007: newobj 0x06000004 IL_000c: throw } + M { // Code size 10 (0xa) .maxstack 8 @@ -18660,6 +18835,7 @@ .maxstack 8 IL_0008: pop IL_0009: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -18706,6 +18882,7 @@ class C }); g.VerifyIL(""" + M { // Code size 10 (0xa) .maxstack 8 @@ -18715,6 +18892,7 @@ .maxstack 8 IL_0008: pop IL_0009: ret } + M { // Code size 13 (0xd) .maxstack 8 @@ -19316,9 +19494,10 @@ .maxstack 4 } """); - // TODO: better test would be to specify FieldDef -> data. // trailing zeros for alignment: - g.VerifyEncFieldRvaData([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0]); + g.VerifyEncFieldRvaData(""" + 78A6273103D17C39A0B6126E226CEC70E33337F4BC6A38067401B54A33E78EAD: 00-01-02-03-04-05-06-07-08-09-0A-00-00 + """); }, options: new EmitDifferenceOptions() { EmitFieldRva = true }) .Verify(); @@ -19515,8 +19694,10 @@ .locals init (System.ReadOnlySpan V_0, //b } """); - // TODO: better test would be to specify FieldDef -> data. - g.VerifyEncFieldRvaData([0, 1, 2, 3, 4, 5, 6, 7]); + // trailing zeros for alignment: + g.VerifyEncFieldRvaData(""" + 8A851FF82EE7048AD09EC3847F1DDF44944104D2CBD17EF4E3DB22C6785A0D45: 00-01-02-03-04-05-06-07 + """); }, options: new EmitDifferenceOptions() { EmitFieldRva = true }) .Verify(); @@ -19700,9 +19881,10 @@ .maxstack 2 } """); - // TODO: better test would be to specify FieldDef -> data. - // Trailing zeros for alignment. - g.VerifyEncFieldRvaData([.. Encoding.UTF8.GetBytes("0123456789X"), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); + // trailing zeros for alignment: + g.VerifyEncFieldRvaData($""" + AFB1C33C5229BFF7EF739BA44DA795A2B68A49E06001C07C5B026CAA6C6322BB: {BitConverter.ToString(Encoding.UTF8.GetBytes("0123456789X"))}-00-00-00-00-00-00-00 + """); }, options: new EmitDifferenceOptions() { EmitFieldRva = true }) .Verify(); @@ -19798,9 +19980,10 @@ .maxstack 1 } """); - // TODO: better test would be to specify FieldDef -> data. - // Trailing zero for alignment. - g.VerifyEncFieldRvaData([.. Encoding.UTF8.GetBytes("0123456789X"), 0x00]); + // trailing zeros for alignment: + g.VerifyEncFieldRvaData($""" + ACE59E7D984CCEB2D860A056A3386344236CE5C42C978E26ECE3F35956DAC3AD: {BitConverter.ToString(Encoding.UTF8.GetBytes("0123456789X"))}-00 + """); }, options: new EmitDifferenceOptions() { EmitFieldRva = true }) .Verify(); @@ -19958,9 +20141,10 @@ .maxstack 1 } """); - // TODO: better test would be to specify FieldDef -> data. - // Trailing zero for alignment. - g.VerifyEncFieldRvaData([.. Encoding.UTF8.GetBytes("0123456789"), 0x00, 0x00]); + // trailing zeros for alignment: + g.VerifyEncFieldRvaData($""" + 84D89877F0D4041EFB6BF91A16F0248F2FD573E6AF05C19F96BEDB9F882F7882: {BitConverter.ToString(Encoding.UTF8.GetBytes("0123456789"))}-00-00 + """); }, options: new EmitDifferenceOptions() { EmitFieldRva = true }) .Verify(); diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index 7401cd367443b..3c820cdd06a80 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -327,7 +327,7 @@ internal MappedField GetOrAddDataField(ImmutableArray data, ushort alignme internal static Cci.IFieldReference? TryGetOrCreateFieldForStringValue( string text, CommonPEModuleBuilder moduleBuilder, - SyntaxNode syntaxNode, + SyntaxNode? syntaxNode, DiagnosticBag diagnostics) { if (!text.TryGetUtf8ByteRepresentation(out byte[]? data, out _)) @@ -354,7 +354,7 @@ internal MappedField GetOrAddDataField(ImmutableArray data, ushort alignme var messageProvider = @this.ModuleBuilder.CommonCompilation.MessageProvider; diagnostics.Add(messageProvider.CreateDiagnostic( messageProvider.ERR_DataSectionStringLiteralHashCollision, - syntaxNode.GetLocation(), + syntaxNode?.GetLocation() ?? Location.None, previousText[..Math.Min(previousText.Length, 500)])); } diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index d8723ac2993ac..fc930e2123be1 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -3442,7 +3442,6 @@ internal static bool SerializePeToStream( internal EmitBaseline? SerializeToDeltaStreams( CommonPEModuleBuilder moduleBeingBuilt, DefinitionMap definitionMap, - SymbolChanges changes, Stream metadataStream, Stream ilStream, Stream pdbStream, @@ -3462,7 +3461,6 @@ internal static bool SerializePeToStream( using (nativePdbWriter) { var context = new EmitContext(moduleBeingBuilt, diagnostics, metadataOnly: false, includePrivateMembers: true); - var deletedMethodDefs = DeltaMetadataWriter.CreateDeletedMethodsDefs(context, changes); // Map the definitions from the previous compilation to the current compilation. // This must be done after compiling since synthesized definitions (generated when compiling method bodies) @@ -3480,8 +3478,6 @@ internal static bool SerializePeToStream( baseline, encId, definitionMap, - changes, - deletedMethodDefs, cancellationToken); moduleBeingBuilt.TestData?.SetMetadataWriter(writer); @@ -3517,7 +3513,7 @@ internal static bool SerializePeToStream( } finally { - foreach (var (_, builder) in deletedMethodDefs) + foreach (var (_, builder) in moduleBeingBuilt.GetDeletedMethodDefinitions()) { builder.Free(); } diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index c202123376ed6..fdc8bcdc6a622 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.IO; using System.Linq; @@ -44,6 +45,9 @@ internal abstract class CommonPEModuleBuilder : Cci.IUnit, Cci.IModuleReference private IEnumerable _embeddedTexts = SpecializedCollections.EmptyEnumerable(); private ArrayMethods? _lazyArrayMethods; + // Calculted when emitting EnC deltas. + private IReadOnlyDictionary>? _encDeletedMethodDefinitions; + // Only set when running tests to allow inspection of the emitted data. internal CompilationTestData? TestData { get; private set; } @@ -113,6 +117,27 @@ protected CommonPEModuleBuilder( /// public abstract INamedTypeSymbolInternal? GetUsedSynthesizedHotReloadExceptionType(); + /// + /// Creates definitions for deleted methods based on symbol changes if emitting EnC delta. + /// Must be called before . + /// + public void CreateDeletedMethodDefinitions(DiagnosticBag diagnosticBag) + { + Debug.Assert(_encDeletedMethodDefinitions == null); + + if (EncSymbolChanges != null) + { + var context = new EmitContext(this, diagnosticBag, metadataOnly: false, includePrivateMembers: true); + _encDeletedMethodDefinitions = DeltaMetadataWriter.CreateDeletedMethodsDefs(context, EncSymbolChanges); + } + } + + public IReadOnlyDictionary> GetDeletedMethodDefinitions() + { + Debug.Assert(_encDeletedMethodDefinitions != null); + return _encDeletedMethodDefinitions; + } + #nullable disable /// @@ -211,12 +236,12 @@ public ArrayMethods ArrayMethods /// /// /// - public Cci.IFieldReference? TryGetOrCreateFieldForStringValue(string text, SyntaxNode syntaxNode, DiagnosticBag diagnostics) + public Cci.IFieldReference? TryGetOrCreateFieldForStringValue(string text, SyntaxNode? syntaxNode, DiagnosticBag diagnostics) => PrivateImplementationDetails.TryGetOrCreateFieldForStringValue(text, this, syntaxNode, diagnostics); public abstract IEnumerable GetTopLevelTypeDefinitions(EmitContext context); - public IEnumerable GetTopLevelTypeDefinitionsCore(EmitContext context) + public IEnumerable GetTopLevelTypeDefinitionsExcludingNoPiaAndRootModule(EmitContext context, bool includePrivateImplementationDetails) { foreach (var typeDef in GetAnonymousTypeDefinitions(context)) { @@ -238,14 +263,17 @@ public ArrayMethods ArrayMethods yield return typeDef; } - var privateImpl = GetFrozenPrivateImplementationDetails(); - if (privateImpl != null) + if (includePrivateImplementationDetails) { - yield return privateImpl; - - foreach (var typeDef in privateImpl.GetAdditionalTopLevelTypes()) + var privateImpl = GetFrozenPrivateImplementationDetails(); + if (privateImpl != null) { - yield return typeDef; + yield return privateImpl; + + foreach (var typeDef in privateImpl.GetAdditionalTopLevelTypes()) + { + yield return typeDef; + } } } } @@ -720,7 +748,7 @@ protected bool ContainsTopLevelType(string fullEmittedName) VisitTopLevelType(typeReferenceIndexer, RootModuleType); yield return RootModuleType; - foreach (var typeDef in GetTopLevelTypeDefinitionsCore(context)) + foreach (var typeDef in GetTopLevelTypeDefinitionsExcludingNoPiaAndRootModule(context, includePrivateImplementationDetails: true)) { AddTopLevelType(names, typeDef); VisitTopLevelType(typeReferenceIndexer, typeDef); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index e054815742b86..96a218ede1dcf 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -26,7 +26,6 @@ internal sealed class DeltaMetadataWriter : MetadataWriter private readonly EmitBaseline _previousGeneration; private readonly Guid _encId; private readonly DefinitionMap _definitionMap; - private readonly SymbolChanges _changes; /// /// Type definitions containing any changes (includes added types). @@ -73,8 +72,6 @@ public DeltaMetadataWriter( EmitBaseline previousGeneration, Guid encId, DefinitionMap definitionMap, - SymbolChanges changes, - IReadOnlyDictionary> deletedMethodDefs, CancellationToken cancellationToken) : base(metadata: MakeTablesBuilder(previousGeneration), debugMetadataOpt: (context.Module.DebugInformationFormat == DebugInformationFormat.PortablePdb) ? new MetadataBuilder() : null, @@ -87,20 +84,20 @@ public DeltaMetadataWriter( cancellationToken: cancellationToken) { Debug.Assert(previousGeneration != null); - Debug.Assert(encId != default(Guid)); + Debug.Assert(encId != default); Debug.Assert(encId != previousGeneration.EncId); Debug.Assert(context.Module.DebugInformationFormat != DebugInformationFormat.Embedded); + Debug.Assert(context.Module.EncSymbolChanges != null); _previousGeneration = previousGeneration; _encId = encId; _definitionMap = definitionMap; - _changes = changes; var sizes = previousGeneration.TableSizes; _changedTypeDefs = new List(); _deletedTypeMembers = new Dictionary>(ReferenceEqualityComparer.Instance); - _deletedMethodDefs = deletedMethodDefs; + _deletedMethodDefs = context.Module.GetDeletedMethodDefinitions(); _typeDefs = new DefinitionIndex(this.TryGetExistingTypeDefIndex, sizes[(int)TableIndex.TypeDef]); _eventDefs = new DefinitionIndex(this.TryGetExistingEventDefIndex, sizes[(int)TableIndex.Event]); _fieldDefs = new DefinitionIndex(this.TryGetExistingFieldDefIndex, sizes[(int)TableIndex.Field]); @@ -130,6 +127,16 @@ public DeltaMetadataWriter( _addedOrChangedMethods = new Dictionary(Cci.SymbolEquivalentEqualityComparer.Instance); } + public SymbolChanges Changes + { + get + { + var changes = Context.Module.EncSymbolChanges; + Debug.Assert(changes != null); + return changes; + } + } + private static MetadataBuilder MakeTablesBuilder(EmitBaseline previousGeneration) { return new MetadataBuilder( @@ -200,7 +207,7 @@ internal EmitBaseline GetDelta(Compilation compilation, Guid encId, MetadataSize var generationOrdinals = CreateDictionary(_previousGeneration.GenerationOrdinals, SymbolEquivalentEqualityComparer.Instance); foreach (var (addedType, _) in addedTypes) { - if (_changes.IsReplacedDef(addedType)) + if (Changes.IsReplacedDef(addedType)) { generationOrdinals[addedType] = currentGenerationOrdinal; } @@ -500,7 +507,9 @@ internal static IReadOnlyDictionary>(ReferenceEqualityComparer.Instance); var typesUsedByDeletedMembers = new Dictionary(ReferenceEqualityComparer.Instance); - foreach (var typeDef in context.Module.GetTopLevelTypeDefinitions(context)) + // Skip PrivateImplementationDetails - we should only be adding new members to it. + // Emitting deleted method body may also produce new PrivateImplementationDetails members. + foreach (var typeDef in context.Module.GetTopLevelTypeDefinitionsExcludingNoPiaAndRootModule(context, includePrivateImplementationDetails: false)) { recurse(typeDef); } @@ -592,7 +601,7 @@ void addDeletedClosureMethods(IMethodSymbolInternal oldMethod, ImmutableArray GetContentToSign( }); } - public static unsafe string GetMethodIL(this ImmutableArray ilArray) + public static unsafe string DumpEncDeltaMethodBodies(ImmutableArray il, ImmutableArray readers) { + var reader = readers[^1]; + + var rvasAndNames = from handle in reader.MethodDefinitions + let method = reader.GetMethodDefinition(handle) + orderby method.RelativeVirtualAddress + group method.Name by method.RelativeVirtualAddress into g + // Legacy test support: name can only be resolved when readers for all generations are given. + select (g.Key, readers.Length > 1 ? string.Join(", ", g.Select(readers.GetString)) : null); + var result = new StringBuilder(); - fixed (byte* ilPtr = ilArray.ToArray()) + + fixed (byte* ilPtr = il.ToArray()) { - int offset = 0; - while (true) - { - // skip padding: - while (offset < ilArray.Length && ilArray[offset] == 0) - { - offset++; - } + var bodyReader = new BlobReader(ilPtr, il.Length); - if (offset == ilArray.Length) + foreach (var (rva, name) in rvasAndNames) + { + if (name != null) { - break; + result.AppendLine(name); } - var reader = new BlobReader(ilPtr + offset, ilArray.Length - offset); - var methodIL = MethodBodyBlock.Create(reader); + bodyReader.Offset = rva; - if (methodIL == null) + MethodBodyBlock body; + try { - result.AppendFormat("", ilArray[offset], offset); - offset++; + body = MethodBodyBlock.Create(bodyReader); } - else + catch (BadImageFormatException) { - ILVisualizer.Default.DumpMethod( - result, - methodIL.MaxStack, - methodIL.GetILContent(), - ImmutableArray.Create(), - ImmutableArray.Create()); - - offset += methodIL.Size; + result.AppendFormat("", il[rva], rva); + continue; } + + ILVisualizer.Default.DumpMethod( + result, + body.MaxStack, + body.GetILContent(), + locals: [], + exceptionHandlers: []); } } return result.ToString(); } + public static unsafe string DumpEncDeltaFieldData(ImmutableArray il, ImmutableArray readers) + { + var reader = readers[^1]; + var aggregator = new MetadataAggregator(readers[0], readers[1..]); + + var fieldRvaTablePtr = reader.MetadataPointer + reader.GetTableMetadataOffset(TableIndex.FieldRva); + var rowCount = reader.GetTableRowCount(TableIndex.FieldRva); + var rowSize = reader.GetTableRowSize(TableIndex.FieldRva); + var tableReader = new BlobReader(fieldRvaTablePtr, rowCount * rowSize); + + var rvasAndNames = new List<(int rva, string name)>(); + for (var i = 0; i < rowCount; i++) + { + var rva = tableReader.ReadInt32(); + + // RowIds are 4 bytes in EnC deltas + var fieldRowId = tableReader.ReadInt32(); + + if (rva > 0) + { + var fieldHandle = MetadataTokens.FieldDefinitionHandle(fieldRowId); + var genFieldHandle = (FieldDefinitionHandle)aggregator.GetGenerationHandle(fieldHandle, out var fieldGen); + var fieldDef = readers[fieldGen].GetFieldDefinition(genFieldHandle); + var genNameHandle = (StringHandle)aggregator.GetGenerationHandle(fieldDef.Name, out var nameGen); + var fieldName = readers[nameGen].GetString(genNameHandle); + + rvasAndNames.Add((rva, fieldName)); + } + } + + var result = new StringBuilder(); + + for (var i = 0; i < rvasAndNames.Count; i++) + { + var (startRva, name) = rvasAndNames[i]; + var endRva = i + 1 < rvasAndNames.Count ? rvasAndNames[i + 1].rva : il.Length; + + result.AppendLine($"{name}: {BitConverter.ToString(il[startRva..endRva].ToArray())}"); + } + + return result.ToString(); + } + public static unsafe MethodBodyBlock GetMethodBodyBlock(this ImmutableArray ilArray) { fixed (byte* ilPtr = ilArray.AsSpan()) diff --git a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb index ddb0a586cbc64..6759c1b62a613 100644 --- a/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb +++ b/src/Compilers/VisualBasic/Portable/Compilation/MethodCompiler.vb @@ -269,6 +269,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic compiler.ProcessEmbeddedMethods() End If + ' Deleted definitions must be emitted before PrivateImplementationDetails are frozen since + ' it may add new members to it. All changes to PrivateImplementationDetails are additions, + ' so we don't need to create deleted method defs for those. + moduleBeingBuiltOpt.CreateDeletedMethodDefinitions(diagnostics.DiagnosticBag) + ' all threads that were adding methods must be finished now, we can freeze the class: Dim privateImplClass = moduleBeingBuiltOpt.FreezePrivateImplementationDetails() If privateImplClass IsNot Nothing Then diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb index 5e6363a8d1a72..c8447c764146e 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/EmitHelpers.vb @@ -120,7 +120,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit newBaseline = compilation.SerializeToDeltaStreams( moduleBeingBuilt, definitionMap, - changes, metadataStream, ilStream, pdbStream, diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb index 9c48546f62ffd..88ad55df98eed 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb @@ -260,7 +260,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Function Public Overrides Function GetTopLevelTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition) - Return GetTopLevelTypeDefinitionsCore(context) + Return GetTopLevelTypeDefinitionsExcludingNoPiaAndRootModule(context, includePrivateImplementationDetails:=True) End Function Public Overrides Function GetTopLevelSourceTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition) diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb index c828331b82cff..8193d204d35d7 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTests.vb @@ -1475,6 +1475,7 @@ End Class }) g.VerifyIL(" +add_E, remove_E, raise_E { // Code size 13 (0xd) .maxstack 8 @@ -1483,6 +1484,7 @@ End Class IL_0007: newobj 0x06000005 IL_000c: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -1537,6 +1539,7 @@ End Class }) g.VerifyIL(" +add_E { // Code size 10 (0xa) .maxstack 8 @@ -1546,6 +1549,7 @@ End Class IL_0008: nop IL_0009: ret } +remove_E { // Code size 10 (0xa) .maxstack 8 @@ -1555,6 +1559,7 @@ End Class IL_0008: nop IL_0009: ret } +raise_E { // Code size 10 (0xa) .maxstack 8 @@ -1649,6 +1654,7 @@ End Class }) g.VerifyIL(" +add_E, remove_E { // Code size 13 (0xd) .maxstack 8 @@ -1657,6 +1663,7 @@ End Class IL_0007: newobj 0x06000007 IL_000c: throw } +add_E { // Code size 10 (0xa) .maxstack 8 @@ -1666,6 +1673,7 @@ End Class IL_0008: nop IL_0009: ret } +remove_E { // Code size 10 (0xa) .maxstack 8 @@ -1675,6 +1683,7 @@ End Class IL_0008: nop IL_0009: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -1736,6 +1745,7 @@ End Class }) g.VerifyIL(" +add_E { // Code size 10 (0xa) .maxstack 8 @@ -1745,6 +1755,7 @@ End Class IL_0008: nop IL_0009: ret } +remove_E { // Code size 13 (0xd) .maxstack 8 @@ -1754,6 +1765,7 @@ End Class IL_000b: nop IL_000c: ret } +add_E, remove_E { // Code size 13 (0xd) .maxstack 8 @@ -2337,6 +2349,7 @@ End Class }) g.VerifyIL(" +get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -2345,6 +2358,7 @@ End Class IL_0007: newobj 0x06000006 IL_000c: throw } +get_P { // Code size 15 (0xf) .maxstack 1 @@ -2358,6 +2372,7 @@ End Class IL_000d: ldloc.0 IL_000e: ret } +set_P { // Code size 10 (0xa) .maxstack 8 @@ -2367,6 +2382,7 @@ End Class IL_0008: nop IL_0009: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2429,6 +2445,7 @@ End Class }) g.VerifyIL(" +get_P { // Code size 15 (0xf) .maxstack 1 @@ -2442,6 +2459,7 @@ End Class IL_000d: ldloc.0 IL_000e: ret } +set_P { // Code size 13 (0xd) .maxstack 8 @@ -2451,6 +2469,7 @@ End Class IL_000b: nop IL_000c: ret } +get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -2522,6 +2541,7 @@ End Class }) g.VerifyIL(" +get_P, set_P { // Code size 13 (0xd) .maxstack 8 @@ -2530,6 +2550,7 @@ End Class IL_0007: newobj 0x06000004 IL_000c: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2576,6 +2597,7 @@ End Class }) g.VerifyIL(" +get_P { // Code size 7 (0x7) .maxstack 1 @@ -2649,6 +2671,7 @@ End Class }) g.VerifyIL(" +get_P { // Code size 13 (0xd) .maxstack 8 @@ -2657,6 +2680,7 @@ End Class IL_0007: newobj 0x06000004 IL_000c: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2703,6 +2727,7 @@ End Class }) g.VerifyIL(" +get_P { // Code size 7 (0x7) .maxstack 1 @@ -5980,6 +6005,7 @@ End Class }) g.VerifyIL(" +F { // Code size 39 (0x27) .maxstack 2 @@ -5996,6 +6022,7 @@ End Class IL_0025: stloc.2 IL_0026: ret } +_Lambda$__1-0 { // Code size 12 (0xc) .maxstack 8 @@ -6004,6 +6031,7 @@ End Class IL_0006: newobj 0x06000007 IL_000b: throw } +_Lambda$__1-1 { // Code size 9 (0x9) .maxstack 8 @@ -6013,6 +6041,7 @@ End Class IL_0007: nop IL_0008: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -6086,33 +6115,36 @@ End Class }) g.VerifyIL(" +F { - // Code size 13 (0xd) - .maxstack 8 - IL_0000: ldstr 0x70000005 - IL_0005: ldc.i4.s -2 - IL_0007: newobj 0x06000006 - IL_000c: throw - } - { - // Code size 12 (0xc) - .maxstack 8 - IL_0000: ldstr 0x7000014E - IL_0005: ldc.i4.m1 - IL_0006: newobj 0x06000006 - IL_000b: throw - } - { - // Code size 15 (0xf) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldarg.1 - IL_0002: call 0x0A000008 - IL_0007: ldarg.0 - IL_0008: ldarg.2 - IL_0009: stfld 0x04000003 - IL_000e: ret - } + // Code size 13 (0xd) + .maxstack 8 + IL_0000: ldstr 0x70000005 + IL_0005: ldc.i4.s -2 + IL_0007: newobj 0x06000006 + IL_000c: throw +} +_Lambda$__1-0 +{ + // Code size 12 (0xc) + .maxstack 8 + IL_0000: ldstr 0x7000014E + IL_0005: ldc.i4.m1 + IL_0006: newobj 0x06000006 + IL_000b: throw +} +.ctor +{ + // Code size 15 (0xf) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldarg.1 + IL_0002: call 0x0A000008 + IL_0007: ldarg.0 + IL_0008: ldarg.2 + IL_0009: stfld 0x04000003 + IL_000e: ret +} ") End Sub). AddGeneration(' 2 @@ -6160,6 +6192,7 @@ End Class }) g.VerifyIL(" +F { // Code size 39 (0x27) .maxstack 2 @@ -6176,6 +6209,7 @@ End Class IL_0025: stloc.0 IL_0026: ret } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -6183,6 +6217,7 @@ End Class IL_0001: call 0x0A00000B IL_0006: ret } +_Lambda$__1#2-0#2 { // Code size 9 (0x9) .maxstack 8 @@ -6233,6 +6268,7 @@ End Class }) g.VerifyIL(" +F { // Code size 13 (0xd) .maxstack 8 @@ -6241,6 +6277,7 @@ End Class IL_0007: newobj 0x06000006 IL_000c: throw } +_Lambda$__1#2-0#2 { // Code size 12 (0xc) .maxstack 8 @@ -6336,6 +6373,7 @@ End Class }) g.VerifyIL(" +F { // Code size 13 (0xd) .maxstack 8 @@ -6344,6 +6382,7 @@ End Class IL_0007: newobj 0x06000006 IL_000c: throw } +_Lambda$__1#1-0#1 { // Code size 12 (0xc) .maxstack 8 @@ -6352,6 +6391,7 @@ End Class IL_0006: newobj 0x06000006 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -6478,6 +6518,7 @@ End Class }) g.VerifyIL(" +F { // Code size 13 (0xd) .maxstack 8 @@ -6486,6 +6527,7 @@ End Class IL_0007: newobj 0x06000009 IL_000c: throw } +_Lambda$__1-0, _Lambda$__1-1#1, _Lambda$__1-2#2 { // Code size 12 (0xc) .maxstack 8 @@ -6494,6 +6536,7 @@ End Class IL_0006: newobj 0x06000009 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -6534,6 +6577,7 @@ End Class g.VerifyMemberRefNames(".ctor", "$I1#4-0#4", "$I", "_Lambda$__1#4-0#4", ".ctor", ".ctor", ".ctor", "$I", "WriteLine") g.VerifyIL(" +F { // Code size 50 (0x32) .maxstack 2 @@ -6554,6 +6598,7 @@ End Class IL_0030: ldloc.0 IL_0031: ret } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -6561,6 +6606,7 @@ End Class IL_0001: call 0x0A000029 IL_0006: ret } +.cctor { // Code size 11 (0xb) .maxstack 8 @@ -6568,6 +6614,7 @@ End Class IL_0005: stsfld 0x0A00002B IL_000a: ret } +_Lambda$__1#4-0#4 { // Code size 9 (0x9) .maxstack 8 @@ -6617,6 +6664,7 @@ End Class }) g.VerifyIL(" +F { // Code size 13 (0xd) .maxstack 8 @@ -6625,6 +6673,7 @@ End Class IL_0007: newobj 0x06000009 IL_000c: throw } +_Lambda$__1#4-0#4 { // Code size 12 (0xc) .maxstack 8 @@ -7319,6 +7368,7 @@ End Class", v.VerifyTypeRefNames("Object") v.VerifyIL(" +M { // Code size 13 (0xd) .maxstack 8 @@ -7371,6 +7421,7 @@ End Class", v.VerifyTypeRefNames("Exception", "Object") v.VerifyIL(" +M { // Code size 13 (0xd) .maxstack 8 @@ -7379,6 +7430,7 @@ End Class", IL_0007: newobj 0x06000003 IL_000c: throw } +.ctor { // Code size 10 (0xa) .maxstack 8 diff --git a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs index f413c28add4fa..63be4ad35bae0 100644 --- a/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs +++ b/src/Test/PdbUtilities/EditAndContinue/EditAndContinueTest.GenerationVerifier.cs @@ -181,11 +181,22 @@ internal void VerifyPdb(string qualifiedMemberName, string expectedPdb, PdbValid internal void VerifyCustomDebugInformation(string qualifiedMemberName, string expectedPdb) => VerifyPdb(qualifiedMemberName, expectedPdb, PdbValidationOptions.ExcludeDocuments | PdbValidationOptions.ExcludeSequencePoints | PdbValidationOptions.ExcludeScopes); - internal void VerifyIL(string expectedIL) + internal void VerifyEncFieldRvaData(string expected) => Verify(() => { Debug.Assert(generationInfo.CompilationDifference != null); - generationInfo.CompilationDifference.VerifyIL(expectedIL); + + var actual = ILValidation.DumpEncDeltaFieldData(generationInfo.CompilationDifference.ILDelta, readers); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, actual, escapeQuotes: false); + }); + + internal void VerifyIL(string expected) + => Verify(() => + { + Debug.Assert(generationInfo.CompilationDifference != null); + + var actual = ILValidation.DumpEncDeltaMethodBodies(generationInfo.CompilationDifference.ILDelta, readers); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expected, actual, escapeQuotes: false); }); internal void VerifyIL(string qualifiedMemberName, string expectedIL) @@ -202,13 +213,6 @@ internal void VerifyIL(string qualifiedMemberName, string expectedIL) } }); - internal void VerifyEncFieldRvaData(byte[] expected) - => Verify(() => - { - Debug.Assert(generationInfo.CompilationDifference != null); - AssertEx.SequenceEqual(expected, generationInfo.CompilationDifference.ILDelta[^expected.Length..]); - }); - public void VerifyLocalSignature(string qualifiedMethodName, string expectedSignature) => Verify(() => { From bd5b0352daa4085ac5e96e4909743042fe825163 Mon Sep 17 00:00:00 2001 From: tmat Date: Thu, 17 Apr 2025 16:02:33 -0700 Subject: [PATCH 18/21] Fixes --- .../AssemblyReferencesTests.cs | 2 + .../EditAndContinueClosureTests.cs | 197 +++++++++++++++++- .../EditAndContinue/EditAndContinueTests.cs | 6 + .../Core/Portable/CodeGen/ILBuilder.cs | 1 + .../Core/Portable/CodeGen/ILBuilderEmit.cs | 2 +- .../Core/Portable/CodeGen/StringTokenMap.cs | 1 - .../Core/Portable/Compilation/Compilation.cs | 1 - .../Test/Core/Metadata/ILBuilderVisualizer.cs | 7 +- .../Test/Utilities/CSharp/CSharpTestBase.cs | 2 + .../VisualBasic/Portable/Errors/ErrorFacts.vb | 1 + .../VisualBasic/Portable/VBResources.resx | 3 + .../Portable/xlf/VBResources.cs.xlf | 5 + .../Portable/xlf/VBResources.de.xlf | 5 + .../Portable/xlf/VBResources.es.xlf | 5 + .../Portable/xlf/VBResources.fr.xlf | 5 + .../Portable/xlf/VBResources.it.xlf | 5 + .../Portable/xlf/VBResources.ja.xlf | 5 + .../Portable/xlf/VBResources.ko.xlf | 5 + .../Portable/xlf/VBResources.pl.xlf | 5 + .../Portable/xlf/VBResources.pt-BR.xlf | 5 + .../Portable/xlf/VBResources.ru.xlf | 5 + .../Portable/xlf/VBResources.tr.xlf | 5 + .../Portable/xlf/VBResources.zh-Hans.xlf | 5 + .../Portable/xlf/VBResources.zh-Hant.xlf | 5 + .../EditAndContinueClosureTests.vb | 76 ++++++- .../Test/Emit/Emit/EmitErrorTests.vb | 11 +- 26 files changed, 365 insertions(+), 10 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs index 60d7d2e5f08cf..f1cd2f3208240 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/AssemblyReferencesTests.cs @@ -84,6 +84,7 @@ class C compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream, EmitDifferenceOptions.Default, CancellationToken.None); var il = ImmutableArray.Create(ilStream.ToArray()); + mdStream.Position = 0; using var mdReaderProvider = MetadataReaderProvider.FromMetadataStream(mdStream); var actualIL = ILValidation.DumpEncDeltaMethodBodies(il, [mdReaderProvider.GetMetadataReader()]); @@ -159,6 +160,7 @@ class C compilation1.EmitDifference(baseline, edits, s => false, mdStream, ilStream, pdbStream, EmitDifferenceOptions.Default, CancellationToken.None); var il = ImmutableArray.Create(ilStream.ToArray()); + mdStream.Position = 0; using var mdReaderProvider = MetadataReaderProvider.FromMetadataStream(mdStream); var actualIL = ILValidation.DumpEncDeltaMethodBodies(il, [mdReaderProvider.GetMetadataReader()]); diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs index 4f4d3c84cdba9..4b5b85deef2b2 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueClosureTests.cs @@ -4846,6 +4846,7 @@ public void F() g.VerifyIL( """ + F { // Code size 44 (0x2c) .maxstack 2 @@ -4864,6 +4865,7 @@ .maxstack 2 IL_0026: stsfld 0x04000003 IL_002b: ret } + b__0_0 { // Code size 13 (0xd) .maxstack 8 @@ -4872,6 +4874,7 @@ .maxstack 8 IL_0007: newobj 0x06000007 IL_000c: throw } + b__0_1 { // Code size 8 (0x8) .maxstack 8 @@ -4880,6 +4883,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -4892,6 +4896,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -4900,6 +4905,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#1 { // Code size 13 (0xd) .maxstack 8 @@ -4986,6 +4992,7 @@ public void F() g.VerifyIL( """ + F { // Code size 12 (0xc) .maxstack 2 @@ -4997,6 +5004,7 @@ .maxstack 2 IL_000a: nop IL_000b: ret } + g__L1|0_0 { // Code size 13 (0xd) .maxstack 8 @@ -5005,6 +5013,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + g__L2|0_1 { // Code size 8 (0x8) .maxstack 8 @@ -5013,6 +5022,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L1|0_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -5022,6 +5032,7 @@ .maxstack 8 IL_000b: nop IL_000c: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5089,6 +5100,7 @@ public void F(int x) g.VerifyIL( """ + F { // Code size 44 (0x2c) .maxstack 2 @@ -5107,6 +5119,7 @@ .maxstack 2 IL_0026: stsfld 0x04000003 IL_002b: ret } + b__0_0 { // Code size 13 (0xd) .maxstack 8 @@ -5115,6 +5128,7 @@ .maxstack 8 IL_0007: newobj 0x06000007 IL_000c: throw } + b__0_1 { // Code size 8 (0x8) .maxstack 8 @@ -5123,6 +5137,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5135,6 +5150,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -5143,6 +5159,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#1 { // Code size 13 (0xd) .maxstack 8 @@ -5226,6 +5243,7 @@ public void F(int x) g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L1|0_0#1", ".ctor"); g.VerifyIL(""" + F { // Code size 12 (0xc) .maxstack 2 @@ -5237,6 +5255,7 @@ .maxstack 2 IL_000a: nop IL_000b: ret } + g__L1|0_0 { // Code size 13 (0xd) .maxstack 8 @@ -5245,6 +5264,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + g__L2|0_1 { // Code size 8 (0x8) .maxstack 8 @@ -5253,6 +5273,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L1|0_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -5262,6 +5283,7 @@ .maxstack 8 IL_000b: nop IL_000c: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5331,6 +5353,7 @@ static void F() g.VerifyIL( """ + F { // Code size 34 (0x22) .maxstack 2 @@ -5347,6 +5370,7 @@ .maxstack 2 IL_0020: stloc.0 IL_0021: ret } + b__1_0 { // Code size 31 (0x1f) .maxstack 2 @@ -5361,6 +5385,7 @@ .maxstack 2 IL_0019: call 0x06000001 IL_001e: ret } + b__1_1 { // Code size 12 (0xc) .maxstack 8 @@ -5369,6 +5394,7 @@ .maxstack 8 IL_0006: newobj 0x06000008 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5381,6 +5407,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -5389,6 +5416,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__1#1 { // Code size 7 (0x7) .maxstack 8 @@ -5453,6 +5481,7 @@ class C : B g.VerifyIL( """ + .ctor { // Code size 42 (0x2a) .maxstack 3 @@ -5474,6 +5503,7 @@ .maxstack 3 IL_0028: nop IL_0029: ret } + <.ctor>b__0_0 { // Code size 13 (0xd) .maxstack 8 @@ -5482,6 +5512,7 @@ .maxstack 8 IL_0007: newobj 0x06000007 IL_000c: throw } + <.ctor>b__0_1 { // Code size 12 (0xc) .maxstack 8 @@ -5490,6 +5521,7 @@ .maxstack 8 IL_0006: newobj 0x06000007 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5502,6 +5534,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -5510,6 +5543,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + <.ctor>b__0#1 { // Code size 7 (0x7) .maxstack 8 @@ -5517,6 +5551,7 @@ .maxstack 8 IL_0001: ldfld 0x04000005 IL_0006: ret } + <.ctor>b__1#1 { // Code size 13 (0xd) .maxstack 8 @@ -5569,6 +5604,7 @@ class B(Func f); g.VerifyIL( """ + .ctor { // Code size 33 (0x21) .maxstack 3 @@ -5585,6 +5621,7 @@ .maxstack 3 IL_001f: nop IL_0020: ret } + <.ctor>b__0_0 { // Code size 13 (0xd) .maxstack 8 @@ -5593,6 +5630,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5605,6 +5643,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -5613,6 +5652,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + <.ctor>b__0#1 { // Code size 7 (0x7) .maxstack 8 @@ -5663,6 +5703,7 @@ public void Capture_TopLevelArgs() g.VerifyIL( """ +
$ { // Code size 27 (0x1b) .maxstack 2 @@ -5677,6 +5718,7 @@ .maxstack 2 IL_0019: stloc.2 IL_001a: ret } + <
$>b__0_0 { // Code size 13 (0xd) .maxstack 8 @@ -5685,6 +5727,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5697,6 +5740,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -5705,6 +5749,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + <
$>b__0#1 { // Code size 7 (0x7) .maxstack 8 @@ -5793,6 +5838,7 @@ public void F() g.VerifyIL( """ + F { // Code size 31 (0x1f) .maxstack 8 @@ -5806,6 +5852,7 @@ .maxstack 8 IL_0019: stsfld 0x04000004 IL_001e: ret } + b__1_0 { // Code size 13 (0xd) .maxstack 8 @@ -5814,6 +5861,7 @@ .maxstack 8 IL_0007: newobj 0x06000008 IL_000c: throw } + b__1_1 { // Code size 8 (0x8) .maxstack 8 @@ -5822,6 +5870,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__1_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -5831,6 +5880,7 @@ .maxstack 8 IL_000b: nop IL_000c: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -5922,6 +5972,7 @@ public void F() g.VerifyIL( """ + F { // Code size 4 (0x4) .maxstack 8 @@ -5930,6 +5981,7 @@ .maxstack 8 IL_0002: nop IL_0003: ret } + g__L1|1_0 { // Code size 13 (0xd) .maxstack 8 @@ -5938,6 +5990,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + g__L2|1_1 { // Code size 8 (0x8) .maxstack 8 @@ -5946,6 +5999,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L1|1_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -5955,6 +6009,7 @@ .maxstack 8 IL_000b: nop IL_000c: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6021,6 +6076,7 @@ public void F() g.VerifyIL( """ + F { // Code size 31 (0x1f) .maxstack 8 @@ -6034,6 +6090,7 @@ .maxstack 8 IL_0019: stsfld 0x04000003 IL_001e: ret } + b__1_0 { // Code size 13 (0xd) .maxstack 8 @@ -6042,6 +6099,7 @@ .maxstack 8 IL_0007: newobj 0x06000008 IL_000c: throw } + b__1_1 { // Code size 8 (0x8) .maxstack 8 @@ -6050,6 +6108,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__1_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -6059,6 +6118,7 @@ .maxstack 8 IL_000b: nop IL_000c: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6122,6 +6182,7 @@ public void F() g.VerifyIL( """ + F { // Code size 4 (0x4) .maxstack 8 @@ -6130,6 +6191,7 @@ .maxstack 8 IL_0002: nop IL_0003: ret } + g__L1|1_0 { // Code size 13 (0xd) .maxstack 8 @@ -6138,6 +6200,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + g__L2|1_1 { // Code size 8 (0x8) .maxstack 8 @@ -6146,6 +6209,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L1|1_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -6155,6 +6219,7 @@ .maxstack 8 IL_000b: nop IL_000c: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6257,6 +6322,7 @@ public void F() g.VerifyIL( """ + F { // Code size 35 (0x23) .maxstack 2 @@ -6275,6 +6341,7 @@ .maxstack 2 IL_0021: nop IL_0022: ret } + b__0 { // Code size 7 (0x7) .maxstack 8 @@ -6356,6 +6423,7 @@ public void F() g.VerifyIL( """ + F { // Code size 13 (0xd) .maxstack 2 @@ -6368,6 +6436,7 @@ .maxstack 2 IL_000b: nop IL_000c: ret } + g__L|0_0 { // Code size 7 (0x7) .maxstack 8 @@ -6427,6 +6496,7 @@ public void F() g.VerifyIL( """ + F { // Code size 32 (0x20) .maxstack 2 @@ -6441,6 +6511,7 @@ .maxstack 2 IL_001a: stsfld 0x04000004 IL_001f: ret } + b__0 { // Code size 13 (0xd) .maxstack 8 @@ -6449,6 +6520,7 @@ .maxstack 8 IL_0007: newobj 0x06000005 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6461,6 +6533,7 @@ .maxstack 8 IL_000a: stfld 0x04000002 IL_000f: ret } + .cctor { // Code size 11 (0xb) .maxstack 8 @@ -6468,6 +6541,7 @@ .maxstack 8 IL_0005: stsfld 0x04000003 IL_000a: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -6476,6 +6550,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0_0#1 { // Code size 8 (0x8) .maxstack 8 @@ -6518,6 +6593,7 @@ public void F() g.VerifyIL( """ + F { // Code size 16 (0x10) .maxstack 2 @@ -6530,6 +6606,7 @@ .maxstack 2 IL_000e: nop IL_000f: ret } + b__0_0#1 { // Code size 12 (0xc) .maxstack 8 @@ -6538,6 +6615,7 @@ .maxstack 8 IL_0006: newobj 0x06000005 IL_000b: throw } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -6546,6 +6624,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#2 { // Code size 15 (0xf) .maxstack 8 @@ -6643,6 +6722,7 @@ public void F() g.VerifyIL( """ + F { // Code size 14 (0xe) .maxstack 1 @@ -6661,6 +6741,7 @@ .maxstack 1 IL_000c: nop IL_000d: ret } + g__L|0_0 { // Code size 13 (0xd) .maxstack 8 @@ -6669,6 +6750,7 @@ .maxstack 8 IL_0007: newobj 0x06000007 IL_000c: throw } + g__L|0_1 { // Code size 12 (0xc) .maxstack 8 @@ -6677,6 +6759,7 @@ .maxstack 8 IL_0006: newobj 0x06000007 IL_000b: throw } + g__L|0_0#1 { // Code size 8 (0x8) .maxstack 8 @@ -6685,6 +6768,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L|0_1#1 { // Code size 8 (0x8) .maxstack 8 @@ -6693,6 +6777,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6807,6 +6892,7 @@ public void F() g.VerifyIL( """ + F { // Code size 58 (0x3a) .maxstack 8 @@ -6825,6 +6911,7 @@ .maxstack 8 IL_0034: stsfld 0x04000003 IL_0039: ret } + b__1_0 { // Code size 13 (0xd) .maxstack 8 @@ -6833,6 +6920,7 @@ .maxstack 8 IL_0007: newobj 0x06000007 IL_000c: throw } + b__1_1 { // Code size 8 (0x8) .maxstack 8 @@ -6841,6 +6929,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -6853,6 +6942,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + b__1_0#1 { // Code size 8 (0x8) .maxstack 8 @@ -6959,6 +7049,7 @@ public void F() g.VerifyIL( """ + F { // Code size 4 (0x4) .maxstack 8 @@ -6967,6 +7058,7 @@ .maxstack 8 IL_0002: nop IL_0003: ret } + g__L1|1_0 { // Code size 13 (0xd) .maxstack 8 @@ -6975,6 +7067,7 @@ .maxstack 8 IL_0007: newobj 0x06000006 IL_000c: throw } + g__L2|1_1 { // Code size 8 (0x8) .maxstack 8 @@ -6983,6 +7076,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L1|1_0#1 { // Code size 8 (0x8) .maxstack 8 @@ -6991,6 +7085,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -7056,6 +7151,7 @@ public void F() g.VerifyIL( """ + F { // Code size 16 (0x10) .maxstack 2 @@ -7068,6 +7164,7 @@ .maxstack 2 IL_000e: nop IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -7076,6 +7173,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__0#1 { // Code size 13 (0xd) .maxstack 8 @@ -7116,6 +7214,7 @@ public void F() g.VerifyMethodDefNames("F", "b__0#1", ".ctor"); g.VerifyIL(""" + F { // Code size 4 (0x4) .maxstack 1 @@ -7124,6 +7223,7 @@ .maxstack 1 IL_0002: stloc.2 IL_0003: ret } + b__0#1 { // Code size 12 (0xc) .maxstack 8 @@ -7132,6 +7232,7 @@ .maxstack 8 IL_0006: newobj 0x06000005 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -7195,6 +7296,7 @@ public void F() g.VerifyIL( """ + F { // Code size 11 (0xb) .maxstack 2 @@ -7205,6 +7307,7 @@ .maxstack 2 IL_0009: nop IL_000a: ret } + g__L|0#1_0#1 { // Code size 13 (0xd) .maxstack 8 @@ -7242,6 +7345,7 @@ public void F() g.VerifyMethodDefNames("F", "g__L|0#1_0#1", ".ctor"); g.VerifyIL(""" + F { // Code size 4 (0x4) .maxstack 1 @@ -7250,6 +7354,7 @@ .maxstack 1 IL_0002: stloc.2 IL_0003: ret } + g__L|0#1_0#1 { // Code size 12 (0xc) .maxstack 8 @@ -7258,6 +7363,7 @@ .maxstack 8 IL_0006: newobj 0x06000004 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -7360,6 +7466,7 @@ void F() g.VerifyIL( """ + F { // Code size 82 (0x52) .maxstack 3 @@ -7396,6 +7503,7 @@ .maxstack 3 IL_0050: nop IL_0051: ret } + b__0 { // Code size 7 (0x7) .maxstack 8 @@ -7403,6 +7511,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + b__1 { // Code size 12 (0xc) .maxstack 8 @@ -7411,6 +7520,7 @@ .maxstack 8 IL_0006: newobj 0x06000008 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -7423,6 +7533,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -7431,6 +7542,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__1#1 { // Code size 19 (0x13) .maxstack 8 @@ -7552,6 +7664,7 @@ void F() g.VerifyIL( """ + F { // Code size 24 (0x18) .maxstack 2 @@ -7570,6 +7683,7 @@ .maxstack 2 IL_0016: nop IL_0017: ret } + g__L1|0_0 { // Code size 7 (0x7) .maxstack 8 @@ -7577,6 +7691,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + g__L2|0_1 { // Code size 12 (0xc) .maxstack 8 @@ -7585,6 +7700,7 @@ .maxstack 8 IL_0006: newobj 0x06000006 IL_000b: throw } + g__L2|0_1#1 { // Code size 14 (0xe) .maxstack 8 @@ -7595,6 +7711,7 @@ .maxstack 8 IL_000c: add IL_000d: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -7698,6 +7815,7 @@ void F() g.VerifyIL( """ + F { // Code size 68 (0x44) .maxstack 2 @@ -7728,6 +7846,7 @@ .maxstack 2 IL_0042: nop IL_0043: ret } + b__0 { // Code size 7 (0x7) .maxstack 8 @@ -7735,6 +7854,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + b__1 { // Code size 12 (0xc) .maxstack 8 @@ -7743,6 +7863,7 @@ .maxstack 8 IL_0006: newobj 0x06000008 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -7755,6 +7876,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -7763,6 +7885,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__1#1 { // Code size 7 (0x7) .maxstack 8 @@ -7883,6 +8006,7 @@ void F() g.VerifyIL( """ + F { // Code size 24 (0x18) .maxstack 2 @@ -7901,6 +8025,7 @@ .maxstack 2 IL_0016: nop IL_0017: ret } + g__L1|0_0 { // Code size 7 (0x7) .maxstack 8 @@ -7908,6 +8033,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + g__L2|0_1 { // Code size 12 (0xc) .maxstack 8 @@ -7916,6 +8042,7 @@ .maxstack 8 IL_0006: newobj 0x06000006 IL_000b: throw } + g__L2|0_1#1 { // Code size 7 (0x7) .maxstack 8 @@ -7923,6 +8050,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -8019,6 +8147,7 @@ void F() "b__2#1"); g.VerifyIL(""" + F { // Code size 131 (0x83) .maxstack 2 @@ -8069,6 +8198,7 @@ .maxstack 2 IL_0081: nop IL_0082: ret } + b__0 { // Code size 7 (0x7) .maxstack 8 @@ -8076,6 +8206,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + b__1 { // Code size 12 (0xc) .maxstack 8 @@ -8084,6 +8215,7 @@ .maxstack 8 IL_0006: newobj 0x06000008 IL_000b: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -8096,6 +8228,7 @@ .maxstack 8 IL_000a: stfld 0x04000004 IL_000f: ret } + .ctor, .ctor { // Code size 8 (0x8) .maxstack 8 @@ -8104,6 +8237,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + b__1#1 { // Code size 24 (0x18) .maxstack 8 @@ -8116,6 +8250,7 @@ .maxstack 8 IL_0016: add IL_0017: ret } + b__2#1 { // Code size 36 (0x24) .maxstack 8 @@ -8249,6 +8384,7 @@ void F() g.VerifyMethodDefNames("F", "g__L1|0_0", "g__L2|0_1", "g__L3|0_2#1"); g.VerifyIL(""" + F { // Code size 35 (0x23) .maxstack 2 @@ -8273,6 +8409,7 @@ .maxstack 2 IL_0021: nop IL_0022: ret } + g__L1|0_0 { // Code size 7 (0x7) .maxstack 8 @@ -8280,6 +8417,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + g__L2|0_1 { // Code size 14 (0xe) .maxstack 8 @@ -8290,6 +8428,7 @@ .maxstack 8 IL_000c: add IL_000d: ret } + g__L3|0_2#1 { // Code size 21 (0x15) .maxstack 8 @@ -8427,6 +8566,7 @@ public void F() g.VerifyIL( """ + F { // Code size 84 (0x54) .maxstack 2 @@ -8460,6 +8600,7 @@ .maxstack 2 IL_0052: nop IL_0053: ret } + b__0 { // Code size 7 (0x7) .maxstack 8 @@ -8467,6 +8608,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + b__2 { // Code size 12 (0xc) .maxstack 8 @@ -8475,6 +8617,7 @@ .maxstack 8 IL_0006: newobj 0x06000009 IL_000b: throw } + b__1 { // Code size 7 (0x7) .maxstack 8 @@ -8482,6 +8625,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -8494,6 +8638,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + b__2#1 { // Code size 9 (0x9) .maxstack 8 @@ -8625,6 +8770,7 @@ public void F() g.VerifyIL( """ + F { // Code size 23 (0x17) .maxstack 2 @@ -8642,6 +8788,7 @@ .maxstack 2 IL_0015: nop IL_0016: ret } + g__L1|0_0 { // Code size 7 (0x7) .maxstack 8 @@ -8649,6 +8796,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + g__L2|0_1 { // Code size 7 (0x7) .maxstack 8 @@ -8656,6 +8804,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + g__L3|0_2 { // Code size 12 (0xc) .maxstack 8 @@ -8664,6 +8813,7 @@ .maxstack 8 IL_0006: newobj 0x06000007 IL_000b: throw } + g__L3|0_2#1 { // Code size 9 (0x9) .maxstack 8 @@ -8673,6 +8823,7 @@ .maxstack 8 IL_0007: add IL_0008: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -8789,6 +8940,7 @@ public void F() g.VerifyIL( """ + F { // Code size 62 (0x3e) .maxstack 2 @@ -8816,6 +8968,7 @@ .maxstack 2 IL_003c: nop IL_003d: ret } + g__L1|0 { // Code size 13 (0xd) .maxstack 8 @@ -8824,6 +8977,7 @@ .maxstack 8 IL_0007: newobj 0x0600000A IL_000c: throw } + b__2 { // Code size 12 (0xc) .maxstack 8 @@ -8832,6 +8986,7 @@ .maxstack 8 IL_0006: newobj 0x0600000A IL_000b: throw } + b__1 { // Code size 7 (0x7) .maxstack 8 @@ -8839,6 +8994,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + g__L1|1_0#1 { // Code size 7 (0x7) .maxstack 8 @@ -8846,6 +9002,7 @@ .maxstack 8 IL_0001: ldfld 0x04000004 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -8858,6 +9015,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + b__2#1 { // Code size 9 (0x9) .maxstack 8 @@ -8990,6 +9148,7 @@ public void F() g.VerifyMethodDefNames("F", "g__L1|1_0", "g__L3|1_2", "b__1", ".ctor", "g__L3|2#1"); g.VerifyIL(""" + F { // Code size 45 (0x2d) .maxstack 2 @@ -9013,6 +9172,7 @@ .maxstack 2 IL_002b: nop IL_002c: ret } + g__L1|1_0 { // Code size 7 (0x7) .maxstack 8 @@ -9020,6 +9180,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + g__L3|1_2 { // Code size 12 (0xc) .maxstack 8 @@ -9028,6 +9189,7 @@ .maxstack 8 IL_0006: newobj 0x06000008 IL_000b: throw } + b__1 { // Code size 7 (0x7) .maxstack 8 @@ -9035,6 +9197,7 @@ .maxstack 8 IL_0001: ldfld 0x04000002 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9047,6 +9210,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + g__L3|2#1 { // Code size 9 (0x9) .maxstack 8 @@ -9128,6 +9292,7 @@ public void F() g.VerifyIL( """ + F { // Code size 40 (0x28) .maxstack 2 @@ -9147,6 +9312,7 @@ .maxstack 2 IL_0026: nop IL_0027: ret } + b__0 { // Code size 14 (0xe) .maxstack 8 @@ -9224,6 +9390,7 @@ public void F() g.VerifyMethodDefNames("F", "g__L|0_0", "g__L|0_0#1", ".ctor"); g.VerifyIL(""" + F { // Code size 19 (0x13) .maxstack 2 @@ -9237,6 +9404,7 @@ .maxstack 2 IL_0011: nop IL_0012: ret } + g__L|0_0 { // Code size 13 (0xd) .maxstack 8 @@ -9245,6 +9413,7 @@ .maxstack 8 IL_0007: newobj 0x06000005 IL_000c: throw } + g__L|0_0#1 { // Code size 14 (0xe) .maxstack 8 @@ -9255,6 +9424,7 @@ .maxstack 8 IL_000c: add IL_000d: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9342,6 +9512,7 @@ public void F() g.VerifyIL( """ + F { // Code size 40 (0x28) .maxstack 2 @@ -9361,6 +9532,7 @@ .maxstack 2 IL_0026: nop IL_0027: ret } + b__0 { // Code size 14 (0xe) .maxstack 8 @@ -9442,6 +9614,7 @@ public void F() g.VerifyIL( """ + F { // Code size 11 (0xb) .maxstack 2 @@ -9452,6 +9625,7 @@ .maxstack 2 IL_0009: nop IL_000a: ret } + g__L|0 { // Code size 13 (0xd) .maxstack 8 @@ -9460,6 +9634,7 @@ .maxstack 8 IL_0007: newobj 0x06000008 IL_000c: throw } + b__1 { // Code size 12 (0xc) .maxstack 8 @@ -9468,6 +9643,7 @@ .maxstack 8 IL_0006: newobj 0x06000008 IL_000b: throw } + g__L|1_0#1 { // Code size 7 (0x7) .maxstack 8 @@ -9475,6 +9651,7 @@ .maxstack 8 IL_0001: ldfld 0x04000003 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9573,6 +9750,7 @@ public void F() g.VerifyIL( """ + F { // Code size 11 (0xb) .maxstack 2 @@ -9583,6 +9761,7 @@ .maxstack 2 IL_0009: nop IL_000a: ret } + g__L|0 { // Code size 13 (0xd) .maxstack 8 @@ -9591,6 +9770,7 @@ .maxstack 8 IL_0007: newobj 0x06000007 IL_000c: throw } + g__L|1_0#1 { // Code size 7 (0x7) .maxstack 8 @@ -9598,6 +9778,7 @@ .maxstack 8 IL_0001: ldfld 0x04000003 IL_0006: ret } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9676,6 +9857,7 @@ public void F() g.VerifyMethodDefNames("F", "g__L|1_0", ".ctor", ".ctor", "g__L|0#1", "b__1#1"); g.VerifyIL(""" + F { // Code size 34 (0x22) .maxstack 2 @@ -9693,6 +9875,7 @@ .maxstack 2 IL_0020: nop IL_0021: ret } + g__L|1_0 { // Code size 13 (0xd) .maxstack 8 @@ -9701,6 +9884,7 @@ .maxstack 8 IL_0007: newobj 0x06000005 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9713,6 +9897,7 @@ .maxstack 8 IL_000a: stfld 0x04000002 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -9721,6 +9906,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L|0#1, b__1#1 { // Code size 7 (0x7) .maxstack 8 @@ -9794,7 +9980,8 @@ public void F() g.VerifyIL( """ - { + F + { // Code size 34 (0x22) .maxstack 2 IL_0000: newobj 0x06000006 @@ -9811,6 +9998,7 @@ .maxstack 2 IL_0020: nop IL_0021: ret } + g__L|1_0 { // Code size 13 (0xd) .maxstack 8 @@ -9819,6 +10007,7 @@ .maxstack 8 IL_0007: newobj 0x06000005 IL_000c: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9831,6 +10020,7 @@ .maxstack 8 IL_000a: stfld 0x04000002 IL_000f: ret } + .ctor { // Code size 8 (0x8) .maxstack 8 @@ -9839,6 +10029,7 @@ .maxstack 8 IL_0006: nop IL_0007: ret } + g__L|0#1 { // Code size 7 (0x7) .maxstack 8 @@ -9906,6 +10097,7 @@ public void F() g.VerifyIL( """ + F { // Code size 30 (0x1e) .maxstack 8 @@ -9918,6 +10110,7 @@ .maxstack 8 IL_0018: stsfld 0x04000004 IL_001d: ret } + b__0_0 { // Code size 16 (0x10) .maxstack 8 @@ -9926,6 +10119,7 @@ .maxstack 8 IL_000a: newobj 0x06000006 IL_000f: throw } + .ctor { // Code size 16 (0x10) .maxstack 8 @@ -9938,6 +10132,7 @@ .maxstack 8 IL_000a: stfld 0x04000003 IL_000f: ret } + b__0_0#1 { // Code size 10 (0xa) .maxstack 8 diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 9656fa081d8b1..77950f04feb40 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -4634,6 +4634,7 @@ class C ]); var expectedIL = """ + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4641,6 +4642,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -4719,6 +4721,7 @@ class C ]); var expectedIL = """ + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4726,6 +4729,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 @@ -4799,6 +4803,7 @@ class C ]); var expectedIL = """ + get_P { // Code size 7 (0x7) .maxstack 8 @@ -4806,6 +4811,7 @@ .maxstack 8 IL_0001: ldfld 0x04000001 IL_0006: ret } + set_P { // Code size 8 (0x8) .maxstack 8 diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index 2337dc9fc7a8c..7e8a8a0da13bb 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 70de0e2d77c0b..a7ac01ba69d52 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -741,7 +741,7 @@ internal void EmitStringConstant(string? value, SyntaxNode? syntax) // If the length is greater than the specified threshold try lfsfld first and fall back to ldstr. // Otherwise, try emit ldstr and fall back to ldsfld if emitting EnC delta and the heap is already full. - bool success = (value.Length >= module.CommonCompilation.DataSectionStringLiteralThreshold) + bool success = (value.Length > module.CommonCompilation.DataSectionStringLiteralThreshold) ? tryEmitLoadField() || tryEmitLoadString() : tryEmitLoadString() || module.PreviousGeneration != null && tryEmitLoadField(); diff --git a/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs b/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs index 88ee01cc58ff3..a6153ce286748 100644 --- a/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs +++ b/src/Compilers/Core/Portable/CodeGen/StringTokenMap.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; -using ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer; namespace Microsoft.CodeAnalysis.CodeGen; diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index fc930e2123be1..631274bba0a40 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -3086,7 +3086,6 @@ public EmitDifferenceResult EmitDifference( /// of the current compilation is returned as an EmitBaseline for use in a /// subsequent Edit and Continue. ///
- [Obsolete("Use overload that takes EmitDifferenceOptions")] public EmitDifferenceResult EmitDifference( EmitBaseline baseline, IEnumerable edits, diff --git a/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs b/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs index 756c2629984fe..6c4b3b99c5af1 100644 --- a/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs +++ b/src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Reflection.Emit; using System.Reflection.Metadata; using System.Text; @@ -24,7 +25,7 @@ internal sealed class ILBuilderVisualizer : ILVisualizer private readonly CommonPEModuleBuilder _module; private readonly SymbolDisplayFormat _symbolDisplayFormat; - public ILBuilderVisualizer(ITokenDeferral tokenDeferral, SymbolDisplayFormat? symbolDisplayFormat = null) + public ILBuilderVisualizer(CommonPEModuleBuilder module, SymbolDisplayFormat? symbolDisplayFormat = null) { _module = module; _symbolDisplayFormat = symbolDisplayFormat ?? SymbolDisplayFormat.ILVisualizationFormat; @@ -139,6 +140,8 @@ internal static string ILBuilderToString( IReadOnlyDictionary? markers = null, SymbolDisplayFormat? ilFormat = null) { + Debug.Assert(builder.LocalSlotManager != null); + var sb = new StringBuilder(); var ilStream = builder.RealizedIL; @@ -177,6 +180,8 @@ internal static string LocalSignatureToString( ILBuilder builder, Func? mapLocal = null) { + Debug.Assert(builder.LocalSlotManager != null); + var sb = new StringBuilder(); if (mapLocal == null) diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index 7cff6341780e6..0611918d426a0 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -2114,6 +2114,8 @@ internal static unsafe string VisualizeRealIL(PEModuleSymbol peModule, Compilati return ImmutableArray.Create(); } + Debug.Assert(builder.LocalSlotManager != null); + var result = new ILVisualizer.LocalInfo[localInfos.Length]; for (int i = 0; i < result.Length; i++) { diff --git a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb index ca8fcd8f48918..b6bb38d54e99f 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/ErrorFacts.vb @@ -1304,6 +1304,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERRID.ERR_InvalidPathMap, ERRID.ERR_PublicSignNoKey, ERRID.ERR_TooManyUserStrings, + ERRID.ERR_TooManyUserStrings_RestartRequired, ERRID.ERR_PeWritingFailure, ERRID.ERR_OptionMustBeAbsolutePath, ERRID.ERR_DocFileGen, diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index c153096c40ad6..9545bc9cc30a9 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5459,6 +5459,9 @@ Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string or XML literals. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + An error occurred while writing the output file: {0} diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf index cd99d16dde1e7..2d0bb2054efc1 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf @@ -132,6 +132,11 @@ {0} je definováno v sestavení {1}. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. Název typu {0} je vyhrazený pro použití kompilátorem. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf index f52b27726a1a1..956b1648d9288 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf @@ -132,6 +132,11 @@ "{0}" ist in Assembly "{1}" definiert. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. Der Typname "{0}" ist für die Verwendung durch den Compiler reserviert. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf index be3274c2999a9..8f3b3eda58e51 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf @@ -132,6 +132,11 @@ '{0}' se define en el ensamblado '{1}'. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. El nombre de tipo "{0}" está reservado para uso del compilador. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf index 4b05beae4f487..262a46314103f 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf @@ -132,6 +132,11 @@ '{0}' est défini dans l'assemblage '{1}'. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. L'utilisation du nom de type '{0}' est réservée au compilateur. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf index d7659c5a7ee3b..88e05af06655b 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf @@ -132,6 +132,11 @@ '{0}' è definito nell'assembly '{1}'. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. Il nome di tipo '{0}' è riservato al compilatore. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf index 440445efa7967..82a9a3cca5878 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf @@ -132,6 +132,11 @@ '{0}' はアセンブリ '{1}' で定義されています。 + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. 型名 '{0}' は、コンパイラによる使用のために予約されています。 diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf index 3ccca121c0470..b9e34c1144700 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf @@ -132,6 +132,11 @@ '{0}'은(는) '{1}' 어셈블리에 정의되어 있습니다. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. 형식 이름 '{0}'은(는) 컴파일러에서 사용하도록 예약되어 있습니다. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf index ea736d6e939fe..194b290b41021 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf @@ -132,6 +132,11 @@ „{0}” jest zdefiniowany w zestawie „{1}”. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. Nazwa typu „{0}” jest zarezerwowana do użycia przez kompilator. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf index dd23654acf80a..6879c0913a3ac 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf @@ -132,6 +132,11 @@ '{0}' é definido no assembly '{1}'. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. O nome do tipo '{0}' está reservado para ser usado pelo compilador. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf index 075a143a0723a..2414dda323091 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf @@ -132,6 +132,11 @@ '{0}' определен в сборке '{1}'. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. Имя типа "{0}" зарезервировано для использования компилятором. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf index 6af7446cd9a65..11927a3b7d654 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf @@ -132,6 +132,11 @@ '{0}', '{1}' derlemesinde tanımlı. + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. '{0}' tür adı, derleyici tarafından kullanılmak üzere ayrılmıştır. diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf index 7a5a5f73a5c49..e4c29d3e6e9a4 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf @@ -132,6 +132,11 @@ “{0}”在程序集“{1}”中定义。 + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. 类型名称“{0}”是保留给编译器使用的。 diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf index 440e9c48e4924..40cae595794b4 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf @@ -132,6 +132,11 @@ '{0}' 於組件 '{1}' 中定義。 + + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + Combined length of user strings used by the program exceeds allowed limit. Adding a string or XML literal requires restarting the application. + + The type name '{0}' is reserved to be used by the compiler. 類型名稱 '{0}' 保留供編譯器使用。 diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb index b07005d502acb..a2735c380d293 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueClosureTests.vb @@ -2275,6 +2275,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor", ".ctor", "_Lambda$__0#1") g.VerifyIL(" +F { // Code size 67 (0x43) .maxstack 2 @@ -2300,6 +2301,7 @@ End Class IL_0040: stloc.s V_5 IL_0042: ret } +_Lambda$__1-0 { // Code size 12 (0xc) .maxstack 8 @@ -2308,6 +2310,7 @@ End Class IL_0006: newobj 0x06000007 IL_000b: throw } +_Lambda$__1-1 { // Code size 9 (0x9) .maxstack 8 @@ -2317,6 +2320,7 @@ End Class IL_0007: nop IL_0008: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2328,6 +2332,7 @@ End Class IL_0009: stfld 0x04000004 IL_000e: ret } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -2335,6 +2340,7 @@ End Class IL_0001: call 0x0A00000C IL_0006: ret } +_Lambda$__0#1 { // Code size 14 (0xe) .maxstack 8 @@ -2392,6 +2398,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__1-0", "_Lambda$__1-1", ".ctor", ".ctor", "_Lambda$__1#1") g.VerifyIL(" +F { // Code size 66 (0x42) .maxstack 2 @@ -2417,6 +2424,7 @@ End Class IL_003f: stloc.s V_4 IL_0041: ret } +_Lambda$__1-0 { // Code size 9 (0x9) .maxstack 8 @@ -2426,6 +2434,7 @@ End Class IL_0007: nop IL_0008: ret } +_Lambda$__1-1 { // Code size 12 (0xc) .maxstack 8 @@ -2434,6 +2443,7 @@ End Class IL_0006: newobj 0x06000007 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2445,6 +2455,7 @@ End Class IL_0009: stfld 0x04000004 IL_000e: ret } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -2452,6 +2463,7 @@ End Class IL_0001: call 0x0A00000C IL_0006: ret } +_Lambda$__1#1 { // Code size 14 (0xe) .maxstack 8 @@ -2512,6 +2524,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__2-0", "_Lambda$__2-1", "_Lambda$__2-1#1", ".ctor") g.VerifyIL(" +F { // Code size 52 (0x34) .maxstack 2 @@ -2532,6 +2545,7 @@ End Class IL_0032: stloc.3 IL_0033: ret } +_Lambda$__2-0 { // Code size 9 (0x9) .maxstack 8 @@ -2541,6 +2555,7 @@ End Class IL_0007: nop IL_0008: ret } +_Lambda$__2-1 { // Code size 12 (0xc) .maxstack 8 @@ -2549,6 +2564,7 @@ End Class IL_0006: newobj 0x06000008 IL_000b: throw } +_Lambda$__2-1#1 { // Code size 14 (0xe) .maxstack 8 @@ -2559,6 +2575,7 @@ End Class IL_000c: nop IL_000d: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2617,6 +2634,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0") g.VerifyIL(" +F { // Code size 30 (0x1e) .maxstack 2 @@ -2634,6 +2652,7 @@ End Class IL_001c: stloc.3 IL_001d: ret } +_Lambda$__0 { // Code size 12 (0xc) .maxstack 1 @@ -2691,6 +2710,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0", ".ctor", ".ctor", ".cctor", "_Lambda$__1-0#1") g.VerifyIL(" +F { // Code size 41 (0x29) .maxstack 2 @@ -2709,6 +2729,7 @@ End Class IL_0027: stloc.3 IL_0028: ret } +_Lambda$__0 { // Code size 12 (0xc) .maxstack 8 @@ -2717,6 +2738,7 @@ End Class IL_0006: newobj 0x06000009 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2728,6 +2750,7 @@ End Class IL_0009: stfld 0x04000002 IL_000e: ret } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -2735,6 +2758,7 @@ End Class IL_0001: call 0x0A00000B IL_0006: ret } +.cctor { // Code size 11 (0xb) .maxstack 8 @@ -2742,6 +2766,7 @@ End Class IL_0005: stsfld 0x04000003 IL_000a: ret } +_Lambda$__1-0#1 { // Code size 7 (0x7) .maxstack 1 @@ -2776,6 +2801,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__1-0#1", ".ctor", "_Lambda$__0#2") g.VerifyIL(" +F { // Code size 32 (0x20) .maxstack 2 @@ -2791,6 +2817,7 @@ End Class IL_001d: stloc.s V_5 IL_001f: ret } +_Lambda$__1-0#1 { // Code size 12 (0xc) .maxstack 8 @@ -2799,6 +2826,7 @@ End Class IL_0006: newobj 0x06000009 IL_000b: throw } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -2806,6 +2834,7 @@ End Class IL_0001: call 0x0A00000E IL_0006: ret } +_Lambda$__0#2 { // Code size 14 (0xe) .maxstack 2 @@ -2869,6 +2898,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__2-0", "_Lambda$__2-1", ".ctor", "_Lambda$__2-0#1") g.VerifyIL(" +F { // Code size 76 (0x4c) .maxstack 2 @@ -2895,6 +2925,7 @@ End Class IL_004a: stloc.3 IL_004b: ret } +_Lambda$__2-0 { // Code size 12 (0xc) .maxstack 8 @@ -2903,6 +2934,7 @@ End Class IL_0006: newobj 0x0600000B IL_000b: throw } +_Lambda$__2-1 { // Code size 7 (0x7) .maxstack 1 @@ -2913,6 +2945,7 @@ End Class IL_0005: ldloc.0 IL_0006: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -2924,6 +2957,7 @@ End Class IL_0009: stfld 0x04000004 IL_000e: ret } +_Lambda$__2-0#1 { // Code size 7 (0x7) .maxstack 1 @@ -2977,6 +3011,7 @@ End Class g.VerifyMethodDefNames("F", ".ctor", "_Lambda$__0#1") g.VerifyIL(" +F { // Code size 28 (0x1c) .maxstack 2 @@ -2992,6 +3027,7 @@ End Class IL_001a: stloc.2 IL_001b: ret } +.ctor { // Code size 7 (0x7) .maxstack 8 @@ -2999,6 +3035,7 @@ End Class IL_0001: call 0x0A000007 IL_0006: ret } +_Lambda$__0#1 { // Code size 12 (0xc) .maxstack 1 @@ -3032,6 +3069,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0#1", ".ctor") g.VerifyIL(" +F { // Code size 4 (0x4) .maxstack 1 @@ -3040,6 +3078,7 @@ End Class IL_0002: stloc.3 IL_0003: ret } +_Lambda$__0#1 { // Code size 12 (0xc) .maxstack 8 @@ -3048,6 +3087,7 @@ End Class IL_0006: newobj 0x06000005 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -3123,6 +3163,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", ".ctor", "_Lambda$__1#1") g.VerifyIL(" +F { // Code size 128 (0x80) .maxstack 3 @@ -3171,6 +3212,7 @@ End Class IL_007c: stloc.s V_5 IL_007e: br.s IL_0011 } +_Lambda$__0 { // Code size 12 (0xc) .maxstack 1 @@ -3182,6 +3224,7 @@ End Class IL_000a: ldloc.0 IL_000b: ret } +_Lambda$__1 { // Code size 12 (0xc) .maxstack 8 @@ -3190,6 +3233,7 @@ End Class IL_0006: newobj 0x06000007 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -3201,6 +3245,7 @@ End Class IL_0009: stfld 0x04000005 IL_000e: ret } +.ctor { // Code size 22 (0x16) .maxstack 8 @@ -3214,6 +3259,7 @@ End Class IL_0010: stfld 0x04000006 IL_0015: ret } +_Lambda$__1#1 { // Code size 24 (0x18) .maxstack 2 @@ -3289,6 +3335,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", ".ctor", "_Lambda$__1#1") g.VerifyIL(" +F { // Code size 96 (0x60) .maxstack 3 @@ -3330,6 +3377,7 @@ End Class IL_005c: stloc.s V_5 IL_005e: br.s IL_0011 } +_Lambda$__0 { // Code size 12 (0xc) .maxstack 1 @@ -3341,6 +3389,7 @@ End Class IL_000a: ldloc.0 IL_000b: ret } +_Lambda$__1 { // Code size 12 (0xc) .maxstack 8 @@ -3349,6 +3398,7 @@ End Class IL_0006: newobj 0x0600000B IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -3360,6 +3410,7 @@ End Class IL_0009: stfld 0x04000005 IL_000e: ret } +.ctor { // Code size 22 (0x16) .maxstack 8 @@ -3373,6 +3424,7 @@ End Class IL_0010: stfld 0x04000006 IL_0015: ret } +_Lambda$__1#1 { // Code size 12 (0xc) .maxstack 1 @@ -3459,7 +3511,8 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__1", ".ctor", ".ctor", "_Lambda$__1#1", "_Lambda$__2#1", ".ctor") g.VerifyIL(" - { +F +{ // Code size 208 (0xd0) .maxstack 3 IL_0000: nop @@ -3528,6 +3581,7 @@ End Class IL_00c9: stloc.s V_7 IL_00cb: br IL_0014 } +_Lambda$__0 { // Code size 12 (0xc) .maxstack 1 @@ -3539,6 +3593,7 @@ End Class IL_000a: ldloc.0 IL_000b: ret } +_Lambda$__1 { // Code size 12 (0xc) .maxstack 8 @@ -3547,6 +3602,7 @@ End Class IL_0006: newobj 0x0600000B IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -3558,6 +3614,7 @@ End Class IL_0009: stfld 0x04000006 IL_000e: ret } +.ctor { // Code size 22 (0x16) .maxstack 8 @@ -3571,6 +3628,7 @@ End Class IL_0010: stfld 0x04000007 IL_0015: ret } +_Lambda$__1#1 { // Code size 29 (0x1d) .maxstack 2 @@ -3587,6 +3645,7 @@ End Class IL_001b: ldloc.0 IL_001c: ret } +_Lambda$__2#1 { // Code size 41 (0x29) .maxstack 2 @@ -3607,6 +3666,7 @@ End Class IL_0027: ldloc.0 IL_0028: ret } +.ctor { // Code size 22 (0x16) .maxstack 8 @@ -3682,6 +3742,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0", "_Lambda$__2", "_Lambda$__1", ".ctor", "_Lambda$__2#1") g.VerifyIL(" +F { // Code size 106 (0x6a) .maxstack 3 @@ -3727,6 +3788,7 @@ End Class IL_0066: stloc.s V_6 IL_0068: br.s IL_0011 } +_Lambda$__0 { // Code size 12 (0xc) .maxstack 1 @@ -3738,6 +3800,7 @@ End Class IL_000a: ldloc.0 IL_000b: ret } +_Lambda$__2 { // Code size 12 (0xc) .maxstack 8 @@ -3746,6 +3809,7 @@ End Class IL_0006: newobj 0x06000008 IL_000b: throw } +_Lambda$__1 { // Code size 12 (0xc) .maxstack 1 @@ -3757,6 +3821,7 @@ End Class IL_000a: ldloc.0 IL_000b: ret } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -3768,6 +3833,7 @@ End Class IL_0009: stfld 0x04000005 IL_000e: ret } +_Lambda$__2#1 { // Code size 14 (0xe) .maxstack 2 @@ -3834,6 +3900,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0") g.VerifyIL(" +F { // Code size 35 (0x23) .maxstack 2 @@ -3852,6 +3919,7 @@ End Class IL_0021: stloc.3 IL_0022: ret } +_Lambda$__0 { // Code size 19 (0x13) .maxstack 2 @@ -3916,6 +3984,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__0") g.VerifyIL(" +F { // Code size 35 (0x23) .maxstack 2 @@ -3934,6 +4003,7 @@ End Class IL_0021: stloc.2 IL_0022: ret } +_Lambda$__0 { // Code size 19 (0x13) .maxstack 2 @@ -3997,6 +4067,7 @@ End Class g.VerifyMethodDefNames("F", "_Lambda$__1-0", ".ctor", "_Lambda$__1-0#1") g.VerifyIL(" +F { // Code size 39 (0x27) .maxstack 2 @@ -4013,6 +4084,7 @@ End Class IL_0025: stloc.1 IL_0026: ret } +_Lambda$__1-0 { // Code size 12 (0xc) .maxstack 8 @@ -4021,6 +4093,7 @@ End Class IL_0006: newobj 0x06000006 IL_000b: throw } +.ctor { // Code size 15 (0xf) .maxstack 8 @@ -4032,6 +4105,7 @@ End Class IL_0009: stfld 0x04000003 IL_000e: ret } +_Lambda$__1-0#1 { // Code size 15 (0xf) .maxstack 1 diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb index 20d5896b8780e..649cc8877b86c 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EmitErrorTests.vb @@ -597,10 +597,13 @@ End Module") Dim compilation = CreateEmptyCompilationWithReferences(VisualBasicSyntaxTree.ParseText(source.ToString()), {MscorlibRef, SystemRef, MsvbRef}) - AssertTheseEmitDiagnostics(compilation, - -BC37255: Combined length of user strings used by the program exceeds allowed limit. Try to decrease use of string or XML literals. -) + Dim expectedDiagnostics = + { + Diagnostic(ERRID.ERR_TooManyUserStrings, """" & New String("K"c, 1000000) & """").WithLocation(13, 33), + Diagnostic(ERRID.ERR_TooManyUserStrings, """" & New String("L"c, 1000000) & """").WithLocation(14, 33) + } + + CreateCompilation(source.ToString()).VerifyEmitDiagnostics(expectedDiagnostics) End Sub #End Region From 1ad4e53b1e7b514fdc03a94767d79fd81439ab18 Mon Sep 17 00:00:00 2001 From: tmat Date: Fri, 2 May 2025 11:18:34 -0700 Subject: [PATCH 19/21] Feedback and test fix --- .../Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs | 4 +--- src/Compilers/Core/Portable/CodeGen/ILBuilder.cs | 2 +- src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs | 2 +- src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs index 77950f04feb40..52fb9f8a63973 100644 --- a/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Emit/EditAndContinue/EditAndContinueTests.cs @@ -16688,7 +16688,7 @@ public HotReloadException(string message, int code) : base(message) {} } """; - using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, parseOptions: parseOptions) + using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.FailsPEVerify, parseOptions: parseOptions) .AddBaseline( source: exceptionSource + """ class C @@ -20061,8 +20061,6 @@ public void PrivateImplDetails_DataSectionStringLiterals_HeapOverflow_FieldRvaSu // The longest string that can fit in the #US heap. The next string would overflow the heap. var baseString = new string('x', (1 << 23) - 3); - var size = MetadataHelpers.GetUserStringBlobSize(baseString); - using var _ = new EditAndContinueTest(targetFramework: TargetFramework.Net90, verification: Verification.Skipped) .AddBaseline( source: $$""" diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index 7e8a8a0da13bb..3d7af82151476 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -165,7 +165,7 @@ private void ReconcileTrailingMarkers() { Debug.Assert(_allocatedILMarkers != null); - if (_allocatedILMarkers![_lastCompleteBlock.LastILMarker].BlockOffset == _lastCompleteBlock.RegularInstructionsLength) + if (_allocatedILMarkers[_lastCompleteBlock.LastILMarker].BlockOffset == _lastCompleteBlock.RegularInstructionsLength) { int startMarker = -1; int endMarker = -1; diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index a7ac01ba69d52..78a3c835ddfbe 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -743,7 +743,7 @@ internal void EmitStringConstant(string? value, SyntaxNode? syntax) // Otherwise, try emit ldstr and fall back to ldsfld if emitting EnC delta and the heap is already full. bool success = (value.Length > module.CommonCompilation.DataSectionStringLiteralThreshold) ? tryEmitLoadField() || tryEmitLoadString() - : tryEmitLoadString() || module.PreviousGeneration != null && tryEmitLoadField(); + : tryEmitLoadString() || (module.PreviousGeneration != null && tryEmitLoadField()); if (!success) { diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs index 07349b48ee6b5..7fce63b6d05b6 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs @@ -1091,7 +1091,7 @@ internal static int GetUserStringBlobSize(string value) /// /// See https://github.com/dotnet/runtime/blob/5bfc0bec9d627c946f154dd99103a393d278f841/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs#L16 /// - internal static int GetCompressedIntegerSize(int value) + private static int GetCompressedIntegerSize(int value) { Debug.Assert(value <= 0x1fffffff); From 0d67b1beadf1d00f36653bbe22a5d16c043a9f22 Mon Sep 17 00:00:00 2001 From: tmat Date: Tue, 6 May 2025 11:50:30 -0700 Subject: [PATCH 20/21] Fix error code --- src/Compilers/CSharp/Portable/Errors/ErrorCode.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index e2279e25d3178..7211e43d60c83 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2398,7 +2398,6 @@ internal enum ErrorCode ERR_ModifierOnUnnamedReceiverParameter = 9305, ERR_ExtensionTypeNameDisallowed = 9306, ERR_ExpressionTreeContainsNamedArgumentOutOfPosition = 9307, - ERR_TooManyUserStrings_RestartRequired = 9308, ERR_OperatorsMustBePublic = 9308, // available 9309, @@ -2409,6 +2408,8 @@ internal enum ErrorCode ERR_PPShebangInProjectBasedProgram = 9314, + ERR_TooManyUserStrings_RestartRequired = 9315, + // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) // 2) Add message to CSharpResources.resx From 8dee93c616b3fd5b01b888af8f3a6249e565afe6 Mon Sep 17 00:00:00 2001 From: tmat Date: Thu, 8 May 2025 19:25:52 -0700 Subject: [PATCH 21/21] Fix --- src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs | 2 +- src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 78a3c835ddfbe..80e5bb29a3e59 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -739,7 +739,7 @@ internal void EmitStringConstant(string? value, SyntaxNode? syntax) return; } - // If the length is greater than the specified threshold try lfsfld first and fall back to ldstr. + // If the length is greater than the specified threshold try ldsfld first and fall back to ldstr. // Otherwise, try emit ldstr and fall back to ldsfld if emitting EnC delta and the heap is already full. bool success = (value.Length > module.CommonCompilation.DataSectionStringLiteralThreshold) ? tryEmitLoadField() || tryEmitLoadString() diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index fdc8bcdc6a622..e128038c6aa81 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -45,7 +45,7 @@ internal abstract class CommonPEModuleBuilder : Cci.IUnit, Cci.IModuleReference private IEnumerable _embeddedTexts = SpecializedCollections.EmptyEnumerable(); private ArrayMethods? _lazyArrayMethods; - // Calculted when emitting EnC deltas. + // Calculated when emitting EnC deltas. private IReadOnlyDictionary>? _encDeletedMethodDefinitions; // Only set when running tests to allow inspection of the emitted data.