From c90632cf2e8f5b1bd8c4da69f30520e9b1b16777 Mon Sep 17 00:00:00 2001 From: ChuckStoner Date: Mon, 5 May 2014 20:32:37 -0700 Subject: [PATCH] EnC: Nested types should be emitted in the same order in delta and full emit Enumerate the set of top-level and nested types in the base PeWriter class. (changeset 1250804) --- .../Test/Emit/Emit/EditAndContinueTests.cs | 66 +++++++++++++++++++ .../Emit/EditAndContinue/DeltaPeWriter.cs | 27 ++------ .../Core/Source/PEWriter/FullPeWriter.cs | 31 +-------- .../Core/Source/PEWriter/PeWriter.cs | 36 +++++++++- 4 files changed, 107 insertions(+), 53 deletions(-) diff --git a/Src/Compilers/CSharp/Test/Emit/Emit/EditAndContinueTests.cs b/Src/Compilers/CSharp/Test/Emit/Emit/EditAndContinueTests.cs index 45c881aad25..3f9c084b477 100644 --- a/Src/Compilers/CSharp/Test/Emit/Emit/EditAndContinueTests.cs +++ b/Src/Compilers/CSharp/Test/Emit/Emit/EditAndContinueTests.cs @@ -716,6 +716,72 @@ static object F() } } + /// + /// Nested types should be emitted in the + /// same order as full emit. + /// + [Fact] + public void AddNestedTypesOrder() + { + var source0 = +@"class A +{ + class B1 + { + class C1 { } + } + class B2 + { + class C2 { } + } +}"; + var source1 = +@"class A +{ + class B1 + { + class C1 { } + } + class B2 + { + class C2 { } + } + class B3 + { + class C3 { } + } + class B4 + { + class C4 { } + } +}"; + var compilation0 = CreateCompilationWithMscorlib(source0, compOptions: TestOptions.UnoptimizedDll); + var compilation1 = CreateCompilationWithMscorlib(source1, compOptions: TestOptions.UnoptimizedDll); + + var bytes0 = compilation0.EmitToArray(debug: true); + using (var md0 = ModuleMetadata.CreateFromImage(bytes0)) + { + var reader0 = md0.MetadataReader; + CheckNames(reader0, reader0.GetTypeDefNames(), "", "A", "B1", "B2", "C1", "C2"); + Assert.Equal(4, reader0.GetTableRowCount(TableIndex.NestedClass)); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, EmptyLocalsProvider); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Insert, null, compilation1.GetMember("A.B3")), + new SemanticEdit(SemanticEditKind.Insert, null, compilation1.GetMember("A.B4")))); + + using (var md1 = diff1.GetMetadata()) + { + var reader1 = md1.Reader; + var readers = new[] { reader0, reader1 }; + CheckNames(readers, reader1.GetTypeDefNames(), "B3", "B4", "C3", "C4"); + Assert.Equal(4, reader1.GetTableRowCount(TableIndex.NestedClass)); + } + } + } + [Fact] public void AddNestedGenericType() { diff --git a/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs b/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs index d7aee556653..1b80f95e3df 100644 --- a/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs +++ b/Src/Compilers/Core/Source/Emit/EditAndContinue/DeltaPeWriter.cs @@ -414,38 +414,19 @@ protected override IReadOnlyList GetStandAloneSignatures() return this.standAloneSignatureIndex.Rows; } - private IEnumerable GetTopLevelTypes() + protected override IEnumerable GetTopLevelTypes(IModule module) { return this.changes.GetTopLevelTypes(this.Context); } protected override void CreateIndicesForModule() { - var typeDefs = ArrayBuilder.GetInstance(); - this.GetTypesAndNestedTypes(typeDefs, this.GetTopLevelTypes()); - foreach (var typeDef in typeDefs) - { - this.CreateIndicesForNonTypeMembers(typeDef); - } - typeDefs.Free(); - + base.CreateIndicesForModule(); var module = (IPEDeltaAssemblyBuilder)this.module; module.OnCreatedIndices(this.Context.Diagnostics); } - /// - /// Get the set of types and nested types, enclosing types first. - /// - private void GetTypesAndNestedTypes(ArrayBuilder builder, IEnumerable typeDefs) - { - foreach (var typeDef in typeDefs) - { - builder.Add(typeDef); - GetTypesAndNestedTypes(builder, typeDef.GetNestedTypes(this.Context)); - } - } - - private void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) + protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) { switch (this.changes.GetChange(typeDef)) { @@ -1340,7 +1321,7 @@ public override void Visit(IAssembly assembly) public override void Visit(IModule module) { this.module = module; - this.Visit(((DeltaPeWriter)this.peWriter).GetTopLevelTypes()); + this.Visit(((DeltaPeWriter)this.peWriter).GetTopLevelTypes(module)); } public override void Visit(IEventDefinition eventDefinition) diff --git a/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs b/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs index 3b79ca0cc41..41b3d065ce0 100644 --- a/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs +++ b/Src/Compilers/Core/Source/PEWriter/FullPeWriter.cs @@ -347,37 +347,12 @@ protected override void PopulatePropertyMapTableRows(List table) } } - protected override void CreateIndicesForModule() + protected override IEnumerable GetTopLevelTypes(IModule module) { - var nestedTypes = new Queue(); - - foreach (INamespaceTypeDefinition typeDef in this.module.GetTopLevelTypes(this.Context)) - { - this.CreateIndicesFor(typeDef, nestedTypes); - } - - while (nestedTypes.Count > 0) - { - this.CreateIndicesFor(nestedTypes.Dequeue(), nestedTypes); - } - } - - private void CreateIndicesFor(ITypeDefinition typeDef, Queue nestedTypes) - { - this.cancellationToken.ThrowIfCancellationRequested(); - - this.CreateIndicesForNonTypeMembers(typeDef); - - // Metadata spec: - // The TypeDef table has a special ordering constraint: - // the definition of an enclosing class shall precede the definition of all classes it encloses. - foreach (var nestedType in typeDef.GetNestedTypes(this.Context)) - { - nestedTypes.Enqueue(nestedType); - } + return module.GetTopLevelTypes(this.Context); } - private void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) + protected override void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef) { this.typeDefs.Add(typeDef); diff --git a/Src/Compilers/Core/Source/PEWriter/PeWriter.cs b/Src/Compilers/Core/Source/PEWriter/PeWriter.cs index 7c3a0ff3d97..0ed18eadad3 100644 --- a/Src/Compilers/Core/Source/PEWriter/PeWriter.cs +++ b/Src/Compilers/Core/Source/PEWriter/PeWriter.cs @@ -386,6 +386,10 @@ protected Guid ModuleVersionId /// protected abstract IReadOnlyList GetStandAloneSignatures(); + protected abstract IEnumerable GetTopLevelTypes(IModule module); + + protected abstract void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef); + /// /// Offset into full metadata blob stream. /// @@ -443,7 +447,7 @@ protected virtual void OnSerializedMetadataTables() // If true, it is allowed to have methods not have bodies (for emitting metadata-only // assembly) internal readonly bool allowMissingMethodBodies; - protected readonly CancellationToken cancellationToken; + private readonly CancellationToken cancellationToken; protected readonly IModule module; public readonly EmitContext Context; private readonly CommonMessageProvider messageProvider; @@ -1086,7 +1090,35 @@ private void CreateUserStringIndices() } } - protected abstract void CreateIndicesForModule(); + protected virtual void CreateIndicesForModule() + { + var nestedTypes = new Queue(); + + foreach (INamespaceTypeDefinition typeDef in this.GetTopLevelTypes(this.module)) + { + this.CreateIndicesFor(typeDef, nestedTypes); + } + + while (nestedTypes.Count > 0) + { + this.CreateIndicesFor(nestedTypes.Dequeue(), nestedTypes); + } + } + + private void CreateIndicesFor(ITypeDefinition typeDef, Queue nestedTypes) + { + this.cancellationToken.ThrowIfCancellationRequested(); + + this.CreateIndicesForNonTypeMembers(typeDef); + + // Metadata spec: + // The TypeDef table has a special ordering constraint: + // the definition of an enclosing class shall precede the definition of all classes it encloses. + foreach (var nestedType in typeDef.GetNestedTypes(Context)) + { + nestedTypes.Enqueue(nestedType); + } + } protected IEnumerable GetConsolidatedTypeParameters(ITypeDefinition typeDef) { -- GitLab