diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs index 777ad14fade5d..ae942e281bda2 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs @@ -1,19 +1,16 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Reflection.Metadata; -using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CSharp.Symbols; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Text; using ILOpCode = Microsoft.CodeAnalysis.CodeGen.ILOpCode; namespace Microsoft.CodeAnalysis.CSharp.CodeGen { + using Roslyn.Reflection; + internal partial class CodeGenerator { private enum ArrayInitializerStyle @@ -312,14 +309,14 @@ private ImmutableArray GetRawData(ImmutableArray initiali // the initial size is a guess. // there is no point to be precise here as MemoryStream always has N + 1 storage // and will need to be trimmed regardless - var writer = new Cci.BlobBuilder(initializers.Length * 4); + var writer = new BlobBuilder(initializers.Length * 4); SerializeArrayRecursive(writer, initializers); return writer.ToImmutableArray(); } - private void SerializeArrayRecursive(Cci.BlobBuilder bw, ImmutableArray inits) + private void SerializeArrayRecursive(BlobBuilder bw, ImmutableArray inits) { if (inits.Length != 0) { diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/ArrayTypeSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/ArrayTypeSymbolAdapter.cs index 9e354eac7a089..81ccef26d6ce9 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/ArrayTypeSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/ArrayTypeSymbolAdapter.cs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using System.Linq; +using System.Collections.Immutable; using System.Reflection.Metadata; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.Emit; @@ -36,51 +36,9 @@ bool Cci.IArrayTypeReference.IsSZArray } } - IEnumerable Cci.IArrayTypeReference.LowerBounds - { - get - { - var lowerBounds = this.LowerBounds; - - if (lowerBounds.IsDefault) - { - return Enumerable.Repeat(0, Rank); - } - else - { - return lowerBounds; - } - } - } - - uint Cci.IArrayTypeReference.Rank - { - get - { - return (uint)this.Rank; - } - } - - IEnumerable Cci.IArrayTypeReference.Sizes - { - get - { - if (this.Sizes.IsEmpty) - { - return SpecializedCollections.EmptyEnumerable(); - } - - return GetSizes(); - } - } - - private IEnumerable GetSizes() - { - foreach (var size in this.Sizes) - { - yield return (ulong)size; - } - } + ImmutableArray Cci.IArrayTypeReference.LowerBounds => LowerBounds; + int Cci.IArrayTypeReference.Rank => Rank; + ImmutableArray Cci.IArrayTypeReference.Sizes => Sizes; void Cci.IReference.Dispatch(Cci.MetadataVisitor visitor) { diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/FieldSymbolAdapter.cs b/src/Compilers/CSharp/Portable/Emitter/Model/FieldSymbolAdapter.cs index 630a282ee071f..363bc2c60543c 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/FieldSymbolAdapter.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/FieldSymbolAdapter.cs @@ -263,13 +263,12 @@ internal virtual ImmutableArray MarshallingDescriptor } } - uint Cci.IFieldDefinition.Offset + int Cci.IFieldDefinition.Offset { get { CheckDefinitionInvariant(); - var offset = this.TypeLayoutOffset; - return (uint)(offset ?? 0); + return TypeLayoutOffset ?? 0; } } diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs index 5cd19c3983b0c..0aabf1626c85b 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEAssemblyBuilder.cs @@ -104,16 +104,18 @@ internal override ImmutableArray GetAdditionalTopLevelTypes() return _lazyFiles; } - uint Cci.IAssembly.Flags + AssemblyFlags Cci.IAssembly.Flags { get { - AssemblyNameFlags result = _sourceAssembly.Flags & ~AssemblyNameFlags.PublicKey; + AssemblyFlags result = _sourceAssembly.Flags & ~AssemblyFlags.PublicKey; if (!_sourceAssembly.PublicKey.IsDefaultOrEmpty) - result |= AssemblyNameFlags.PublicKey; + { + result |= AssemblyFlags.PublicKey; + } - return (uint)result; + return result; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index 91f5d1d2eb854..4a8dfd39a9513 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -424,11 +424,11 @@ internal AssemblyHashAlgorithm? AssemblyAlgorithmIdAttributeSetting /// This represents what the user claimed in source through the AssemblyFlagsAttribute. /// It may be modified as emitted due to presence or absence of the public key. /// - internal AssemblyNameFlags Flags + internal AssemblyFlags Flags { get { - var defaultValue = default(AssemblyNameFlags); + var defaultValue = default(AssemblyFlags); var fieldValue = defaultValue; var data = GetSourceDecodedWellKnownAttributeData(); @@ -2202,15 +2202,15 @@ private void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments().AssemblyFlagsAttributeSetting = nameFlags; diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index ad7f9138a28a3..5f16785e24476 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -2207,12 +2207,12 @@ public class C Assert.Equal(true, info.ThrowOnUnmappableCharacter); Assert.Equal( - Cci.PInvokeAttributes.NoMangle | - Cci.PInvokeAttributes.CharSetUnicode | - Cci.PInvokeAttributes.SupportsLastError | - Cci.PInvokeAttributes.CallConvCdecl | - Cci.PInvokeAttributes.BestFitEnabled | - Cci.PInvokeAttributes.ThrowOnUnmappableCharEnabled, ((Cci.IPlatformInvokeInformation)info).Flags); + MethodImportAttributes.ExactSpelling | + MethodImportAttributes.CharSetUnicode | + MethodImportAttributes.SetLastError | + MethodImportAttributes.CallingConventionCDecl | + MethodImportAttributes.BestFitMappingEnable | + MethodImportAttributes.ThrowOnUnmappableCharEnable, ((Cci.IPlatformInvokeInformation)info).Flags); }); } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs index 686748f4ef1f1..c698973e98912 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/CompilationEmitTests.cs @@ -2559,6 +2559,7 @@ public interface ITestPlatform var refCompilation = CreateCompilation(refSource, options: TestOptions.ReleaseModule.WithPlatform(Platform.Itanium), assemblyName: "PlatformMismatch"); refCompilation.VerifyEmitDiagnostics(emitOptions); + var imageRef = refCompilation.EmitToImageReference(); string useSource = @" @@ -2698,16 +2699,17 @@ public void BrokenOutStream() var compilation = CreateCompilationWithMscorlib(source); var output = new BrokenStream(); + + output.BreakHow = BrokenStream.BreakHowType.ThrowOnWrite; var result = compilation.Emit(output); result.Diagnostics.Verify( // error CS8104: An error occurred while writing the Portable Executable file. Diagnostic(ErrorCode.ERR_PeWritingFailure).WithArguments(output.ThrownException.ToString()).WithLocation(1, 1)); - + + // Stream.Position is not called: output.BreakHow = BrokenStream.BreakHowType.ThrowOnSetPosition; result = compilation.Emit(output); - result.Diagnostics.Verify( - // error CS8104: An error occurred while writing the Portable Executable file. - Diagnostic(ErrorCode.ERR_PeWritingFailure).WithArguments(output.ThrownException.ToString()).WithLocation(1, 1)); + result.Diagnostics.Verify(); // disposed stream is not writable var outReal = new MemoryStream(); diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadata.cs b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadata.cs index 7d5117febd6bf..1d47ea7a9cd65 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadata.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EmitMetadata.cs @@ -2172,7 +2172,7 @@ private void VerifyEmitWithNoResources(CSharpCompilation comp, Platform platform [Fact] public unsafe void PEHeaders1() { - var options = EmitOptions.Default.WithFileAlignment(8192); + var options = EmitOptions.Default.WithFileAlignment(0x2000); var syntax = SyntaxFactory.ParseSyntaxTree(@"class C {}", TestOptions.Regular); var peStream = CreateCompilationWithMscorlib( diff --git a/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj b/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj index 98219ca86b649..86890f3d9933e 100644 --- a/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj +++ b/src/Compilers/Core/CodeAnalysisTest/CodeAnalysisTest.csproj @@ -45,6 +45,10 @@ + + + + diff --git a/src/Compilers/Core/CodeAnalysisTest/Emit/CustomDebugInfoTests.cs b/src/Compilers/Core/CodeAnalysisTest/Emit/CustomDebugInfoTests.cs index 996c8a33b4091..51c3104f27fbd 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Emit/CustomDebugInfoTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Emit/CustomDebugInfoTests.cs @@ -1,11 +1,12 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. extern alias PDB; - using System; using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; using PDB::Microsoft.CodeAnalysis; @@ -14,6 +15,8 @@ namespace Microsoft.CodeAnalysis.UnitTests.Emit { + using Roslyn.Reflection; + public class CustomDebugInfoTests { [Fact] @@ -196,7 +199,7 @@ public void EditAndContinueLocalSlotMap_NegativeSyntaxOffsets() var closures = ImmutableArray.Empty; var lambdas = ImmutableArray.Empty; - var cmw = new Cci.BlobBuilder(); + var cmw = new BlobBuilder(); new EditAndContinueMethodDebugInformation(123, slots, closures, lambdas).SerializeLocalSlots(cmw); @@ -223,7 +226,7 @@ public void EditAndContinueLambdaAndClosureMap_NegativeSyntaxOffsets() new LambdaDebugInfo(-50, new DebugId(1, 0), 0), new LambdaDebugInfo(-180, new DebugId(2, 0), LambdaDebugInfo.StaticClosureOrdinal)); - var cmw = new Cci.BlobBuilder(); + var cmw = new BlobBuilder(); new EditAndContinueMethodDebugInformation(0x7b, slots, closures, lambdas).SerializeLambdaMap(cmw); @@ -245,7 +248,7 @@ public void EditAndContinueLambdaAndClosureMap_NoClosures() var closures = ImmutableArray.Empty; var lambdas = ImmutableArray.Create(new LambdaDebugInfo(20, new DebugId(0, 0), LambdaDebugInfo.StaticClosureOrdinal)); - var cmw = new Cci.BlobBuilder(); + var cmw = new BlobBuilder(); new EditAndContinueMethodDebugInformation(-1, slots, closures, lambdas).SerializeLambdaMap(cmw); @@ -268,7 +271,7 @@ public void EditAndContinueLambdaAndClosureMap_NoLambdas() var closures = ImmutableArray.Empty; var lambdas = ImmutableArray.Empty; - var cmw = new Cci.BlobBuilder(); + var cmw = new BlobBuilder(); new EditAndContinueMethodDebugInformation(10, slots, closures, lambdas).SerializeLambdaMap(cmw); diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs index d6b055f2dee5f..d3938cbc6bf83 100644 --- a/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobTests.cs @@ -5,6 +5,8 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; using System.Text; using Microsoft.Cci; using Microsoft.CodeAnalysis.Collections; @@ -13,6 +15,8 @@ namespace Microsoft.CodeAnalysis.UnitTests.PEWriter { + using Roslyn.Reflection; + public class BlobTests { [Fact] @@ -136,11 +140,11 @@ public void GetBlobs() blobs = builder.GetBlobs().ToArray(); Assert.Equal(3, blobs.Length); Assert.Equal(16, blobs[0].Length); - Assert.Equal(16, blobs[0].GetUnderlyingBuffer().Array.Length); + Assert.Equal(16, blobs[0].GetBytes().Array.Length); Assert.Equal(100 - 16, blobs[1].Length); - Assert.Equal(100 - 16, blobs[1].GetUnderlyingBuffer().Array.Length); + Assert.Equal(100 - 16, blobs[1].GetBytes().Array.Length); Assert.Equal(1, blobs[2].Length); - Assert.Equal(100 - 16, blobs[2].GetUnderlyingBuffer().Array.Length); + Assert.Equal(100 - 16, blobs[2].GetBytes().Array.Length); builder.Clear(); @@ -149,7 +153,7 @@ public void GetBlobs() Assert.Equal(0, blobs[0].Length); // Clear uses the first buffer: - Assert.Equal(16, blobs[0].GetUnderlyingBuffer().Array.Length); + Assert.Equal(16, blobs[0].GetBytes().Array.Length); } [Fact] @@ -485,9 +489,9 @@ public unsafe void Write_Errors() public void ReserveBytes1() { var builder = new BlobBuilder(16); - var writer0 = builder.ReserveBytes(0); - var writer1 = builder.ReserveBytes(1); - var writer2 = builder.ReserveBytes(2); + var writer0 = new BlobWriter(builder.ReserveBytes(0)); + var writer1 = new BlobWriter(builder.ReserveBytes(1)); + var writer2 = new BlobWriter(builder.ReserveBytes(2)); Assert.Equal(3, builder.Count); AssertEx.Equal(new byte[] { 0, 0, 0 }, builder.ToArray()); @@ -507,7 +511,7 @@ public void ReserveBytes1() public void ReserveBytes2() { var builder = new BlobBuilder(16); - var writer = builder.ReserveBytes(17); + var writer = new BlobWriter(builder.ReserveBytes(17)); writer.WriteBytes(1, 17); var blobs = builder.GetBlobs().ToArray(); @@ -517,7 +521,7 @@ public void ReserveBytes2() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 - }, blobs[0].GetUnderlyingBuffer().ToArray()); + }, blobs[0].GetBytes().ToArray()); } // TODO: @@ -530,11 +534,11 @@ public void ReserveBytes2() private static void TestCompressedUnsignedInteger(byte[] expected, int value) { var writer = new BlobWriter(4); - writer.WriteCompressedInteger((uint)value); + writer.WriteCompressedInteger(value); AssertEx.Equal(expected, writer.ToArray()); var builder = new BlobBuilder(); - builder.WriteCompressedInteger((uint)value); + builder.WriteCompressedInteger(value); AssertEx.Equal(expected, builder.ToArray()); } diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobUtilitiesTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobUtilitiesTests.cs index da608ca031892..c7dc7b97ddd4f 100644 --- a/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobUtilitiesTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/BlobUtilitiesTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.Cci; +using System.Reflection; +using Roslyn.Reflection; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests.PEWriter diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/LabelHandleTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/LabelHandleTests.cs new file mode 100644 index 0000000000000..f1a717b629cb8 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/LabelHandleTests.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests +{ + using Roslyn.Reflection.Metadata.Ecma335.Blobs; + + public class LabelHandleTests + { + [Fact] + public void Equality() + { + var a1 = new LabelHandle(1); + var a2 = new LabelHandle(2); + var b1 = new LabelHandle(1); + + Assert.False(((object)a1).Equals(a2)); + Assert.False(a1.Equals(new object())); + Assert.False(a1.Equals(a2)); + Assert.False(a1 == a2); + + Assert.True(((object)a1).Equals(b1)); + Assert.True(a1.Equals(b1)); + Assert.True(a1 == b1); + + Assert.Equal(a1.GetHashCode(), b1.GetHashCode()); + } + } +} diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/MetadataBuilderTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/MetadataBuilderTests.cs new file mode 100644 index 0000000000000..2947256c89045 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/MetadataBuilderTests.cs @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Xunit; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +namespace Microsoft.CodeAnalysis.UnitTests.PEWriter +{ + using Roslyn.Reflection; + using Roslyn.Reflection.Metadata; + using Roslyn.Reflection.Metadata.Ecma335; + using Roslyn.Test.Utilities; + public class MetadataBuilderTests + { + [Fact] + public void Add() + { + var builder = new MetadataBuilder(); + + builder.AddModule(default(Int32), default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Module]); + + builder.AddAssembly(default(StringHandle), default(Version), default(StringHandle), default(BlobHandle), default(AssemblyFlags), default(AssemblyHashAlgorithm)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Assembly]); + + var assemblyReference = builder.AddAssemblyReference(default(StringHandle), default(Version), default(StringHandle), default(BlobHandle), default(AssemblyFlags), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.AssemblyRef]); + Assert.Equal(1, MetadataTokens.GetRowNumber(assemblyReference)); + + var typeDefinition = builder.AddTypeDefinition(default(TypeAttributes), default(StringHandle), default(StringHandle), default(EntityHandle), default(FieldDefinitionHandle), default(MethodDefinitionHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.TypeDef]); + Assert.Equal(1, MetadataTokens.GetRowNumber(typeDefinition)); + + builder.AddTypeLayout(default(TypeDefinitionHandle), default(UInt16), default(UInt32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ClassLayout]); + + builder.AddInterfaceImplementation(MetadataTokens.TypeDefinitionHandle(1), MetadataTokens.TypeDefinitionHandle(1)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.InterfaceImpl]); + + builder.AddNestedType(default(TypeDefinitionHandle), default(TypeDefinitionHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.NestedClass]); + + var typeReference = builder.AddTypeReference(EntityHandle.ModuleDefinition, default(StringHandle), default(StringHandle)); + Assert.Equal(1, MetadataTokens.GetRowNumber(typeReference)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.TypeRef]); + + builder.AddTypeSpecification(default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.TypeSpec]); + + builder.AddStandaloneSignature(default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.StandAloneSig]); + + builder.AddProperty(default(PropertyAttributes), default(StringHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Property]); + + builder.AddPropertyMap(default(TypeDefinitionHandle), default(PropertyDefinitionHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.PropertyMap]); + + builder.AddEvent(default(EventAttributes), default(StringHandle), MetadataTokens.TypeDefinitionHandle(1)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Event]); + + builder.AddEventMap(default(TypeDefinitionHandle), default(EventDefinitionHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.EventMap]); + + builder.AddConstant(MetadataTokens.FieldDefinitionHandle(1), default(Object)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Constant]); + + builder.AddMethodSemantics(MetadataTokens.EventDefinitionHandle(1), default(UInt16), default(MethodDefinitionHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodSemantics]); + + builder.AddCustomAttribute(MetadataTokens.TypeDefinitionHandle(1), MetadataTokens.MethodDefinitionHandle(1), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.CustomAttribute]); + + builder.AddMethodSpecification(MetadataTokens.MethodDefinitionHandle(1), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodSpec]); + + builder.AddModuleReference(default(StringHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ModuleRef]); + + builder.AddParameter(default(ParameterAttributes), default(StringHandle), default(Int32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Param]); + + var genericParameter = builder.AddGenericParameter(MetadataTokens.MethodDefinitionHandle(1), default(GenericParameterAttributes), default(StringHandle), default(Int32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.GenericParam]); + Assert.Equal(1, MetadataTokens.GetRowNumber(genericParameter)); + + builder.AddGenericParameterConstraint(default(GenericParameterHandle), MetadataTokens.TypeDefinitionHandle(1)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.GenericParamConstraint]); + + builder.AddFieldDefinition(default(FieldAttributes), default(StringHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Field]); + + builder.AddFieldLayout(default(FieldDefinitionHandle), default(Int32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.FieldLayout]); + + builder.AddMarshallingDescriptor(MetadataTokens.FieldDefinitionHandle(1), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.FieldMarshal]); + + builder.AddFieldRelativeVirtualAddress(default(FieldDefinitionHandle), default(Int32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.FieldRva]); + + var methodDefinition = builder.AddMethodDefinition(default(MethodAttributes), default(MethodImplAttributes), default(StringHandle), default(BlobHandle), default(Int32), default(ParameterHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodDef]); + Assert.Equal(1, MetadataTokens.GetRowNumber(methodDefinition)); + + builder.AddMethodImport(MetadataTokens.MethodDefinitionHandle(1), default(MethodImportAttributes), default(StringHandle), default(ModuleReferenceHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ImplMap]); + + builder.AddMethodImplementation(default(TypeDefinitionHandle), MetadataTokens.MethodDefinitionHandle(1), MetadataTokens.MethodDefinitionHandle(1)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodImpl]); + + var memberReference = builder.AddMemberReference(MetadataTokens.TypeDefinitionHandle(1), default(StringHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MemberRef]); + Assert.Equal(1, MetadataTokens.GetRowNumber(memberReference)); + + builder.AddManifestResource(default(ManifestResourceAttributes), default(StringHandle), MetadataTokens.AssemblyFileHandle(1), default(Int64)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ManifestResource]); + + builder.AddAssemblyFile(default(StringHandle), default(BlobHandle), default(Boolean)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.File]); + + builder.AddExportedType(default(TypeAttributes), default(StringHandle), default(StringHandle), MetadataTokens.AssemblyFileHandle(1), default(Int32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ExportedType]); + + builder.AddDeclarativeSecurityAttribute(MetadataTokens.TypeDefinitionHandle(1), default(DeclarativeSecurityAction), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.DeclSecurity]); + + builder.AddEncLogEntry(MetadataTokens.TypeDefinitionHandle(1), default(EditAndContinueOperation)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.EncLog]); + + builder.AddEncMapEntry(MetadataTokens.TypeDefinitionHandle(1)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.EncMap]); + + var document = builder.AddDocument(default(BlobHandle), default(GuidHandle), default(BlobHandle), default(GuidHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Document]); + Assert.Equal(1, MetadataTokens.GetRowNumber(document)); + + builder.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodDebugInformation]); + + var localScope = builder.AddLocalScope(default(MethodDefinitionHandle), default(ImportScopeHandle), default(LocalVariableHandle), default(LocalConstantHandle), default(Int32), default(Int32)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.LocalScope]); + Assert.Equal(1, MetadataTokens.GetRowNumber(localScope)); + + var localVariable = builder.AddLocalVariable(default(LocalVariableAttributes), default(Int32), default(StringHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.LocalVariable]); + Assert.Equal(1, MetadataTokens.GetRowNumber(localVariable)); + + var localConstant = builder.AddLocalConstant(default(StringHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.LocalConstant]); + Assert.Equal(1, MetadataTokens.GetRowNumber(localConstant)); + + var importScope = builder.AddImportScope(default(ImportScopeHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ImportScope]); + Assert.Equal(1, MetadataTokens.GetRowNumber(importScope)); + + builder.AddStateMachineMethod(default(MethodDefinitionHandle), default(MethodDefinitionHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.StateMachineMethod]); + + builder.AddCustomDebugInformation(default(EntityHandle), default(GuidHandle), default(BlobHandle)); + Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.CustomDebugInformation]); + } + + [Fact, WorkItem(9852, "https://github.com/dotnet/roslyn/issues/9852")] + public void HeapOverflow_UserString() + { + string veryLargeString = new string('x', 0x00fffff0 / 2); + + var builder1 = new MetadataBuilder(); + Assert.Equal(0x70000001, MetadataTokens.GetToken(builder1.GetOrAddUserString(veryLargeString))); + + // TODO: https://github.com/dotnet/roslyn/issues/9852 + // Should throw: Assert.Throws(() => builder1.GetOrAddUserString("123")); + // Assert.Equal(0x70fffff6, MetadataTokens.GetToken(builder1.GetOrAddUserString("12"))); + // Assert.Equal(0x70fffff6, MetadataTokens.GetToken(builder1.GetOrAddUserString("12"))); + Assert.Equal(0x70fffff6, MetadataTokens.GetToken(builder1.GetOrAddUserString(veryLargeString + "z"))); + Assert.Throws(() => builder1.GetOrAddUserString("12")); + + var builder2 = new MetadataBuilder(); + Assert.Equal(0x70000001, MetadataTokens.GetToken(builder2.GetOrAddUserString("123"))); + Assert.Equal(0x70000009, MetadataTokens.GetToken(builder2.GetOrAddUserString(veryLargeString))); + Assert.Equal(0x70fffffe, MetadataTokens.GetToken(builder2.GetOrAddUserString("4"))); // TODO: should throw https://github.com/dotnet/roslyn/issues/9852 + + var builder3 = new MetadataBuilder(userStringHeapStartOffset: 0x00fffffe); + Assert.Equal(0x70ffffff, MetadataTokens.GetToken(builder3.GetOrAddUserString("1"))); // TODO: should throw https://github.com/dotnet/roslyn/issues/9852 + + var builder4 = new MetadataBuilder(userStringHeapStartOffset: 0x00fffff7); + Assert.Equal(0x70fffff8, MetadataTokens.GetToken(builder4.GetOrAddUserString("1"))); // 4B + Assert.Equal(0x70fffffc, MetadataTokens.GetToken(builder4.GetOrAddUserString("2"))); // 4B + + var builder5 = new MetadataBuilder(userStringHeapStartOffset: 0x00fffff8); + Assert.Equal(0x70fffff9, MetadataTokens.GetToken(builder5.GetOrAddUserString("1"))); // 4B + Assert.Equal(0x70fffffd, MetadataTokens.GetToken(builder5.GetOrAddUserString("2"))); // 4B // TODO: should throw https://github.com/dotnet/roslyn/issues/9852 + } + + // TODO: test overflow of other heaps, tables + } +} diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/MethodBodyEncoderTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/MethodBodyEncoderTests.cs new file mode 100644 index 0000000000000..847d9d1a11f51 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/MethodBodyEncoderTests.cs @@ -0,0 +1,269 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Linq; +using System.Reflection.Metadata; +using Microsoft.CodeAnalysis.CodeGen; +using Roslyn.Test.Utilities; +using Xunit; +using ILOpCode = Microsoft.CodeAnalysis.CodeGen.ILOpCode; + +namespace Microsoft.CodeAnalysis.UnitTests +{ + using Roslyn.Reflection; + using Roslyn.Reflection.Metadata.Ecma335.Blobs; + + public class MethodBodyEncoderTests + { + private static unsafe MethodBodyBlock ReadMethodBody(byte[] body) + { + fixed (byte* bodyPtr = &body[0]) + { + return MethodBodyBlock.Create(new BlobReader(bodyPtr, body.Length)); + } + } + + private static void WriteFakeILWithBranches(BlobBuilder builder, BranchBuilder branchBuilder, int size) + { + Assert.Equal(0, builder.Count); + + const byte filling = 0x01; + int ilOffset = 0; + foreach (var branch in branchBuilder.Branches) + { + builder.WriteBytes(filling, branch.ILOffset - ilOffset); + + Assert.Equal(branch.ILOffset, builder.Count); + builder.WriteByte(branch.ShortOpCode); + builder.WriteByte(0xff); + + ilOffset = branch.ILOffset + 2; + } + + builder.WriteBytes(filling, size - ilOffset); + Assert.Equal(size, builder.Count); + } + + [Fact] + public void TinyBody() + { + var bodyBuilder = new BlobBuilder(); + var codeBuilder = new BlobBuilder(); + var branchBuilder = new BranchBuilder(); + var il = new InstructionEncoder(codeBuilder, branchBuilder); + + var bodyEncoder = new MethodBodyEncoder( + bodyBuilder, + maxStack: 2, + exceptionRegionCount: 0, + localVariablesSignature: default(StandaloneSignatureHandle), + attributes: MethodBodyAttributes.None); + + Assert.True(bodyEncoder.IsTiny(10)); + Assert.True(bodyEncoder.IsTiny(63)); + Assert.False(bodyEncoder.IsTiny(64)); + + codeBuilder.WriteBytes(1, 61); + var l1 = il.DefineLabel(); + il.MarkLabel(l1); + + Assert.Equal(61, branchBuilder.Labels.Single()); + + il.Branch(ILOpCode.Br, l1); + + var brInfo = branchBuilder.Branches.Single(); + Assert.Equal(61, brInfo.ILOffset); + Assert.Equal(l1, brInfo.Label); + Assert.Equal((byte)ILOpCode.Br_s, brInfo.ShortOpCode); + + AssertEx.Equal(new byte[] { 1, (byte)ILOpCode.Br_s, unchecked((byte)-1) }, codeBuilder.ToArray(60, 3)); + + int bodyOffset; + bodyEncoder.WriteInstructions(codeBuilder, branchBuilder, out bodyOffset); + + var bodyBytes = bodyBuilder.ToArray(); + + AssertEx.Equal(new byte[] + { + 0xFE, // tiny header + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x2B, 0xFE + }, bodyBytes); + + var body = ReadMethodBody(bodyBytes); + Assert.Equal(0, body.ExceptionRegions.Length); + Assert.Equal(default(StandaloneSignatureHandle), body.LocalSignature); + Assert.Equal(8, body.MaxStack); + Assert.Equal(bodyBytes.Length, body.Size); + + var ilBytes = body.GetILBytes(); + AssertEx.Equal(new byte[] + { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x2B, 0xFE + }, ilBytes); + } + + [Fact] + public void FatBody() + { + var bodyBuilder = new BlobBuilder(); + var codeBuilder = new BlobBuilder(); + var branchBuilder = new BranchBuilder(); + var il = new InstructionEncoder(codeBuilder, branchBuilder); + + var bodyEncoder = new MethodBodyEncoder( + bodyBuilder, + maxStack: 2, + exceptionRegionCount: 0, + localVariablesSignature: default(StandaloneSignatureHandle), + attributes: MethodBodyAttributes.None); + + Assert.True(bodyEncoder.IsTiny(10)); + Assert.True(bodyEncoder.IsTiny(63)); + Assert.False(bodyEncoder.IsTiny(64)); + + codeBuilder.WriteBytes(1, 62); + var l1 = il.DefineLabel(); + il.MarkLabel(l1); + + Assert.Equal(62, branchBuilder.Labels.Single()); + + il.Branch(ILOpCode.Br, l1); + + var brInfo = branchBuilder.Branches.Single(); + Assert.Equal(62, brInfo.ILOffset); + Assert.Equal(l1, brInfo.Label); + Assert.Equal((byte)ILOpCode.Br_s, brInfo.ShortOpCode); + + AssertEx.Equal(new byte[] { 1, 1, (byte)ILOpCode.Br_s, unchecked((byte)-1) }, codeBuilder.ToArray(60, 4)); + + int bodyOffset; + bodyEncoder.WriteInstructions(codeBuilder, branchBuilder, out bodyOffset); + + var bodyBytes = bodyBuilder.ToArray(); + + AssertEx.Equal(new byte[] + { + 0x03, 0x30, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // fat header + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2B, 0xFE + }, bodyBytes); + + var body = ReadMethodBody(bodyBytes); + Assert.Equal(0, body.ExceptionRegions.Length); + Assert.Equal(default(StandaloneSignatureHandle), body.LocalSignature); + Assert.Equal(2, body.MaxStack); + Assert.Equal(bodyBytes.Length, body.Size); + + var ilBytes = body.GetILBytes(); + AssertEx.Equal(new byte[] + { + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x2B, 0xFE + }, ilBytes); + } + + [Fact] + public void Branches1() + { + var branchBuilder = new BranchBuilder(); + + var l0 = branchBuilder.AddLabel(); + var l64 = branchBuilder.AddLabel(); + var l255 = branchBuilder.AddLabel(); + + branchBuilder.MarkLabel(0, l0); + branchBuilder.MarkLabel(64, l64); + branchBuilder.MarkLabel(255, l255); + + branchBuilder.AddBranch(0, l255, (byte)ILOpCode.Bge_s); + branchBuilder.AddBranch(16, l0, (byte)ILOpCode.Bge_un_s); // blob boundary + branchBuilder.AddBranch(33, l255, (byte)ILOpCode.Ble_s); // blob boundary + branchBuilder.AddBranch(35, l0, (byte)ILOpCode.Ble_un_s); // branches immediately next to each other + branchBuilder.AddBranch(37, l255, (byte)ILOpCode.Blt_s); // branches immediately next to each other + branchBuilder.AddBranch(40, l64, (byte)ILOpCode.Blt_un_s); + branchBuilder.AddBranch(254, l0, (byte)ILOpCode.Brfalse_s); // long branch at the end + + var dstBuilder = new BlobBuilder(); + var srcBuilder = new BlobBuilder(size: 17); + WriteFakeILWithBranches(srcBuilder, branchBuilder, size: 256); + + branchBuilder.FixupBranches(srcBuilder, dstBuilder); + + AssertEx.Equal(new byte[] + { + (byte)ILOpCode.Bge, 0xFA, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + (byte)ILOpCode.Bge_un_s, 0xEE, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + (byte)ILOpCode.Ble, 0xD9, 0x00, 0x00, 0x00, + (byte)ILOpCode.Ble_un_s, 0xDB, + (byte)ILOpCode.Blt, 0xD5, 0x00, 0x00, 0x00, + 0x01, + (byte)ILOpCode.Blt_un_s, 0x16, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, + (byte)ILOpCode.Brfalse, 0xFD, 0xFE, 0xFF, 0xFF, + }, dstBuilder.ToArray()); + } + + [Fact] + public void BranchErrors() + { + var codeBuilder = new BlobBuilder(); + + var il = new InstructionEncoder(codeBuilder); + Assert.Throws(() => il.DefineLabel()); + + il = new InstructionEncoder(codeBuilder, new BranchBuilder()); + il.DefineLabel(); + il.DefineLabel(); + var l2 = il.DefineLabel(); + + var branchBuilder = new BranchBuilder(); + il = new InstructionEncoder(codeBuilder, branchBuilder); + var l0 = il.DefineLabel(); + + Assert.Throws(() => il.Branch(ILOpCode.Nop, l0)); + Assert.Throws(() => il.Branch(ILOpCode.Br, default(LabelHandle))); + Assert.Throws(() => il.Branch(ILOpCode.Br, l2)); + } + } +} diff --git a/src/Compilers/Core/CodeAnalysisTest/PEWriter/PEBuilderTests.cs b/src/Compilers/Core/CodeAnalysisTest/PEWriter/PEBuilderTests.cs new file mode 100644 index 0000000000000..a699217dcb672 --- /dev/null +++ b/src/Compilers/Core/CodeAnalysisTest/PEWriter/PEBuilderTests.cs @@ -0,0 +1,432 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.IO; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using Xunit; +using Microsoft.CodeAnalysis.CodeGen; +using ILOpCode = Microsoft.CodeAnalysis.CodeGen.ILOpCode; + +namespace Microsoft.CodeAnalysis.UnitTests +{ + using Roslyn.Reflection; + using Roslyn.Reflection.Metadata; + using Roslyn.Reflection.Metadata.Ecma335; + using Roslyn.Reflection.PortableExecutable; + using Roslyn.Reflection.Metadata.Ecma335.Blobs; + + internal static class BlobEncoderExtensions + { + public static void Parameters(this MethodSignatureEncoder encoder, int parameterCount, Action returnType, Action parameters) + { + ReturnTypeEncoder returnTypeEncoder; + ParametersEncoder parametersEncoder; + encoder.Parameters(parameterCount, out returnTypeEncoder, out parametersEncoder); + returnType(returnTypeEncoder); + parameters(parametersEncoder); + } + } + + public class PEBuilderTests + { + private static void WritePEImage(Stream peStream, MetadataBuilder metadataBuilder, BlobBuilder ilBuilder, MethodDefinitionHandle entryPointHandle) + { + var mappedFieldDataBuilder = new BlobBuilder(); + var managedResourceDataBuilder = new BlobBuilder(); + + var peBuilder = new PEBuilder( + machine: 0, + sectionAlignment: 0x2000, + fileAlignment: 0x200, + imageBase: 0x00400000, + majorLinkerVersion: 0x30, // (what is ref.emit using?) + minorLinkerVersion: 0, + majorOperatingSystemVersion: 4, + minorOperatingSystemVersion: 0, + majorImageVersion: 0, + minorImageVersion: 0, + majorSubsystemVersion: 4, + minorSubsystemVersion: 0, + subsystem: Subsystem.WindowsCui, + dllCharacteristics: DllCharacteristics.DynamicBase | DllCharacteristics.NxCompatible | DllCharacteristics.NoSeh | DllCharacteristics.TerminalServerAware, + imageCharacteristics: entryPointHandle.IsNil ? Characteristics.Dll : Characteristics.ExecutableImage, + sizeOfStackReserve: 0x00100000, + sizeOfStackCommit: 0x1000, + sizeOfHeapReserve: 0x00100000, + sizeOfHeapCommit: 0x1000); + + var peDirectoriesBuilder = new PEDirectoriesBuilder(); + + peBuilder.AddManagedSections( + peDirectoriesBuilder, + new TypeSystemMetadataSerializer(metadataBuilder, "v4.0.30319", isMinimalDelta: false), + ilBuilder, + mappedFieldDataBuilder, + managedResourceDataBuilder, + nativeResourceSectionSerializer: null, + strongNameSignatureSize: 0, + entryPoint: entryPointHandle, + pdbPathOpt: null, + nativePdbContentId: default(ContentId), + portablePdbContentId: default(ContentId), + corFlags: CorFlags.ILOnly); + + var peBlob = new BlobBuilder(); + ContentId peContentId; + peBuilder.Serialize(peBlob, peDirectoriesBuilder, out peContentId); + + peBlob.WriteContentTo(peStream); + } + + [Fact] + public void BasicValidation() + { + using (var peStream = new MemoryStream()) + { + var ilBuilder = new BlobBuilder(); + var metadataBuilder = new MetadataBuilder(); + var entryPoint = BasicValidationEmit(metadataBuilder, ilBuilder); + WritePEImage(peStream, metadataBuilder, ilBuilder, entryPoint); + + peStream.Position = 0; + var r = new PEReader(peStream); + var h = r.PEHeaders; + var mdReader = r.GetMetadataReader(); + } + } + + private static MethodDefinitionHandle BasicValidationEmit(MetadataBuilder metadata, BlobBuilder ilBuilder) + { + metadata.AddModule( + 0, + metadata.GetOrAddString("ConsoleApplication.exe"), + metadata.GetOrAddGuid(Guid.NewGuid()), + default(GuidHandle), + default(GuidHandle)); + + metadata.AddAssembly( + metadata.GetOrAddString("ConsoleApplication"), + version: new Version(0, 0, 0, 0), + culture: default(StringHandle), + publicKey: default(BlobHandle), + flags: default(AssemblyFlags), + hashAlgorithm: AssemblyHashAlgorithm.Sha1); + + var mscorlibAssemblyRef = metadata.AddAssemblyReference( + name: metadata.GetOrAddString("mscorlib"), + version: new Version(4, 0, 0, 0), + culture: default(StringHandle), + publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + flags: default(AssemblyFlags), + hashValue: default(BlobHandle)); + + var systemObjectTypeRef = metadata.AddTypeReference( + mscorlibAssemblyRef, + metadata.GetOrAddString("System"), + metadata.GetOrAddString("Object")); + + var systemConsoleTypeRefHandle = metadata.AddTypeReference( + mscorlibAssemblyRef, + metadata.GetOrAddString("System"), + metadata.GetOrAddString("Console")); + + var consoleWriteLineSignature = new BlobBuilder(); + + new BlobEncoder(consoleWriteLineSignature). + MethodSignature(). + Parameters(1, + returnType => returnType.Void(), + parameters => + { + parameters.AddParameter().Type().String(); + parameters.EndParameters(); + }); + + var consoleWriteLineMemberRef = metadata.AddMemberReference( + systemConsoleTypeRefHandle, + metadata.GetOrAddString("WriteLine"), + metadata.GetOrAddBlob(consoleWriteLineSignature)); + + var parameterlessCtorSignature = new BlobBuilder(); + + new BlobEncoder(parameterlessCtorSignature). + MethodSignature(isInstanceMethod: true). + Parameters(0, returnType => returnType.Void(), parameters => parameters.EndParameters()); + + var parameterlessCtorBlobIndex = metadata.GetOrAddBlob(parameterlessCtorSignature); + + var objectCtorMemberRef = metadata.AddMemberReference( + systemObjectTypeRef, + metadata.GetOrAddString(".ctor"), + parameterlessCtorBlobIndex); + + var mainSignature = new BlobBuilder(); + + new BlobEncoder(mainSignature). + MethodSignature(). + Parameters(0, returnType => returnType.Void(), parameters => parameters.EndParameters()); + + var methodBodies = new MethodBodiesEncoder(ilBuilder); + + var codeBuilder = new BlobBuilder(); + var branchBuilder = new BranchBuilder(); + InstructionEncoder il; + + // + // Program::.ctor + // + int ctorBodyOffset; + il = new InstructionEncoder(codeBuilder); + + // ldarg.0 + il.LoadArgument(0); + + // call instance void [mscorlib]System.Object::.ctor() + il.Call(objectCtorMemberRef); + + // ret + il.OpCode(ILOpCode.Ret); + + methodBodies.AddMethodBody().WriteInstructions(codeBuilder, out ctorBodyOffset); + codeBuilder.Clear(); + + // + // Program::Main + // + int mainBodyOffset; + il = new InstructionEncoder(codeBuilder, branchBuilder); + var endLabel = il.DefineLabel(); + + // .try + int tryOffset = il.Offset; + + // ldstr "hello" + il.LoadString(metadata.GetOrAddUserString("hello")); + + // call void [mscorlib]System.Console::WriteLine(string) + il.Call(consoleWriteLineMemberRef); + + // leave.s END + il.Branch(ILOpCode.Leave, endLabel); + + // .finally + int handlerOffset = il.Offset; + + // ldstr "world" + il.LoadString(metadata.GetOrAddUserString("world")); + + // call void [mscorlib]System.Console::WriteLine(string) + il.Call(consoleWriteLineMemberRef); + + // .endfinally + il.OpCode(ILOpCode.Endfinally); + int handlerEnd = il.Offset; + + // END: + il.MarkLabel(endLabel); + + // ret + il.OpCode(ILOpCode.Ret); + + var body = methodBodies.AddMethodBody(exceptionRegionCount: 1); + var eh = body.WriteInstructions(codeBuilder, branchBuilder, out mainBodyOffset); + eh.StartRegions(); + eh.AddFinally(tryOffset, handlerOffset - tryOffset, handlerOffset, handlerEnd - handlerOffset); + eh.EndRegions(); + + codeBuilder.Clear(); + branchBuilder.Clear(); + + var mainMethodDef = metadata.AddMethodDefinition( + MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig, + MethodImplAttributes.IL | MethodImplAttributes.Managed, + metadata.GetOrAddString("Main"), + metadata.GetOrAddBlob(mainSignature), + mainBodyOffset, + paramList: default(ParameterHandle)); + + var ctorDef = metadata.AddMethodDefinition( + MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, + MethodImplAttributes.IL | MethodImplAttributes.Managed, + metadata.GetOrAddString(".ctor"), + parameterlessCtorBlobIndex, + ctorBodyOffset, + paramList: default(ParameterHandle)); + + metadata.AddTypeDefinition( + default(TypeAttributes), + default(StringHandle), + metadata.GetOrAddString(""), + baseType: default(EntityHandle), + fieldList: MetadataTokens.FieldDefinitionHandle(1), + methodList: mainMethodDef); + + metadata.AddTypeDefinition( + TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit, + metadata.GetOrAddString("ConsoleApplication"), + metadata.GetOrAddString("Program"), + systemObjectTypeRef, + fieldList: MetadataTokens.FieldDefinitionHandle(1), + methodList: mainMethodDef); + + return mainMethodDef; + } + + [Fact] + public void Complex() + { + using (var peStream = new MemoryStream()) + { + var ilBuilder = new BlobBuilder(); + var metadataBuilder = new MetadataBuilder(); + var entryPoint = ComplexEmit(metadataBuilder, ilBuilder); + + WritePEImage(peStream, metadataBuilder, ilBuilder, entryPoint); + + // peStream.Position = 0; + // File.WriteAllBytes(@"c:\temp\test.dll", peStream.ToArray()); + } + } + + private static BlobBuilder BuildSignature(Action action) + { + var builder = new BlobBuilder(); + action(new BlobEncoder(builder)); + return builder; + } + + private static MethodDefinitionHandle ComplexEmit(MetadataBuilder metadata, BlobBuilder ilBuilder) + { + metadata.AddModule( + 0, + metadata.GetOrAddString("ConsoleApplication.exe"), + metadata.GetOrAddGuid(Guid.NewGuid()), + default(GuidHandle), + default(GuidHandle)); + + metadata.AddAssembly( + metadata.GetOrAddString("ConsoleApplication"), + version: new Version(0, 0, 0, 0), + culture: default(StringHandle), + publicKey: default(BlobHandle), + flags: default(AssemblyFlags), + hashAlgorithm: AssemblyHashAlgorithm.Sha1); + + var mscorlibAssemblyRef = metadata.AddAssemblyReference( + name: metadata.GetOrAddString("mscorlib"), + version: new Version(4, 0, 0, 0), + culture: default(StringHandle), + publicKeyOrToken: metadata.GetOrAddBlob(ImmutableArray.Create(0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89)), + flags: default(AssemblyFlags), + hashValue: default(BlobHandle)); + + // TypeRefs: + + var systemObjectTypeRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System"), metadata.GetOrAddString("Object")); + var dictionaryTypeRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System.Collections.Generic"), metadata.GetOrAddString("Dictionary`2")); + var strignBuilderTypeRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System.Text"), metadata.GetOrAddString("StringBuilder")); + var typeTypeRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System"), metadata.GetOrAddString("Type")); + var int32TypeRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System"), metadata.GetOrAddString("Int32")); + var runtimeTypeHandleRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System"), metadata.GetOrAddString("RuntimeTypeHandle")); + var invalidOperationExceptionTypeRef = metadata.AddTypeReference(mscorlibAssemblyRef, metadata.GetOrAddString("System"), metadata.GetOrAddString("InvalidOperationException")); + + // TypeDefs: + + metadata.AddTypeDefinition( + default(TypeAttributes), + default(StringHandle), + metadata.GetOrAddString(""), + baseType: default(EntityHandle), + fieldList: MetadataTokens.FieldDefinitionHandle(1), + methodList: MetadataTokens.MethodDefinitionHandle(1)); + + var baseClassTypeDef = metadata.AddTypeDefinition( + TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit | TypeAttributes.Abstract, + metadata.GetOrAddString("Lib"), + metadata.GetOrAddString("BaseClass"), + systemObjectTypeRef, + fieldList: MetadataTokens.FieldDefinitionHandle(1), + methodList: MetadataTokens.MethodDefinitionHandle(1)); + + var derivedClassTypeDef = metadata.AddTypeDefinition( + TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.AutoLayout | TypeAttributes.BeforeFieldInit, + metadata.GetOrAddString("Lib"), + metadata.GetOrAddString("DerivedClass"), + baseClassTypeDef, + fieldList: MetadataTokens.FieldDefinitionHandle(4), + methodList: MetadataTokens.MethodDefinitionHandle(1)); + + // FieldDefs: + + // Field1 + var baseClassNumberFieldDef = metadata.AddFieldDefinition( + FieldAttributes.Private, + metadata.GetOrAddString("_number"), + metadata.GetOrAddBlob(BuildSignature(e => e.FieldSignature().Int32()))); + + // Field2 + var baseClassNegativeFieldDef = metadata.AddFieldDefinition( + FieldAttributes.Assembly, + metadata.GetOrAddString("negative"), + metadata.GetOrAddBlob(BuildSignature(e => e.FieldSignature().Boolean()))); + + // Field3 + var derivedClassSumCacheFieldDef = metadata.AddFieldDefinition( + FieldAttributes.Assembly, + metadata.GetOrAddString("_sumCache"), + metadata.GetOrAddBlob(BuildSignature(e => + { + var inst = e.FieldSignature().GenericInstantiation(isValueType: false, typeRefDefSpec: dictionaryTypeRef, genericArgumentCount: 2); + inst.AddArgument().Int32(); + inst.AddArgument().Object(); + }))); + + // Field4 + var derivedClassCountFieldDef = metadata.AddFieldDefinition( + FieldAttributes.Assembly, + metadata.GetOrAddString("_count"), + metadata.GetOrAddBlob(BuildSignature(e => e.FieldSignature().SZArray().Int32()))); + + // Field5 + var derivedClassBCFieldDef = metadata.AddFieldDefinition( + FieldAttributes.Assembly, + metadata.GetOrAddString("_bc"), + metadata.GetOrAddBlob(BuildSignature(e => e.FieldSignature().TypeDefOrRefOrSpec(isValueType: false, typeRefDefSpec: baseClassTypeDef)))); + + var methodBodies = new MethodBodiesEncoder(ilBuilder); + + var buffer = new BlobBuilder(); + InstructionEncoder il; + + // + // Foo + // + int fooBodyOffset; + il = new InstructionEncoder(buffer); + + il.LoadString(metadata.GetOrAddUserString("asdsad")); + il.OpCode(ILOpCode.Newobj); + il.Token(invalidOperationExceptionTypeRef); + il.OpCode(ILOpCode.Throw); + + methodBodies.AddMethodBody().WriteInstructions(buffer, out fooBodyOffset); + buffer.Clear(); + + // Method1 + var derivedClassFooMethodDef = metadata.AddMethodDefinition( + MethodAttributes.PrivateScope | MethodAttributes.Private | MethodAttributes.HideBySig, + MethodImplAttributes.IL, + metadata.GetOrAddString("Foo"), + metadata.GetOrAddBlob(BuildSignature(e => + e.MethodSignature(isInstanceMethod: true).Parameters(0, returnType => returnType.Void(), parameters => parameters.EndParameters()))), + fooBodyOffset, + default(ParameterHandle)); + + return default(MethodDefinitionHandle); + } + } +} diff --git a/src/Compilers/Core/CodeAnalysisTest/Win32Res.cs b/src/Compilers/Core/CodeAnalysisTest/Win32Res.cs index 204f9da62f571..0bdef3d833aa3 100644 --- a/src/Compilers/Core/CodeAnalysisTest/Win32Res.cs +++ b/src/Compilers/Core/CodeAnalysisTest/Win32Res.cs @@ -57,7 +57,7 @@ public void BasicResourcesWithStringTypes() public void EnsureResourceSorting() { //confirm that we sort the resources in the order required by the serialization format. - var resources = Microsoft.Cci.PeWriter.SortResources(BuildResources()).ToArray(); + var resources = Cci.NativeResourceWriter.SortResources(BuildResources()).ToArray(); var elem = resources[0]; Assert.Equal("a", elem.TypeName); diff --git a/src/Compilers/Core/Portable/CodeAnalysis.csproj b/src/Compilers/Core/Portable/CodeAnalysis.csproj index 03e67ad88b1f3..931a9d78a3f4b 100644 --- a/src/Compilers/Core/Portable/CodeAnalysis.csproj +++ b/src/Compilers/Core/Portable/CodeAnalysis.csproj @@ -50,6 +50,36 @@ false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CoreClrShim.cs @@ -80,9 +110,11 @@ + + @@ -90,7 +122,6 @@ - @@ -442,13 +473,6 @@ - - - - - - - @@ -468,7 +492,6 @@ - @@ -488,21 +511,17 @@ - - - - @@ -778,7 +797,6 @@ Designer - Designer diff --git a/src/Compilers/Core/Portable/CodeGen/BasicBlock.cs b/src/Compilers/Core/Portable/CodeGen/BasicBlock.cs index ade4512ee1f44..bee41a01682ed 100644 --- a/src/Compilers/Core/Portable/CodeGen/BasicBlock.cs +++ b/src/Compilers/Core/Portable/CodeGen/BasicBlock.cs @@ -6,10 +6,14 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen { + using Roslyn.Reflection; + using Roslyn.Reflection.Metadata; + internal partial class ILBuilder { internal enum BlockType @@ -205,7 +209,7 @@ public BasicBlock BranchBlock public void SetBranchCode(ILOpCode newBranchCode) { Debug.Assert(this.BranchCode.IsConditionalBranch() == newBranchCode.IsConditionalBranch()); - Debug.Assert(newBranchCode.IsBranchToLabel() == (_branchLabel != null)); + Debug.Assert(newBranchCode.IsBranch() == (_branchLabel != null)); this.BranchCode = newBranchCode; } @@ -249,7 +253,7 @@ private bool IsBranchToLabel /// /// Instructions that are not branches. /// - public Cci.BlobBuilder RegularInstructions => _lazyRegularInstructions; + public BlobBuilder RegularInstructions => _lazyRegularInstructions; /// /// The block contains only the final branch or nothing at all @@ -309,7 +313,7 @@ internal void ShortenBranches(ref int delta) } var curBranchCode = this.BranchCode; - if (curBranchCode.BranchOperandSize() == 1) + if (curBranchCode.GetBranchOperandSize() == 1) { return; //already short; } @@ -337,7 +341,7 @@ internal void ShortenBranches(ref int delta) if (unchecked((sbyte)offset == offset)) { //it fits! - this.SetBranchCode(curBranchCode.GetShortOpcode()); + this.SetBranchCode(curBranchCode.GetShortBranch()); delta += reduction; } } @@ -406,7 +410,7 @@ private bool TryOptimizeSameAsNext(BasicBlock next, ref int delta) { if (next.EnclosingHandler == this.EnclosingHandler) { - var diff = this.BranchCode.Size() + this.BranchCode.BranchOperandSize(); + var diff = this.BranchCode.Size() + this.BranchCode.GetBranchOperandSize(); delta -= diff; this.SetBranch(null, ILOpCode.Nop); @@ -467,7 +471,7 @@ private bool TryOptimizeBranchOverUncondBranch(BasicBlock next, ref int delta) if (next.BranchCode == ILOpCode.Br_s) { - revBrOp = revBrOp.GetShortOpcode(); + revBrOp = revBrOp.GetShortBranch(); } // our next block is now where we used to branch @@ -496,7 +500,7 @@ private bool TryOptimizeBranchToNextOrRet(BasicBlock next, ref int delta) // becomes a nop block this.SetBranch(null, ILOpCode.Nop); - delta -= (curBranchCode.Size() + curBranchCode.BranchOperandSize()); + delta -= (curBranchCode.Size() + curBranchCode.GetBranchOperandSize()); return true; } @@ -506,7 +510,7 @@ private bool TryOptimizeBranchToNextOrRet(BasicBlock next, ref int delta) this.SetBranch(null, ILOpCode.Ret); // curBranchCode.Size() + curBranchCode.BranchOperandSize() - Ret.Size() - delta -= (curBranchCode.Size() + curBranchCode.BranchOperandSize() - 1); + delta -= (curBranchCode.Size() + curBranchCode.GetBranchOperandSize() - 1); return true; } } @@ -529,7 +533,7 @@ private bool TryOptimizeBranchToEquivalent(BasicBlock next, ref int delta) this.Writer.WriteByte((byte)ILOpCode.Pop); // curBranchCode.Size() + curBranchCode.BranchOperandSize() - ILOpCode.Pop.Size() - delta -= (curBranchCode.Size() + curBranchCode.BranchOperandSize() - 1); + delta -= (curBranchCode.Size() + curBranchCode.GetBranchOperandSize() - 1); if (curBranchCode.IsRelationalBranch()) { @@ -627,7 +631,7 @@ public virtual int TotalSize default: Debug.Assert(BranchCode.Size() == 1); - branchSize = 1 + BranchCode.BranchOperandSize(); + branchSize = 1 + BranchCode.GetBranchOperandSize(); break; } diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs index d7a57aa66f4d5..e5bde4947b619 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilder.cs @@ -922,7 +922,7 @@ private void RealizeBlocks() int curBlockEnd = block.Start + block.TotalSize; int offset = target - curBlockEnd; - if (block.BranchCode.BranchOperandSize() == 1) + if (block.BranchCode.GetBranchOperandSize() == 1) { sbyte btOffset = (sbyte)offset; Debug.Assert(btOffset == offset); diff --git a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs index 7f612bb89e07d..c181c36beb193 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILBuilderEmit.cs @@ -4,11 +4,15 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen { + using Roslyn.Reflection; + internal partial class ILBuilder { internal void AdjustStack(int stackAdjustment) @@ -127,10 +131,10 @@ internal void MarkLabel(object label) internal void EmitBranch(ILOpCode code, object label, ILOpCode revOpCode = ILOpCode.Nop) { - bool validOpCode = (code == ILOpCode.Nop) || code.IsBranchToLabel(); + bool validOpCode = (code == ILOpCode.Nop) || code.IsBranch(); Debug.Assert(validOpCode); - Debug.Assert(revOpCode == ILOpCode.Nop || revOpCode.IsBranchToLabel()); + Debug.Assert(revOpCode == ILOpCode.Nop || revOpCode.IsBranch()); Debug.Assert(!code.HasVariableStackBehavior()); _emitState.AdjustStack(code.NetStackBehavior()); @@ -705,7 +709,7 @@ private void EmitDouble(double doubleValue) this.GetCurrentWriter().WriteInt64(int64); } - private static void WriteOpCode(Cci.BlobBuilder writer, ILOpCode code) + private static void WriteOpCode(BlobBuilder writer, ILOpCode code) { var size = code.Size(); if (size == 1) @@ -725,7 +729,7 @@ private static void WriteOpCode(Cci.BlobBuilder writer, ILOpCode code) } } - private Cci.BlobBuilder GetCurrentWriter() + private BlobBuilder GetCurrentWriter() { return this.GetCurrentBlock().Writer; } diff --git a/src/Compilers/Core/Portable/CodeGen/ILOpCodeExtensions.cs b/src/Compilers/Core/Portable/CodeGen/ILOpCodeExtensions.cs index b5f43f12bab3a..8f52750bbfee3 100644 --- a/src/Compilers/Core/Portable/CodeGen/ILOpCodeExtensions.cs +++ b/src/Compilers/Core/Portable/CodeGen/ILOpCodeExtensions.cs @@ -1,12 +1,13 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Diagnostics; using System.Reflection.Metadata; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen { - internal static class ILOpCodeExtensions + internal static partial class ILOpCodeExtensions { public static int Size(this ILOpCode opcode) { @@ -23,96 +24,6 @@ public static int Size(this ILOpCode opcode) } } - public static int BranchOperandSize(this ILOpCode opcode) - { - switch (opcode) - { - case ILOpCode.Br_s: - case ILOpCode.Brfalse_s: - case ILOpCode.Brtrue_s: - case ILOpCode.Beq_s: - case ILOpCode.Bge_s: - case ILOpCode.Bgt_s: - case ILOpCode.Ble_s: - case ILOpCode.Blt_s: - case ILOpCode.Bne_un_s: - case ILOpCode.Bge_un_s: - case ILOpCode.Bgt_un_s: - case ILOpCode.Ble_un_s: - case ILOpCode.Blt_un_s: - case ILOpCode.Leave_s: - return 1; - - case ILOpCode.Br: - case ILOpCode.Brfalse: - case ILOpCode.Brtrue: - case ILOpCode.Beq: - case ILOpCode.Bge: - case ILOpCode.Bgt: - case ILOpCode.Ble: - case ILOpCode.Blt: - case ILOpCode.Bne_un: - case ILOpCode.Bge_un: - case ILOpCode.Bgt_un: - case ILOpCode.Ble_un: - case ILOpCode.Blt_un: - case ILOpCode.Leave: - return 4; - } - - throw ExceptionUtilities.UnexpectedValue(opcode); - } - - public static ILOpCode GetShortOpcode(this ILOpCode opcode) - { - switch (opcode) - { - case ILOpCode.Br: - return ILOpCode.Br_s; - - case ILOpCode.Brfalse: - return ILOpCode.Brfalse_s; - - case ILOpCode.Brtrue: - return ILOpCode.Brtrue_s; - - case ILOpCode.Beq: - return ILOpCode.Beq_s; - - case ILOpCode.Bge: - return ILOpCode.Bge_s; - - case ILOpCode.Bgt: - return ILOpCode.Bgt_s; - - case ILOpCode.Ble: - return ILOpCode.Ble_s; - - case ILOpCode.Blt: - return ILOpCode.Blt_s; - - case ILOpCode.Bne_un: - return ILOpCode.Bne_un_s; - - case ILOpCode.Bge_un: - return ILOpCode.Bge_un_s; - - case ILOpCode.Bgt_un: - return ILOpCode.Bgt_un_s; - - case ILOpCode.Ble_un: - return ILOpCode.Ble_un_s; - - case ILOpCode.Blt_un: - return ILOpCode.Blt_un_s; - - case ILOpCode.Leave: - return ILOpCode.Leave_s; - } - - throw ExceptionUtilities.UnexpectedValue(opcode); - } - public static ILOpCode GetLeaveOpcode(this ILOpCode opcode) { switch (opcode) @@ -147,7 +58,7 @@ public static bool HasVariableStackBehavior(this ILOpCode opcode) /// public static bool IsControlTransfer(this ILOpCode opcode) { - if (opcode.IsBranchToLabel()) + if (opcode.IsBranch()) { return true; } @@ -166,46 +77,6 @@ public static bool IsControlTransfer(this ILOpCode opcode) return false; } - /// - /// Opcodes that represents a branch to a label. - /// - public static bool IsBranchToLabel(this ILOpCode opcode) - { - switch (opcode) - { - case ILOpCode.Br: - case ILOpCode.Br_s: - case ILOpCode.Brtrue: - case ILOpCode.Brtrue_s: - case ILOpCode.Brfalse: - case ILOpCode.Brfalse_s: - case ILOpCode.Beq: - case ILOpCode.Beq_s: - case ILOpCode.Bne_un: - case ILOpCode.Bne_un_s: - case ILOpCode.Bge: - case ILOpCode.Bge_s: - case ILOpCode.Bge_un: - case ILOpCode.Bge_un_s: - case ILOpCode.Bgt: - case ILOpCode.Bgt_s: - case ILOpCode.Bgt_un: - case ILOpCode.Bgt_un_s: - case ILOpCode.Ble: - case ILOpCode.Ble_s: - case ILOpCode.Ble_un: - case ILOpCode.Ble_un_s: - case ILOpCode.Blt: - case ILOpCode.Blt_s: - case ILOpCode.Blt_un: - case ILOpCode.Blt_un_s: - case ILOpCode.Leave: - case ILOpCode.Leave_s: - return true; - } - return false; - } - public static bool IsConditionalBranch(this ILOpCode opcode) { switch (opcode) diff --git a/src/Compilers/Core/Portable/CodeGen/LocalConstantDefinition.cs b/src/Compilers/Core/Portable/CodeGen/LocalConstantDefinition.cs index 4ce00e7e20cff..61c7b694d6c36 100644 --- a/src/Compilers/Core/Portable/CodeGen/LocalConstantDefinition.cs +++ b/src/Compilers/Core/Portable/CodeGen/LocalConstantDefinition.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Immutable; using System.Diagnostics; +using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Symbols; namespace Microsoft.CodeAnalysis.CodeGen @@ -57,7 +58,7 @@ public ImmutableArray CustomModifiers public bool IsDynamic => _isDynamic; - public uint PdbAttributes => Cci.PdbWriter.DefaultLocalAttributesValue; + public LocalVariableAttributes PdbAttributes => LocalVariableAttributes.None; public ImmutableArray DynamicTransformFlags => _dynamicTransformFlags; diff --git a/src/Compilers/Core/Portable/CodeGen/LocalDefinition.cs b/src/Compilers/Core/Portable/CodeGen/LocalDefinition.cs index d6a22ac25c0e2..181e80f0cbb97 100644 --- a/src/Compilers/Core/Portable/CodeGen/LocalDefinition.cs +++ b/src/Compilers/Core/Portable/CodeGen/LocalDefinition.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -38,7 +39,7 @@ internal sealed class LocalDefinition : Cci.ILocalDefinition private readonly LocalSlotDebugInfo _slotInfo; /// . - private readonly uint _pdbAttributes; + private readonly LocalVariableAttributes _pdbAttributes; //Gives the synthesized dynamic attributes of the local definition private readonly ImmutableArray _dynamicTransformFlags; @@ -63,7 +64,7 @@ public LocalDefinition( int slot, SynthesizedLocalKind synthesizedKind, LocalDebugId id, - uint pdbAttributes, + LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray dynamicTransformFlags) @@ -128,7 +129,7 @@ public bool IsReference public bool IsDynamic => _isDynamic; - public uint PdbAttributes => _pdbAttributes; + public LocalVariableAttributes PdbAttributes => _pdbAttributes; public ImmutableArray DynamicTransformFlags => _dynamicTransformFlags; diff --git a/src/Compilers/Core/Portable/CodeGen/LocalSlotManager.cs b/src/Compilers/Core/Portable/CodeGen/LocalSlotManager.cs index cac4c81ed5398..9bc2ec152388d 100644 --- a/src/Compilers/Core/Portable/CodeGen/LocalSlotManager.cs +++ b/src/Compilers/Core/Portable/CodeGen/LocalSlotManager.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; +using System.Reflection.Metadata; namespace Microsoft.CodeAnalysis.CodeGen { @@ -124,7 +125,7 @@ internal LocalDefinition DeclareLocal( string name, SynthesizedLocalKind kind, LocalDebugId id, - uint pdbAttributes, + LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray dynamicTransformFlags, @@ -177,7 +178,7 @@ internal LocalDefinition AllocateSlot( nameOpt: null, kind: SynthesizedLocalKind.EmitterTemp, id: LocalDebugId.None, - pdbAttributes: Cci.PdbWriter.HiddenLocalAttributesValue, + pdbAttributes: LocalVariableAttributes.DebuggerHidden, constraints: constraints, isDynamic: false, dynamicTransformFlags: dynamicTransformFlags); @@ -192,7 +193,7 @@ private LocalDefinition DeclareLocalImpl( string nameOpt, SynthesizedLocalKind kind, LocalDebugId id, - uint pdbAttributes, + LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray dynamicTransformFlags) diff --git a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs index cf1716dc103ae..a49b3f95b3da3 100644 --- a/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs +++ b/src/Compilers/Core/Portable/CodeGen/PrivateImplementationDetails.cs @@ -327,7 +327,7 @@ internal MappedField(string name, Cci.INamedTypeDefinition containingType, Cci.I public ImmutableArray MarshallingDescriptor => default(ImmutableArray); - public uint Offset + public int Offset { get { throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/Core/Portable/CodeGen/SignatureOnlyLocalDefinition.cs b/src/Compilers/Core/Portable/CodeGen/SignatureOnlyLocalDefinition.cs index aaeff960f7460..3b48ad8da0226 100644 --- a/src/Compilers/Core/Portable/CodeGen/SignatureOnlyLocalDefinition.cs +++ b/src/Compilers/Core/Portable/CodeGen/SignatureOnlyLocalDefinition.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Immutable; +using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -43,7 +44,7 @@ public ImmutableArray DynamicTransformFlags /// This temp is not interesting to the expression compiler. However, it /// may be replaced by an interesting local in a later stage. /// - public uint PdbAttributes => Cci.PdbWriter.HiddenLocalAttributesValue; + public LocalVariableAttributes PdbAttributes => LocalVariableAttributes.DebuggerHidden; public bool IsDynamic => false; diff --git a/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs b/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs index 7ef00792995bf..4d327279469b4 100644 --- a/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs +++ b/src/Compilers/Core/Portable/CodeGen/SwitchIntegralJumpTableEmitter.cs @@ -399,7 +399,7 @@ private object[] CreateBucketLabels(SwitchBucket switchBucket) private void EmitCondBranchForSwitch(ILOpCode branchCode, ConstantValue constant, object targetLabel) { - Debug.Assert(branchCode.IsBranchToLabel()); + Debug.Assert(branchCode.IsBranch()); Debug.Assert(constant != null && SwitchConstantValueHelper.IsValidSwitchCaseLabelConstant(constant)); Debug.Assert(targetLabel != null); diff --git a/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs b/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs index db0f892243c3d..4853bbcfc66dd 100644 --- a/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/CodeGen/VariableSlotAllocator.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Immutable; +using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Symbols; namespace Microsoft.CodeAnalysis.CodeGen @@ -15,7 +16,7 @@ public abstract LocalDefinition GetPreviousLocal( string nameOpt, SynthesizedLocalKind kind, LocalDebugId id, - uint pdbAttributes, + LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray dynamicTransformFlags); diff --git a/src/Compilers/Core/Portable/Compilation/Compilation.cs b/src/Compilers/Core/Portable/Compilation/Compilation.cs index 0feeea72d37c6..bebb88f5472ee 100644 --- a/src/Compilers/Core/Portable/Compilation/Compilation.cs +++ b/src/Compilers/Core/Portable/Compilation/Compilation.cs @@ -10,6 +10,7 @@ using System.Linq; using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; using System.Text; using System.Threading; @@ -22,6 +23,8 @@ namespace Microsoft.CodeAnalysis { + using Roslyn.Reflection.Metadata.Ecma335; + /// /// The compilation object is an immutable representation of a single invocation of the /// compiler. Although immutable, a compilation is also on-demand, and will realize and cache @@ -1220,21 +1223,18 @@ internal Cci.ModulePropertiesForSerialization ConstructModuleSerializationProper return new Cci.ModulePropertiesForSerialization( persistentIdentifier: moduleVersionId, + corFlags: GetCorHeaderFlags(machine, HasStrongName, prefers32Bit: platform == Platform.AnyCpu32BitPreferred), fileAlignment: fileAlignment, sectionAlignment: Cci.ModulePropertiesForSerialization.DefaultSectionAlignment, targetRuntimeVersion: targetRuntimeVersion, machine: machine, - prefer32Bit: platform == Platform.AnyCpu32BitPreferred, - trackDebugData: false, baseAddress: baseAddress, sizeOfHeapReserve: sizeOfHeapReserve, sizeOfHeapCommit: sizeOfHeapCommit, sizeOfStackReserve: sizeOfStackReserve, sizeOfStackCommit: sizeOfStackCommit, - enableHighEntropyVA: emitOptions.HighEntropyVirtualAddressSpace, - strongNameSigned: HasStrongName, + dllCharacteristics: GetDllCharacteristics(emitOptions.HighEntropyVirtualAddressSpace, compilationOptions.OutputKind == OutputKind.WindowsRuntimeApplication), imageCharacteristics: GetCharacteristics(outputKind, requires32Bit), - configureToExecuteInAppContainer: compilationOptions.OutputKind == OutputKind.WindowsRuntimeApplication, subsystem: GetSubsystem(outputKind), majorSubsystemVersion: (ushort)subsystemVersion.Major, minorSubsystemVersion: (ushort)subsystemVersion.Minor, @@ -1242,6 +1242,50 @@ internal Cci.ModulePropertiesForSerialization ConstructModuleSerializationProper linkerMinorVersion: 0); } + private static CorFlags GetCorHeaderFlags(Machine machine, bool strongNameSigned, bool prefers32Bit) + { + CorFlags result = CorFlags.ILOnly; + + if (machine == Machine.I386) + { + result |= CorFlags.Requires32Bit; + } + + if (strongNameSigned) + { + result |= CorFlags.StrongNameSigned; + } + + if (prefers32Bit) + { + result |= CorFlags.Requires32Bit | CorFlags.Prefers32Bit; + } + + return result; + } + + internal static DllCharacteristics GetDllCharacteristics(bool enableHighEntropyVA, bool configureToExecuteInAppContainer) + { + var result = + DllCharacteristics.DynamicBase | + DllCharacteristics.NxCompatible | + DllCharacteristics.NoSeh | + DllCharacteristics.TerminalServerAware; + + if (enableHighEntropyVA) + { + // IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA + result |= (DllCharacteristics)0x0020; + } + + if (configureToExecuteInAppContainer) + { + result |= DllCharacteristics.AppContainer; + } + + return result; + } + private static Characteristics GetCharacteristics(OutputKind outputKind, bool requires32Bit) { var characteristics = Characteristics.ExecutableImage; @@ -1792,8 +1836,6 @@ internal bool SerializeToPeStream( DiagnosticBag pdbBag = null; Stream peStream = null; Stream portablePdbStream = null; - Stream portablePdbTempStream = null; - Stream peTempStream = null; bool deterministic = IsEmitDeterministic; bool emitPortablePdb = moduleBeingBuilt.EmitOptions.DebugInformationFormat == DebugInformationFormat.PortablePdb; @@ -1834,21 +1876,8 @@ internal bool SerializeToPeStream( } portablePdbStream = pdbStreamProvider.GetOrCreateStream(metadataDiagnostics); - if (portablePdbStream == null) - { - Debug.Assert(metadataDiagnostics.HasAnyErrors()); - return null; - } - - // When in deterministic mode, we need to seek and read the stream to compute a deterministic PDB ID. - // If the underlying stream isn't readable and seekable, we need to use a temp stream. - var retStream = portablePdbStream; - if (!retStream.CanSeek || deterministic && !retStream.CanRead) - { - retStream = portablePdbTempStream = new MemoryStream(); - } - - return retStream; + Debug.Assert(portablePdbStream != null || metadataDiagnostics.HasAnyErrors()); + return portablePdbStream; }; } else @@ -1879,7 +1908,15 @@ internal bool SerializeToPeStream( { Debug.Assert(Options.StrongNameProvider != null); - signingInputStream = Options.StrongNameProvider.CreateInputStream(); + try + { + signingInputStream = Options.StrongNameProvider.CreateInputStream(); + } + catch (IOException e) + { + throw new Cci.PeWritingException(e); + } + retStream = signingInputStream; } else @@ -1888,14 +1925,6 @@ internal bool SerializeToPeStream( retStream = peStream; } - // When in deterministic mode, we need to seek and read the stream to compute a deterministic MVID. - // If the underlying stream isn't readable and seekable, we need to use a temp stream. - if (!retStream.CanSeek || deterministic && !retStream.CanRead) - { - peTempStream = new MemoryStream(); - return peTempStream; - } - return retStream; }; @@ -1912,18 +1941,6 @@ internal bool SerializeToPeStream( deterministic, cancellationToken)) { - if (peTempStream != null) - { - peTempStream.Position = 0; - peTempStream.CopyTo(peStream); - } - - if (portablePdbTempStream != null) - { - portablePdbTempStream.Position = 0; - portablePdbTempStream.CopyTo(portablePdbStream); - } - if (nativePdbWriter != null) { var nativePdbStream = pdbStreamProvider.GetOrCreateStream(metadataDiagnostics); @@ -1981,8 +1998,6 @@ internal bool SerializeToPeStream( finally { nativePdbWriter?.Dispose(); - peTempStream?.Dispose(); - portablePdbTempStream?.Dispose(); signingInputStream?.Dispose(); pdbBag?.Free(); metadataDiagnostics?.Free(); @@ -2023,7 +2038,7 @@ internal EmitBaseline SerializeToDeltaStreams( changes, cancellationToken); - Cci.MetadataSizes metadataSizes; + MetadataSizes metadataSizes; writer.WriteMetadataAndIL(pdbWriter, metadataStream, ilStream, out metadataSizes); writer.GetMethodTokens(updatedMethods); diff --git a/src/Compilers/Core/Portable/ConstantValue.cs b/src/Compilers/Core/Portable/ConstantValue.cs index 64c6485782cf4..9de1817a58e8e 100644 --- a/src/Compilers/Core/Portable/ConstantValue.cs +++ b/src/Compilers/Core/Portable/ConstantValue.cs @@ -2,10 +2,15 @@ using System; using System.Diagnostics; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; +using Roslyn.Reflection; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis { + using Roslyn.Reflection; + internal enum ConstantValueTypeDiscriminator : byte { Nothing, @@ -662,7 +667,7 @@ public bool IsNothing } } - public void Serialize(Cci.BlobBuilder writer) + public void Serialize(BlobBuilder writer) { switch (this.Discriminator) { diff --git a/src/Compilers/Core/Portable/CryptographicHashProvider.cs b/src/Compilers/Core/Portable/CryptographicHashProvider.cs index 72d3f11ccfe1d..2844a1757cc6a 100644 --- a/src/Compilers/Core/Portable/CryptographicHashProvider.cs +++ b/src/Compilers/Core/Portable/CryptographicHashProvider.cs @@ -10,6 +10,8 @@ namespace Microsoft.CodeAnalysis { + using Roslyn.Reflection; + internal abstract class CryptographicHashProvider { private ImmutableArray _lazySHA1Hash; @@ -164,5 +166,13 @@ internal static ImmutableArray ComputeSha1(byte[] bytes) return ImmutableArray.Create(hashProvider.ComputeHash(bytes)); } } + + internal static ImmutableArray ComputeSha1(BlobBuilder bytes) + { + using (var hashProvider = new SHA1CryptoServiceProvider()) + { + return ImmutableArray.Create(hashProvider.ComputeHash(bytes)); + } + } } } diff --git a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs index 25572c3a8fdde..a222ca568deae 100644 --- a/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs +++ b/src/Compilers/Core/Portable/Emit/CommonPEModuleBuilder.cs @@ -765,11 +765,11 @@ bool Cci.IModule.IsPlatformType(Cci.ITypeReference typeRef, Cci.PlatformType pla protected abstract IEnumerable GetAssemblyReferencesFromAddedModules(DiagnosticBag diagnostics); - private IEnumerable _lazyManagedResources; + private ImmutableArray _lazyManagedResources; - IEnumerable Cci.IModule.GetResources(EmitContext context) + ImmutableArray Cci.IModule.GetResources(EmitContext context) { - if (_lazyManagedResources == null) + if (_lazyManagedResources.IsDefault) { var builder = ArrayBuilder.GetInstance(); diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs index 067edb6c63195..85fb7d8ca968b 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DeltaMetadataWriter.cs @@ -10,12 +10,13 @@ using System.Threading; using Microsoft.Cci; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeGen; using Roslyn.Utilities; -using MetadataSizes = Microsoft.Cci.MetadataSizes; namespace Microsoft.CodeAnalysis.Emit { + using Roslyn.Reflection.Metadata.Ecma335; + using Roslyn.Reflection.Metadata.Ecma335.Blobs; + internal sealed class DeltaMetadataWriter : MetadataWriter { private readonly EmitBaseline _previousGeneration; @@ -41,7 +42,7 @@ internal sealed class DeltaMetadataWriter : MetadataWriter private readonly InstanceAndStructuralReferenceIndex _methodSpecIndex; private readonly HeapOrReferenceIndex _typeRefIndex; private readonly InstanceAndStructuralReferenceIndex _typeSpecIndex; - private readonly HeapOrReferenceIndex _standAloneSignatureIndex; + private readonly HeapOrReferenceIndex _standAloneSignatureIndex; private readonly Dictionary _addedOrChangedMethods; public DeltaMetadataWriter( @@ -52,7 +53,7 @@ public DeltaMetadataWriter( DefinitionMap definitionMap, SymbolChanges changes, CancellationToken cancellationToken) - : base(MakeHeapsBuilder(previousGeneration), null, context, messageProvider, false, false, cancellationToken) + : base(MakeTablesBuilder(previousGeneration), null, context, messageProvider, false, false, cancellationToken) { Debug.Assert(previousGeneration != null); Debug.Assert(encId != default(Guid)); @@ -83,14 +84,14 @@ public DeltaMetadataWriter( _methodSpecIndex = new InstanceAndStructuralReferenceIndex(this, new MethodSpecComparer(this), lastRowId: sizes[(int)TableIndex.MethodSpec]); _typeRefIndex = new HeapOrReferenceIndex(this, lastRowId: sizes[(int)TableIndex.TypeRef]); _typeSpecIndex = new InstanceAndStructuralReferenceIndex(this, new TypeSpecComparer(this), lastRowId: sizes[(int)TableIndex.TypeSpec]); - _standAloneSignatureIndex = new HeapOrReferenceIndex(this, lastRowId: sizes[(int)TableIndex.StandAloneSig]); + _standAloneSignatureIndex = new HeapOrReferenceIndex(this, lastRowId: sizes[(int)TableIndex.StandAloneSig]); _addedOrChangedMethods = new Dictionary(); } - private static MetadataHeapsBuilder MakeHeapsBuilder(EmitBaseline previousGeneration) + private static MetadataBuilder MakeTablesBuilder(EmitBaseline previousGeneration) { - return new MetadataHeapsBuilder( + return new MetadataBuilder( previousGeneration.UserStringStreamLength, previousGeneration.StringStreamLength, previousGeneration.BlobStreamLength, @@ -131,7 +132,7 @@ internal EmitBaseline GetDelta(EmitBaseline baseline, Compilation compilation, G var addedOrChangedMethodsByIndex = new Dictionary(); foreach (var pair in _addedOrChangedMethods) { - addedOrChangedMethodsByIndex.Add(this.GetMethodDefIndex(pair.Key), pair.Value); + addedOrChangedMethodsByIndex.Add(MetadataTokens.GetRowNumber(GetMethodDefinitionHandle(pair.Key)), pair.Value); } var previousTableSizes = _previousGeneration.TableEntriesAdded; @@ -232,9 +233,9 @@ protected override Guid EncBaseId get { return _previousGeneration.EncId; } } - protected override int GetEventDefIndex(IEventDefinition def) + protected override EventDefinitionHandle GetEventDefinitionHandle(IEventDefinition def) { - return _eventDefs[def]; + return MetadataTokens.EventDefinitionHandle(_eventDefs[def]); } protected override IReadOnlyList GetEventDefs() @@ -242,9 +243,9 @@ protected override IReadOnlyList GetEventDefs() return _eventDefs.GetRows(); } - protected override int GetFieldDefIndex(IFieldDefinition def) + protected override FieldDefinitionHandle GetFieldDefinitionHandle(IFieldDefinition def) { - return _fieldDefs[def]; + return MetadataTokens.FieldDefinitionHandle(_fieldDefs[def]); } protected override IReadOnlyList GetFieldDefs() @@ -252,19 +253,22 @@ protected override IReadOnlyList GetFieldDefs() return _fieldDefs.GetRows(); } - protected override bool TryGetTypeDefIndex(ITypeDefinition def, out int index) + protected override bool TryGetTypeDefinitionHandle(ITypeDefinition def, out TypeDefinitionHandle handle) { - return _typeDefs.TryGetValue(def, out index); + int index; + bool result = _typeDefs.TryGetValue(def, out index); + handle = MetadataTokens.TypeDefinitionHandle(index); + return result; } - protected override int GetTypeDefIndex(ITypeDefinition def) + protected override TypeDefinitionHandle GetTypeDefinitionHandle(ITypeDefinition def) { - return _typeDefs[def]; + return MetadataTokens.TypeDefinitionHandle(_typeDefs[def]); } - protected override ITypeDefinition GetTypeDef(int index) + protected override ITypeDefinition GetTypeDef(TypeDefinitionHandle handle) { - return _typeDefs[index]; + return _typeDefs[MetadataTokens.GetRowNumber(handle)]; } protected override IReadOnlyList GetTypeDefs() @@ -272,19 +276,22 @@ protected override IReadOnlyList GetTypeDefs() return _typeDefs.GetRows(); } - protected override bool TryGetMethodDefIndex(IMethodDefinition def, out int index) + protected override bool TryGetMethodDefinitionHandle(IMethodDefinition def, out MethodDefinitionHandle handle) { - return _methodDefs.TryGetValue(def, out index); + int index; + bool result = _methodDefs.TryGetValue(def, out index); + handle = MetadataTokens.MethodDefinitionHandle(index); + return result; } - protected override int GetMethodDefIndex(IMethodDefinition def) + protected override MethodDefinitionHandle GetMethodDefinitionHandle(IMethodDefinition def) { - return _methodDefs[def]; + return MetadataTokens.MethodDefinitionHandle(_methodDefs[def]); } - protected override IMethodDefinition GetMethodDef(int index) + protected override IMethodDefinition GetMethodDef(MethodDefinitionHandle index) { - return _methodDefs[index]; + return _methodDefs[MetadataTokens.GetRowNumber(index)]; } protected override IReadOnlyList GetMethodDefs() @@ -292,9 +299,9 @@ protected override IReadOnlyList GetMethodDefs() return _methodDefs.GetRows(); } - protected override int GetPropertyDefIndex(IPropertyDefinition def) + protected override PropertyDefinitionHandle GetPropertyDefIndex(IPropertyDefinition def) { - return _propertyDefs[def]; + return MetadataTokens.PropertyDefinitionHandle(_propertyDefs[def]); } protected override IReadOnlyList GetPropertyDefs() @@ -302,9 +309,9 @@ protected override IReadOnlyList GetPropertyDefs() return _propertyDefs.GetRows(); } - protected override int GetParameterDefIndex(IParameterDefinition def) + protected override ParameterHandle GetParameterHandle(IParameterDefinition def) { - return _parameterDefs[def]; + return MetadataTokens.ParameterHandle(_parameterDefs[def]); } protected override IReadOnlyList GetParameterDefs() @@ -317,28 +324,28 @@ protected override IReadOnlyList GetGenericParameters() return _genericParameters.GetRows(); } - protected override int GetFieldDefIndex(INamedTypeDefinition typeDef) + protected override FieldDefinitionHandle GetFirstFieldDefinitionHandle(INamedTypeDefinition typeDef) { // Fields are associated with the // type through the EncLog table. - return 0; + return default(FieldDefinitionHandle); } - protected override int GetMethodDefIndex(INamedTypeDefinition typeDef) + protected override MethodDefinitionHandle GetFirstMethodDefinitionHandle(INamedTypeDefinition typeDef) { // Methods are associated with the // type through the EncLog table. - return 0; + return default(MethodDefinitionHandle); } - protected override int GetParameterDefIndex(IMethodDefinition methodDef) + protected override ParameterHandle GetFirstParameterHandle(IMethodDefinition methodDef) { // Parameters are associated with the // method through the EncLog table. - return 0; + return default(ParameterHandle); } - protected override int GetOrAddAssemblyRefIndex(IAssemblyReference reference) + protected override AssemblyReferenceHandle GetOrAddAssemblyReferenceHandle(IAssemblyReference reference) { var identity = reference.Identity; var versionPattern = reference.AssemblyVersionPattern; @@ -348,7 +355,7 @@ protected override int GetOrAddAssemblyRefIndex(IAssemblyReference reference) identity = _previousGeneration.InitialBaseline.LazyMetadataSymbols.AssemblyReferenceIdentityMap[identity.WithVersion(versionPattern)]; } - return _assemblyRefIndex.GetOrAdd(identity); + return MetadataTokens.AssemblyReferenceHandle(_assemblyRefIndex.GetOrAdd(identity)); } protected override IReadOnlyList GetAssemblyRefs() @@ -356,9 +363,9 @@ protected override IReadOnlyList GetAssemblyRefs() return _assemblyRefIndex.Rows; } - protected override int GetOrAddModuleRefIndex(string reference) + protected override ModuleReferenceHandle GetOrAddModuleReferenceHandle(string reference) { - return _moduleRefIndex.GetOrAdd(reference); + return MetadataTokens.ModuleReferenceHandle(_moduleRefIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetModuleRefs() @@ -366,9 +373,9 @@ protected override IReadOnlyList GetModuleRefs() return _moduleRefIndex.Rows; } - protected override int GetOrAddMemberRefIndex(ITypeMemberReference reference) + protected override MemberReferenceHandle GetOrAddMemberReferenceHandle(ITypeMemberReference reference) { - return _memberRefIndex.GetOrAdd(reference); + return MetadataTokens.MemberReferenceHandle(_memberRefIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetMemberRefs() @@ -376,9 +383,9 @@ protected override IReadOnlyList GetMemberRefs() return _memberRefIndex.Rows; } - protected override int GetOrAddMethodSpecIndex(IGenericMethodInstanceReference reference) + protected override MethodSpecificationHandle GetOrAddMethodSpecificationHandle(IGenericMethodInstanceReference reference) { - return _methodSpecIndex.GetOrAdd(reference); + return MetadataTokens.MethodSpecificationHandle(_methodSpecIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetMethodSpecs() @@ -386,14 +393,17 @@ protected override IReadOnlyList GetMethodSpecs return _methodSpecIndex.Rows; } - protected override bool TryGetTypeRefIndex(ITypeReference reference, out int index) + protected override bool TryGetTypeRefeferenceHandle(ITypeReference reference, out TypeReferenceHandle handle) { - return _typeRefIndex.TryGetValue(reference, out index); + int index; + bool result = _typeRefIndex.TryGetValue(reference, out index); + handle = MetadataTokens.TypeReferenceHandle(index); + return result; } - protected override int GetOrAddTypeRefIndex(ITypeReference reference) + protected override TypeReferenceHandle GetOrAddTypeReferenceHandle(ITypeReference reference) { - return _typeRefIndex.GetOrAdd(reference); + return MetadataTokens.TypeReferenceHandle(_typeRefIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetTypeRefs() @@ -401,9 +411,9 @@ protected override IReadOnlyList GetTypeRefs() return _typeRefIndex.Rows; } - protected override int GetOrAddTypeSpecIndex(ITypeReference reference) + protected override TypeSpecificationHandle GetOrAddTypeSpecificationHandle(ITypeReference reference) { - return _typeSpecIndex.GetOrAdd(reference); + return MetadataTokens.TypeSpecificationHandle(_typeSpecIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetTypeSpecs() @@ -411,12 +421,12 @@ protected override IReadOnlyList GetTypeSpecs() return _typeSpecIndex.Rows; } - protected override int GetOrAddStandAloneSignatureIndex(BlobIdx blobIndex) + protected override StandaloneSignatureHandle GetOrAddStandaloneSignatureHandle(BlobHandle blobIndex) { - return _standAloneSignatureIndex.GetOrAdd(blobIndex); + return MetadataTokens.StandaloneSignatureHandle(_standAloneSignatureIndex.GetOrAdd(blobIndex)); } - protected override IReadOnlyList GetStandAloneSignatures() + protected override IReadOnlyList GetStandaloneSignatureBlobHandles() { return _standAloneSignatureIndex.Rows; } @@ -609,17 +619,16 @@ private void ReportReferencesToAddedSymbol(ISymbol symbolOpt) } } - protected override int SerializeLocalVariablesSignature(IMethodBody body) + protected override StandaloneSignatureHandle SerializeLocalVariablesSignature(IMethodBody body) { - int localSignatureRowId; + StandaloneSignatureHandle localSignatureHandle; var localVariables = body.LocalVariables; var encInfos = ArrayBuilder.GetInstance(); if (localVariables.Length > 0) { var writer = PooledBlobBuilder.GetInstance(); - writer.WriteByte(0x07); - writer.WriteCompressedInteger((uint)localVariables.Length); + var encoder = new BlobEncoder(writer).LocalVariableSignature(localVariables.Length); foreach (ILocalDefinition local in localVariables) { @@ -627,7 +636,7 @@ protected override int SerializeLocalVariablesSignature(IMethodBody body) if (signature == null) { int start = writer.Position; - this.SerializeLocalVariableSignature(writer, local); + SerializeLocalVariableType(encoder.AddVariable(), local); signature = writer.ToArray(start, writer.Position - start); } else @@ -637,14 +646,17 @@ protected override int SerializeLocalVariablesSignature(IMethodBody body) encInfos.Add(CreateEncLocalInfo(local, signature)); } - - BlobIdx blobIndex = heaps.GetBlobIndex(writer); - localSignatureRowId = GetOrAddStandAloneSignatureIndex(blobIndex); + + encoder.EndVariables(); + + BlobHandle blobIndex = metadata.GetOrAddBlob(writer); + + localSignatureHandle = GetOrAddStandaloneSignatureHandle(blobIndex); writer.Free(); } else { - localSignatureRowId = 0; + localSignatureHandle = default(StandaloneSignatureHandle); } var method = body.MethodDefinition; @@ -663,7 +675,7 @@ protected override int SerializeLocalVariablesSignature(IMethodBody body) } encInfos.Free(); - return localSignatureRowId; + return localSignatureHandle; } private EncLocalInfo CreateEncLocalInfo(ILocalDefinition localDef, byte[] signature) @@ -684,7 +696,7 @@ private EncLocalInfo CreateEncLocalInfo(ILocalDefinition localDef, byte[] signat return new EncLocalInfo(localDef.SlotInfo, translatedType, localDef.Constraints, signature); } - protected override void PopulateEncLogTableRows(List table, ImmutableArray rowCounts) + protected override void PopulateEncLogTableRows(ImmutableArray rowCounts) { // The EncLog table is a log of all the operations needed // to update the previous metadata. That means all @@ -692,47 +704,46 @@ protected override void PopulateEncLogTableRows(List table, Immutable var previousSizes = _previousGeneration.TableSizes; var deltaSizes = this.GetDeltaTableSizes(rowCounts); - PopulateEncLogTableRows(table, TableIndex.AssemblyRef, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.ModuleRef, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.MemberRef, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.MethodSpec, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.TypeRef, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.TypeSpec, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.StandAloneSig, previousSizes, deltaSizes); - - PopulateEncLogTableRows(table, _typeDefs, TokenTypeIds.TypeDef); - PopulateEncLogTableRows(table, TableIndex.EventMap, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.PropertyMap, previousSizes, deltaSizes); - - PopulateEncLogTableEventsOrProperties(table, _eventDefs, TokenTypeIds.Event, EncFuncCode.AddEvent, _eventMap, TokenTypeIds.EventMap); - PopulateEncLogTableFieldsOrMethods(table, _fieldDefs, TokenTypeIds.FieldDef, EncFuncCode.AddField); - PopulateEncLogTableFieldsOrMethods(table, _methodDefs, TokenTypeIds.MethodDef, EncFuncCode.AddMethod); - PopulateEncLogTableEventsOrProperties(table, _propertyDefs, TokenTypeIds.Property, EncFuncCode.AddProperty, _propertyMap, TokenTypeIds.PropertyMap); - - PopulateEncLogTableParameters(table); - - PopulateEncLogTableRows(table, TableIndex.Constant, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.CustomAttribute, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.DeclSecurity, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.ClassLayout, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.FieldLayout, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.MethodSemantics, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.MethodImpl, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.ImplMap, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.FieldRva, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.NestedClass, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.GenericParam, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.InterfaceImpl, previousSizes, deltaSizes); - PopulateEncLogTableRows(table, TableIndex.GenericParamConstraint, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.AssemblyRef, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.ModuleRef, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.MemberRef, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.MethodSpec, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.TypeRef, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.TypeSpec, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.StandAloneSig, previousSizes, deltaSizes); + + PopulateEncLogTableRows(_typeDefs, TableIndex.TypeDef); + PopulateEncLogTableRows(TableIndex.EventMap, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.PropertyMap, previousSizes, deltaSizes); + + PopulateEncLogTableEventsOrProperties(_eventDefs, TableIndex.Event, EditAndContinueOperation.AddEvent, _eventMap, TableIndex.EventMap); + PopulateEncLogTableFieldsOrMethods(_fieldDefs, TableIndex.Field, EditAndContinueOperation.AddField); + PopulateEncLogTableFieldsOrMethods(_methodDefs, TableIndex.MethodDef, EditAndContinueOperation.AddMethod); + PopulateEncLogTableEventsOrProperties(_propertyDefs, TableIndex.Property, EditAndContinueOperation.AddProperty, _propertyMap, TableIndex.PropertyMap); + + PopulateEncLogTableParameters(); + + PopulateEncLogTableRows(TableIndex.Constant, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.CustomAttribute, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.DeclSecurity, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.ClassLayout, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.FieldLayout, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.MethodSemantics, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.MethodImpl, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.ImplMap, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.FieldRva, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.NestedClass, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.GenericParam, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.InterfaceImpl, previousSizes, deltaSizes); + PopulateEncLogTableRows(TableIndex.GenericParamConstraint, previousSizes, deltaSizes); } private void PopulateEncLogTableEventsOrProperties( - List table, DefinitionIndex index, - int tokenType, - EncFuncCode addCode, + TableIndex table, + EditAndContinueOperation addCode, EventOrPropertyMapIndex map, - int mapTokenType) + TableIndex mapTable) where T : ITypeDefinitionMember { foreach (var member in index.GetRows()) @@ -742,88 +753,92 @@ private void PopulateEncLogTableEventsOrProperties( int typeIndex = _typeDefs[member.ContainingTypeDefinition]; Debug.Assert(typeIndex > 0); - int mapIndex; - var ok = map.TryGetValue(typeIndex, out mapIndex); + int mapRowId; + var ok = map.TryGetValue(typeIndex, out mapRowId); Debug.Assert(ok); - int mapToken = mapTokenType | mapIndex; - table.Add(new EncLogRow() { Token = (uint)mapToken, FuncCode = addCode }); + metadata.AddEncLogEntry( + entity: MetadataTokens.Handle(mapTable, mapRowId), + code: addCode); } - int token = tokenType | index[member]; - table.Add(new EncLogRow() { Token = (uint)token, FuncCode = EncFuncCode.Default }); + metadata.AddEncLogEntry( + entity: MetadataTokens.Handle(table, index[member]), + code: EditAndContinueOperation.Default); } } private void PopulateEncLogTableFieldsOrMethods( - List table, DefinitionIndex index, - int tokenType, - EncFuncCode addCode) + TableIndex tableIndex, + EditAndContinueOperation addCode) where T : ITypeDefinitionMember { foreach (var member in index.GetRows()) { if (index.IsAddedNotChanged(member)) { - int typeToken = TokenTypeIds.TypeDef | _typeDefs[(INamedTypeDefinition)member.ContainingTypeDefinition]; - table.Add(new EncLogRow() { Token = (uint)typeToken, FuncCode = addCode }); + metadata.AddEncLogEntry( + entity: MetadataTokens.TypeDefinitionHandle(_typeDefs[(INamedTypeDefinition)member.ContainingTypeDefinition]), + code: addCode); } - int token = tokenType | index[member]; - table.Add(new EncLogRow() { Token = (uint)token, FuncCode = EncFuncCode.Default }); + metadata.AddEncLogEntry( + entity: MetadataTokens.Handle(tableIndex, index[member]), + code: EditAndContinueOperation.Default); } } - private void PopulateEncLogTableParameters(List table) + private void PopulateEncLogTableParameters() { var parameterFirstId = _parameterDefs.FirstRowId; for (int i = 0; i < _parameterDefList.Count; i++) { var methodDef = _parameterDefList[i].Key; - int methodToken = TokenTypeIds.MethodDef | _methodDefs[methodDef]; - table.Add(new EncLogRow() { Token = (uint)methodToken, FuncCode = EncFuncCode.AddParameter }); - int paramRowId = parameterFirstId + i; - int token = TokenTypeIds.ParamDef | paramRowId; - table.Add(new EncLogRow() { Token = (uint)token, FuncCode = EncFuncCode.Default }); + metadata.AddEncLogEntry( + entity: MetadataTokens.MethodDefinitionHandle(_methodDefs[methodDef]), + code: EditAndContinueOperation.AddParameter); + + metadata.AddEncLogEntry( + entity: MetadataTokens.ParameterHandle(parameterFirstId + i), + code: EditAndContinueOperation.Default); } } - private static void PopulateEncLogTableRows(List table, DefinitionIndex index, int tokenType) + private void PopulateEncLogTableRows(DefinitionIndex index, TableIndex tableIndex) where T : IDefinition { foreach (var member in index.GetRows()) { - int token = tokenType | index[member]; - table.Add(new EncLogRow() { Token = (uint)token, FuncCode = EncFuncCode.Default }); + metadata.AddEncLogEntry( + entity: MetadataTokens.Handle(tableIndex, index[member]), + code: EditAndContinueOperation.Default); } } - private static void PopulateEncLogTableRows( - List table, - TableIndex tableIndex, - ImmutableArray previousSizes, - ImmutableArray deltaSizes) + private void PopulateEncLogTableRows(TableIndex tableIndex, ImmutableArray previousSizes, ImmutableArray deltaSizes) { - PopulateEncLogTableRows(table, ((uint)tableIndex) << 24, (uint)previousSizes[(int)tableIndex] + 1, deltaSizes[(int)tableIndex]); + PopulateEncLogTableRows(tableIndex, previousSizes[(int)tableIndex] + 1, deltaSizes[(int)tableIndex]); } - private static void PopulateEncLogTableRows(List table, uint tokenType, uint firstRowId, int nTokens) + private void PopulateEncLogTableRows(TableIndex tableIndex, int firstRowId, int tokenCount) { - for (int i = 0; i < nTokens; i++) + for (int i = 0; i < tokenCount; i++) { - table.Add(new EncLogRow() { Token = tokenType | (firstRowId + (uint)i), FuncCode = EncFuncCode.Default }); + metadata.AddEncLogEntry( + entity: MetadataTokens.Handle(tableIndex, firstRowId + i), + code: EditAndContinueOperation.Default); } } - protected override void PopulateEncMapTableRows(List table, ImmutableArray rowCounts) + protected override void PopulateEncMapTableRows(ImmutableArray rowCounts) { // The EncMap table maps from offset in each table in the delta // metadata to token. As such, the EncMap is a concatenated // list of all tokens in all tables from the delta sorted by table // and, within each table, sorted by row. - var tokens = ArrayBuilder.GetInstance(); + var tokens = ArrayBuilder.GetInstance(); var previousSizes = _previousGeneration.TableSizes; var deltaSizes = this.GetDeltaTableSizes(rowCounts); @@ -835,11 +850,11 @@ protected override void PopulateEncMapTableRows(List table, Immutable AddReferencedTokens(tokens, TableIndex.TypeSpec, previousSizes, deltaSizes); AddReferencedTokens(tokens, TableIndex.StandAloneSig, previousSizes, deltaSizes); - AddDefinitionTokens(tokens, _typeDefs, TokenTypeIds.TypeDef); - AddDefinitionTokens(tokens, _eventDefs, TokenTypeIds.Event); - AddDefinitionTokens(tokens, _fieldDefs, TokenTypeIds.FieldDef); - AddDefinitionTokens(tokens, _methodDefs, TokenTypeIds.MethodDef); - AddDefinitionTokens(tokens, _propertyDefs, TokenTypeIds.Property); + AddDefinitionTokens(tokens, _typeDefs, TableIndex.TypeDef); + AddDefinitionTokens(tokens, _eventDefs, TableIndex.Event); + AddDefinitionTokens(tokens, _fieldDefs, TableIndex.Field); + AddDefinitionTokens(tokens, _methodDefs, TableIndex.MethodDef); + AddDefinitionTokens(tokens, _propertyDefs, TableIndex.Property); AddReferencedTokens(tokens, TableIndex.Param, previousSizes, deltaSizes); AddReferencedTokens(tokens, TableIndex.Constant, previousSizes, deltaSizes); @@ -858,14 +873,14 @@ protected override void PopulateEncMapTableRows(List table, Immutable AddReferencedTokens(tokens, TableIndex.InterfaceImpl, previousSizes, deltaSizes); AddReferencedTokens(tokens, TableIndex.GenericParamConstraint, previousSizes, deltaSizes); - tokens.Sort(); + tokens.Sort(HandleComparer.Default); // Should not be any duplicates. Debug.Assert(tokens.Distinct().Count() == tokens.Count); foreach (var token in tokens) { - table.Add(new EncMapRow() { Token = (uint)token }); + metadata.AddEncMapEntry(token); } tokens.Free(); @@ -926,50 +941,48 @@ protected override void PopulateEncMapTableRows(List table, Immutable } private static void AddReferencedTokens( - ArrayBuilder builder, + ArrayBuilder builder, TableIndex tableIndex, ImmutableArray previousSizes, ImmutableArray deltaSizes) { - AddReferencedTokens(builder, (int)tableIndex << 24, previousSizes[(int)tableIndex] + 1, deltaSizes[(int)tableIndex]); + AddReferencedTokens(builder, tableIndex, previousSizes[(int)tableIndex] + 1, deltaSizes[(int)tableIndex]); } - private static void AddReferencedTokens(ArrayBuilder builder, int tokenType, int firstRowId, int nTokens) + private static void AddReferencedTokens(ArrayBuilder builder, TableIndex tableIndex, int firstRowId, int nTokens) { for (int i = 0; i < nTokens; i++) { - builder.Add(tokenType | (firstRowId + i)); + builder.Add(MetadataTokens.Handle(tableIndex, firstRowId + i)); } } - private static void AddDefinitionTokens(ArrayBuilder tokens, DefinitionIndex index, int tokenType) + private static void AddDefinitionTokens(ArrayBuilder tokens, DefinitionIndex index, TableIndex tableIndex) where T : IDefinition { foreach (var member in index.GetRows()) { - tokens.Add(tokenType | index[member]); + tokens.Add(MetadataTokens.Handle(tableIndex, index[member])); } } - protected override void PopulateEventMapTableRows(List table) + protected override void PopulateEventMapTableRows() { foreach (var typeId in _eventMap.GetRows()) { - var r = new EventMapRow(); - r.Parent = (uint)typeId; - r.EventList = (uint)_eventMap[typeId]; - table.Add(r); + metadata.AddEventMap( + declaringType: MetadataTokens.TypeDefinitionHandle(typeId), + eventList: MetadataTokens.EventDefinitionHandle(_eventMap[typeId])); } } - protected override void PopulatePropertyMapTableRows(List table) + protected override void PopulatePropertyMapTableRows() { foreach (var typeId in _propertyMap.GetRows()) { - var r = new PropertyMapRow(); - r.Parent = (uint)typeId; - r.PropertyList = (uint)_propertyMap[typeId]; - table.Add(r); + metadata.AddPropertyMap( + declaringType: MetadataTokens.TypeDefinitionHandle(typeId), + propertyList: MetadataTokens.PropertyDefinitionHandle(_propertyMap[typeId])); } } @@ -1095,11 +1108,10 @@ public override bool TryGetValue(T item, out int index) return false; } - public T this[int index] + public T this[int rowId] { get { - int rowId = index + 1; return _map[rowId]; } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs index 18cf8b2c50140..b1c87c8feacec 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Reflection.Metadata; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -135,7 +136,7 @@ public override LocalDefinition GetPreviousLocal( string nameOpt, SynthesizedLocalKind kind, LocalDebugId id, - uint pdbAttributes, + LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray dynamicTransformFlags) diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs b/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs index bad69dec05eb2..3fe9152cadb7c 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinueMethodDebugInformation.cs @@ -5,11 +5,15 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using Microsoft.CodeAnalysis.CodeGen; namespace Microsoft.CodeAnalysis.Emit { + using Roslyn.Reflection; + /// /// Debugging information associated with the specified method that is emitted by the compiler to support Edit and Continue. /// @@ -121,7 +125,7 @@ private unsafe static ImmutableArray UncompressSlotMap(Immut return mapBuilder.ToImmutableAndFree(); } - internal void SerializeLocalSlots(Cci.BlobBuilder writer) + internal void SerializeLocalSlots(BlobBuilder writer) { int syntaxOffsetBaseline = -1; foreach (LocalSlotDebugInfo localSlot in this.LocalSlots) @@ -135,7 +139,7 @@ internal void SerializeLocalSlots(Cci.BlobBuilder writer) if (syntaxOffsetBaseline != -1) { writer.WriteByte(SyntaxOffsetBaseline); - writer.WriteCompressedInteger((uint)(-syntaxOffsetBaseline)); + writer.WriteCompressedInteger(-syntaxOffsetBaseline); } foreach (LocalSlotDebugInfo localSlot in this.LocalSlots) @@ -160,11 +164,11 @@ internal void SerializeLocalSlots(Cci.BlobBuilder writer) } writer.WriteByte(b); - writer.WriteCompressedInteger((uint)(localSlot.Id.SyntaxOffset - syntaxOffsetBaseline)); + writer.WriteCompressedInteger(localSlot.Id.SyntaxOffset - syntaxOffsetBaseline); if (hasOrdinal) { - writer.WriteCompressedInteger((uint)localSlot.Id.Ordinal); + writer.WriteCompressedInteger(localSlot.Id.Ordinal); } } } @@ -237,10 +241,10 @@ private unsafe static void UncompressLambdaMap( lambdas = lambdasBuilder.ToImmutableAndFree(); } - internal void SerializeLambdaMap(Cci.BlobBuilder writer) + internal void SerializeLambdaMap(BlobBuilder writer) { Debug.Assert(this.MethodOrdinal >= -1); - writer.WriteCompressedInteger((uint)(this.MethodOrdinal + 1)); + writer.WriteCompressedInteger(this.MethodOrdinal + 1); int syntaxOffsetBaseline = -1; foreach (ClosureDebugInfo info in this.Closures) @@ -259,12 +263,12 @@ internal void SerializeLambdaMap(Cci.BlobBuilder writer) } } - writer.WriteCompressedInteger((uint)(-syntaxOffsetBaseline)); - writer.WriteCompressedInteger((uint)this.Closures.Length); + writer.WriteCompressedInteger(-syntaxOffsetBaseline); + writer.WriteCompressedInteger(this.Closures.Length); foreach (ClosureDebugInfo info in this.Closures) { - writer.WriteCompressedInteger((uint)(info.SyntaxOffset - syntaxOffsetBaseline)); + writer.WriteCompressedInteger(info.SyntaxOffset - syntaxOffsetBaseline); } foreach (LambdaDebugInfo info in this.Lambdas) @@ -272,8 +276,8 @@ internal void SerializeLambdaMap(Cci.BlobBuilder writer) Debug.Assert(info.ClosureOrdinal >= LambdaDebugInfo.MinClosureOrdinal); Debug.Assert(info.LambdaId.Generation == 0); - writer.WriteCompressedInteger((uint)(info.SyntaxOffset - syntaxOffsetBaseline)); - writer.WriteCompressedInteger((uint)(info.ClosureOrdinal - LambdaDebugInfo.MinClosureOrdinal)); + writer.WriteCompressedInteger(info.SyntaxOffset - syntaxOffsetBaseline); + writer.WriteCompressedInteger(info.ClosureOrdinal - LambdaDebugInfo.MinClosureOrdinal); } } diff --git a/src/Compilers/Core/Portable/Emit/ModulePropertiesForSerialization.cs b/src/Compilers/Core/Portable/Emit/ModulePropertiesForSerialization.cs index 95b06f40e8ff8..1abf1125d2c9f 100644 --- a/src/Compilers/Core/Portable/Emit/ModulePropertiesForSerialization.cs +++ b/src/Compilers/Core/Portable/Emit/ModulePropertiesForSerialization.cs @@ -32,39 +32,12 @@ internal sealed class ModulePropertiesForSerialization /// Specifies the target CPU. means AnyCPU. /// public readonly Machine Machine; - - /// - /// True if the module contains only IL and is processor independent. Should there be a choice between launching as a 64-bit or 32-bit - /// process, this setting will cause the host to launch it as a 32-bit process. - /// - public readonly bool Prefers32Bit; - - /// - /// The first part of a two part version number indicating the version of the format used to persist this module. For example, the 1 in 1.0. - /// - public readonly byte MetadataFormatMajorVersion = 2; - - /// - /// The second part of a two part version number indicating the version of the format used to persist this module. For example, the 0 in 1.0. - /// - public readonly byte MetadataFormatMinorVersion; - + /// /// A globally unique persistent identifier for this module. /// public readonly Guid PersistentIdentifier; - /// - /// True if the module contains only IL and is processor independent. - /// - public readonly bool ILOnly = true; - - /// - /// True if the instructions in this module must be compiled in such a way that the debugging experience is not compromised. - /// To set the value of this property, add an instance of System.Diagnostics.DebuggableAttribute to the MetadataAttributes list. - /// - public readonly bool TrackDebugData; - /// /// The preferred memory address at which the module is to be loaded at runtime. /// @@ -89,7 +62,6 @@ internal sealed class ModulePropertiesForSerialization public readonly ulong SizeOfStackReserve; public readonly ulong SizeOfStackCommit; - public readonly bool StrongNameSigned; public readonly ushort MajorSubsystemVersion; public readonly ushort MinorSubsystemVersion; @@ -112,6 +84,8 @@ internal sealed class ModulePropertiesForSerialization public Subsystem Subsystem { get; } + public CorFlags CorFlags { get; } + public const ulong DefaultExeBaseAddress32Bit = 0x00400000; public const ulong DefaultExeBaseAddress64Bit = 0x0000000140000000; @@ -137,20 +111,17 @@ internal sealed class ModulePropertiesForSerialization internal ModulePropertiesForSerialization( Guid persistentIdentifier, + CorFlags corFlags, int fileAlignment, int sectionAlignment, string targetRuntimeVersion, Machine machine, - bool prefer32Bit, - bool trackDebugData, ulong baseAddress, ulong sizeOfHeapReserve, ulong sizeOfHeapCommit, ulong sizeOfStackReserve, ulong sizeOfStackCommit, - bool enableHighEntropyVA, - bool strongNameSigned, - bool configureToExecuteInAppContainer, + DllCharacteristics dllCharacteristics, Characteristics imageCharacteristics, Subsystem subsystem, ushort majorSubsystemVersion, @@ -163,95 +134,20 @@ internal ModulePropertiesForSerialization( this.SectionAlignment = sectionAlignment; this.TargetRuntimeVersion = targetRuntimeVersion; this.Machine = machine; - this.Prefers32Bit = prefer32Bit; - this.TrackDebugData = trackDebugData; this.BaseAddress = baseAddress; this.SizeOfHeapReserve = sizeOfHeapReserve; this.SizeOfHeapCommit = sizeOfHeapCommit; this.SizeOfStackReserve = sizeOfStackReserve; this.SizeOfStackCommit = sizeOfStackCommit; - this.StrongNameSigned = strongNameSigned; this.LinkerMajorVersion = linkerMajorVersion; this.LinkerMinorVersion = linkerMinorVersion; this.MajorSubsystemVersion = majorSubsystemVersion; this.MinorSubsystemVersion = minorSubsystemVersion; this.ImageCharacteristics = imageCharacteristics; this.Subsystem = subsystem; - this.DllCharacteristics = GetDllCharacteristics(enableHighEntropyVA, configureToExecuteInAppContainer); - } - - private static DllCharacteristics GetDllCharacteristics(bool enableHighEntropyVA, bool configureToExecuteInAppContainer) - { - var result = - DllCharacteristics.DynamicBase | - DllCharacteristics.NxCompatible | - DllCharacteristics.NoSeh | - DllCharacteristics.TerminalServerAware; - - if (enableHighEntropyVA) - { - result |= DllCharacteristics.HighEntropyVirtualAddressSpace; - } - - if (configureToExecuteInAppContainer) - { - result |= DllCharacteristics.AppContainer; - } - - return result; - } - - /// - /// If set, the module must include a machine code stub that transfers control to the virtual execution system. - /// - internal bool RequiresStartupStub => Machine == Machine.I386 || Machine == 0; - - /// - /// If set, the module contains instructions or assumptions that are specific to the AMD 64 bit instruction set. - /// - internal bool RequiresAmdInstructionSet => Machine == Machine.Amd64; - - /// - /// If set, the module contains instructions that assume a 32 bit instruction set. For example it may depend on an address being 32 bits. - /// This may be true even if the module contains only IL instructions because of PlatformInvoke and COM interop. - /// - internal bool Requires32bits => Machine == Machine.I386; - - /// - /// If set, the module contains instructions that assume a 64 bit instruction set. For example it may depend on an address being 64 bits. - /// This may be true even if the module contains only IL instructions because of PlatformInvoke and COM interop. - /// - internal bool Requires64bits => Machine == Machine.Amd64 || Machine == Machine.IA64; - - internal CorFlags GetCorHeaderFlags() - { - CorFlags result = 0; - if (ILOnly) - { - result |= CorFlags.ILOnly; - } - - if (Requires32bits) - { - result |= CorFlags.Requires32Bit; - } - - if (StrongNameSigned) - { - result |= CorFlags.StrongNameSigned; - } - - if (TrackDebugData) - { - result |= CorFlags.TrackDebugData; - } - - if (Prefers32Bit) - { - result |= CorFlags.Requires32Bit | CorFlags.Prefers32Bit; - } - return result; + this.DllCharacteristics = dllCharacteristics; + this.CorFlags = corFlags; } } } diff --git a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedField.cs b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedField.cs index ebe43ae7ba072..cce45f6c936ab 100644 --- a/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedField.cs +++ b/src/Compilers/Core/Portable/Emit/NoPia/CommonEmbeddedField.cs @@ -144,12 +144,11 @@ ImmutableArray Cci.IFieldDefinition.MarshallingDescriptor } } - uint Cci.IFieldDefinition.Offset + int Cci.IFieldDefinition.Offset { get { - var offset = TypeLayoutOffset; - return (uint)(offset ?? 0); + return TypeLayoutOffset ?? 0; } } diff --git a/src/Compilers/Core/Portable/InternalUtilities/HashAlgorithmExtensions.cs b/src/Compilers/Core/Portable/InternalUtilities/HashAlgorithmExtensions.cs new file mode 100644 index 0000000000000..abc13c0142aa4 --- /dev/null +++ b/src/Compilers/Core/Portable/InternalUtilities/HashAlgorithmExtensions.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Diagnostics; +using System.Reflection; + +namespace Roslyn.Utilities +{ + using Roslyn.Reflection; + + internal static class HashAlgorithmExtensions + { + internal static byte[] ComputeHash(this HashAlgorithm algorithm, BlobBuilder builder) + { + int remaining = builder.Count; + foreach (var blob in builder.GetBlobs()) + { + var segment = blob.GetBytes(); + remaining -= segment.Count; + if (remaining == 0) + { + algorithm.TransformFinalBlock(segment.Array, segment.Offset, segment.Count); + } + else + { + algorithm.TransformBlock(segment.Array, segment.Offset, segment.Count); + } + } + + Debug.Assert(remaining == 0); + return algorithm.Hash; + } + } +} diff --git a/src/Compilers/Core/Portable/InternalUtilities/ImmutableArrayInterop.cs b/src/Compilers/Core/Portable/InternalUtilities/ImmutableArrayInterop.cs index af61ff5b534eb..79adb9ebcc185 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/ImmutableArrayInterop.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/ImmutableArrayInterop.cs @@ -6,7 +6,7 @@ namespace Roslyn.Utilities { - internal static class ImmutableArrayInterop + internal static class ImmutableByteArrayInterop { internal static byte[] DangerousGetUnderlyingArray(this ImmutableArray array) { @@ -15,7 +15,7 @@ internal static byte[] DangerousGetUnderlyingArray(this ImmutableArray arr return union.MutableArray; } - internal static ImmutableArray DangerousToImmutableArray(ref byte[] array) + internal static ImmutableArray DangerousCreateFromUnderlyingArray(ref byte[] array) { var union = new ByteArrayUnion(); union.MutableArray = array; diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs index a82d02be917ca..eb96a47dbdcf9 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataDecoder.cs @@ -1052,7 +1052,7 @@ internal unsafe TypeSymbol DecodeLocalVariableTypeOrThrow(ImmutableArray s throw new UnsupportedSignatureContent(); } - fixed (byte* ptr = ImmutableArrayInterop.DangerousGetUnderlyingArray(signature)) + fixed (byte* ptr = ImmutableByteArrayInterop.DangerousGetUnderlyingArray(signature)) { var blobReader = new BlobReader(ptr, signature.Length); var info = DecodeLocalVariableOrThrow(ref blobReader); diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index 869cd2815fb5d..e42e985dc06bf 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -2464,7 +2464,7 @@ internal DllImportData GetDllImportData(MethodDefinitionHandle methodDef) string moduleName = GetModuleRefNameOrThrow(methodImport.Module); string entryPointName = MetadataReader.GetString(methodImport.Name); - Cci.PInvokeAttributes flags = (Cci.PInvokeAttributes)methodImport.Attributes; + MethodImportAttributes flags = (MethodImportAttributes)methodImport.Attributes; return new DllImportData(moduleName, entryPointName, flags); } diff --git a/src/Compilers/Core/Portable/NativePdbWriter/PdbMetadataWrapper.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbMetadataWrapper.cs index 97e252f2748f7..2593dc37e98f6 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/PdbMetadataWrapper.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbMetadataWrapper.cs @@ -3,6 +3,7 @@ #pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib using System; +using System.Reflection.Metadata.Ecma335; using System.Runtime.InteropServices; using System.Security; using System.Text; @@ -222,7 +223,7 @@ unsafe uint IMetaDataImport.GetTypeDefProps(uint td, IntPtr stringTypeDef, uint *(pointerTypeDef + pchTypeDef) = (char)0; uint* pointerFlags = (uint*)pdwTypeDefFlags.ToPointer(); - *pointerFlags = _writer.GetTypeDefFlags(t.GetResolvedType(_writer.Context)); + *pointerFlags = (uint)_writer.GetTypeAttributes(t.GetResolvedType(_writer.Context)); return 0; } @@ -233,7 +234,7 @@ unsafe uint IMetaDataImport.GetMethodProps(uint mb, out uint pointerClass, IntPt IntPtr ppvSigBlob, IntPtr pcbSigBlob, IntPtr pulCodeRVA) { IMethodDefinition m = _writer.GetMethodDefinition(mb); - pointerClass = (uint)_writer.GetTypeToken(m.GetContainingType(_writer.Context)); + pointerClass = (uint)MetadataTokens.GetToken(_writer.GetTypeHandle(m.GetContainingType(_writer.Context))); string methName = m.Name; // if the buffer is too small to fit the name, truncate the name @@ -260,7 +261,7 @@ uint IMetaDataImport.GetNestedClassProps(uint typeDefNestedClass) return 0; } - return (uint)_writer.GetTypeToken(nt.GetContainingType(_writer.Context)); + return (uint)MetadataTokens.GetToken(_writer.GetTypeHandle(nt.GetContainingType(_writer.Context))); } #region Not Implemented diff --git a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs index f7abfcce2f815..925de8ae460e1 100644 --- a/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs +++ b/src/Compilers/Core/Portable/NativePdbWriter/PdbWriter.cs @@ -6,18 +6,23 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Emit; using Roslyn.Utilities; +using OP = Microsoft.Cci.PdbLogger.PdbWriterOperation; namespace Microsoft.Cci { - using OP = Microsoft.Cci.PdbLogger.PdbWriterOperation; + using Roslyn.Reflection; + using Roslyn.Reflection.PortableExecutable; /// /// Exception to enable callers to catch all of the exceptions originating @@ -80,7 +85,7 @@ private void EnsureSpace(int space) { foreach (var blob in _logData.GetBlobs()) { - var segment = blob.GetUnderlyingBuffer(); + var segment = blob.GetBytes(); _hashAlgorithm.TransformBlock(segment.Array, segment.Offset, segment.Count); } @@ -92,25 +97,9 @@ internal byte[] GetLogHash() { Debug.Assert(_logData != null); - int remaining = _logData.Count; - foreach (var blob in _logData.GetBlobs()) - { - var segment = blob.GetUnderlyingBuffer(); - remaining -= segment.Count; - if (remaining == 0) - { - _hashAlgorithm.TransformFinalBlock(segment.Array, segment.Offset, segment.Count); - } - else - { - _hashAlgorithm.TransformBlock(segment.Array, segment.Offset, segment.Count); - } - } - - Debug.Assert(remaining == 0); - + var hash = _hashAlgorithm.ComputeHash(_logData); _logData.Clear(); - return _hashAlgorithm.Hash; + return hash; } internal void Close() @@ -230,8 +219,6 @@ public void LogArgument(object data) internal sealed class PdbWriter : IDisposable { - internal const uint HiddenLocalAttributesValue = 1u; - internal const uint DefaultLocalAttributesValue = 0u; internal const uint Age = 1; private static Type s_lazyCorSymWriterSxSType; @@ -313,7 +300,7 @@ private void Close() private IModule Module => Context.Module; private EmitContext Context => _metadataWriter.Context; - public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, CustomDebugInfoWriter customDebugInfoWriter) + public void SerializeDebugInfo(IMethodBody methodBody, StandaloneSignatureHandle localSignatureHandleOpt, CustomDebugInfoWriter customDebugInfoWriter) { Debug.Assert(_metadataWriter != null); @@ -325,16 +312,16 @@ public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, return; } - int methodToken = _metadataWriter.GetMethodToken(methodBody.MethodDefinition); + int methodToken = MetadataTokens.GetToken(_metadataWriter.GetMethodHandle(methodBody.MethodDefinition)); - OpenMethod((uint)methodToken, methodBody.MethodDefinition); + OpenMethod(methodToken, methodBody.MethodDefinition); var localScopes = methodBody.LocalScopes; // Define locals, constants and namespaces in the outermost local scope (opened in OpenMethod): if (localScopes.Length > 0) { - this.DefineScopeLocals(localScopes[0], localSignatureToken); + this.DefineScopeLocals(localScopes[0], localSignatureHandleOpt); } // NOTE: This is an attempt to match Dev10's apparent behavior. For iterator methods (i.e. the method @@ -347,7 +334,7 @@ public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, { if (forwardToMethod != null) { - UsingNamespace("@" + _metadataWriter.GetMethodToken(forwardToMethod), methodBody.MethodDefinition); + UsingNamespace("@" + MetadataTokens.GetToken(_metadataWriter.GetMethodHandle(forwardToMethod)), methodBody.MethodDefinition); } // otherwise, the forwarding is done via custom debug info } @@ -357,7 +344,7 @@ public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, } } - DefineLocalScopes(localScopes, localSignatureToken); + DefineLocalScopes(localScopes, localSignatureHandleOpt); ArrayBuilder sequencePoints = ArrayBuilder.GetInstance(); methodBody.GetSequencePoints(sequencePoints); EmitSequencePoints(sequencePoints); @@ -368,7 +355,7 @@ public void SerializeDebugInfo(IMethodBody methodBody, uint localSignatureToken, { SetAsyncInfo( methodToken, - _metadataWriter.GetMethodToken(asyncDebugInfo.KickoffMethod), + MetadataTokens.GetToken(_metadataWriter.GetMethodHandle(asyncDebugInfo.KickoffMethod)), asyncDebugInfo.CatchHandlerOffset, asyncDebugInfo.YieldOffsets, asyncDebugInfo.ResumeOffsets); @@ -689,7 +676,7 @@ private string GetAssemblyReferenceAlias(IAssemblyReference assembly, HashSet scopes, uint localSignatureToken) + private void DefineLocalScopes(ImmutableArray scopes, StandaloneSignatureHandle localSignatureHandleOpt) { // VB scope ranges are end-inclusive bool endInclusive = this.Module.GenerateVisualBasicStylePdb; @@ -717,7 +704,7 @@ private void DefineLocalScopes(ImmutableArray scopes, uint localSign // Open this scope. scopeStack.Add(currentScope); OpenScope(currentScope.StartOffset); - this.DefineScopeLocals(currentScope, localSignatureToken); + this.DefineScopeLocals(currentScope, localSignatureHandleOpt); } // Close remaining scopes. @@ -730,14 +717,14 @@ private void DefineLocalScopes(ImmutableArray scopes, uint localSign scopeStack.Free(); } - private void DefineScopeLocals(LocalScope currentScope, uint localSignatureToken) + private void DefineScopeLocals(LocalScope currentScope, StandaloneSignatureHandle localSignatureHandleOpt) { foreach (ILocalDefinition scopeConstant in currentScope.Constants) { - int token = _metadataWriter.SerializeLocalConstantStandAloneSignature(scopeConstant); + var signatureHandle = _metadataWriter.SerializeLocalConstantStandAloneSignature(scopeConstant); if (!_metadataWriter.IsLocalNameTooLong(scopeConstant)) { - DefineLocalConstant(scopeConstant.Name, scopeConstant.CompileTimeValue.Value, _metadataWriter.GetConstantTypeCode(scopeConstant), (uint)token); + DefineLocalConstant(scopeConstant.Name, scopeConstant.CompileTimeValue.Value, _metadataWriter.GetConstantTypeCode(scopeConstant), signatureHandle); } } @@ -746,7 +733,7 @@ private void DefineScopeLocals(LocalScope currentScope, uint localSignatureToken if (!_metadataWriter.IsLocalNameTooLong(scopeLocal)) { Debug.Assert(scopeLocal.SlotIndex >= 0); - DefineLocalVariable((uint)scopeLocal.SlotIndex, scopeLocal.Name, scopeLocal.PdbAttributes, localSignatureToken); + DefineLocalVariable((uint)scopeLocal.SlotIndex, scopeLocal.Name, scopeLocal.PdbAttributes, localSignatureHandleOpt); } } } @@ -1003,11 +990,11 @@ private ISymUnmanagedDocumentWriter GetDocumentWriter(DebugSourceDocument docume return writer; } - private void OpenMethod(uint methodToken, IMethodDefinition method) + private void OpenMethod(int methodToken, IMethodDefinition method) { try { - _symWriter.OpenMethod(methodToken); + _symWriter.OpenMethod((uint)methodToken); if (_callLogger.LogOperation(OP.OpenMethod)) { _callLogger.LogArgument(methodToken); @@ -1210,8 +1197,10 @@ private unsafe void DefineCustomMetadata(string name, byte[] metadata) } } - private void DefineLocalConstant(string name, object value, PrimitiveTypeCode typeCode, uint constantSignatureToken) + private void DefineLocalConstant(string name, object value, PrimitiveTypeCode typeCode, StandaloneSignatureHandle constantSignatureHandle) { + uint constantSignatureToken = (uint)MetadataTokens.GetToken(constantSignatureHandle); + if (value == null) { // ISymUnmanagedWriter2.DefineConstant2 throws an ArgumentException @@ -1309,17 +1298,19 @@ private void DefineLocalStringConstant(string name, string value, uint constantS } } - private void DefineLocalVariable(uint index, string name, uint attributes, uint localVariablesSignatureToken) + private void DefineLocalVariable(uint index, string name, LocalVariableAttributes attributes, StandaloneSignatureHandle localSignatureHandleOpt) { + uint localSignatureToken = localSignatureHandleOpt.IsNil ? 0 : (uint)MetadataTokens.GetToken(localSignatureHandleOpt); + const uint ADDR_IL_OFFSET = 1; try { - _symWriter.DefineLocalVariable2(name, attributes, localVariablesSignatureToken, ADDR_IL_OFFSET, index, 0, 0, 0, 0); + _symWriter.DefineLocalVariable2(name, (uint)attributes, localSignatureToken, ADDR_IL_OFFSET, index, 0, 0, 0, 0); if (_callLogger.LogOperation(OP.DefineLocalVariable2)) { _callLogger.LogArgument(name); - _callLogger.LogArgument(attributes); - _callLogger.LogArgument(localVariablesSignatureToken); + _callLogger.LogArgument((uint)attributes); + _callLogger.LogArgument(localSignatureToken); _callLogger.LogArgument(ADDR_IL_OFFSET); _callLogger.LogArgument(index); _callLogger.LogArgument((uint)0); @@ -1411,8 +1402,8 @@ public void AssertAllDefinitionsHaveTokens(MultiDictionary _length; - - public ArraySegment GetUnderlyingBuffer() - { - return new ArraySegment(_buffer, _start, _length); - } - } -} diff --git a/src/Compilers/Core/Portable/PEWriter/CoffHeader.cs b/src/Compilers/Core/Portable/PEWriter/CoffHeader.cs deleted file mode 100644 index eff109a84a4f2..0000000000000 --- a/src/Compilers/Core/Portable/PEWriter/CoffHeader.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection.PortableExecutable; - -namespace Microsoft.Cci -{ - // TODO: merge with System.Reflection.PortableExecutable.CoffHeader - internal sealed class CoffHeader - { - /// - /// The type of target machine. - /// - public Machine Machine { get; } - - /// - /// The number of sections. This indicates the size of the section table, which immediately follows the headers. - /// - public short NumberOfSections { get; } - - /// - /// The low 32 bits of the number of seconds since 00:00 January 1, 1970, that indicates when the file was created. - /// - public int TimeDateStamp { get; } - - /// - /// The file pointer to the COFF symbol table, or zero if no COFF symbol table is present. - /// This value should be zero for a PE image. - /// - public int PointerToSymbolTable { get; } - - /// - /// The number of entries in the symbol table. This data can be used to locate the string table, - /// which immediately follows the symbol table. This value should be zero for a PE image. - /// - public int NumberOfSymbols { get; } - - /// - /// The size of the optional header, which is required for executable files but not for object files. - /// This value should be zero for an object file. - /// - public short SizeOfOptionalHeader { get; } - - /// - /// The flags that indicate the attributes of the file. - /// - public Characteristics Characteristics { get; } - - public CoffHeader( - Machine machine, - short numberOfSections, - int timeDateStamp, - int pointerToSymbolTable, - int numberOfSymbols, - short sizeOfOptionalHeader, - Characteristics characteristics) - { - Machine = machine; - NumberOfSections = numberOfSections; - TimeDateStamp = timeDateStamp; - PointerToSymbolTable = pointerToSymbolTable; - NumberOfSymbols = numberOfSymbols; - SizeOfOptionalHeader = sizeOfOptionalHeader; - Characteristics = characteristics; - } - } -} diff --git a/src/Compilers/Core/Portable/PEWriter/Constants.cs b/src/Compilers/Core/Portable/PEWriter/Constants.cs index dc7518324f516..316730e6a7cce 100644 --- a/src/Compilers/Core/Portable/PEWriter/Constants.cs +++ b/src/Compilers/Core/Portable/PEWriter/Constants.cs @@ -1,6 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System.Reflection.Metadata; using System.Runtime.InteropServices; namespace Microsoft.Cci @@ -30,54 +29,6 @@ internal static class Constants // Non-portable CompilationRelaxations value: public const int CompilationRelaxations_NoStringInterning = 0x0008; - - // Not exposed by the metadata reader since they are abstracted away and presented as SignatureTypeCode.TypeHandle - public const SignatureTypeCode SignatureTypeCode_Class = (SignatureTypeCode)0x12; - public const SignatureTypeCode SignatureTypeCode_ValueType = (SignatureTypeCode)0x11; - } - - internal enum HeapSizeFlag : byte - { - StringHeapLarge = 0x01, // 4 byte uint indexes used for string heap offsets - GuidHeapLarge = 0x02, // 4 byte uint indexes used for GUID heap offsets - BlobHeapLarge = 0x04, // 4 byte uint indexes used for Blob heap offsets - EnCDeltas = 0x20, // Indicates only EnC Deltas are present - DeletedMarks = 0x80, // Indicates metadata might contain items marked deleted - } - - internal static class TokenTypeIds - { - internal const int Module = 0x00000000; - internal const int TypeRef = 0x01000000; - internal const int TypeDef = 0x02000000; - internal const int FieldDef = 0x04000000; - internal const int MethodDef = 0x06000000; - internal const int ParamDef = 0x08000000; - internal const int InterfaceImpl = 0x09000000; - internal const int MemberRef = 0x0a000000; - internal const int Constant = 0x0b000000; - internal const int CustomAttribute = 0x0c000000; - internal const int Permission = 0x0e000000; - internal const int Signature = 0x11000000; - internal const int EventMap = 0x12000000; - internal const int Event = 0x14000000; - internal const int PropertyMap = 0x15000000; - internal const int Property = 0x17000000; - internal const int MethodSemantics = 0x18000000; - internal const int MethodImpl = 0x19000000; - internal const int ModuleRef = 0x1a000000; - internal const int TypeSpec = 0x1b000000; - internal const int Assembly = 0x20000000; - internal const int AssemblyRef = 0x23000000; - internal const int File = 0x26000000; - internal const int ExportedType = 0x27000000; - internal const int ManifestResource = 0x28000000; - internal const int NestedClass = 0x29000000; - internal const int GenericParam = 0x2a000000; - internal const int MethodSpec = 0x2b000000; - internal const int GenericParamConstraint = 0x2c000000; - internal const int UserString = 0x70000000; - internal const int String = 0x71000000; } internal enum TypeFlags : uint diff --git a/src/Compilers/Core/Portable/PEWriter/CorHeader.cs b/src/Compilers/Core/Portable/PEWriter/CorHeader.cs deleted file mode 100644 index c9d051a34b2d9..0000000000000 --- a/src/Compilers/Core/Portable/PEWriter/CorHeader.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection.PortableExecutable; - -namespace Microsoft.Cci -{ - // TODO: merge with System.Reflection.PortableExecutable.CorHeader - internal sealed class CorHeader - { - public ushort MajorRuntimeVersion { get; } - public ushort MinorRuntimeVersion { get; } - public DirectoryEntry MetadataDirectory { get; } - public CorFlags Flags { get; } - public int EntryPointTokenOrRelativeVirtualAddress { get; } - public DirectoryEntry ResourcesDirectory { get; } - public DirectoryEntry StrongNameSignatureDirectory { get; } - public DirectoryEntry CodeManagerTableDirectory { get; } - public DirectoryEntry VtableFixupsDirectory { get; } - public DirectoryEntry ExportAddressTableJumpsDirectory { get; } - public DirectoryEntry ManagedNativeHeaderDirectory { get; } - - public CorHeader( - CorFlags flags, - DirectoryEntry metadataDirectory, - int entryPointTokenOrRelativeVirtualAddress = 0, - ushort majorRuntimeVersion = 2, - ushort minorRuntimeVersion = 5, - DirectoryEntry resourcesDirectory = default(DirectoryEntry), - DirectoryEntry strongNameSignatureDirectory = default(DirectoryEntry), - DirectoryEntry codeManagerTableDirectory = default(DirectoryEntry), - DirectoryEntry vtableFixupsDirectory = default(DirectoryEntry), - DirectoryEntry exportAddressTableJumpsDirectory = default(DirectoryEntry), - DirectoryEntry managedNativeHeaderDirectory = default(DirectoryEntry)) - { - MajorRuntimeVersion = majorRuntimeVersion; - MinorRuntimeVersion = minorRuntimeVersion; - MetadataDirectory = metadataDirectory; - Flags = flags; - EntryPointTokenOrRelativeVirtualAddress = entryPointTokenOrRelativeVirtualAddress; - ResourcesDirectory = resourcesDirectory; - StrongNameSignatureDirectory = strongNameSignatureDirectory; - CodeManagerTableDirectory = codeManagerTableDirectory; - VtableFixupsDirectory = vtableFixupsDirectory; - ExportAddressTableJumpsDirectory = exportAddressTableJumpsDirectory; - ManagedNativeHeaderDirectory = managedNativeHeaderDirectory; - } - } -} diff --git a/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs b/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs index 6e5fdefa40d65..bcfe8886e4248 100644 --- a/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/CustomDebugInfoWriter.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; +using System.Reflection.Metadata.Ecma335; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Emit; using Roslyn.Utilities; @@ -11,6 +13,8 @@ namespace Microsoft.Cci { + using Roslyn.Reflection; + internal sealed class CustomDebugInfoWriter { private int _methodTokenWithModuleInfo; @@ -156,7 +160,7 @@ private static PooledBlobBuilder SerializeRecord( cmw.WriteByte(0); // alignment size and length (will be patched) - var alignmentSizeAndLengthWriter = cmw.ReserveBytes(sizeof(byte) + sizeof(uint)); + var alignmentSizeAndLengthWriter = new BlobWriter(cmw.ReserveBytes(sizeof(byte) + sizeof(uint))); recordSerializer(debugInfo, cmw); diff --git a/src/Compilers/Core/Portable/PEWriter/ExceptionHandlerRegion.cs b/src/Compilers/Core/Portable/PEWriter/ExceptionHandlerRegion.cs index 20d64aff75271..e3e000e8cdc98 100644 --- a/src/Compilers/Core/Portable/PEWriter/ExceptionHandlerRegion.cs +++ b/src/Compilers/Core/Portable/PEWriter/ExceptionHandlerRegion.cs @@ -11,10 +11,25 @@ namespace Microsoft.Cci /// internal abstract class ExceptionHandlerRegion { - private readonly int _tryStartOffset; - private readonly int _tryEndOffset; - private readonly int _handlerStartOffset; - private readonly int _handlerEndOffset; + /// + /// Label instruction corresponding to the start of try block + /// + public int TryStartOffset { get; } + + /// + /// Label instruction corresponding to the end of try block + /// + public int TryEndOffset { get; } + + /// + /// Label instruction corresponding to the start of handler block + /// + public int HandlerStartOffset { get; } + + /// + /// Label instruction corresponding to the end of handler block + /// + public int HandlerEndOffset { get; } public ExceptionHandlerRegion( int tryStartOffset, @@ -30,12 +45,15 @@ public ExceptionHandlerRegion( Debug.Assert(handlerStartOffset >= 0); Debug.Assert(handlerEndOffset >= 0); - _tryStartOffset = tryStartOffset; - _tryEndOffset = tryEndOffset; - _handlerStartOffset = handlerStartOffset; - _handlerEndOffset = handlerEndOffset; + TryStartOffset = tryStartOffset; + TryEndOffset = tryEndOffset; + HandlerStartOffset = handlerStartOffset; + HandlerEndOffset = handlerEndOffset; } + public int HandlerLength => HandlerEndOffset - HandlerStartOffset; + public int TryLength => TryEndOffset - TryStartOffset; + /// /// Handler kind for this SEH info /// @@ -60,38 +78,6 @@ public virtual int FilterDecisionStartOffset { get { return 0; } } - - /// - /// Label instruction corresponding to the start of try block - /// - public int TryStartOffset - { - get { return _tryStartOffset; } - } - - /// - /// Label instruction corresponding to the end of try block - /// - public int TryEndOffset - { - get { return _tryEndOffset; } - } - - /// - /// Label instruction corresponding to the start of handler block - /// - public int HandlerStartOffset - { - get { return _handlerStartOffset; } - } - - /// - /// Label instruction corresponding to the end of handler block - /// - public int HandlerEndOffset - { - get { return _handlerEndOffset; } - } } internal sealed class ExceptionHandlerRegionFinally : ExceptionHandlerRegion diff --git a/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs index aeff80ff8b01f..4c5dc103d7211 100644 --- a/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/FullMetadataWriter.cs @@ -3,6 +3,8 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Emit; @@ -10,6 +12,8 @@ namespace Microsoft.Cci { + using Roslyn.Reflection.Metadata.Ecma335; + internal sealed class FullMetadataWriter : MetadataWriter { private readonly DefinitionIndex _typeDefs; @@ -30,7 +34,7 @@ internal sealed class FullMetadataWriter : MetadataWriter private readonly InstanceAndStructuralReferenceIndex _methodSpecIndex; private readonly HeapOrReferenceIndex _typeRefIndex; private readonly InstanceAndStructuralReferenceIndex _typeSpecIndex; - private readonly HeapOrReferenceIndex _standAloneSignatureIndex; + private readonly HeapOrReferenceIndex _standAloneSignatureIndex; public static MetadataWriter Create( EmitContext context, @@ -40,35 +44,35 @@ public static MetadataWriter Create( bool hasPdbStream, CancellationToken cancellationToken) { - var heaps = new MetadataHeapsBuilder(); - MetadataHeapsBuilder debugHeapsOpt; + var builder = new MetadataBuilder(); + MetadataBuilder debugBuilderOpt; switch (context.ModuleBuilder.EmitOptions.DebugInformationFormat) { case DebugInformationFormat.PortablePdb: - debugHeapsOpt = hasPdbStream ? new MetadataHeapsBuilder() : null; + debugBuilderOpt = hasPdbStream ? new MetadataBuilder() : null; break; case DebugInformationFormat.Embedded: - debugHeapsOpt = heaps; + debugBuilderOpt = builder; break; default: - debugHeapsOpt = null; + debugBuilderOpt = null; break; } - return new FullMetadataWriter(context, heaps, debugHeapsOpt, messageProvider, allowMissingMethodBodies, deterministic, cancellationToken); + return new FullMetadataWriter(context, builder, debugBuilderOpt, messageProvider, allowMissingMethodBodies, deterministic, cancellationToken); } private FullMetadataWriter( EmitContext context, - MetadataHeapsBuilder heaps, - MetadataHeapsBuilder debugHeapsOpt, + MetadataBuilder builder, + MetadataBuilder debugBuilderOpt, CommonMessageProvider messageProvider, bool allowMissingMethodBodies, bool deterministic, CancellationToken cancellationToken) - : base(heaps, debugHeapsOpt, context, messageProvider, allowMissingMethodBodies, deterministic, cancellationToken) + : base(builder, debugBuilderOpt, context, messageProvider, allowMissingMethodBodies, deterministic, cancellationToken) { // EDMAURER make some intelligent guesses for the initial sizes of these things. int numMethods = this.module.HintNumberOfMethodDefinitions; @@ -94,7 +98,7 @@ private FullMetadataWriter( _methodSpecIndex = new InstanceAndStructuralReferenceIndex(this, new MethodSpecComparer(this)); _typeRefIndex = new HeapOrReferenceIndex(this); _typeSpecIndex = new InstanceAndStructuralReferenceIndex(this, new TypeSpecComparer(this)); - _standAloneSignatureIndex = new HeapOrReferenceIndex(this); + _standAloneSignatureIndex = new HeapOrReferenceIndex(this); } protected override ushort Generation @@ -112,19 +116,22 @@ protected override Guid EncBaseId get { return Guid.Empty; } } - protected override bool TryGetTypeDefIndex(ITypeDefinition def, out int index) + protected override bool TryGetTypeDefinitionHandle(ITypeDefinition def, out TypeDefinitionHandle handle) { - return _typeDefs.TryGetValue(def, out index); + int index; + bool result = _typeDefs.TryGetValue(def, out index); + handle = MetadataTokens.TypeDefinitionHandle(index); + return result; } - protected override int GetTypeDefIndex(ITypeDefinition def) + protected override TypeDefinitionHandle GetTypeDefinitionHandle(ITypeDefinition def) { - return _typeDefs[def]; + return MetadataTokens.TypeDefinitionHandle(_typeDefs[def]); } - protected override ITypeDefinition GetTypeDef(int index) + protected override ITypeDefinition GetTypeDef(TypeDefinitionHandle handle) { - return _typeDefs[index]; + return _typeDefs[MetadataTokens.GetRowNumber(handle)]; } protected override IReadOnlyList GetTypeDefs() @@ -132,9 +139,9 @@ protected override IReadOnlyList GetTypeDefs() return _typeDefs.Rows; } - protected override int GetEventDefIndex(IEventDefinition def) + protected override EventDefinitionHandle GetEventDefinitionHandle(IEventDefinition def) { - return _eventDefs[def]; + return MetadataTokens.EventDefinitionHandle(_eventDefs[def]); } protected override IReadOnlyList GetEventDefs() @@ -142,9 +149,9 @@ protected override IReadOnlyList GetEventDefs() return _eventDefs.Rows; } - protected override int GetFieldDefIndex(IFieldDefinition def) + protected override FieldDefinitionHandle GetFieldDefinitionHandle(IFieldDefinition def) { - return _fieldDefs[def]; + return MetadataTokens.FieldDefinitionHandle(_fieldDefs[def]); } protected override IReadOnlyList GetFieldDefs() @@ -152,19 +159,22 @@ protected override IReadOnlyList GetFieldDefs() return _fieldDefs.Rows; } - protected override bool TryGetMethodDefIndex(IMethodDefinition def, out int index) + protected override bool TryGetMethodDefinitionHandle(IMethodDefinition def, out MethodDefinitionHandle handle) { - return _methodDefs.TryGetValue(def, out index); + int index; + bool result = _methodDefs.TryGetValue(def, out index); + handle = MetadataTokens.MethodDefinitionHandle(index); + return result; } - protected override int GetMethodDefIndex(IMethodDefinition def) + protected override MethodDefinitionHandle GetMethodDefinitionHandle(IMethodDefinition def) { - return _methodDefs[def]; + return MetadataTokens.MethodDefinitionHandle(_methodDefs[def]); } - protected override IMethodDefinition GetMethodDef(int index) + protected override IMethodDefinition GetMethodDef(MethodDefinitionHandle handle) { - return _methodDefs[index]; + return _methodDefs[MetadataTokens.GetRowNumber(handle)]; } protected override IReadOnlyList GetMethodDefs() @@ -172,9 +182,9 @@ protected override IReadOnlyList GetMethodDefs() return _methodDefs.Rows; } - protected override int GetPropertyDefIndex(IPropertyDefinition def) + protected override PropertyDefinitionHandle GetPropertyDefIndex(IPropertyDefinition def) { - return _propertyDefs[def]; + return MetadataTokens.PropertyDefinitionHandle(_propertyDefs[def]); } protected override IReadOnlyList GetPropertyDefs() @@ -182,9 +192,9 @@ protected override IReadOnlyList GetPropertyDefs() return _propertyDefs.Rows; } - protected override int GetParameterDefIndex(IParameterDefinition def) + protected override ParameterHandle GetParameterHandle(IParameterDefinition def) { - return _parameterDefs[def]; + return MetadataTokens.ParameterHandle(_parameterDefs[def]); } protected override IReadOnlyList GetParameterDefs() @@ -197,24 +207,24 @@ protected override IReadOnlyList GetGenericParameters() return _genericParameters.Rows; } - protected override int GetFieldDefIndex(INamedTypeDefinition typeDef) + protected override FieldDefinitionHandle GetFirstFieldDefinitionHandle(INamedTypeDefinition typeDef) { - return _fieldDefIndex[typeDef]; + return MetadataTokens.FieldDefinitionHandle(_fieldDefIndex[typeDef]); } - protected override int GetMethodDefIndex(INamedTypeDefinition typeDef) + protected override MethodDefinitionHandle GetFirstMethodDefinitionHandle(INamedTypeDefinition typeDef) { - return _methodDefIndex[typeDef]; + return MetadataTokens.MethodDefinitionHandle(_methodDefIndex[typeDef]); } - protected override int GetParameterDefIndex(IMethodDefinition methodDef) + protected override ParameterHandle GetFirstParameterHandle(IMethodDefinition methodDef) { - return _parameterListIndex[methodDef]; + return MetadataTokens.ParameterHandle(_parameterListIndex[methodDef]); } - protected override int GetOrAddAssemblyRefIndex(IAssemblyReference reference) + protected override AssemblyReferenceHandle GetOrAddAssemblyReferenceHandle(IAssemblyReference reference) { - return _assemblyRefIndex.GetOrAdd(reference.Identity); + return MetadataTokens.AssemblyReferenceHandle(_assemblyRefIndex.GetOrAdd(reference.Identity)); } protected override IReadOnlyList GetAssemblyRefs() @@ -222,9 +232,9 @@ protected override IReadOnlyList GetAssemblyRefs() return _assemblyRefIndex.Rows; } - protected override int GetOrAddModuleRefIndex(string reference) + protected override ModuleReferenceHandle GetOrAddModuleReferenceHandle(string reference) { - return _moduleRefIndex.GetOrAdd(reference); + return MetadataTokens.ModuleReferenceHandle(_moduleRefIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetModuleRefs() @@ -232,9 +242,9 @@ protected override IReadOnlyList GetModuleRefs() return _moduleRefIndex.Rows; } - protected override int GetOrAddMemberRefIndex(ITypeMemberReference reference) + protected override MemberReferenceHandle GetOrAddMemberReferenceHandle(ITypeMemberReference reference) { - return _memberRefIndex.GetOrAdd(reference); + return MetadataTokens.MemberReferenceHandle(_memberRefIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetMemberRefs() @@ -242,9 +252,9 @@ protected override IReadOnlyList GetMemberRefs() return _memberRefIndex.Rows; } - protected override int GetOrAddMethodSpecIndex(IGenericMethodInstanceReference reference) + protected override MethodSpecificationHandle GetOrAddMethodSpecificationHandle(IGenericMethodInstanceReference reference) { - return _methodSpecIndex.GetOrAdd(reference); + return MetadataTokens.MethodSpecificationHandle(_methodSpecIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetMethodSpecs() @@ -252,14 +262,17 @@ protected override IReadOnlyList GetMethodSpecs return _methodSpecIndex.Rows; } - protected override bool TryGetTypeRefIndex(ITypeReference reference, out int index) + protected override bool TryGetTypeRefeferenceHandle(ITypeReference reference, out TypeReferenceHandle handle) { - return _typeRefIndex.TryGetValue(reference, out index); + int index; + bool result = _typeRefIndex.TryGetValue(reference, out index); + handle = MetadataTokens.TypeReferenceHandle(index); + return result; } - protected override int GetOrAddTypeRefIndex(ITypeReference reference) + protected override TypeReferenceHandle GetOrAddTypeReferenceHandle(ITypeReference reference) { - return _typeRefIndex.GetOrAdd(reference); + return MetadataTokens.TypeReferenceHandle(_typeRefIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetTypeRefs() @@ -267,9 +280,9 @@ protected override IReadOnlyList GetTypeRefs() return _typeRefIndex.Rows; } - protected override int GetOrAddTypeSpecIndex(ITypeReference reference) + protected override TypeSpecificationHandle GetOrAddTypeSpecificationHandle(ITypeReference reference) { - return _typeSpecIndex.GetOrAdd(reference); + return MetadataTokens.TypeSpecificationHandle(_typeSpecIndex.GetOrAdd(reference)); } protected override IReadOnlyList GetTypeSpecs() @@ -277,12 +290,12 @@ protected override IReadOnlyList GetTypeSpecs() return _typeSpecIndex.Rows; } - protected override int GetOrAddStandAloneSignatureIndex(BlobIdx blobIndex) + protected override StandaloneSignatureHandle GetOrAddStandaloneSignatureHandle(BlobHandle blobIndex) { - return _standAloneSignatureIndex.GetOrAdd(blobIndex); + return MetadataTokens.StandaloneSignatureHandle(_standAloneSignatureIndex.GetOrAdd(blobIndex)); } - protected override IReadOnlyList GetStandAloneSignatures() + protected override IReadOnlyList GetStandaloneSignatureBlobHandles() { return _standAloneSignatureIndex.Rows; } @@ -305,15 +318,15 @@ internal FullReferenceIndexer(MetadataWriter metadataWriter) } } - protected override void PopulateEncLogTableRows(List table, ImmutableArray rowCounts) + protected override void PopulateEncLogTableRows(ImmutableArray rowCounts) { } - protected override void PopulateEncMapTableRows(List table, ImmutableArray rowCounts) + protected override void PopulateEncMapTableRows(ImmutableArray rowCounts) { } - protected override void PopulateEventMapTableRows(List table) + protected override void PopulateEventMapTableRows() { ITypeDefinition lastParent = null; foreach (IEventDefinition eventDef in this.GetEventDefs()) @@ -324,15 +337,14 @@ protected override void PopulateEventMapTableRows(List table) } lastParent = eventDef.ContainingTypeDefinition; - int eventIndex = this.GetEventDefIndex(eventDef); - EventMapRow r = new EventMapRow(); - r.Parent = (uint)this.GetTypeDefIndex(lastParent); - r.EventList = (uint)eventIndex; - table.Add(r); + + metadata.AddEventMap( + declaringType: GetTypeDefinitionHandle(lastParent), + eventList: GetEventDefinitionHandle(eventDef)); } } - protected override void PopulatePropertyMapTableRows(List table) + protected override void PopulatePropertyMapTableRows() { ITypeDefinition lastParent = null; foreach (IPropertyDefinition propertyDef in this.GetPropertyDefs()) @@ -343,11 +355,10 @@ protected override void PopulatePropertyMapTableRows(List table) } lastParent = propertyDef.ContainingTypeDefinition; - int propertyIndex = this.GetPropertyDefIndex(propertyDef); - PropertyMapRow r = new PropertyMapRow(); - r.Parent = (uint)this.GetTypeDefIndex(lastParent); - r.PropertyList = (uint)propertyIndex; - table.Add(r); + + metadata.AddPropertyMap( + declaringType: GetTypeDefinitionHandle(lastParent), + propertyList: GetPropertyDefIndex(propertyDef)); } } @@ -418,6 +429,7 @@ private void CreateIndicesFor(IMethodDefinition methodDef) private struct DefinitionIndex where T : IReference { + // IReference to RowId private readonly Dictionary _index; private readonly List _rows; @@ -427,9 +439,9 @@ public DefinitionIndex(int capacity) _rows = new List(capacity); } - public bool TryGetValue(T item, out int index) + public bool TryGetValue(T item, out int rowId) { - return _index.TryGetValue(item, out index); + return _index.TryGetValue(item, out rowId); } public int this[T item] @@ -437,9 +449,9 @@ public int this[T item] get { return _index[item]; } } - public T this[int index] + public T this[int rowId] { - get { return _rows[index]; } + get { return _rows[rowId - 1]; } } public IReadOnlyList Rows diff --git a/src/Compilers/Core/Portable/PEWriter/ManagedResource.cs b/src/Compilers/Core/Portable/PEWriter/ManagedResource.cs index f254ee86d751c..f543acfd6ec0c 100644 --- a/src/Compilers/Core/Portable/PEWriter/ManagedResource.cs +++ b/src/Compilers/Core/Portable/PEWriter/ManagedResource.cs @@ -4,12 +4,14 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Globalization; using Microsoft.CodeAnalysis; using Roslyn.Utilities; -using System.Globalization; namespace Microsoft.Cci { + using Roslyn.Reflection; + internal sealed class ManagedResource { private readonly Func _streamProvider; diff --git a/src/Compilers/Core/Portable/PEWriter/MemberRefComparer.cs b/src/Compilers/Core/Portable/PEWriter/MemberRefComparer.cs index 63899c6e25cb8..5e4fe8d3bb3df 100644 --- a/src/Compilers/Core/Portable/PEWriter/MemberRefComparer.cs +++ b/src/Compilers/Core/Portable/PEWriter/MemberRefComparer.cs @@ -23,7 +23,7 @@ public bool Equals(ITypeMemberReference x, ITypeMemberReference y) if (x.GetContainingType(_metadataWriter.Context) != y.GetContainingType(_metadataWriter.Context)) { - if (_metadataWriter.GetMemberRefParentCodedIndex(x) != _metadataWriter.GetMemberRefParentCodedIndex(y)) + if (_metadataWriter.GetMemberReferenceParent(x) != _metadataWriter.GetMemberReferenceParent(y)) { return false; } @@ -45,7 +45,7 @@ public bool Equals(ITypeMemberReference x, ITypeMemberReference y) var ym = y as IMethodReference; if (xm != null && ym != null) { - return _metadataWriter.GetMethodSignatureIndex(xm) == _metadataWriter.GetMethodSignatureIndex(ym); + return _metadataWriter.GetMethodSignatureHandle(xm) == _metadataWriter.GetMethodSignatureHandle(ym); } return false; @@ -53,7 +53,7 @@ public bool Equals(ITypeMemberReference x, ITypeMemberReference y) public int GetHashCode(ITypeMemberReference memberRef) { - int hash = Hash.Combine(memberRef.Name, (int)_metadataWriter.GetMemberRefParentCodedIndex(memberRef) << 4); + int hash = Hash.Combine(memberRef.Name, _metadataWriter.GetMemberReferenceParent(memberRef).GetHashCode()); var fieldRef = memberRef as IFieldReference; if (fieldRef != null) @@ -65,7 +65,7 @@ public int GetHashCode(ITypeMemberReference memberRef) var methodRef = memberRef as IMethodReference; if (methodRef != null) { - hash = Hash.Combine(hash, _metadataWriter.GetMethodSignatureIndex(methodRef).GetHashCode()); + hash = Hash.Combine(hash, _metadataWriter.GetMethodSignatureHandle(methodRef).GetHashCode()); } } diff --git a/src/Compilers/Core/Portable/PEWriter/Members.cs b/src/Compilers/Core/Portable/PEWriter/Members.cs index 1f488889c46de..9b14e846f0a96 100644 --- a/src/Compilers/Core/Portable/PEWriter/Members.cs +++ b/src/Compilers/Core/Portable/PEWriter/Members.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Reflection; +using System.Reflection.Metadata; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; @@ -23,47 +24,47 @@ internal enum CallingConvention /// C/C++ style calling convention for unmanaged methods. The call stack is cleaned up by the caller, /// which makes this convention suitable for calling methods that accept extra arguments. /// - C = 1, + C = SignatureCallingConvention.CDecl, /// /// The convention for calling managed methods with a fixed number of arguments. /// - Default = 0, + Default = SignatureCallingConvention.Default, /// /// The convention for calling managed methods that accept extra arguments. /// - ExtraArguments = 5, + ExtraArguments = SignatureCallingConvention.VarArgs, /// /// Arguments are passed in registers when possible. This calling convention is not yet supported. /// - FastCall = 4, + FastCall = SignatureCallingConvention.FastCall, /// /// Win32 API calling convention for calling unmanaged methods via PlatformInvoke. The call stack is cleaned up by the callee. /// - Standard = 2, + Standard = SignatureCallingConvention.StdCall, /// /// C++ member unmanaged method (non-vararg) calling convention. The callee cleans the stack and the this pointer is pushed on the stack last. /// - ThisCall = 3, + ThisCall = SignatureCallingConvention.ThisCall, /// /// The convention for calling a generic method. /// - Generic = 0x10, + Generic = SignatureAttributes.Generic, /// /// The convention for calling an instance method with an implicit this parameter (the method does not have an explicit parameter definition for this). /// - HasThis = 0x20, + HasThis = SignatureAttributes.Instance, /// /// The convention for calling an instance method that explicitly declares its first parameter to correspond to the this instance. /// - ExplicitThis = 0x40 + ExplicitThis = SignatureAttributes.ExplicitThis } /// @@ -184,7 +185,7 @@ ImmutableArray MarshallingDescriptor /// /// Offset of the field. /// - uint Offset + int Offset { get; // ^ requires this.ContainingTypeDefinition.Layout == LayoutKind.Explicit; @@ -262,16 +263,17 @@ ImmutableArray CustomModifiers /// /// Each local has an attributes field in the PDB. To match the native compiler, - /// we emit "1" for locals that should definitely not bind in the debugger and "0" + /// we emit for locals that should + /// definitely not bind in the debugger and /// for all other locals. /// /// - /// A value of "1" is a sufficient, but not a necessary, condition for hiding the - /// local in the debugger. Locals with value "0" may also be hidden. + /// A value of is a sufficient, but not a necessary, condition for hiding the + /// local in the debugger. Locals with value may also be hidden. /// /// Hidden locals must still be emitted because they participate in evaluation. /// - uint PdbAttributes { get; } + LocalVariableAttributes PdbAttributes { get; } /// /// Should return the synthesized dynamic attributes of the local definition if any. Else null. @@ -956,16 +958,6 @@ internal interface IGlobalMethodDefinition : IMethodDefinition new string Name { get; } } - internal enum EncFuncCode - { - Default = 0, - AddMethod = 1, - AddField = 2, - AddParameter = 3, - AddProperty = 4, - AddEvent = 5 - } - internal static class Extensions { internal static bool HasBody(this IMethodDefinition methodDef) diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs index 18914e0b90aea..662a76be62e9c 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.PortablePdb.cs @@ -5,82 +5,21 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.Metadata.Ecma335.Blobs; using Microsoft.CodeAnalysis; using Roslyn.Utilities; namespace Microsoft.Cci { + using Roslyn.Reflection; + using Roslyn.Reflection.Metadata.Ecma335; + using Roslyn.Reflection.Metadata.Ecma335.Blobs; + internal partial class MetadataWriter { - private struct DocumentRow - { - public BlobIdx Name; - public uint HashAlgorithm; // Guid - public BlobIdx Hash; - public uint Language; // Guid - } - - private struct MethodDebugInformationRow - { - public uint Document; // DocumentRid - public BlobIdx SequencePoints; - } - - private struct LocalScopeRow - { - public uint Method; // MethodRid - public uint ImportScope; // ImportScopeRid - public uint VariableList; // LocalVariableRid - public uint ConstantList; // LocalConstantRid - public uint StartOffset; - public uint Length; - } - - private struct LocalVariableRow - { - public ushort Attributes; - public ushort Index; - public StringIdx Name; - } - - private struct LocalConstantRow - { - public StringIdx Name; - public BlobIdx Signature; - } - - private struct ImportScopeRow - { - public uint Parent; // ImportScopeRid - public BlobIdx Imports; - } - - private struct StateMachineMethodRow - { - public uint MoveNextMethod; // MethodRid - public uint KickoffMethod; // MethodRid - } - - private struct CustomDebugInformationRow - { - public uint Parent; // HasCustomDebugInformation coded index - public uint Kind; // Guid - public BlobIdx Value; - } - - private readonly List _documentTable = new List(); - private readonly List _methodDebugInformationTable = new List(); - private readonly List _localScopeTable = new List(); - private readonly List _localVariableTable = new List(); - private readonly List _localConstantTable = new List(); - private readonly List _importScopeTable = new List(); - private readonly List _stateMachineMethodTable = new List(); - private readonly List _customDebugInformationTable = new List(); - - private readonly Dictionary _documentIndex = new Dictionary(); - private readonly Dictionary _scopeIndex = new Dictionary(ImportScopeEqualityComparer.Instance); - /// /// Import scopes are associated with binders (in C#) and thus multiple instances might be created for a single set of imports. /// We consider scopes with the same parent and the same imports the same. @@ -102,11 +41,14 @@ public int GetHashCode(IImportScope obj) } } - private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int localSignatureRowId) + private readonly Dictionary _documentIndex = new Dictionary(); + private readonly Dictionary _scopeIndex = new Dictionary(ImportScopeEqualityComparer.Instance); + + private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, StandaloneSignatureHandle localSignatureHandleOpt, ref LocalVariableHandle lastLocalVariableHandle, ref LocalConstantHandle lastLocalConstantHandle) { if (bodyOpt == null) { - _methodDebugInformationTable.Add(default(MethodDebugInformationRow)); + _debugMetadataOpt.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle)); return; } @@ -115,19 +57,22 @@ private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int lo if (!emitDebugInfo) { - _methodDebugInformationTable.Add(default(MethodDebugInformationRow)); + _debugMetadataOpt.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle)); return; } + var methodHandle = MetadataTokens.MethodDefinitionHandle(methodRid); + var bodyImportScope = bodyOpt.ImportScope; - int importScopeRid = (bodyImportScope != null) ? GetImportScopeIndex(bodyImportScope, _scopeIndex) : 0; + var importScopeHandle = (bodyImportScope != null) ? GetImportScopeIndex(bodyImportScope, _scopeIndex) : default(ImportScopeHandle); // documents & sequence points: - int singleDocumentRowId; + DocumentHandle singleDocumentHandle; ArrayBuilder sequencePoints = ArrayBuilder.GetInstance(); bodyOpt.GetSequencePoints(sequencePoints); - BlobIdx sequencePointsBlob = SerializeSequencePoints(localSignatureRowId, sequencePoints.ToImmutableAndFree(), _documentIndex, out singleDocumentRowId); - _methodDebugInformationTable.Add(new MethodDebugInformationRow { Document = (uint)singleDocumentRowId, SequencePoints = sequencePointsBlob }); + BlobHandle sequencePointsBlob = SerializeSequencePoints(localSignatureHandleOpt, sequencePoints.ToImmutableAndFree(), _documentIndex, out singleDocumentHandle); + + _debugMetadataOpt.AddMethodDebugInformation(document: singleDocumentHandle, sequencePoints: sequencePointsBlob); // Unlike native PDB we don't emit an empty root scope. // scopes are already ordered by StartOffset ascending then by EndOffset descending (the longest scope first). @@ -135,42 +80,36 @@ private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int lo if (bodyOpt.LocalScopes.Length == 0) { // TODO: the compiler should produce a scope for each debuggable method - _localScopeTable.Add(new LocalScopeRow - { - Method = (uint)methodRid, - ImportScope = (uint)importScopeRid, - VariableList = (uint)_localVariableTable.Count + 1, - ConstantList = (uint)_localConstantTable.Count + 1, - StartOffset = 0, - Length = (uint)bodyOpt.IL.Length - }); + _debugMetadataOpt.AddLocalScope( + method: methodHandle, + importScope: importScopeHandle, + variableList: NextHandle(lastLocalVariableHandle), + constantList: NextHandle(lastLocalConstantHandle), + startOffset: 0, + length: bodyOpt.IL.Length); } else { foreach (LocalScope scope in bodyOpt.LocalScopes) { - _localScopeTable.Add(new LocalScopeRow - { - Method = (uint)methodRid, - ImportScope = (uint)importScopeRid, - VariableList = (uint)_localVariableTable.Count + 1, - ConstantList = (uint)_localConstantTable.Count + 1, - StartOffset = (uint)scope.StartOffset, - Length = (uint)scope.Length - }); + _debugMetadataOpt.AddLocalScope( + method: methodHandle, + importScope: importScopeHandle, + variableList: NextHandle(lastLocalVariableHandle), + constantList: NextHandle(lastLocalConstantHandle), + startOffset: scope.StartOffset, + length: scope.Length); foreach (ILocalDefinition local in scope.Variables) { Debug.Assert(local.SlotIndex >= 0); - _localVariableTable.Add(new LocalVariableRow - { - Attributes = (ushort)local.PdbAttributes, - Index = (ushort)local.SlotIndex, - Name = _debugHeapsOpt.GetStringIndex(local.Name) - }); + lastLocalVariableHandle = _debugMetadataOpt.AddLocalVariable( + attributes: local.PdbAttributes, + index: local.SlotIndex, + name: _debugMetadataOpt.GetOrAddString(local.Name)); - SerializeDynamicLocalInfo(local, rowId: _localVariableTable.Count, isConstant: false); + SerializeDynamicLocalInfo(local, lastLocalVariableHandle); } foreach (ILocalDefinition constant in scope.Constants) @@ -178,13 +117,11 @@ private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int lo var mdConstant = constant.CompileTimeValue; Debug.Assert(mdConstant != null); - _localConstantTable.Add(new LocalConstantRow - { - Name = _debugHeapsOpt.GetStringIndex(constant.Name), - Signature = SerializeLocalConstantSignature(constant) - }); + lastLocalConstantHandle = _debugMetadataOpt.AddLocalConstant( + name: _debugMetadataOpt.GetOrAddString(constant.Name), + signature: SerializeLocalConstantSignature(constant)); - SerializeDynamicLocalInfo(constant, rowId: _localConstantTable.Count, isConstant: true); + SerializeDynamicLocalInfo(constant, lastLocalConstantHandle); } } } @@ -192,30 +129,37 @@ private void SerializeMethodDebugInfo(IMethodBody bodyOpt, int methodRid, int lo var asyncDebugInfo = bodyOpt.AsyncDebugInfo; if (asyncDebugInfo != null) { - _stateMachineMethodTable.Add(new StateMachineMethodRow - { - MoveNextMethod = (uint)methodRid, - KickoffMethod = (uint)GetMethodDefIndex(asyncDebugInfo.KickoffMethod) - }); + _debugMetadataOpt.AddStateMachineMethod( + moveNextMethod: methodHandle, + kickoffMethod: GetMethodDefinitionHandle(asyncDebugInfo.KickoffMethod)); - SerializeAsyncMethodSteppingInfo(asyncDebugInfo, methodRid); + SerializeAsyncMethodSteppingInfo(asyncDebugInfo, methodHandle); } - SerializeStateMachineLocalScopes(bodyOpt, methodRid); + SerializeStateMachineLocalScopes(bodyOpt, methodHandle); // delta doesn't need this information - we use information recorded by previous generation emit if (Context.ModuleBuilder.CommonCompilation.Options.EnableEditAndContinue && !IsFullMetadata) { - SerializeEncMethodDebugInformation(bodyOpt, methodRid); + SerializeEncMethodDebugInformation(bodyOpt, methodHandle); } } - private BlobIdx SerializeLocalConstantSignature(ILocalDefinition localConstant) + private static LocalVariableHandle NextHandle(LocalVariableHandle handle) => + MetadataTokens.LocalVariableHandle(MetadataTokens.GetRowNumber(handle) + 1); + + private static LocalConstantHandle NextHandle(LocalConstantHandle handle) => + MetadataTokens.LocalConstantHandle(MetadataTokens.GetRowNumber(handle) + 1); + + private BlobHandle SerializeLocalConstantSignature(ILocalDefinition localConstant) { - var writer = new BlobBuilder(); + var builder = new BlobBuilder(); + + // TODO: BlobEncoder.LocalConstantSignature // CustomMod* - SerializeCustomModifiers(localConstant.CustomModifiers, writer); + var encoder = new CustomModifiersEncoder(builder); + SerializeCustomModifiers(encoder, localConstant.CustomModifiers); var type = localConstant.Type; var typeCode = type.TypeCode(Context); @@ -225,81 +169,68 @@ private BlobIdx SerializeLocalConstantSignature(ILocalDefinition localConstant) // PrimitiveConstant or EnumConstant if (value is decimal) { - writer.WriteByte(0x11); - writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); + builder.WriteByte(0x11); + builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(GetTypeHandle(type))); - writer.WriteDecimal((decimal)value); + builder.WriteDecimal((decimal)value); } else if (value is DateTime) { - writer.WriteByte(0x11); - writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); + builder.WriteByte(0x11); + builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(GetTypeHandle(type))); - writer.WriteDateTime((DateTime)value); + builder.WriteDateTime((DateTime)value); } else if (typeCode == PrimitiveTypeCode.String) { - writer.WriteByte((byte)ConstantTypeCode.String); + builder.WriteByte((byte)ConstantTypeCode.String); if (value == null) { - writer.WriteByte(0xff); + builder.WriteByte(0xff); } else { - writer.WriteUTF16((string)value); + builder.WriteUTF16((string)value); } } else if (value != null) { // TypeCode - writer.WriteByte((byte)GetConstantTypeCode(value)); + builder.WriteByte((byte)MetadataWriterUtilities.GetConstantTypeCode(value)); + // Value - writer.WriteConstant(value); + builder.WriteConstant(value); // EnumType if (type.IsEnum) { - writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); + builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(GetTypeHandle(type))); } } else if (this.module.IsPlatformType(type, PlatformType.SystemObject)) { - writer.WriteByte(0x1c); + builder.WriteByte(0x1c); } else { - writer.WriteByte((byte)(type.IsValueType ? 0x11 : 0x12)); - writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(type, treatRefAsPotentialTypeSpec: true)); + builder.WriteByte((byte)(type.IsValueType ? 0x11 : 0x12)); + builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(GetTypeHandle(type))); } - return _debugHeapsOpt.GetBlobIndex(writer); - } - - private static uint HasCustomDebugInformation(HasCustomDebugInformationTag tag, int rowId) - { - return (uint)(rowId << 5) | (uint)tag; - } - - private enum HasCustomDebugInformationTag - { - MethodDef = 0, - Module = 7, - Assembly = 14, - LocalVariable = 24, - LocalConstant = 25, + return _debugMetadataOpt.GetOrAddBlob(builder); } #region ImportScope - private const int ModuleImportScopeRid = 1; + private static readonly ImportScopeHandle ModuleImportScopeHandle = MetadataTokens.ImportScopeHandle(1); private void SerializeImport(BlobBuilder writer, AssemblyReferenceAlias alias) { // ::= AliasAssemblyReference writer.WriteByte((byte)ImportDefinitionKind.AliasAssemblyReference); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(alias.Name))); - writer.WriteCompressedInteger((uint)GetOrAddAssemblyRefIndex(alias.Assembly)); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(alias.Name))); + writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(GetOrAddAssemblyReferenceHandle(alias.Assembly))); } private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) @@ -312,8 +243,8 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) // ::= ImportXmlNamespace writer.WriteByte((byte)ImportDefinitionKind.ImportXmlNamespace); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.TargetXmlNamespaceOpt))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(import.AliasOpt))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(import.TargetXmlNamespaceOpt))); } else if (import.TargetTypeOpt != null) { @@ -324,7 +255,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) { // ::= AliasType writer.WriteByte((byte)ImportDefinitionKind.AliasType); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(import.AliasOpt))); } else { @@ -332,7 +263,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) writer.WriteByte((byte)ImportDefinitionKind.ImportType); } - writer.WriteCompressedInteger(GetTypeDefOrRefCodedIndex(import.TargetTypeOpt, treatRefAsPotentialTypeSpec: true)); // TODO: index in release build + writer.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(GetTypeHandle(import.TargetTypeOpt))); // TODO: index in release build } else if (import.TargetNamespaceOpt != null) { @@ -342,7 +273,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) { // ::= AliasAssemblyNamespace writer.WriteByte((byte)ImportDefinitionKind.AliasAssemblyNamespace); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(import.AliasOpt))); } else { @@ -350,7 +281,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) writer.WriteByte((byte)ImportDefinitionKind.ImportAssemblyNamespace); } - writer.WriteCompressedInteger((uint)GetAssemblyRefIndex(import.TargetAssemblyOpt)); + writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(GetAssemblyReferenceHandle(import.TargetAssemblyOpt))); } else { @@ -358,7 +289,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) { // ::= AliasNamespace writer.WriteByte((byte)ImportDefinitionKind.AliasNamespace); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(import.AliasOpt))); } else { @@ -369,7 +300,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) // TODO: cache? string namespaceName = TypeNameSerializer.BuildQualifiedNamespaceName(import.TargetNamespaceOpt); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(namespaceName))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(namespaceName))); } else { @@ -378,7 +309,7 @@ private void SerializeImport(BlobBuilder writer, UsedNamespaceOrType import) Debug.Assert(import.TargetAssemblyOpt == null); writer.WriteByte((byte)ImportDefinitionKind.ImportAssemblyReferenceAlias); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(_debugHeapsOpt.GetBlobIndexUtf8(import.AliasOpt))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(_debugMetadataOpt.GetOrAddBlobUtf8(import.AliasOpt))); } } @@ -399,39 +330,34 @@ private void DefineModuleImportScope() SerializeImport(writer, import); } - _importScopeTable.Add(new ImportScopeRow - { - Parent = 0, - Imports = _debugHeapsOpt.GetBlobIndex(writer) - }); + var rid = _debugMetadataOpt.AddImportScope( + parentScope: default(ImportScopeHandle), + imports: _debugMetadataOpt.GetOrAddBlob(writer)); - Debug.Assert(_importScopeTable.Count == ModuleImportScopeRid); + Debug.Assert(rid == ModuleImportScopeHandle); } - private int GetImportScopeIndex(IImportScope scope, Dictionary scopeIndex) + private ImportScopeHandle GetImportScopeIndex(IImportScope scope, Dictionary scopeIndex) { - int scopeRid; - if (scopeIndex.TryGetValue(scope, out scopeRid)) + ImportScopeHandle scopeHandle; + if (scopeIndex.TryGetValue(scope, out scopeHandle)) { // scope is already indexed: - return scopeRid; + return scopeHandle; } var parent = scope.Parent; - int parentScopeRid = (parent != null) ? GetImportScopeIndex(scope.Parent, scopeIndex) : ModuleImportScopeRid; + var parentScopeHandle = (parent != null) ? GetImportScopeIndex(scope.Parent, scopeIndex) : ModuleImportScopeHandle; - _importScopeTable.Add(new ImportScopeRow - { - Parent = (uint)parentScopeRid, - Imports = SerializeImportsBlob(scope) - }); + var result = _debugMetadataOpt.AddImportScope( + parentScope: parentScopeHandle, + imports: SerializeImportsBlob(scope)); - var rid = _importScopeTable.Count; - scopeIndex.Add(scope, rid); - return rid; + scopeIndex.Add(scope, result); + return result; } - private BlobIdx SerializeImportsBlob(IImportScope scope) + private BlobHandle SerializeImportsBlob(IImportScope scope) { var writer = new BlobBuilder(); @@ -440,7 +366,7 @@ private BlobIdx SerializeImportsBlob(IImportScope scope) SerializeImport(writer, import); } - return _debugHeapsOpt.GetBlobIndex(writer); + return _debugMetadataOpt.GetOrAddBlob(writer); } private void SerializeModuleDefaultNamespace() @@ -452,19 +378,17 @@ private void SerializeModuleDefaultNamespace() return; } - _customDebugInformationTable.Add(new CustomDebugInformationRow - { - Parent = HasCustomDebugInformation(HasCustomDebugInformationTag.Module, 1), - Kind = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.DefaultNamespace), - Value = _debugHeapsOpt.GetBlobIndexUtf8(module.DefaultNamespace) - }); + _debugMetadataOpt.AddCustomDebugInformation( + parent: EntityHandle.ModuleDefinition, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.DefaultNamespace), + value: _debugMetadataOpt.GetOrAddBlobUtf8(module.DefaultNamespace)); } #endregion #region Locals - private void SerializeDynamicLocalInfo(ILocalDefinition local, int rowId, bool isConstant) + private void SerializeDynamicLocalInfo(ILocalDefinition local, EntityHandle parent) { var dynamicFlags = local.DynamicTransformFlags; if (dynamicFlags.IsDefault) @@ -474,14 +398,10 @@ private void SerializeDynamicLocalInfo(ILocalDefinition local, int rowId, bool i var value = SerializeBitVector(dynamicFlags); - var tag = isConstant ? HasCustomDebugInformationTag.LocalConstant : HasCustomDebugInformationTag.LocalVariable; - - _customDebugInformationTable.Add(new CustomDebugInformationRow - { - Parent = HasCustomDebugInformation(tag, rowId), - Kind = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.DynamicLocalVariables), - Value = _debugHeapsOpt.GetBlobIndex(value), - }); + _debugMetadataOpt.AddCustomDebugInformation( + parent: parent, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.DynamicLocalVariables), + value: _debugMetadataOpt.GetOrAddBlob(value)); } private static ImmutableArray SerializeBitVector(ImmutableArray vector) @@ -532,7 +452,7 @@ private static ImmutableArray SerializeBitVector(ImmutableArray= -1); @@ -545,18 +465,16 @@ private void SerializeAsyncMethodSteppingInfo(AsyncMethodBodyDebugInfo asyncInfo { writer.WriteUInt32((uint)asyncInfo.YieldOffsets[i]); writer.WriteUInt32((uint)asyncInfo.ResumeOffsets[i]); - writer.WriteCompressedInteger((uint)moveNextMethodRid); + writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(moveNextMethod)); } - _customDebugInformationTable.Add(new CustomDebugInformationRow - { - Parent = HasCustomDebugInformation(HasCustomDebugInformationTag.MethodDef, moveNextMethodRid), - Kind = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob), - Value = _debugHeapsOpt.GetBlobIndex(writer), - }); + _debugMetadataOpt.AddCustomDebugInformation( + parent: moveNextMethod, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob), + value: _debugMetadataOpt.GetOrAddBlob(writer)); } - private void SerializeStateMachineLocalScopes(IMethodBody methodBody, int methodRowId) + private void SerializeStateMachineLocalScopes(IMethodBody methodBody, MethodDefinitionHandle method) { var scopes = methodBody.StateMachineHoistedLocalScopes; if (scopes.IsDefaultOrEmpty) @@ -572,28 +490,26 @@ private void SerializeStateMachineLocalScopes(IMethodBody methodBody, int method writer.WriteUInt32((uint)scope.Length); } - _customDebugInformationTable.Add(new CustomDebugInformationRow - { - Parent = HasCustomDebugInformation(HasCustomDebugInformationTag.MethodDef, methodRowId), - Kind = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.StateMachineHoistedLocalScopes), - Value = _debugHeapsOpt.GetBlobIndex(writer), - }); + _debugMetadataOpt.AddCustomDebugInformation( + parent: method, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.StateMachineHoistedLocalScopes), + value: _debugMetadataOpt.GetOrAddBlob(writer)); } #endregion #region Sequence Points - private BlobIdx SerializeSequencePoints( - int localSignatureRowId, + private BlobHandle SerializeSequencePoints( + StandaloneSignatureHandle localSignatureHandleOpt, ImmutableArray sequencePoints, - Dictionary documentIndex, - out int singleDocumentRowId) + Dictionary documentIndex, + out DocumentHandle singleDocumentHandle) { if (sequencePoints.Length == 0) { - singleDocumentRowId = 0; - return default(BlobIdx); + singleDocumentHandle = default(DocumentHandle); + return default(BlobHandle); } var writer = new BlobBuilder(); @@ -602,17 +518,17 @@ private BlobIdx SerializeSequencePoints( int previousNonHiddenStartColumn = -1; // header: - writer.WriteCompressedInteger((uint)localSignatureRowId); + writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(localSignatureHandleOpt)); var previousDocument = TryGetSingleDocument(sequencePoints); - singleDocumentRowId = (previousDocument != null) ? GetOrAddDocument(previousDocument, documentIndex) : 0; + singleDocumentHandle = (previousDocument != null) ? GetOrAddDocument(previousDocument, documentIndex) : default(DocumentHandle); for (int i = 0; i < sequencePoints.Length; i++) { var currentDocument = sequencePoints[i].Document; if (previousDocument != currentDocument) { - int documentRowId = GetOrAddDocument(currentDocument, documentIndex); + var documentHandle = GetOrAddDocument(currentDocument, documentIndex); // optional document in header or document record: if (previousDocument != null) @@ -620,18 +536,18 @@ private BlobIdx SerializeSequencePoints( writer.WriteCompressedInteger(0); } - writer.WriteCompressedInteger((uint)documentRowId); + writer.WriteCompressedInteger(MetadataTokens.GetRowNumber(documentHandle)); previousDocument = currentDocument; } // delta IL offset: if (i > 0) { - writer.WriteCompressedInteger((uint)(sequencePoints[i].Offset - sequencePoints[i - 1].Offset)); + writer.WriteCompressedInteger(sequencePoints[i].Offset - sequencePoints[i - 1].Offset); } else { - writer.WriteCompressedInteger((uint)sequencePoints[i].Offset); + writer.WriteCompressedInteger(sequencePoints[i].Offset); } if (sequencePoints[i].IsHidden) @@ -647,8 +563,8 @@ private BlobIdx SerializeSequencePoints( if (previousNonHiddenStartLine < 0) { Debug.Assert(previousNonHiddenStartColumn < 0); - writer.WriteCompressedInteger((uint)sequencePoints[i].StartLine); - writer.WriteCompressedInteger((uint)sequencePoints[i].StartColumn); + writer.WriteCompressedInteger(sequencePoints[i].StartLine); + writer.WriteCompressedInteger(sequencePoints[i].StartColumn); } else { @@ -660,7 +576,7 @@ private BlobIdx SerializeSequencePoints( previousNonHiddenStartColumn = sequencePoints[i].StartColumn; } - return _debugHeapsOpt.GetBlobIndex(writer); + return _debugMetadataOpt.GetOrAddBlob(writer); } private static DebugSourceDocument TryGetSingleDocument(ImmutableArray sequencePoints) @@ -685,11 +601,11 @@ private void SerializeDeltaLinesAndColumns(BlobBuilder writer, SequencePoint seq // only hidden sequence points have zero width Debug.Assert(deltaLines != 0 || deltaColumns != 0 || sequencePoint.IsHidden); - writer.WriteCompressedInteger((uint)deltaLines); + writer.WriteCompressedInteger(deltaLines); if (deltaLines == 0) { - writer.WriteCompressedInteger((uint)deltaColumns); + writer.WriteCompressedInteger(deltaColumns); } else { @@ -701,31 +617,29 @@ private void SerializeDeltaLinesAndColumns(BlobBuilder writer, SequencePoint seq #region Documents - private int GetOrAddDocument(DebugSourceDocument document, Dictionary index) + private DocumentHandle GetOrAddDocument(DebugSourceDocument document, Dictionary index) { - int documentRowId; - if (!index.TryGetValue(document, out documentRowId)) + DocumentHandle documentHandle; + if (!index.TryGetValue(document, out documentHandle)) { - documentRowId = _documentTable.Count + 1; - index.Add(document, documentRowId); - var checksumAndAlgorithm = document.ChecksumAndAlgorithm; - _documentTable.Add(new DocumentRow - { - Name = SerializeDocumentName(document.Location), - HashAlgorithm = (uint)(checksumAndAlgorithm.Item1.IsDefault ? 0 : _debugHeapsOpt.GetGuidIndex(checksumAndAlgorithm.Item2)), - Hash = (checksumAndAlgorithm.Item1.IsDefault) ? new BlobIdx(0) : _debugHeapsOpt.GetBlobIndex(checksumAndAlgorithm.Item1), - Language = (uint)_debugHeapsOpt.GetGuidIndex(document.Language), - }); + + documentHandle = _debugMetadataOpt.AddDocument( + name: SerializeDocumentName(document.Location), + hashAlgorithm: checksumAndAlgorithm.Item1.IsDefault ? default(GuidHandle) : _debugMetadataOpt.GetOrAddGuid(checksumAndAlgorithm.Item2), + hash: (checksumAndAlgorithm.Item1.IsDefault) ? default(BlobHandle) : _debugMetadataOpt.GetOrAddBlob(checksumAndAlgorithm.Item1), + language: _debugMetadataOpt.GetOrAddGuid(document.Language)); + + index.Add(document, documentHandle); } - return documentRowId; + return documentHandle; } private static readonly char[] s_separator1 = { '/' }; private static readonly char[] s_separator2 = { '\\' }; - private BlobIdx SerializeDocumentName(string name) + private BlobHandle SerializeDocumentName(string name) { Debug.Assert(name != null); @@ -740,11 +654,11 @@ private BlobIdx SerializeDocumentName(string name) // TODO: avoid allocations foreach (var part in name.Split(separator)) { - BlobIdx partIndex = _debugHeapsOpt.GetBlobIndex(ImmutableArray.Create(s_utf8Encoding.GetBytes(part))); - writer.WriteCompressedInteger((uint)_debugHeapsOpt.ResolveBlobIndex(partIndex)); + BlobHandle partIndex = _debugMetadataOpt.GetOrAddBlob(ImmutableArray.Create(s_utf8Encoding.GetBytes(part))); + writer.WriteCompressedInteger(_debugMetadataOpt.GetHeapOffset(partIndex)); } - return _debugHeapsOpt.GetBlobIndex(writer); + return _debugMetadataOpt.GetOrAddBlob(writer); } private static int Count(string str, char c) @@ -765,7 +679,7 @@ private static int Count(string str, char c) #region Edit and Continue - private void SerializeEncMethodDebugInformation(IMethodBody methodBody, int methodRowId) + private void SerializeEncMethodDebugInformation(IMethodBody methodBody, MethodDefinitionHandle method) { var encInfo = GetEncMethodDebugInfo(methodBody); @@ -775,12 +689,10 @@ private void SerializeEncMethodDebugInformation(IMethodBody methodBody, int meth encInfo.SerializeLocalSlots(writer); - _customDebugInformationTable.Add(new CustomDebugInformationRow - { - Parent = HasCustomDebugInformation(HasCustomDebugInformationTag.MethodDef, methodRowId), - Kind = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.EncLocalSlotMap), - Value = _debugHeapsOpt.GetBlobIndex(writer), - }); + _debugMetadataOpt.AddCustomDebugInformation( + parent: method, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap), + value: _debugMetadataOpt.GetOrAddBlob(writer)); } if (!encInfo.Lambdas.IsDefaultOrEmpty) @@ -789,110 +701,10 @@ private void SerializeEncMethodDebugInformation(IMethodBody methodBody, int meth encInfo.SerializeLambdaMap(writer); - _customDebugInformationTable.Add(new CustomDebugInformationRow - { - Parent = HasCustomDebugInformation(HasCustomDebugInformationTag.MethodDef, methodRowId), - Kind = (uint)_debugHeapsOpt.GetGuidIndex(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), - Value = _debugHeapsOpt.GetBlobIndex(writer), - }); - } - } - - #endregion - - #region Table Serialization - - private void SerializeDocumentTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _documentTable) - { - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Name), metadataSizes.BlobIndexSize); - writer.WriteReference(row.HashAlgorithm, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Hash), metadataSizes.BlobIndexSize); - writer.WriteReference(row.Language, metadataSizes.GuidIndexSize); - } - } - - private void SerializeMethodDebugInformationTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _methodDebugInformationTable) - { - writer.WriteReference(row.Document, metadataSizes.DocumentIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.SequencePoints), metadataSizes.BlobIndexSize); - } - } - - private void SerializeLocalScopeTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _localScopeTable) - { - writer.WriteReference(row.Method, metadataSizes.MethodDefIndexSize); - writer.WriteReference(row.ImportScope, metadataSizes.ImportScopeIndexSize); - writer.WriteReference(row.VariableList, metadataSizes.LocalVariableIndexSize); - writer.WriteReference(row.ConstantList, metadataSizes.LocalConstantIndexSize); - writer.WriteUInt32(row.StartOffset); - writer.WriteUInt32(row.Length); - } - } - - private void SerializeLocalVariableTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _localVariableTable) - { - writer.WriteUInt16(row.Attributes); - writer.WriteUInt16(row.Index); - writer.WriteReference((uint)_debugHeapsOpt.ResolveStringIndex(row.Name), metadataSizes.StringIndexSize); - } - } - - private void SerializeLocalConstantTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _localConstantTable) - { - writer.WriteReference((uint)_debugHeapsOpt.ResolveStringIndex(row.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Signature), metadataSizes.BlobIndexSize); - } - } - - private void SerializeImportScopeTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _importScopeTable) - { - writer.WriteReference(row.Parent, metadataSizes.ImportScopeIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Imports), metadataSizes.BlobIndexSize); - } - } - - private void SerializeStateMachineMethodTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (var row in _stateMachineMethodTable) - { - writer.WriteReference(row.MoveNextMethod, metadataSizes.MethodDefIndexSize); - writer.WriteReference(row.KickoffMethod, metadataSizes.MethodDefIndexSize); - } - } - - private void SerializeCustomDebugInformationTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - // sort by Parent, Kind - _customDebugInformationTable.Sort(CustomDebugInformationRowComparer.Instance); - - foreach (var row in _customDebugInformationTable) - { - writer.WriteReference(row.Parent, metadataSizes.HasCustomDebugInformationSize); - writer.WriteReference(row.Kind, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Value), metadataSizes.BlobIndexSize); - } - } - - private class CustomDebugInformationRowComparer : Comparer - { - public static readonly CustomDebugInformationRowComparer Instance = new CustomDebugInformationRowComparer(); - - public override int Compare(CustomDebugInformationRow x, CustomDebugInformationRow y) - { - int result = (int)x.Parent - (int)y.Parent; - return (result != 0) ? result : (int)x.Kind - (int)y.Kind; + _debugMetadataOpt.AddCustomDebugInformation( + parent: method, + kind: _debugMetadataOpt.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), + value: _debugMetadataOpt.GetOrAddBlob(writer)); } } diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs index b166c6793d66d..a95226fee44bd 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/MetadataWriter.cs @@ -11,6 +11,7 @@ using System.Reflection.Emit; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; using System.Runtime.InteropServices; using System.Text; using System.Threading; @@ -23,6 +24,12 @@ namespace Microsoft.Cci { + using Roslyn.Reflection; + using Roslyn.Reflection.Metadata; + using Roslyn.Reflection.Metadata.Ecma335; + using Roslyn.Reflection.Metadata.Ecma335.Blobs; + using Roslyn.Reflection.PortableExecutable; + internal abstract partial class MetadataWriter { private static readonly Encoding s_utf8Encoding = Encoding.UTF8; @@ -72,8 +79,8 @@ internal abstract partial class MetadataWriter private readonly Dictionary, int> _smallMethodBodies; protected MetadataWriter( - MetadataHeapsBuilder heaps, - MetadataHeapsBuilder debugHeapsOpt, + MetadataBuilder metadata, + MetadataBuilder debugMetadataOpt, EmitContext context, CommonMessageProvider messageProvider, bool allowMissingMethodBodies, @@ -86,7 +93,7 @@ protected MetadataWriter( // EDMAURER provide some reasonable size estimates for these that will avoid // much of the reallocation that would occur when growing these from empty. - _signatureIndex = new Dictionary>>(module.HintNumberOfMethodDefinitions); //ignores field signatures + _signatureIndex = new Dictionary>>(module.HintNumberOfMethodDefinitions); //ignores field signatures _numTypeDefsEstimate = module.HintNumberOfMethodDefinitions / 6; _exportedTypeIndex = new Dictionary(_numTypeDefsEstimate); @@ -96,8 +103,9 @@ protected MetadataWriter( this.messageProvider = messageProvider; _cancellationToken = cancellationToken; - this.heaps = heaps; - _debugHeapsOpt = debugHeapsOpt; + this.metadata = metadata; + _debugMetadataOpt = debugMetadataOpt; + _smallMethodBodies = new Dictionary, int>(ByteSequenceComparer.Instance); } @@ -144,23 +152,21 @@ private bool IsMinimalDelta protected abstract Guid EncBaseId { get; } /// - /// Returns true and the 1-based index of the type definition + /// Returns true and full metadata handle of the type definition /// if the type definition is recognized. Otherwise returns false. - /// The index is into the full metadata. /// - protected abstract bool TryGetTypeDefIndex(ITypeDefinition def, out int index); + protected abstract bool TryGetTypeDefinitionHandle(ITypeDefinition def, out TypeDefinitionHandle handle); /// - /// The 1-based index of the type definition. - /// The index is into the full metadata. + /// Get full metadata handle of the type definition. /// - protected abstract int GetTypeDefIndex(ITypeDefinition def); + protected abstract TypeDefinitionHandle GetTypeDefinitionHandle(ITypeDefinition def); /// - /// The type definition at the 0-based index into the full set. Deltas - /// are only required to support indexing into current generation. + /// The type definition corresponding to full metadata type handle. + /// Deltas are only required to support indexing into current generation. /// - protected abstract ITypeDefinition GetTypeDef(int index); + protected abstract ITypeDefinition GetTypeDef(TypeDefinitionHandle handle); /// /// The type definitions to be emitted, in row order. These @@ -169,10 +175,9 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetTypeDefs(); /// - /// The 1-based index of the event definition. - /// The index is into the full metadata. + /// Get full metadata handle of the event definition. /// - protected abstract int GetEventDefIndex(IEventDefinition def); + protected abstract EventDefinitionHandle GetEventDefinitionHandle(IEventDefinition def); /// /// The event definitions to be emitted, in row order. These @@ -181,10 +186,9 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetEventDefs(); /// - /// The 1-based index of the field definition. - /// The index is into the full metadata. + /// Get full metadata handle of the field definition. /// - protected abstract int GetFieldDefIndex(IFieldDefinition def); + protected abstract FieldDefinitionHandle GetFieldDefinitionHandle(IFieldDefinition def); /// /// The field definitions to be emitted, in row order. These @@ -193,23 +197,22 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetFieldDefs(); /// - /// Returns true and the 1-based index of the method definition + /// Returns true and handle of the method definition /// if the method definition is recognized. Otherwise returns false. /// The index is into the full metadata. /// - protected abstract bool TryGetMethodDefIndex(IMethodDefinition def, out int index); + protected abstract bool TryGetMethodDefinitionHandle(IMethodDefinition def, out MethodDefinitionHandle handle); /// - /// The 1-based index of the method definition. - /// The index is into the full metadata. + /// Get full metadata handle of the method definition. /// - protected abstract int GetMethodDefIndex(IMethodDefinition def); + protected abstract MethodDefinitionHandle GetMethodDefinitionHandle(IMethodDefinition def); /// - /// The method definition at the 0-based index into the full set. Deltas - /// are only required to support indexing into current generation. + /// The method definition corresponding to full metadata method handle. + /// Deltas are only required to support indexing into current generation. /// - protected abstract IMethodDefinition GetMethodDef(int index); + protected abstract IMethodDefinition GetMethodDef(MethodDefinitionHandle handle); /// /// The method definitions to be emitted, in row order. These @@ -218,10 +221,9 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetMethodDefs(); /// - /// The 1-based index of the property definition. - /// The index is into the full metadata. + /// Get full metadata handle of the property definition. /// - protected abstract int GetPropertyDefIndex(IPropertyDefinition def); + protected abstract PropertyDefinitionHandle GetPropertyDefIndex(IPropertyDefinition def); /// /// The property definitions to be emitted, in row order. These @@ -230,10 +232,9 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetPropertyDefs(); /// - /// The 1-based index of the parameter definition. - /// The index is into the full metadata. + /// The full metadata handle of the parameter definition. /// - protected abstract int GetParameterDefIndex(IParameterDefinition def); + protected abstract ParameterHandle GetParameterHandle(IParameterDefinition def); /// /// The parameter definitions to be emitted, in row order. These @@ -248,27 +249,26 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetGenericParameters(); /// - /// The 1-based index of the first field of the type. + /// The handle of the first field of the type. /// - protected abstract int GetFieldDefIndex(INamedTypeDefinition typeDef); + protected abstract FieldDefinitionHandle GetFirstFieldDefinitionHandle(INamedTypeDefinition typeDef); /// - /// The 1-based index of the first method of the type. + /// The handle of the first method of the type. /// - protected abstract int GetMethodDefIndex(INamedTypeDefinition typeDef); + protected abstract MethodDefinitionHandle GetFirstMethodDefinitionHandle(INamedTypeDefinition typeDef); /// - /// The 1-based index of the first parameter of the method. + /// The handle of the first parameter of the method. /// - protected abstract int GetParameterDefIndex(IMethodDefinition methodDef); + protected abstract ParameterHandle GetFirstParameterHandle(IMethodDefinition methodDef); /// - /// Return the 1-based index of the assembly reference, adding + /// Return full metadata handle of the assembly reference, adding /// the reference to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddAssemblyRefIndex(IAssemblyReference reference); + protected abstract AssemblyReferenceHandle GetOrAddAssemblyReferenceHandle(IAssemblyReference reference); /// /// The assembly references to be emitted, in row order. These @@ -287,12 +287,11 @@ private bool IsMinimalDelta // Entries aren't added for P/Invoked modules. /// - /// Return the 1-based index of the module reference, adding + /// Return full metadata handle of the module reference, adding /// the reference to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddModuleRefIndex(string reference); + protected abstract ModuleReferenceHandle GetOrAddModuleReferenceHandle(string reference); /// /// The module references to be emitted, in row order. These @@ -301,12 +300,11 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetModuleRefs(); /// - /// Return the 1-based index of the member reference, adding + /// Return full metadata handle of the member reference, adding /// the reference to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddMemberRefIndex(ITypeMemberReference reference); + protected abstract MemberReferenceHandle GetOrAddMemberReferenceHandle(ITypeMemberReference reference); /// /// The member references to be emitted, in row order. These @@ -315,12 +313,11 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetMemberRefs(); /// - /// Return the 1-based index of the method spec, adding + /// Return full metadata handle of the method spec, adding /// the spec to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddMethodSpecIndex(IGenericMethodInstanceReference reference); + protected abstract MethodSpecificationHandle GetOrAddMethodSpecificationHandle(IGenericMethodInstanceReference reference); /// /// The method specs to be emitted, in row order. These @@ -329,20 +326,18 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetMethodSpecs(); /// - /// Return true and the 1-based index of the type reference + /// Return true and full metadata handle of the type reference /// if the reference is available in the current generation. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract bool TryGetTypeRefIndex(ITypeReference reference, out int index); + protected abstract bool TryGetTypeRefeferenceHandle(ITypeReference reference, out TypeReferenceHandle handle); /// - /// Return the 1-based index of the type reference, adding + /// Return full metadata handle of the type reference, adding /// the reference to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddTypeRefIndex(ITypeReference reference); + protected abstract TypeReferenceHandle GetOrAddTypeReferenceHandle(ITypeReference reference); /// /// The type references to be emitted, in row order. These @@ -351,12 +346,11 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetTypeRefs(); /// - /// Return the 1-based index of the type spec, adding + /// Returns full metadata handle of the type spec, adding /// the spec to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddTypeSpecIndex(ITypeReference reference); + protected abstract TypeSpecificationHandle GetOrAddTypeSpecificationHandle(ITypeReference reference); /// /// The type specs to be emitted, in row order. These @@ -365,18 +359,17 @@ private bool IsMinimalDelta protected abstract IReadOnlyList GetTypeSpecs(); /// - /// Return the 1-based index of the signature index, adding + /// Returns full metadata handle the stanadlone signature, adding /// the signature to the index for this generation if missing. - /// The index is into the full metadata. However, deltas - /// are not required to return rows from previous generations. + /// Deltas are not required to return rows from previous generations. /// - protected abstract int GetOrAddStandAloneSignatureIndex(BlobIdx blobIndex); + protected abstract StandaloneSignatureHandle GetOrAddStandaloneSignatureHandle(BlobHandle handle); /// - /// The signature indices to be emitted, in row order. These + /// The signature blob handles to be emitted, in row order. These /// are just the signature indices from the current generation. /// - protected abstract IReadOnlyList GetStandAloneSignatures(); + protected abstract IReadOnlyList GetStandaloneSignatureBlobHandles(); protected abstract IEnumerable GetTopLevelTypes(IModule module); @@ -390,22 +383,22 @@ private bool IsMinimalDelta /// /// Populate EventMap table. /// - protected abstract void PopulateEventMapTableRows(List table); + protected abstract void PopulateEventMapTableRows(); /// /// Populate PropertyMap table. /// - protected abstract void PopulatePropertyMapTableRows(List table); + protected abstract void PopulatePropertyMapTableRows(); /// /// Populate EncLog table. /// - protected abstract void PopulateEncLogTableRows(List table, ImmutableArray rowCounts); + protected abstract void PopulateEncLogTableRows(ImmutableArray rowCounts); /// /// Populate EncMap table. /// - protected abstract void PopulateEncMapTableRows(List table, ImmutableArray rowCounts); + protected abstract void PopulateEncMapTableRows(ImmutableArray rowCounts); protected abstract void ReportReferencesToAddedSymbols(); @@ -419,108 +412,52 @@ private bool IsMinimalDelta // progress: private bool _tableIndicesAreComplete; - private int[] _pseudoSymbolTokenToTokenMap; + private EntityHandle[] _pseudoSymbolTokenToTokenMap; private IReference[] _pseudoSymbolTokenToReferenceMap; - private int[] _pseudoStringTokenToTokenMap; + private UserStringHandle[] _pseudoStringTokenToTokenMap; private bool _userStringTokenOverflow; private List _pseudoStringTokenToStringMap; private ReferenceIndexer _referenceVisitor; - protected readonly MetadataHeapsBuilder heaps; + protected readonly MetadataBuilder metadata; - // A heap builder distinct from heaps if we are emitting debug information into a separate Portable PDB stream. - // Shared heap builder (reference equals heaps) if we are embedding Portable PDB into the metadata stream. + // A builder distinct from type-system metadata builder if we are emitting debug information into a separate Portable PDB stream. + // Shared builder (reference equals heaps) if we are embedding Portable PDB into the metadata stream. // Null otherwise. - private readonly MetadataHeapsBuilder _debugHeapsOpt; + private readonly MetadataBuilder _debugMetadataOpt; - private bool EmitStandaloneDebugMetadata => _debugHeapsOpt != null && heaps != _debugHeapsOpt; + internal bool EmitStandaloneDebugMetadata => _debugMetadataOpt != null && metadata != _debugMetadataOpt; - private readonly Dictionary _customAttributeSignatureIndex = new Dictionary(); - private readonly Dictionary _typeSpecSignatureIndex = new Dictionary(); - private readonly Dictionary _exportedTypeIndex; + private readonly Dictionary _customAttributeSignatureIndex = new Dictionary(); + private readonly Dictionary _typeSpecSignatureIndex = new Dictionary(); + private readonly Dictionary _exportedTypeIndex; // value is a RowId private readonly List _exportedTypeList; - private readonly Dictionary _fileRefIndex = new Dictionary(32); //more than enough in most cases + private readonly Dictionary _fileRefIndex = new Dictionary(32); // more than enough in most cases, value is a RowId private readonly List _fileRefList = new List(32); - private readonly Dictionary _fieldSignatureIndex = new Dictionary(); + private readonly Dictionary _fieldSignatureIndex = new Dictionary(); // We need to keep track of both the index of the signature and the actual blob to support VB static local naming scheme. - private readonly Dictionary>> _signatureIndex; + private readonly Dictionary>> _signatureIndex; - private readonly Dictionary _marshallingDescriptorIndex = new Dictionary(); + private readonly Dictionary _marshallingDescriptorIndex = new Dictionary(); protected readonly List methodImplList = new List(); - private readonly Dictionary _methodInstanceSignatureIndex = new Dictionary(); + private readonly Dictionary _methodInstanceSignatureIndex = new Dictionary(); // Well known dummy cor library types whose refs are used for attaching assembly attributes off within net modules // There is no guarantee the types actually exist in a cor library internal static readonly string dummyAssemblyAttributeParentNamespace = "System.Runtime.CompilerServices"; internal static readonly string dummyAssemblyAttributeParentName = "AssemblyAttributesGoHere"; internal static readonly string[,] dummyAssemblyAttributeParentQualifier = { { "", "M" }, { "S", "SM" } }; - private readonly uint[,] _dummyAssemblyAttributeParent = { { 0, 0 }, { 0, 0 } }; - - internal const int MappedFieldDataAlignment = 8; - internal const int ManagedResourcesDataAlignment = 8; + private readonly TypeReferenceHandle[,] _dummyAssemblyAttributeParent = { { default(TypeReferenceHandle), default(TypeReferenceHandle) }, { default(TypeReferenceHandle), default(TypeReferenceHandle) } }; internal IModule Module => module; - private ImmutableArray GetRowCounts() - { - var rowCounts = new int[MetadataTokens.TableCount]; - - rowCounts[(int)TableIndex.Assembly] = EmitAssemblyDefinition ? 1 : 0; - rowCounts[(int)TableIndex.AssemblyRef] = _assemblyRefTable.Count; - rowCounts[(int)TableIndex.ClassLayout] = _classLayoutTable.Count; - rowCounts[(int)TableIndex.Constant] = _constantTable.Count; - rowCounts[(int)TableIndex.CustomAttribute] = _customAttributeTable.Count; - rowCounts[(int)TableIndex.DeclSecurity] = _declSecurityTable.Count; - rowCounts[(int)TableIndex.EncLog] = _encLogTable.Count; - rowCounts[(int)TableIndex.EncMap] = _encMapTable.Count; - rowCounts[(int)TableIndex.EventMap] = _eventMapTable.Count; - rowCounts[(int)TableIndex.Event] = _eventTable.Count; - rowCounts[(int)TableIndex.ExportedType] = _exportedTypeTable.Count; - rowCounts[(int)TableIndex.FieldLayout] = _fieldLayoutTable.Count; - rowCounts[(int)TableIndex.FieldMarshal] = _fieldMarshalTable.Count; - rowCounts[(int)TableIndex.FieldRva] = _fieldRvaTable.Count; - rowCounts[(int)TableIndex.Field] = _fieldDefTable.Count; - rowCounts[(int)TableIndex.File] = _fileTable.Count; - rowCounts[(int)TableIndex.GenericParamConstraint] = _genericParamConstraintTable.Count; - rowCounts[(int)TableIndex.GenericParam] = _genericParamTable.Count; - rowCounts[(int)TableIndex.ImplMap] = _implMapTable.Count; - rowCounts[(int)TableIndex.InterfaceImpl] = _interfaceImplTable.Count; - rowCounts[(int)TableIndex.ManifestResource] = _manifestResourceTable.Count; - rowCounts[(int)TableIndex.MemberRef] = _memberRefTable.Count; - rowCounts[(int)TableIndex.MethodImpl] = _methodImplTable.Count; - rowCounts[(int)TableIndex.MethodSemantics] = _methodSemanticsTable.Count; - rowCounts[(int)TableIndex.MethodSpec] = _methodSpecTable.Count; - rowCounts[(int)TableIndex.MethodDef] = _methodTable.Length; - rowCounts[(int)TableIndex.ModuleRef] = _moduleRefTable.Count; - rowCounts[(int)TableIndex.Module] = 1; - rowCounts[(int)TableIndex.NestedClass] = _nestedClassTable.Count; - rowCounts[(int)TableIndex.Param] = _paramTable.Count; - rowCounts[(int)TableIndex.PropertyMap] = _propertyMapTable.Count; - rowCounts[(int)TableIndex.Property] = _propertyTable.Count; - rowCounts[(int)TableIndex.StandAloneSig] = GetStandAloneSignatures().Count; - rowCounts[(int)TableIndex.TypeDef] = _typeDefTable.Count; - rowCounts[(int)TableIndex.TypeRef] = _typeRefTable.Count; - rowCounts[(int)TableIndex.TypeSpec] = _typeSpecTable.Count; - - rowCounts[(int)TableIndex.Document] = _documentTable.Count; - rowCounts[(int)TableIndex.MethodDebugInformation] = _methodDebugInformationTable.Count; - rowCounts[(int)TableIndex.LocalScope] = _localScopeTable.Count; - rowCounts[(int)TableIndex.LocalVariable] = _localVariableTable.Count; - rowCounts[(int)TableIndex.LocalConstant] = _localConstantTable.Count; - rowCounts[(int)TableIndex.StateMachineMethod] = _stateMachineMethodTable.Count; - rowCounts[(int)TableIndex.ImportScope] = _importScopeTable.Count; - rowCounts[(int)TableIndex.CustomDebugInformation] = _customDebugInformationTable.Count; - - return ImmutableArray.CreateRange(rowCounts); - } - private void CreateMethodBodyReferenceIndex() { int count; var referencesInIL = module.ReferencesInIL(out count); - _pseudoSymbolTokenToTokenMap = new int[count]; + _pseudoSymbolTokenToTokenMap = new EntityHandle[count]; _pseudoSymbolTokenToReferenceMap = new IReference[count]; int cur = 0; @@ -559,7 +496,7 @@ private void CreateUserStringIndices() _pseudoStringTokenToStringMap.Add(str); } - _pseudoStringTokenToTokenMap = new int[_pseudoStringTokenToStringMap.Count]; + _pseudoStringTokenToTokenMap = new UserStringHandle[_pseudoStringTokenToStringMap.Count]; } private void CreateIndicesForModule() @@ -733,7 +670,7 @@ private void CreateInitialAssemblyRefIndex() Debug.Assert(!_tableIndicesAreComplete); foreach (IAssemblyReference assemblyRef in this.module.GetAssemblyReferences(Context)) { - this.GetOrAddAssemblyRefIndex(assemblyRef); + this.GetOrAddAssemblyReferenceHandle(assemblyRef); } } @@ -774,40 +711,40 @@ private void CreateInitialFileRefIndex() } } - internal int GetAssemblyRefIndex(IAssemblyReference assemblyReference) + internal AssemblyReferenceHandle GetAssemblyReferenceHandle(IAssemblyReference assemblyReference) { var containingAssembly = this.module.GetContainingAssembly(Context); if (containingAssembly != null && ReferenceEquals(assemblyReference, containingAssembly)) { - return 0; + return default(AssemblyReferenceHandle); } - return this.GetOrAddAssemblyRefIndex(assemblyReference); + return this.GetOrAddAssemblyReferenceHandle(assemblyReference); } - internal int GetModuleRefIndex(string moduleName) + internal ModuleReferenceHandle GetModuleReferenceHandle(string moduleName) { - return this.GetOrAddModuleRefIndex(moduleName); + return this.GetOrAddModuleReferenceHandle(moduleName); } - private BlobIdx GetCustomAttributeSignatureIndex(ICustomAttribute customAttribute) + private BlobHandle GetCustomAttributeSignatureIndex(ICustomAttribute customAttribute) { - BlobIdx result; + BlobHandle result; if (_customAttributeSignatureIndex.TryGetValue(customAttribute, out result)) { return result; } var writer = PooledBlobBuilder.GetInstance(); - this.SerializeCustomAttributeSignature(customAttribute, false, writer); - result = heaps.GetBlobIndex(writer); + this.SerializeCustomAttributeSignature(customAttribute, writer); + result = metadata.GetOrAddBlob(writer); _customAttributeSignatureIndex.Add(customAttribute, result); writer.Free(); return result; } - private uint GetCustomAttributeTypeCodedIndex(IMethodReference methodReference) + private EntityHandle GetCustomAttributeTypeCodedIndex(IMethodReference methodReference) { IMethodDefinition methodDef = null; IUnitReference definingUnit = GetDefiningUnitReference(methodReference.GetContainingType(Context), Context); @@ -817,94 +754,80 @@ private uint GetCustomAttributeTypeCodedIndex(IMethodReference methodReference) } return methodDef != null - ? ((uint)this.GetMethodDefIndex(methodDef) << 3) | 2 - : ((uint)this.GetMemberRefIndex(methodReference) << 3) | 3; + ? (EntityHandle)GetMethodDefinitionHandle(methodDef) + : GetMemberReferenceHandle(methodReference); } - public static ushort GetEventFlags(IEventDefinition eventDef) + public static EventAttributes GetEventAttributes(IEventDefinition eventDef) { - ushort result = 0; + EventAttributes result = 0; if (eventDef.IsSpecialName) { - result |= 0x0200; + result |= EventAttributes.SpecialName; } if (eventDef.IsRuntimeSpecial) { - result |= 0x0400; - } - - return result; - } - - private int GetExportedTypeIndex(ITypeReference typeReference) - { - int result; - if (_exportedTypeIndex.TryGetValue(typeReference, out result)) - { - return result; + result |= EventAttributes.RTSpecialName; } - Debug.Assert(!_tableIndicesAreComplete); - _exportedTypeList.Add(typeReference); - _exportedTypeIndex.Add(typeReference, _exportedTypeList.Count); return result; } - public static ushort GetFieldFlags(IFieldDefinition fieldDef) + public static FieldAttributes GetFieldAttributes(IFieldDefinition fieldDef) { - ushort result = GetTypeMemberVisibilityFlags(fieldDef); + var result = (FieldAttributes)fieldDef.Visibility; if (fieldDef.IsStatic) { - result |= 0x0010; + result |= FieldAttributes.Static; } if (fieldDef.IsReadOnly) { - result |= 0x0020; + result |= FieldAttributes.InitOnly; } if (fieldDef.IsCompileTimeConstant) { - result |= 0x0040; + result |= FieldAttributes.Literal; } if (fieldDef.IsNotSerialized) { - result |= 0x0080; + result |= FieldAttributes.NotSerialized; } if (!fieldDef.MappedData.IsDefault) { - result |= 0x0100; + result |= FieldAttributes.HasFieldRVA; } if (fieldDef.IsSpecialName) { - result |= 0x0200; + result |= FieldAttributes.SpecialName; } if (fieldDef.IsRuntimeSpecial) { - result |= 0x0400; + result |= FieldAttributes.RTSpecialName; } if (fieldDef.IsMarshalledExplicitly) { - result |= 0x1000; + result |= FieldAttributes.HasFieldMarshal; } if (fieldDef.IsCompileTimeConstant) { - result |= 0x8000; + result |= FieldAttributes.HasDefault; } return result; } - internal BlobIdx GetFieldSignatureIndex(IFieldReference fieldReference) + internal BlobHandle GetFieldSignatureIndex(IFieldReference fieldReference) { - BlobIdx result; + BlobHandle result; ISpecializedFieldReference specializedFieldReference = fieldReference.AsSpecializedFieldReference; if (specializedFieldReference != null) { @@ -918,13 +841,13 @@ internal BlobIdx GetFieldSignatureIndex(IFieldReference fieldReference) var writer = PooledBlobBuilder.GetInstance(); this.SerializeFieldSignature(fieldReference, writer); - result = heaps.GetBlobIndex(writer); + result = metadata.GetOrAddBlob(writer); _fieldSignatureIndex.Add(fieldReference, result); writer.Free(); return result; } - internal virtual int GetFieldToken(IFieldReference fieldReference) + internal EntityHandle GetFieldHandle(IFieldReference fieldReference) { IFieldDefinition fieldDef = null; IUnitReference definingUnit = GetDefiningUnitReference(fieldReference.GetContainingType(Context), Context); @@ -934,93 +857,74 @@ internal virtual int GetFieldToken(IFieldReference fieldReference) } return fieldDef != null - ? 0x04000000 | this.GetFieldDefIndex(fieldDef) - : 0x0A000000 | this.GetMemberRefIndex(fieldReference); + ? (EntityHandle)GetFieldDefinitionHandle(fieldDef) + : GetMemberReferenceHandle(fieldReference); } - internal int GetFileRefIndex(IFileReference fileReference) + internal AssemblyFileHandle GetAssemblyFileHandle(IFileReference fileReference) { string key = fileReference.FileName; - int result; - if (_fileRefIndex.TryGetValue(key, out result)) + int index; + if (!_fileRefIndex.TryGetValue(key, out index)) { - return result; + Debug.Assert(!_tableIndicesAreComplete); + _fileRefList.Add(fileReference); + _fileRefIndex.Add(key, index = _fileRefList.Count); } - Debug.Assert(!_tableIndicesAreComplete); - _fileRefList.Add(fileReference); - _fileRefIndex.Add(key, _fileRefList.Count); - return result; + return MetadataTokens.AssemblyFileHandle(index); } - private int GetFileRefIndex(IModuleReference mref) + private AssemblyFileHandle GetAssemblyFileHandle(IModuleReference mref) { - string key = mref.Name; - int result; - if (_fileRefIndex.TryGetValue(key, out result)) - { - return result; - } - - Debug.Assert(false); - - // TODO: error - return result; + return MetadataTokens.AssemblyFileHandle(_fileRefIndex[mref.Name]); } - private static ushort GetGenericParamFlags(IGenericParameter genPar) + private static GenericParameterAttributes GetGenericParameterAttributes(IGenericParameter genPar) { - ushort result = 0; + GenericParameterAttributes result = 0; switch (genPar.Variance) { case TypeParameterVariance.Covariant: - result |= 0x0001; + result |= GenericParameterAttributes.Covariant; break; case TypeParameterVariance.Contravariant: - result |= 0x0002; + result |= GenericParameterAttributes.Contravariant; break; } if (genPar.MustBeReferenceType) { - result |= 0x0004; + result |= GenericParameterAttributes.ReferenceTypeConstraint; } if (genPar.MustBeValueType) { - result |= 0x0008; + result |= GenericParameterAttributes.NotNullableValueTypeConstraint; } if (genPar.MustHaveDefaultConstructor) { - result |= 0x0010; + result |= GenericParameterAttributes.DefaultConstructorConstraint; } return result; } - private uint GetImplementationCodedIndex(INamespaceTypeReference namespaceRef) + private EntityHandle GetExportedTypeImplementation(INamespaceTypeReference namespaceRef) { IUnitReference uref = namespaceRef.GetUnit(Context); - IAssemblyReference aref = uref as IAssemblyReference; + var aref = uref as IAssemblyReference; if (aref != null) { - return ((uint)this.GetAssemblyRefIndex(aref) << 2) | 1; - } - - IModuleReference mref = uref as IModuleReference; - if (mref != null) - { - aref = mref.GetContainingAssembly(Context); - return aref == null || ReferenceEquals(aref, this.module.GetContainingAssembly(Context)) - ? ((uint)this.GetFileRefIndex(mref) << 2) | 0 - : ((uint)this.GetAssemblyRefIndex(aref) << 2) | 1; + return GetAssemblyReferenceHandle(aref); } - Debug.Assert(false); - - // TODO: error - return 0; + var mref = (IModuleReference)uref; + aref = mref.GetContainingAssembly(Context); + return aref == null || ReferenceEquals(aref, this.module.GetContainingAssembly(Context)) + ? (EntityHandle)GetAssemblyFileHandle(mref) + : GetAssemblyReferenceHandle(aref); } private static uint GetManagedResourceOffset(ManagedResource resource, BlobBuilder resourceWriter) @@ -1044,24 +948,24 @@ public static string GetMangledName(INamedTypeReference namedType) : unmangledName; } - internal int GetMemberRefIndex(ITypeMemberReference memberRef) + internal MemberReferenceHandle GetMemberReferenceHandle(ITypeMemberReference memberRef) { - return this.GetOrAddMemberRefIndex(memberRef); + return this.GetOrAddMemberReferenceHandle(memberRef); } - internal uint GetMemberRefParentCodedIndex(ITypeMemberReference memberRef) + internal EntityHandle GetMemberReferenceParent(ITypeMemberReference memberRef) { ITypeDefinition parentTypeDef = memberRef.GetContainingType(Context).AsTypeDefinition(Context); if (parentTypeDef != null) { - int parentTypeDefIndex; - this.TryGetTypeDefIndex(parentTypeDef, out parentTypeDefIndex); - if (parentTypeDefIndex > 0) + TypeDefinitionHandle parentTypeDefHandle; + TryGetTypeDefinitionHandle(parentTypeDef, out parentTypeDefHandle); + + if (!parentTypeDefHandle.IsNil) { - IFieldReference fieldRef = memberRef as IFieldReference; - if (fieldRef != null) + if (memberRef is IFieldReference) { - return (uint)parentTypeDefIndex << 3; + return parentTypeDefHandle; } IMethodReference methodRef = memberRef as IMethodReference; @@ -1069,26 +973,27 @@ internal uint GetMemberRefParentCodedIndex(ITypeMemberReference memberRef) { if (methodRef.AcceptsExtraArguments) { - int methodIndex; - if (this.TryGetMethodDefIndex(methodRef.GetResolvedMethod(Context), out methodIndex)) + MethodDefinitionHandle methodHandle; + if (this.TryGetMethodDefinitionHandle(methodRef.GetResolvedMethod(Context), out methodHandle)) { - return ((uint)methodIndex << 3) | 3; + return methodHandle; } } - return (uint)parentTypeDefIndex << 3; + return parentTypeDefHandle; } // TODO: error } } // TODO: special treatment for global fields and methods. Object model support would be nice. - return memberRef.GetContainingType(Context).IsTypeSpecification() - ? ((uint)this.GetTypeSpecIndex(memberRef.GetContainingType(Context)) << 3) | 4 - : ((uint)this.GetTypeRefIndex(memberRef.GetContainingType(Context)) << 3) | 1; + var containingType = memberRef.GetContainingType(Context); + return containingType.IsTypeSpecification() + ? (EntityHandle)GetTypeSpecificationHandle(containingType) + : GetTypeReferenceHandle(containingType); } - internal uint GetMethodDefOrRefCodedIndex(IMethodReference methodReference) + internal EntityHandle GetMethodDefinitionOrReferenceHandle(IMethodReference methodReference) { IMethodDefinition methodDef = null; IUnitReference definingUnit = GetDefiningUnitReference(methodReference.GetContainingType(Context), Context); @@ -1098,101 +1003,104 @@ internal uint GetMethodDefOrRefCodedIndex(IMethodReference methodReference) } return methodDef != null - ? (uint)this.GetMethodDefIndex(methodDef) << 1 - : ((uint)this.GetMemberRefIndex(methodReference) << 1) | 1; + ? (EntityHandle)GetMethodDefinitionHandle(methodDef) + : GetMemberReferenceHandle(methodReference); } - public static ushort GetMethodFlags(IMethodDefinition methodDef) + public static MethodAttributes GetMethodAttributes(IMethodDefinition methodDef) { - ushort result = GetTypeMemberVisibilityFlags(methodDef); + var result = (MethodAttributes)methodDef.Visibility; if (methodDef.IsStatic) { - result |= 0x0010; + result |= MethodAttributes.Static; } if (methodDef.IsSealed) { - result |= 0x0020; + result |= MethodAttributes.Final; } if (methodDef.IsVirtual) { - result |= 0x0040; + result |= MethodAttributes.Virtual; } if (methodDef.IsHiddenBySignature) { - result |= 0x0080; + result |= MethodAttributes.HideBySig; } if (methodDef.IsNewSlot) { - result |= 0x0100; + result |= MethodAttributes.NewSlot; } if (methodDef.IsAccessCheckedOnOverride) { - result |= 0x0200; + result |= MethodAttributes.CheckAccessOnOverride; } if (methodDef.IsAbstract) { - result |= 0x0400; + result |= MethodAttributes.Abstract; } if (methodDef.IsSpecialName) { - result |= 0x0800; + result |= MethodAttributes.SpecialName; } if (methodDef.IsRuntimeSpecial) { - result |= 0x1000; + result |= MethodAttributes.RTSpecialName; } if (methodDef.IsPlatformInvoke) { - result |= 0x2000; + result |= MethodAttributes.PinvokeImpl; } if (methodDef.HasDeclarativeSecurity) { - result |= 0x4000; + result |= MethodAttributes.HasSecurity; } if (methodDef.RequiresSecurityObject) { - result |= 0x8000; + result |= MethodAttributes.RequireSecObject; } return result; } - internal BlobIdx GetMethodInstanceSignatureIndex(IGenericMethodInstanceReference methodInstanceReference) + internal BlobHandle GetMethodSpecificationSignatureHandle(IGenericMethodInstanceReference methodInstanceReference) { - BlobIdx result; + BlobHandle result; if (_methodInstanceSignatureIndex.TryGetValue(methodInstanceReference, out result)) { return result; } - var writer = PooledBlobBuilder.GetInstance(); - writer.WriteByte(0x0A); - writer.WriteCompressedInteger(methodInstanceReference.GetGenericMethod(Context).GenericParameterCount); - foreach (ITypeReference typeref in methodInstanceReference.GetGenericArguments(Context)) + var builder = PooledBlobBuilder.GetInstance(); + var encoder = new BlobEncoder(builder).MethodSpecificationSignature(methodInstanceReference.GetGenericMethod(Context).GenericParameterCount); + + foreach (ITypeReference typeReference in methodInstanceReference.GetGenericArguments(Context)) { - this.SerializeTypeReference(typeref, writer, false, true); + var typeRef = typeReference; + SerializeTypeReference(encoder.AddArgument(), typeRef); } - result = heaps.GetBlobIndex(writer); + encoder.EndArguments(); + + result = metadata.GetOrAddBlob(builder); _methodInstanceSignatureIndex.Add(methodInstanceReference, result); - writer.Free(); + builder.Free(); return result; } - private BlobIdx GetMarshallingDescriptorIndex(IMarshallingInformation marshallingInformation) + private BlobHandle GetMarshallingDescriptorHandle(IMarshallingInformation marshallingInformation) { - BlobIdx result; + BlobHandle result; if (_marshallingDescriptorIndex.TryGetValue(marshallingInformation, out result)) { return result; @@ -1200,18 +1108,18 @@ private BlobIdx GetMarshallingDescriptorIndex(IMarshallingInformation marshallin var writer = PooledBlobBuilder.GetInstance(); this.SerializeMarshallingDescriptor(marshallingInformation, writer); - result = heaps.GetBlobIndex(writer); + result = metadata.GetOrAddBlob(writer); _marshallingDescriptorIndex.Add(marshallingInformation, result); writer.Free(); return result; } - private BlobIdx GetMarshallingDescriptorIndex(ImmutableArray descriptor) + private BlobHandle GetMarshallingDescriptorHandle(ImmutableArray descriptor) { - return heaps.GetBlobIndex(descriptor); + return metadata.GetOrAddBlob(descriptor); } - private BlobIdx GetMemberRefSignatureIndex(ITypeMemberReference memberRef) + private BlobHandle GetMemberReferenceSignatureHandle(ITypeMemberReference memberRef) { IFieldReference fieldReference = memberRef as IFieldReference; if (fieldReference != null) @@ -1222,69 +1130,77 @@ private BlobIdx GetMemberRefSignatureIndex(ITypeMemberReference memberRef) IMethodReference methodReference = memberRef as IMethodReference; if (methodReference != null) { - return this.GetMethodSignatureIndex(methodReference); + return this.GetMethodSignatureHandle(methodReference); } - // TODO: error - return default(BlobIdx); + throw ExceptionUtilities.Unreachable; } - internal BlobIdx GetMethodSignatureIndex(IMethodReference methodReference) + internal BlobHandle GetMethodSignatureHandle(IMethodReference methodReference) { ImmutableArray signatureBlob; - return GetMethodSignatureIndexAndBlob(methodReference, out signatureBlob); + return GetMethodSignatureHandleAndBlob(methodReference, out signatureBlob); } internal byte[] GetMethodSignature(IMethodReference methodReference) { ImmutableArray signatureBlob; - GetMethodSignatureIndexAndBlob(methodReference, out signatureBlob); + GetMethodSignatureHandleAndBlob(methodReference, out signatureBlob); return signatureBlob.ToArray(); } - private BlobIdx GetMethodSignatureIndexAndBlob(IMethodReference methodReference, out ImmutableArray signatureBlob) + private BlobHandle GetMethodSignatureHandleAndBlob(IMethodReference methodReference, out ImmutableArray signatureBlob) { - BlobIdx result; + BlobHandle result; ISpecializedMethodReference specializedMethodReference = methodReference.AsSpecializedMethodReference; if (specializedMethodReference != null) { methodReference = specializedMethodReference.UnspecializedVersion; } - KeyValuePair> existing; + KeyValuePair> existing; if (_signatureIndex.TryGetValue(methodReference, out existing)) { signatureBlob = existing.Value; return existing.Key; } - var writer = PooledBlobBuilder.GetInstance(); - this.SerializeSignature(methodReference, methodReference.GenericParameterCount, methodReference.ExtraParameters, writer); + Debug.Assert((methodReference.CallingConvention & CallingConvention.Generic) != 0 == (methodReference.GenericParameterCount > 0)); + + var builder = PooledBlobBuilder.GetInstance(); + + var encoder = new BlobEncoder(builder).MethodSignature( + new SignatureHeader((byte)methodReference.CallingConvention).CallingConvention, + methodReference.GenericParameterCount, + isInstanceMethod: (methodReference.CallingConvention & CallingConvention.HasThis) != 0); - signatureBlob = writer.ToImmutableArray(); - result = heaps.GetBlobIndex(signatureBlob); + SerializeReturnValueAndParameters(encoder, methodReference, methodReference.ExtraParameters); + + + signatureBlob = builder.ToImmutableArray(); + result = metadata.GetOrAddBlob(signatureBlob); _signatureIndex.Add(methodReference, KeyValuePair.Create(result, signatureBlob)); - writer.Free(); + builder.Free(); return result; } - private BlobIdx GetGenericMethodInstanceIndex(IGenericMethodInstanceReference genericMethodInstanceReference) + private BlobHandle GetMethodSpecificationBlobHandle(IGenericMethodInstanceReference genericMethodInstanceReference) { var writer = PooledBlobBuilder.GetInstance(); - this.SerializeGenericMethodInstanceSignature(writer, genericMethodInstanceReference); - BlobIdx result = heaps.GetBlobIndex(writer); + SerializeMethodSpecificationSignature(writer, genericMethodInstanceReference); + BlobHandle result = metadata.GetOrAddBlob(writer); writer.Free(); return result; } - private int GetMethodSpecIndex(IGenericMethodInstanceReference methodSpec) + private MethodSpecificationHandle GetMethodSpecificationHandle(IGenericMethodInstanceReference methodSpec) { - return this.GetOrAddMethodSpecIndex(methodSpec); + return this.GetOrAddMethodSpecificationHandle(methodSpec); } - internal virtual int GetMethodToken(IMethodReference methodReference) + internal EntityHandle GetMethodHandle(IMethodReference methodReference) { - int methodDefIndex; + MethodDefinitionHandle methodDefHandle; IMethodDefinition methodDef = null; IUnitReference definingUnit = GetDefiningUnitReference(methodReference.GetContainingType(Context), Context); if (definingUnit != null && ReferenceEquals(definingUnit, this.module)) @@ -1292,43 +1208,43 @@ internal virtual int GetMethodToken(IMethodReference methodReference) methodDef = methodReference.GetResolvedMethod(Context); } - if (methodDef != null && (methodReference == methodDef || !methodReference.AcceptsExtraArguments) && this.TryGetMethodDefIndex(methodDef, out methodDefIndex)) + if (methodDef != null && (methodReference == methodDef || !methodReference.AcceptsExtraArguments) && this.TryGetMethodDefinitionHandle(methodDef, out methodDefHandle)) { - return 0x06000000 | methodDefIndex; + return methodDefHandle; } IGenericMethodInstanceReference methodSpec = methodReference.AsGenericMethodInstanceReference; return methodSpec != null - ? 0x2B000000 | this.GetMethodSpecIndex(methodSpec) - : 0x0A000000 | this.GetMemberRefIndex(methodReference); + ? (EntityHandle)GetMethodSpecificationHandle(methodSpec) + : GetMemberReferenceHandle(methodReference); } - public static ushort GetParameterFlags(IParameterDefinition parDef) + public static ParameterAttributes GetParameterAttributes(IParameterDefinition parDef) { - ushort result = 0; + ParameterAttributes result = 0; if (parDef.IsIn) { - result |= 0x0001; + result |= ParameterAttributes.In; } if (parDef.IsOut) { - result |= 0x0002; + result |= ParameterAttributes.Out; } if (parDef.IsOptional) { - result |= 0x0010; + result |= ParameterAttributes.Optional; } if (parDef.HasDefaultValue) { - result |= 0x1000; + result |= ParameterAttributes.HasDefault; } if (parDef.IsMarshalledExplicitly) { - result |= 0x2000; + result |= ParameterAttributes.HasFieldMarshal; } return result; @@ -1339,16 +1255,16 @@ internal PrimitiveTypeCode GetConstantTypeCode(ILocalDefinition constant) return constant.CompileTimeValue.Type.TypeCode(Context); } - private BlobIdx GetPermissionSetIndex(ImmutableArray permissionSet) + private BlobHandle GetPermissionSetBlobHandle(ImmutableArray permissionSet) { var writer = PooledBlobBuilder.GetInstance(); - BlobIdx result; + BlobHandle result; try { writer.WriteByte((byte)'.'); - writer.WriteCompressedInteger((uint)permissionSet.Length); + writer.WriteCompressedInteger(permissionSet.Length); this.SerializePermissionSet(permissionSet, writer); - result = heaps.GetBlobIndex(writer); + result = metadata.GetOrAddBlob(writer); } finally { @@ -1358,86 +1274,81 @@ private BlobIdx GetPermissionSetIndex(ImmutableArray permissio return result; } - public static ushort GetPropertyFlags(IPropertyDefinition propertyDef) + public static PropertyAttributes GetPropertyAttributes(IPropertyDefinition propertyDef) { - ushort result = 0; + PropertyAttributes result = 0; if (propertyDef.IsSpecialName) { - result |= 0x0200; + result |= PropertyAttributes.SpecialName; } if (propertyDef.IsRuntimeSpecial) { - result |= 0x0400; + result |= PropertyAttributes.RTSpecialName; } if (propertyDef.HasDefaultValue) { - result |= 0x1000; + result |= PropertyAttributes.HasDefault; } return result; } - private BlobIdx GetPropertySignatureIndex(IPropertyDefinition propertyDef) + private BlobHandle GetPropertySignatureHandle(IPropertyDefinition propertyDef) { - KeyValuePair> existing; + KeyValuePair> existing; if (_signatureIndex.TryGetValue(propertyDef, out existing)) { return existing.Key; } - var writer = PooledBlobBuilder.GetInstance(); - this.SerializeSignature(propertyDef, 0, ImmutableArray.Empty, writer); - var blob = writer.ToImmutableArray(); - var result = heaps.GetBlobIndex(blob); + var builder = PooledBlobBuilder.GetInstance(); + + var encoder = new BlobEncoder(builder).PropertySignature( + isInstanceProperty: (propertyDef.CallingConvention & CallingConvention.HasThis) != 0); + + SerializeReturnValueAndParameters(encoder, propertyDef, ImmutableArray.Empty); + + var blob = builder.ToImmutableArray(); + var result = metadata.GetOrAddBlob(blob); + _signatureIndex.Add(propertyDef, KeyValuePair.Create(result, blob)); - writer.Free(); + builder.Free(); return result; } - private uint GetResolutionScopeCodedIndex(ITypeReference typeReference) - { - return ((uint)this.GetTypeRefIndex(typeReference) << 2) | 3; - } - - private uint GetResolutionScopeCodedIndex(IUnitReference unitReference) + private EntityHandle GetResolutionScopeHandle(IUnitReference unitReference) { - IAssemblyReference aref = unitReference as IAssemblyReference; + var aref = unitReference as IAssemblyReference; if (aref != null) { - return ((uint)this.GetAssemblyRefIndex(aref) << 2) | 2; + return GetAssemblyReferenceHandle(aref); } - IModuleReference mref = unitReference as IModuleReference; - if (mref != null) - { - // If this is a module from a referenced multi-module assembly, - // the assembly should be used as the resolution scope. - aref = mref.GetContainingAssembly(Context); - - if (aref != null && aref != module.AsAssembly) - { - return ((uint)this.GetAssemblyRefIndex(aref) << 2) | 2; - } + // If this is a module from a referenced multi-module assembly, + // the assembly should be used as the resolution scope. + var mref = (IModuleReference)unitReference; + aref = mref.GetContainingAssembly(Context); - return ((uint)this.GetModuleRefIndex(mref.Name) << 2) | 1; + if (aref != null && aref != module.AsAssembly) + { + return GetAssemblyReferenceHandle(aref); } - // TODO: error - return 0; + return GetModuleReferenceHandle(mref.Name); } - private StringIdx GetStringIndexForPathAndCheckLength(string path, INamedEntity errorEntity = null) + private StringHandle GetStringHandleForPathAndCheckLength(string path, INamedEntity errorEntity = null) { CheckPathLength(path, errorEntity); - return heaps.GetStringIndex(path); + return metadata.GetOrAddString(path); } - private StringIdx GetStringIndexForNameAndCheckLength(string name, INamedEntity errorEntity = null) + private StringHandle GetStringHandleForNameAndCheckLength(string name, INamedEntity errorEntity = null) { CheckNameLength(name, errorEntity); - return heaps.GetStringIndex(name); + return metadata.GetOrAddString(name); } /// @@ -1449,16 +1360,16 @@ private StringIdx GetStringIndexForNameAndCheckLength(string name, INamedEntity /// We're trying to add the containing namespace of this type to the string heap. /// Namespace names are never used on their own - this is the type that is adding the namespace name. /// Used only for length checking. - private StringIdx GetStringIndexForNamespaceAndCheckLength(INamespaceTypeReference namespaceType, string mangledTypeName) + private StringHandle GetStringHandleForNamespaceAndCheckLength(INamespaceTypeReference namespaceType, string mangledTypeName) { string namespaceName = namespaceType.NamespaceName; if (namespaceName.Length == 0) // Optimization: CheckNamespaceLength is relatively expensive. { - return default(StringIdx); + return default(StringHandle); } CheckNamespaceLength(namespaceName, mangledTypeName, namespaceType); - return heaps.GetStringIndex(namespaceName); + return metadata.GetOrAddString(namespaceName); } private void CheckNameLength(string name, INamedEntity errorEntity) @@ -1562,95 +1473,14 @@ protected static Location GetSymbolLocation(ISymbol symbolOpt) return symbolOpt != null && !symbolOpt.Locations.IsDefaultOrEmpty ? symbolOpt.Locations[0] : Location.None; } - private static SignatureTypeCode GetConstantTypeCode(object val) - { - if (val == null) - { - // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a zero. - return Constants.SignatureTypeCode_Class; - } - - Debug.Assert(!val.GetType().GetTypeInfo().IsEnum); - - // Perf: Note that JIT optimizes each expression val.GetType() == typeof(T) to a single register comparison. - // Also the checks are sorted by commonality of the checked types. - - if (val.GetType() == typeof(int)) - { - return SignatureTypeCode.Int32; - } - - if (val.GetType() == typeof(string)) - { - return SignatureTypeCode.String; - } - - if (val.GetType() == typeof(bool)) - { - return SignatureTypeCode.Boolean; - } - - if (val.GetType() == typeof(char)) - { - return SignatureTypeCode.Char; - } - - if (val.GetType() == typeof(byte)) - { - return SignatureTypeCode.Byte; - } - - if (val.GetType() == typeof(long)) - { - return SignatureTypeCode.Int64; - } - - if (val.GetType() == typeof(double)) - { - return SignatureTypeCode.Double; - } - - if (val.GetType() == typeof(short)) - { - return SignatureTypeCode.Int16; - } - - if (val.GetType() == typeof(ushort)) - { - return SignatureTypeCode.UInt16; - } - - if (val.GetType() == typeof(uint)) - { - return SignatureTypeCode.UInt32; - } - - if (val.GetType() == typeof(sbyte)) - { - return SignatureTypeCode.SByte; - } - - if (val.GetType() == typeof(ulong)) - { - return SignatureTypeCode.UInt64; - } - - if (val.GetType() == typeof(float)) - { - return SignatureTypeCode.Single; - } - - throw ExceptionUtilities.UnexpectedValue(val); - } - - internal uint GetTypeDefFlags(ITypeDefinition typeDef) + internal TypeAttributes GetTypeAttributes(ITypeDefinition typeDef) { - return GetTypeDefFlags(typeDef, Context); + return GetTypeAttributes(typeDef, Context); } - public static uint GetTypeDefFlags(ITypeDefinition typeDef, EmitContext context) + public static TypeAttributes GetTypeAttributes(ITypeDefinition typeDef, EmitContext context) { - TypeAttributes result = default(TypeAttributes); + TypeAttributes result = 0; switch (typeDef.Layout) { @@ -1749,7 +1579,7 @@ public static uint GetTypeDefFlags(ITypeDefinition typeDef, EmitContext context) break; } - return (uint)result; + return result; } INamespaceTypeDefinition namespaceTypeDef = typeDef.AsNamespaceTypeDefinition(context); @@ -1758,72 +1588,30 @@ public static uint GetTypeDefFlags(ITypeDefinition typeDef, EmitContext context) result |= TypeAttributes.Public; } - return (uint)result; - } - - private uint GetTypeDefOrRefCodedIndex(ITypeReference typeReference, bool treatRefAsPotentialTypeSpec) - { - int typeDefIndex; - var typeDefinition = typeReference.AsTypeDefinition(this.Context); - if ((typeDefinition != null) && this.TryGetTypeDefIndex(typeDefinition, out typeDefIndex)) - { - return (uint)((typeDefIndex << 2) | 0); - } - - return treatRefAsPotentialTypeSpec && typeReference.IsTypeSpecification() - ? ((uint)this.GetTypeSpecIndex(typeReference) << 2) | 2 - : ((uint)this.GetTypeRefIndex(typeReference) << 2) | 1; - } - - private static ushort GetTypeMemberVisibilityFlags(ITypeDefinitionMember member) - { - ushort result = 0; - switch (member.Visibility) - { - case TypeMemberVisibility.Private: - result |= 0x00000001; - break; - case TypeMemberVisibility.FamilyAndAssembly: - result |= 0x00000002; - break; - case TypeMemberVisibility.Assembly: - result |= 0x00000003; - break; - case TypeMemberVisibility.Family: - result |= 0x00000004; - break; - case TypeMemberVisibility.FamilyOrAssembly: - result |= 0x00000005; - break; - case TypeMemberVisibility.Public: - result |= 0x00000006; - break; - } - return result; } - private uint GetTypeOrMethodDefCodedIndex(IGenericParameter genPar) + private EntityHandle GetDeclaringTypeOrMethodHandle(IGenericParameter genPar) { IGenericTypeParameter genTypePar = genPar.AsGenericTypeParameter; if (genTypePar != null) { - return (uint)this.GetTypeDefIndex(genTypePar.DefiningType) << 1; + return GetTypeDefinitionHandle(genTypePar.DefiningType); } IGenericMethodParameter genMethPar = genPar.AsGenericMethodParameter; if (genMethPar != null) { - return ((uint)this.GetMethodDefIndex(genMethPar.DefiningMethod) << 1) | 1; - } // TODO: error + return GetMethodDefinitionHandle(genMethPar.DefiningMethod); + } - return 0; + throw ExceptionUtilities.Unreachable; } - private int GetTypeRefIndex(ITypeReference typeReference) + private TypeReferenceHandle GetTypeReferenceHandle(ITypeReference typeReference) { - int result; - if (this.TryGetTypeRefIndex(typeReference, out result)) + TypeReferenceHandle result; + if (this.TryGetTypeRefeferenceHandle(typeReference, out result)) { return result; } @@ -1837,15 +1625,15 @@ private int GetTypeRefIndex(ITypeReference typeReference) INestedTypeReference nestedTypeRef = typeReference.AsNestedTypeReference; if (nestedTypeRef != null) { - GetTypeRefIndex(nestedTypeRef.GetContainingType(this.Context)); + GetTypeReferenceHandle(nestedTypeRef.GetContainingType(this.Context)); } - return this.GetOrAddTypeRefIndex(typeReference); + return this.GetOrAddTypeReferenceHandle(typeReference); } - private int GetTypeSpecIndex(ITypeReference typeReference) + private TypeSpecificationHandle GetTypeSpecificationHandle(ITypeReference typeReference) { - return this.GetOrAddTypeSpecIndex(typeReference); + return this.GetOrAddTypeSpecificationHandle(typeReference); } internal ITypeDefinition GetTypeDefinition(uint token) @@ -1853,291 +1641,137 @@ internal ITypeDefinition GetTypeDefinition(uint token) // The token must refer to a TypeDef row since we are // only handling indexes into the full metadata (in EnC) // for def tables. Other tables contain deltas only. - Debug.Assert(TypeOnly(token) == TokenTypeIds.TypeDef); - int index = (int)RowOnly(token) - 1; - return this.GetTypeDef(index); + return GetTypeDef(MetadataTokens.TypeDefinitionHandle((int)token)); } internal IMethodDefinition GetMethodDefinition(uint token) { // Must be a def table. (See comment in GetTypeDefinition.) - Debug.Assert(TypeOnly(token) == TokenTypeIds.MethodDef); - int index = (int)RowOnly(token) - 1; - return this.GetMethodDef(index); + return GetMethodDef(MetadataTokens.MethodDefinitionHandle((int)token)); } internal INestedTypeReference GetNestedTypeReference(uint token) { // Must be a def table. (See comment in GetTypeDefinition.) - Debug.Assert(TypeOnly(token) == TokenTypeIds.TypeDef); - int index = (int)RowOnly(token) - 1; - var t = this.GetTypeDef(index); - return t.AsNestedTypeReference; + return GetTypeDef(MetadataTokens.TypeDefinitionHandle((int)token)).AsNestedTypeReference; } - internal BlobIdx GetTypeSpecSignatureIndex(ITypeReference typeReference) + internal BlobHandle GetTypeSpecSignatureIndex(ITypeReference typeReference) { - BlobIdx result; + BlobHandle result; if (_typeSpecSignatureIndex.TryGetValue(typeReference, out result)) { return result; } - var writer = PooledBlobBuilder.GetInstance(); - this.SerializeTypeReference(typeReference, writer, false, true); - result = heaps.GetBlobIndex(writer); + var builder = PooledBlobBuilder.GetInstance(); + this.SerializeTypeReference(new BlobEncoder(builder).TypeSpecificationSignature(), typeReference); + result = metadata.GetOrAddBlob(builder); + _typeSpecSignatureIndex.Add(typeReference, result); - writer.Free(); + builder.Free(); return result; } - internal void RecordTypeReference(ITypeReference typeReference) - { - var typeDefinition = typeReference.AsTypeDefinition(this.Context); - int token; - if ((typeDefinition != null) && this.TryGetTypeDefIndex(typeDefinition, out token)) - { - return; - } - - if (!typeReference.IsTypeSpecification()) - { - this.GetTypeRefIndex(typeReference); - } - else - { - this.GetTypeSpecIndex(typeReference); - } - } - - internal virtual int GetTypeToken(ITypeReference typeReference) + internal EntityHandle GetTypeHandle(ITypeReference typeReference, bool treatRefAsPotentialTypeSpec = true) { - int typeDefIndex; + TypeDefinitionHandle handle; var typeDefinition = typeReference.AsTypeDefinition(this.Context); - if (typeDefinition != null && this.TryGetTypeDefIndex(typeDefinition, out typeDefIndex)) + if (typeDefinition != null && this.TryGetTypeDefinitionHandle(typeDefinition, out handle)) { - return 0x02000000 | typeDefIndex; + return handle; } - return typeReference.IsTypeSpecification() - ? 0x1B000000 | this.GetTypeSpecIndex(typeReference) - : 0x01000000 | this.GetTypeRefIndex(typeReference); + return treatRefAsPotentialTypeSpec && typeReference.IsTypeSpecification() + ? (EntityHandle)GetTypeSpecificationHandle(typeReference) + : GetTypeReferenceHandle(typeReference); } - internal int GetTokenForDefinition(IDefinition definition) + internal EntityHandle GetDefinitionHandle(IDefinition definition) { ITypeDefinition typeDef = definition as ITypeDefinition; if (typeDef != null) { - return TokenTypeIds.TypeDef | this.GetTypeDefIndex(typeDef); + return GetTypeDefinitionHandle(typeDef); } IMethodDefinition methodDef = definition as IMethodDefinition; if (methodDef != null) { - return TokenTypeIds.MethodDef | this.GetMethodDefIndex(methodDef); + return GetMethodDefinitionHandle(methodDef); } IFieldDefinition fieldDef = definition as IFieldDefinition; if (fieldDef != null) { - return TokenTypeIds.FieldDef | this.GetFieldDefIndex(fieldDef); + return GetFieldDefinitionHandle(fieldDef); } IEventDefinition eventDef = definition as IEventDefinition; if (eventDef != null) { - return TokenTypeIds.Event | this.GetEventDefIndex(eventDef); + return GetEventDefinitionHandle(eventDef); } IPropertyDefinition propertyDef = definition as IPropertyDefinition; if (propertyDef != null) { - return TokenTypeIds.Property | this.GetPropertyDefIndex(propertyDef); + return GetPropertyDefIndex(propertyDef); } throw ExceptionUtilities.Unreachable; } - private void SerializeCustomModifiers(ImmutableArray customModifiers, BlobBuilder writer) - { - foreach (ICustomModifier customModifier in customModifiers) - { - this.SerializeCustomModifier(customModifier, writer); - } - } - - private void SerializeCustomModifier(ICustomModifier customModifier, BlobBuilder writer) - { - if (customModifier.IsOptional) - { - writer.WriteByte(0x20); - } - else - { - writer.WriteByte(0x1f); - } - - writer.WriteCompressedInteger(this.GetTypeDefOrRefCodedIndex(customModifier.GetModifier(Context), true)); - } - - private void SerializeMetadataHeader(BlobBuilder writer, MetadataSizes metadataSizes) - { - int startOffset = writer.Position; - - // signature - writer.WriteUInt32(0x424A5342); - - // major version - writer.WriteUInt16(1); - - // minor version - writer.WriteUInt16(1); - - // reserved - writer.WriteUInt32(0); - - // metadata version length - writer.WriteUInt32(MetadataSizes.MetadataVersionPaddedLength); - - string targetRuntimeVersion = metadataSizes.IsStandaloneDebugMetadata ? "PDB v1.0" : module.Properties.TargetRuntimeVersion; - - int n = Math.Min(MetadataSizes.MetadataVersionPaddedLength, targetRuntimeVersion.Length); - for (int i = 0; i < n; i++) - { - writer.WriteByte((byte)targetRuntimeVersion[i]); - } - - for (int i = n; i < MetadataSizes.MetadataVersionPaddedLength; i++) - { - writer.WriteByte(0); - } - - // reserved - writer.WriteUInt16(0); - - // number of streams - writer.WriteUInt16((ushort)(5 + (metadataSizes.IsMinimalDelta ? 1 : 0) + (metadataSizes.IsStandaloneDebugMetadata ? 1 : 0))); - - // stream headers - int offsetFromStartOfMetadata = metadataSizes.MetadataHeaderSize; - - // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID - if (metadataSizes.IsStandaloneDebugMetadata) - { - SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.StandalonePdbStreamSize, "#Pdb", writer); - } - - // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables; - // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard. - // - // Note: EnC delta is stored as uncompressed metadata stream. - SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.MetadataTableStreamSize, (metadataSizes.IsMetadataTableStreamCompressed ? "#~" : "#-"), writer); - - SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", writer); - SerializeStreamHeader(ref offsetFromStartOfMetadata, metadataSizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", writer); - - if (metadataSizes.IsMinimalDelta) - { - SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", writer); - } - - int endOffset = writer.Position; - Debug.Assert(endOffset - startOffset == metadataSizes.MetadataHeaderSize); - } - - private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BlobBuilder writer) - { - // 4 for the first uint (offset), 4 for the second uint (padded size), length of stream name + 1 for null terminator (then padded) - int sizeOfStreamHeader = MetadataSizes.GetMetadataStreamHeaderSize(streamName); - writer.WriteInt32(offsetFromStartOfMetadata); - writer.WriteInt32(alignedStreamSize); - foreach (char ch in streamName) - { - writer.WriteByte((byte)ch); - } - - // After offset, size, and stream name, write 0-bytes until we reach our padded size. - for (uint i = 8 + (uint)streamName.Length; i < sizeOfStreamHeader; i++) - { - writer.WriteByte(0); - } - - offsetFromStartOfMetadata += alignedStreamSize; - } - public void WriteMetadataAndIL(PdbWriter pdbWriterOpt, Stream metadataStream, Stream ilStream, out MetadataSizes metadataSizes) { pdbWriterOpt?.SetMetadataEmitter(this); // TODO: we can precalculate the exact size of IL stream - var ilWriter = new BlobBuilder(1024); - var metadataWriter = new BlobBuilder(4 * 1024); - var mappedFieldDataWriter = new BlobBuilder(0); - var managedResourceDataWriter = new BlobBuilder(0); + var ilBuilder = new BlobBuilder(1024); + var metadataBuilder = new BlobBuilder(4 * 1024); + var mappedFieldDataBuilder = new BlobBuilder(0); + var managedResourceDataBuilder = new BlobBuilder(0); // Add 4B of padding to the start of the separated IL stream, // so that method RVAs, which are offsets to this stream, are never 0. - ilWriter.WriteUInt32(0); + ilBuilder.WriteUInt32(0); // this is used to handle edit-and-continue emit, so we should have a module // version ID that is imposed by the caller (the same as the previous module version ID). // Therefore we do not have to fill in a new module version ID in the generated metadata // stream. Debug.Assert(this.module.Properties.PersistentIdentifier != default(Guid)); + Blob mvidFixup; + + BuildMetadataAndIL(pdbWriterOpt, ilBuilder, mappedFieldDataBuilder, managedResourceDataBuilder, out mvidFixup); - int moduleVersionIdOffsetInMetadataStream; - int pdbIdOffsetInMetadataStream; - int entryPointToken; - - SerializeMetadataAndIL( - metadataWriter, - default(BlobBuilder), - pdbWriterOpt, - ilWriter, - mappedFieldDataWriter, - managedResourceDataWriter, - methodBodyStreamRva: 0, - calculateMappedFieldDataStreamRva: _ => 0, - moduleVersionIdOffsetInMetadataStream: out moduleVersionIdOffsetInMetadataStream, - pdbIdOffsetInPortablePdbStream: out pdbIdOffsetInMetadataStream, - metadataSizes: out metadataSizes, - entryPointToken: out entryPointToken); - - ilWriter.WriteContentTo(ilStream); - metadataWriter.WriteContentTo(metadataStream); - - Debug.Assert(entryPointToken == 0); - Debug.Assert(mappedFieldDataWriter.Count == 0); - Debug.Assert(managedResourceDataWriter.Count == 0); - Debug.Assert(pdbIdOffsetInMetadataStream == 0); - } - - public void SerializeMetadataAndIL( - BlobBuilder metadataWriter, - BlobBuilder debugMetadataWriterOpt, + Debug.Assert(mappedFieldDataBuilder.Count == 0); + Debug.Assert(managedResourceDataBuilder.Count == 0); + + var serializer = new TypeSystemMetadataSerializer(metadata, module.Properties.TargetRuntimeVersion, IsMinimalDelta); + serializer.SerializeMetadata(metadataBuilder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0); + metadataSizes = serializer.MetadataSizes; + + ilBuilder.WriteContentTo(ilStream); + metadataBuilder.WriteContentTo(metadataStream); + } + + public void BuildMetadataAndIL( PdbWriter nativePdbWriterOpt, - BlobBuilder ilWriter, - BlobBuilder mappedFieldDataWriter, - BlobBuilder managedResourceDataWriter, - int methodBodyStreamRva, - Func calculateMappedFieldDataStreamRva, - out int moduleVersionIdOffsetInMetadataStream, - out int pdbIdOffsetInPortablePdbStream, - out int entryPointToken, - out MetadataSizes metadataSizes) + BlobBuilder ilBuilder, + BlobBuilder mappedFieldDataBuilder, + BlobBuilder managedResourceDataBuilder, + out Blob mvidFixup) { // Extract information from object model into tables, indices and streams CreateIndices(); - if (_debugHeapsOpt != null) + if (_debugMetadataOpt != null) { DefineModuleImportScope(); } - int[] methodBodyRvas = SerializeMethodBodies(ilWriter, nativePdbWriterOpt); + int[] methodBodyOffsets = SerializeMethodBodies(ilBuilder, nativePdbWriterOpt); _cancellationToken.ThrowIfCancellationRequested(); @@ -2146,390 +1780,63 @@ public void SerializeMetadataAndIL( ReportReferencesToAddedSymbols(); - PopulateTables(methodBodyRvas, mappedFieldDataWriter, managedResourceDataWriter); + PopulateTables(methodBodyOffsets, mappedFieldDataBuilder, managedResourceDataBuilder, out mvidFixup); + } + + public TypeSystemMetadataSerializer GetTypeSystemMetadataSerializer() + { + return new TypeSystemMetadataSerializer(metadata, module.Properties.TargetRuntimeVersion, IsMinimalDelta); + } + + public StandaloneDebugMetadataSerializer GetStandaloneDebugMetadataSerializer(MetadataSizes metadataSizes, MethodDefinitionHandle debugEntryPoint) + { + return new StandaloneDebugMetadataSerializer(_debugMetadataOpt, metadataSizes.RowCounts, debugEntryPoint, IsMinimalDelta); + } - int debugEntryPointToken; + internal void GetEntryPoints(out MethodDefinitionHandle entryPointHandle, out MethodDefinitionHandle debugEntryPointHandle) + { if (IsFullMetadata) { // PE entry point is set for executable programs IMethodReference entryPoint = module.PEEntryPoint; - entryPointToken = entryPoint != null ? GetMethodToken((IMethodDefinition)entryPoint.AsDefinition(Context)) : 0; + entryPointHandle = entryPoint != null ? (MethodDefinitionHandle)GetMethodHandle((IMethodDefinition)entryPoint.AsDefinition(Context)) : default(MethodDefinitionHandle); // debug entry point may be different from PE entry point, it may also be set for libraries IMethodReference debugEntryPoint = module.DebugEntryPoint; if (debugEntryPoint != null && debugEntryPoint != entryPoint) { - debugEntryPointToken = GetMethodToken((IMethodDefinition)debugEntryPoint.AsDefinition(Context)); + debugEntryPointHandle = (MethodDefinitionHandle)GetMethodHandle((IMethodDefinition)debugEntryPoint.AsDefinition(Context)); } else { - debugEntryPointToken = entryPointToken; - } - - // entry point can only be a MethodDef: - Debug.Assert(entryPointToken == 0 || (entryPointToken & 0xff000000) == 0x06000000); - Debug.Assert(debugEntryPointToken == 0 || (debugEntryPointToken & 0xff000000) == 0x06000000); - - if (debugEntryPointToken != 0) - { - nativePdbWriterOpt?.SetEntryPoint((uint)debugEntryPointToken); + debugEntryPointHandle = entryPointHandle; } } else { - entryPointToken = debugEntryPointToken = 0; - } - - heaps.Complete(); - - var tableRowCounts = GetRowCounts(); - - metadataSizes = new MetadataSizes( - rowCounts: tableRowCounts, - heapSizes: heaps.GetHeapSizes(), - ilStreamSize: ilWriter.Count, - mappedFieldDataSize: mappedFieldDataWriter.Count, - resourceDataSize: managedResourceDataWriter.Count, - strongNameSignatureSize: CalculateStrongNameSignatureSize(module), - isMinimalDelta: IsMinimalDelta, - emitStandaloneDebugMetadata: EmitStandaloneDebugMetadata, - isStandaloneDebugMetadata: false); - - int mappedFieldDataStreamRva = calculateMappedFieldDataStreamRva(metadataSizes); - - int guidHeapStartOffset; - SerializeMetadata(metadataWriter, metadataSizes, methodBodyStreamRva, mappedFieldDataStreamRva, debugEntryPointToken, out guidHeapStartOffset, out pdbIdOffsetInPortablePdbStream); - moduleVersionIdOffsetInMetadataStream = GetModuleVersionGuidOffsetInMetadataStream(guidHeapStartOffset); - Debug.Assert(pdbIdOffsetInPortablePdbStream == 0); - - if (!EmitStandaloneDebugMetadata) - { - return; - } - - // serialize debug metadata stream - - Debug.Assert(_debugHeapsOpt != null); - _debugHeapsOpt.Complete(); - - var debugMetadataSizes = new MetadataSizes( - rowCounts: tableRowCounts, - heapSizes: _debugHeapsOpt.GetHeapSizes(), - ilStreamSize: 0, - mappedFieldDataSize: 0, - resourceDataSize: 0, - strongNameSignatureSize: 0, - isMinimalDelta: IsMinimalDelta, - emitStandaloneDebugMetadata: true, - isStandaloneDebugMetadata: true); - - SerializeMetadata(debugMetadataWriterOpt, debugMetadataSizes, 0, 0, debugEntryPointToken, out guidHeapStartOffset, out pdbIdOffsetInPortablePdbStream); - } - - private static int CalculateStrongNameSignatureSize(IModule module) - { - IAssembly assembly = module.AsAssembly; - if (assembly == null) - { - return 0; - } - - // EDMAURER the count of characters divided by two because the each pair of characters will turn in to one byte. - int keySize = (assembly.SignatureKey == null) ? 0 : assembly.SignatureKey.Length / 2; - - if (keySize == 0) - { - keySize = assembly.PublicKey.Length; + entryPointHandle = debugEntryPointHandle = default(MethodDefinitionHandle); } - - if (keySize == 0) - { - return 0; - } - - return (keySize < 128 + 32) ? 128 : keySize - 32; } - private void SerializeMetadata( - BlobBuilder metadataWriter, - MetadataSizes metadataSizes, - int methodBodyStreamRva, - int mappedFieldDataStreamRva, - int debugEntryPointToken, - out int guidHeapStartOffset, - out int pdbIdOffset) + private ImmutableArray GetSortedGenericParameters() { - // header: - SerializeMetadataHeader(metadataWriter, metadataSizes); - - // #Pdb stream - if (metadataSizes.IsStandaloneDebugMetadata) - { - SerializeStandalonePdbStream(metadataWriter, metadataSizes, debugEntryPointToken, out pdbIdOffset); - } - else + return GetGenericParameters().OrderBy((x, y) => { - pdbIdOffset = 0; - } - - // #~ or #- stream: - SerializeMetadataTables(metadataWriter, metadataSizes, methodBodyStreamRva, mappedFieldDataStreamRva); + // Spec: GenericParam table is sorted by Owner and then by Number. + int result = (int)CodedIndex.ToTypeOrMethodDef(GetDeclaringTypeOrMethodHandle(x)) - (int)CodedIndex.ToTypeOrMethodDef(GetDeclaringTypeOrMethodHandle(y)); + if (result != 0) + { + return result; + } - // #Strings, #US, #Guid and #Blob streams: - (metadataSizes.IsStandaloneDebugMetadata ? _debugHeapsOpt : heaps).WriteTo(metadataWriter, out guidHeapStartOffset); + return x.Index - y.Index; + }).ToImmutableArray(); } - private int GetModuleVersionGuidOffsetInMetadataStream(int guidHeapOffsetInMetadataStream) + private void PopulateTables(int[] methodBodyOffsets, BlobBuilder mappedFieldDataWriter, BlobBuilder resourceWriter, out Blob mvidFixup) { - // index of module version ID in the guidWriter stream - int moduleVersionIdIndex = _moduleRow.ModuleVersionId; - - // offset into the guidWriter stream of the module version ID - int moduleVersionOffsetInGuidTable = (moduleVersionIdIndex - 1) << 4; + var sortedGenericParameters = GetSortedGenericParameters(); - return guidHeapOffsetInMetadataStream + moduleVersionOffsetInGuidTable; - } - - private void SerializeMetadataTables( - BlobBuilder writer, - MetadataSizes metadataSizes, - int methodBodyStreamRva, - int mappedFieldDataStreamRva) - { - int startPosition = writer.Position; - - this.SerializeTablesHeader(writer, metadataSizes); - - if (metadataSizes.IsPresent(TableIndex.Module)) - { - SerializeModuleTable(writer, metadataSizes, heaps); - } - - if (metadataSizes.IsPresent(TableIndex.TypeRef)) - { - this.SerializeTypeRefTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.TypeDef)) - { - this.SerializeTypeDefTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.Field)) - { - this.SerializeFieldTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.MethodDef)) - { - this.SerializeMethodDefTable(writer, metadataSizes, methodBodyStreamRva); - } - - if (metadataSizes.IsPresent(TableIndex.Param)) - { - this.SerializeParamTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.InterfaceImpl)) - { - this.SerializeInterfaceImplTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.MemberRef)) - { - this.SerializeMemberRefTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.Constant)) - { - this.SerializeConstantTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.CustomAttribute)) - { - this.SerializeCustomAttributeTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.FieldMarshal)) - { - this.SerializeFieldMarshalTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.DeclSecurity)) - { - this.SerializeDeclSecurityTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.ClassLayout)) - { - this.SerializeClassLayoutTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.FieldLayout)) - { - this.SerializeFieldLayoutTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.StandAloneSig)) - { - this.SerializeStandAloneSigTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.EventMap)) - { - this.SerializeEventMapTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.Event)) - { - this.SerializeEventTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.PropertyMap)) - { - this.SerializePropertyMapTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.Property)) - { - this.SerializePropertyTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.MethodSemantics)) - { - this.SerializeMethodSemanticsTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.MethodImpl)) - { - this.SerializeMethodImplTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.ModuleRef)) - { - this.SerializeModuleRefTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.TypeSpec)) - { - this.SerializeTypeSpecTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.ImplMap)) - { - this.SerializeImplMapTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.FieldRva)) - { - this.SerializeFieldRvaTable(writer, metadataSizes, mappedFieldDataStreamRva); - } - - if (metadataSizes.IsPresent(TableIndex.EncLog)) - { - this.SerializeEncLogTable(writer); - } - - if (metadataSizes.IsPresent(TableIndex.EncMap)) - { - this.SerializeEncMapTable(writer); - } - - if (metadataSizes.IsPresent(TableIndex.Assembly)) - { - this.SerializeAssemblyTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.AssemblyRef)) - { - this.SerializeAssemblyRefTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.File)) - { - this.SerializeFileTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.ExportedType)) - { - this.SerializeExportedTypeTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.ManifestResource)) - { - this.SerializeManifestResourceTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.NestedClass)) - { - this.SerializeNestedClassTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.GenericParam)) - { - this.SerializeGenericParamTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.MethodSpec)) - { - this.SerializeMethodSpecTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.GenericParamConstraint)) - { - this.SerializeGenericParamConstraintTable(writer, metadataSizes); - } - - // debug tables - if (metadataSizes.IsPresent(TableIndex.Document)) - { - this.SerializeDocumentTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.MethodDebugInformation)) - { - this.SerializeMethodDebugInformationTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.LocalScope)) - { - this.SerializeLocalScopeTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.LocalVariable)) - { - this.SerializeLocalVariableTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.LocalConstant)) - { - this.SerializeLocalConstantTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.ImportScope)) - { - this.SerializeImportScopeTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.StateMachineMethod)) - { - this.SerializeStateMachineMethodTable(writer, metadataSizes); - } - - if (metadataSizes.IsPresent(TableIndex.CustomDebugInformation)) - { - this.SerializeCustomDebugInformationTable(writer, metadataSizes); - } - - writer.WriteByte(0); - writer.Align(4); - - int endPosition = writer.Position; - Debug.Assert(metadataSizes.MetadataTableStreamSize == endPosition - startPosition); - } - - private void PopulateTables(int[] methodBodyRvas, BlobBuilder mappedFieldDataWriter, BlobBuilder resourceWriter) - { this.PopulateAssemblyRefTableRows(); this.PopulateAssemblyTableRows(); this.PopulateClassLayoutTableRows(); @@ -2543,18 +1850,17 @@ private void PopulateTables(int[] methodBodyRvas, BlobBuilder mappedFieldDataWri this.PopulateFieldRvaTableRows(mappedFieldDataWriter); this.PopulateFieldTableRows(); this.PopulateFileTableRows(); - this.PopulateGenericParamTableRows(); - this.PopulateGenericParamConstraintTableRows(); + this.PopulateGenericParameters(sortedGenericParameters); this.PopulateImplMapTableRows(); this.PopulateInterfaceImplTableRows(); this.PopulateManifestResourceTableRows(resourceWriter); this.PopulateMemberRefTableRows(); this.PopulateMethodImplTableRows(); - this.PopulateMethodTableRows(methodBodyRvas); + this.PopulateMethodTableRows(methodBodyOffsets); this.PopulateMethodSemanticsTableRows(); this.PopulateMethodSpecTableRows(); this.PopulateModuleRefTableRows(); - this.PopulateModuleTableRow(); + this.PopulateModuleTableRow(out mvidFixup); this.PopulateNestedClassTableRows(); this.PopulateParamTableRows(); this.PopulatePropertyMapTableRows(); @@ -2562,52 +1868,36 @@ private void PopulateTables(int[] methodBodyRvas, BlobBuilder mappedFieldDataWri this.PopulateTypeDefTableRows(); this.PopulateTypeRefTableRows(); this.PopulateTypeSpecTableRows(); + this.PopulateStandaloneSignatures(); // This table is populated after the others because it depends on the order of the entries of the generic parameter table. - this.PopulateCustomAttributeTableRows(); + this.PopulateCustomAttributeTableRows(sortedGenericParameters); - ImmutableArray rowCounts = GetRowCounts(); + ImmutableArray rowCounts = metadata.GetRowCounts(); Debug.Assert(rowCounts[(int)TableIndex.EncLog] == 0 && rowCounts[(int)TableIndex.EncMap] == 0); - this.PopulateEncLogTableRows(_encLogTable, rowCounts); - this.PopulateEncMapTableRows(_encMapTable, rowCounts); - } - - private struct AssemblyRefTableRow - { - public Version Version; - public BlobIdx PublicKeyToken; - public StringIdx Name; - public StringIdx Culture; - public AssemblyContentType ContentType; - public bool IsRetargetable; + this.PopulateEncLogTableRows(rowCounts); + this.PopulateEncMapTableRows(rowCounts); } private void PopulateAssemblyRefTableRows() { var assemblyRefs = this.GetAssemblyRefs(); - _assemblyRefTable.Capacity = assemblyRefs.Count; + metadata.SetCapacity(TableIndex.AssemblyRef, assemblyRefs.Count); foreach (var identity in assemblyRefs) { - AssemblyRefTableRow r = new AssemblyRefTableRow(); - - r.Version = identity.Version; - r.PublicKeyToken = heaps.GetBlobIndex(identity.PublicKeyToken); - - Debug.Assert(!string.IsNullOrEmpty(identity.Name)); - r.Name = this.GetStringIndexForPathAndCheckLength(identity.Name); - - r.Culture = heaps.GetStringIndex(identity.CultureName); - - r.IsRetargetable = identity.IsRetargetable; - r.ContentType = identity.ContentType; - _assemblyRefTable.Add(r); + // reference has token, not full public key + metadata.AddAssemblyReference( + name: GetStringHandleForPathAndCheckLength(identity.Name), + version: identity.Version, + culture: metadata.GetOrAddString(identity.CultureName), + publicKeyOrToken: metadata.GetOrAddBlob(identity.PublicKeyToken), + flags: (AssemblyFlags)((int)identity.ContentType << 9) | (identity.IsRetargetable ? AssemblyFlags.Retargetable : 0), + hashValue: default(BlobHandle)); } } - private readonly List _assemblyRefTable = new List(); - private void PopulateAssemblyTableRows() { if (!EmitAssemblyDefinition) @@ -2616,132 +1906,45 @@ private void PopulateAssemblyTableRows() } IAssembly assembly = this.module.AsAssembly; - _assemblyKey = heaps.GetBlobIndex(assembly.PublicKey); - _assemblyName = this.GetStringIndexForPathAndCheckLength(assembly.Name, assembly); - _assemblyCulture = heaps.GetStringIndex(assembly.Identity.CultureName); - } - - private BlobIdx _assemblyKey; - private StringIdx _assemblyName; - private StringIdx _assemblyCulture; - - private void PopulateClassLayoutTableRows() - { - foreach (ITypeDefinition typeDef in this.GetTypeDefs()) - { - if (typeDef.Alignment == 0 && typeDef.SizeOf == 0) - { - continue; - } - - uint typeDefIndex = (uint)this.GetTypeDefIndex(typeDef); - ClassLayoutRow r = new ClassLayoutRow(); - r.PackingSize = typeDef.Alignment; - r.ClassSize = typeDef.SizeOf; - r.Parent = typeDefIndex; - _classLayoutTable.Add(r); - } - } - - private struct ClassLayoutRow { public ushort PackingSize; public uint ClassSize; public uint Parent; } - - private readonly List _classLayoutTable = new List(); - - private void PopulateConstantTableRows() - { - foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) - { - var constant = fieldDef.GetCompileTimeValue(Context); - if (constant == null) - { - continue; - } - - uint fieldDefIndex = (uint)this.GetFieldDefIndex(fieldDef); - _constantTable.Add(CreateConstantRow(constant.Value, parent: fieldDefIndex << 2)); - } - - int sizeWithOnlyFields = _constantTable.Count; - foreach (IParameterDefinition parDef in this.GetParameterDefs()) - { - var defaultValue = parDef.GetDefaultValue(Context); - if (defaultValue == null) - { - continue; - } - - uint parameterDefIndex = (uint)this.GetParameterDefIndex(parDef); - _constantTable.Add(CreateConstantRow(defaultValue.Value, parent: (parameterDefIndex << 2) | 1)); - } - - foreach (IPropertyDefinition propDef in this.GetPropertyDefs()) - { - if (!propDef.HasDefaultValue) - { - continue; - } - - uint propertyDefIndex = (uint)this.GetPropertyDefIndex(propDef); - _constantTable.Add(CreateConstantRow(propDef.DefaultValue.Value, parent: (propertyDefIndex << 2) | 2)); - } - - if (sizeWithOnlyFields > 0 && sizeWithOnlyFields < _constantTable.Count) - { - _constantTable.Sort(new ConstantRowComparer()); - } - } - private class ConstantRowComparer : Comparer - { - public override int Compare(ConstantRow x, ConstantRow y) - { - return ((int)x.Parent) - (int)y.Parent; - } - } - - private struct ConstantRow { public byte Type; public uint Parent; public BlobIdx Value; } - - private ConstantRow CreateConstantRow(object value, uint parent) - { - return new ConstantRow - { - Type = (byte)GetConstantTypeCode(value), - Parent = parent, - Value = heaps.GetConstantBlobIndex(value) - }; + metadata.AddAssembly( + flags: assembly.Flags, + hashAlgorithm: assembly.HashAlgorithm, + version: assembly.Identity.Version, + publicKey: metadata.GetOrAddBlob(assembly.PublicKey), + name: GetStringHandleForPathAndCheckLength(assembly.Name, assembly), + culture: metadata.GetOrAddString(assembly.Identity.CultureName)); } - - private readonly List _constantTable = new List(); - - private void PopulateCustomAttributeTableRows() + + private void PopulateCustomAttributeTableRows(ImmutableArray sortedGenericParameters) { if (this.IsFullMetadata) { this.AddAssemblyAttributesToTable(); } - this.AddCustomAttributesToTable(this.GetMethodDefs(), 0, this.GetMethodDefIndex); - this.AddCustomAttributesToTable(this.GetFieldDefs(), 1, this.GetFieldDefIndex); + this.AddCustomAttributesToTable(GetMethodDefs(), def => GetMethodDefinitionHandle(def)); + this.AddCustomAttributesToTable(GetFieldDefs(), def => GetFieldDefinitionHandle(def)); // this.AddCustomAttributesToTable(this.typeRefList, 2); - this.AddCustomAttributesToTable(this.GetTypeDefs(), 3, this.GetTypeDefIndex); - this.AddCustomAttributesToTable(this.GetParameterDefs(), 4, this.GetParameterDefIndex); + this.AddCustomAttributesToTable(GetTypeDefs(), def => GetTypeDefinitionHandle(def)); + this.AddCustomAttributesToTable(GetParameterDefs(), def => GetParameterHandle(def)); // TODO: attributes on interface implementation entries 5 // TODO: attributes on member reference entries 6 if (this.IsFullMetadata) { - this.AddModuleAttributesToTable(this.module, 7); + this.AddModuleAttributesToTable(module); } // TODO: declarative security entries 8 - this.AddCustomAttributesToTable(this.GetPropertyDefs(), 9, this.GetPropertyDefIndex); - this.AddCustomAttributesToTable(this.GetEventDefs(), 10, this.GetEventDefIndex); + this.AddCustomAttributesToTable(GetPropertyDefs(), def => GetPropertyDefIndex(def)); + this.AddCustomAttributesToTable(GetEventDefs(), def => GetEventDefinitionHandle(def)); // TODO: standalone signature entries 11 if (this.IsFullMetadata) { - this.AddCustomAttributesToTable(this.module.ModuleReferences, 12); + this.AddCustomAttributesToTable(module.ModuleReferences, TableIndex.ModuleRef); } // TODO: type spec entries 13 @@ -2750,19 +1953,7 @@ private void PopulateCustomAttributeTableRows() // TODO: exported types 17 // TODO: this.AddCustomAttributesToTable(assembly.Resources, 18); - // The indices of this.GetGenericParameters() do not correspond to the table indices because the - // the table may be sorted after the list has been constructed. - // Note that in all other cases, tables that are sorted are sorted in an order that depends - // only on list indices. The generic parameter table is the sole exception. - List sortedGenericParameterList = new List(); - foreach (GenericParamRow genericParamRow in _genericParamTable) - { - sortedGenericParameterList.Add(genericParamRow.GenericParameter); - } - - this.AddCustomAttributesToTable(sortedGenericParameterList, 19); - - _customAttributeTable.Sort(new CustomAttributeRowComparer()); + this.AddCustomAttributesToTable(sortedGenericParameters, TableIndex.GenericParam); } private void AddAssemblyAttributesToTable() @@ -2777,20 +1968,20 @@ private void AddAssemblyAttributesToTable() // at multi-module assembly build time. AddAssemblyAttributesToTable( this.module.AssemblySecurityAttributes.Select(sa => sa.Attribute), - true, // needsDummyParent - true); // isSecurity + needsDummyParent: true, + isSecurity: true); } AddAssemblyAttributesToTable( this.module.AssemblyAttributes, - writingNetModule, // needsDummyParent - false); // IsSecurity + needsDummyParent: writingNetModule, + isSecurity: false); } private void AddAssemblyAttributesToTable(IEnumerable assemblyAttributes, bool needsDummyParent, bool isSecurity) { Debug.Assert(this.IsFullMetadata); // parentToken is not relative - uint parentToken = (1 << 5) | 14; + EntityHandle parentHandle = Handle.AssemblyDefinition; foreach (ICustomAttribute customAttribute in assemblyAttributes) { if (needsDummyParent) @@ -2799,13 +1990,14 @@ private void AddAssemblyAttributesToTable(IEnumerable assembly // System.Runtime.CompilerServices.AssemblyAttributesGoHere* type refs. This is the contract for publishing // assembly attributes in netmodules so they may be migrated to containing/referencing multi-module assemblies, // at multi-module assembly build time. - parentToken = GetDummyAssemblyAttributeParent(isSecurity, customAttribute.AllowMultiple); + parentHandle = GetDummyAssemblyAttributeParent(isSecurity, customAttribute.AllowMultiple); } - AddCustomAttributeToTable(parentToken, customAttribute); + + AddCustomAttributeToTable(parentHandle, customAttribute); } } - private uint GetDummyAssemblyAttributeParent(bool isSecurity, bool allowMultiple) + private TypeReferenceHandle GetDummyAssemblyAttributeParent(bool isSecurity, bool allowMultiple) { // Lazily get or create placeholder assembly attribute parent type ref for the given combination of // whether isSecurity and allowMultiple. Convert type ref row id to corresponding attribute parent tag. @@ -2813,92 +2005,67 @@ private uint GetDummyAssemblyAttributeParent(bool isSecurity, bool allowMultiple // resolution scope, the types backing the placeholder type refs need not actually exist. int iS = isSecurity ? 1 : 0; int iM = allowMultiple ? 1 : 0; - if (_dummyAssemblyAttributeParent[iS, iM] == 0) + if (_dummyAssemblyAttributeParent[iS, iM].IsNil) { - TypeRefRow r = new TypeRefRow(); - r.ResolutionScope = this.GetResolutionScopeCodedIndex(this.module.GetCorLibrary(Context)); - r.Name = heaps.GetStringIndex(dummyAssemblyAttributeParentName + dummyAssemblyAttributeParentQualifier[iS, iM]); - r.Namespace = heaps.GetStringIndex(dummyAssemblyAttributeParentNamespace); - _typeRefTable.Add(r); - _dummyAssemblyAttributeParent[iS, iM] = ((uint)_typeRefTable.Count << 5) | 2; + _dummyAssemblyAttributeParent[iS, iM] = metadata.AddTypeReference( + resolutionScope: GetResolutionScopeHandle(module.GetCorLibrary(Context)), + @namespace: metadata.GetOrAddString(dummyAssemblyAttributeParentNamespace), + name: metadata.GetOrAddString(dummyAssemblyAttributeParentName + dummyAssemblyAttributeParentQualifier[iS, iM])); } + return _dummyAssemblyAttributeParent[iS, iM]; } - private void AddModuleAttributesToTable(IModule module, uint tag) + private void AddModuleAttributesToTable(IModule module) { - Debug.Assert(this.IsFullMetadata); // parentToken is not relative - uint parentToken = (1 << 5) | tag; + Debug.Assert(this.IsFullMetadata); foreach (ICustomAttribute customAttribute in module.ModuleAttributes) { - AddCustomAttributeToTable(parentToken, customAttribute); + AddCustomAttributeToTable(EntityHandle.ModuleDefinition, customAttribute); } } - private void AddCustomAttributesToTable(IEnumerable parentList, uint tag) + private void AddCustomAttributesToTable(IEnumerable parentList, TableIndex tableIndex) where T : IReference { - uint parentIndex = 0; + int parentRowId = 1; foreach (var parent in parentList) { - parentIndex++; - uint parentToken = (parentIndex << 5) | tag; + var parentHandle = MetadataTokens.Handle(tableIndex, parentRowId++); foreach (ICustomAttribute customAttribute in parent.GetAttributes(Context)) { - AddCustomAttributeToTable(parentToken, customAttribute); + AddCustomAttributeToTable(parentHandle, customAttribute); } } } - private void AddCustomAttributesToTable(IEnumerable parentList, uint tag, Func getDefIndex) + private void AddCustomAttributesToTable(IEnumerable parentList, Func getDefinitionHandle) where T : IReference { foreach (var parent in parentList) { - uint parentIndex = (uint)getDefIndex(parent); - uint parentToken = (parentIndex << 5) | tag; + EntityHandle parentHandle = getDefinitionHandle(parent); foreach (ICustomAttribute customAttribute in parent.GetAttributes(Context)) { - AddCustomAttributeToTable(parentToken, customAttribute); + AddCustomAttributeToTable(parentHandle, customAttribute); } } } - private void AddCustomAttributeToTable(uint parentToken, ICustomAttribute customAttribute) - { - CustomAttributeRow r = new CustomAttributeRow(); - r.Parent = parentToken; - var ctor = customAttribute.Constructor(Context); - r.Type = this.GetCustomAttributeTypeCodedIndex(ctor); - r.Value = this.GetCustomAttributeSignatureIndex(customAttribute); - r.OriginalPosition = _customAttributeTable.Count; - _customAttributeTable.Add(r); - } - - private class CustomAttributeRowComparer : Comparer + private void AddCustomAttributeToTable(EntityHandle parentHandle, ICustomAttribute customAttribute) { - public override int Compare(CustomAttributeRow x, CustomAttributeRow y) - { - int result = ((int)x.Parent) - (int)y.Parent; - if (result == 0) - { - result = x.OriginalPosition - y.OriginalPosition; - } - - return result; - } + metadata.AddCustomAttribute( + parent: parentHandle, + constructor: GetCustomAttributeTypeCodedIndex(customAttribute.Constructor(Context)), + value: GetCustomAttributeSignatureIndex(customAttribute)); } - private struct CustomAttributeRow { public uint Parent; public uint Type; public BlobIdx Value; public int OriginalPosition; } - - private readonly List _customAttributeTable = new List(); - private void PopulateDeclSecurityTableRows() { IAssembly assembly = this.module.AsAssembly; if (assembly != null) { - this.PopulateDeclSecurityTableRowsFor((1 << 2) | 2, assembly.AssemblySecurityAttributes); + this.PopulateDeclSecurityTableRowsFor(EntityHandle.AssemblyDefinition, assembly.AssemblySecurityAttributes); } foreach (ITypeDefinition typeDef in this.GetTypeDefs()) @@ -2908,8 +2075,7 @@ private void PopulateDeclSecurityTableRows() continue; } - uint typeDefIndex = (uint)this.GetTypeDefIndex(typeDef); - this.PopulateDeclSecurityTableRowsFor(typeDefIndex << 2, typeDef.SecurityAttributes); + this.PopulateDeclSecurityTableRowsFor(GetTypeDefinitionHandle(typeDef), typeDef.SecurityAttributes); } foreach (IMethodDefinition methodDef in this.GetMethodDefs()) @@ -2919,14 +2085,11 @@ private void PopulateDeclSecurityTableRows() continue; } - uint methodDefIndex = (uint)this.GetMethodDefIndex(methodDef); - this.PopulateDeclSecurityTableRowsFor((methodDefIndex << 2) | 1, methodDef.SecurityAttributes); + this.PopulateDeclSecurityTableRowsFor(GetMethodDefinitionHandle(methodDef), methodDef.SecurityAttributes); } - - _declSecurityTable.Sort(new DeclSecurityRowComparer()); } - private void PopulateDeclSecurityTableRowsFor(uint parent, IEnumerable attributes) + private void PopulateDeclSecurityTableRowsFor(EntityHandle parentHandle, IEnumerable attributes) { OrderPreservingMultiDictionary groupedSecurityAttributes = null; @@ -2941,113 +2104,78 @@ private void PopulateDeclSecurityTableRowsFor(uint parent, IEnumerable - { - public override int Compare(DeclSecurityRow x, DeclSecurityRow y) - { - int result = (int)x.Parent - (int)y.Parent; - if (result == 0) - { - result = x.OriginalIndex - y.OriginalIndex; - } - - return result; - } - } - - private struct DeclSecurityRow { public ushort Action; public uint Parent; public BlobIdx PermissionSet; public int OriginalIndex; } - - private readonly List _declSecurityTable = new List(); - - protected struct EncLogRow { public uint Token; public EncFuncCode FuncCode; } - - private readonly List _encLogTable = new List(); - - protected struct EncMapRow { public uint Token; } - - private readonly List _encMapTable = new List(); - - private void PopulateEventMapTableRows() - { - this.PopulateEventMapTableRows(_eventMapTable); - } - - protected struct EventMapRow { public uint Parent; public uint EventList; } - - private readonly List _eventMapTable = new List(); - private void PopulateEventTableRows() { var eventDefs = this.GetEventDefs(); - _eventTable.Capacity = eventDefs.Count; + metadata.SetCapacity(TableIndex.Event, eventDefs.Count); foreach (IEventDefinition eventDef in eventDefs) { - EventRow r = new EventRow(); - r.EventFlags = GetEventFlags(eventDef); - r.Name = this.GetStringIndexForNameAndCheckLength(eventDef.Name, eventDef); - r.EventType = this.GetTypeDefOrRefCodedIndex(eventDef.GetType(Context), true); - _eventTable.Add(r); + metadata.AddEvent( + attributes: GetEventAttributes(eventDef), + name: GetStringHandleForNameAndCheckLength(eventDef.Name, eventDef), + type: GetTypeHandle(eventDef.GetType(Context))); } } - private struct EventRow { public ushort EventFlags; public StringIdx Name; public uint EventType; } - - private readonly List _eventTable = new List(); - private void PopulateExportedTypeTableRows() { if (this.IsFullMetadata) { - _exportedTypeTable.Capacity = this.NumberOfTypeDefsEstimate; + metadata.SetCapacity(TableIndex.ExportedType, NumberOfTypeDefsEstimate); foreach (ITypeReference exportedType in this.module.GetExportedTypes(Context)) { INestedTypeReference nestedRef; INamespaceTypeReference namespaceTypeRef; - ExportedTypeRow r = new ExportedTypeRow(); - r.TypeDefId = (uint)MetadataTokens.GetToken(exportedType.TypeDef); + + TypeFlags flags; + int typeDefinitionId = MetadataTokens.GetToken(exportedType.TypeDef); + StringHandle typeName; + StringHandle typeNamespace; + EntityHandle implementation; + if ((namespaceTypeRef = exportedType.AsNamespaceTypeReference) != null) { - r.Flags = TypeFlags.PublicAccess; + flags = TypeFlags.PublicAccess; + string mangledTypeName = GetMangledName(namespaceTypeRef); - r.TypeName = this.GetStringIndexForNameAndCheckLength(mangledTypeName, namespaceTypeRef); - r.TypeNamespace = this.GetStringIndexForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); - r.Implementation = this.GetImplementationCodedIndex(namespaceTypeRef); - if ((r.Implementation & 1) == 1) + typeName = this.GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef); + typeNamespace = this.GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); + implementation = GetExportedTypeImplementation(namespaceTypeRef); + + if (implementation.Kind == HandleKind.AssemblyReference) { - r.Flags = TypeFlags.PrivateAccess | TypeFlags.ForwarderImplementation; - r.TypeDefId = 0; // Must be cleared for type forwarders. + flags = TypeFlags.PrivateAccess | TypeFlags.ForwarderImplementation; + typeDefinitionId = 0; // Must be cleared for type forwarders. } } else if ((nestedRef = exportedType.AsNestedTypeReference) != null) { - r.Flags = TypeFlags.NestedPublicAccess; - r.TypeName = this.GetStringIndexForNameAndCheckLength(GetMangledName(nestedRef), nestedRef); - r.TypeNamespace = default(StringIdx); + flags = TypeFlags.NestedPublicAccess; + typeName = this.GetStringHandleForNameAndCheckLength(GetMangledName(nestedRef), nestedRef); + typeNamespace = default(StringHandle); - var containingType = nestedRef.GetContainingType(Context); - uint ci = (uint)this.GetExportedTypeIndex(containingType); - r.Implementation = (ci << 2) | 2; + ITypeReference containingType = nestedRef.GetContainingType(Context); - var parentFlags = _exportedTypeTable[((int)ci) - 1].Flags; + int exportedTypeIndex = _exportedTypeIndex[containingType]; + implementation = MetadataTokens.ExportedTypeHandle(exportedTypeIndex); + + var parentFlags = (TypeFlags)metadata.GetExportedTypeFlags(exportedTypeIndex - 1); if (parentFlags == TypeFlags.PrivateAccess) { - r.Flags = TypeFlags.PrivateAccess; + flags = TypeFlags.PrivateAccess; } ITypeReference topLevelType = containingType; @@ -3057,11 +2185,11 @@ private void PopulateExportedTypeTableRows() topLevelType = tmp.GetContainingType(Context); } - var topLevelFlags = _exportedTypeTable[(int)this.GetExportedTypeIndex(topLevelType) - 1].Flags; + var topLevelFlags = (TypeFlags)metadata.GetExportedTypeFlags(_exportedTypeIndex[topLevelType] - 1); if ((topLevelFlags & TypeFlags.ForwarderImplementation) != 0) { - r.Flags = TypeFlags.PrivateAccess; - r.TypeDefId = 0; // Must be cleared for type forwarders and types they contain. + flags = TypeFlags.PrivateAccess; + typeDefinitionId = 0; // Must be cleared for type forwarders and types they contain. } } else @@ -3069,15 +2197,16 @@ private void PopulateExportedTypeTableRows() throw ExceptionUtilities.UnexpectedValue(exportedType); } - _exportedTypeTable.Add(r); + metadata.AddExportedType( + attributes: (TypeAttributes)flags, + @namespace: typeNamespace, + name: typeName, + implementation: implementation, + typeDefinitionId: typeDefinitionId); } } } - private struct ExportedTypeRow { public TypeFlags Flags; public uint TypeDefId; public StringIdx TypeName; public StringIdx TypeNamespace; public uint Implementation; } - - private readonly List _exportedTypeTable = new List(); - private void PopulateFieldLayoutTableRows() { foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) @@ -3087,18 +2216,12 @@ private void PopulateFieldLayoutTableRows() continue; } - uint fieldDefIndex = (uint)this.GetFieldDefIndex(fieldDef); - FieldLayoutRow r = new FieldLayoutRow(); - r.Offset = fieldDef.Offset; - r.Field = fieldDefIndex; - _fieldLayoutTable.Add(r); + metadata.AddFieldLayout( + field: GetFieldDefinitionHandle(fieldDef), + offset: fieldDef.Offset); } } - private struct FieldLayoutRow { public uint Offset; public uint Field; } - - private readonly List _fieldLayoutTable = new List(); - private void PopulateFieldMarshalTableRows() { foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) @@ -3108,20 +2231,17 @@ private void PopulateFieldMarshalTableRows() continue; } - FieldMarshalRow r = new FieldMarshalRow(); - var marshallingInformation = fieldDef.MarshallingInformation; - r.NativeType = (marshallingInformation != null) - ? this.GetMarshallingDescriptorIndex(marshallingInformation) - : this.GetMarshallingDescriptorIndex(fieldDef.MarshallingDescriptor); + BlobHandle descriptor = (marshallingInformation != null) + ? GetMarshallingDescriptorHandle(marshallingInformation) + : GetMarshallingDescriptorHandle(fieldDef.MarshallingDescriptor); - uint fieldDefIndex = (uint)this.GetFieldDefIndex(fieldDef); - r.Parent = fieldDefIndex << 1; - _fieldMarshalTable.Add(r); + metadata.AddMarshallingDescriptor( + parent: GetFieldDefinitionHandle(fieldDef), + descriptor: descriptor); } - int sizeWithOnlyFields = _fieldMarshalTable.Count; foreach (IParameterDefinition parDef in this.GetParameterDefs()) { if (!parDef.IsMarshalledExplicitly) @@ -3129,37 +2249,18 @@ private void PopulateFieldMarshalTableRows() continue; } - FieldMarshalRow r = new FieldMarshalRow(); - var marshallingInformation = parDef.MarshallingInformation; - r.NativeType = (marshallingInformation != null) - ? this.GetMarshallingDescriptorIndex(marshallingInformation) - : this.GetMarshallingDescriptorIndex(parDef.MarshallingDescriptor); + BlobHandle descriptor = (marshallingInformation != null) + ? GetMarshallingDescriptorHandle(marshallingInformation) + : GetMarshallingDescriptorHandle(parDef.MarshallingDescriptor); - uint parameterDefIndex = (uint)this.GetParameterDefIndex(parDef); - r.Parent = (parameterDefIndex << 1) | 1; - _fieldMarshalTable.Add(r); - } - - if (sizeWithOnlyFields > 0 && sizeWithOnlyFields < _fieldMarshalTable.Count) - { - _fieldMarshalTable.Sort(new FieldMarshalRowComparer()); - } - } - - private class FieldMarshalRowComparer : Comparer - { - public override int Compare(FieldMarshalRow x, FieldMarshalRow y) - { - return ((int)x.Parent) - (int)y.Parent; + metadata.AddMarshallingDescriptor( + parent: GetParameterHandle(parDef), + descriptor: descriptor); } } - private struct FieldMarshalRow { public uint Parent; public BlobIdx NativeType; } - - private readonly List _fieldMarshalTable = new List(); - private void PopulateFieldRvaTableRows(BlobBuilder mappedFieldDataWriter) { foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) @@ -3169,46 +2270,75 @@ private void PopulateFieldRvaTableRows(BlobBuilder mappedFieldDataWriter) continue; } - uint fieldIndex = (uint)this.GetFieldDefIndex(fieldDef); - FieldRvaRow r = new FieldRvaRow(); - - r.Offset = (uint)mappedFieldDataWriter.Position; + int rva = mappedFieldDataWriter.Position; mappedFieldDataWriter.WriteBytes(fieldDef.MappedData); - mappedFieldDataWriter.Align(MappedFieldDataAlignment); + mappedFieldDataWriter.Align(ManagedTextSection.MappedFieldDataAlignment); - r.Field = fieldIndex; - _fieldRvaTable.Add(r); + metadata.AddFieldRelativeVirtualAddress( + field: GetFieldDefinitionHandle(fieldDef), + relativeVirtualAddress: rva); } } - private struct FieldRvaRow { public uint Offset; public uint Field; } - - private readonly List _fieldRvaTable = new List(); - private void PopulateFieldTableRows() { var fieldDefs = this.GetFieldDefs(); - _fieldDefTable.Capacity = fieldDefs.Count; + metadata.SetCapacity(TableIndex.Field, fieldDefs.Count); foreach (IFieldDefinition fieldDef in fieldDefs) { - FieldDefRow r = new FieldDefRow(); - r.Flags = GetFieldFlags(fieldDef); - if (fieldDef.IsContextualNamedEntity) { ((IContextualNamedEntity)fieldDef).AssociateWithMetadataWriter(this); } - r.Name = this.GetStringIndexForNameAndCheckLength(fieldDef.Name, fieldDef); - r.Signature = this.GetFieldSignatureIndex(fieldDef); - _fieldDefTable.Add(r); + metadata.AddFieldDefinition( + attributes: GetFieldAttributes(fieldDef), + name: GetStringHandleForNameAndCheckLength(fieldDef.Name, fieldDef), + signature: GetFieldSignatureIndex(fieldDef)); } } - private struct FieldDefRow { public ushort Flags; public StringIdx Name; public BlobIdx Signature; } + private void PopulateConstantTableRows() + { + foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) + { + var constant = fieldDef.GetCompileTimeValue(Context); + if (constant == null) + { + continue; + } + + metadata.AddConstant( + parent: GetFieldDefinitionHandle(fieldDef), + value: constant.Value); + } + + foreach (IParameterDefinition parDef in this.GetParameterDefs()) + { + var defaultValue = parDef.GetDefaultValue(Context); + if (defaultValue == null) + { + continue; + } + + metadata.AddConstant( + parent: GetParameterHandle(parDef), + value: defaultValue.Value); + } + + foreach (IPropertyDefinition propDef in this.GetPropertyDefs()) + { + if (!propDef.HasDefaultValue) + { + continue; + } - private readonly List _fieldDefTable = new List(); + metadata.AddConstant( + parent: GetPropertyDefIndex(propDef), + value: propDef.DefaultValue.Value); + } + } private void PopulateFileTableRows() { @@ -3219,84 +2349,39 @@ private void PopulateFileTableRows() } var hashAlgorithm = assembly.HashAlgorithm; - _fileTable.Capacity = _fileRefList.Count; + metadata.SetCapacity(TableIndex.File, _fileRefList.Count); foreach (IFileReference fileReference in _fileRefList) { - FileTableRow r = new FileTableRow(); - r.Flags = fileReference.HasMetadata ? 0u : 1u; - r.FileName = this.GetStringIndexForPathAndCheckLength(fileReference.FileName); - r.HashValue = heaps.GetBlobIndex(fileReference.GetHashValue(hashAlgorithm)); - _fileTable.Add(r); - } - } - - private struct FileTableRow { public uint Flags; public StringIdx FileName; public BlobIdx HashValue; } - - private readonly List _fileTable = new List(); - - private void PopulateGenericParamConstraintTableRows() - { - uint genericParamIndex = 0; - foreach (GenericParamRow genericParameterRow in _genericParamTable) - { - genericParamIndex++; - GenericParamConstraintRow r = new GenericParamConstraintRow(); - r.Owner = genericParamIndex; - foreach (ITypeReference constraint in genericParameterRow.GenericParameter.GetConstraints(Context)) - { - r.Constraint = this.GetTypeDefOrRefCodedIndex(constraint, true); - _genericParamConstraintTable.Add(r); - } + metadata.AddAssemblyFile( + name: GetStringHandleForPathAndCheckLength(fileReference.FileName), + hashValue: metadata.GetOrAddBlob(fileReference.GetHashValue(hashAlgorithm)), + containsMetadata: fileReference.HasMetadata); } } - private struct GenericParamConstraintRow { public uint Owner; public uint Constraint; } - - private readonly List _genericParamConstraintTable = new List(); - - private void PopulateGenericParamTableRows() + private void PopulateGenericParameters(ImmutableArray sortedGenericParameters) { - var genericParameters = this.GetGenericParameters(); - _genericParamTable.Capacity = genericParameters.Count; - - foreach (IGenericParameter genPar in genericParameters) + foreach (IGenericParameter genericParameter in sortedGenericParameters) { - GenericParamRow r = new GenericParamRow(); - r.Number = genPar.Index; - r.Flags = GetGenericParamFlags(genPar); - r.Owner = this.GetTypeOrMethodDefCodedIndex(genPar); - // CONSIDER: The CLI spec doesn't mention a restriction on the Name column of the GenericParam table, // but they go in the same string heap as all the other declaration names, so it stands to reason that // they should be restricted in the same way. - r.Name = this.GetStringIndexForNameAndCheckLength(genPar.Name, genPar); + var genericParameterHandle = metadata.AddGenericParameter( + parent: GetDeclaringTypeOrMethodHandle(genericParameter), + attributes: GetGenericParameterAttributes(genericParameter), + name: GetStringHandleForNameAndCheckLength(genericParameter.Name, genericParameter), + index: genericParameter.Index); - r.GenericParameter = genPar; - _genericParamTable.Add(r); - } - - _genericParamTable.Sort(new GenericParamRowComparer()); - } - - private class GenericParamRowComparer : Comparer - { - public override int Compare(GenericParamRow x, GenericParamRow y) - { - int result = ((int)x.Owner) - (int)y.Owner; - if (result != 0) + foreach (ITypeReference constraint in genericParameter.GetConstraints(Context)) { - return result; + metadata.AddGenericParameterConstraint( + genericParameter: genericParameterHandle, + constraint: GetTypeHandle(constraint)); } - - return x.Number - y.Number; } } - private struct GenericParamRow { public ushort Number; public ushort Flags; public uint Owner; public StringIdx Name; public IGenericParameter GenericParameter; } - - private readonly List _genericParamTable = new List(); - private void PopulateImplMapTableRows() { foreach (IMethodDefinition methodDef in this.GetMethodDefs()) @@ -3307,415 +2392,339 @@ private void PopulateImplMapTableRows() } var data = methodDef.PlatformInvokeData; - uint methodDefIndex = (uint)this.GetMethodDefIndex(methodDef); - var r = new ImplMapRow(); - r.MappingFlags = (ushort)data.Flags; - r.MemberForwarded = (methodDefIndex << 1) | 1; - string entryPointName = data.EntryPointName; - r.ImportName = entryPointName != null - ? this.GetStringIndexForNameAndCheckLength(entryPointName, methodDef) - : heaps.GetStringIndex(methodDef.Name); // Length checked while populating the method def table. - r.ImportScope = (uint)this.GetModuleRefIndex(data.ModuleName); - _implMapTable.Add(r); + StringHandle importName = (entryPointName != null) + ? GetStringHandleForNameAndCheckLength(entryPointName, methodDef) + : metadata.GetOrAddString(methodDef.Name); // Length checked while populating the method def table. + + metadata.AddMethodImport( + member: GetMethodDefinitionHandle(methodDef), + attributes: data.Flags, + name: importName, + module: GetModuleReferenceHandle(data.ModuleName)); } } - private struct ImplMapRow { public ushort MappingFlags; public uint MemberForwarded; public StringIdx ImportName; public uint ImportScope; } - - private readonly List _implMapTable = new List(); - private void PopulateInterfaceImplTableRows() { foreach (ITypeDefinition typeDef in this.GetTypeDefs()) { - uint typeDefIndex = (uint)this.GetTypeDefIndex(typeDef); + var typeDefHandle = GetTypeDefinitionHandle(typeDef); foreach (ITypeReference interfaceRef in typeDef.Interfaces(Context)) { - InterfaceImplRow r = new InterfaceImplRow(); - r.Class = typeDefIndex; - r.Interface = this.GetTypeDefOrRefCodedIndex(interfaceRef, true); - _interfaceImplTable.Add(r); + metadata.AddInterfaceImplementation( + type: typeDefHandle, + implementedInterface: GetTypeHandle(interfaceRef)); } } } - - private struct InterfaceImplRow { public uint Class; public uint Interface; } - - private readonly List _interfaceImplTable = new List(); - + private void PopulateManifestResourceTableRows(BlobBuilder resourceDataWriter) { foreach (var resource in this.module.GetResources(Context)) { - ManifestResourceRow r = new ManifestResourceRow(); - r.Offset = GetManagedResourceOffset(resource, resourceDataWriter); - r.Flags = resource.IsPublic ? 1u : 2u; - r.Name = this.GetStringIndexForNameAndCheckLength(resource.Name); - + EntityHandle implementation; if (resource.ExternalFile != null) { - IFileReference externalFile = resource.ExternalFile; // Length checked on insertion into the file table. - r.Implementation = (uint)this.GetFileRefIndex(externalFile) << 2; + implementation = GetAssemblyFileHandle(resource.ExternalFile); } else { // This is an embedded resource, we don't support references to resources from referenced assemblies. - r.Implementation = 0; + implementation = default(EntityHandle); } - _manifestResourceTable.Add(r); + metadata.AddManifestResource( + attributes: resource.IsPublic ? ManifestResourceAttributes.Public : ManifestResourceAttributes.Private, + name: GetStringHandleForNameAndCheckLength(resource.Name), + implementation: implementation, + offset: GetManagedResourceOffset(resource, resourceDataWriter)); } // the stream should be aligned: - Debug.Assert((resourceDataWriter.Count % ManagedResourcesDataAlignment) == 0); + Debug.Assert((resourceDataWriter.Count % ManagedTextSection.ManagedResourcesDataAlignment) == 0); } - private struct ManifestResourceRow { public uint Offset; public uint Flags; public StringIdx Name; public uint Implementation; } - - private readonly List _manifestResourceTable = new List(); - private void PopulateMemberRefTableRows() { var memberRefs = this.GetMemberRefs(); - _memberRefTable.Capacity = memberRefs.Count; + metadata.SetCapacity(TableIndex.MemberRef, memberRefs.Count); foreach (ITypeMemberReference memberRef in memberRefs) { - MemberRefRow r = new MemberRefRow(); - r.Class = this.GetMemberRefParentCodedIndex(memberRef); - r.Name = this.GetStringIndexForNameAndCheckLength(memberRef.Name, memberRef); - r.Signature = this.GetMemberRefSignatureIndex(memberRef); - _memberRefTable.Add(r); + metadata.AddMemberReference( + parent: GetMemberReferenceParent(memberRef), + name: GetStringHandleForNameAndCheckLength(memberRef.Name, memberRef), + signature: GetMemberReferenceSignatureHandle(memberRef)); } } - - private struct MemberRefRow { public uint Class; public StringIdx Name; public BlobIdx Signature; } - - private readonly List _memberRefTable = new List(); - + private void PopulateMethodImplTableRows() { - _methodImplTable.Capacity = this.methodImplList.Count; + metadata.SetCapacity(TableIndex.MethodImpl, methodImplList.Count); foreach (MethodImplementation methodImplementation in this.methodImplList) { - MethodImplRow r = new MethodImplRow(); - r.Class = (uint)this.GetTypeDefIndex(methodImplementation.ContainingType); - r.MethodBody = this.GetMethodDefOrRefCodedIndex(methodImplementation.ImplementingMethod); - r.MethodDecl = this.GetMethodDefOrRefCodedIndex(methodImplementation.ImplementedMethod); - _methodImplTable.Add(r); + metadata.AddMethodImplementation( + type: GetTypeDefinitionHandle(methodImplementation.ContainingType), + methodBody: GetMethodDefinitionOrReferenceHandle(methodImplementation.ImplementingMethod), + methodDeclaration: GetMethodDefinitionOrReferenceHandle(methodImplementation.ImplementedMethod)); + } + } + + private void PopulateMethodSpecTableRows() + { + var methodSpecs = this.GetMethodSpecs(); + metadata.SetCapacity(TableIndex.MethodSpec, methodSpecs.Count); + + foreach (IGenericMethodInstanceReference genericMethodInstanceReference in methodSpecs) + { + metadata.AddMethodSpecification( + method: GetMethodDefinitionOrReferenceHandle(genericMethodInstanceReference.GetGenericMethod(Context)), + instantiation: GetMethodSpecificationBlobHandle(genericMethodInstanceReference)); } } - private struct MethodImplRow { public uint Class; public uint MethodBody; public uint MethodDecl; } + private void PopulateMethodTableRows(int[] methodBodyOffsets) + { + var methodDefs = this.GetMethodDefs(); + metadata.SetCapacity(TableIndex.MethodDef, methodDefs.Count); + + int i = 0; + foreach (IMethodDefinition methodDef in methodDefs) + { + metadata.AddMethodDefinition( + attributes: GetMethodAttributes(methodDef), + implAttributes: methodDef.GetImplementationAttributes(Context), + name: GetStringHandleForNameAndCheckLength(methodDef.Name, methodDef), + signature: GetMethodSignatureHandle(methodDef), + bodyOffset: methodBodyOffsets[i], + paramList: GetFirstParameterHandle(methodDef)); - private readonly List _methodImplTable = new List(); + i++; + } + } private void PopulateMethodSemanticsTableRows() { var propertyDefs = this.GetPropertyDefs(); var eventDefs = this.GetEventDefs(); - //EDMAURER an estimate, not necessarily accurate. - _methodSemanticsTable.Capacity = propertyDefs.Count * 2 + eventDefs.Count * 2; + // an estimate, not necessarily accurate. + metadata.SetCapacity(TableIndex.MethodSemantics, propertyDefs.Count * 2 + eventDefs.Count * 2); - uint i = 0; foreach (IPropertyDefinition propertyDef in this.GetPropertyDefs()) { - uint propertyIndex = (uint)this.GetPropertyDefIndex(propertyDef); - var r = new MethodSemanticsRow(); - r.Association = (propertyIndex << 1) | 1; + var association = GetPropertyDefIndex(propertyDef); foreach (IMethodReference accessorMethod in propertyDef.Accessors) { + ushort semantics; if (accessorMethod == propertyDef.Setter) { - r.Semantic = 0x0001; + semantics = 0x0001; } else if (accessorMethod == propertyDef.Getter) { - r.Semantic = 0x0002; + semantics = 0x0002; } else { - r.Semantic = 0x0004; + semantics = 0x0004; } - r.Method = (uint)this.GetMethodDefIndex(accessorMethod.GetResolvedMethod(Context)); - r.OriginalIndex = i++; - _methodSemanticsTable.Add(r); + metadata.AddMethodSemantics( + association: association, + semantics: semantics, + methodDefinition: GetMethodDefinitionHandle(accessorMethod.GetResolvedMethod(Context))); } } - int propertiesOnlyTableCount = _methodSemanticsTable.Count; foreach (IEventDefinition eventDef in this.GetEventDefs()) { - uint eventIndex = (uint)this.GetEventDefIndex(eventDef); - var r = new MethodSemanticsRow(); - r.Association = eventIndex << 1; + var association = GetEventDefinitionHandle(eventDef); foreach (IMethodReference accessorMethod in eventDef.Accessors) { - r.Semantic = 0x0004; + ushort semantics; if (accessorMethod == eventDef.Adder) { - r.Semantic = 0x0008; + semantics = 0x0008; } else if (accessorMethod == eventDef.Remover) { - r.Semantic = 0x0010; + semantics = 0x0010; } else if (accessorMethod == eventDef.Caller) { - r.Semantic = 0x0020; + semantics = 0x0020; + } + else + { + semantics = 0x0004; } - r.Method = (uint)this.GetMethodDefIndex(accessorMethod.GetResolvedMethod(Context)); - r.OriginalIndex = i++; - _methodSemanticsTable.Add(r); - } - } - - if (_methodSemanticsTable.Count > propertiesOnlyTableCount) - { - _methodSemanticsTable.Sort(new MethodSemanticsRowComparer()); - } - } - - private class MethodSemanticsRowComparer : Comparer - { - public override int Compare(MethodSemanticsRow x, MethodSemanticsRow y) - { - int result = ((int)x.Association) - (int)y.Association; - if (result == 0) - { - result = ((int)x.OriginalIndex) - (int)y.OriginalIndex; + metadata.AddMethodSemantics( + association: association, + semantics: semantics, + methodDefinition: GetMethodDefinitionHandle(accessorMethod.GetResolvedMethod(Context))); } - - return result; } } - private struct MethodSemanticsRow { public ushort Semantic; public uint Method; public uint Association; public uint OriginalIndex; } - - private readonly List _methodSemanticsTable = new List(); - - private void PopulateMethodSpecTableRows() - { - var methodSpecs = this.GetMethodSpecs(); - _methodSpecTable.Capacity = methodSpecs.Count; - - foreach (IGenericMethodInstanceReference genericMethodInstanceReference in methodSpecs) - { - MethodSpecRow r = new MethodSpecRow(); - r.Method = this.GetMethodDefOrRefCodedIndex(genericMethodInstanceReference.GetGenericMethod(Context)); - r.Instantiation = this.GetGenericMethodInstanceIndex(genericMethodInstanceReference); - _methodSpecTable.Add(r); - } - } - - private struct MethodSpecRow { public uint Method; public BlobIdx Instantiation; } - - private readonly List _methodSpecTable = new List(); - - private void PopulateMethodTableRows(int[] methodBodyRvas) - { - var methodDefs = this.GetMethodDefs(); - _methodTable = new MethodRow[methodDefs.Count]; - - int i = 0; - foreach (IMethodDefinition methodDef in methodDefs) - { - _methodTable[i] = new MethodRow - { - Rva = methodBodyRvas[i], - ImplFlags = (ushort)methodDef.GetImplementationAttributes(Context), - Flags = GetMethodFlags(methodDef), - Name = this.GetStringIndexForNameAndCheckLength(methodDef.Name, methodDef), - Signature = this.GetMethodSignatureIndex(methodDef), - ParamList = (uint)this.GetParameterDefIndex(methodDef), - }; - - i++; - } - } - - private struct MethodRow { public int Rva; public ushort ImplFlags; public ushort Flags; public StringIdx Name; public BlobIdx Signature; public uint ParamList; } - - private MethodRow[] _methodTable; - private void PopulateModuleRefTableRows() { var moduleRefs = this.GetModuleRefs(); - _moduleRefTable.Capacity = moduleRefs.Count; + metadata.SetCapacity(TableIndex.ModuleRef, moduleRefs.Count); foreach (string moduleName in moduleRefs) { - ModuleRefRow r = new ModuleRefRow(); - r.Name = this.GetStringIndexForPathAndCheckLength(moduleName); - _moduleRefTable.Add(r); + metadata.AddModuleReference(GetStringHandleForPathAndCheckLength(moduleName)); } } - private struct ModuleRefRow { public StringIdx Name; } - - private readonly List _moduleRefTable = new List(); - - private void PopulateModuleTableRow() + private void PopulateModuleTableRow(out Blob mvidFixup) { CheckPathLength(this.module.ModuleName); - // MVID is specified upfront when emitting EnC delta: + GuidHandle mvidIdx; Guid mvid = this.module.Properties.PersistentIdentifier; - - if (mvid == default(Guid) && !_deterministic) + if (mvid != default(Guid)) { - // If we are being nondeterministic, generate random - mvid = Guid.NewGuid(); + // MVID is specified upfront when emitting EnC delta: + mvidIdx = metadata.GetOrAddGuid(mvid); + mvidFixup = default(Blob); } - - _moduleRow = MakeModuleRow(heaps, mvid); - } - - private ModuleRow MakeModuleRow(MetadataHeapsBuilder heaps, Guid mvid) - { - return new ModuleRow + else if (_deterministic) { - Generation = this.Generation, - Name = heaps.GetStringIndex(this.module.ModuleName), - ModuleVersionId = heaps.AllocateGuid(mvid), - EncId = heaps.GetGuidIndex(this.EncId), - EncBaseId = heaps.GetGuidIndex(this.EncBaseId), - }; - } - - private struct ModuleRow { public ushort Generation; public StringIdx Name; public int ModuleVersionId; public int EncId; public int EncBaseId; } - - private ModuleRow _moduleRow; - - private void PopulateNestedClassTableRows() - { - foreach (ITypeDefinition typeDef in this.GetTypeDefs()) + // The guid will be filled in later based on hash of the file content: + mvidIdx = metadata.ReserveGuid(out mvidFixup); + } + else { - INestedTypeDefinition nestedTypeDef = typeDef.AsNestedTypeDefinition(Context); - if (nestedTypeDef == null) - { - continue; - } - - NestedClassRow r = new NestedClassRow(); - uint typeDefIndex = (uint)this.GetTypeDefIndex(typeDef); - r.NestedClass = typeDefIndex; - r.EnclosingClass = (uint)this.GetTypeDefIndex(nestedTypeDef.ContainingTypeDefinition); - _nestedClassTable.Add(r); + // If we are being nondeterministic generate random: + mvidIdx = metadata.GetOrAddGuid(Guid.NewGuid()); + mvidFixup = default(Blob); } - } - - private struct NestedClassRow { public uint NestedClass; public uint EnclosingClass; } - - private readonly List _nestedClassTable = new List(); + metadata.AddModule( + generation: this.Generation, + moduleName: metadata.GetOrAddString(this.module.ModuleName), + mvid: mvidIdx, + encId: metadata.GetOrAddGuid(EncId), + encBaseId: metadata.GetOrAddGuid(EncBaseId)); + } + private void PopulateParamTableRows() { var parameterDefs = this.GetParameterDefs(); - _paramTable.Capacity = parameterDefs.Count; + metadata.SetCapacity(TableIndex.Param, parameterDefs.Count); foreach (IParameterDefinition parDef in parameterDefs) { - ParamRow r = new ParamRow(); - r.Flags = GetParameterFlags(parDef); - r.Sequence = (ushort)(parDef is ReturnValueParameter ? 0 : parDef.Index + 1); - r.Name = this.GetStringIndexForNameAndCheckLength(parDef.Name, parDef); - _paramTable.Add(r); + metadata.AddParameter( + attributes: GetParameterAttributes(parDef), + sequenceNumber: (parDef is ReturnValueParameter) ? 0 : parDef.Index + 1, + name: GetStringHandleForNameAndCheckLength(parDef.Name, parDef)); } } - private struct ParamRow { public ushort Flags; public ushort Sequence; public StringIdx Name; } - - private readonly List _paramTable = new List(); - - private void PopulatePropertyMapTableRows() - { - this.PopulatePropertyMapTableRows(_propertyMapTable); - } - - protected struct PropertyMapRow { public uint Parent; public uint PropertyList; } - - private readonly List _propertyMapTable = new List(); - private void PopulatePropertyTableRows() { var propertyDefs = this.GetPropertyDefs(); - _propertyTable.Capacity = propertyDefs.Count; + metadata.SetCapacity(TableIndex.Property, propertyDefs.Count); foreach (IPropertyDefinition propertyDef in propertyDefs) { - var r = new PropertyRow(); - r.PropFlags = GetPropertyFlags(propertyDef); - r.Name = this.GetStringIndexForNameAndCheckLength(propertyDef.Name, propertyDef); - r.Type = this.GetPropertySignatureIndex(propertyDef); - _propertyTable.Add(r); + metadata.AddProperty( + attributes: GetPropertyAttributes(propertyDef), + name: GetStringHandleForNameAndCheckLength(propertyDef.Name, propertyDef), + signature: GetPropertySignatureHandle(propertyDef)); } } - - [StructLayout(LayoutKind.Auto)] - private struct PropertyRow { public ushort PropFlags; public StringIdx Name; public BlobIdx Type; } - - private readonly List _propertyTable = new List(); - + private void PopulateTypeDefTableRows() { var typeDefs = this.GetTypeDefs(); - _typeDefTable.Capacity = typeDefs.Count; + metadata.SetCapacity(TableIndex.TypeDef, typeDefs.Count); foreach (INamedTypeDefinition typeDef in typeDefs) { - var r = new TypeDefRow(); INamespaceTypeDefinition namespaceType = typeDef.AsNamespaceTypeDefinition(Context); - r.Flags = GetTypeDefFlags(typeDef); string mangledTypeName = GetMangledName(typeDef); - r.Name = this.GetStringIndexForNameAndCheckLength(mangledTypeName, typeDef); - r.Namespace = namespaceType == null - ? default(StringIdx) - : this.GetStringIndexForNamespaceAndCheckLength(namespaceType, mangledTypeName); ITypeReference baseType = typeDef.GetBaseClass(Context); - r.Extends = (baseType != null) ? this.GetTypeDefOrRefCodedIndex(baseType, true) : 0; - r.FieldList = (uint)this.GetFieldDefIndex(typeDef); - r.MethodList = (uint)this.GetMethodDefIndex(typeDef); + metadata.AddTypeDefinition( + attributes: GetTypeAttributes(typeDef), + @namespace: (namespaceType != null) ? GetStringHandleForNamespaceAndCheckLength(namespaceType, mangledTypeName) : default(StringHandle), + name: GetStringHandleForNameAndCheckLength(mangledTypeName, typeDef), + baseType: (baseType != null) ? GetTypeHandle(baseType) : default(EntityHandle), + fieldList: GetFirstFieldDefinitionHandle(typeDef), + methodList: GetFirstMethodDefinitionHandle(typeDef)); + } + } - _typeDefTable.Add(r); + private void PopulateNestedClassTableRows() + { + foreach (ITypeDefinition typeDef in this.GetTypeDefs()) + { + INestedTypeDefinition nestedTypeDef = typeDef.AsNestedTypeDefinition(Context); + if (nestedTypeDef == null) + { + continue; + } + + metadata.AddNestedType( + type: GetTypeDefinitionHandle(typeDef), + enclosingType: GetTypeDefinitionHandle(nestedTypeDef.ContainingTypeDefinition)); } } - private struct TypeDefRow { public uint Flags; public StringIdx Name; public StringIdx Namespace; public uint Extends; public uint FieldList; public uint MethodList; } + private void PopulateClassLayoutTableRows() + { + foreach (ITypeDefinition typeDef in this.GetTypeDefs()) + { + if (typeDef.Alignment == 0 && typeDef.SizeOf == 0) + { + continue; + } - private readonly List _typeDefTable = new List(); + metadata.AddTypeLayout( + type: GetTypeDefinitionHandle(typeDef), + packingSize: typeDef.Alignment, + size: typeDef.SizeOf); + } + } private void PopulateTypeRefTableRows() { var typeRefs = this.GetTypeRefs(); - _typeRefTable.Capacity = typeRefs.Count; + metadata.SetCapacity(TableIndex.TypeRef, typeRefs.Count); foreach (ITypeReference typeRef in typeRefs) { - TypeRefRow r = new TypeRefRow(); + EntityHandle resolutionScope; + StringHandle name; + StringHandle @namespace; + INestedTypeReference nestedTypeRef = typeRef.AsNestedTypeReference; if (nestedTypeRef != null) { + ITypeReference scopeTypeRef; + ISpecializedNestedTypeReference sneTypeRef = nestedTypeRef.AsSpecializedNestedTypeReference; if (sneTypeRef != null) { - r.ResolutionScope = this.GetResolutionScopeCodedIndex(sneTypeRef.UnspecializedVersion.GetContainingType(Context)); + scopeTypeRef = sneTypeRef.UnspecializedVersion.GetContainingType(Context); } else { - r.ResolutionScope = this.GetResolutionScopeCodedIndex(nestedTypeRef.GetContainingType(Context)); + scopeTypeRef = nestedTypeRef.GetContainingType(Context); } - r.Name = this.GetStringIndexForNameAndCheckLength(GetMangledName(nestedTypeRef), nestedTypeRef); - r.Namespace = default(StringIdx); + resolutionScope = GetTypeReferenceHandle(scopeTypeRef); + name = this.GetStringHandleForNameAndCheckLength(GetMangledName(nestedTypeRef), nestedTypeRef); + @namespace = default(StringHandle); } else { @@ -3725,516 +2734,59 @@ private void PopulateTypeRefTableRows() throw ExceptionUtilities.UnexpectedValue(typeRef); } - r.ResolutionScope = this.GetResolutionScopeCodedIndex(namespaceTypeRef.GetUnit(Context)); + resolutionScope = this.GetResolutionScopeHandle(namespaceTypeRef.GetUnit(Context)); string mangledTypeName = GetMangledName(namespaceTypeRef); - r.Name = this.GetStringIndexForNameAndCheckLength(mangledTypeName, namespaceTypeRef); - r.Namespace = this.GetStringIndexForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); + name = this.GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef); + @namespace = this.GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName); } - _typeRefTable.Add(r); + metadata.AddTypeReference( + resolutionScope: resolutionScope, + @namespace: @namespace, + name: name); } } - private struct TypeRefRow { public uint ResolutionScope; public StringIdx Name; public StringIdx Namespace; } - - private readonly List _typeRefTable = new List(); - private void PopulateTypeSpecTableRows() { var typeSpecs = this.GetTypeSpecs(); - _typeSpecTable.Capacity = typeSpecs.Count; + metadata.SetCapacity(TableIndex.TypeSpec, typeSpecs.Count); foreach (ITypeReference typeSpec in typeSpecs) { - TypeSpecRow r = new TypeSpecRow(); - r.Signature = this.GetTypeSpecSignatureIndex(typeSpec); - _typeSpecTable.Add(r); + metadata.AddTypeSpecification(GetTypeSpecSignatureIndex(typeSpec)); } } - private struct TypeSpecRow { public BlobIdx Signature; } - - private readonly List _typeSpecTable = new List(); - - private void SerializeTablesHeader(BlobBuilder writer, MetadataSizes metadataSizes) + private void PopulateStandaloneSignatures() { - int startPosition = writer.Position; - - HeapSizeFlag heapSizes = 0; - if (metadataSizes.StringIndexSize > 2) - { - heapSizes |= HeapSizeFlag.StringHeapLarge; - } + var signatures = GetStandaloneSignatureBlobHandles(); - if (metadataSizes.GuidIndexSize > 2) + foreach (BlobHandle signature in signatures) { - heapSizes |= HeapSizeFlag.GuidHeapLarge; + metadata.AddStandaloneSignature(signature); } - - if (metadataSizes.BlobIndexSize > 2) - { - heapSizes |= HeapSizeFlag.BlobHeapLarge; - } - - if (!this.IsFullMetadata) - { - heapSizes |= (HeapSizeFlag.EnCDeltas | HeapSizeFlag.DeletedMarks); - } - - ulong sortedDebugTables = metadataSizes.PresentTablesMask & MetadataSizes.SortedDebugTables; - - // Consider filtering out type system tables that are not present: - ulong sortedTables = sortedDebugTables | (metadataSizes.IsStandaloneDebugMetadata ? 0UL : 0x16003301fa00); - - writer.WriteUInt32(0); // reserved - writer.WriteByte(module.Properties.MetadataFormatMajorVersion); - writer.WriteByte(module.Properties.MetadataFormatMinorVersion); - writer.WriteByte((byte)heapSizes); - writer.WriteByte(1); // reserved - writer.WriteUInt64(metadataSizes.PresentTablesMask); - writer.WriteUInt64(sortedTables); - SerializeRowCounts(writer, metadataSizes.RowCounts, metadataSizes.PresentTablesMask); - - int endPosition = writer.Position; - Debug.Assert(metadataSizes.CalculateTableStreamHeaderSize() == endPosition - startPosition); } - private static void SerializeStandalonePdbStream(BlobBuilder writer, MetadataSizes metadataSizes, int entryPointToken, out int pdbIdOffset) - { - int startPosition = writer.Position; - - // zero out and save position, will be filled in later - pdbIdOffset = startPosition; - writer.WriteBytes(0, MetadataSizes.PdbIdSize); - - writer.WriteUInt32((uint)entryPointToken); - - writer.WriteUInt64(metadataSizes.ExternalTablesMask); - SerializeRowCounts(writer, metadataSizes.RowCounts, metadataSizes.ExternalTablesMask); - - int endPosition = writer.Position; - Debug.Assert(metadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition); - } - - private static void SerializeRowCounts(BlobBuilder writer, ImmutableArray rowCounts, ulong includeTables) - { - for (int i = 0; i < rowCounts.Length; i++) - { - if (((1UL << i) & includeTables) != 0) - { - int rowCount = rowCounts[i]; - if (rowCount > 0) - { - writer.WriteInt32(rowCount); - } - } - } - } - - private void SerializeModuleTable(BlobBuilder writer, MetadataSizes metadataSizes, MetadataHeapsBuilder heaps) - { - writer.WriteUInt16(_moduleRow.Generation); - writer.WriteReference((uint)heaps.ResolveStringIndex(_moduleRow.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_moduleRow.ModuleVersionId, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)_moduleRow.EncId, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)_moduleRow.EncBaseId, metadataSizes.GuidIndexSize); - } - - private void SerializeEncLogTable(BlobBuilder writer) - { - foreach (EncLogRow encLog in _encLogTable) - { - writer.WriteUInt32(encLog.Token); - writer.WriteUInt32((uint)encLog.FuncCode); - } - } - - private void SerializeEncMapTable(BlobBuilder writer) - { - foreach (EncMapRow encMap in _encMapTable) - { - writer.WriteUInt32(encMap.Token); - } - } - - private void SerializeTypeRefTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (TypeRefRow typeRef in _typeRefTable) - { - writer.WriteReference(typeRef.ResolutionScope, metadataSizes.ResolutionScopeCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(typeRef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(typeRef.Namespace), metadataSizes.StringIndexSize); - } - } - - private void SerializeTypeDefTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (TypeDefRow typeDef in _typeDefTable) - { - writer.WriteUInt32(typeDef.Flags); - writer.WriteReference((uint)heaps.ResolveStringIndex(typeDef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(typeDef.Namespace), metadataSizes.StringIndexSize); - writer.WriteReference(typeDef.Extends, metadataSizes.TypeDefOrRefCodedIndexSize); - writer.WriteReference(typeDef.FieldList, metadataSizes.FieldDefIndexSize); - writer.WriteReference(typeDef.MethodList, metadataSizes.MethodDefIndexSize); - } - } - - private void SerializeFieldTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (FieldDefRow fieldDef in _fieldDefTable) - { - writer.WriteUInt16(fieldDef.Flags); - writer.WriteReference((uint)heaps.ResolveStringIndex(fieldDef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(fieldDef.Signature), metadataSizes.BlobIndexSize); - } - } - - private void SerializeMethodDefTable(BlobBuilder writer, MetadataSizes metadataSizes, int methodBodyStreamRva) - { - foreach (MethodRow method in _methodTable) - { - if (method.Rva == -1) - { - writer.WriteUInt32(0); - } - else - { - writer.WriteUInt32((uint)(methodBodyStreamRva + method.Rva)); - } - - writer.WriteUInt16(method.ImplFlags); - writer.WriteUInt16(method.Flags); - writer.WriteReference((uint)heaps.ResolveStringIndex(method.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(method.Signature), metadataSizes.BlobIndexSize); - writer.WriteReference(method.ParamList, metadataSizes.ParameterIndexSize); - } - } - - private void SerializeParamTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ParamRow param in _paramTable) - { - writer.WriteUInt16(param.Flags); - writer.WriteUInt16(param.Sequence); - writer.WriteReference((uint)heaps.ResolveStringIndex(param.Name), metadataSizes.StringIndexSize); - } - } - - private void SerializeInterfaceImplTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (InterfaceImplRow interfaceImpl in _interfaceImplTable) - { - writer.WriteReference(interfaceImpl.Class, metadataSizes.TypeDefIndexSize); - writer.WriteReference(interfaceImpl.Interface, metadataSizes.TypeDefOrRefCodedIndexSize); - } - } - - private void SerializeMemberRefTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (MemberRefRow memberRef in _memberRefTable) - { - writer.WriteReference(memberRef.Class, metadataSizes.MemberRefParentCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(memberRef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(memberRef.Signature), metadataSizes.BlobIndexSize); - } - } - - private void SerializeConstantTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ConstantRow constant in _constantTable) - { - writer.WriteByte(constant.Type); - writer.WriteByte(0); - writer.WriteReference(constant.Parent, metadataSizes.HasConstantCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(constant.Value), metadataSizes.BlobIndexSize); - } - } - - private void SerializeCustomAttributeTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (CustomAttributeRow customAttribute in _customAttributeTable) - { - writer.WriteReference(customAttribute.Parent, metadataSizes.HasCustomAttributeCodedIndexSize); - writer.WriteReference(customAttribute.Type, metadataSizes.CustomAttributeTypeCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(customAttribute.Value), metadataSizes.BlobIndexSize); - } - } - - private void SerializeFieldMarshalTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (FieldMarshalRow fieldMarshal in _fieldMarshalTable) - { - writer.WriteReference(fieldMarshal.Parent, metadataSizes.HasFieldMarshalCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(fieldMarshal.NativeType), metadataSizes.BlobIndexSize); - } - } - - private void SerializeDeclSecurityTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (DeclSecurityRow declSecurity in _declSecurityTable) - { - writer.WriteUInt16(declSecurity.Action); - writer.WriteReference(declSecurity.Parent, metadataSizes.DeclSecurityCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(declSecurity.PermissionSet), metadataSizes.BlobIndexSize); - } - } - - private void SerializeClassLayoutTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ClassLayoutRow classLayout in _classLayoutTable) - { - writer.WriteUInt16(classLayout.PackingSize); - writer.WriteUInt32(classLayout.ClassSize); - writer.WriteReference(classLayout.Parent, metadataSizes.TypeDefIndexSize); - } - } - - private void SerializeFieldLayoutTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (FieldLayoutRow fieldLayout in _fieldLayoutTable) - { - writer.WriteUInt32(fieldLayout.Offset); - writer.WriteReference(fieldLayout.Field, metadataSizes.FieldDefIndexSize); - } - } - - private void SerializeStandAloneSigTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (BlobIdx blobIndex in this.GetStandAloneSignatures()) - { - writer.WriteReference((uint)heaps.ResolveBlobIndex(blobIndex), metadataSizes.BlobIndexSize); - } - } - - private void SerializeEventMapTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (EventMapRow eventMap in _eventMapTable) - { - writer.WriteReference(eventMap.Parent, metadataSizes.TypeDefIndexSize); - writer.WriteReference(eventMap.EventList, metadataSizes.EventDefIndexSize); - } - } - - private void SerializeEventTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (EventRow eventRow in _eventTable) - { - writer.WriteUInt16(eventRow.EventFlags); - writer.WriteReference((uint)heaps.ResolveStringIndex(eventRow.Name), metadataSizes.StringIndexSize); - writer.WriteReference(eventRow.EventType, metadataSizes.TypeDefOrRefCodedIndexSize); - } - } - - private void SerializePropertyMapTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (PropertyMapRow propertyMap in _propertyMapTable) - { - writer.WriteReference(propertyMap.Parent, metadataSizes.TypeDefIndexSize); - writer.WriteReference(propertyMap.PropertyList, metadataSizes.PropertyDefIndexSize); - } - } - - private void SerializePropertyTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (PropertyRow property in _propertyTable) - { - writer.WriteUInt16(property.PropFlags); - writer.WriteReference((uint)heaps.ResolveStringIndex(property.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(property.Type), metadataSizes.BlobIndexSize); - } - } - - private void SerializeMethodSemanticsTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (MethodSemanticsRow methodSemantic in _methodSemanticsTable) - { - writer.WriteUInt16(methodSemantic.Semantic); - writer.WriteReference(methodSemantic.Method, metadataSizes.MethodDefIndexSize); - writer.WriteReference(methodSemantic.Association, metadataSizes.HasSemanticsCodedIndexSize); - } - } - - private void SerializeMethodImplTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (MethodImplRow methodImpl in _methodImplTable) - { - writer.WriteReference(methodImpl.Class, metadataSizes.TypeDefIndexSize); - writer.WriteReference(methodImpl.MethodBody, metadataSizes.MethodDefOrRefCodedIndexSize); - writer.WriteReference(methodImpl.MethodDecl, metadataSizes.MethodDefOrRefCodedIndexSize); - } - } - - private void SerializeModuleRefTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ModuleRefRow moduleRef in _moduleRefTable) - { - writer.WriteReference((uint)heaps.ResolveStringIndex(moduleRef.Name), metadataSizes.StringIndexSize); - } - } - - private void SerializeTypeSpecTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (TypeSpecRow typeSpec in _typeSpecTable) - { - writer.WriteReference((uint)heaps.ResolveBlobIndex(typeSpec.Signature), metadataSizes.BlobIndexSize); - } - } - - private void SerializeImplMapTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ImplMapRow implMap in _implMapTable) - { - writer.WriteUInt16(implMap.MappingFlags); - writer.WriteReference(implMap.MemberForwarded, metadataSizes.MemberForwardedCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(implMap.ImportName), metadataSizes.StringIndexSize); - writer.WriteReference(implMap.ImportScope, metadataSizes.ModuleRefIndexSize); - } - } - - private void SerializeFieldRvaTable(BlobBuilder writer, MetadataSizes metadataSizes, int mappedFieldDataStreamRva) - { - foreach (FieldRvaRow fieldRva in _fieldRvaTable) - { - writer.WriteUInt32((uint)mappedFieldDataStreamRva + fieldRva.Offset); - writer.WriteReference(fieldRva.Field, metadataSizes.FieldDefIndexSize); - } - } - - private void SerializeAssemblyTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - if (!EmitAssemblyDefinition) - { - return; - } - - IAssembly assembly = this.module.AsAssembly; - var identity = assembly.Identity; - - writer.WriteUInt32((uint)assembly.HashAlgorithm); - writer.WriteUInt16((ushort)identity.Version.Major); - writer.WriteUInt16((ushort)identity.Version.Minor); - writer.WriteUInt16((ushort)identity.Version.Build); - writer.WriteUInt16((ushort)identity.Version.Revision); - writer.WriteUInt32(assembly.Flags); - writer.WriteReference((uint)heaps.ResolveBlobIndex(_assemblyKey), metadataSizes.BlobIndexSize); - - writer.WriteReference((uint)heaps.ResolveStringIndex(_assemblyName), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(_assemblyCulture), metadataSizes.StringIndexSize); - } - - private void SerializeAssemblyRefTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (AssemblyRefTableRow assemblyRef in _assemblyRefTable) - { - writer.WriteUInt16((ushort)assemblyRef.Version.Major); - writer.WriteUInt16((ushort)assemblyRef.Version.Minor); - writer.WriteUInt16((ushort)assemblyRef.Version.Build); - writer.WriteUInt16((ushort)assemblyRef.Version.Revision); - - // flags: reference has token, not full public key - uint flags = 0; - if (assemblyRef.IsRetargetable) - { - flags |= (uint)AssemblyFlags.Retargetable; - } - - flags |= (uint)assemblyRef.ContentType << 9; - - writer.WriteUInt32(flags); - - writer.WriteReference((uint)heaps.ResolveBlobIndex(assemblyRef.PublicKeyToken), metadataSizes.BlobIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(assemblyRef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(assemblyRef.Culture), metadataSizes.StringIndexSize); - writer.WriteReference(0, metadataSizes.BlobIndexSize); // hash of referenced assembly. Omitted. - } - } - - private void SerializeFileTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (FileTableRow fileReference in _fileTable) - { - writer.WriteUInt32(fileReference.Flags); - writer.WriteReference((uint)heaps.ResolveStringIndex(fileReference.FileName), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(fileReference.HashValue), metadataSizes.BlobIndexSize); - } - } - - private void SerializeExportedTypeTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ExportedTypeRow exportedType in _exportedTypeTable) - { - writer.WriteUInt32((uint)exportedType.Flags); - writer.WriteUInt32(exportedType.TypeDefId); - writer.WriteReference((uint)heaps.ResolveStringIndex(exportedType.TypeName), metadataSizes.StringIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(exportedType.TypeNamespace), metadataSizes.StringIndexSize); - writer.WriteReference(exportedType.Implementation, metadataSizes.ImplementationCodedIndexSize); - } - } - - private void SerializeManifestResourceTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (ManifestResourceRow manifestResource in _manifestResourceTable) - { - writer.WriteUInt32(manifestResource.Offset); - writer.WriteUInt32(manifestResource.Flags); - writer.WriteReference((uint)heaps.ResolveStringIndex(manifestResource.Name), metadataSizes.StringIndexSize); - writer.WriteReference(manifestResource.Implementation, metadataSizes.ImplementationCodedIndexSize); - } - } - - private void SerializeNestedClassTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (NestedClassRow nestedClass in _nestedClassTable) - { - writer.WriteReference(nestedClass.NestedClass, metadataSizes.TypeDefIndexSize); - writer.WriteReference(nestedClass.EnclosingClass, metadataSizes.TypeDefIndexSize); - } - } - - private void SerializeGenericParamTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (GenericParamRow genericParam in _genericParamTable) - { - writer.WriteUInt16(genericParam.Number); - writer.WriteUInt16(genericParam.Flags); - writer.WriteReference(genericParam.Owner, metadataSizes.TypeOrMethodDefCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveStringIndex(genericParam.Name), metadataSizes.StringIndexSize); - } - } - - private void SerializeMethodSpecTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (MethodSpecRow methodSpec in _methodSpecTable) - { - writer.WriteReference(methodSpec.Method, metadataSizes.MethodDefOrRefCodedIndexSize); - writer.WriteReference((uint)heaps.ResolveBlobIndex(methodSpec.Instantiation), metadataSizes.BlobIndexSize); - } - } - - private void SerializeGenericParamConstraintTable(BlobBuilder writer, MetadataSizes metadataSizes) - { - foreach (GenericParamConstraintRow genericParamConstraint in _genericParamConstraintTable) - { - writer.WriteReference(genericParamConstraint.Owner, metadataSizes.GenericParamIndexSize); - writer.WriteReference(genericParamConstraint.Constraint, metadataSizes.TypeDefOrRefCodedIndexSize); - } - } - - private int[] SerializeMethodBodies(BlobBuilder ilWriter, PdbWriter pdbWriterOpt) + private int[] SerializeMethodBodies(BlobBuilder ilBuilder, PdbWriter pdbWriterOpt) { CustomDebugInfoWriter customDebugInfoWriter = (pdbWriterOpt != null) ? new CustomDebugInfoWriter(pdbWriterOpt) : null; var methods = this.GetMethodDefs(); - int[] rvas = new int[methods.Count]; + int[] bodyOffsets = new int[methods.Count]; + + var lastLocalVariableHandle = default(LocalVariableHandle); + var lastLocalConstantHandle = default(LocalConstantHandle); + + var encoder = new MethodBodiesEncoder(ilBuilder); int methodRid = 1; foreach (IMethodDefinition method in methods) { _cancellationToken.ThrowIfCancellationRequested(); - int rva; + int bodyOffset; IMethodBody body; - int localSignatureRid; + StandaloneSignatureHandle localSignatureHandleOpt; if (method.HasBody()) { @@ -4243,176 +2795,145 @@ private int[] SerializeMethodBodies(BlobBuilder ilWriter, PdbWriter pdbWriterOpt if (body != null) { - localSignatureRid = this.SerializeLocalVariablesSignature(body); - uint localSignatureToken = (localSignatureRid != 0) ? (uint)(0x11000000 | localSignatureRid) : 0; + localSignatureHandleOpt = this.SerializeLocalVariablesSignature(body); // TODO: consider parallelizing these (local signature tokens can be piped into IL serialization & debug info generation) - rva = this.SerializeMethodBody(body, ilWriter, localSignatureToken); + bodyOffset = SerializeMethodBody(encoder, body, localSignatureHandleOpt); - pdbWriterOpt?.SerializeDebugInfo(body, localSignatureToken, customDebugInfoWriter); + pdbWriterOpt?.SerializeDebugInfo(body, localSignatureHandleOpt, customDebugInfoWriter); } else { - rva = 0; - localSignatureRid = 0; + bodyOffset = 0; + localSignatureHandleOpt = default(StandaloneSignatureHandle); } } else { // 0 is actually written to metadata when the row is serialized - rva = -1; + bodyOffset = -1; body = null; - localSignatureRid = 0; + localSignatureHandleOpt = default(StandaloneSignatureHandle); } - if (_debugHeapsOpt != null) + if (_debugMetadataOpt != null) { - SerializeMethodDebugInfo(body, methodRid, localSignatureRid); + SerializeMethodDebugInfo(body, methodRid, localSignatureHandleOpt, ref lastLocalVariableHandle, ref lastLocalConstantHandle); } - rvas[methodRid - 1] = rva; + bodyOffsets[methodRid - 1] = bodyOffset; methodRid++; } - return rvas; + return bodyOffsets; } - private int SerializeMethodBody(IMethodBody methodBody, BlobBuilder ilWriter, uint localSignatureToken) + private int SerializeMethodBody(MethodBodiesEncoder encoder, IMethodBody methodBody, StandaloneSignatureHandle localSignatureHandleOpt) { int ilLength = methodBody.IL.Length; - uint numberOfExceptionHandlers = (uint)methodBody.ExceptionRegions.Length; - bool isSmallBody = ilLength < 64 && methodBody.MaxStack <= 8 && localSignatureToken == 0 && numberOfExceptionHandlers == 0; + var exceptionRegions = methodBody.ExceptionRegions; + bool isSmallBody = ilLength < 64 && methodBody.MaxStack <= 8 && localSignatureHandleOpt.IsNil && exceptionRegions.Length == 0; // Check if an identical method body has already been serialized. // If so, use the RVA of the already serialized one. // Note that we don't need to rewrite the fake tokens in the body before looking it up. - int bodyRva; + int bodyOffset; // Don't do small body method caching during deterministic builds until this issue is fixed // https://github.com/dotnet/roslyn/issues/7595 - if (!_deterministic && isSmallBody && _smallMethodBodies.TryGetValue(methodBody.IL, out bodyRva)) - { - return bodyRva; - } - - if (isSmallBody) + if (!_deterministic && isSmallBody && _smallMethodBodies.TryGetValue(methodBody.IL, out bodyOffset)) { - bodyRva = ilWriter.Position; - ilWriter.WriteByte((byte)((ilLength << 2) | 2)); - - // Don't do small body method caching during deterministic builds until this issue is fixed - // https://github.com/dotnet/roslyn/issues/7595 - if (!_deterministic) - { - _smallMethodBodies.Add(methodBody.IL, bodyRva); - } + return bodyOffset; } - else - { - ilWriter.Align(4); - - bodyRva = ilWriter.Position; - - ushort flags = (3 << 12) | 0x3; - if (numberOfExceptionHandlers > 0) - { - flags |= 0x08; - } - if (methodBody.LocalsAreZeroed) - { - flags |= 0x10; - } + MethodBodyAttributes attributes = + (methodBody.LocalsAreZeroed ? MethodBodyAttributes.InitLocals : 0) | + (MayUseSmallExceptionHeaders(exceptionRegions) ? 0 : MethodBodyAttributes.LargeExceptionRegions); - ilWriter.WriteUInt16(flags); - ilWriter.WriteUInt16(methodBody.MaxStack); - ilWriter.WriteUInt32((uint)ilLength); - ilWriter.WriteUInt32(localSignatureToken); - } + var bodyEncoder = encoder.AddMethodBody(methodBody.MaxStack, exceptionRegions.Length, localSignatureHandleOpt, attributes); - WriteMethodBodyIL(ilWriter, methodBody); + Blob ilBlob; + var ehEncoder = bodyEncoder.WriteInstructions(methodBody.IL, out bodyOffset, out ilBlob); - if (numberOfExceptionHandlers > 0) + // Don't do small body method caching during deterministic builds until this issue is fixed + // https://github.com/dotnet/roslyn/issues/7595 + if (isSmallBody && !_deterministic) { - SerializeMethodBodyExceptionHandlerTable(methodBody, numberOfExceptionHandlers, ilWriter); + _smallMethodBodies.Add(methodBody.IL, bodyOffset); } - return bodyRva; + SubstituteFakeTokens(ilBlob, methodBody.IL); + SerializeMethodBodyExceptionHandlerTable(ehEncoder, exceptionRegions); + + return bodyOffset; } /// /// Serialize the method local signature to the blob. /// /// Standalone signature token - protected virtual int SerializeLocalVariablesSignature(IMethodBody body) + protected virtual StandaloneSignatureHandle SerializeLocalVariablesSignature(IMethodBody body) { Debug.Assert(!_tableIndicesAreComplete); var localVariables = body.LocalVariables; if (localVariables.Length == 0) { - return 0; + return default(StandaloneSignatureHandle); } - var writer = PooledBlobBuilder.GetInstance(); - writer.WriteByte(0x07); - writer.WriteCompressedInteger((uint)localVariables.Length); + var builder = PooledBlobBuilder.GetInstance(); + + var encoder = new BlobEncoder(builder).LocalVariableSignature(localVariables.Length); foreach (ILocalDefinition local in localVariables) { - this.SerializeLocalVariableSignature(writer, local); + SerializeLocalVariableType(encoder.AddVariable(), local); } - BlobIdx blobIndex = heaps.GetBlobIndex(writer); - int signatureIndex = this.GetOrAddStandAloneSignatureIndex(blobIndex); - writer.Free(); + encoder.EndVariables(); + + BlobHandle blobIndex = metadata.GetOrAddBlob(builder); - return signatureIndex; + var handle = GetOrAddStandaloneSignatureHandle(blobIndex); + builder.Free(); + + return handle; } - protected void SerializeLocalVariableSignature(BlobBuilder writer, ILocalDefinition local) + protected void SerializeLocalVariableType(LocalVariableTypeEncoder encoder, ILocalDefinition local) { - if (module.IsPlatformType(local.Type, PlatformType.SystemTypedReference)) + if (local.CustomModifiers.Length > 0) { - writer.WriteByte(0x16); + SerializeCustomModifiers(encoder.CustomModifiers(), local.CustomModifiers); } - else - { - foreach (ICustomModifier customModifier in local.CustomModifiers) - { - this.SerializeCustomModifier(customModifier, writer); - } - - if (local.IsPinned) - { - writer.WriteByte(0x45); - } - - if (local.IsReference) - { - writer.WriteByte(0x10); - } - this.SerializeTypeReference(local.Type, writer, false, true); + if (module.IsPlatformType(local.Type, PlatformType.SystemTypedReference)) + { + encoder.TypedReference(); + return; } + + SerializeTypeReference(encoder.Type(local.IsReference, local.IsPinned), local.Type); } - internal int SerializeLocalConstantStandAloneSignature(ILocalDefinition localConstant) + internal StandaloneSignatureHandle SerializeLocalConstantStandAloneSignature(ILocalDefinition localConstant) { - var writer = PooledBlobBuilder.GetInstance(); - writer.WriteByte(0x06); + var builder = PooledBlobBuilder.GetInstance(); + var typeEncoder = new BlobEncoder(builder).FieldSignature(); - foreach (ICustomModifier modifier in localConstant.CustomModifiers) + if (localConstant.CustomModifiers.Length > 0) { - this.SerializeCustomModifier(modifier, writer); + SerializeCustomModifiers(typeEncoder.CustomModifiers(), localConstant.CustomModifiers); } - this.SerializeTypeReference(localConstant.Type, writer, false, true); - BlobIdx blobIndex = heaps.GetBlobIndex(writer); - int signatureIndex = GetOrAddStandAloneSignatureIndex(blobIndex); - writer.Free(); + SerializeTypeReference(typeEncoder, localConstant.Type); - return 0x11000000 | signatureIndex; + BlobHandle blobIndex = metadata.GetOrAddBlob(builder); + var signatureHandle = GetOrAddStandaloneSignatureHandle(blobIndex); + builder.Free(); + + return signatureHandle; } private static int ReadInt32(ImmutableArray buffer, int pos) @@ -4420,43 +2941,30 @@ private static int ReadInt32(ImmutableArray buffer, int pos) return buffer[pos] | buffer[pos + 1] << 8 | buffer[pos + 2] << 16 | buffer[pos + 3] << 24; } - private static void WriteUint(byte[] buffer, uint value, int pos) - { - unchecked - { - buffer[pos] = (byte)value; - buffer[pos + 1] = (byte)(value >> 8); - buffer[pos + 2] = (byte)(value >> 16); - buffer[pos + 3] = (byte)(value >> 24); - } - } - - private int ResolveTokenFromReference(IReference reference) + private EntityHandle GetHandle(IReference reference) { - ITypeReference typeReference = reference as ITypeReference; - + var typeReference = reference as ITypeReference; if (typeReference != null) { - return this.GetTypeToken(typeReference); + return GetTypeHandle(typeReference); } - IFieldReference fieldReference = reference as IFieldReference; - + var fieldReference = reference as IFieldReference; if (fieldReference != null) { - return this.GetFieldToken(fieldReference); + return GetFieldHandle(fieldReference); } - IMethodReference methodReference = reference as IMethodReference; + var methodReference = reference as IMethodReference; if (methodReference != null) { - return this.GetMethodToken(methodReference); + return GetMethodHandle(methodReference); } throw ExceptionUtilities.UnexpectedValue(reference); } - private int ResolveSymbolTokenFromPseudoSymbolToken(int pseudoSymbolToken) + private EntityHandle ResolveEntityHandleFromPseudoToken(int pseudoSymbolToken) { int index = pseudoSymbolToken; var reference = _pseudoSymbolTokenToReferenceMap[index]; @@ -4466,53 +2974,52 @@ private int ResolveSymbolTokenFromPseudoSymbolToken(int pseudoSymbolToken) // that would have been done on them are done here. _referenceVisitor.VisitMethodBodyReference(reference); - int token = ResolveTokenFromReference(reference); - _pseudoSymbolTokenToTokenMap[index] = token; + EntityHandle handle = GetHandle(reference); + _pseudoSymbolTokenToTokenMap[index] = handle; _pseudoSymbolTokenToReferenceMap[index] = null; // Set to null to bypass next lookup - return token; + return handle; } return _pseudoSymbolTokenToTokenMap[index]; } - private int ResolveStringTokenFromPseudoStringToken(int pseudoStringToken) + private UserStringHandle ResolveUserStringHandleFromPseudoToken(int pseudoStringToken) { int index = pseudoStringToken; var str = _pseudoStringTokenToStringMap[index]; if (str != null) { - const int overflowToken = 0x70000000; // 0x70 is a token type for a user string - int token; + UserStringHandle handle; if (!_userStringTokenOverflow) { - if (!heaps.TryGetUserStringToken(str, out token)) + try { - this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.ERR_TooManyUserStrings, - NoLocation.Singleton)); + handle = metadata.GetOrAddUserString(str); + } + catch (ImageFormatLimitationException) + { + this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.ERR_TooManyUserStrings, NoLocation.Singleton)); _userStringTokenOverflow = true; - token = overflowToken; + handle = default(UserStringHandle); } } else { - token = overflowToken; + handle = default(UserStringHandle); } - _pseudoStringTokenToTokenMap[index] = token; + _pseudoStringTokenToTokenMap[index] = handle; _pseudoStringTokenToStringMap[index] = null; // Set to null to bypass next lookup - return token; + return handle; } return _pseudoStringTokenToTokenMap[index]; } - private void WriteMethodBodyIL(BlobBuilder builder, IMethodBody methodBody) + private void SubstituteFakeTokens(Blob blob, ImmutableArray methodBodyIL) { - ImmutableArray methodBodyIL = methodBody.IL; - // write the raw body first and then patch tokens: - var writer = builder.ReserveBytes(methodBodyIL.Length); - writer.WriteBytes(methodBodyIL); + var writer = new BlobWriter(blob); int offset = 0; while (offset < methodBodyIL.Length) @@ -4525,13 +3032,13 @@ private void WriteMethodBodyIL(BlobBuilder builder, IMethodBody methodBody) case OperandType.InlineTok: case OperandType.InlineType: writer.Offset = offset; - writer.WriteInt32(ResolveSymbolTokenFromPseudoSymbolToken(ReadInt32(methodBodyIL, offset))); + writer.WriteInt32(MetadataTokens.GetToken(ResolveEntityHandleFromPseudoToken(ReadInt32(methodBodyIL, offset)))); offset += 4; break; case OperandType.InlineString: writer.Offset = offset; - writer.WriteInt32(ResolveStringTokenFromPseudoStringToken(ReadInt32(methodBodyIL, offset))); + writer.WriteInt32(MetadataTokens.GetToken(ResolveUserStringHandleFromPseudoToken(ReadInt32(methodBodyIL, offset)))); offset += 4; break; @@ -4572,87 +3079,38 @@ private void WriteMethodBodyIL(BlobBuilder builder, IMethodBody methodBody) } } - private void SerializeMethodBodyExceptionHandlerTable(IMethodBody methodBody, uint numberOfExceptionHandlers, BlobBuilder writer) + private void SerializeMethodBodyExceptionHandlerTable(ExceptionRegionEncoder encoder, ImmutableArray regions) { - var regions = methodBody.ExceptionRegions; - bool useSmallExceptionHeaders = MayUseSmallExceptionHeaders(numberOfExceptionHandlers, regions); - writer.Align(4); - if (useSmallExceptionHeaders) - { - uint dataSize = numberOfExceptionHandlers * 12 + 4; - writer.WriteByte(0x01); - writer.WriteByte((byte)(dataSize & 0xff)); - writer.WriteUInt16(0); - } - else - { - uint dataSize = numberOfExceptionHandlers * 24 + 4; - writer.WriteByte(0x41); - writer.WriteByte((byte)(dataSize & 0xff)); - writer.WriteUInt16((ushort)((dataSize >> 8) & 0xffff)); - } + encoder.StartRegions(); foreach (var region in regions) { - this.SerializeExceptionRegion(region, useSmallExceptionHeaders, writer); - } - } - - private void SerializeExceptionRegion(ExceptionHandlerRegion region, bool useSmallExceptionHeaders, BlobBuilder writer) - { - writer.WriteUInt16((ushort)region.HandlerKind); + var exceptionType = region.ExceptionType; - if (useSmallExceptionHeaders) - { - writer.WriteUInt16((ushort)region.TryStartOffset); - writer.WriteByte((byte)(region.TryEndOffset - region.TryStartOffset)); - writer.WriteUInt16((ushort)region.HandlerStartOffset); - writer.WriteByte((byte)(region.HandlerEndOffset - region.HandlerStartOffset)); - } - else - { - writer.WriteUInt16(0); - writer.WriteUInt32((uint)region.TryStartOffset); - writer.WriteUInt32((uint)(region.TryEndOffset - region.TryStartOffset)); - writer.WriteUInt32((uint)region.HandlerStartOffset); - writer.WriteUInt32((uint)(region.HandlerEndOffset - region.HandlerStartOffset)); + encoder.AddRegion( + region.HandlerKind, + region.TryStartOffset, + region.TryLength, + region.HandlerStartOffset, + region.HandlerLength, + (exceptionType != null) ? GetTypeHandle(exceptionType) : default(EntityHandle), + region.FilterDecisionStartOffset); } - if (region.HandlerKind == ExceptionRegionKind.Catch) - { - writer.WriteUInt32((uint)this.GetTypeToken(region.ExceptionType)); - } - else - { - writer.WriteUInt32((uint)region.FilterDecisionStartOffset); - } + encoder.EndRegions(); } - private static bool MayUseSmallExceptionHeaders(uint numberOfExceptionHandlers, ImmutableArray exceptionRegions) + private static bool MayUseSmallExceptionHeaders(ImmutableArray exceptionRegions) { - if (numberOfExceptionHandlers * 12 + 4 > 0xff) + if (!ExceptionRegionEncoder.IsSmallRegionCount(exceptionRegions.Length)) { return false; } foreach (var region in exceptionRegions) { - if (region.TryStartOffset > 0xffff) - { - return false; - } - - if (region.TryEndOffset - region.TryStartOffset > 0xff) - { - return false; - } - - if (region.HandlerStartOffset > 0xffff) - { - return false; - } - - if (region.HandlerEndOffset - region.HandlerStartOffset > 0xff) + if (!ExceptionRegionEncoder.IsSmallExceptionRegion(region.TryStartOffset, region.TryLength) || + !ExceptionRegionEncoder.IsSmallExceptionRegion(region.HandlerStartOffset, region.HandlerLength)) { return false; } @@ -4661,98 +3119,109 @@ private static bool MayUseSmallExceptionHeaders(uint numberOfExceptionHandlers, return true; } - private void SerializeParameterInformation(IParameterTypeInformation parameterTypeInformation, BlobBuilder writer) + private void SerializeParameterInformation(ParameterTypeEncoder encoder, IParameterTypeInformation parameterTypeInformation) { - ushort countOfCustomModifiersPrecedingByRef = parameterTypeInformation.CountOfCustomModifiersPrecedingByRef; var modifiers = parameterTypeInformation.CustomModifiers; + ushort numberOfModifiersPrecedingByRef = parameterTypeInformation.CountOfCustomModifiersPrecedingByRef; + int numberOfRemainingModifiers = modifiers.Length - numberOfModifiersPrecedingByRef; - Debug.Assert(countOfCustomModifiersPrecedingByRef == 0 || parameterTypeInformation.IsByReference); + Debug.Assert(numberOfModifiersPrecedingByRef == 0 || parameterTypeInformation.IsByReference); - if (parameterTypeInformation.IsByReference) + if (numberOfModifiersPrecedingByRef > 0) { - for (int i = 0; i < countOfCustomModifiersPrecedingByRef; i++) - { - this.SerializeCustomModifier(modifiers[i], writer); - } + SerializeCustomModifiers(encoder.CustomModifiers(), modifiers, 0, numberOfModifiersPrecedingByRef); + } - writer.WriteByte(0x10); + var type = parameterTypeInformation.GetType(Context); + if (module.IsPlatformType(type, PlatformType.SystemTypedReference)) + { + encoder.TypedReference(); + return; } - for (int i = countOfCustomModifiersPrecedingByRef; i < modifiers.Length; i++) + var typeEncoder = encoder.Type(parameterTypeInformation.IsByReference); + + if (numberOfRemainingModifiers > 0) { - this.SerializeCustomModifier(modifiers[i], writer); + SerializeCustomModifiers(typeEncoder.CustomModifiers(), modifiers, numberOfModifiersPrecedingByRef, numberOfRemainingModifiers); } - this.SerializeTypeReference(parameterTypeInformation.GetType(Context), writer, false, true); + SerializeTypeReference(typeEncoder, type); } - private void SerializeFieldSignature(IFieldReference fieldReference, BlobBuilder writer) + private void SerializeFieldSignature(IFieldReference fieldReference, BlobBuilder builder) { - writer.WriteByte(0x06); - - this.SerializeTypeReference(fieldReference.GetType(Context), writer, false, true); + var typeEncoder = new BlobEncoder(builder).FieldSignature(); + SerializeTypeReference(typeEncoder, fieldReference.GetType(Context)); } - private void SerializeGenericMethodInstanceSignature(BlobBuilder writer, IGenericMethodInstanceReference genericMethodInstanceReference) + private void SerializeMethodSpecificationSignature(BlobBuilder builder, IGenericMethodInstanceReference genericMethodInstanceReference) { - writer.WriteByte(0x0a); - writer.WriteCompressedInteger(genericMethodInstanceReference.GetGenericMethod(Context).GenericParameterCount); + var argsEncoder = new BlobEncoder(builder).MethodSpecificationSignature(genericMethodInstanceReference.GetGenericMethod(Context).GenericParameterCount); foreach (ITypeReference genericArgument in genericMethodInstanceReference.GetGenericArguments(Context)) { - this.SerializeTypeReference(genericArgument, writer, false, true); + ITypeReference typeRef = genericArgument; + SerializeTypeReference(argsEncoder.AddArgument(), typeRef); } + + argsEncoder.EndArguments(); } - private void SerializeCustomAttributeSignature(ICustomAttribute customAttribute, bool writeOnlyNamedArguments, BlobBuilder writer) + private void SerializeCustomAttributeSignature(ICustomAttribute customAttribute, BlobBuilder builder) { - if (!writeOnlyNamedArguments) - { - writer.WriteUInt16(0x0001); - var parameters = customAttribute.Constructor(Context).GetParameters(Context).GetEnumerator(); - foreach (var argument in customAttribute.GetArguments(Context)) - { - var success = parameters.MoveNext(); - Debug.Assert(success); - if (!success) - { - // TODO: md error - break; - } - - this.SerializeMetadataExpression(writer, argument, parameters.Current.GetType(Context)); - } + var parameters = customAttribute.Constructor(Context).GetParameters(Context); + var arguments = customAttribute.GetArguments(Context); + Debug.Assert(parameters.Length == arguments.Length); - Debug.Assert(!parameters.MoveNext()); + FixedArgumentsEncoder fixedArgsEncoder; + CustomAttributeNamedArgumentsEncoder namedArgsEncoder; + new BlobEncoder(builder).CustomAttributeSignature(out fixedArgsEncoder, out namedArgsEncoder); - writer.WriteUInt16(customAttribute.NamedArgumentCount); - } - else + for (int i = 0; i < parameters.Length; i++) { - writer.WriteCompressedInteger(customAttribute.NamedArgumentCount); + SerializeMetadataExpression(fixedArgsEncoder.AddArgument(), arguments[i], parameters[i].GetType(Context)); } - if (customAttribute.NamedArgumentCount > 0) + fixedArgsEncoder.EndArguments(); + + SerializeCustomAttributeNamedArguments(namedArgsEncoder.Count(customAttribute.NamedArgumentCount), customAttribute); + } + + private void SerializeCustomAttributeNamedArguments(NamedArgumentsEncoder encoder, ICustomAttribute customAttribute) + { + foreach (IMetadataNamedArgument namedArgument in customAttribute.GetNamedArguments(Context)) { - foreach (IMetadataNamedArgument namedArgument in customAttribute.GetNamedArguments(Context)) - { - writer.WriteByte(namedArgument.IsField ? (byte)0x53 : (byte)0x54); - if (this.module.IsPlatformType(namedArgument.Type, PlatformType.SystemObject)) - { - writer.WriteByte(0x51); - } - else - { - this.SerializeTypeReference(namedArgument.Type, writer, true, true); - } + NamedArgumentTypeEncoder typeEncoder; + NameEncoder nameEncoder; + LiteralEncoder literalEncoder; + encoder.AddArgument(namedArgument.IsField, out typeEncoder, out nameEncoder, out literalEncoder); - writer.WriteSerializedString(namedArgument.ArgumentName); + SerializeNamedArgumentType(typeEncoder, namedArgument.Type); + nameEncoder.Name(namedArgument.ArgumentName); + SerializeMetadataExpression(literalEncoder, namedArgument.ArgumentValue, namedArgument.Type); + } - this.SerializeMetadataExpression(writer, namedArgument.ArgumentValue, namedArgument.Type); - } + encoder.EndArguments(); + } + + private void SerializeNamedArgumentType(NamedArgumentTypeEncoder encoder, ITypeReference type) + { + var arrayType = type as IArrayTypeReference; + if (arrayType != null) + { + SerializeCustomAttributeArrayType(encoder.SZArray(), arrayType); + } + else if (module.IsPlatformType(type, PlatformType.SystemObject)) + { + encoder.Object(); + } + else + { + SerializeCustomAttributeElementType(encoder.ScalarType(), type); } } - private void SerializeMetadataExpression(BlobBuilder writer, IMetadataExpression expression, ITypeReference targetType) + private void SerializeMetadataExpression(LiteralEncoder encoder, IMetadataExpression expression, ITypeReference targetType) { IMetadataCreateArray a = expression as IMetadataCreateArray; if (a != null) @@ -4760,93 +3229,93 @@ private void SerializeMetadataExpression(BlobBuilder writer, IMetadataExpression ITypeReference targetElementType; var targetArrayType = targetType as IArrayTypeReference; + VectorEncoder vectorEncoder; if (targetArrayType == null) { // implicit conversion from array to object Debug.Assert(this.module.IsPlatformType(targetType, PlatformType.SystemObject)); - targetElementType = a.ElementType; + CustomAttributeArrayTypeEncoder arrayTypeEncoder; + encoder.TaggedVector(out arrayTypeEncoder, out vectorEncoder); + SerializeCustomAttributeArrayType(arrayTypeEncoder, (IArrayTypeReference)a.Type); - writer.WriteByte(0x1d); - this.SerializeTypeReference(targetElementType, writer, true, true); + targetElementType = a.ElementType; } else { + vectorEncoder = encoder.Vector(); + + // In FixedArg the element type of the parameter array has to match the element type of the argument array, + // but in NamedArg T[] can be assigned to object[]. In that case we need to encode the arguments using + // the parameter element type not the argument element type. targetElementType = targetArrayType.GetElementType(this.Context); } - writer.WriteUInt32(a.ElementCount); + var literalsEncoder = vectorEncoder.Count((int)a.ElementCount); foreach (IMetadataExpression elemValue in a.Elements) { - this.SerializeMetadataExpression(writer, elemValue, targetElementType); + SerializeMetadataExpression(literalsEncoder.AddLiteral(), elemValue, targetElementType); } + + literalsEncoder.EndLiterals(); } else { + ScalarEncoder scalarEncoder; IMetadataConstant c = expression as IMetadataConstant; if (this.module.IsPlatformType(targetType, PlatformType.SystemObject)) { + CustomAttributeElementTypeEncoder typeEncoder; + encoder.TaggedScalar(out typeEncoder, out scalarEncoder); + + // special case null argument assigned to Object parameter - treat as null string if (c != null && c.Value == null && this.module.IsPlatformType(c.Type, PlatformType.SystemObject)) { - // handle null case - writer.WriteByte(0x0e); // serialize string type - writer.WriteByte(0xFF); // null string - return; + typeEncoder.String(); } - - this.SerializeTypeReference(expression.Type, writer, true, true); + else + { + SerializeCustomAttributeElementType(typeEncoder, expression.Type); + } + } + else + { + scalarEncoder = encoder.Scalar(); } if (c != null) { if (c.Type is IArrayTypeReference) { - writer.WriteInt32(-1); // null array - } - else if (c.Type.TypeCode(Context) == PrimitiveTypeCode.String) - { - writer.WriteSerializedString((string)c.Value); - } - else if (this.module.IsPlatformType(c.Type, PlatformType.SystemType)) - { - Debug.Assert(c.Value == null); - writer.WriteSerializedString(null); - } - else - { - writer.WriteConstant(c.Value); + scalarEncoder.NullArray(); + return; } + + Debug.Assert(!module.IsPlatformType(c.Type, PlatformType.SystemType) || c.Value == null); + scalarEncoder.Constant(c.Value); } else { - IMetadataTypeOf t = expression as IMetadataTypeOf; - if (t != null) - { - this.SerializeTypeName(t.TypeToGet, writer); - } - else - { - // TODO: error - } + scalarEncoder.SystemType(((IMetadataTypeOf)expression).TypeToGet.GetSerializedTypeName(Context)); } } } private void SerializeMarshallingDescriptor(IMarshallingInformation marshallingInformation, BlobBuilder writer) { - writer.WriteCompressedInteger((uint)marshallingInformation.UnmanagedType); + writer.WriteCompressedInteger((int)marshallingInformation.UnmanagedType); switch (marshallingInformation.UnmanagedType) { case UnmanagedType.ByValArray: // NATIVE_TYPE_FIXEDARRAY Debug.Assert(marshallingInformation.NumberOfElements >= 0); - writer.WriteCompressedInteger((uint)marshallingInformation.NumberOfElements); + writer.WriteCompressedInteger(marshallingInformation.NumberOfElements); if (marshallingInformation.ElementType >= 0) { - writer.WriteCompressedInteger((uint)marshallingInformation.ElementType); + writer.WriteCompressedInteger((int)marshallingInformation.ElementType); } break; @@ -4883,20 +3352,20 @@ private void SerializeMarshallingDescriptor(IMarshallingInformation marshallingI case UnmanagedType.LPArray: // NATIVE_TYPE_ARRAY Debug.Assert(marshallingInformation.ElementType >= 0); - writer.WriteCompressedInteger((uint)marshallingInformation.ElementType); + writer.WriteCompressedInteger((int)marshallingInformation.ElementType); if (marshallingInformation.ParamIndex >= 0) { - writer.WriteCompressedInteger((uint)marshallingInformation.ParamIndex); + writer.WriteCompressedInteger(marshallingInformation.ParamIndex); if (marshallingInformation.NumberOfElements >= 0) { - writer.WriteCompressedInteger((uint)marshallingInformation.NumberOfElements); + writer.WriteCompressedInteger(marshallingInformation.NumberOfElements); writer.WriteByte(1); // The parameter number is valid } } else if (marshallingInformation.NumberOfElements >= 0) { writer.WriteByte(0); // Dummy parameter value emitted so that NumberOfElements can be in a known position - writer.WriteCompressedInteger((uint)marshallingInformation.NumberOfElements); + writer.WriteCompressedInteger(marshallingInformation.NumberOfElements); writer.WriteByte(0); // The parameter number is not valid } @@ -4905,7 +3374,7 @@ private void SerializeMarshallingDescriptor(IMarshallingInformation marshallingI case Constants.UnmanagedType_SafeArray: if (marshallingInformation.SafeArrayElementSubtype >= 0) { - writer.WriteCompressedInteger((uint)marshallingInformation.SafeArrayElementSubtype); + writer.WriteCompressedInteger((int)marshallingInformation.SafeArrayElementSubtype); var elementType = marshallingInformation.GetSafeArrayElementUserDefinedSubtype(Context); if (elementType != null) { @@ -4916,7 +3385,7 @@ private void SerializeMarshallingDescriptor(IMarshallingInformation marshallingI break; case UnmanagedType.ByValTStr: // NATIVE_TYPE_FIXEDSYSSTRING - writer.WriteCompressedInteger((uint)marshallingInformation.NumberOfElements); + writer.WriteCompressedInteger(marshallingInformation.NumberOfElements); break; case UnmanagedType.Interface: @@ -4924,7 +3393,7 @@ private void SerializeMarshallingDescriptor(IMarshallingInformation marshallingI case UnmanagedType.IUnknown: if (marshallingInformation.IidParameterIndex >= 0) { - writer.WriteCompressedInteger((uint)marshallingInformation.IidParameterIndex); + writer.WriteCompressedInteger(marshallingInformation.IidParameterIndex); } break; @@ -5004,287 +3473,238 @@ private void SerializePermissionSet(IEnumerable permissionSet, } writer.WriteSerializedString(typeName); - var customAttributeWriter = PooledBlobBuilder.GetInstance(); - this.SerializeCustomAttributeSignature(customAttribute, true, customAttributeWriter); - writer.WriteCompressedInteger((uint)customAttributeWriter.Count); - customAttributeWriter.WriteContentTo(writer); - customAttributeWriter.Free(); + + var customAttributeArgsBuilder = PooledBlobBuilder.GetInstance(); + var namedArgsEncoder = new BlobEncoder(customAttributeArgsBuilder).PermissionSetArguments(customAttribute.NamedArgumentCount); + SerializeCustomAttributeNamedArguments(namedArgsEncoder, customAttribute); + writer.WriteCompressedInteger(customAttributeArgsBuilder.Count); + + customAttributeArgsBuilder.WriteContentTo(writer); + customAttributeArgsBuilder.Free(); } // TODO: xml for older platforms } - private void SerializeSignature(ISignature signature, ushort genericParameterCount, ImmutableArray extraArgumentTypes, BlobBuilder writer) + private void SerializeReturnValueAndParameters(MethodSignatureEncoder encoder, ISignature signature, ImmutableArray varargParameters) { - byte header = (byte)signature.CallingConvention; - if (signature is IPropertyDefinition) + var declaredParameters = signature.GetParameters(Context); + var returnType = signature.GetType(Context); + + ReturnTypeEncoder returnTypeEncoder; + ParametersEncoder parametersEncoder; + + encoder.Parameters(declaredParameters.Length + varargParameters.Length, out returnTypeEncoder, out parametersEncoder); + if (signature.ReturnValueCustomModifiers.Length > 0) { - header |= 0x08; + SerializeCustomModifiers(returnTypeEncoder.CustomModifiers(), signature.ReturnValueCustomModifiers); } - writer.WriteByte(header); - if (genericParameterCount > 0) + if (module.IsPlatformType(returnType, PlatformType.SystemTypedReference)) { - writer.WriteCompressedInteger(genericParameterCount); + returnTypeEncoder.TypedReference(); } - - var @params = signature.GetParameters(Context); - uint numberOfRequiredParameters = (uint)@params.Length; - uint numberOfOptionalParameters = (uint)extraArgumentTypes.Length; - writer.WriteCompressedInteger(numberOfRequiredParameters + numberOfOptionalParameters); - - foreach (ICustomModifier customModifier in signature.ReturnValueCustomModifiers) + else if (module.IsPlatformType(returnType, PlatformType.SystemVoid)) { - this.SerializeCustomModifier(customModifier, writer); + returnTypeEncoder.Void(); } - - if (signature.ReturnValueIsByRef) + else { - writer.WriteByte(0x10); + SerializeTypeReference(returnTypeEncoder.Type(signature.ReturnValueIsByRef), returnType); } - this.SerializeTypeReference(signature.GetType(Context), writer, false, true); - foreach (IParameterTypeInformation parameterTypeInformation in @params) + foreach (IParameterTypeInformation parameter in declaredParameters) { - this.SerializeParameterInformation(parameterTypeInformation, writer); + SerializeParameterInformation(parametersEncoder.AddParameter(), parameter); } - if (numberOfOptionalParameters > 0) + if (varargParameters.Length > 0) { - writer.WriteByte(0x41); - foreach (IParameterTypeInformation extraArgumentTypeInformation in extraArgumentTypes) + parametersEncoder = parametersEncoder.StartVarArgs(); + foreach (IParameterTypeInformation parameter in varargParameters) { - this.SerializeParameterInformation(extraArgumentTypeInformation, writer); + SerializeParameterInformation(parametersEncoder.AddParameter(), parameter); } } + + parametersEncoder.EndParameters(); } - private void SerializeTypeReference(ITypeReference typeReference, BlobBuilder writer, bool noTokens, bool treatRefAsPotentialTypeSpec) + private void SerializeTypeReference(SignatureTypeEncoder encoder, ITypeReference typeReference) { while (true) { + // BYREF is specified directly in RetType, Param, LocalVarSig signatures + Debug.Assert(!(typeReference is IManagedPointerTypeReference)); + + // TYPEDREF is only allowed in RetType, Param, LocalVarSig signatures + Debug.Assert(!module.IsPlatformType(typeReference, PlatformType.SystemTypedReference)); + var modifiedTypeReference = typeReference as IModifiedTypeReference; if (modifiedTypeReference != null) { - foreach (ICustomModifier customModifier in modifiedTypeReference.CustomModifiers) - { - this.SerializeCustomModifier(customModifier, writer); - } - + SerializeCustomModifiers(encoder.CustomModifiers(), modifiedTypeReference.CustomModifiers); typeReference = modifiedTypeReference.UnmodifiedType; + continue; } - switch (typeReference.TypeCode(Context)) - { - case PrimitiveTypeCode.Void: - writer.WriteByte(0x01); - return; - case PrimitiveTypeCode.Boolean: - writer.WriteByte(0x02); - return; - case PrimitiveTypeCode.Char: - writer.WriteByte(0x03); - return; - case PrimitiveTypeCode.Int8: - writer.WriteByte(0x04); - return; - case PrimitiveTypeCode.UInt8: - writer.WriteByte(0x05); - return; - case PrimitiveTypeCode.Int16: - writer.WriteByte(0x06); - return; - case PrimitiveTypeCode.UInt16: - writer.WriteByte(0x07); - return; - case PrimitiveTypeCode.Int32: - writer.WriteByte(0x08); - return; - case PrimitiveTypeCode.UInt32: - writer.WriteByte(0x09); - return; - case PrimitiveTypeCode.Int64: - writer.WriteByte(0x0a); - return; - case PrimitiveTypeCode.UInt64: - writer.WriteByte(0x0b); - return; - case PrimitiveTypeCode.Float32: - writer.WriteByte(0x0c); - return; - case PrimitiveTypeCode.Float64: - writer.WriteByte(0x0d); - return; - case PrimitiveTypeCode.String: - writer.WriteByte(0x0e); - return; - case PrimitiveTypeCode.Pointer: - var pointerTypeReference = typeReference as IPointerTypeReference; - if (pointerTypeReference != null) - { - if (noTokens) - { - this.SerializeTypeName(pointerTypeReference, writer); - return; - } - - writer.WriteByte(0x0f); - typeReference = pointerTypeReference.GetTargetType(Context); - treatRefAsPotentialTypeSpec = true; - continue; - } - - break; - case PrimitiveTypeCode.Reference: - var managedPointerTypeReference = typeReference as IManagedPointerTypeReference; - if (managedPointerTypeReference != null) - { - if (noTokens) - { - this.SerializeTypeName(managedPointerTypeReference, writer); - return; - } - - writer.WriteByte(0x10); - typeReference = managedPointerTypeReference.GetTargetType(Context); - treatRefAsPotentialTypeSpec = true; - continue; - } - - break; - case PrimitiveTypeCode.IntPtr: - writer.WriteByte(0x18); - return; - case PrimitiveTypeCode.UIntPtr: - writer.WriteByte(0x19); - return; - } - - - IGenericTypeParameterReference genericTypeParameterReference = typeReference.AsGenericTypeParameterReference; - if (genericTypeParameterReference != null) + var primitiveType = typeReference.TypeCode(Context); + if (primitiveType != PrimitiveTypeCode.Pointer && primitiveType != PrimitiveTypeCode.NotPrimitive) { - writer.WriteByte(0x13); - uint numberOfInheritedParameters = GetNumberOfInheritedTypeParameters(genericTypeParameterReference.DefiningType); - writer.WriteCompressedInteger(numberOfInheritedParameters + genericTypeParameterReference.Index); + encoder.PrimitiveType(primitiveType); return; } - var arrayTypeReference = typeReference as IArrayTypeReference; - if (arrayTypeReference?.IsSZArray == false) + var pointerTypeReference = typeReference as IPointerTypeReference; + if (pointerTypeReference != null) { - Debug.Assert(noTokens == false, "Custom attributes cannot have multi-dimensional arrays"); - - writer.WriteByte(0x14); - this.SerializeTypeReference(arrayTypeReference.GetElementType(Context), writer, false, true); - writer.WriteCompressedInteger(arrayTypeReference.Rank); - writer.WriteCompressedInteger(IteratorHelper.EnumerableCount(arrayTypeReference.Sizes)); - foreach (ulong size in arrayTypeReference.Sizes) + typeReference = pointerTypeReference.GetTargetType(Context); + if (module.IsPlatformType(typeReference, PlatformType.SystemVoid)) { - writer.WriteCompressedInteger((uint)size); + encoder.VoidPointer(); + return; } - - writer.WriteCompressedInteger(IteratorHelper.EnumerableCount(arrayTypeReference.LowerBounds)); - foreach (int lowerBound in arrayTypeReference.LowerBounds) + else { - writer.WriteCompressedSignedInteger(lowerBound); + encoder = encoder.Pointer(); + continue; } - - return; } - if (module.IsPlatformType(typeReference, PlatformType.SystemTypedReference)) + IGenericTypeParameterReference genericTypeParameterReference = typeReference.AsGenericTypeParameterReference; + if (genericTypeParameterReference != null) { - writer.WriteByte(0x16); + encoder.GenericTypeParameter( + GetNumberOfInheritedTypeParameters(genericTypeParameterReference.DefiningType) + + genericTypeParameterReference.Index); return; } - if (module.IsPlatformType(typeReference, PlatformType.SystemObject)) + var arrayTypeReference = typeReference as IArrayTypeReference; + if (arrayTypeReference != null) { - if (noTokens) + typeReference = arrayTypeReference.GetElementType(Context); + + if (arrayTypeReference.IsSZArray) { - writer.WriteByte(0x51); + encoder = encoder.SZArray(); + continue; } else { - writer.WriteByte(0x1c); + SignatureTypeEncoder elementType; + ArrayShapeEncoder arrayShape; + encoder.Array(out elementType, out arrayShape); + SerializeTypeReference(elementType, typeReference); + arrayShape.Shape(arrayTypeReference.Rank, arrayTypeReference.Sizes, arrayTypeReference.LowerBounds); + return; } - - return; } - if (arrayTypeReference != null && arrayTypeReference.IsSZArray) + if (module.IsPlatformType(typeReference, PlatformType.SystemObject)) { - writer.WriteByte(0x1d); - typeReference = arrayTypeReference.GetElementType(Context); - treatRefAsPotentialTypeSpec = true; - continue; + encoder.Object(); + return; } IGenericMethodParameterReference genericMethodParameterReference = typeReference.AsGenericMethodParameterReference; if (genericMethodParameterReference != null) { - writer.WriteByte(0x1e); - writer.WriteCompressedInteger(genericMethodParameterReference.Index); + encoder.GenericMethodTypeParameter(genericMethodParameterReference.Index); return; } - if (!noTokens && typeReference.IsTypeSpecification() && treatRefAsPotentialTypeSpec) + if (typeReference.IsTypeSpecification()) { ITypeReference uninstantiatedTypeReference = typeReference.GetUninstantiatedGenericType(); // Roslyn's uninstantiated type is the same object as the instantiated type for // types closed over their type parameters, so to speak. - writer.WriteByte(0x15); - this.SerializeTypeReference(uninstantiatedTypeReference, writer, false, false); var consolidatedTypeArguments = ArrayBuilder.GetInstance(); typeReference.GetConsolidatedTypeArguments(consolidatedTypeArguments, this.Context); - writer.WriteCompressedInteger((uint)consolidatedTypeArguments.Count); + + var genericArgsEncoder = encoder.GenericInstantiation( + typeReference.IsValueType, + GetTypeHandle(uninstantiatedTypeReference, treatRefAsPotentialTypeSpec: false), + consolidatedTypeArguments.Count); + foreach (ITypeReference typeArgument in consolidatedTypeArguments) { - this.SerializeTypeReference(typeArgument, writer, false, true); + SerializeTypeReference(genericArgsEncoder.AddArgument(), typeArgument); } consolidatedTypeArguments.Free(); - + genericArgsEncoder.EndArguments(); return; } - if (noTokens) - { - if (this.module.IsPlatformType(typeReference, PlatformType.SystemType)) - { - writer.WriteByte(0x50); - } - else if (!typeReference.IsEnum) - { - writer.WriteByte(0x51); - } - else - { - writer.WriteByte(0x55); - this.SerializeTypeName(typeReference, writer); - } - } - else - { - if (typeReference.IsValueType) - { - writer.WriteByte(0x11); - } - else - { - writer.WriteByte(0x12); - } + encoder.TypeDefOrRefOrSpec(typeReference.IsValueType, GetTypeHandle(typeReference)); + return; + } + } - writer.WriteCompressedInteger(this.GetTypeDefOrRefCodedIndex(typeReference, treatRefAsPotentialTypeSpec)); - } + private void SerializeCustomAttributeArrayType(CustomAttributeArrayTypeEncoder encoder, IArrayTypeReference arrayTypeReference) + { + // A single-dimensional, zero-based array is specified as a single byte 0x1D followed by the FieldOrPropType of the element type. - return; + // only non-jagged SZ arrays are allowed in attributes + // (need to encode the type of the SZ array if the parameter type is Object): + Debug.Assert(arrayTypeReference.IsSZArray); + + var elementType = arrayTypeReference.GetElementType(Context); + Debug.Assert(!(elementType is IModifiedTypeReference)); + + if (module.IsPlatformType(elementType, PlatformType.SystemObject)) + { + encoder.ObjectArray(); + } + else + { + SerializeCustomAttributeElementType(encoder.ElementType(), elementType); + } + } + + private void SerializeCustomAttributeElementType(CustomAttributeElementTypeEncoder encoder, ITypeReference typeReference) + { + // Spec: + // The FieldOrPropType shall be exactly one of: + // ELEMENT_TYPE_BOOLEAN, ELEMENT_TYPE_CHAR, ELEMENT_TYPE_I1, ELEMENT_TYPE_U1, ELEMENT_TYPE_I2, ELEMENT_TYPE_U2, ELEMENT_TYPE_I4, + // ELEMENT_TYPE_U4, ELEMENT_TYPE_I8, ELEMENT_TYPE_U8, ELEMENT_TYPE_R4, ELEMENT_TYPE_R8, ELEMENT_TYPE_STRING. + // An enum is specified as a single byte 0x55 followed by a SerString. + + var primitiveType = typeReference.TypeCode(Context); + if (primitiveType != PrimitiveTypeCode.NotPrimitive) + { + encoder.PrimitiveType(primitiveType); + } + else if (module.IsPlatformType(typeReference, PlatformType.SystemType)) + { + encoder.SystemType(); + } + else + { + Debug.Assert(typeReference.IsEnum); + encoder.Enum(typeReference.GetSerializedTypeName(this.Context)); + } + } + + private void SerializeCustomModifiers(CustomModifiersEncoder encoder, ImmutableArray modifiers) + { + SerializeCustomModifiers(encoder, modifiers, 0, modifiers.Length); + } + + private void SerializeCustomModifiers(CustomModifiersEncoder encoder, ImmutableArray modifiers, int start, int count) + { + for (int i = 0; i < count; i++) + { + var modifier = modifiers[start + i]; + encoder = encoder.AddModifier(modifier.IsOptional, GetTypeHandle(modifier.GetModifier(Context))); } + + encoder.EndModifiers(); } - private uint GetNumberOfInheritedTypeParameters(ITypeReference type) + private int GetNumberOfInheritedTypeParameters(ITypeReference type) { INestedTypeReference nestedType = type.AsNestedTypeReference; if (nestedType == null) @@ -5298,7 +3718,7 @@ private uint GetNumberOfInheritedTypeParameters(ITypeReference type) nestedType = specializedNestedType.UnspecializedVersion; } - uint result = 0; + int result = 0; type = nestedType.GetContainingType(Context); nestedType = type.AsNestedTypeReference; while (nestedType != null) @@ -5351,16 +3771,6 @@ internal static ImmutableArray GetLocalSlotDebugInfos(Immuta return locals.SelectAsArray(variable => variable.SlotInfo); } - protected static uint RowOnly(uint token) - { - return token & 0xFFFFFF; - } - - protected static uint TypeOnly(uint token) - { - return token & 0xFF000000; - } - protected abstract class HeapOrReferenceIndexBase { private readonly MetadataWriter _writer; diff --git a/src/Compilers/Core/Portable/PEWriter/MethodSpecComparer.cs b/src/Compilers/Core/Portable/PEWriter/MethodSpecComparer.cs index 77ee82370d85f..7705512c433cd 100644 --- a/src/Compilers/Core/Portable/PEWriter/MethodSpecComparer.cs +++ b/src/Compilers/Core/Portable/PEWriter/MethodSpecComparer.cs @@ -22,15 +22,15 @@ public bool Equals(IGenericMethodInstanceReference x, IGenericMethodInstanceRefe } return - _metadataWriter.GetMethodDefOrRefCodedIndex(x.GetGenericMethod(_metadataWriter.Context)) == _metadataWriter.GetMethodDefOrRefCodedIndex(y.GetGenericMethod(_metadataWriter.Context)) && - _metadataWriter.GetMethodInstanceSignatureIndex(x) == _metadataWriter.GetMethodInstanceSignatureIndex(y); + _metadataWriter.GetMethodDefinitionOrReferenceHandle(x.GetGenericMethod(_metadataWriter.Context)) == _metadataWriter.GetMethodDefinitionOrReferenceHandle(y.GetGenericMethod(_metadataWriter.Context)) && + _metadataWriter.GetMethodSpecificationSignatureHandle(x) == _metadataWriter.GetMethodSpecificationSignatureHandle(y); } public int GetHashCode(IGenericMethodInstanceReference methodInstanceReference) { return Hash.Combine( - (int)_metadataWriter.GetMethodDefOrRefCodedIndex(methodInstanceReference.GetGenericMethod(_metadataWriter.Context)), - _metadataWriter.GetMethodInstanceSignatureIndex(methodInstanceReference).GetHashCode()); + _metadataWriter.GetMethodDefinitionOrReferenceHandle(methodInstanceReference.GetGenericMethod(_metadataWriter.Context)).GetHashCode(), + _metadataWriter.GetMethodSpecificationSignatureHandle(methodInstanceReference).GetHashCode()); } } } diff --git a/src/Compilers/Core/Portable/PEWriter/Miscellaneous.cs b/src/Compilers/Core/Portable/PEWriter/Miscellaneous.cs index 17b243ee06c95..8aa768df8f9d5 100644 --- a/src/Compilers/Core/Portable/PEWriter/Miscellaneous.cs +++ b/src/Compilers/Core/Portable/PEWriter/Miscellaneous.cs @@ -211,43 +211,6 @@ internal interface IParameterListEntry ushort Index { get; } } - /// - /// This enum is used internally by BCL. It includes flags that are not in the metadata spec. - /// - [Flags] - internal enum PInvokeAttributes : ushort - { - NoMangle = 0x0001, - - CharSetMask = 0x0006, - CharSetNotSpec = 0x0000, - CharSetAnsi = 0x0002, - CharSetUnicode = 0x0004, - CharSetAuto = 0x0006, - - - BestFitUseAssem = 0x0000, - BestFitEnabled = 0x0010, - BestFitDisabled = 0x0020, - BestFitMask = 0x0030, - - ThrowOnUnmappableCharUseAssem = 0x0000, - ThrowOnUnmappableCharEnabled = 0x1000, - ThrowOnUnmappableCharDisabled = 0x2000, - ThrowOnUnmappableCharMask = 0x3000, - - SupportsLastError = 0x0040, - - CallConvMask = 0x0700, - CallConvWinapi = 0x0100, - CallConvCdecl = 0x0200, - CallConvStdcall = 0x0300, - CallConvThiscall = 0x0400, - CallConvFastcall = 0x0500, - - MaxValue = 0xFFFF, - } - /// /// Information that describes how a method from the underlying Platform is to be invoked. /// @@ -266,7 +229,7 @@ internal interface IPlatformInvokeInformation /// /// Flags that determine marshalling behavior. /// - PInvokeAttributes Flags { get; } + MethodImportAttributes Flags { get; } } internal class ResourceSection diff --git a/src/Compilers/Core/Portable/PEWriter/NativeResourceWriter.cs b/src/Compilers/Core/Portable/PEWriter/NativeResourceWriter.cs new file mode 100644 index 0000000000000..f845f86f2dde8 --- /dev/null +++ b/src/Compilers/Core/Portable/PEWriter/NativeResourceWriter.cs @@ -0,0 +1,368 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using Roslyn.Utilities; + +namespace Microsoft.Cci +{ + using Roslyn.Reflection; + + internal static class NativeResourceWriter + { + //// + //// Resource Format. + //// + + //// + //// Resource directory consists of two counts, following by a variable length + //// array of directory entries. The first count is the number of entries at + //// beginning of the array that have actual names associated with each entry. + //// The entries are in ascending order, case insensitive strings. The second + //// count is the number of entries that immediately follow the named entries. + //// This second count identifies the number of entries that have 16-bit integer + //// Ids as their name. These entries are also sorted in ascending order. + //// + //// This structure allows fast lookup by either name or number, but for any + //// given resource entry only one form of lookup is supported, not both. + //// This is consistent with the syntax of the .RC file and the .RES file. + //// + + //typedef struct _IMAGE_RESOURCE_DIRECTORY { + // DWORD Characteristics; + // DWORD TimeDateStamp; + // WORD MajorVersion; + // WORD MinorVersion; + // WORD NumberOfNamedEntries; + // WORD NumberOfIdEntries; + //// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; + //} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; + + //#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 + //#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 + //// + //// Each directory contains the 32-bit Name of the entry and an offset, + //// relative to the beginning of the resource directory of the data associated + //// with this directory entry. If the name of the entry is an actual text + //// string instead of an integer Id, then the high order bit of the name field + //// is set to one and the low order 31-bits are an offset, relative to the + //// beginning of the resource directory of the string, which is of type + //// IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the + //// low-order 16-bits are the integer Id that identify this resource directory + //// entry. If the directory entry is yet another resource directory (i.e. a + //// subdirectory), then the high order bit of the offset field will be + //// set to indicate this. Otherwise the high bit is clear and the offset + //// field points to a resource data entry. + //// + + //typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { + // union { + // struct { + // DWORD NameOffset:31; + // DWORD NameIsString:1; + // } DUMMYSTRUCTNAME; + // DWORD Name; + // WORD Id; + // } DUMMYUNIONNAME; + // union { + // DWORD OffsetToData; + // struct { + // DWORD OffsetToDirectory:31; + // DWORD DataIsDirectory:1; + // } DUMMYSTRUCTNAME2; + // } DUMMYUNIONNAME2; + //} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; + + //// + //// For resource directory entries that have actual string names, the Name + //// field of the directory entry points to an object of the following type. + //// All of these string objects are stored together after the last resource + //// directory entry and before the first resource data object. This minimizes + //// the impact of these variable length objects on the alignment of the fixed + //// size directory entry objects. + //// + + //typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { + // WORD Length; + // CHAR NameString[ 1 ]; + //} IMAGE_RESOURCE_DIRECTORY_STRING, *PIMAGE_RESOURCE_DIRECTORY_STRING; + + + //typedef struct _IMAGE_RESOURCE_DIR_STRING_U { + // WORD Length; + // WCHAR NameString[ 1 ]; + //} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U; + + + //// + //// Each resource data entry describes a leaf node in the resource directory + //// tree. It contains an offset, relative to the beginning of the resource + //// directory of the data for the resource, a size field that gives the number + //// of bytes of data at that offset, a CodePage that should be used when + //// decoding code point values within the resource data. Typically for new + //// applications the code page would be the unicode code page. + //// + + //typedef struct _IMAGE_RESOURCE_DATA_ENTRY { + // DWORD OffsetToData; + // DWORD Size; + // DWORD CodePage; + // DWORD Reserved; + //} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; + + private class Directory + { + internal readonly string Name; + internal readonly int ID; + internal ushort NumberOfNamedEntries; + internal ushort NumberOfIdEntries; + internal readonly List Entries; + + internal Directory(string name, int id) + { + this.Name = name; + this.ID = id; + this.Entries = new List(); + } + } + + private static int CompareResources(IWin32Resource left, IWin32Resource right) + { + int result = CompareResourceIdentifiers(left.TypeId, left.TypeName, right.TypeId, right.TypeName); + + return (result == 0) ? CompareResourceIdentifiers(left.Id, left.Name, right.Id, right.Name) : result; + } + + //when comparing a string vs ordinal, the string should always be less than the ordinal. Per the spec, + //entries identified by string must precede those identified by ordinal. + private static int CompareResourceIdentifiers(int xOrdinal, string xString, int yOrdinal, string yString) + { + if (xString == null) + { + if (yString == null) + { + return xOrdinal - yOrdinal; + } + else + { + return 1; + } + } + else if (yString == null) + { + return -1; + } + else + { + return String.Compare(xString, yString, StringComparison.OrdinalIgnoreCase); + } + } + + //sort the resources by ID least to greatest then by NAME. + //Where strings and ordinals are compared, strings are less than ordinals. + internal static IEnumerable SortResources(IEnumerable resources) + { + return resources.OrderBy(CompareResources); + } + + public static void SerializeWin32Resources(BlobBuilder builder, IEnumerable theResources, int resourcesRva) + { + theResources = SortResources(theResources); + + Directory typeDirectory = new Directory(string.Empty, 0); + Directory nameDirectory = null; + Directory languageDirectory = null; + int lastTypeID = int.MinValue; + string lastTypeName = null; + int lastID = int.MinValue; + string lastName = null; + uint sizeOfDirectoryTree = 16; + + //EDMAURER note that this list is assumed to be sorted lowest to highest + //first by typeId, then by Id. + foreach (IWin32Resource r in theResources) + { + bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID; + if (typeDifferent) + { + lastTypeID = r.TypeId; + lastTypeName = r.TypeName; + if (lastTypeID < 0) + { + Debug.Assert(typeDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with types encoded as strings precede those encoded as ints"); + typeDirectory.NumberOfNamedEntries++; + } + else + { + typeDirectory.NumberOfIdEntries++; + } + + sizeOfDirectoryTree += 24; + typeDirectory.Entries.Add(nameDirectory = new Directory(lastTypeName, lastTypeID)); + } + + if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID) + { + lastID = r.Id; + lastName = r.Name; + if (lastID < 0) + { + Debug.Assert(nameDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with names encoded as strings precede those encoded as ints"); + nameDirectory.NumberOfNamedEntries++; + } + else + { + nameDirectory.NumberOfIdEntries++; + } + + sizeOfDirectoryTree += 24; + nameDirectory.Entries.Add(languageDirectory = new Directory(lastName, lastID)); + } + + languageDirectory.NumberOfIdEntries++; + sizeOfDirectoryTree += 8; + languageDirectory.Entries.Add(r); + } + + var dataWriter = new BlobBuilder(); + + //'dataWriter' is where opaque resource data goes as well as strings that are used as type or name identifiers + WriteDirectory(typeDirectory, builder, 0, 0, sizeOfDirectoryTree, resourcesRva, dataWriter); + builder.LinkSuffix(dataWriter); + builder.WriteByte(0); + builder.Align(4); + } + + private static void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) + { + writer.WriteUInt32(0); // Characteristics + writer.WriteUInt32(0); // Timestamp + writer.WriteUInt32(0); // Version + writer.WriteUInt16(directory.NumberOfNamedEntries); + writer.WriteUInt16(directory.NumberOfIdEntries); + uint n = (uint)directory.Entries.Count; + uint k = offset + 16 + n * 8; + for (int i = 0; i < n; i++) + { + int id; + string name; + uint nameOffset = (uint)dataWriter.Position + sizeOfDirectoryTree; + uint directoryOffset = k; + Directory subDir = directory.Entries[i] as Directory; + if (subDir != null) + { + id = subDir.ID; + name = subDir.Name; + if (level == 0) + { + k += SizeOfDirectory(subDir); + } + else + { + k += 16 + 8 * (uint)subDir.Entries.Count; + } + } + else + { + //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed + //immediately by the data that it refers to. This results + //in a layout different than that produced by pulling the resources + //from an OBJ. In that case all of the data bits of a resource are + //contiguous in .rsrc$02. After processing these will end up at + //the end of .rsrc following all of the directory + //info and IMAGE_RESOURCE_DATA_ENTRYs + IWin32Resource r = (IWin32Resource)directory.Entries[i]; + id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId; + name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; + dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Position)); + byte[] data = new List(r.Data).ToArray(); + dataWriter.WriteUInt32((uint)data.Length); + dataWriter.WriteUInt32(r.CodePage); + dataWriter.WriteUInt32(0); + dataWriter.WriteBytes(data); + while ((dataWriter.Count % 4) != 0) + { + dataWriter.WriteByte(0); + } + } + + if (id >= 0) + { + writer.WriteInt32(id); + } + else + { + if (name == null) + { + name = string.Empty; + } + + writer.WriteUInt32(nameOffset | 0x80000000); + dataWriter.WriteUInt16((ushort)name.Length); + dataWriter.WriteUTF16(name); + } + + if (subDir != null) + { + writer.WriteUInt32(directoryOffset | 0x80000000); + } + else + { + writer.WriteUInt32(nameOffset); + } + } + + k = offset + 16 + n * 8; + for (int i = 0; i < n; i++) + { + Directory subDir = directory.Entries[i] as Directory; + if (subDir != null) + { + WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter); + if (level == 0) + { + k += SizeOfDirectory(subDir); + } + else + { + k += 16 + 8 * (uint)subDir.Entries.Count; + } + } + } + } + + private static uint SizeOfDirectory(Directory/*!*/ directory) + { + uint n = (uint)directory.Entries.Count; + uint size = 16 + 8 * n; + for (int i = 0; i < n; i++) + { + Directory subDir = directory.Entries[i] as Directory; + if (subDir != null) + { + size += 16 + 8 * (uint)subDir.Entries.Count; + } + } + + return size; + } + + public static void SerializeWin32Resources(BlobBuilder builder, ResourceSection resourceSections, int resourcesRva) + { + var sectionWriter = new BlobWriter(builder.ReserveBytes(resourceSections.SectionBytes.Length)); + sectionWriter.WriteBytes(resourceSections.SectionBytes); + + var readStream = new MemoryStream(resourceSections.SectionBytes); + var reader = new BinaryReader(readStream); + + foreach (int addressToFixup in resourceSections.Relocations) + { + sectionWriter.Offset = addressToFixup; + reader.BaseStream.Position = addressToFixup; + sectionWriter.WriteUInt32(reader.ReadUInt32() + (uint)resourcesRva); + } + } + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/NtHeader.cs b/src/Compilers/Core/Portable/PEWriter/NtHeader.cs deleted file mode 100644 index a573f1afb801d..0000000000000 --- a/src/Compilers/Core/Portable/PEWriter/NtHeader.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection.PortableExecutable; - -namespace Microsoft.Cci -{ - internal sealed class NtHeader - { - // standard fields - internal PEMagic Magic; - internal byte MajorLinkerVersion; - internal byte MinorLinkerVersion; - internal int SizeOfCode; - internal int SizeOfInitializedData; - internal int SizeOfUninitializedData; - internal int AddressOfEntryPoint; - internal int BaseOfCode; // this.sectionHeaders[0].virtualAddress - internal int BaseOfData; - - // Windows - - internal ulong ImageBase; - internal int SectionAlignment = 0x2000; - internal int FileAlignment; - - internal ushort MajorOperatingSystemVersion = 4; - internal ushort MinorOperatingSystemVersion = 0; - internal ushort MajorImageVersion = 0; - internal ushort MinorImageVersion = 0; - internal ushort MajorSubsystemVersion; - internal ushort MinorSubsystemVersion; - - internal int SizeOfImage; - internal int SizeOfHeaders; - internal uint Checksum = 0; - - internal Subsystem Subsystem; - internal DllCharacteristics DllCharacteristics; - - internal ulong SizeOfStackReserve; - internal ulong SizeOfStackCommit; - internal ulong SizeOfHeapReserve; - internal ulong SizeOfHeapCommit; - - internal DirectoryEntry ExportTable; - internal DirectoryEntry ImportTable; - internal DirectoryEntry ResourceTable; - internal DirectoryEntry ExceptionTable; - internal DirectoryEntry CertificateTable; - internal DirectoryEntry BaseRelocationTable; - internal DirectoryEntry DebugTable; - internal DirectoryEntry CopyrightTable; - internal DirectoryEntry GlobalPointerTable; - internal DirectoryEntry ThreadLocalStorageTable; - internal DirectoryEntry LoadConfigTable; - internal DirectoryEntry BoundImportTable; - internal DirectoryEntry ImportAddressTable; - internal DirectoryEntry DelayImportTable; - internal DirectoryEntry CliHeaderTable; - } -} diff --git a/src/Compilers/Core/Portable/PEWriter/PeWriter.cs b/src/Compilers/Core/Portable/PEWriter/PeWriter.cs index 902cd45ee6639..4729960257da9 100644 --- a/src/Compilers/Core/Portable/PEWriter/PeWriter.cs +++ b/src/Compilers/Core/Portable/PEWriter/PeWriter.cs @@ -1,21 +1,23 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; +using System.Collections.Immutable; using System.Diagnostics; using System.IO; -using System.Linq; +using System.Reflection; using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; using System.Reflection.PortableExecutable; -using System.Text; using System.Threading; using Microsoft.CodeAnalysis; -using Roslyn.Utilities; using EmitContext = Microsoft.CodeAnalysis.Emit.EmitContext; using Microsoft.CodeAnalysis.CodeGen; namespace Microsoft.Cci { + using Roslyn.Reflection; + using Roslyn.Reflection.PortableExecutable; + internal sealed class PeWritingException : Exception { public PeWritingException(Exception inner) @@ -23,58 +25,8 @@ public PeWritingException(Exception inner) { } } - internal sealed class PeWriter + internal static class PeWriter { - private const string ResourceSectionName = ".rsrc"; - private const string RelocationSectionName = ".reloc"; - - /// - /// Minimal size of PDB path in Debug Directory. We pad the path to this minimal size to - /// allow some tools to patch the path without the need to rewrite the entire image. - /// This is a workaround put in place until these tools are retired. - /// - private readonly int _minPdbPath; - - /// - /// True if we should attempt to generate a deterministic output (no timestamps or random data). - /// - private readonly bool _deterministic; - private readonly int _timeStamp; - - private readonly string _pdbPathOpt; - private readonly bool _is32bit; - private readonly ModulePropertiesForSerialization _properties; - - private readonly IEnumerable _nativeResourcesOpt; - private readonly ResourceSection _nativeResourceSectionOpt; - - private readonly BlobBuilder _win32ResourceWriter = new BlobBuilder(1024); - - private PeWriter( - ModulePropertiesForSerialization properties, - IEnumerable nativeResourcesOpt, - ResourceSection nativeResourceSectionOpt, - string pdbPathOpt, - bool deterministic) - { - _properties = properties; - _pdbPathOpt = pdbPathOpt; - _deterministic = deterministic; - - // The PDB padding workaround is only needed for legacy tools that don't use deterministic build. - _minPdbPath = deterministic ? 0 : 260; - _nativeResourcesOpt = nativeResourcesOpt; - _nativeResourceSectionOpt = nativeResourceSectionOpt; - _is32bit = !_properties.Requires64bits; - - // In the PE File Header this is a "Time/Date Stamp" whose description is "Time and date - // the file was created in seconds since January 1st 1970 00:00:00 or 0" - // However, when we want to make it deterministic we fill it in (later) with bits from the hash of the full PE file. - _timeStamp = _deterministic ? 0 : (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; - } - - private bool EmitPdb => _pdbPathOpt != null; - public static bool WritePeToStream( EmitContext context, CommonMessageProvider messageProvider, @@ -83,69 +35,44 @@ public static bool WritePeToStream( PdbWriter nativePdbWriterOpt, string pdbPathOpt, bool allowMissingMethodBodies, - bool deterministic, + bool isDeterministic, CancellationToken cancellationToken) { // If PDB writer is given, we have to have PDB path. Debug.Assert(nativePdbWriterOpt == null || pdbPathOpt != null); - try - { - var peWriter = new PeWriter(context.Module.Properties, context.Module.Win32Resources, context.Module.Win32ResourceSection, pdbPathOpt, deterministic); - var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, deterministic, getPortablePdbStreamOpt != null, cancellationToken); - return peWriter.WritePeToStream(mdWriter, getPeStream, getPortablePdbStreamOpt, nativePdbWriterOpt); - } - catch (Exception ex) when (!(ex is PdbWritingException || ex is ResourceException || ex is PermissionSetFileReadException || ex is OperationCanceledException)) - { - throw new PeWritingException(ex); - } - } + var mdWriter = FullMetadataWriter.Create(context, messageProvider, allowMissingMethodBodies, isDeterministic, getPortablePdbStreamOpt != null, cancellationToken); - private bool WritePeToStream(MetadataWriter mdWriter, Func getPeStream, Func getPortablePdbStreamOpt, PdbWriter nativePdbWriterOpt) - { - // TODO: we can precalculate the exact size of IL stream - var ilWriter = new BlobBuilder(32 * 1024); - var metadataWriter = new BlobBuilder(16 * 1024); - var mappedFieldDataWriter = new BlobBuilder(); - var managedResourceWriter = new BlobBuilder(1024); - - var debugMetadataWriterOpt = (getPortablePdbStreamOpt != null) ? new BlobBuilder(16 * 1024) : null; + var properties = context.Module.Properties; nativePdbWriterOpt?.SetMetadataEmitter(mdWriter); // Since we are producing a full assembly, we should not have a module version ID // imposed ahead-of time. Instead we will compute a deterministic module version ID // based on the contents of the generated stream. - Debug.Assert(_properties.PersistentIdentifier == default(Guid)); - - int sectionCount = 1; - if (_properties.RequiresStartupStub) sectionCount++; //.reloc - if (!IteratorHelper.EnumerableIsEmpty(_nativeResourcesOpt) || _nativeResourceSectionOpt != null) sectionCount++; //.rsrc; - - int sizeOfPeHeaders = ComputeSizeOfPeHeaders(sectionCount); - int textSectionRva = BitArithmeticUtilities.Align(sizeOfPeHeaders, _properties.SectionAlignment); + Debug.Assert(properties.PersistentIdentifier == default(Guid)); - int moduleVersionIdOffsetInMetadataStream; - int methodBodyStreamRva = textSectionRva + OffsetToILStream; - int pdbIdOffsetInPortablePdbStream; + var ilBuilder = new BlobBuilder(32 * 1024); + var mappedFieldDataBuilder = new BlobBuilder(); + var managedResourceBuilder = new BlobBuilder(1024); - int entryPointToken; - MetadataSizes metadataSizes; - mdWriter.SerializeMetadataAndIL( - metadataWriter, - debugMetadataWriterOpt, + Blob mvidFixup; + mdWriter.BuildMetadataAndIL( nativePdbWriterOpt, - ilWriter, - mappedFieldDataWriter, - managedResourceWriter, - methodBodyStreamRva, - mdSizes => CalculateMappedFieldDataStreamRva(textSectionRva, mdSizes), - out moduleVersionIdOffsetInMetadataStream, - out pdbIdOffsetInPortablePdbStream, - out entryPointToken, - out metadataSizes); + ilBuilder, + mappedFieldDataBuilder, + managedResourceBuilder, + out mvidFixup); + + MethodDefinitionHandle entryPointHandle; + MethodDefinitionHandle debugEntryPointHandle; + mdWriter.GetEntryPoints(out entryPointHandle, out debugEntryPointHandle); + + if (!debugEntryPointHandle.IsNil) + { + nativePdbWriterOpt?.SetEntryPoint((uint)MetadataTokens.GetToken(debugEntryPointHandle)); + } - ContentId nativePdbContentId; if (nativePdbWriterOpt != null) { var assembly = mdWriter.Module.AsAssembly; @@ -163,1373 +90,156 @@ private bool WritePeToStream(MetadataWriter mdWriter, Func getPeStream, nativePdbWriterOpt.AssertAllDefinitionsHaveTokens(mdWriter.Module.GetSymbolToLocationMap()); #endif } - - nativePdbContentId = nativePdbWriterOpt.GetContentId(); - - // the writer shall not be used after this point for writing: - nativePdbWriterOpt = null; - } - else - { - nativePdbContentId = default(ContentId); - } - - // write to Portable PDB stream: - ContentId portablePdbContentId; - Stream portablePdbStream = getPortablePdbStreamOpt?.Invoke(); - if (portablePdbStream != null) - { - debugMetadataWriterOpt.WriteContentTo(portablePdbStream); - - if (_deterministic) - { - portablePdbContentId = ContentId.FromHash(CryptographicHashProvider.ComputeSha1(portablePdbStream)); - } - else - { - portablePdbContentId = new ContentId(Guid.NewGuid().ToByteArray(), BitConverter.GetBytes(_timeStamp)); - } - - // fill in the PDB id: - long previousPosition = portablePdbStream.Position; - CheckZeroDataInStream(portablePdbStream, pdbIdOffsetInPortablePdbStream, ContentId.Size); - portablePdbStream.Position = pdbIdOffsetInPortablePdbStream; - portablePdbStream.Write(portablePdbContentId.Guid, 0, portablePdbContentId.Guid.Length); - portablePdbStream.Write(portablePdbContentId.Stamp, 0, portablePdbContentId.Stamp.Length); - portablePdbStream.Position = previousPosition; - } - else - { - portablePdbContentId = default(ContentId); - } - - // Only the size of the fixed part of the debug table goes here. - DirectoryEntry debugDirectory = default(DirectoryEntry); - DirectoryEntry importTable = default(DirectoryEntry); - DirectoryEntry importAddressTable = default(DirectoryEntry); - int entryPointAddress = 0; - - if (EmitPdb || _deterministic) - { - debugDirectory = new DirectoryEntry(textSectionRva + ComputeOffsetToDebugTable(metadataSizes), ImageDebugDirectoryBaseSize); - } - - if (_properties.RequiresStartupStub) - { - importAddressTable = new DirectoryEntry(textSectionRva, SizeOfImportAddressTable); - entryPointAddress = CalculateMappedFieldDataStreamRva(textSectionRva, metadataSizes) - (_is32bit ? 6 : 10); // TODO: constants - importTable = new DirectoryEntry(textSectionRva + ComputeOffsetToImportTable(metadataSizes), (_is32bit ? 66 : 70) + 13); // TODO: constants } - var corHeaderDirectory = new DirectoryEntry(textSectionRva + SizeOfImportAddressTable, size: CorHeaderSize); - - long ntHeaderTimestampPosition; - long metadataPosition; - - List sectionHeaders = CreateSectionHeaders(metadataSizes, sectionCount); - - CoffHeader coffHeader; - NtHeader ntHeader; - FillInNtHeader(sectionHeaders, entryPointAddress, corHeaderDirectory, importTable, importAddressTable, debugDirectory, out coffHeader, out ntHeader); - Stream peStream = getPeStream(); if (peStream == null) { return false; } - WriteHeaders(peStream, ntHeader, coffHeader, sectionHeaders, out ntHeaderTimestampPosition); - - WriteTextSection( - peStream, - sectionHeaders[0], - importTable.RelativeVirtualAddress, - importAddressTable.RelativeVirtualAddress, - entryPointToken, - metadataWriter, - ilWriter, - mappedFieldDataWriter, - managedResourceWriter, - metadataSizes, - nativePdbContentId, - portablePdbContentId, - out metadataPosition); - - var resourceSection = sectionHeaders.FirstOrDefault(s => s.Name == ResourceSectionName); - if (resourceSection != null) - { - WriteResourceSection(peStream, resourceSection); - } - - var relocSection = sectionHeaders.FirstOrDefault(s => s.Name == RelocationSectionName); - if (relocSection != null) - { - WriteRelocSection(peStream, relocSection, entryPointAddress); - } - - if (_deterministic) - { - var mvidPosition = metadataPosition + moduleVersionIdOffsetInMetadataStream; - WriteDeterministicGuidAndTimestamps(peStream, mvidPosition, ntHeaderTimestampPosition); - } - - return true; - } - - private List CreateSectionHeaders(MetadataSizes metadataSizes, int sectionCount) - { - var sectionHeaders = new List(); - SectionHeader lastSection; - int sizeOfPeHeaders = ComputeSizeOfPeHeaders(sectionCount); - int sizeOfTextSection = ComputeSizeOfTextSection(metadataSizes); - - sectionHeaders.Add(lastSection = new SectionHeader( - characteristics: SectionCharacteristics.MemRead | - SectionCharacteristics.MemExecute | - SectionCharacteristics.ContainsCode, - name: ".text", - numberOfLinenumbers: 0, - numberOfRelocations: 0, - pointerToLinenumbers: 0, - pointerToRawData: BitArithmeticUtilities.Align(sizeOfPeHeaders, _properties.FileAlignment), - pointerToRelocations: 0, - relativeVirtualAddress: BitArithmeticUtilities.Align(sizeOfPeHeaders, _properties.SectionAlignment), - sizeOfRawData: BitArithmeticUtilities.Align(sizeOfTextSection, _properties.FileAlignment), - virtualSize: sizeOfTextSection - )); - - int resourcesRva = BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, _properties.SectionAlignment); - int sizeOfWin32Resources = this.ComputeSizeOfWin32Resources(resourcesRva); - - if (sizeOfWin32Resources > 0) - { - sectionHeaders.Add(lastSection = new SectionHeader( - characteristics: SectionCharacteristics.MemRead | - SectionCharacteristics.ContainsInitializedData, - name: ResourceSectionName, - numberOfLinenumbers: 0, - numberOfRelocations: 0, - pointerToLinenumbers: 0, - pointerToRawData: lastSection.PointerToRawData + lastSection.SizeOfRawData, - pointerToRelocations: 0, - relativeVirtualAddress: resourcesRva, - sizeOfRawData: BitArithmeticUtilities.Align(sizeOfWin32Resources, _properties.FileAlignment), - virtualSize: sizeOfWin32Resources - )); - } - - if (_properties.RequiresStartupStub) - { - var size = (_properties.Requires64bits && !_properties.RequiresAmdInstructionSet) ? 14 : 12; // TODO: constants - - sectionHeaders.Add(lastSection = new SectionHeader( - characteristics: SectionCharacteristics.MemRead | - SectionCharacteristics.MemDiscardable | - SectionCharacteristics.ContainsInitializedData, - name: RelocationSectionName, - numberOfLinenumbers: 0, - numberOfRelocations: 0, - pointerToLinenumbers: 0, - pointerToRawData: lastSection.PointerToRawData + lastSection.SizeOfRawData, - pointerToRelocations: 0, - relativeVirtualAddress: BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, _properties.SectionAlignment), - sizeOfRawData: BitArithmeticUtilities.Align(size, _properties.FileAlignment), - virtualSize: size)); - } - - Debug.Assert(sectionHeaders.Count == sectionCount); - return sectionHeaders; - } - - private const string CorEntryPointDll = "mscoree.dll"; - private string CorEntryPointName => (_properties.ImageCharacteristics & Characteristics.Dll) != 0 ? "_CorDllMain" : "_CorExeMain"; - - private int SizeOfImportAddressTable => _properties.RequiresStartupStub ? (_is32bit ? 2 * sizeof(uint) : 2 * sizeof(ulong)) : 0; - - // (_is32bit ? 66 : 70); - private int SizeOfImportTable => - sizeof(uint) + // RVA - sizeof(uint) + // 0 - sizeof(uint) + // 0 - sizeof(uint) + // name RVA - sizeof(uint) + // import address table RVA - 20 + // ? - (_is32bit ? 3 * sizeof(uint) : 2 * sizeof(ulong)) + // import lookup table - sizeof(ushort) + // hint - CorEntryPointName.Length + - 1; // NUL - - private static int SizeOfNameTable => - CorEntryPointDll.Length + 1 + sizeof(ushort); - - private int SizeOfRuntimeStartupStub => _is32bit ? 8 : 16; - - private int CalculateOffsetToMappedFieldDataStream(MetadataSizes metadataSizes) - { - int result = ComputeOffsetToImportTable(metadataSizes); - - if (_properties.RequiresStartupStub) - { - result += SizeOfImportTable + SizeOfNameTable; - result = BitArithmeticUtilities.Align(result, _is32bit ? 4 : 8); //optional padding to make startup stub's target address align on word or double word boundary - result += SizeOfRuntimeStartupStub; - } - - return result; - } - - private int CalculateMappedFieldDataStreamRva(int textSectionRva, MetadataSizes metadataSizes) - { - return textSectionRva + CalculateOffsetToMappedFieldDataStream(metadataSizes); - } - - /// - /// Compute a deterministic Guid and timestamp based on the contents of the stream, and replace - /// the 16 zero bytes at the given position and one or two 4-byte values with that computed Guid and timestamp. - /// - /// PE stream. - /// Position in the stream of 16 zero bytes to be replaced by a Guid - /// Position in the stream of four zero bytes to be replaced by a timestamp - private static void WriteDeterministicGuidAndTimestamps( - Stream peStream, - long mvidPosition, - long ntHeaderTimestampPosition) - { - Debug.Assert(mvidPosition != 0); - Debug.Assert(ntHeaderTimestampPosition != 0); - - var previousPosition = peStream.Position; - - // Compute and write deterministic guid data over the relevant portion of the stream - peStream.Position = 0; - var contentId = ContentId.FromHash(CryptographicHashProvider.ComputeSha1(peStream)); - - // The existing Guid should be zero. - CheckZeroDataInStream(peStream, mvidPosition, contentId.Guid.Length); - peStream.Position = mvidPosition; - peStream.Write(contentId.Guid, 0, contentId.Guid.Length); - - // The existing timestamp should be zero. - CheckZeroDataInStream(peStream, ntHeaderTimestampPosition, contentId.Stamp.Length); - peStream.Position = ntHeaderTimestampPosition; - peStream.Write(contentId.Stamp, 0, contentId.Stamp.Length); + ContentId nativePdbContentId = nativePdbWriterOpt?.GetContentId() ?? default(ContentId); + + // the writer shall not be used after this point for writing: + nativePdbWriterOpt = null; + + var metadataSerializer = mdWriter.GetTypeSystemMetadataSerializer(); + + var peBuilder = new PEBuilder( + machine: properties.Machine, + sectionAlignment: properties.SectionAlignment, + fileAlignment: properties.FileAlignment, + imageBase: properties.BaseAddress, + majorLinkerVersion: properties.LinkerMajorVersion, + minorLinkerVersion: properties.LinkerMinorVersion, + majorOperatingSystemVersion: 4, + minorOperatingSystemVersion: 0, + majorImageVersion: 0, + minorImageVersion: 0, + majorSubsystemVersion: properties.MajorSubsystemVersion, + minorSubsystemVersion: properties.MinorSubsystemVersion, + subsystem: properties.Subsystem, + dllCharacteristics: properties.DllCharacteristics, + imageCharacteristics: properties.ImageCharacteristics, + sizeOfStackReserve: properties.SizeOfStackReserve, + sizeOfStackCommit: properties.SizeOfStackCommit, + sizeOfHeapReserve: properties.SizeOfHeapReserve, + sizeOfHeapCommit: properties.SizeOfHeapCommit, + deterministicIdProvider: isDeterministic ? new Func(content => ContentId.FromHash(CryptographicHashProvider.ComputeSha1(content))) : null); - peStream.Position = previousPosition; - } - - [Conditional("DEBUG")] - private static void CheckZeroDataInStream(Stream stream, long position, int bytes) - { - stream.Position = position; - for (int i = 0; i < bytes; i++) - { - int value = stream.ReadByte(); - Debug.Assert(value == 0); - } - } - - private int ComputeOffsetToDebugTable(MetadataSizes metadataSizes) - { - Debug.Assert(metadataSizes.MetadataSize % 4 == 0); - Debug.Assert(metadataSizes.ResourceDataSize % 4 == 0); - - return - ComputeOffsetToMetadata(metadataSizes.ILStreamSize) + - metadataSizes.MetadataSize + - metadataSizes.ResourceDataSize + - metadataSizes.StrongNameSignatureSize; - } - - private int ComputeOffsetToImportTable(MetadataSizes metadataSizes) - { - return - ComputeOffsetToDebugTable(metadataSizes) + - ComputeSizeOfDebugDirectory(); - } - - private const int CorHeaderSize = - sizeof(int) + // header size - sizeof(short) + // major runtime version - sizeof(short) + // minor runtime version - sizeof(long) + // metadata directory - sizeof(int) + // COR flags - sizeof(int) + // entry point - sizeof(long) + // resources directory - sizeof(long) + // strong name signature directory - sizeof(long) + // code manager table directory - sizeof(long) + // vtable fixups directory - sizeof(long) + // export address table jumps directory - sizeof(long); // managed-native header directory - - private int OffsetToILStream => SizeOfImportAddressTable + CorHeaderSize; - - private int ComputeOffsetToMetadata(int ilStreamLength) - { - return OffsetToILStream + BitArithmeticUtilities.Align(ilStreamLength, 4); - } - - /// - /// The size of a single entry in the "Debug Directory (Image Only)" - /// - private const int ImageDebugDirectoryEntrySize = - sizeof(uint) + // Characteristics - sizeof(uint) + // TimeDataStamp - sizeof(uint) + // Version - sizeof(uint) + // Type - sizeof(uint) + // SizeOfData - sizeof(uint) + // AddressOfRawData - sizeof(uint); // PointerToRawData - - /// - /// The size of our debug directory: one entry for debug information, and an optional second one indicating - /// that the timestamp is deterministic (i.e. not really a timestamp) - /// - private int ImageDebugDirectoryBaseSize => - (_deterministic ? ImageDebugDirectoryEntrySize : 0) + - (EmitPdb ? ImageDebugDirectoryEntrySize : 0); - - private int ComputeSizeOfDebugDirectoryData() - { - // The debug directory data is only needed if this.EmitPdb. - return (!EmitPdb) ? 0 : - 4 + // 4B signature "RSDS" - 16 + // GUID - sizeof(uint) + // Age - Math.Max(BlobUtilities.GetUTF8ByteCount(_pdbPathOpt) + 1, _minPdbPath); - } - - private int ComputeSizeOfDebugDirectory() - { - return ImageDebugDirectoryBaseSize + ComputeSizeOfDebugDirectoryData(); - } - - private int ComputeSizeOfPeHeaders(int sectionCount) - { - int sizeOfPeHeaders = 128 + 4 + 20 + 224 + 40 * sectionCount; // TODO: constants - if (!_is32bit) - { - sizeOfPeHeaders += 16; - } - - return sizeOfPeHeaders; - } - - private int ComputeSizeOfTextSection(MetadataSizes metadataSizes) - { - Debug.Assert(metadataSizes.MappedFieldDataSize % MetadataWriter.MappedFieldDataAlignment == 0); - return CalculateOffsetToMappedFieldDataStream(metadataSizes) + metadataSizes.MappedFieldDataSize; - } - - private int ComputeSizeOfWin32Resources(int resourcesRva) - { - this.SerializeWin32Resources(resourcesRva); - int result = 0; - if (_win32ResourceWriter.Count > 0) - { - result += BitArithmeticUtilities.Align(_win32ResourceWriter.Count, 4); - } // result += Align(this.win32ResourceWriter.Length+1, 8); - - return result; - } - - private CorHeader CreateCorHeader(MetadataSizes metadataSizes, int textSectionRva, int entryPointToken) - { - int metadataRva = textSectionRva + ComputeOffsetToMetadata(metadataSizes.ILStreamSize); - int resourcesRva = metadataRva + metadataSizes.MetadataSize; - int signatureRva = resourcesRva + metadataSizes.ResourceDataSize; - - return new CorHeader( - entryPointTokenOrRelativeVirtualAddress: entryPointToken, - flags: _properties.GetCorHeaderFlags(), - metadataDirectory: new DirectoryEntry(metadataRva, metadataSizes.MetadataSize), - resourcesDirectory: new DirectoryEntry(resourcesRva, metadataSizes.ResourceDataSize), - strongNameSignatureDirectory: new DirectoryEntry(signatureRva, metadataSizes.StrongNameSignatureSize)); - } - - private void FillInNtHeader( - List sectionHeaders, - int entryPointAddress, - DirectoryEntry corHeader, - DirectoryEntry importTable, - DirectoryEntry importAddressTable, - DirectoryEntry debugTable, - out CoffHeader coffHeader, - out NtHeader ntHeader) - { - short sectionCount = (short)sectionHeaders.Count; - - coffHeader = new CoffHeader( - machine: (_properties.Machine == 0) ? Machine.I386 : _properties.Machine, - numberOfSections: sectionCount, - timeDateStamp: _timeStamp, - pointerToSymbolTable: 0, - numberOfSymbols: 0, - sizeOfOptionalHeader: (short)(_is32bit ? 224 : 240), // TODO: constants - characteristics: _properties.ImageCharacteristics); - - SectionHeader codeSection = sectionHeaders.FirstOrDefault(sh => (sh.Characteristics & SectionCharacteristics.ContainsCode) != 0); - SectionHeader dataSection = sectionHeaders.FirstOrDefault(sh => (sh.Characteristics & SectionCharacteristics.ContainsInitializedData) != 0); - - ntHeader = new NtHeader(); - ntHeader.Magic = _is32bit ? PEMagic.PE32 : PEMagic.PE32Plus; - ntHeader.MajorLinkerVersion = _properties.LinkerMajorVersion; - ntHeader.MinorLinkerVersion = _properties.LinkerMinorVersion; - ntHeader.AddressOfEntryPoint = entryPointAddress; - ntHeader.BaseOfCode = codeSection?.RelativeVirtualAddress ?? 0; - ntHeader.BaseOfData = dataSection?.RelativeVirtualAddress ?? 0; - ntHeader.ImageBase = _properties.BaseAddress; - ntHeader.FileAlignment = _properties.FileAlignment; - ntHeader.MajorSubsystemVersion = _properties.MajorSubsystemVersion; - ntHeader.MinorSubsystemVersion = _properties.MinorSubsystemVersion; - - ntHeader.Subsystem = _properties.Subsystem; - ntHeader.DllCharacteristics = _properties.DllCharacteristics; - - ntHeader.SizeOfStackReserve = _properties.SizeOfStackReserve; - ntHeader.SizeOfStackCommit = _properties.SizeOfStackCommit; - ntHeader.SizeOfHeapReserve = _properties.SizeOfHeapReserve; - ntHeader.SizeOfHeapCommit = _properties.SizeOfHeapCommit; - - ntHeader.SizeOfCode = codeSection?.SizeOfRawData ?? 0; - - ntHeader.SizeOfInitializedData = sectionHeaders.Sum( - sectionHeader => (sectionHeader.Characteristics & SectionCharacteristics.ContainsInitializedData) != 0 ? sectionHeader.SizeOfRawData : 0); - - ntHeader.SizeOfHeaders = BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(sectionCount), _properties.FileAlignment); - - var lastSection = sectionHeaders.Last(); - ntHeader.SizeOfImage = BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, _properties.SectionAlignment); - ntHeader.SizeOfUninitializedData = 0; - - ntHeader.ImportAddressTable = importAddressTable; - ntHeader.CliHeaderTable = corHeader; - ntHeader.ImportTable = importTable; - - var relocSection = sectionHeaders.FirstOrDefault(sectionHeader => sectionHeader.Name == RelocationSectionName); - if (relocSection != null) - { - ntHeader.BaseRelocationTable = new DirectoryEntry(relocSection.RelativeVirtualAddress, relocSection.VirtualSize); - } - - ntHeader.DebugTable = debugTable; - - var resourceSection = sectionHeaders.FirstOrDefault(sectionHeader => sectionHeader.Name == ResourceSectionName); - if (resourceSection != null) + ContentId portablePdbContentId; + if (mdWriter.EmitStandaloneDebugMetadata) { - ntHeader.ResourceTable = new DirectoryEntry(resourceSection.RelativeVirtualAddress, resourceSection.VirtualSize); - } - } - - //// - //// Resource Format. - //// - - //// - //// Resource directory consists of two counts, following by a variable length - //// array of directory entries. The first count is the number of entries at - //// beginning of the array that have actual names associated with each entry. - //// The entries are in ascending order, case insensitive strings. The second - //// count is the number of entries that immediately follow the named entries. - //// This second count identifies the number of entries that have 16-bit integer - //// Ids as their name. These entries are also sorted in ascending order. - //// - //// This structure allows fast lookup by either name or number, but for any - //// given resource entry only one form of lookup is supported, not both. - //// This is consistent with the syntax of the .RC file and the .RES file. - //// - - //typedef struct _IMAGE_RESOURCE_DIRECTORY { - // DWORD Characteristics; - // DWORD TimeDateStamp; - // WORD MajorVersion; - // WORD MinorVersion; - // WORD NumberOfNamedEntries; - // WORD NumberOfIdEntries; - //// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[]; - //} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY; + Debug.Assert(getPortablePdbStreamOpt != null); - //#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000 - //#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000 - //// - //// Each directory contains the 32-bit Name of the entry and an offset, - //// relative to the beginning of the resource directory of the data associated - //// with this directory entry. If the name of the entry is an actual text - //// string instead of an integer Id, then the high order bit of the name field - //// is set to one and the low order 31-bits are an offset, relative to the - //// beginning of the resource directory of the string, which is of type - //// IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the - //// low-order 16-bits are the integer Id that identify this resource directory - //// entry. If the directory entry is yet another resource directory (i.e. a - //// subdirectory), then the high order bit of the offset field will be - //// set to indicate this. Otherwise the high bit is clear and the offset - //// field points to a resource data entry. - //// + var debugMetadataBuilder = new BlobBuilder(); + var debugMetadataSerializer = mdWriter.GetStandaloneDebugMetadataSerializer(metadataSerializer.MetadataSizes, debugEntryPointHandle); + debugMetadataSerializer.SerializeMetadata(debugMetadataBuilder, peBuilder.IdProvider, out portablePdbContentId); - //typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY { - // union { - // struct { - // DWORD NameOffset:31; - // DWORD NameIsString:1; - // } DUMMYSTRUCTNAME; - // DWORD Name; - // WORD Id; - // } DUMMYUNIONNAME; - // union { - // DWORD OffsetToData; - // struct { - // DWORD OffsetToDirectory:31; - // DWORD DataIsDirectory:1; - // } DUMMYSTRUCTNAME2; - // } DUMMYUNIONNAME2; - //} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY; - - //// - //// For resource directory entries that have actual string names, the Name - //// field of the directory entry points to an object of the following type. - //// All of these string objects are stored together after the last resource - //// directory entry and before the first resource data object. This minimizes - //// the impact of these variable length objects on the alignment of the fixed - //// size directory entry objects. - //// - - //typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING { - // WORD Length; - // CHAR NameString[ 1 ]; - //} IMAGE_RESOURCE_DIRECTORY_STRING, *PIMAGE_RESOURCE_DIRECTORY_STRING; - - - //typedef struct _IMAGE_RESOURCE_DIR_STRING_U { - // WORD Length; - // WCHAR NameString[ 1 ]; - //} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U; - - - //// - //// Each resource data entry describes a leaf node in the resource directory - //// tree. It contains an offset, relative to the beginning of the resource - //// directory of the data for the resource, a size field that gives the number - //// of bytes of data at that offset, a CodePage that should be used when - //// decoding code point values within the resource data. Typically for new - //// applications the code page would be the unicode code page. - //// - - //typedef struct _IMAGE_RESOURCE_DATA_ENTRY { - // DWORD OffsetToData; - // DWORD Size; - // DWORD CodePage; - // DWORD Reserved; - //} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY; - - private class Directory - { - internal readonly string Name; - internal readonly int ID; - internal ushort NumberOfNamedEntries; - internal ushort NumberOfIdEntries; - internal readonly List Entries; - - internal Directory(string name, int id) - { - this.Name = name; - this.ID = id; - this.Entries = new List(); - } - } - - private static int CompareResources(IWin32Resource left, IWin32Resource right) - { - int result = CompareResourceIdentifiers(left.TypeId, left.TypeName, right.TypeId, right.TypeName); - - return (result == 0) ? CompareResourceIdentifiers(left.Id, left.Name, right.Id, right.Name) : result; - } - - //when comparing a string vs ordinal, the string should always be less than the ordinal. Per the spec, - //entries identified by string must precede those identified by ordinal. - private static int CompareResourceIdentifiers(int xOrdinal, string xString, int yOrdinal, string yString) - { - if (xString == null) - { - if (yString == null) + // write to Portable PDB stream: + Stream portablePdbStream = getPortablePdbStreamOpt(); + if (portablePdbStream != null) { - return xOrdinal - yOrdinal; - } - else - { - return 1; + debugMetadataBuilder.WriteContentTo(portablePdbStream); } } - else if (yString == null) - { - return -1; - } else { - return String.Compare(xString, yString, StringComparison.OrdinalIgnoreCase); + portablePdbContentId = default(ContentId); } - } - //sort the resources by ID least to greatest then by NAME. - //Where strings and ordinals are compared, strings are less than ordinals. - internal static IEnumerable SortResources(IEnumerable resources) - { - return resources.OrderBy(CompareResources); - } + var peDirectoriesBuilder = new PEDirectoriesBuilder(); - //Win32 resources are supplied to the compiler in one of two forms, .RES (the output of the resource compiler), - //or .OBJ (the output of running cvtres.exe on a .RES file). A .RES file is parsed and processed into - //a set of objects implementing IWin32Resources. These are then ordered and the final image form is constructed - //and written to the resource section. Resources in .OBJ form are already very close to their final output - //form. Rather than reading them and parsing them into a set of objects similar to those produced by - //processing a .RES file, we process them like the native linker would, copy the relevant sections from - //the .OBJ into our output and apply some fixups. - private void SerializeWin32Resources(int resourcesRva) - { - if (_nativeResourceSectionOpt != null) - { - SerializeWin32Resources(_nativeResourceSectionOpt, resourcesRva); - return; - } + peBuilder.AddManagedSections( + peDirectoriesBuilder, + metadataSerializer, + ilBuilder, + mappedFieldDataBuilder, + managedResourceBuilder, + CreateNativeResourceSectionSerializer(context.Module), + CalculateStrongNameSignatureSize(context.Module), + entryPointHandle, + pdbPathOpt, + nativePdbContentId, + portablePdbContentId, + properties.CorFlags); + + var peBlob = new BlobBuilder(); + ContentId peContentId; + peBuilder.Serialize(peBlob, peDirectoriesBuilder, out peContentId); - if (IteratorHelper.EnumerableIsEmpty(_nativeResourcesOpt)) + // Patch MVID + if (!mvidFixup.IsDefault) { - return; + var mvidWriter = new BlobWriter(mvidFixup); + mvidWriter.WriteBytes(peContentId.Guid); + Debug.Assert(mvidWriter.RemainingBytes == 0); } - SerializeWin32Resources(_nativeResourcesOpt, resourcesRva); - } - - private void SerializeWin32Resources(IEnumerable theResources, int resourcesRva) - { - theResources = SortResources(theResources); - - Directory typeDirectory = new Directory(string.Empty, 0); - Directory nameDirectory = null; - Directory languageDirectory = null; - int lastTypeID = int.MinValue; - string lastTypeName = null; - int lastID = int.MinValue; - string lastName = null; - uint sizeOfDirectoryTree = 16; - - //EDMAURER note that this list is assumed to be sorted lowest to highest - //first by typeId, then by Id. - foreach (IWin32Resource r in theResources) + try { - bool typeDifferent = (r.TypeId < 0 && r.TypeName != lastTypeName) || r.TypeId > lastTypeID; - if (typeDifferent) - { - lastTypeID = r.TypeId; - lastTypeName = r.TypeName; - if (lastTypeID < 0) - { - Debug.Assert(typeDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with types encoded as strings precede those encoded as ints"); - typeDirectory.NumberOfNamedEntries++; - } - else - { - typeDirectory.NumberOfIdEntries++; - } - - sizeOfDirectoryTree += 24; - typeDirectory.Entries.Add(nameDirectory = new Directory(lastTypeName, lastTypeID)); - } - - if (typeDifferent || (r.Id < 0 && r.Name != lastName) || r.Id > lastID) - { - lastID = r.Id; - lastName = r.Name; - if (lastID < 0) - { - Debug.Assert(nameDirectory.NumberOfIdEntries == 0, "Not all Win32 resources with names encoded as strings precede those encoded as ints"); - nameDirectory.NumberOfNamedEntries++; - } - else - { - nameDirectory.NumberOfIdEntries++; - } - - sizeOfDirectoryTree += 24; - nameDirectory.Entries.Add(languageDirectory = new Directory(lastName, lastID)); - } - - languageDirectory.NumberOfIdEntries++; - sizeOfDirectoryTree += 8; - languageDirectory.Entries.Add(r); + peBlob.WriteContentTo(peStream); } - - var dataWriter = new BlobBuilder(); - - //'dataWriter' is where opaque resource data goes as well as strings that are used as type or name identifiers - this.WriteDirectory(typeDirectory, _win32ResourceWriter, 0, 0, sizeOfDirectoryTree, resourcesRva, dataWriter); - _win32ResourceWriter.LinkSuffix(dataWriter); - _win32ResourceWriter.WriteByte(0); - while ((_win32ResourceWriter.Count % 4) != 0) + catch (Exception e) when (!(e is OperationCanceledException)) { - _win32ResourceWriter.WriteByte(0); + throw new PeWritingException(e); } + + return true; } - private void WriteDirectory(Directory directory, BlobBuilder writer, uint offset, uint level, uint sizeOfDirectoryTree, int virtualAddressBase, BlobBuilder dataWriter) + private static Action CreateNativeResourceSectionSerializer(IModule module) { - writer.WriteUInt32(0); // Characteristics - writer.WriteUInt32(0); // Timestamp - writer.WriteUInt32(0); // Version - writer.WriteUInt16(directory.NumberOfNamedEntries); - writer.WriteUInt16(directory.NumberOfIdEntries); - uint n = (uint)directory.Entries.Count; - uint k = offset + 16 + n * 8; - for (int i = 0; i < n; i++) - { - int id; - string name; - uint nameOffset = (uint)dataWriter.Position + sizeOfDirectoryTree; - uint directoryOffset = k; - Directory subDir = directory.Entries[i] as Directory; - if (subDir != null) - { - id = subDir.ID; - name = subDir.Name; - if (level == 0) - { - k += SizeOfDirectory(subDir); - } - else - { - k += 16 + 8 * (uint)subDir.Entries.Count; - } - } - else - { - //EDMAURER write out an IMAGE_RESOURCE_DATA_ENTRY followed - //immediately by the data that it refers to. This results - //in a layout different than that produced by pulling the resources - //from an OBJ. In that case all of the data bits of a resource are - //contiguous in .rsrc$02. After processing these will end up at - //the end of .rsrc following all of the directory - //info and IMAGE_RESOURCE_DATA_ENTRYs - IWin32Resource r = (IWin32Resource)directory.Entries[i]; - id = level == 0 ? r.TypeId : level == 1 ? r.Id : (int)r.LanguageId; - name = level == 0 ? r.TypeName : level == 1 ? r.Name : null; - dataWriter.WriteUInt32((uint)(virtualAddressBase + sizeOfDirectoryTree + 16 + dataWriter.Position)); - byte[] data = new List(r.Data).ToArray(); - dataWriter.WriteUInt32((uint)data.Length); - dataWriter.WriteUInt32(r.CodePage); - dataWriter.WriteUInt32(0); - dataWriter.WriteBytes(data); - while ((dataWriter.Count % 4) != 0) - { - dataWriter.WriteByte(0); - } - } + // Win32 resources are supplied to the compiler in one of two forms, .RES (the output of the resource compiler), + // or .OBJ (the output of running cvtres.exe on a .RES file). A .RES file is parsed and processed into + // a set of objects implementing IWin32Resources. These are then ordered and the final image form is constructed + // and written to the resource section. Resources in .OBJ form are already very close to their final output + // form. Rather than reading them and parsing them into a set of objects similar to those produced by + // processing a .RES file, we process them like the native linker would, copy the relevant sections from + // the .OBJ into our output and apply some fixups. - if (id >= 0) - { - writer.WriteInt32(id); - } - else - { - if (name == null) - { - name = string.Empty; - } - - writer.WriteUInt32(nameOffset | 0x80000000); - dataWriter.WriteUInt16((ushort)name.Length); - dataWriter.WriteUTF16(name); - } - - if (subDir != null) - { - writer.WriteUInt32(directoryOffset | 0x80000000); - } - else - { - writer.WriteUInt32(nameOffset); - } - } - - k = offset + 16 + n * 8; - for (int i = 0; i < n; i++) + var nativeResourcesOpt = module.Win32Resources; + var nativeResourceSectionOpt = module.Win32ResourceSection; + if (!IteratorHelper.EnumerableIsEmpty(nativeResourcesOpt) || nativeResourceSectionOpt != null) { - Directory subDir = directory.Entries[i] as Directory; - if (subDir != null) + return (sectionBuilder, location) => { - this.WriteDirectory(subDir, writer, k, level + 1, sizeOfDirectoryTree, virtualAddressBase, dataWriter); - if (level == 0) + if (nativeResourceSectionOpt != null) { - k += SizeOfDirectory(subDir); + NativeResourceWriter.SerializeWin32Resources(sectionBuilder, nativeResourceSectionOpt, location.RelativeVirtualAddress); } else { - k += 16 + 8 * (uint)subDir.Entries.Count; + NativeResourceWriter.SerializeWin32Resources(sectionBuilder, nativeResourcesOpt, location.RelativeVirtualAddress); } - } - } - } - - private static uint SizeOfDirectory(Directory/*!*/ directory) - { - uint n = (uint)directory.Entries.Count; - uint size = 16 + 8 * n; - for (int i = 0; i < n; i++) - { - Directory subDir = directory.Entries[i] as Directory; - if (subDir != null) - { - size += 16 + 8 * (uint)subDir.Entries.Count; - } + }; } - return size; + return null; } - private void SerializeWin32Resources(ResourceSection resourceSections, int resourcesRva) + private static int CalculateStrongNameSignatureSize(IModule module) { - var sectionWriter = _win32ResourceWriter.ReserveBytes(resourceSections.SectionBytes.Length); - sectionWriter.WriteBytes(resourceSections.SectionBytes); - - var readStream = new MemoryStream(resourceSections.SectionBytes); - var reader = new BinaryReader(readStream); - - foreach (int addressToFixup in resourceSections.Relocations) + IAssembly assembly = module.AsAssembly; + if (assembly == null) { - sectionWriter.Offset = addressToFixup; - reader.BaseStream.Position = addressToFixup; - sectionWriter.WriteUInt32(reader.ReadUInt32() + (uint)resourcesRva); + return 0; } - } - - //#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file. - //#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved external references). - //#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line numbers stripped from file. - //#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file. - //#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set - //#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses - //#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed. - //#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine. - //#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file - //#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file. - //#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file. - //#define IMAGE_FILE_SYSTEM 0x1000 // System File. - //#define IMAGE_FILE_DLL 0x2000 // File is a DLL. - //#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine - //#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed. - private static readonly byte[] s_dosHeader = new byte[] - { - 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, - 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, - 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, - 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, - 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - private void WriteHeaders(Stream peStream, NtHeader ntHeader, CoffHeader coffHeader, List sectionHeaders, out long ntHeaderTimestampPosition) - { - var writer = PooledBlobBuilder.GetInstance(); + // EDMAURER the count of characters divided by two because the each pair of characters will turn in to one byte. + int keySize = (assembly.SignatureKey == null) ? 0 : assembly.SignatureKey.Length / 2; - // MS-DOS stub (128 bytes) - writer.WriteBytes(s_dosHeader); - - // PE Signature "PE\0\0" - writer.WriteUInt32(0x00004550); - - // COFF Header (20 bytes) - writer.WriteUInt16((ushort)coffHeader.Machine); - writer.WriteUInt16((ushort)coffHeader.NumberOfSections); - ntHeaderTimestampPosition = writer.Position + peStream.Position; - writer.WriteUInt32((uint)coffHeader.TimeDateStamp); - writer.WriteUInt32((uint)coffHeader.PointerToSymbolTable); - writer.WriteUInt32((uint)coffHeader.NumberOfSymbols); - writer.WriteUInt16((ushort)(_is32bit ? 224 : 240)); // SizeOfOptionalHeader - writer.WriteUInt16((ushort)coffHeader.Characteristics); - - // PE Headers: - writer.WriteUInt16((ushort)(_is32bit ? PEMagic.PE32 : PEMagic.PE32Plus)); // 2 - writer.WriteByte(ntHeader.MajorLinkerVersion); // 3 - writer.WriteByte(ntHeader.MinorLinkerVersion); // 4 - writer.WriteUInt32((uint)ntHeader.SizeOfCode); // 8 - writer.WriteUInt32((uint)ntHeader.SizeOfInitializedData); // 12 - writer.WriteUInt32((uint)ntHeader.SizeOfUninitializedData); // 16 - writer.WriteUInt32((uint)ntHeader.AddressOfEntryPoint); // 20 - writer.WriteUInt32((uint)ntHeader.BaseOfCode); // 24 - - if (_is32bit) - { - writer.WriteUInt32((uint)ntHeader.BaseOfData); // 28 - writer.WriteUInt32((uint)ntHeader.ImageBase); // 32 - } - else + if (keySize == 0) { - writer.WriteUInt64(ntHeader.ImageBase); // 32 + keySize = assembly.PublicKey.Length; } - // NT additional fields: - writer.WriteUInt32((uint)ntHeader.SectionAlignment); // 36 - writer.WriteUInt32((uint)ntHeader.FileAlignment); // 40 - writer.WriteUInt16(ntHeader.MajorOperatingSystemVersion); // 42 - writer.WriteUInt16(ntHeader.MinorOperatingSystemVersion); // 44 - writer.WriteUInt16(ntHeader.MajorImageVersion); // 46 - writer.WriteUInt16(ntHeader.MinorImageVersion); // 48 - writer.WriteUInt16(ntHeader.MajorSubsystemVersion); // MajorSubsystemVersion 50 - writer.WriteUInt16(ntHeader.MinorSubsystemVersion); // MinorSubsystemVersion 52 - - // Win32VersionValue (reserved, should be 0) - writer.WriteUInt32(0); // 56 - - writer.WriteUInt32((uint)ntHeader.SizeOfImage); // 60 - writer.WriteUInt32((uint)ntHeader.SizeOfHeaders); // 64 - writer.WriteUInt32(ntHeader.Checksum); // 68 - writer.WriteUInt16((ushort)ntHeader.Subsystem); // 70 - writer.WriteUInt16((ushort)ntHeader.DllCharacteristics); - - if (_is32bit) - { - writer.WriteUInt32((uint)ntHeader.SizeOfStackReserve); // 76 - writer.WriteUInt32((uint)ntHeader.SizeOfStackCommit); // 80 - writer.WriteUInt32((uint)ntHeader.SizeOfHeapReserve); // 84 - writer.WriteUInt32((uint)ntHeader.SizeOfHeapCommit); // 88 - } - else + if (keySize == 0) { - writer.WriteUInt64(ntHeader.SizeOfStackReserve); // 80 - writer.WriteUInt64(ntHeader.SizeOfStackCommit); // 88 - writer.WriteUInt64(ntHeader.SizeOfHeapReserve); // 96 - writer.WriteUInt64(ntHeader.SizeOfHeapCommit); // 104 + return 0; } - // LoaderFlags - writer.WriteUInt32(0); // 92|108 - - // The number of data-directory entries in the remainder of the header. - writer.WriteUInt32(16); // 96|112 - - // directory entries: - writer.WriteUInt32((uint)ntHeader.ExportTable.RelativeVirtualAddress); // 100|116 - writer.WriteUInt32((uint)ntHeader.ExportTable.Size); // 104|120 - writer.WriteUInt32((uint)ntHeader.ImportTable.RelativeVirtualAddress); // 108|124 - writer.WriteUInt32((uint)ntHeader.ImportTable.Size); // 112|128 - writer.WriteUInt32((uint)ntHeader.ResourceTable.RelativeVirtualAddress); // 116|132 - writer.WriteUInt32((uint)ntHeader.ResourceTable.Size); // 120|136 - writer.WriteUInt32((uint)ntHeader.ExceptionTable.RelativeVirtualAddress); // 124|140 - writer.WriteUInt32((uint)ntHeader.ExceptionTable.Size); // 128|144 - writer.WriteUInt32((uint)ntHeader.CertificateTable.RelativeVirtualAddress); // 132|148 - writer.WriteUInt32((uint)ntHeader.CertificateTable.Size); // 136|152 - writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.RelativeVirtualAddress); // 140|156 - writer.WriteUInt32((uint)ntHeader.BaseRelocationTable.Size); // 144|160 - writer.WriteUInt32((uint)ntHeader.DebugTable.RelativeVirtualAddress); // 148|164 - writer.WriteUInt32((uint)ntHeader.DebugTable.Size); // 152|168 - writer.WriteUInt32((uint)ntHeader.CopyrightTable.RelativeVirtualAddress); // 156|172 - writer.WriteUInt32((uint)ntHeader.CopyrightTable.Size); // 160|176 - writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.RelativeVirtualAddress); // 164|180 - writer.WriteUInt32((uint)ntHeader.GlobalPointerTable.Size); // 168|184 - writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.RelativeVirtualAddress); // 172|188 - writer.WriteUInt32((uint)ntHeader.ThreadLocalStorageTable.Size); // 176|192 - writer.WriteUInt32((uint)ntHeader.LoadConfigTable.RelativeVirtualAddress); // 180|196 - writer.WriteUInt32((uint)ntHeader.LoadConfigTable.Size); // 184|200 - writer.WriteUInt32((uint)ntHeader.BoundImportTable.RelativeVirtualAddress); // 188|204 - writer.WriteUInt32((uint)ntHeader.BoundImportTable.Size); // 192|208 - writer.WriteUInt32((uint)ntHeader.ImportAddressTable.RelativeVirtualAddress); // 196|212 - writer.WriteUInt32((uint)ntHeader.ImportAddressTable.Size); // 200|216 - writer.WriteUInt32((uint)ntHeader.DelayImportTable.RelativeVirtualAddress); // 204|220 - writer.WriteUInt32((uint)ntHeader.DelayImportTable.Size); // 208|224 - writer.WriteUInt32((uint)ntHeader.CliHeaderTable.RelativeVirtualAddress); // 212|228 - writer.WriteUInt32((uint)ntHeader.CliHeaderTable.Size); // 216|232 - writer.WriteUInt64(0); // 224|240 - - // Section Headers - foreach (var sectionHeader in sectionHeaders) - { - WriteSectionHeader(sectionHeader, writer); - } - - writer.WriteContentTo(peStream); - writer.Free(); - } - - private static void WriteSectionHeader(SectionHeader sectionHeader, BlobBuilder writer) - { - if (sectionHeader.VirtualSize == 0) - { - return; - } - - for (int j = 0, m = sectionHeader.Name.Length; j < 8; j++) - { - if (j < m) - { - writer.WriteByte((byte)sectionHeader.Name[j]); - } - else - { - writer.WriteByte(0); - } - } - - writer.WriteUInt32((uint)sectionHeader.VirtualSize); - writer.WriteUInt32((uint)sectionHeader.RelativeVirtualAddress); - writer.WriteUInt32((uint)sectionHeader.SizeOfRawData); - writer.WriteUInt32((uint)sectionHeader.PointerToRawData); - writer.WriteUInt32((uint)sectionHeader.PointerToRelocations); - writer.WriteUInt32((uint)sectionHeader.PointerToLinenumbers); - writer.WriteUInt16(sectionHeader.NumberOfRelocations); - writer.WriteUInt16(sectionHeader.NumberOfLinenumbers); - writer.WriteUInt32((uint)sectionHeader.Characteristics); - } - - private void WriteTextSection( - Stream peStream, - SectionHeader textSection, - int importTableRva, - int importAddressTableRva, - int entryPointToken, - BlobBuilder metadataWriter, - BlobBuilder ilWriter, - BlobBuilder mappedFieldDataWriter, - BlobBuilder managedResourceWriter, - MetadataSizes metadataSizes, - ContentId nativePdbContentId, - ContentId portablePdbContentId, - out long metadataPosition) - { - // TODO: zero out all bytes: - peStream.Position = textSection.PointerToRawData; - - if (_properties.RequiresStartupStub) - { - WriteImportAddressTable(peStream, importTableRva); - } - - var corHeader = CreateCorHeader(metadataSizes, textSection.RelativeVirtualAddress, entryPointToken); - WriteCorHeader(peStream, corHeader); - - // IL: - ilWriter.Align(4); - ilWriter.WriteContentTo(peStream); - - // metadata: - metadataPosition = peStream.Position; - Debug.Assert(metadataWriter.Count % 4 == 0); - metadataWriter.WriteContentTo(peStream); - - // managed resources: - Debug.Assert(managedResourceWriter.Count % 4 == 0); - managedResourceWriter.WriteContentTo(peStream); - - // strong name signature: - WriteSpaceForHash(peStream, metadataSizes.StrongNameSignatureSize); - - if (EmitPdb || _deterministic) - { - WriteDebugTable(peStream, textSection, nativePdbContentId, portablePdbContentId, metadataSizes); - } - - if (_properties.RequiresStartupStub) - { - WriteImportTable(peStream, importTableRva, importAddressTableRva); - WriteNameTable(peStream); - WriteRuntimeStartupStub(peStream, importAddressTableRva); - } - - // mapped field data: - mappedFieldDataWriter.WriteContentTo(peStream); - - // TODO: zero out all bytes: - int alignedPosition = textSection.PointerToRawData + textSection.SizeOfRawData; - if (peStream.Position != alignedPosition) - { - peStream.Position = alignedPosition - 1; - peStream.WriteByte(0); - } - } - - private void WriteImportAddressTable(Stream peStream, int importTableRva) - { - var writer = new BlobBuilder(SizeOfImportAddressTable); - int ilRVA = importTableRva + 40; - int hintRva = ilRVA + (_is32bit ? 12 : 16); - - // Import Address Table - if (_is32bit) - { - writer.WriteUInt32((uint)hintRva); // 4 - writer.WriteUInt32(0); // 8 - } - else - { - writer.WriteUInt64((uint)hintRva); // 8 - writer.WriteUInt64(0); // 16 - } - - Debug.Assert(writer.Count == SizeOfImportAddressTable); - writer.WriteContentTo(peStream); - } - - private void WriteImportTable(Stream peStream, int importTableRva, int importAddressTableRva) - { - var writer = new BlobBuilder(SizeOfImportTable); - int ilRVA = importTableRva + 40; - int hintRva = ilRVA + (_is32bit ? 12 : 16); - int nameRva = hintRva + 12 + 2; - - // Import table - writer.WriteUInt32((uint)ilRVA); // 4 - writer.WriteUInt32(0); // 8 - writer.WriteUInt32(0); // 12 - writer.WriteUInt32((uint)nameRva); // 16 - writer.WriteUInt32((uint)importAddressTableRva); // 20 - writer.WriteBytes(0, 20); // 40 - - // Import Lookup table - if (_is32bit) - { - writer.WriteUInt32((uint)hintRva); // 44 - writer.WriteUInt32(0); // 48 - writer.WriteUInt32(0); // 52 - } - else - { - writer.WriteUInt64((uint)hintRva); // 48 - writer.WriteUInt64(0); // 56 - } - - // Hint table - writer.WriteUInt16(0); // Hint 54|58 - - foreach (char ch in CorEntryPointName) - { - writer.WriteByte((byte)ch); // 65|69 - } - - writer.WriteByte(0); // 66|70 - Debug.Assert(writer.Count == SizeOfImportTable); - - writer.WriteContentTo(peStream); - } - - private static void WriteNameTable(Stream peStream) - { - var writer = new BlobBuilder(SizeOfNameTable); - foreach (char ch in CorEntryPointDll) - { - writer.WriteByte((byte)ch); - } - - writer.WriteByte(0); - writer.WriteUInt16(0); - Debug.Assert(writer.Count == SizeOfNameTable); - - writer.WriteContentTo(peStream); - } - - private static void WriteCorHeader(Stream peStream, CorHeader corHeader) - { - var writer = new BlobBuilder(CorHeaderSize); - writer.WriteUInt32(CorHeaderSize); - writer.WriteUInt16(corHeader.MajorRuntimeVersion); - writer.WriteUInt16(corHeader.MinorRuntimeVersion); - writer.WriteUInt32((uint)corHeader.MetadataDirectory.RelativeVirtualAddress); - writer.WriteUInt32((uint)corHeader.MetadataDirectory.Size); - writer.WriteUInt32((uint)corHeader.Flags); - writer.WriteUInt32((uint)corHeader.EntryPointTokenOrRelativeVirtualAddress); - writer.WriteUInt32((uint)(corHeader.ResourcesDirectory.Size == 0 ? 0 : corHeader.ResourcesDirectory.RelativeVirtualAddress)); // 28 - writer.WriteUInt32((uint)corHeader.ResourcesDirectory.Size); - writer.WriteUInt32((uint)(corHeader.StrongNameSignatureDirectory.Size == 0 ? 0 : corHeader.StrongNameSignatureDirectory.RelativeVirtualAddress)); // 36 - writer.WriteUInt32((uint)corHeader.StrongNameSignatureDirectory.Size); - writer.WriteUInt32((uint)corHeader.CodeManagerTableDirectory.RelativeVirtualAddress); - writer.WriteUInt32((uint)corHeader.CodeManagerTableDirectory.Size); - writer.WriteUInt32((uint)corHeader.VtableFixupsDirectory.RelativeVirtualAddress); - writer.WriteUInt32((uint)corHeader.VtableFixupsDirectory.Size); - writer.WriteUInt32((uint)corHeader.ExportAddressTableJumpsDirectory.RelativeVirtualAddress); - writer.WriteUInt32((uint)corHeader.ExportAddressTableJumpsDirectory.Size); - writer.WriteUInt64(0); - Debug.Assert(writer.Count == CorHeaderSize); - Debug.Assert(writer.Count % 4 == 0); - - writer.WriteContentTo(peStream); - } - - private static void WriteSpaceForHash(Stream peStream, int strongNameSignatureSize) - { - while (strongNameSignatureSize > 0) - { - peStream.WriteByte(0); - strongNameSignatureSize--; - } - } - - /// - /// Write one entry in the "Debug Directory (Image Only)" - /// See https://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx - /// section 5.1.1 (pages 71-72). - /// - private static void WriteDebugTableEntry( - PooledBlobBuilder writer, - byte[] stamp, - uint version, // major and minor version, combined - uint debugType, - uint sizeOfData, - uint addressOfRawData, - uint pointerToRawData - ) - { - writer.WriteUInt32(0); // characteristics - Debug.Assert(stamp.Length == 4); - writer.WriteBytes(stamp); - writer.WriteUInt32(version); - writer.WriteUInt32(debugType); - writer.WriteUInt32(sizeOfData); - writer.WriteUInt32(addressOfRawData); - writer.WriteUInt32(pointerToRawData); - } - - private readonly static byte[] s_zeroStamp = new byte[4]; // four bytes of zero - - /// - /// Write the entire "Debug Directory (Image Only)" along with data that it points to. - /// - private void WriteDebugTable(Stream peStream, SectionHeader textSection, ContentId nativePdbContentId, ContentId portablePdbContentId, MetadataSizes metadataSizes) - { - int tableSize = ImageDebugDirectoryBaseSize; - Debug.Assert(tableSize != 0); - Debug.Assert(nativePdbContentId.IsDefault || portablePdbContentId.IsDefault); - Debug.Assert(!EmitPdb || (nativePdbContentId.IsDefault ^ portablePdbContentId.IsDefault)); - - var writer = PooledBlobBuilder.GetInstance(); - - int dataSize = ComputeSizeOfDebugDirectoryData(); - if (this.EmitPdb) - { - const int IMAGE_DEBUG_TYPE_CODEVIEW = 2; // from PE spec - uint dataOffset = (uint)(ComputeOffsetToDebugTable(metadataSizes) + tableSize); - WriteDebugTableEntry(writer, - stamp: nativePdbContentId.Stamp ?? portablePdbContentId.Stamp, - version: portablePdbContentId.IsDefault ? (uint)0 : ('P' << 24 | 'M' << 16 | 0x01 << 8 | 0x00), - debugType: IMAGE_DEBUG_TYPE_CODEVIEW, - sizeOfData: (uint)dataSize, - addressOfRawData: (uint)textSection.RelativeVirtualAddress + dataOffset, // RVA of the data - pointerToRawData: (uint)textSection.PointerToRawData + dataOffset); // position of the data in the PE stream - } - - if (_deterministic) - { - const int IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16; // from PE spec - WriteDebugTableEntry(writer, - stamp: s_zeroStamp, - version: 0, - debugType: IMAGE_DEBUG_TYPE_NO_TIMESTAMP, - sizeOfData: 0, - addressOfRawData: 0, - pointerToRawData: 0); - } - - // We should now have written all and precisely the data we said we'd write for the table entries. - Debug.Assert(writer.Count == tableSize); - - // ==================== - // The following is additional data beyond the debug directory at the offset `dataOffset` - // pointed to by the ImageDebugTypeCodeView entry. - - if (EmitPdb) - { - writer.WriteByte((byte)'R'); - writer.WriteByte((byte)'S'); - writer.WriteByte((byte)'D'); - writer.WriteByte((byte)'S'); - - // PDB id: - writer.WriteBytes(nativePdbContentId.Guid ?? portablePdbContentId.Guid); - - // age - writer.WriteUInt32(PdbWriter.Age); - - // UTF-8 encoded zero-terminated path to PDB - int pathStart = writer.Position; - writer.WriteUTF8(_pdbPathOpt, allowUnpairedSurrogates: true); - writer.WriteByte(0); - - // padding: - writer.WriteBytes(0, Math.Max(0, _minPdbPath - (writer.Position - pathStart))); - } - - // We should now have written all and precisely the data we said we'd write for the table and its data. - Debug.Assert(writer.Count == tableSize + dataSize); - - writer.WriteContentTo(peStream); - writer.Free(); - } - - private void WriteRuntimeStartupStub(Stream peStream, int importAddressTableRva) - { - var writer = new BlobBuilder(16); - // entry point code, consisting of a jump indirect to _CorXXXMain - if (_is32bit) - { - //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. - for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 4) - peStream.Position); i < n; i++) - { - writer.WriteByte(0); - } - - writer.WriteUInt16(0); - writer.WriteByte(0xff); - writer.WriteByte(0x25); //4 - writer.WriteUInt32((uint)importAddressTableRva + (uint)_properties.BaseAddress); //8 - } - else - { - //emit 0's (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. - for (uint i = 0, n = (uint)(BitArithmeticUtilities.Align((uint)peStream.Position, 8) - peStream.Position); i < n; i++) - { - writer.WriteByte(0); - } - - writer.WriteUInt32(0); - writer.WriteUInt16(0); - writer.WriteByte(0xff); - writer.WriteByte(0x25); //8 - writer.WriteUInt64((ulong)importAddressTableRva + _properties.BaseAddress); //16 - } - - writer.WriteContentTo(peStream); - } - - private void WriteRelocSection(Stream peStream, SectionHeader relocSection, int entryPointAddress) - { - peStream.Position = relocSection.PointerToRawData; - var writer = new BlobBuilder(relocSection.SizeOfRawData); - writer.WriteUInt32((((uint)entryPointAddress + 2) / 0x1000) * 0x1000); - writer.WriteUInt32(_properties.Requires64bits && !_properties.RequiresAmdInstructionSet ? 14u : 12u); - uint offsetWithinPage = ((uint)entryPointAddress + 2) % 0x1000; - uint relocType = _properties.Requires64bits ? 10u : 3u; - ushort s = (ushort)((relocType << 12) | offsetWithinPage); - writer.WriteUInt16(s); - if (_properties.Requires64bits && !_properties.RequiresAmdInstructionSet) - { - writer.WriteUInt32(relocType << 12); - } - - writer.WriteUInt16(0); // next chunk's RVA - writer.PadTo(relocSection.SizeOfRawData); - writer.WriteContentTo(peStream); - } - - private void WriteResourceSection(Stream peStream, SectionHeader resourceSection) - { - peStream.Position = resourceSection.PointerToRawData; - _win32ResourceWriter.PadTo(resourceSection.SizeOfRawData); - _win32ResourceWriter.WriteContentTo(peStream); + return (keySize < 128 + 32) ? 128 : keySize - 32; } } } diff --git a/src/Compilers/Core/Portable/PEWriter/PooledBlobBuilder.cs b/src/Compilers/Core/Portable/PEWriter/PooledBlobBuilder.cs index 01b84c58efad2..179577ffe0a9f 100644 --- a/src/Compilers/Core/Portable/PEWriter/PooledBlobBuilder.cs +++ b/src/Compilers/Core/Portable/PEWriter/PooledBlobBuilder.cs @@ -1,9 +1,12 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Reflection; using Roslyn.Utilities; namespace Microsoft.Cci { + using Roslyn.Reflection; + internal sealed class PooledBlobBuilder : BlobBuilder { private const int PoolSize = 128; diff --git a/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs b/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs index 5cf891b251993..6e99ea9dc9300 100644 --- a/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs +++ b/src/Compilers/Core/Portable/PEWriter/ReferenceIndexer.cs @@ -107,7 +107,7 @@ public void VisitMethodBodyReference(IReference reference) protected override void RecordAssemblyReference(IAssemblyReference assemblyReference) { - this.metadataWriter.GetAssemblyRefIndex(assemblyReference); + this.metadataWriter.GetAssemblyReferenceHandle(assemblyReference); } protected override void ProcessMethodBody(IMethodDefinition method) @@ -167,37 +167,37 @@ private void VisitImports(ImmutableArray imports) protected override void RecordTypeReference(ITypeReference typeReference) { - this.metadataWriter.RecordTypeReference(typeReference); + this.metadataWriter.GetTypeHandle(typeReference); } protected override void RecordTypeMemberReference(ITypeMemberReference typeMemberReference) { - this.metadataWriter.GetMemberRefIndex(typeMemberReference); + this.metadataWriter.GetMemberReferenceHandle(typeMemberReference); } protected override void RecordFileReference(IFileReference fileReference) { - this.metadataWriter.GetFileRefIndex(fileReference); + this.metadataWriter.GetAssemblyFileHandle(fileReference); } protected override void ReserveMethodToken(IMethodReference methodReference) { - this.metadataWriter.GetMethodToken(methodReference); + this.metadataWriter.GetMethodHandle(methodReference); } protected override void ReserveFieldToken(IFieldReference fieldReference) { - this.metadataWriter.GetFieldToken(fieldReference); + this.metadataWriter.GetFieldHandle(fieldReference); } protected override void RecordModuleReference(IModuleReference moduleReference) { - this.metadataWriter.GetModuleRefIndex(moduleReference.Name); + this.metadataWriter.GetModuleReferenceHandle(moduleReference.Name); } public override void Visit(IPlatformInvokeInformation platformInvokeInformation) { - this.metadataWriter.GetModuleRefIndex(platformInvokeInformation.ModuleName); + this.metadataWriter.GetModuleReferenceHandle(platformInvokeInformation.ModuleName); } } } diff --git a/src/Compilers/Core/Portable/PEWriter/SectionHeader.cs b/src/Compilers/Core/Portable/PEWriter/SectionHeader.cs deleted file mode 100644 index 223e7d2c963c4..0000000000000 --- a/src/Compilers/Core/Portable/PEWriter/SectionHeader.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Reflection.PortableExecutable; - -namespace Microsoft.Cci -{ - // TODO: merge with System.Reflection.PortableExecutable.SectionHeader - internal sealed class SectionHeader - { - internal readonly string Name; - internal readonly int VirtualSize; - internal readonly int RelativeVirtualAddress; - internal readonly int SizeOfRawData; - internal readonly int PointerToRawData; - internal readonly int PointerToRelocations; - internal readonly int PointerToLinenumbers; - internal readonly ushort NumberOfRelocations; - internal readonly ushort NumberOfLinenumbers; - internal readonly SectionCharacteristics Characteristics; - - public SectionHeader( - string name, - int virtualSize, - int relativeVirtualAddress, - int sizeOfRawData, - int pointerToRawData, - int pointerToRelocations, - int pointerToLinenumbers, - ushort numberOfRelocations, - ushort numberOfLinenumbers, - SectionCharacteristics characteristics) - { - Name = name; - VirtualSize = virtualSize; - RelativeVirtualAddress = relativeVirtualAddress; - SizeOfRawData = sizeOfRawData; - PointerToRawData = pointerToRawData; - PointerToRelocations = pointerToRelocations; - PointerToLinenumbers = pointerToLinenumbers; - NumberOfRelocations = numberOfRelocations; - NumberOfLinenumbers = numberOfLinenumbers; - Characteristics = characteristics; - } - } -} diff --git a/src/Compilers/Core/Portable/PEWriter/Types.cs b/src/Compilers/Core/Portable/PEWriter/Types.cs index 9e3d084df435d..cda215ea359ed 100644 --- a/src/Compilers/Core/Portable/PEWriter/Types.cs +++ b/src/Compilers/Core/Portable/PEWriter/Types.cs @@ -42,7 +42,7 @@ bool IsSZArray /// A possibly empty list of lower bounds for dimension indices. When not explicitly specified, a lower bound defaults to zero. /// The first lower bound in the list corresponds to the first dimension. Dimensions cannot be skipped. /// - IEnumerable LowerBounds + ImmutableArray LowerBounds { get; // ^ ensures count(result) <= Rank; @@ -51,7 +51,7 @@ IEnumerable LowerBounds /// /// The number of array dimensions. /// - uint Rank + int Rank { get; // ^ ensures result > 0; @@ -62,7 +62,7 @@ uint Rank /// The first upper bound in the list corresponds to the first dimension. Dimensions cannot be skipped. /// An unspecified upper bound means that instances of this type can have an arbitrary upper bound for that dimension. /// - IEnumerable Sizes + ImmutableArray Sizes { get; // ^ ensures count(result) <= Rank; @@ -705,49 +705,34 @@ internal enum PrimitiveTypeCode internal enum TypeMemberVisibility { /// - /// The visibility has not been specified. Use the applicable default. - /// - Default, - - /// - /// The member is visible only within its own assembly. - /// - Assembly, - - /// - /// The member is visible only within its own type and any subtypes. + /// The member is visible only within its own type. /// - Family, + Private = 1, /// /// The member is visible only within the intersection of its family (its own type and any subtypes) and assembly. /// - FamilyAndAssembly, + FamilyAndAssembly = 2, /// - /// The member is visible only within the union of its family and assembly. + /// The member is visible only within its own assembly. /// - FamilyOrAssembly, + Assembly = 3, /// - /// The member is visible only to the compiler producing its assembly. + /// The member is visible only within its own type and any subtypes. /// - Other, + Family = 4, /// - /// The member is visible only within its own type. + /// The member is visible only within the union of its family and assembly. /// - Private, + FamilyOrAssembly = 5, /// /// The member is visible everywhere its declaring type is visible. /// - Public, - - /// - /// A mask that can be used to mask out flag bits when the latter are stored in the same memory word as this enumeration. - /// - Mask = 0xF + Public = 6 } /// @@ -758,23 +743,18 @@ internal enum TypeParameterVariance /// /// Two type or method instances are compatible only if they have exactly the same type argument for this parameter. /// - NonVariant, + NonVariant = 0, /// /// A type or method instance will match another instance if it has a type for this parameter that is the same or a subtype of the type the /// other instance has for this parameter. /// - Covariant, + Covariant = 1, /// /// A type or method instance will match another instance if it has a type for this parameter that is the same or a supertype of the type the /// other instance has for this parameter. /// - Contravariant, - - /// - /// A mask that can be used to mask out flag bits when the latter are stored in the same memory word as the enumeration. - /// - Mask = 3, + Contravariant = 2, } } diff --git a/src/Compilers/Core/Portable/PEWriter/Units.cs b/src/Compilers/Core/Portable/PEWriter/Units.cs index 2d0061a177921..4c93b6d096cb1 100644 --- a/src/Compilers/Core/Portable/PEWriter/Units.cs +++ b/src/Compilers/Core/Portable/PEWriter/Units.cs @@ -29,7 +29,7 @@ internal interface IAssembly : IModule, IAssemblyReference /// A set of bits and bit ranges representing properties of the assembly. The value of can be set /// from source code via the AssemblyFlags assembly custom attribute. The interpretation of the property depends on the target platform. /// - uint Flags { get; } + AssemblyFlags Flags { get; } /// /// The public part of the key used to encrypt the SHA1 hash over the persisted form of this assembly. Empty or null if not specified. @@ -101,7 +101,7 @@ internal interface IModule : IUnit, IModuleReference /// /// A list of named byte sequences persisted with the assembly and used during execution, typically via .NET Framework helper classes. /// - IEnumerable GetResources(EmitContext context); + ImmutableArray GetResources(EmitContext context); /// /// CorLibrary assembly referenced by this module. diff --git a/src/Compilers/Core/Portable/StrongName/DesktopStrongNameProvider.cs b/src/Compilers/Core/Portable/StrongName/DesktopStrongNameProvider.cs index 3a958598bbb66..52af49b113a01 100644 --- a/src/Compilers/Core/Portable/StrongName/DesktopStrongNameProvider.cs +++ b/src/Compilers/Core/Portable/StrongName/DesktopStrongNameProvider.cs @@ -172,6 +172,7 @@ internal string ResolveStrongNameKeyFile(string path) return null; } + /// internal override Stream CreateInputStream() { var path = PortableShim.Path.GetTempFileName(); diff --git a/src/Compilers/Core/Portable/StrongName/StrongNameProvider.cs b/src/Compilers/Core/Portable/StrongName/StrongNameProvider.cs index 681e9571b90b6..cffe90ea61d71 100644 --- a/src/Compilers/Core/Portable/StrongName/StrongNameProvider.cs +++ b/src/Compilers/Core/Portable/StrongName/StrongNameProvider.cs @@ -16,6 +16,7 @@ protected StrongNameProvider() public abstract override bool Equals(object other); public abstract override int GetHashCode(); + /// internal abstract Stream CreateInputStream(); internal abstract StrongNameKeys CreateKeys(string keyFilePath, string keyContainerName, CommonMessageProvider messageProvider); diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/CommonAssemblyWellKnownAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/CommonAssemblyWellKnownAttributeData.cs index 7b2009fac0ad1..e68997e7d2062 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/CommonAssemblyWellKnownAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/CommonAssemblyWellKnownAttributeData.cs @@ -270,8 +270,8 @@ public string AssemblyTrademarkAttributeSetting #endregion #region AssemblyFlagsAttributeSetting - private AssemblyNameFlags _assemblyFlagsAttributeSetting; - public AssemblyNameFlags AssemblyFlagsAttributeSetting + private AssemblyFlags _assemblyFlagsAttributeSetting; + public AssemblyFlags AssemblyFlagsAttributeSetting { get { diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodWellKnownAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodWellKnownAttributeData.cs index efb0eb64b4903..38047c29c8a54 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodWellKnownAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodWellKnownAttributeData.cs @@ -63,7 +63,7 @@ public void SetMethodImplementation(int attributeIndex, MethodImplAttributes att } // used by DllImportAttribute - public void SetDllImport(int attributeIndex, string moduleName, string entryPointName, Cci.PInvokeAttributes flags, bool preserveSig) + public void SetDllImport(int attributeIndex, string moduleName, string entryPointName, MethodImportAttributes flags, bool preserveSig) { VerifySealed(expected: false); Debug.Assert(attributeIndex >= 0); diff --git a/src/Compilers/Core/Portable/Symbols/PlatformInvokeInformation.cs b/src/Compilers/Core/Portable/Symbols/PlatformInvokeInformation.cs index 76b03f6ce745a..06173f5f48d5c 100644 --- a/src/Compilers/Core/Portable/Symbols/PlatformInvokeInformation.cs +++ b/src/Compilers/Core/Portable/Symbols/PlatformInvokeInformation.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Reflection; using System.Runtime.InteropServices; using Roslyn.Utilities; @@ -12,9 +13,9 @@ public sealed class DllImportData : Cci.IPlatformInvokeInformation { private readonly string _moduleName; private readonly string _entryPointName; // null if unspecified, the name of the target method should be used - private readonly Cci.PInvokeAttributes _flags; + private readonly MethodImportAttributes _flags; - internal DllImportData(string moduleName, string entryPointName, Cci.PInvokeAttributes flags) + internal DllImportData(string moduleName, string entryPointName, MethodImportAttributes flags) { _moduleName = moduleName; _entryPointName = entryPointName; @@ -37,7 +38,7 @@ public string EntryPointName get { return _entryPointName; } } - Cci.PInvokeAttributes Cci.IPlatformInvokeInformation.Flags + MethodImportAttributes Cci.IPlatformInvokeInformation.Flags { get { return _flags; } } @@ -50,7 +51,7 @@ public bool ExactSpelling { get { - return (_flags & Cci.PInvokeAttributes.NoMangle) != 0; + return (_flags & MethodImportAttributes.ExactSpelling) != 0; } } @@ -61,15 +62,15 @@ public CharSet CharacterSet { get { - switch (_flags & Cci.PInvokeAttributes.CharSetMask) + switch (_flags & MethodImportAttributes.CharSetMask) { - case Cci.PInvokeAttributes.CharSetAnsi: + case MethodImportAttributes.CharSetAnsi: return CharSet.Ansi; - case Cci.PInvokeAttributes.CharSetUnicode: + case MethodImportAttributes.CharSetUnicode: return CharSet.Unicode; - case Cci.PInvokeAttributes.CharSetAuto: + case MethodImportAttributes.CharSetAuto: return Cci.Constants.CharSet_Auto; case 0: @@ -87,7 +88,7 @@ public bool SetLastError { get { - return (_flags & Cci.PInvokeAttributes.SupportsLastError) != 0; + return (_flags & MethodImportAttributes.SetLastError) != 0; } } @@ -98,21 +99,21 @@ public CallingConvention CallingConvention { get { - switch (_flags & Cci.PInvokeAttributes.CallConvMask) + switch (_flags & MethodImportAttributes.CallingConventionMask) { default: return CallingConvention.Winapi; - case Cci.PInvokeAttributes.CallConvCdecl: + case MethodImportAttributes.CallingConventionCDecl: return CallingConvention.Cdecl; - case Cci.PInvokeAttributes.CallConvStdcall: + case MethodImportAttributes.CallingConventionStdCall: return CallingConvention.StdCall; - case Cci.PInvokeAttributes.CallConvThiscall: + case MethodImportAttributes.CallingConventionThisCall: return CallingConvention.ThisCall; - case Cci.PInvokeAttributes.CallConvFastcall: + case MethodImportAttributes.CallingConventionFastCall: return Cci.Constants.CallingConvention_FastCall; } } @@ -126,12 +127,12 @@ public bool? BestFitMapping { get { - switch (_flags & Cci.PInvokeAttributes.BestFitMask) + switch (_flags & MethodImportAttributes.BestFitMappingMask ) { - case Cci.PInvokeAttributes.BestFitEnabled: + case MethodImportAttributes.BestFitMappingEnable: return true; - case Cci.PInvokeAttributes.BestFitDisabled: + case MethodImportAttributes.BestFitMappingDisable: return false; default: @@ -148,12 +149,12 @@ public bool? ThrowOnUnmappableCharacter { get { - switch (_flags & Cci.PInvokeAttributes.ThrowOnUnmappableCharMask) + switch (_flags & MethodImportAttributes.ThrowOnUnmappableCharMask) { - case Cci.PInvokeAttributes.ThrowOnUnmappableCharEnabled: + case MethodImportAttributes.ThrowOnUnmappableCharEnable: return true; - case Cci.PInvokeAttributes.ThrowOnUnmappableCharDisabled: + case MethodImportAttributes.ThrowOnUnmappableCharDisable: return false; default: @@ -162,26 +163,26 @@ public bool? ThrowOnUnmappableCharacter } } - internal static Cci.PInvokeAttributes MakeFlags(bool noMangle, CharSet charSet, bool setLastError, CallingConvention callingConvention, bool? useBestFit, bool? throwOnUnmappable) + internal static MethodImportAttributes MakeFlags(bool exactSpelling, CharSet charSet, bool setLastError, CallingConvention callingConvention, bool? useBestFit, bool? throwOnUnmappable) { - Cci.PInvokeAttributes result = 0; - if (noMangle) + MethodImportAttributes result = 0; + if (exactSpelling) { - result |= Cci.PInvokeAttributes.NoMangle; + result |= MethodImportAttributes.ExactSpelling; } switch (charSet) { case CharSet.Ansi: - result |= Cci.PInvokeAttributes.CharSetAnsi; + result |= MethodImportAttributes.CharSetAnsi; break; case CharSet.Unicode: - result |= Cci.PInvokeAttributes.CharSetUnicode; + result |= MethodImportAttributes.CharSetUnicode; break; case Cci.Constants.CharSet_Auto: - result |= Cci.PInvokeAttributes.CharSetAuto; + result |= MethodImportAttributes.CharSetAuto; break; // Dev10: use default without reporting an error @@ -189,29 +190,29 @@ internal static Cci.PInvokeAttributes MakeFlags(bool noMangle, CharSet charSet, if (setLastError) { - result |= Cci.PInvokeAttributes.SupportsLastError; + result |= MethodImportAttributes.SetLastError; } switch (callingConvention) { default: // Dev10: uses default without reporting an error - result |= Cci.PInvokeAttributes.CallConvWinapi; + result |= MethodImportAttributes.CallingConventionWinApi; break; case CallingConvention.Cdecl: - result |= Cci.PInvokeAttributes.CallConvCdecl; + result |= MethodImportAttributes.CallingConventionCDecl; break; case CallingConvention.StdCall: - result |= Cci.PInvokeAttributes.CallConvStdcall; + result |= MethodImportAttributes.CallingConventionStdCall; break; case CallingConvention.ThisCall: - result |= Cci.PInvokeAttributes.CallConvThiscall; + result |= MethodImportAttributes.CallingConventionThisCall; break; case Cci.Constants.CallingConvention_FastCall: - result |= Cci.PInvokeAttributes.CallConvFastcall; + result |= MethodImportAttributes.CallingConventionFastCall; break; } @@ -219,11 +220,11 @@ internal static Cci.PInvokeAttributes MakeFlags(bool noMangle, CharSet charSet, { if (throwOnUnmappable.Value) { - result |= Cci.PInvokeAttributes.ThrowOnUnmappableCharEnabled; + result |= MethodImportAttributes.ThrowOnUnmappableCharEnable; } else { - result |= Cci.PInvokeAttributes.ThrowOnUnmappableCharDisabled; + result |= MethodImportAttributes.ThrowOnUnmappableCharDisable; } } @@ -231,11 +232,11 @@ internal static Cci.PInvokeAttributes MakeFlags(bool noMangle, CharSet charSet, { if (useBestFit.Value) { - result |= Cci.PInvokeAttributes.BestFitEnabled; + result |= MethodImportAttributes.BestFitMappingEnable; } else { - result |= Cci.PInvokeAttributes.BestFitDisabled; + result |= MethodImportAttributes.BestFitMappingDisable; } } diff --git a/src/Compilers/Core/Portable/SynthesizedLocalKind.cs b/src/Compilers/Core/Portable/SynthesizedLocalKind.cs index 146d35d7fb52d..bc527479667c8 100644 --- a/src/Compilers/Core/Portable/SynthesizedLocalKind.cs +++ b/src/Compilers/Core/Portable/SynthesizedLocalKind.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Reflection.Metadata; using Microsoft.CodeAnalysis.Emit; namespace Microsoft.CodeAnalysis @@ -261,14 +262,14 @@ public static bool IsSlotReusable(this SynthesizedLocalKind kind, bool isDebug) } } - public static uint PdbAttributes(this SynthesizedLocalKind kind) + public static LocalVariableAttributes PdbAttributes(this SynthesizedLocalKind kind) { // Marking variables with hidden attribute is only needed for compat with Dev12 EE. // We mark all synthesized locals, other than lambda display class as hidden so that they don't show up in Dev12 EE. // Display class is special - it is used by the EE to access variables lifted into a closure. return (kind != SynthesizedLocalKind.LambdaDisplayClass && kind != SynthesizedLocalKind.UserDefined && kind != SynthesizedLocalKind.With) - ? Cci.PdbWriter.HiddenLocalAttributesValue - : Cci.PdbWriter.DefaultLocalAttributesValue; + ? LocalVariableAttributes.DebuggerHidden + : LocalVariableAttributes.None; } } } diff --git a/src/Compilers/Core/Portable/System/Reflection/Blob.cs b/src/Compilers/Core/Portable/System/Reflection/Blob.cs new file mode 100644 index 0000000000000..620860135de33 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Blob.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +#if SRM +namespace System.Reflection +#else +namespace Roslyn.Reflection +#endif +{ +#if SRM + public +#endif + struct Blob + { + internal readonly byte[] Buffer; + internal readonly int Start; + public int Length { get; } + + internal Blob(byte[] buffer, int start, int length) + { + Buffer = buffer; + Start = start; + Length = length; + } + + public bool IsDefault => Buffer == null; + + public ArraySegment GetBytes() => new ArraySegment(Buffer, Start, Length); + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/BlobBuilder.Enumerators.cs b/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.Enumerators.cs similarity index 97% rename from src/Compilers/Core/Portable/PEWriter/BlobBuilder.Enumerators.cs rename to src/Compilers/Core/Portable/System/Reflection/BlobBuilder.Enumerators.cs index 4db6bc2fa1060..0aa26121921f3 100644 --- a/src/Compilers/Core/Portable/PEWriter/BlobBuilder.Enumerators.cs +++ b/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.Enumerators.cs @@ -1,11 +1,15 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Diagnostics; using System.Collections; using System.Collections.Generic; +using System; -namespace Microsoft.Cci +#if SRM +namespace System.Reflection +#else +namespace Roslyn.Reflection +#endif { internal partial class BlobBuilder { diff --git a/src/Compilers/Core/Portable/PEWriter/BlobBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs similarity index 96% rename from src/Compilers/Core/Portable/PEWriter/BlobBuilder.cs rename to src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs index 5d4ff7414cf4f..775e6427c8a92 100644 --- a/src/Compilers/Core/Portable/PEWriter/BlobBuilder.cs +++ b/src/Compilers/Core/Portable/System/Reflection/BlobBuilder.cs @@ -1,22 +1,32 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; -using Microsoft.CodeAnalysis; + +#if SRM +using System.Reflection.Internal; +using BitArithmeticUtilities = System.Reflection.Internal.BitArithmetic; +#else using Microsoft.CodeAnalysis.Collections; using Roslyn.Utilities; +#endif -namespace Microsoft.Cci +#if SRM +namespace System.Reflection +#else +namespace Roslyn.Reflection +#endif { [DebuggerDisplay("{GetDebuggerDisplay(),nq}")] - internal unsafe partial class BlobBuilder +#if SRM + public +#endif + unsafe partial class BlobBuilder { // The implementation is akin to StringBuilder. // The differences: @@ -316,7 +326,7 @@ public ImmutableArray ToImmutableArray() public ImmutableArray ToImmutableArray(int start, int byteCount) { var array = ToArray(start, byteCount); - return ImmutableArrayInterop.DangerousToImmutableArray(ref array); + return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref array); } /// is null. @@ -557,7 +567,7 @@ private void Expand(int newLength) /// /// is negative. /// Builder is not writable, it has been linked with another one. - public BlobWriter ReserveBytes(int byteCount) + public Blob ReserveBytes(int byteCount) { if (byteCount < 0) { @@ -565,7 +575,7 @@ public BlobWriter ReserveBytes(int byteCount) } int start = ReserveBytesImpl(byteCount); - return new BlobWriter(_buffer, start, byteCount); + return new Blob(_buffer, start, byteCount); } private int ReserveBytesImpl(int byteCount) @@ -721,7 +731,7 @@ public void WriteBytes(ImmutableArray buffer) /// Builder is not writable, it has been linked with another one. public void WriteBytes(ImmutableArray buffer, int start, int byteCount) { - WriteBytes(ImmutableArrayInterop.DangerousGetUnderlyingArray(buffer), start, byteCount); + WriteBytes(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(buffer), start, byteCount); } /// is null. @@ -820,14 +830,26 @@ public void WriteUInt16(ushort value) } /// Builder is not writable, it has been linked with another one. - internal void WriteUInt16BE(ushort value) + public void WriteInt16BE(short value) + { + WriteUInt16BE(unchecked((ushort)value)); + } + + /// Builder is not writable, it has been linked with another one. + public void WriteUInt16BE(ushort value) { int start = ReserveBytesPrimitive(sizeof(ushort)); _buffer.WriteUInt16BE(start, value); } /// Builder is not writable, it has been linked with another one. - internal void WriteUInt32BE(uint value) + public void WriteInt32BE(int value) + { + WriteUInt32BE(unchecked((uint)value)); + } + + /// Builder is not writable, it has been linked with another one. + public void WriteUInt32BE(uint value) { int start = ReserveBytesPrimitive(sizeof(uint)); _buffer.WriteUInt32BE(start, value); @@ -999,7 +1021,7 @@ private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurr if (prependSize) { - WriteCompressedInteger((uint)(bytesToCurrent + bytesToNext)); + WriteCompressedInteger(bytesToCurrent + bytesToNext); } _buffer.WriteUTF8(Length, currentPtr, charsToCurrent, bytesToCurrent, allowUnpairedSurrogates); @@ -1030,7 +1052,7 @@ private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurr /// /// can't be represented as a compressed signed integer. /// Builder is not writable, it has been linked with another one. - internal void WriteCompressedSignedInteger(int value) + public void WriteCompressedSignedInteger(int value) { BlobWriterImpl.WriteCompressedSignedInteger(this, value); } @@ -1043,13 +1065,13 @@ internal void WriteCompressedSignedInteger(int value) /// encode as a one-byte integer (bit 7 is clear, value held in bits 6 through 0). /// /// If the value lies between 28 (0x80) and 214 – 1 (0x3FFF), inclusive, - /// encode as a 2-byte integer with bit 15 set, bit 14 clear(value held in bits 13 through 0). + /// encode as a 2-byte integer with bit 15 set, bit 14 clear (value held in bits 13 through 0). /// /// Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set, bit 29 clear (value held in bits 28 through 0). /// /// can't be represented as a compressed integer. /// Builder is not writable, it has been linked with another one. - internal void WriteCompressedInteger(uint value) + public void WriteCompressedInteger(int value) { BlobWriterImpl.WriteCompressedInteger(this, value); } diff --git a/src/Compilers/Core/Portable/PEWriter/BlobWriter.cs b/src/Compilers/Core/Portable/System/Reflection/BlobWriter.cs similarity index 93% rename from src/Compilers/Core/Portable/PEWriter/BlobWriter.cs rename to src/Compilers/Core/Portable/System/Reflection/BlobWriter.cs index 2c44871a272a6..ad51eba2e166b 100644 --- a/src/Compilers/Core/Portable/PEWriter/BlobWriter.cs +++ b/src/Compilers/Core/Portable/System/Reflection/BlobWriter.cs @@ -6,14 +6,26 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + +#if SRM +using System.Reflection.Internal; +using BitArithmeticUtilities = System.Reflection.Internal.BitArithmetic; +#else using Microsoft.CodeAnalysis.Collections; using Roslyn.Utilities; +#endif -namespace Microsoft.Cci +#if SRM +namespace System.Reflection +#else +namespace Roslyn.Reflection +#endif { // TODO: argument checking - - internal unsafe struct BlobWriter +#if SRM + public +#endif + unsafe struct BlobWriter { // writable slice: private readonly byte[] _buffer; @@ -33,7 +45,10 @@ public BlobWriter(byte[] buffer) { } - internal bool IsDefault => _buffer == null; + public BlobWriter(Blob blob) + : this(blob.Buffer, blob.Start, blob.Length) + { + } public BlobWriter(byte[] buffer, int start, int count) { @@ -49,6 +64,8 @@ public BlobWriter(byte[] buffer, int start, int count) _end = start + count; } + internal bool IsDefault => _buffer == null; + /// /// Compares the current content of this writer with another one. /// @@ -76,6 +93,7 @@ public int Offset public int Length => _end - _start; public int RemainingBytes => _end - _position; + public Blob Blob => new Blob(_buffer, _start, Length); public byte[] ToArray() { @@ -101,7 +119,7 @@ public ImmutableArray ToImmutableArray() public ImmutableArray ToImmutableArray(int start, int byteCount) { var array = ToArray(start, byteCount); - return ImmutableArrayInterop.DangerousToImmutableArray(ref array); + return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref array); } private int Advance(int value) @@ -201,7 +219,7 @@ public void WriteBytes(ImmutableArray buffer) /// Range specified by and falls outside of the bounds of the . public void WriteBytes(ImmutableArray buffer, int start, int byteCount) { - WriteBytes(ImmutableArrayInterop.DangerousGetUnderlyingArray(buffer), start, byteCount); + WriteBytes(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(buffer), start, byteCount); } /// is null. @@ -283,13 +301,23 @@ public void WriteUInt16(ushort value) _buffer.WriteUInt16(start, value); } - internal void WriteUInt16BE(ushort value) + public void WriteInt16BE(short value) + { + WriteUInt16BE(unchecked((ushort)value)); + } + + public void WriteUInt16BE(ushort value) { int start = Advance(sizeof(ushort)); _buffer.WriteUInt16BE(start, value); } - internal void WriteUInt32BE(uint value) + public void WriteInt32BE(int value) + { + WriteUInt32BE(unchecked((uint)value)); + } + + public void WriteUInt32BE(uint value) { int start = Advance(sizeof(uint)); _buffer.WriteUInt32BE(start, value); @@ -427,7 +455,7 @@ private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurr if (prependSize) { - WriteCompressedInteger((uint)byteCount); + WriteCompressedInteger(byteCount); } int startOffset = Advance(byteCount); @@ -467,7 +495,7 @@ public void WriteCompressedSignedInteger(int value) /// Otherwise, encode as a 4-byte integer, with bit 31 set, bit 30 set, bit 29 clear (value held in bits 28 through 0). /// /// can't be represented as a compressed signed integer. - public void WriteCompressedInteger(uint value) + public void WriteCompressedInteger(int value) { BlobWriterImpl.WriteCompressedInteger(ref this, value); } diff --git a/src/Compilers/Core/Portable/PEWriter/BlobWriterImpl.cs b/src/Compilers/Core/Portable/System/Reflection/BlobWriterImpl.cs similarity index 87% rename from src/Compilers/Core/Portable/PEWriter/BlobWriterImpl.cs rename to src/Compilers/Core/Portable/System/Reflection/BlobWriterImpl.cs index 66ea1a631b37e..b2ebcecf80f4e 100644 --- a/src/Compilers/Core/Portable/PEWriter/BlobWriterImpl.cs +++ b/src/Compilers/Core/Portable/System/Reflection/BlobWriterImpl.cs @@ -5,41 +5,14 @@ using System.Reflection; using System.Runtime.CompilerServices; -namespace Microsoft.Cci +#if SRM +namespace System.Reflection +#else +namespace Roslyn.Reflection +#endif { internal static class BlobWriterImpl { - // Performance considerations: - // Ideally we wouldn't need to have duplicate implementations of the bellow methods and use - // the following pattern. However, the JIT currently doesn't inline the interface calls. - // - // interface IPrimitiveWriter - // { - // void WriteByte(byte value); - // void WriteUInt16BE(ushort value); - // void WriteUInt32BE(uint value); - // ... - // } - // - // static class BlobWriterImpl where T : struct, IPrimitiveWriter - // { - // public static void WriteCompressedInteger(ref T writer, uint value) - // { - // if (...) - // { - // writer.WriteByte((byte)value); - // } - // else if (...) - // { - // writer.WriteUInt16BE((ushort)value); - // } - // else if (...) - // { - // writer.WriteUInt32BE(value); - // } - // } - // } - internal const int SingleByteCompressedIntegerMaxValue = 0x7f; internal const int TwoByteCompressedIntegerMaxValue = 0x3fff; internal const int MaxCompressedIntegerValue = 0x1fffffff; @@ -67,7 +40,7 @@ private static void ThrowValueArgumentOutOfRange() throw new ArgumentOutOfRangeException("value"); } - internal static void WriteCompressedInteger(ref BlobWriter writer, uint value) + internal static void WriteCompressedInteger(ref BlobWriter writer, int value) { unchecked { @@ -81,7 +54,7 @@ internal static void WriteCompressedInteger(ref BlobWriter writer, uint value) } else if (value <= MaxCompressedIntegerValue) { - writer.WriteUInt32BE(0xc0000000 | value); + writer.WriteUInt32BE(0xc0000000 | (uint)value); } else { @@ -90,7 +63,7 @@ internal static void WriteCompressedInteger(ref BlobWriter writer, uint value) } } - internal static void WriteCompressedInteger(BlobBuilder writer, uint value) + internal static void WriteCompressedInteger(BlobBuilder writer, int value) { unchecked { @@ -104,7 +77,7 @@ internal static void WriteCompressedInteger(BlobBuilder writer, uint value) } else if (value <= MaxCompressedIntegerValue) { - writer.WriteUInt32BE(0xc0000000 | value); + writer.WriteUInt32BE(0xc0000000 | (uint)value); } else { diff --git a/src/Compilers/Core/Portable/PEWriter/BlobUtilities.cs b/src/Compilers/Core/Portable/System/Reflection/Internal/Utilities/BlobUtilities.cs similarity index 98% rename from src/Compilers/Core/Portable/PEWriter/BlobUtilities.cs rename to src/Compilers/Core/Portable/System/Reflection/Internal/Utilities/BlobUtilities.cs index 72e3dbbc97ce3..4ca1d19015767 100644 --- a/src/Compilers/Core/Portable/PEWriter/BlobUtilities.cs +++ b/src/Compilers/Core/Portable/System/Reflection/Internal/Utilities/BlobUtilities.cs @@ -2,9 +2,18 @@ using System; using System.Diagnostics; + +#if SRM +using System.Reflection.Internal; +#else using Roslyn.Utilities; +#endif -namespace Microsoft.Cci +#if SRM +namespace System.Reflection +#else +namespace Roslyn.Reflection +#endif { internal unsafe static class BlobUtilities { diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/BlobEncoders.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/BlobEncoders.cs new file mode 100644 index 0000000000000..89ec2ad29c236 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/BlobEncoders.cs @@ -0,0 +1,923 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#pragma warning disable RS0008 // Implement IEquatable when overriding Object.Equals + +using System; +using System.Collections.Immutable; +using System.ComponentModel; +using System.Diagnostics; +using System.Reflection.Metadata; + +#if !SRM +using PrimitiveTypeCode = Microsoft.Cci.PrimitiveTypeCode; +#endif + +#if SRM +namespace System.Reflection.Metadata.Ecma335.Blobs +#else +namespace Roslyn.Reflection.Metadata.Ecma335.Blobs +#endif +{ + // TODO: arg validation + // TODO: can we hide useless inherited methods? + // TODO: debug metadata blobs + // TODO: revisit ctors (public vs internal)? + + //[EditorBrowsable(EditorBrowsableState.Never)] + //public override bool Equals(object obj) => base.Equals(obj); + //[EditorBrowsable(EditorBrowsableState.Never)] + //public override int GetHashCode() => base.GetHashCode(); + //[EditorBrowsable(EditorBrowsableState.Never)] + //public override string ToString() => base.ToString(); + +#if SRM + public +#endif + struct BlobEncoder + { + public BlobBuilder Builder { get; } + + public BlobEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public SignatureTypeEncoder FieldSignature() + { + Builder.WriteByte((byte)SignatureKind.Field); + return new SignatureTypeEncoder(Builder); + } + + public GenericTypeArgumentsEncoder MethodSpecificationSignature(int genericArgumentCount) + { + // TODO: arg validation + + Builder.WriteByte((byte)SignatureKind.MethodSpecification); + Builder.WriteCompressedInteger(genericArgumentCount); + + return new GenericTypeArgumentsEncoder(Builder); + } + + public MethodSignatureEncoder MethodSignature( + SignatureCallingConvention convention = SignatureCallingConvention.Default, + int genericParameterCount = 0, + bool isInstanceMethod = false) + { + // TODO: arg validation + + var attributes = + (genericParameterCount != 0 ? SignatureAttributes.Generic : 0) | + (isInstanceMethod ? SignatureAttributes.Instance : 0); + + Builder.WriteByte(SignatureHeader(SignatureKind.Method, convention, attributes).RawValue); + + if (genericParameterCount != 0) + { + Builder.WriteCompressedInteger(genericParameterCount); + } + + return new MethodSignatureEncoder(Builder, isVarArg: convention == SignatureCallingConvention.VarArgs); + } + + public MethodSignatureEncoder PropertySignature(bool isInstanceProperty = false) + { + Builder.WriteByte(SignatureHeader(SignatureKind.Property, SignatureCallingConvention.Default, (isInstanceProperty ? SignatureAttributes.Instance : 0)).RawValue); + return new MethodSignatureEncoder(Builder, isVarArg: false); + } + + public void CustomAttributeSignature(out FixedArgumentsEncoder fixedArguments, out CustomAttributeNamedArgumentsEncoder namedArguments) + { + Builder.WriteUInt16(0x0001); + + fixedArguments = new FixedArgumentsEncoder(Builder); + namedArguments = new CustomAttributeNamedArgumentsEncoder(Builder); + } + + public LocalVariablesEncoder LocalVariableSignature(int count) + { + Builder.WriteByte((byte)SignatureKind.LocalVariables); + Builder.WriteCompressedInteger(count); + return new LocalVariablesEncoder(Builder); + } + + // TODO: TypeSpec is limited to structured types (doesn't have primitive types, TypeDefRefSpec, custom modifiers) + public SignatureTypeEncoder TypeSpecificationSignature() + { + return new SignatureTypeEncoder(Builder); + } + + public PermissionSetEncoder PermissionSetBlob(int attributeCount) + { + Builder.WriteByte((byte)'.'); + Builder.WriteCompressedInteger(attributeCount); + return new PermissionSetEncoder(Builder); + } + + public NamedArgumentsEncoder PermissionSetArguments(int argumentCount) + { + Builder.WriteCompressedInteger(argumentCount); + return new NamedArgumentsEncoder(Builder); + } + + // TOOD: add ctor to SignatureHeader + internal static SignatureHeader SignatureHeader(SignatureKind kind, SignatureCallingConvention convention, SignatureAttributes attributes) + { + return new SignatureHeader((byte)((int)kind | (int)convention | (int)attributes)); + } + } + +#if SRM + public +#endif + struct MethodSignatureEncoder + { + public BlobBuilder Builder { get; } + private readonly bool _isVarArg; + + public MethodSignatureEncoder(BlobBuilder builder, bool isVarArg) + { + Builder = builder; + _isVarArg = isVarArg; + } + + public void Parameters(int parameterCount, out ReturnTypeEncoder returnType, out ParametersEncoder parameters) + { + Builder.WriteCompressedInteger(parameterCount); + + returnType = new ReturnTypeEncoder(Builder); + parameters = new ParametersEncoder(Builder, allowVarArgs: _isVarArg); + } + } + +#if SRM + public +#endif + struct LocalVariablesEncoder + { + public BlobBuilder Builder { get; } + + public LocalVariablesEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public LocalVariableTypeEncoder AddVariable() + { + return new LocalVariableTypeEncoder(Builder); + } + + public void EndVariables() + { + } + } + +#if SRM + public +#endif + struct LocalVariableTypeEncoder + { + public BlobBuilder Builder { get; } + + public LocalVariableTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public CustomModifiersEncoder CustomModifiers() + { + return new CustomModifiersEncoder(Builder); + } + + public SignatureTypeEncoder Type(bool isByRef = false, bool isPinned = false) + { + if (isPinned) + { + Builder.WriteByte((byte)SignatureTypeCode.Pinned); + } + + if (isByRef) + { + Builder.WriteByte((byte)SignatureTypeCode.ByReference); + } + + return new SignatureTypeEncoder(Builder); + } + + public void TypedReference() + { + Builder.WriteByte((byte)SignatureTypeCode.TypedReference); + } + } + +#if SRM + public +#endif + struct ParameterTypeEncoder + { + public BlobBuilder Builder { get; } + + public ParameterTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public CustomModifiersEncoder CustomModifiers() + { + return new CustomModifiersEncoder(Builder); + } + + public SignatureTypeEncoder Type(bool isByRef = false) + { + if (isByRef) + { + Builder.WriteByte((byte)SignatureTypeCode.ByReference); + } + + return new SignatureTypeEncoder(Builder); + } + + public void TypedReference() + { + Builder.WriteByte((byte)SignatureTypeCode.TypedReference); + } + } + +#if SRM + public +#endif + struct PermissionSetEncoder + { + public BlobBuilder Builder { get; } + + public PermissionSetEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public PermissionSetEncoder AddPermission(string typeName, BlobBuilder arguments) + { + Builder.WriteSerializedString(typeName); + Builder.WriteCompressedInteger(arguments.Count); + arguments.WriteContentTo(Builder); + return new PermissionSetEncoder(Builder); + } + + public void EndPermissions() + { + } + } + +#if SRM + public +#endif + struct GenericTypeArgumentsEncoder + { + public BlobBuilder Builder { get; } + + public GenericTypeArgumentsEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public SignatureTypeEncoder AddArgument() + { + return new SignatureTypeEncoder(Builder); + } + + public void EndArguments() + { + } + } + +#if SRM + public +#endif + struct FixedArgumentsEncoder + { + public BlobBuilder Builder { get; } + + public FixedArgumentsEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public LiteralEncoder AddArgument() + { + return new LiteralEncoder(Builder); + } + + public void EndArguments() + { + } + } + +#if SRM + public +#endif + struct LiteralEncoder + { + public BlobBuilder Builder { get; } + + public LiteralEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public VectorEncoder Vector() + { + return new VectorEncoder(Builder); + } + + public void TaggedVector(out CustomAttributeArrayTypeEncoder arrayType, out VectorEncoder vector) + { + arrayType = new CustomAttributeArrayTypeEncoder(Builder); + vector = new VectorEncoder(Builder); + } + + public ScalarEncoder Scalar() + { + return new ScalarEncoder(Builder); + } + + public void TaggedScalar(out CustomAttributeElementTypeEncoder type, out ScalarEncoder scalar) + { + type = new CustomAttributeElementTypeEncoder(Builder); + scalar = new ScalarEncoder(Builder); + } + } + +#if SRM + public +#endif + struct ScalarEncoder + { + public BlobBuilder Builder { get; } + + public ScalarEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public void NullArray() + { + Builder.WriteInt32(-1); + } + + public void Constant(object value) + { + string str = value as string; + if (str != null || value == null) + { + String(str); + } + else + { + Builder.WriteConstant(value); + } + } + + public void SystemType(string serializedTypeName) + { + String(serializedTypeName); + } + + private void String(string value) + { + Builder.WriteSerializedString(value); + } + } + +#if SRM + public +#endif + struct LiteralsEncoder + { + public BlobBuilder Builder { get; } + + public LiteralsEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public LiteralEncoder AddLiteral() + { + return new LiteralEncoder(Builder); + } + + public void EndLiterals() + { + } + } + +#if SRM + public +#endif + struct VectorEncoder + { + public BlobBuilder Builder { get; } + + public VectorEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public LiteralsEncoder Count(int count) + { + Builder.WriteUInt32((uint)count); + return new LiteralsEncoder(Builder); + } + } + +#if SRM + public +#endif + struct NameEncoder + { + public BlobBuilder Builder { get; } + + public NameEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public void Name(string name) + { + Builder.WriteSerializedString(name); + } + } + +#if SRM + public +#endif + struct CustomAttributeNamedArgumentsEncoder + { + public BlobBuilder Builder { get; } + + public CustomAttributeNamedArgumentsEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public NamedArgumentsEncoder Count(int count) + { + if (unchecked((ushort)count) > ushort.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + + Builder.WriteUInt16((ushort)count); + return new NamedArgumentsEncoder(Builder); + } + } + +#if SRM + public +#endif + struct NamedArgumentsEncoder + { + public BlobBuilder Builder { get; } + + public NamedArgumentsEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public void AddArgument(bool isField, out NamedArgumentTypeEncoder typeEncoder, out NameEncoder name, out LiteralEncoder literal) + { + Builder.WriteByte(isField ? (byte)0x53 : (byte)0x54); + typeEncoder = new NamedArgumentTypeEncoder(Builder); + name = new NameEncoder(Builder); + literal = new LiteralEncoder(Builder); + } + + public void EndArguments() + { + } + } + +#if SRM + public +#endif + struct NamedArgumentTypeEncoder + { + public BlobBuilder Builder { get; } + + public NamedArgumentTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public CustomAttributeElementTypeEncoder ScalarType() + { + return new CustomAttributeElementTypeEncoder(Builder); + } + + public void Object() + { + Builder.WriteByte(0x51); // OBJECT + } + + public CustomAttributeArrayTypeEncoder SZArray() + { + return new CustomAttributeArrayTypeEncoder(Builder); + } + } + +#if SRM + public +#endif + struct CustomAttributeArrayTypeEncoder + { + public BlobBuilder Builder { get; } + + public CustomAttributeArrayTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public void ObjectArray() + { + Builder.WriteByte((byte)SignatureTypeCode.SZArray); + Builder.WriteByte(0x51); // OBJECT + } + + public CustomAttributeElementTypeEncoder ElementType() + { + Builder.WriteByte((byte)SignatureTypeCode.SZArray); + return new CustomAttributeElementTypeEncoder(Builder); + } + } + +#if SRM + public +#endif + struct CustomAttributeElementTypeEncoder + { + public BlobBuilder Builder { get; } + + public CustomAttributeElementTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + private void WriteTypeCode(SignatureTypeCode value) + { + Builder.WriteByte((byte)value); + } + + public void Boolean() => WriteTypeCode(SignatureTypeCode.Boolean); + public void Char() => WriteTypeCode(SignatureTypeCode.Char); + public void Int8() => WriteTypeCode(SignatureTypeCode.SByte); + public void UInt8() => WriteTypeCode(SignatureTypeCode.Byte); + public void Int16() => WriteTypeCode(SignatureTypeCode.Int16); + public void UInt16() => WriteTypeCode(SignatureTypeCode.UInt16); + public void Int32() => WriteTypeCode(SignatureTypeCode.Int32); + public void UInt32() => WriteTypeCode(SignatureTypeCode.UInt32); + public void Int64() => WriteTypeCode(SignatureTypeCode.Int64); + public void UInt64() => WriteTypeCode(SignatureTypeCode.UInt64); + public void Float32() => WriteTypeCode(SignatureTypeCode.Single); + public void Float64() => WriteTypeCode(SignatureTypeCode.Double); + public void String() => WriteTypeCode(SignatureTypeCode.String); + public void IntPtr() => WriteTypeCode(SignatureTypeCode.IntPtr); + public void UIntPtr() => WriteTypeCode(SignatureTypeCode.UIntPtr); + +#if !SRM + public void PrimitiveType(PrimitiveTypeCode type) + { + switch (type) + { + case PrimitiveTypeCode.Boolean: Boolean(); return; + case PrimitiveTypeCode.Char: Char(); return; + case PrimitiveTypeCode.Int8: Int8(); return; + case PrimitiveTypeCode.UInt8: UInt8(); return; + case PrimitiveTypeCode.Int16: Int16(); return; + case PrimitiveTypeCode.UInt16: UInt16(); return; + case PrimitiveTypeCode.Int32: Int32(); return; + case PrimitiveTypeCode.UInt32: UInt32(); return; + case PrimitiveTypeCode.Int64: Int64(); return; + case PrimitiveTypeCode.UInt64: UInt64(); return; + case PrimitiveTypeCode.Float32: Float32(); return; + case PrimitiveTypeCode.Float64: Float64(); return; + case PrimitiveTypeCode.String: String(); return; + case PrimitiveTypeCode.IntPtr: IntPtr(); return; + case PrimitiveTypeCode.UIntPtr: UIntPtr(); return; + + default: + throw new InvalidOperationException(); + } + } +#endif + public void SystemType() + { + Builder.WriteByte(0x50); // TYPE + } + + public void Enum(string enumTypeName) + { + Builder.WriteByte(0x55); // ENUM + Builder.WriteSerializedString(enumTypeName); + } + } + +#if SRM + public +#endif + enum FunctionPointerAttributes + { + None = SignatureAttributes.None, + HasThis = SignatureAttributes.Instance, + HasExplicitThis = SignatureAttributes.Instance | SignatureAttributes.ExplicitThis + } + +#if SRM + public +#endif + struct SignatureTypeEncoder + { + public BlobBuilder Builder { get; } + + public SignatureTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + private void WriteTypeCode(SignatureTypeCode value) + { + Builder.WriteByte((byte)value); + } + + private void ClassOrValue(bool isValueType) + { + Builder.WriteByte(isValueType ? (byte)0x11 : (byte)0x12); // CLASS|VALUETYPE + } + + public void Boolean() => WriteTypeCode(SignatureTypeCode.Boolean); + public void Char() => WriteTypeCode(SignatureTypeCode.Char); + public void Int8() => WriteTypeCode(SignatureTypeCode.SByte); + public void UInt8() => WriteTypeCode(SignatureTypeCode.Byte); + public void Int16() => WriteTypeCode(SignatureTypeCode.Int16); + public void UInt16() => WriteTypeCode(SignatureTypeCode.UInt16); + public void Int32() => WriteTypeCode(SignatureTypeCode.Int32); + public void UInt32() => WriteTypeCode(SignatureTypeCode.UInt32); + public void Int64() => WriteTypeCode(SignatureTypeCode.Int64); + public void UInt64() => WriteTypeCode(SignatureTypeCode.UInt64); + public void Float32() => WriteTypeCode(SignatureTypeCode.Single); + public void Float64() => WriteTypeCode(SignatureTypeCode.Double); + public void String() => WriteTypeCode(SignatureTypeCode.String); + public void IntPtr() => WriteTypeCode(SignatureTypeCode.IntPtr); + public void UIntPtr() => WriteTypeCode(SignatureTypeCode.UIntPtr); + +#if !SRM + public void PrimitiveType(PrimitiveTypeCode type) + { + switch (type) + { + case PrimitiveTypeCode.Boolean: Boolean(); return; + case PrimitiveTypeCode.Char: Char(); return; + case PrimitiveTypeCode.Int8: Int8(); return; + case PrimitiveTypeCode.UInt8: UInt8(); return; + case PrimitiveTypeCode.Int16: Int16(); return; + case PrimitiveTypeCode.UInt16: UInt16(); return; + case PrimitiveTypeCode.Int32: Int32(); return; + case PrimitiveTypeCode.UInt32: UInt32(); return; + case PrimitiveTypeCode.Int64: Int64(); return; + case PrimitiveTypeCode.UInt64: UInt64(); return; + case PrimitiveTypeCode.Float32: Float32(); return; + case PrimitiveTypeCode.Float64: Float64(); return; + case PrimitiveTypeCode.String: String(); return; + case PrimitiveTypeCode.IntPtr: IntPtr(); return; + case PrimitiveTypeCode.UIntPtr: UIntPtr(); return; + default: + throw new InvalidOperationException(); + } + } +#endif + public void Object() => WriteTypeCode(SignatureTypeCode.Object); + + public void Array(out SignatureTypeEncoder elementType, out ArrayShapeEncoder arrayShape) + { + Builder.WriteByte((byte)SignatureTypeCode.Array); + elementType = this; + arrayShape = new ArrayShapeEncoder(Builder); + } + + public void TypeDefOrRefOrSpec(bool isValueType, EntityHandle typeRefDefSpec) + { + ClassOrValue(isValueType); + Builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(typeRefDefSpec)); + } + + public MethodSignatureEncoder FunctionPointer(SignatureCallingConvention convention, FunctionPointerAttributes attributes, int genericParameterCount) + { + // Spec: + // The EXPLICITTHIS (0x40) bit can be set only in signatures for function pointers. + // If EXPLICITTHIS (0x40) in the signature is set, then HASTHIS (0x20) shall also be set. + + if (attributes != FunctionPointerAttributes.None && + attributes != FunctionPointerAttributes.HasThis && + attributes != FunctionPointerAttributes.HasExplicitThis) + { + throw new ArgumentException(nameof(attributes)); + } + + Builder.WriteByte((byte)SignatureTypeCode.FunctionPointer); + Builder.WriteByte(BlobEncoder.SignatureHeader(SignatureKind.Method, convention, (SignatureAttributes)attributes).RawValue); + + if (genericParameterCount != 0) + { + Builder.WriteCompressedInteger(genericParameterCount); + } + + return new MethodSignatureEncoder(Builder, isVarArg: convention == SignatureCallingConvention.VarArgs); + } + + public GenericTypeArgumentsEncoder GenericInstantiation(bool isValueType, EntityHandle typeRefDefSpec, int genericArgumentCount) + { + Builder.WriteByte((byte)SignatureTypeCode.GenericTypeInstance); + ClassOrValue(isValueType); + Builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(typeRefDefSpec)); + Builder.WriteCompressedInteger(genericArgumentCount); + return new GenericTypeArgumentsEncoder(Builder); + } + + public void GenericMethodTypeParameter(int parameterIndex) + { + Builder.WriteByte((byte)SignatureTypeCode.GenericMethodParameter); + Builder.WriteCompressedInteger(parameterIndex); + } + + public void GenericTypeParameter(int parameterIndex) + { + Builder.WriteByte((byte)SignatureTypeCode.GenericTypeParameter); + Builder.WriteCompressedInteger(parameterIndex); + } + + public SignatureTypeEncoder Pointer() + { + Builder.WriteByte((byte)SignatureTypeCode.Pointer); + return this; + } + + public void VoidPointer() + { + Builder.WriteByte((byte)SignatureTypeCode.Pointer); + Builder.WriteByte((byte)SignatureTypeCode.Void); + } + + public SignatureTypeEncoder SZArray() + { + Builder.WriteByte((byte)SignatureTypeCode.SZArray); + return this; + } + + public CustomModifiersEncoder CustomModifiers() + { + return new CustomModifiersEncoder(Builder); + } + } + +#if SRM + public +#endif + struct CustomModifiersEncoder + { + public BlobBuilder Builder { get; } + + public CustomModifiersEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public CustomModifiersEncoder AddModifier(bool isOptional, EntityHandle typeDefRefSpec) + { + if (isOptional) + { + Builder.WriteByte((byte)SignatureTypeCode.OptionalModifier); + } + else + { + Builder.WriteByte((byte)SignatureTypeCode.RequiredModifier); + } + + Builder.WriteCompressedInteger(CodedIndex.ToTypeDefOrRefOrSpec(typeDefRefSpec)); + return this; + } + + public void EndModifiers() + { + } + } + +#if SRM + public +#endif + struct ArrayShapeEncoder + { + public BlobBuilder Builder { get; } + + public ArrayShapeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public void Shape(int rank, ImmutableArray sizes, ImmutableArray lowerBounds) + { + Builder.WriteCompressedInteger(rank); + Builder.WriteCompressedInteger(sizes.Length); + foreach (int size in sizes) + { + Builder.WriteCompressedInteger(size); + } + + if (lowerBounds.IsDefault) + { + Builder.WriteCompressedInteger(rank); + for (int i = 0; i < rank; i++) + { + Builder.WriteCompressedSignedInteger(0); + } + } + else + { + Builder.WriteCompressedInteger(lowerBounds.Length); + foreach (int lowerBound in lowerBounds) + { + Builder.WriteCompressedSignedInteger(lowerBound); + } + } + } + } + +#if SRM + public +#endif + struct ReturnTypeEncoder + { + public BlobBuilder Builder { get; } + + public ReturnTypeEncoder(BlobBuilder builder) + { + Builder = builder; + } + + public CustomModifiersEncoder CustomModifiers() + { + return new CustomModifiersEncoder(Builder); + } + + public SignatureTypeEncoder Type(bool isByRef = false) + { + if (isByRef) + { + Builder.WriteByte((byte)SignatureTypeCode.ByReference); + } + + return new SignatureTypeEncoder(Builder); + } + + public void TypedReference() + { + Builder.WriteByte((byte)SignatureTypeCode.TypedReference); + } + + public void Void() + { + Builder.WriteByte((byte)SignatureTypeCode.Void); + } + } + +#if SRM + public +#endif + struct ParametersEncoder + { + public BlobBuilder Builder { get; } + private readonly bool _allowOptional; + + public ParametersEncoder(BlobBuilder builder, bool allowVarArgs) + { + Builder = builder; + _allowOptional = allowVarArgs; + } + + public ParameterTypeEncoder AddParameter() + { + return new ParameterTypeEncoder(Builder); + } + + public ParametersEncoder StartVarArgs() + { + if (!_allowOptional) + { + throw new InvalidOperationException(); + } + + Builder.WriteByte((byte)SignatureTypeCode.Sentinel); + return new ParametersEncoder(Builder, allowVarArgs: false); + } + + public void EndParameters() + { + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/BranchBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/BranchBuilder.cs new file mode 100644 index 0000000000000..9fcf043eef6b4 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/BranchBuilder.cs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; + +#if !SRM +using Microsoft.CodeAnalysis.CodeGen; +#endif + +#if SRM +namespace System.Reflection.Metadata.Ecma335.Blobs +#else +namespace Roslyn.Reflection.Metadata.Ecma335.Blobs +#endif +{ +#if SRM + public +#endif + sealed class BranchBuilder + { + // internal for testing: + internal struct BranchInfo + { + internal readonly int ILOffset; + internal readonly LabelHandle Label; + internal readonly byte ShortOpCode; + + internal BranchInfo(int ilOffset, LabelHandle label, byte shortOpCode) + { + ILOffset = ilOffset; + Label = label; + ShortOpCode = shortOpCode; + } + + internal bool IsShortBranchDistance(ImmutableArray.Builder labels, out int distance) + { + const int shortBranchSize = 2; + const int longBranchSize = 5; + + int labelTargetOffset = labels[Label.Id - 1]; + + distance = labelTargetOffset - (ILOffset + shortBranchSize); + if (unchecked((sbyte)distance) == distance) + { + return true; + } + + distance = labelTargetOffset - (ILOffset + longBranchSize); + return false; + } + } + + private readonly ImmutableArray.Builder _branches; + private readonly ImmutableArray.Builder _labels; + + public BranchBuilder() + { + _branches = ImmutableArray.CreateBuilder(); + _labels = ImmutableArray.CreateBuilder(); + } + + internal void Clear() + { + _branches.Clear(); + _labels.Clear(); + } + + internal LabelHandle AddLabel() + { + _labels.Add(-1); + return new LabelHandle(_labels.Count); + } + + internal void AddBranch(int ilOffset, LabelHandle label, byte shortOpCode) + { + Debug.Assert(ilOffset >= 0); + Debug.Assert(_branches.Count == 0 || ilOffset > _branches.Last().ILOffset); + ValidateLabel(label); + _branches.Add(new BranchInfo(ilOffset, label, shortOpCode)); + } + + internal void MarkLabel(int ilOffset, LabelHandle label) + { + Debug.Assert(ilOffset >= 0); + ValidateLabel(label); + _labels[label.Id - 1] = ilOffset; + } + + private void ValidateLabel(LabelHandle label) + { + if (label.IsNil) + { + throw new ArgumentNullException(nameof(label)); + } + + if (label.Id > _labels.Count) + { + // TODO: localize + throw new ArgumentException("Label not defined", nameof(label)); + } + } + + // internal for testing: + internal IEnumerable Branches => _branches; + + // internal for testing: + internal IEnumerable Labels => _labels; + + internal int BranchCount => _branches.Count; + + internal void FixupBranches(BlobBuilder srcBuilder, BlobBuilder dstBuilder) + { + int srcOffset = 0; + var branch = _branches[0]; + int branchIndex = 0; + int blobOffset = 0; + foreach (Blob blob in srcBuilder.GetBlobs()) + { + Debug.Assert(blobOffset == 0 || blobOffset == 1 && blob.Buffer[blobOffset - 1] == 0xff); + + while (true) + { + // copy bytes preceding the next branch, or till the end of the blob: + int chunkSize = Math.Min(branch.ILOffset - srcOffset, blob.Length - blobOffset); + dstBuilder.WriteBytes(blob.Buffer, blobOffset, chunkSize); + srcOffset += chunkSize; + blobOffset += chunkSize; + + // there is no branch left in the blob: + if (blobOffset == blob.Length) + { + blobOffset = 0; + break; + } + + Debug.Assert(blob.Buffer[blobOffset] == branch.ShortOpCode && (blobOffset + 1 == blob.Length || blob.Buffer[blobOffset + 1] == 0xff)); + srcOffset += sizeof(byte) + sizeof(sbyte); + + // write actual branch instruction: + int branchDistance; + if (branch.IsShortBranchDistance(_labels, out branchDistance)) + { + dstBuilder.WriteByte(branch.ShortOpCode); + dstBuilder.WriteSByte((sbyte)branchDistance); + } + else + { + dstBuilder.WriteByte((byte)((ILOpCode)branch.ShortOpCode).GetLongBranch()); + dstBuilder.WriteInt32(branchDistance); + } + + // next branch: + branchIndex++; + if (branchIndex == _branches.Count) + { + branch = new BranchInfo(int.MaxValue, default(LabelHandle), 0); + } + else + { + branch = _branches[branchIndex]; + } + + // the branch starts at the very end and its operand is in the next blob: + if (blobOffset == blob.Length - 1) + { + blobOffset = 1; + break; + } + + // skip fake branch instruction: + blobOffset += sizeof(byte) + sizeof(sbyte); + } + } + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/ExceptionRegionEncoder.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/ExceptionRegionEncoder.cs new file mode 100644 index 0000000000000..e007a2b20f282 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/ExceptionRegionEncoder.cs @@ -0,0 +1,156 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +#if SRM +namespace System.Reflection.Metadata.Ecma335.Blobs +#else +namespace Roslyn.Reflection.Metadata.Ecma335.Blobs +#endif +{ +#if SRM + public +#endif + struct ExceptionRegionEncoder + { + private readonly int _exceptionRegionCount; + private readonly bool _isSmallFormat; + public BlobBuilder Builder { get; } + + internal ExceptionRegionEncoder(BlobBuilder builder, int exceptionRegionCount, bool hasLargeRegions) + { + Builder = builder; + _exceptionRegionCount = exceptionRegionCount; + _isSmallFormat = !hasLargeRegions && IsSmallRegionCount(exceptionRegionCount); + } + + public void StartRegions() + { + if (_exceptionRegionCount == 0) + { + return; + } + + const byte EHTableFlag = 0x01; + const byte FatFormatFlag = 0x40; + + int dataSize = GetExceptionTableSize(_exceptionRegionCount, _isSmallFormat); + + Builder.Align(4); + if (_isSmallFormat) + { + Builder.WriteByte(EHTableFlag); + Builder.WriteByte((byte)(dataSize & 0xff)); + Builder.WriteInt16(0); + } + else + { + Builder.WriteByte(EHTableFlag | FatFormatFlag); + Builder.WriteByte((byte)(dataSize & 0xff)); + Builder.WriteUInt16((ushort)((dataSize >> 8) & 0xffff)); + } + } + + public static bool IsSmallRegionCount(int exceptionRegionCount) + { + return GetExceptionTableSize(exceptionRegionCount, isSmallFormat: true) <= 0xff; + } + + public static bool IsSmallExceptionRegion(int startOffset, int length) + { + return startOffset <= 0xffff && length <= 0xff; + } + + internal static int GetExceptionTableSize(int exceptionRegionCount, bool isSmallFormat) + { + const int HeaderSize = 4; + + const int SmallRegionSize = + sizeof(short) + // Flags + sizeof(short) + // TryOffset + sizeof(byte) + // TryLength + sizeof(short) + // HandlerOffset + sizeof(byte) + // HandleLength + sizeof(int); // ClassToken | FilterOffset + + const int FatRegionSize = + sizeof(int) + // Flags + sizeof(int) + // TryOffset + sizeof(int) + // TryLength + sizeof(int) + // HandlerOffset + sizeof(int) + // HandleLength + sizeof(int); // ClassToken | FilterOffset + + return HeaderSize + exceptionRegionCount * (isSmallFormat ? SmallRegionSize : FatRegionSize); + } + + public void AddFinally(int tryOffset, int tryLength, int handlerOffset, int handlerLength) + { + AddRegion(ExceptionRegionKind.Finally, tryOffset, tryLength, handlerOffset, handlerLength, default(EntityHandle), 0); + } + + public void AddFault(int tryOffset, int tryLength, int handlerOffset, int handlerLength) + { + AddRegion(ExceptionRegionKind.Fault, tryOffset, tryLength, handlerOffset, handlerLength, default(EntityHandle), 0); + } + + public void AddCatch(int tryOffset, int tryLength, int handlerOffset, int handlerLength, EntityHandle catchType) + { + AddRegion(ExceptionRegionKind.Catch, tryOffset, tryLength, handlerOffset, handlerLength, catchType, 0); + } + + public void AddFilter(int tryOffset, int tryLength, int handlerOffset, int handlerLength, int filterOffset) + { + AddRegion(ExceptionRegionKind.Filter, tryOffset, tryLength, handlerOffset, handlerLength, default(EntityHandle), filterOffset); + } + + public void AddRegion( + ExceptionRegionKind kind, + int tryOffset, + int tryLength, + int handlerOffset, + int handlerLength, + EntityHandle catchType, + int filterOffset) + { + if (_isSmallFormat) + { + Builder.WriteUInt16((ushort)kind); + Builder.WriteUInt16((ushort)tryOffset); + Builder.WriteByte((byte)tryLength); + Builder.WriteUInt16((ushort)handlerOffset); + Builder.WriteByte((byte)handlerLength); + } + else + { + Builder.WriteInt32((int)kind); + Builder.WriteInt32(tryOffset); + Builder.WriteInt32(tryLength); + Builder.WriteInt32(handlerOffset); + Builder.WriteInt32(handlerLength); + } + + switch (kind) + { + case ExceptionRegionKind.Catch: + Builder.WriteInt32(MetadataTokens.GetToken(catchType)); + break; + + case ExceptionRegionKind.Filter: + Builder.WriteInt32(filterOffset); + break; + + default: + Builder.WriteInt32(0); + break; + } + } + + public void EndRegions() + { + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/InstructionEncoder.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/InstructionEncoder.cs new file mode 100644 index 0000000000000..5609183464c99 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/InstructionEncoder.cs @@ -0,0 +1,285 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +#if SRM +namespace System.Reflection.Metadata.Ecma335.Blobs +#else +namespace Roslyn.Reflection.Metadata.Ecma335.Blobs +#endif +{ +#if !SRM + using Microsoft.CodeAnalysis.CodeGen; +#endif + +#if SRM + public +#endif + struct InstructionEncoder + { + public BlobBuilder Builder { get; } + private readonly BranchBuilder _branchBuilderOpt; + + public InstructionEncoder(BlobBuilder builder, BranchBuilder branchBuilder = null) + { + Builder = builder; + _branchBuilderOpt = branchBuilder; + } + + public int Offset => Builder.Count; + + public void OpCode(ILOpCode code) + { + if (unchecked((byte)code) == (ushort)code) + { + Builder.WriteByte((byte)code); + } + else + { + // IL opcodes that occupy two bytes are written to + // the byte stream with the high-order byte first, + // in contrast to the little-endian format of the + // numeric arguments and tokens. + Builder.WriteUInt16BE((ushort)code); + } + } + + public void Token(EntityHandle handle) + { + Token(MetadataTokens.GetToken(handle)); + } + + public void Token(int token) + { + Builder.WriteInt32(token); + } + + public void LongBranchTarget(int ilOffset) + { + Builder.WriteInt32(ilOffset); + } + + public void ShortBranchTarget(byte ilOffset) + { + Builder.WriteByte(ilOffset); + } + + public void LoadString(UserStringHandle handle) + { + OpCode(ILOpCode.Ldstr); + Token(MetadataTokens.GetToken(handle)); + } + + public void Call(EntityHandle methodHandle) + { + OpCode(ILOpCode.Call); + Token(methodHandle); + } + + public void CallIndirect(StandaloneSignatureHandle signature) + { + OpCode(ILOpCode.Calli); + Token(signature); + } + + public void LoadConstantI4(int value) + { + ILOpCode code; + switch (value) + { + case -1: code = ILOpCode.Ldc_i4_m1; break; + case 0: code = ILOpCode.Ldc_i4_0; break; + case 1: code = ILOpCode.Ldc_i4_1; break; + case 2: code = ILOpCode.Ldc_i4_2; break; + case 3: code = ILOpCode.Ldc_i4_3; break; + case 4: code = ILOpCode.Ldc_i4_4; break; + case 5: code = ILOpCode.Ldc_i4_5; break; + case 6: code = ILOpCode.Ldc_i4_6; break; + case 7: code = ILOpCode.Ldc_i4_7; break; + case 8: code = ILOpCode.Ldc_i4_8; break; + + default: + if (unchecked((sbyte)value == value)) + { + OpCode(ILOpCode.Ldc_i4_s); + Builder.WriteSByte(unchecked((sbyte)value)); + } + else + { + OpCode(ILOpCode.Ldc_i4); + Builder.WriteInt32(value); + } + + return; + } + + OpCode(code); + } + + public void LoadConstantI8(long value) + { + OpCode(ILOpCode.Ldc_i8); + Builder.WriteInt64(value); + } + + public void LoadConstantR4(float value) + { + OpCode(ILOpCode.Ldc_r4); + Builder.WriteSingle(value); + } + + public void LoadConstantR8(double value) + { + OpCode(ILOpCode.Ldc_r8); + Builder.WriteDouble(value); + } + + public void LoadLocal(int slotIndex) + { + switch (slotIndex) + { + case 0: OpCode(ILOpCode.Ldloc_0); break; + case 1: OpCode(ILOpCode.Ldloc_1); break; + case 2: OpCode(ILOpCode.Ldloc_2); break; + case 3: OpCode(ILOpCode.Ldloc_3); break; + default: + if (slotIndex < 0xFF) + { + OpCode(ILOpCode.Ldloc_s); + Builder.WriteByte(unchecked((byte)slotIndex)); + } + else + { + OpCode(ILOpCode.Ldloc); + Builder.WriteInt32(slotIndex); + } + break; + } + } + + public void StoreLocal(int slotIndex) + { + switch (slotIndex) + { + case 0: OpCode(ILOpCode.Stloc_0); break; + case 1: OpCode(ILOpCode.Stloc_1); break; + case 2: OpCode(ILOpCode.Stloc_2); break; + case 3: OpCode(ILOpCode.Stloc_3); break; + default: + if (slotIndex < 0xFF) + { + OpCode(ILOpCode.Stloc_s); + Builder.WriteByte(unchecked((byte)slotIndex)); + } + else + { + OpCode(ILOpCode.Stloc); + Builder.WriteInt32(slotIndex); + } + break; + } + } + + public void LoadLocalAddress(int slotIndex) + { + if (slotIndex < 0xFF) + { + OpCode(ILOpCode.Ldloca_s); + Builder.WriteByte(unchecked((byte)slotIndex)); + } + else + { + OpCode(ILOpCode.Ldloca); + Builder.WriteInt32(slotIndex); + } + } + + public void LoadArgument(int argumentIndex) + { + switch (argumentIndex) + { + case 0: OpCode(ILOpCode.Ldarg_0); break; + case 1: OpCode(ILOpCode.Ldarg_1); break; + case 2: OpCode(ILOpCode.Ldarg_2); break; + case 3: OpCode(ILOpCode.Ldarg_3); break; + default: + if (argumentIndex < 0xFF) + { + OpCode(ILOpCode.Ldarg_s); + Builder.WriteByte(unchecked((byte)argumentIndex)); + } + else + { + OpCode(ILOpCode.Ldarg); + Builder.WriteInt32(argumentIndex); + } + break; + } + } + + public void LoadArgumentAddress(int argumentIndex) + { + if (argumentIndex < 0xFF) + { + OpCode(ILOpCode.Ldarga_s); + Builder.WriteByte(unchecked((byte)argumentIndex)); + } + else + { + OpCode(ILOpCode.Ldarga); + Builder.WriteInt32(argumentIndex); + } + } + + public void StoreArgument(int argumentIndex) + { + if (argumentIndex < 0xFF) + { + OpCode(ILOpCode.Starg_s); + Builder.WriteByte(unchecked((byte)argumentIndex)); + } + else + { + OpCode(ILOpCode.Starg); + Builder.WriteInt32(argumentIndex); + } + } + + public LabelHandle DefineLabel() + { + return GetBranchBuilder().AddLabel(); + } + + public void Branch(ILOpCode code, LabelHandle label) + { + // throws if code is not a branch: + ILOpCode shortCode = code.GetShortBranch(); + + GetBranchBuilder().AddBranch(Offset, label, (byte)shortCode); + OpCode(shortCode); + + // -1 points in the middle of the branch instruction and is thus invalid. + // We want to produce invalid IL so that if the caller doesn't patch the branches + // the branch instructions will be invalid in an obvious way. + Builder.WriteSByte(-1); + } + + public void MarkLabel(LabelHandle label) + { + GetBranchBuilder().MarkLabel(Offset, label); + } + + private BranchBuilder GetBranchBuilder() + { + if (_branchBuilderOpt == null) + { + // TODO: localize + throw new InvalidOperationException(nameof(InstructionEncoder) + " created without a branch builder"); + } + + return _branchBuilderOpt; + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/LabelHandle.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/LabelHandle.cs new file mode 100644 index 0000000000000..6edb6c969f352 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/LabelHandle.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; + +#if SRM +namespace System.Reflection.Metadata.Ecma335.Blobs +#else +namespace Roslyn.Reflection.Metadata.Ecma335.Blobs +#endif +{ +#if SRM + public +#endif + struct LabelHandle : IEquatable + { + // 1-based + internal readonly int Id; + + internal LabelHandle(int id) + { + Debug.Assert(id >= 1); + Id = id; + } + + public bool IsNil => Id == 0; + + public bool Equals(LabelHandle other) => Id == other.Id; + public override bool Equals(object obj) => obj is LabelHandle && Equals((LabelHandle)obj); + public override int GetHashCode() => Id.GetHashCode(); + + public static bool operator ==(LabelHandle left, LabelHandle right) => left.Equals(right); + public static bool operator !=(LabelHandle left, LabelHandle right) => !left.Equals(right); + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/MethodBodyEncoder.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/MethodBodyEncoder.cs new file mode 100644 index 0000000000000..e924cb3a21d1f --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/Blobs/MethodBodyEncoder.cs @@ -0,0 +1,229 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +#if SRM +namespace System.Reflection.Metadata.Ecma335.Blobs +#else +namespace Roslyn.Reflection.Metadata.Ecma335.Blobs +#endif +{ + [Flags] +#if SRM + public +#endif + enum MethodBodyAttributes + { + None = 0, + InitLocals = 1, + LargeExceptionRegions = 2, + } + +#if SRM + public +#endif + struct MethodBodiesEncoder + { + public BlobBuilder Builder { get; } + + public MethodBodiesEncoder(BlobBuilder builder = null) + { + if (builder == null) + { + builder = new BlobBuilder(); + } + + // Fat methods are 4-byte aligned. We calculate the alignment relative to the start of the ILStream. + // + // See ECMA-335 paragraph 25.4.5, Method data section: + // "At the next 4-byte boundary following the method body can be extra method data sections." + if ((builder.Count % 4) != 0) + { + // TODO: error message + throw new ArgumentException("Builder has to be aligned to 4 byte boundary", nameof(builder)); + } + + Builder = builder; + } + + public MethodBodyEncoder AddMethodBody( + int maxStack = 8, + int exceptionRegionCount = 0, + StandaloneSignatureHandle localVariablesSignature = default(StandaloneSignatureHandle), + MethodBodyAttributes attributes = MethodBodyAttributes.InitLocals) + { + if (unchecked((ushort)maxStack) > ushort.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(maxStack)); + } + + if (exceptionRegionCount < 0) + { + throw new ArgumentOutOfRangeException(nameof(exceptionRegionCount)); + } + + return new MethodBodyEncoder(Builder, (ushort)maxStack, exceptionRegionCount, localVariablesSignature, attributes); + } + } + +#if SRM + public +#endif + struct MethodBodyEncoder + { + public BlobBuilder Builder { get; } + + private readonly ushort _maxStack; + private readonly int _exceptionRegionCount; + private readonly StandaloneSignatureHandle _localVariablesSignature; + private readonly byte _attributes; + + internal MethodBodyEncoder( + BlobBuilder builder, + ushort maxStack, + int exceptionRegionCount, + StandaloneSignatureHandle localVariablesSignature, + MethodBodyAttributes attributes) + { + Builder = builder; + _maxStack = maxStack; + _localVariablesSignature = localVariablesSignature; + _attributes = (byte)attributes; + _exceptionRegionCount = exceptionRegionCount; + } + + internal bool IsTiny(int codeSize) + { + return codeSize < 64 && _maxStack <= 8 && _localVariablesSignature.IsNil && _exceptionRegionCount == 0; + } + + private int WriteHeader(int codeSize) + { + Blob blob; + return WriteHeader(codeSize, false, out blob); + } + + private int WriteHeader(int codeSize, bool codeSizeFixup, out Blob codeSizeBlob) + { + const int TinyFormat = 2; + const int FatFormat = 3; + const int MoreSections = 8; + const byte InitLocals = 0x10; + + int offset; + + if (IsTiny(codeSize)) + { + offset = Builder.Count; + Builder.WriteByte((byte)((codeSize << 2) | TinyFormat)); + + Debug.Assert(!codeSizeFixup); + codeSizeBlob = default(Blob); + } + else + { + Builder.Align(4); + + offset = Builder.Count; + + ushort flags = (3 << 12) | FatFormat; + if (_exceptionRegionCount > 0) + { + flags |= MoreSections; + } + + if ((_attributes & (int)MethodBodyAttributes.InitLocals) != 0) + { + flags |= InitLocals; + } + + Builder.WriteUInt16((ushort)(_attributes | flags)); + Builder.WriteUInt16(_maxStack); + if (codeSizeFixup) + { + codeSizeBlob = Builder.ReserveBytes(sizeof(int)); + } + else + { + codeSizeBlob = default(Blob); + Builder.WriteInt32(codeSize); + } + + Builder.WriteInt32(_localVariablesSignature.IsNil ? 0 : MetadataTokens.GetToken(_localVariablesSignature)); + } + + return offset; + } + + private ExceptionRegionEncoder CreateExceptionEncoder() + { + return new ExceptionRegionEncoder( + Builder, + _exceptionRegionCount, + hasLargeRegions: (_attributes & (int)MethodBodyAttributes.LargeExceptionRegions) != 0); + } + + public ExceptionRegionEncoder WriteInstructions(ImmutableArray instructions, out int bodyOffset) + { + bodyOffset = WriteHeader(instructions.Length); + Builder.WriteBytes(instructions); + return CreateExceptionEncoder(); + } + + public ExceptionRegionEncoder WriteInstructions(ImmutableArray instructions, out int bodyOffset, out Blob instructionBlob) + { + bodyOffset = WriteHeader(instructions.Length); + instructionBlob = Builder.ReserveBytes(instructions.Length); + new BlobWriter(instructionBlob).WriteBytes(instructions); + return CreateExceptionEncoder(); + } + + public ExceptionRegionEncoder WriteInstructions(BlobBuilder codeBuilder, out int bodyOffset) + { + bodyOffset = WriteHeader(codeBuilder.Count); + codeBuilder.WriteContentTo(Builder); + return CreateExceptionEncoder(); + } + + public ExceptionRegionEncoder WriteInstructions(BlobBuilder codeBuilder, BranchBuilder branchBuilder, out int bodyOffset) + { + if (branchBuilder == null || branchBuilder.BranchCount == 0) + { + return WriteInstructions(codeBuilder, out bodyOffset); + } + + // When emitting branches we emitted short branches. + int initialCodeSize = codeBuilder.Count; + Blob codeSizeFixup; + if (IsTiny(initialCodeSize)) + { + // If the method is tiny so far then all branches have to be short + // (the max distance between any label and a branch instruction is < 64). + bodyOffset = WriteHeader(initialCodeSize); + codeSizeFixup = default(Blob); + } + else + { + // Otherwise, it's fat format and we can fixup the size later on: + bodyOffset = WriteHeader(initialCodeSize, true, out codeSizeFixup); + } + + int codeStartOffset = Builder.Count; + branchBuilder.FixupBranches(codeBuilder, Builder); + if (!codeSizeFixup.IsDefault) + { + new BlobWriter(codeSizeFixup).WriteInt32(Builder.Count - codeStartOffset); + } + else + { + Debug.Assert(initialCodeSize == Builder.Count - codeStartOffset); + } + + return CreateExceptionEncoder(); + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/CodedIndex.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/CodedIndex.cs new file mode 100644 index 0000000000000..d81ab33f4c6e9 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/CodedIndex.cs @@ -0,0 +1,439 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +#if SRM +namespace System.Reflection.Metadata.Ecma335 +#else +namespace Roslyn.Reflection.Metadata.Ecma335 +#endif +{ +#if SRM + public +#endif + static class CodedIndex + { + private static int ToCodedIndex(this int rowId, HasCustomAttribute tag) => (rowId << (int)HasCustomAttribute.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, HasConstant tag) => (rowId << (int)HasConstant.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, CustomAttributeType tag) => (rowId << (int)CustomAttributeType.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, HasDeclSecurity tag) => (rowId << (int)HasDeclSecurity.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, HasFieldMarshal tag) => (rowId << (int)HasFieldMarshal.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, HasSemantics tag) => (rowId << (int)HasSemantics.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, Implementation tag) => (rowId << (int)Implementation.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, MemberForwarded tag) => (rowId << (int)MemberForwarded.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, MemberRefParent tag) => (rowId << (int)MemberRefParent.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, MethodDefOrRef tag) => (rowId << (int)MethodDefOrRef.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, ResolutionScope tag) => (rowId << (int)ResolutionScope.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, TypeDefOrRefOrSpec tag) => (rowId << (int)TypeDefOrRefOrSpec.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, TypeOrMethodDef tag) => (rowId << (int)TypeOrMethodDef.__bits) | (int)tag; + private static int ToCodedIndex(this int rowId, HasCustomDebugInformation tag) => (rowId << (int)HasCustomDebugInformation.__bits) | (int)tag; + + public static int ToHasCustomAttribute(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToHasCustomAttributeTag(handle.Kind)); + public static int ToHasConstant(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToHasConstantTag(handle.Kind)); + public static int ToCustomAttributeType(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToCustomAttributeTypeTag(handle.Kind)); + public static int ToHasDeclSecurity(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToHasDeclSecurityTag(handle.Kind)); + public static int ToHasFieldMarshal(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToHasFieldMarshalTag(handle.Kind)); + public static int ToHasSemantics(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToHasSemanticsTag(handle.Kind)); + public static int ToImplementation(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToImplementationTag(handle.Kind)); + public static int ToMemberForwarded(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToMemberForwardedTag(handle.Kind)); + public static int ToMemberRefParent(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToMemberRefParentTag(handle.Kind)); + public static int ToMethodDefOrRef(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToMethodDefOrRefTag(handle.Kind)); + public static int ToResolutionScope(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToResolutionScopeTag(handle.Kind)); + public static int ToTypeDefOrRefOrSpec(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToTypeDefOrRefOrSpecTag(handle.Kind)); + public static int ToTypeOrMethodDef(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToTypeOrMethodDefTag(handle.Kind)); + public static int ToHasCustomDebugInformation(EntityHandle handle) => MetadataTokens.GetRowNumber(handle).ToCodedIndex(ToHasCustomDebugInformationTag(handle.Kind)); + + private enum HasCustomAttribute + { + MethodDef = 0, + Field = 1, + TypeRef = 2, + TypeDef = 3, + Param = 4, + InterfaceImpl = 5, + MemberRef = 6, + Module = 7, + DeclSecurity = 8, + Property = 9, + Event = 10, + StandAloneSig = 11, + ModuleRef = 12, + TypeSpec = 13, + Assembly = 14, + AssemblyRef = 15, + File = 16, + ExportedType = 17, + ManifestResource = 18, + GenericParam = 19, + GenericParamConstraint = 20, + MethodSpec = 21, + + __bits = 5 + } + + private static HasCustomAttribute ToHasCustomAttributeTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.MethodDefinition: return HasCustomAttribute.MethodDef; + case HandleKind.FieldDefinition: return HasCustomAttribute.Field; + case HandleKind.TypeReference: return HasCustomAttribute.TypeRef; + case HandleKind.TypeDefinition: return HasCustomAttribute.TypeDef; + case HandleKind.Parameter: return HasCustomAttribute.Param; + case HandleKind.InterfaceImplementation: return HasCustomAttribute.InterfaceImpl; + case HandleKind.MemberReference: return HasCustomAttribute.MemberRef; + case HandleKind.ModuleDefinition: return HasCustomAttribute.Module; + case HandleKind.DeclarativeSecurityAttribute: return HasCustomAttribute.DeclSecurity; + case HandleKind.PropertyDefinition: return HasCustomAttribute.Property; + case HandleKind.EventDefinition: return HasCustomAttribute.Event; + case HandleKind.StandaloneSignature: return HasCustomAttribute.StandAloneSig; + case HandleKind.ModuleReference: return HasCustomAttribute.ModuleRef; + case HandleKind.TypeSpecification: return HasCustomAttribute.TypeSpec; + case HandleKind.AssemblyDefinition: return HasCustomAttribute.Assembly; + case HandleKind.AssemblyReference: return HasCustomAttribute.AssemblyRef; + case HandleKind.AssemblyFile: return HasCustomAttribute.File; + case HandleKind.ExportedType: return HasCustomAttribute.ExportedType; + case HandleKind.ManifestResource: return HasCustomAttribute.ManifestResource; + case HandleKind.GenericParameter: return HasCustomAttribute.GenericParam; + case HandleKind.GenericParameterConstraint: return HasCustomAttribute.GenericParamConstraint; + case HandleKind.MethodSpecification: return HasCustomAttribute.MethodSpec; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum HasConstant + { + Field = 0, + Param = 1, + Property = 2, + + __bits = 2, + __mask = (1 << __bits) - 1 + } + + private static HasConstant ToHasConstantTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.FieldDefinition: return HasConstant.Field; + case HandleKind.Parameter: return HasConstant.Param; + case HandleKind.PropertyDefinition: return HasConstant.Property; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum CustomAttributeType + { + MethodDef = 2, + MemberRef = 3, + + __bits = 3 + } + + private static CustomAttributeType ToCustomAttributeTypeTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.MethodDefinition: return CustomAttributeType.MethodDef; + case HandleKind.MemberReference: return CustomAttributeType.MemberRef; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum HasDeclSecurity + { + TypeDef = 0, + MethodDef = 1, + Assembly = 2, + + __bits = 2, + __mask = (1 << __bits) - 1 + } + + private static HasDeclSecurity ToHasDeclSecurityTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.TypeDefinition: return HasDeclSecurity.TypeDef; + case HandleKind.MethodDefinition: return HasDeclSecurity.MethodDef; + case HandleKind.AssemblyDefinition: return HasDeclSecurity.Assembly; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum HasFieldMarshal + { + Field = 0, + Param = 1, + + __bits = 1, + __mask = (1 << __bits) - 1 + } + + private static HasFieldMarshal ToHasFieldMarshalTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.FieldDefinition: return HasFieldMarshal.Field; + case HandleKind.Parameter: return HasFieldMarshal.Param; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum HasSemantics + { + Event = 0, + Property = 1, + + __bits = 1 + } + + private static HasSemantics ToHasSemanticsTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.EventDefinition: return HasSemantics.Event; + case HandleKind.PropertyDefinition: return HasSemantics.Property; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum Implementation + { + File = 0, + AssemblyRef = 1, + ExportedType = 2, + + __bits = 2 + } + + private static Implementation ToImplementationTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.AssemblyFile: return Implementation.File; + case HandleKind.AssemblyReference: return Implementation.AssemblyRef; + case HandleKind.ExportedType: return Implementation.ExportedType; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum MemberForwarded + { + Field = 0, + MethodDef = 1, + + __bits = 1 + } + + private static MemberForwarded ToMemberForwardedTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.FieldDefinition: return MemberForwarded.Field; + case HandleKind.MethodDefinition: return MemberForwarded.MethodDef; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum MemberRefParent + { + TypeDef = 0, + TypeRef = 1, + ModuleRef = 2, + MethodDef = 3, + TypeSpec = 4, + + __bits = 3 + } + + private static MemberRefParent ToMemberRefParentTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.TypeDefinition: return MemberRefParent.TypeDef; + case HandleKind.TypeReference: return MemberRefParent.TypeRef; + case HandleKind.ModuleReference: return MemberRefParent.ModuleRef; + case HandleKind.MethodDefinition: return MemberRefParent.MethodDef; + case HandleKind.TypeSpecification: return MemberRefParent.TypeSpec; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum MethodDefOrRef + { + MethodDef = 0, + MemberRef = 1, + + __bits = 1 + } + + private static MethodDefOrRef ToMethodDefOrRefTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.MethodDefinition: return MethodDefOrRef.MethodDef; + case HandleKind.MemberReference: return MethodDefOrRef.MemberRef; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum ResolutionScope + { + Module = 0, + ModuleRef = 1, + AssemblyRef = 2, + TypeRef = 3, + + __bits = 2 + } + + private static ResolutionScope ToResolutionScopeTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.ModuleDefinition: return ResolutionScope.Module; + case HandleKind.ModuleReference: return ResolutionScope.ModuleRef; + case HandleKind.AssemblyReference: return ResolutionScope.AssemblyRef; + case HandleKind.TypeReference: return ResolutionScope.TypeRef; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum TypeDefOrRefOrSpec + { + TypeDef = 0, + TypeRef = 1, + TypeSpec = 2, + + __bits = 2 + } + + private static TypeDefOrRefOrSpec ToTypeDefOrRefOrSpecTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.TypeDefinition: return TypeDefOrRefOrSpec.TypeDef; + case HandleKind.TypeReference: return TypeDefOrRefOrSpec.TypeRef; + case HandleKind.TypeSpecification: return TypeDefOrRefOrSpec.TypeSpec; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum TypeOrMethodDef + { + TypeDef = 0, + MethodDef = 1, + + __bits = 1 + } + + private static TypeOrMethodDef ToTypeOrMethodDefTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.TypeDefinition: return TypeOrMethodDef.TypeDef; + case HandleKind.MethodDefinition: return TypeOrMethodDef.MethodDef; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + + private enum HasCustomDebugInformation + { + MethodDef = 0, + Field = 1, + TypeRef = 2, + TypeDef = 3, + Param = 4, + InterfaceImpl = 5, + MemberRef = 6, + Module = 7, + DeclSecurity = 8, + Property = 9, + Event = 10, + StandAloneSig = 11, + ModuleRef = 12, + TypeSpec = 13, + Assembly = 14, + AssemblyRef = 15, + File = 16, + ExportedType = 17, + ManifestResource = 18, + GenericParam = 19, + GenericParamConstraint = 20, + MethodSpec = 21, + Document = 22, + LocalScope = 23, + LocalVariable = 24, + LocalConstant = 25, + ImportScope = 26, + + __bits = 5 + } + + private static HasCustomDebugInformation ToHasCustomDebugInformationTag(HandleKind kind) + { + switch (kind) + { + case HandleKind.MethodDefinition: return HasCustomDebugInformation.MethodDef; + case HandleKind.FieldDefinition: return HasCustomDebugInformation.Field; + case HandleKind.TypeReference: return HasCustomDebugInformation.TypeRef; + case HandleKind.TypeDefinition: return HasCustomDebugInformation.TypeDef; + case HandleKind.Parameter: return HasCustomDebugInformation.Param; + case HandleKind.InterfaceImplementation: return HasCustomDebugInformation.InterfaceImpl; + case HandleKind.MemberReference: return HasCustomDebugInformation.MemberRef; + case HandleKind.ModuleDefinition: return HasCustomDebugInformation.Module; + case HandleKind.DeclarativeSecurityAttribute: return HasCustomDebugInformation.DeclSecurity; + case HandleKind.PropertyDefinition: return HasCustomDebugInformation.Property; + case HandleKind.EventDefinition: return HasCustomDebugInformation.Event; + case HandleKind.StandaloneSignature: return HasCustomDebugInformation.StandAloneSig; + case HandleKind.ModuleReference: return HasCustomDebugInformation.ModuleRef; + case HandleKind.TypeSpecification: return HasCustomDebugInformation.TypeSpec; + case HandleKind.AssemblyDefinition: return HasCustomDebugInformation.Assembly; + case HandleKind.AssemblyReference: return HasCustomDebugInformation.AssemblyRef; + case HandleKind.AssemblyFile: return HasCustomDebugInformation.File; + case HandleKind.ExportedType: return HasCustomDebugInformation.ExportedType; + case HandleKind.ManifestResource: return HasCustomDebugInformation.ManifestResource; + case HandleKind.GenericParameter: return HasCustomDebugInformation.GenericParam; + case HandleKind.GenericParameterConstraint: return HasCustomDebugInformation.GenericParamConstraint; + case HandleKind.MethodSpecification: return HasCustomDebugInformation.MethodSpec; + case HandleKind.Document: return HasCustomDebugInformation.Document; + case HandleKind.LocalScope: return HasCustomDebugInformation.LocalScope; + case (HandleKind)0x33: return HasCustomDebugInformation.LocalVariable; // TODO + case HandleKind.LocalConstant: return HasCustomDebugInformation.LocalConstant; + case HandleKind.ImportScope: return HasCustomDebugInformation.ImportScope; + + default: + throw new ArgumentException($"Unexpected kind of handle: {kind}"); + } + } + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs similarity index 66% rename from src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs rename to src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs index 3916475a3341f..8ad7f350e064c 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataHeapsBuilder.cs +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs @@ -1,127 +1,68 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.Reflection; +using System.Text; using System.Reflection.Metadata; +using Microsoft.CodeAnalysis; + +#if SRM +using System.Reflection.Internal; +using BitArithmeticUtilities = System.Reflection.Internal.BitArithmetic; +#else +using System; using System.Reflection.Metadata.Ecma335; -using System.Text; using Microsoft.CodeAnalysis.Collections; using Roslyn.Utilities; +#endif -namespace Microsoft.Cci +#if SRM +namespace System.Reflection.Metadata.Ecma335 +#else +namespace Roslyn.Reflection.Metadata.Ecma335 +#endif { - /// - /// Represents a value on #String heap that has not been serialized yet. - /// - internal struct StringIdx : IEquatable - { - // index in _stringIndexToHeapPositionMap - public readonly int MapIndex; - - internal StringIdx(int mapIndex) - { - MapIndex = mapIndex; - } - - public bool Equals(StringIdx other) - { - return MapIndex == other.MapIndex; - } - - public override bool Equals(object obj) - { - return obj is StringIdx && Equals((StringIdx)obj); - } - - public override int GetHashCode() - { - return MapIndex.GetHashCode(); - } - - public static bool operator ==(StringIdx left, StringIdx right) - { - return left.Equals(right); - } - - public static bool operator !=(StringIdx left, StringIdx right) - { - return !left.Equals(right); - } - } - - /// - /// Represents a value on #Blob heap that has not been serialized yet. - /// - internal struct BlobIdx : IEquatable - { - // The position of the blob on heap relative to the start of the heap. - // In EnC deltas this value is not the same as the value stored in blob token. - public readonly int HeapPosition; - - internal BlobIdx(int heapPosition) - { - HeapPosition = heapPosition; - } - - public bool Equals(BlobIdx other) - { - return HeapPosition == other.HeapPosition; - } - - public override bool Equals(object obj) - { - return obj is BlobIdx && Equals((BlobIdx)obj); - } - - public override int GetHashCode() - { - return HeapPosition.GetHashCode(); - } - - public static bool operator ==(BlobIdx left, BlobIdx right) - { - return left.Equals(right); - } - - public static bool operator !=(BlobIdx left, BlobIdx right) - { - return !left.Equals(right); - } - } - - internal sealed class MetadataHeapsBuilder +#if SRM + public +#endif + sealed partial class MetadataBuilder { // #US heap + private const int UserStringHeapSizeLimit = 0x01000000; private readonly Dictionary _userStrings = new Dictionary(); private readonly BlobBuilder _userStringWriter = new BlobBuilder(1024); private readonly int _userStringHeapStartOffset; // #String heap - private Dictionary _strings = new Dictionary(128); + private Dictionary _strings = new Dictionary(128); private int[] _stringIndexToResolvedOffsetMap; private BlobBuilder _stringWriter; private readonly int _stringHeapStartOffset; // #Blob heap - private readonly Dictionary, BlobIdx> _blobs = new Dictionary, BlobIdx>(ByteSequenceComparer.Instance); + private readonly Dictionary, BlobHandle> _blobs = new Dictionary, BlobHandle>(ByteSequenceComparer.Instance); private readonly int _blobHeapStartOffset; private int _blobHeapSize; // #GUID heap - private readonly Dictionary _guids = new Dictionary(); + private readonly Dictionary _guids = new Dictionary(); private readonly BlobBuilder _guidWriter = new BlobBuilder(16); // full metadata has just a single guid private bool _streamsAreComplete; - public MetadataHeapsBuilder( + public MetadataBuilder( int userStringHeapStartOffset = 0, int stringHeapStartOffset = 0, int blobHeapStartOffset = 0, int guidHeapStartOffset = 0) { + // -1 for the 0 we always write at the beginning of the heap: + if (userStringHeapStartOffset > UserStringHeapSizeLimit - 1) + { + ImageFormatLimitationException.ThrowHeapSizeLimitExceeded(HeapIndex.UserString); + } + // Add zero-th entry to all heaps, even in EnC delta. // We don't want generation-relative handles to ever be IsNil. // In both full and delta metadata all nil heap handles should have zero value. @@ -129,7 +70,7 @@ public MetadataHeapsBuilder( // beginning of the delta blob. _userStringWriter.WriteByte(0); - _blobs.Add(ImmutableArray.Empty, new BlobIdx(0)); + _blobs.Add(ImmutableArray.Empty, default(BlobHandle)); _blobHeapSize = 1; // When EnC delta is applied #US, #String and #Blob heaps are appended. @@ -143,20 +84,20 @@ public MetadataHeapsBuilder( _guidWriter.WriteBytes(0, guidHeapStartOffset); } - internal BlobIdx GetBlobIndex(BlobBuilder builder) + public BlobHandle GetOrAddBlob(BlobBuilder builder) { // TODO: avoid making a copy if the blob exists in the index - return GetBlobIndex(builder.ToImmutableArray()); + return GetOrAddBlob(builder.ToImmutableArray()); } - internal BlobIdx GetBlobIndex(ImmutableArray blob) + public BlobHandle GetOrAddBlob(ImmutableArray blob) { - BlobIdx index; + BlobHandle index; if (!_blobs.TryGetValue(blob, out index)) { Debug.Assert(!_streamsAreComplete); - index = new BlobIdx(_blobHeapSize); + index = MetadataTokens.BlobHandle(_blobHeapSize); _blobs.Add(blob, index); _blobHeapSize += BlobWriterImpl.GetCompressedIntegerSize(blob.Length) + blob.Length; @@ -165,22 +106,22 @@ internal BlobIdx GetBlobIndex(ImmutableArray blob) return index; } - public BlobIdx GetConstantBlobIndex(object value) + public BlobHandle GetOrAddConstantBlob(object value) { string str = value as string; if (str != null) { - return this.GetBlobIndex(str); + return GetOrAddBlob(str); } - var writer = PooledBlobBuilder.GetInstance(); - writer.WriteConstant(value); - var result = this.GetBlobIndex(writer); - writer.Free(); + var builder = Microsoft.Cci.PooledBlobBuilder.GetInstance(); + builder.WriteConstant(value); + var result = GetOrAddBlob(builder); + builder.Free(); return result; } - public BlobIdx GetBlobIndex(string str) + public BlobHandle GetOrAddBlob(string str) { byte[] byteArray = new byte[str.Length * 2]; int i = 0; @@ -190,31 +131,41 @@ public BlobIdx GetBlobIndex(string str) byteArray[i++] = (byte)(ch >> 8); } - return this.GetBlobIndex(ImmutableArray.Create(byteArray)); + return GetOrAddBlob(ImmutableArray.Create(byteArray)); } - public BlobIdx GetBlobIndexUtf8(string str) + public BlobHandle GetOrAddBlobUtf8(string str) { - return GetBlobIndex(ImmutableArray.Create(Encoding.UTF8.GetBytes(str))); + return GetOrAddBlob(ImmutableArray.Create(Encoding.UTF8.GetBytes(str))); } - public int GetGuidIndex(Guid guid) + public GuidHandle GetOrAddGuid(Guid guid) { if (guid == Guid.Empty) { - return 0; + return default(GuidHandle); } - int result; + GuidHandle result; if (_guids.TryGetValue(guid, out result)) { return result; } - return AllocateGuid(guid); + result = GetNextGuid(); + _guids.Add(guid, result); + _guidWriter.WriteBytes(guid.ToByteArray()); + return result; + } + + public GuidHandle ReserveGuid(out Blob reservedBlob) + { + var handle = GetNextGuid(); + reservedBlob = _guidWriter.ReserveBytes(16); + return handle; } - public int AllocateGuid(Guid guid) + private GuidHandle GetNextGuid() { Debug.Assert(!_streamsAreComplete); @@ -228,60 +179,68 @@ public int AllocateGuid(Guid guid) // Metadata Spec: // The Guid heap is an array of GUIDs, each 16 bytes wide. // Its first element is numbered 1, its second 2, and so on. - int result = (_guidWriter.Count >> 4) + 1; - - _guids.Add(guid, result); - _guidWriter.WriteBytes(guid.ToByteArray()); - - return result; + return MetadataTokens.GuidHandle((_guidWriter.Count >> 4) + 1); } - public StringIdx GetStringIndex(string str) + public StringHandle GetOrAddString(string str) { - StringIdx index; + StringHandle index; if (str.Length == 0) { - index = new StringIdx(0); + index = default(StringHandle); } else if (!_strings.TryGetValue(str, out index)) { Debug.Assert(!_streamsAreComplete); - index = new StringIdx(_strings.Count + 1); // idx 0 is reserved for empty string + index = MetadataTokens.StringHandle(_strings.Count + 1); // idx 0 is reserved for empty string _strings.Add(str, index); } return index; } - public int ResolveStringIndex(StringIdx index) + public int GetHeapOffset(StringHandle handle) { - return _stringIndexToResolvedOffsetMap[index.MapIndex]; + return _stringIndexToResolvedOffsetMap[MetadataTokens.GetHeapOffset(handle)]; } - public int ResolveBlobIndex(BlobIdx index) + public int GetHeapOffset(BlobHandle handle) { - return (index.HeapPosition == 0) ? 0 : _blobHeapStartOffset + index.HeapPosition; + int offset = MetadataTokens.GetHeapOffset(handle); + return (offset == 0) ? 0 : _blobHeapStartOffset + offset; + } + + public int GetHeapOffset(GuidHandle handle) + { + return MetadataTokens.GetHeapOffset(handle); + } + + public int GetHeapOffset(UserStringHandle handle) + { + return MetadataTokens.GetHeapOffset(handle); } - public bool TryGetUserStringToken(string str, out int token) + /// The remaining space on the heap is too small to fit the string. + public UserStringHandle GetOrAddUserString(string str) { int index; if (!_userStrings.TryGetValue(str, out index)) { Debug.Assert(!_streamsAreComplete); - index = _userStringWriter.Position + _userStringHeapStartOffset; + int startPosition = _userStringWriter.Position; + int encodedLength = str.Length * 2 + 1; + index = startPosition + _userStringHeapStartOffset; - // User strings are referenced by metadata tokens (8 bits of which are used for the token type) leaving only 24 bits for the offset. - if ((index & 0xFF000000) != 0) + // Native metadata emitter allows strings to exceed the heap size limit as long + // as the index is within the limits (see https://github.com/dotnet/roslyn/issues/9852) + if (index > UserStringHeapSizeLimit) { - token = 0; - return false; + ImageFormatLimitationException.ThrowHeapSizeLimitExceeded(HeapIndex.UserString); } _userStrings.Add(str, index); - _userStringWriter.WriteCompressedInteger((uint)str.Length * 2 + 1); - + _userStringWriter.WriteCompressedInteger(encodedLength); _userStringWriter.WriteUTF16(str); // Write out a trailing byte indicating if the string is really quite simple @@ -337,11 +296,10 @@ public bool TryGetUserStringToken(string str, out int token) _userStringWriter.WriteByte(stringKind); } - token = 0x70000000 | index; - return true; + return MetadataTokens.UserStringHandle(index); } - public void Complete() + internal void CompleteHeaps() { Debug.Assert(!_streamsAreComplete); _streamsAreComplete = true; @@ -367,7 +325,7 @@ public ImmutableArray GetHeapSizes() private void SerializeStringHeap() { // Sort by suffix and remove stringIndex - var sorted = new List>(_strings); + var sorted = new List>(_strings); sorted.Sort(new SuffixSort()); _strings = null; @@ -381,7 +339,7 @@ private void SerializeStringHeap() // Find strings that can be folded string prev = string.Empty; - foreach (KeyValuePair entry in sorted) + foreach (KeyValuePair entry in sorted) { int position = _stringHeapStartOffset + _stringWriter.Position; @@ -389,11 +347,11 @@ private void SerializeStringHeap() if (prev.EndsWith(entry.Key, StringComparison.Ordinal) && !BlobUtilities.IsLowSurrogateChar(entry.Key[0])) { // Map over the tail of prev string. Watch for null-terminator of prev string. - _stringIndexToResolvedOffsetMap[entry.Value.MapIndex] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1); + _stringIndexToResolvedOffsetMap[MetadataTokens.GetHeapOffset(entry.Value)] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1); } else { - _stringIndexToResolvedOffsetMap[entry.Value.MapIndex] = position; + _stringIndexToResolvedOffsetMap[MetadataTokens.GetHeapOffset(entry.Value)] = position; _stringWriter.WriteUTF8(entry.Key, allowUnpairedSurrogates: false); _stringWriter.WriteByte(0); } @@ -406,9 +364,9 @@ private void SerializeStringHeap() /// Sorts strings such that a string is followed immediately by all strings /// that are a suffix of it. /// - private class SuffixSort : IComparer> + private class SuffixSort : IComparer> { - public int Compare(KeyValuePair xPair, KeyValuePair yPair) + public int Compare(KeyValuePair xPair, KeyValuePair yPair) { string x = xPair.Key; string y = yPair.Key; @@ -430,13 +388,10 @@ public int Compare(KeyValuePair xPair, KeyValuePair _moduleTable = new List(1); @@ -107,7 +103,9 @@ private struct CustomDebugInformationRow { public uint Parent; public uint Kind; private bool _fieldMarshalTableNeedsSorting; private readonly List _fieldRvaTable = new List(); + private readonly List _fieldTable = new List(); + private readonly List _fileTable = new List(); private readonly List _genericParamConstraintTable = new List(); private readonly List _genericParamTable = new List(); @@ -134,6 +132,7 @@ private struct CustomDebugInformationRow { public uint Parent; public uint Kind; private readonly List _assemblyRefTable = new List(); private readonly List _standAloneSigTable = new List(); + // debug tables: private readonly List _documentTable = new List(); private readonly List _methodDebugInformationTable = new List(); @@ -211,28 +210,30 @@ public void SetCapacity(TableIndex table, int capacity) #region Building - public void AddModule( + public ModuleDefinitionHandle AddModule( int generation, - StringIdx moduleName, - Guid mvid, - Guid encId, - Guid encBaseId) + StringHandle moduleName, + GuidHandle mvid, + GuidHandle encId, + GuidHandle encBaseId) { _moduleTable.Add(new ModuleRow { Generation = (ushort)generation, Name = moduleName, - ModuleVersionId = _heaps.AllocateGuid(mvid), - EncId = _heaps.GetGuidIndex(encId), - EncBaseId = _heaps.GetGuidIndex(encBaseId), + ModuleVersionId = mvid, + EncId = encId, + EncBaseId = encBaseId, }); + + return EntityHandle.ModuleDefinition; } - public void AddAssembly( - StringIdx name, + public AssemblyDefinitionHandle AddAssembly( + StringHandle name, Version version, - StringIdx culture, - BlobIdx publicKey, + StringHandle culture, + BlobHandle publicKey, AssemblyFlags flags, AssemblyHashAlgorithm hashAlgorithm) { @@ -245,15 +246,17 @@ public void AddAssembly( AssemblyName = name, AssemblyCulture = culture }); + + return EntityHandle.AssemblyDefinition; } - public void AddAssemblyReference( - StringIdx name, + public AssemblyReferenceHandle AddAssemblyReference( + StringHandle name, Version version, - StringIdx culture, - BlobIdx publicKeyOrToken, + StringHandle culture, + BlobHandle publicKeyOrToken, AssemblyFlags flags, - BlobIdx hashValue) + BlobHandle hashValue) { _assemblyRefTable.Add(new AssemblyRefTableRow { @@ -264,15 +267,17 @@ public void AddAssemblyReference( Flags = (uint)flags, HashValue = hashValue }); + + return MetadataTokens.AssemblyReferenceHandle(_assemblyRefTable.Count); } - public void AddTypeDefinition( + public TypeDefinitionHandle AddTypeDefinition( TypeAttributes attributes, - StringIdx @namespace, - StringIdx name, - uint baseTypeCodedIndex, - int fieldList, - int methodList) + StringHandle @namespace, + StringHandle name, + EntityHandle baseType, + FieldDefinitionHandle fieldList, + MethodDefinitionHandle methodList) { Debug.Assert(@namespace != null); Debug.Assert(name != null); @@ -282,90 +287,91 @@ public void AddTypeDefinition( Flags = (uint)attributes, Name = name, Namespace = @namespace, - Extends = baseTypeCodedIndex, - FieldList = (uint)fieldList, - MethodList = (uint)methodList + Extends = baseType.IsNil ? 0 : (uint)CodedIndex.ToTypeDefOrRefOrSpec(baseType), + FieldList = (uint)MetadataTokens.GetRowNumber(fieldList), + MethodList = (uint)MetadataTokens.GetRowNumber(methodList) }); + + return MetadataTokens.TypeDefinitionHandle(_typeDefTable.Count); } public void AddTypeLayout( - int typeDefinitionRowId, + TypeDefinitionHandle type, ushort packingSize, uint size) { _classLayoutTable.Add(new ClassLayoutRow { - Parent = (uint)typeDefinitionRowId, + Parent = (uint)MetadataTokens.GetRowNumber(type), PackingSize = packingSize, ClassSize = size }); } - public void AddInterfaceImplementation( - int typeDefinitionRowId, - uint interfaceCodedIndex) + public InterfaceImplementationHandle AddInterfaceImplementation( + TypeDefinitionHandle type, + EntityHandle implementedInterface) { _interfaceImplTable.Add(new InterfaceImplRow { - Class = (uint)typeDefinitionRowId, - Interface = interfaceCodedIndex + Class = (uint)MetadataTokens.GetRowNumber(type), + Interface = (uint)CodedIndex.ToTypeDefOrRefOrSpec(implementedInterface) }); + + // TODO: + return (InterfaceImplementationHandle)MetadataTokens.Handle(TableIndex.InterfaceImpl, _interfaceImplTable.Count); } public void AddNestedType( - int typeDefinitionRowId, - int enclosingTypeDefinitionRowId) + TypeDefinitionHandle type, + TypeDefinitionHandle enclosingType) { _nestedClassTable.Add(new NestedClassRow { - NestedClass = (uint)typeDefinitionRowId, - EnclosingClass = (uint)enclosingTypeDefinitionRowId + NestedClass = (uint)MetadataTokens.GetRowNumber(type), + EnclosingClass = (uint)MetadataTokens.GetRowNumber(enclosingType) }); } - public int AddTypeReference(uint resolutionScope, StringIdx @namespace, StringIdx name) + public TypeReferenceHandle AddTypeReference( + EntityHandle resolutionScope, + StringHandle @namespace, + StringHandle name) { Debug.Assert(@namespace != null); Debug.Assert(name != null); _typeRefTable.Add(new TypeRefRow { - ResolutionScope = resolutionScope, + ResolutionScope = (uint)CodedIndex.ToResolutionScope(resolutionScope), Name = name, Namespace = @namespace }); - // row id - return _typeRefTable.Count; - } - - public void SetTypeSpecificationTableCapacity(int capacity) - { - _typeSpecTable.Capacity = capacity; + return MetadataTokens.TypeReferenceHandle(_typeRefTable.Count); } - public void AddTypeSpecification(BlobIdx signature) + public TypeSpecificationHandle AddTypeSpecification(BlobHandle signature) { _typeSpecTable.Add(new TypeSpecRow { Signature = signature }); - } - public void SetStandaloneSigTableCapacity(int capacity) - { - _standAloneSigTable.Capacity = capacity; + return MetadataTokens.TypeSpecificationHandle(_typeSpecTable.Count); } - public void AddStandaloneSignature(BlobIdx signature) + public StandaloneSignatureHandle AddStandaloneSignature(BlobHandle signature) { _standAloneSigTable.Add(new StandaloneSigRow { Signature = signature }); + + return MetadataTokens.StandaloneSignatureHandle(_standAloneSigTable.Count); } - public void AddProperty(PropertyAttributes attributes, StringIdx name, BlobIdx signature) + public PropertyDefinitionHandle AddProperty(PropertyAttributes attributes, StringHandle name, BlobHandle signature) { _propertyTable.Add(new PropertyRow { @@ -373,96 +379,114 @@ public void AddProperty(PropertyAttributes attributes, StringIdx name, BlobIdx s Name = name, Type = signature }); + + return MetadataTokens.PropertyDefinitionHandle(_propertyTable.Count); } - public void AddPropertyMap(int typeDefinitionRowId, int propertyList) + public void AddPropertyMap(TypeDefinitionHandle declaringType, PropertyDefinitionHandle propertyList) { _propertyMapTable.Add(new PropertyMapRow { - Parent = (uint)typeDefinitionRowId, - PropertyList = (uint)propertyList + Parent = (uint)MetadataTokens.GetRowNumber(declaringType), + PropertyList = (uint)MetadataTokens.GetRowNumber(propertyList) }); } - public void AddEvent(EventAttributes attributes, StringIdx name, uint type) + public EventDefinitionHandle AddEvent(EventAttributes attributes, StringHandle name, EntityHandle type) { _eventTable.Add(new EventRow { EventFlags = (ushort)attributes, Name = name, - EventType = type + EventType = (uint)CodedIndex.ToTypeDefOrRefOrSpec(type) }); + + return MetadataTokens.EventDefinitionHandle(_eventTable.Count); } - public void AddEventMap(int typeDefinitionRowId, int eventList) + public void AddEventMap(TypeDefinitionHandle declaringType, EventDefinitionHandle eventList) { _eventMapTable.Add(new EventMapRow { - Parent = (uint)typeDefinitionRowId, - EventList = (uint)eventList + Parent = (uint)MetadataTokens.GetRowNumber(declaringType), + EventList = (uint)MetadataTokens.GetRowNumber(eventList) }); } - public void AddConstant(uint parent, object value) + public ConstantHandle AddConstant(EntityHandle parent, object value) { + uint parentCodedIndex = (uint)CodedIndex.ToHasConstant(parent); + // the table is required to be sorted by Parent: - _constantTableNeedsSorting |= parent < _constantTableLastParent; - _constantTableLastParent = parent; + _constantTableNeedsSorting |= parentCodedIndex < _constantTableLastParent; + _constantTableLastParent = parentCodedIndex; _constantTable.Add(new ConstantRow { Type = (byte)MetadataWriterUtilities.GetConstantTypeCode(value), - Parent = parent, - Value = _heaps.GetConstantBlobIndex(value) + Parent = parentCodedIndex, + Value = GetOrAddConstantBlob(value) }); + + return MetadataTokens.ConstantHandle(_constantTable.Count); } - public void AddMethodSemantics(uint association, ushort semantics, int methodDefinitionRowId) + public void AddMethodSemantics(EntityHandle association, ushort semantics, MethodDefinitionHandle methodDefinition) { + uint associationCodedIndex = (uint)CodedIndex.ToHasSemantics(association); + // the table is required to be sorted by Association: - _methodSemanticsTableNeedsSorting |= association < _methodSemanticsTableLastAssociation; - _methodSemanticsTableLastAssociation = association; + _methodSemanticsTableNeedsSorting |= associationCodedIndex < _methodSemanticsTableLastAssociation; + _methodSemanticsTableLastAssociation = associationCodedIndex; _methodSemanticsTable.Add(new MethodSemanticsRow { - Association = association, - Method = (uint)methodDefinitionRowId, + Association = associationCodedIndex, + Method = (uint)MetadataTokens.GetRowNumber(methodDefinition), Semantic = semantics }); } - public void AddCustomAttribute(uint parent, uint constructor, BlobIdx value) + public CustomAttributeHandle AddCustomAttribute(EntityHandle parent, EntityHandle constructor, BlobHandle value) { + uint parentCodedIndex = (uint)CodedIndex.ToHasCustomAttribute(parent); + // the table is required to be sorted by Parent: - _customAttributeTableNeedsSorting |= parent < _customAttributeTableLastParent; - _customAttributeTableLastParent = parent; + _customAttributeTableNeedsSorting |= parentCodedIndex < _customAttributeTableLastParent; + _customAttributeTableLastParent = parentCodedIndex; _customAttributeTable.Add(new CustomAttributeRow { - Parent = parent, - Type = constructor, + Parent = parentCodedIndex, + Type = (uint)CodedIndex.ToCustomAttributeType(constructor), Value = value }); + + return MetadataTokens.CustomAttributeHandle(_customAttributeTable.Count); } - public void AddMethodSpecification(uint method, BlobIdx instantiation) + public MethodSpecificationHandle AddMethodSpecification(EntityHandle method, BlobHandle instantiation) { _methodSpecTable.Add(new MethodSpecRow { - Method = method, + Method = (uint)CodedIndex.ToMethodDefOrRef(method), Instantiation = instantiation }); + + return MetadataTokens.MethodSpecificationHandle(_methodSpecTable.Count); } - public void AddModuleReference(StringIdx moduleName) + public ModuleReferenceHandle AddModuleReference(StringHandle moduleName) { _moduleRefTable.Add(new ModuleRefRow { Name = moduleName }); + + return MetadataTokens.ModuleReferenceHandle(_moduleRefTable.Count); } - public void AddParameter(ParameterAttributes attributes, StringIdx name, int sequenceNumber) + public ParameterHandle AddParameter(ParameterAttributes attributes, StringHandle name, int sequenceNumber) { _paramTable.Add(new ParamRow { @@ -470,12 +494,14 @@ public void AddParameter(ParameterAttributes attributes, StringIdx name, int seq Name = name, Sequence = (ushort)sequenceNumber }); + + return MetadataTokens.ParameterHandle(_paramTable.Count); } - public int AddGenericParameter( - uint parent, + public GenericParameterHandle AddGenericParameter( + EntityHandle parent, GenericParameterAttributes attributes, - StringIdx name, + StringHandle name, int index) { _genericParamTable.Add(new GenericParamRow @@ -483,28 +509,29 @@ public int AddGenericParameter( Flags = (ushort)attributes, Name = name, Number = (ushort)index, - Owner = parent + Owner = (uint)CodedIndex.ToTypeOrMethodDef(parent) }); - // row id - return _genericParamTable.Count; + return MetadataTokens.GenericParameterHandle(_genericParamTable.Count); } - public void AddGenericParameterConstraint( - int genericParameterRowId, - uint constraint) + public GenericParameterConstraintHandle AddGenericParameterConstraint( + GenericParameterHandle genericParameter, + EntityHandle constraint) { _genericParamConstraintTable.Add(new GenericParamConstraintRow { - Owner = (uint)genericParameterRowId, - Constraint = constraint, + Owner = (uint)MetadataTokens.GetRowNumber(genericParameter), + Constraint = (uint)CodedIndex.ToTypeDefOrRefOrSpec(constraint), }); + + return MetadataTokens.GenericParameterConstraintHandle(_genericParamConstraintTable.Count); } - public void AddFieldDefinition( + public FieldDefinitionHandle AddFieldDefinition( FieldAttributes attributes, - StringIdx name, - BlobIdx signature) + StringHandle name, + BlobHandle signature) { _fieldTable.Add(new FieldDefRow { @@ -512,51 +539,56 @@ public void AddFieldDefinition( Name = name, Signature = signature }); + + return MetadataTokens.FieldDefinitionHandle(_fieldTable.Count); } public void AddFieldLayout( - int fieldDefinitionRowId, + FieldDefinitionHandle field, int offset) { _fieldLayoutTable.Add(new FieldLayoutRow { - Field = (uint)fieldDefinitionRowId, + Field = (uint)MetadataTokens.GetRowNumber(field), Offset = (uint)offset }); } + public void AddMarshallingDescriptor( - uint parent, - BlobIdx descriptor) + EntityHandle parent, + BlobHandle descriptor) { + uint codedIndex = (uint)CodedIndex.ToHasFieldMarshal(parent); + // the table is required to be sorted by Parent: - _fieldMarshalTableNeedsSorting |= parent < _fieldMarshalTableLastParent; - _fieldMarshalTableLastParent = parent; + _fieldMarshalTableNeedsSorting |= codedIndex < _fieldMarshalTableLastParent; + _fieldMarshalTableLastParent = codedIndex; _fieldMarshalTable.Add(new FieldMarshalRow { - Parent = parent, + Parent = codedIndex, NativeType = descriptor }); } public void AddFieldRelativeVirtualAddress( - int fieldDefinitionRowId, + FieldDefinitionHandle field, int relativeVirtualAddress) { _fieldRvaTable.Add(new FieldRvaRow { - Field = (uint)fieldDefinitionRowId, + Field = (uint)MetadataTokens.GetRowNumber(field), Offset = (uint)relativeVirtualAddress }); } - public void AddMethodDefinition( + public MethodDefinitionHandle AddMethodDefinition( MethodAttributes attributes, MethodImplAttributes implAttributes, - StringIdx name, - BlobIdx signature, - int relativeVirtualAddress, - int paramList) + StringHandle name, + BlobHandle signature, + int bodyOffset, + ParameterHandle paramList) { _methodDefTable.Add(new MethodRow { @@ -564,70 +596,78 @@ public void AddMethodDefinition( ImplFlags = (ushort)implAttributes, Name = name, Signature = signature, - Rva = relativeVirtualAddress, - ParamList = (uint)paramList + BodyOffset = bodyOffset, + ParamList = (uint)MetadataTokens.GetRowNumber(paramList) }); + + return MetadataTokens.MethodDefinitionHandle(_methodDefTable.Count); } public void AddMethodImport( - uint member, + EntityHandle member, MethodImportAttributes attributes, - StringIdx name, - int moduleReferenceRowId) + StringHandle name, + ModuleReferenceHandle module) { _implMapTable.Add(new ImplMapRow { - MemberForwarded = member, + MemberForwarded = (uint)CodedIndex.ToMemberForwarded(member), ImportName = name, - ImportScope = (uint)moduleReferenceRowId, + ImportScope = (uint)MetadataTokens.GetRowNumber(module), MappingFlags = (ushort)attributes, }); } - public void AddMethodImplementation( - int typeDefinitionRowId, - uint methodBody, - uint methodDeclaration) + public MethodImplementationHandle AddMethodImplementation( + TypeDefinitionHandle type, + EntityHandle methodBody, + EntityHandle methodDeclaration) { _methodImplTable.Add(new MethodImplRow { - Class = (uint)typeDefinitionRowId, - MethodBody = methodBody, - MethodDecl = methodDeclaration + Class = (uint)MetadataTokens.GetRowNumber(type), + MethodBody = (uint)CodedIndex.ToMethodDefOrRef(methodBody), + MethodDecl = (uint)CodedIndex.ToMethodDefOrRef(methodDeclaration) }); + + return MetadataTokens.MethodImplementationHandle(_methodImplTable.Count); } - public void AddMemberReference( - uint type, - StringIdx name, - BlobIdx signature) + public MemberReferenceHandle AddMemberReference( + EntityHandle parent, + StringHandle name, + BlobHandle signature) { _memberRefTable.Add(new MemberRefRow { - Class = type, + Class = (uint)CodedIndex.ToMemberRefParent(parent), Name = name, Signature = signature }); + + return MetadataTokens.MemberReferenceHandle(_memberRefTable.Count); } - public void AddManifestResource( + public ManifestResourceHandle AddManifestResource( ManifestResourceAttributes attributes, - StringIdx name, - uint implementation, + StringHandle name, + EntityHandle implementation, long offset) { _manifestResourceTable.Add(new ManifestResourceRow { Flags = (uint)attributes, Name = name, - Implementation = implementation, + Implementation = implementation.IsNil ? 0 : (uint)CodedIndex.ToImplementation(implementation), Offset = (uint)offset }); + + return MetadataTokens.ManifestResourceHandle(_manifestResourceTable.Count); } - public void AddAssemblyFile( - StringIdx name, - BlobIdx hashValue, + public AssemblyFileHandle AddAssemblyFile( + StringHandle name, + BlobHandle hashValue, bool containsMetadata) { _fileTable.Add(new FileTableRow @@ -636,23 +676,27 @@ public void AddAssemblyFile( Flags = containsMetadata ? 0u : 1u, HashValue = hashValue }); + + return MetadataTokens.AssemblyFileHandle(_fileTable.Count); } - public void AddExportedType( + public ExportedTypeHandle AddExportedType( TypeAttributes attributes, - StringIdx @namespace, - StringIdx name, - uint implementation, + StringHandle @namespace, + StringHandle name, + EntityHandle implementation, int typeDefinitionId) { _exportedTypeTable.Add(new ExportedTypeRow { Flags = (uint)attributes, - Implementation = implementation, + Implementation = (uint)CodedIndex.ToImplementation(implementation), TypeNamespace = @namespace, TypeName = name, TypeDefId = (uint)typeDefinitionId }); + + return MetadataTokens.ExportedTypeHandle(_exportedTypeTable.Count); } // TODO: remove @@ -661,38 +705,137 @@ public uint GetExportedTypeFlags(int rowId) return _exportedTypeTable[rowId].Flags; } - public void AddDeclarativeSecurityAttribute( - uint parent, + public DeclarativeSecurityAttributeHandle AddDeclarativeSecurityAttribute( + EntityHandle parent, DeclarativeSecurityAction action, - BlobIdx permissionSet) + BlobHandle permissionSet) { + uint parentCodedIndex = (uint)CodedIndex.ToHasDeclSecurity(parent); + // the table is required to be sorted by Parent: - _declSecurityTableNeedsSorting |= parent < _declSecurityTableLastParent; - _declSecurityTableLastParent = parent; + _declSecurityTableNeedsSorting |= parentCodedIndex < _declSecurityTableLastParent; + _declSecurityTableLastParent = parentCodedIndex; _declSecurityTable.Add(new DeclSecurityRow { - Parent = parent, + Parent = parentCodedIndex, Action = (ushort)action, PermissionSet = permissionSet }); + + return MetadataTokens.DeclarativeSecurityAttributeHandle(_declSecurityTable.Count); } - public void AddEncLogEntry(int token, EncFuncCode code) + public void AddEncLogEntry(EntityHandle entity, EditAndContinueOperation code) { _encLogTable.Add(new EncLogRow { - Token = (uint)token, + Token = (uint)MetadataTokens.GetToken(entity), FuncCode = (byte)code }); } - public void AddEncMapEntry(int token) + public void AddEncMapEntry(EntityHandle entity) { _encMapTable.Add(new EncMapRow { - Token = (uint)token + Token = (uint)MetadataTokens.GetToken(entity) + }); + } + + public DocumentHandle AddDocument(BlobHandle name, GuidHandle hashAlgorithm, BlobHandle hash, GuidHandle language) + { + _documentTable.Add(new DocumentRow + { + Name = name, + HashAlgorithm = hashAlgorithm, + Hash = hash, + Language = language }); + + return MetadataTokens.DocumentHandle(_documentTable.Count); + } + + public MethodDebugInformationHandle AddMethodDebugInformation(DocumentHandle document, BlobHandle sequencePoints) + { + _methodDebugInformationTable.Add(new MethodDebugInformationRow + { + Document = (uint)MetadataTokens.GetRowNumber(document), + SequencePoints = sequencePoints + }); + + // TODO: + return (MethodDebugInformationHandle)MetadataTokens.Handle(TableIndex.MethodDebugInformation, _methodDebugInformationTable.Count); + } + + public LocalScopeHandle AddLocalScope(MethodDefinitionHandle method, ImportScopeHandle importScope, LocalVariableHandle variableList, LocalConstantHandle constantList, int startOffset, int length) + { + _localScopeTable.Add(new LocalScopeRow + { + Method = (uint)MetadataTokens.GetRowNumber(method), + ImportScope = (uint)MetadataTokens.GetRowNumber(importScope), + VariableList = (uint)MetadataTokens.GetRowNumber(variableList), + ConstantList = (uint)MetadataTokens.GetRowNumber(constantList), + StartOffset = (uint)startOffset, + Length = (uint)length + }); + + return MetadataTokens.LocalScopeHandle(_localScopeTable.Count); + } + + public LocalVariableHandle AddLocalVariable(LocalVariableAttributes attributes, int index, StringHandle name) + { + _localVariableTable.Add(new LocalVariableRow + { + Attributes = (ushort)attributes, + Index = (ushort)index, + Name = name + }); + + return MetadataTokens.LocalVariableHandle(_localVariableTable.Count); + } + + public LocalConstantHandle AddLocalConstant(StringHandle name, BlobHandle signature) + { + _localConstantTable.Add(new LocalConstantRow + { + Name = name, + Signature = signature + }); + + return MetadataTokens.LocalConstantHandle(_localConstantTable.Count); + } + + public ImportScopeHandle AddImportScope(ImportScopeHandle parentScope, BlobHandle imports) + { + _importScopeTable.Add(new ImportScopeRow + { + Parent = (uint)MetadataTokens.GetRowNumber(parentScope), + Imports = imports + }); + + return MetadataTokens.ImportScopeHandle(_importScopeTable.Count); + } + + public void AddStateMachineMethod(MethodDefinitionHandle moveNextMethod, MethodDefinitionHandle kickoffMethod) + { + _stateMachineMethodTable.Add(new StateMachineMethodRow + { + MoveNextMethod = (uint)MetadataTokens.GetRowNumber(moveNextMethod), + KickoffMethod = (uint)MetadataTokens.GetRowNumber(kickoffMethod) + }); + } + + public CustomDebugInformationHandle AddCustomDebugInformation(EntityHandle parent, GuidHandle kind, BlobHandle value) + { + _customDebugInformationTable.Add(new CustomDebugInformationRow + { + Parent = (uint)CodedIndex.ToHasCustomDebugInformation(parent), + Kind = kind, + Value = value + }); + + return MetadataTokens.CustomDebugInformationHandle(_customDebugInformationTable.Count); } #endregion @@ -728,7 +871,7 @@ public ImmutableArray GetRowCounts() rowCounts[(int)TableIndex.MethodSpec] = _methodSpecTable.Count; rowCounts[(int)TableIndex.MethodDef] = _methodDefTable.Count; rowCounts[(int)TableIndex.ModuleRef] = _moduleRefTable.Count; - rowCounts[(int)TableIndex.Module] = 1; + rowCounts[(int)TableIndex.Module] = _moduleTable.Count; rowCounts[(int)TableIndex.NestedClass] = _nestedClassTable.Count; rowCounts[(int)TableIndex.Param] = _paramTable.Count; rowCounts[(int)TableIndex.PropertyMap] = _propertyMapTable.Count; @@ -750,20 +893,9 @@ public ImmutableArray GetRowCounts() return ImmutableArray.CreateRange(rowCounts); } - public int GetModuleVersionGuidOffsetInMetadataStream(int guidHeapOffsetInMetadataStream) - { - // index of module version ID in the guidWriter stream - int moduleVersionIdIndex = _moduleTable[0].ModuleVersionId; - - // offset into the guidWriter stream of the module version ID - int moduleVersionOffsetInGuidTable = (moduleVersionIdIndex - 1) << 4; - - return guidHeapOffsetInMetadataStream + moduleVersionOffsetInGuidTable; - } - #region Serialization - private void SerializeMetadataTables( + internal void SerializeMetadataTables( BlobBuilder writer, MetadataSizes metadataSizes, int methodBodyStreamRva, @@ -775,7 +907,7 @@ private void SerializeMetadataTables( if (metadataSizes.IsPresent(TableIndex.Module)) { - SerializeModuleTable(writer, metadataSizes, _heaps); + SerializeModuleTable(writer, metadataSizes); } if (metadataSizes.IsPresent(TableIndex.TypeRef)) @@ -1038,36 +1170,21 @@ private void SerializeTablesHeader(BlobBuilder writer, MetadataSizes metadataSiz writer.WriteByte(1); // reserved writer.WriteUInt64(metadataSizes.PresentTablesMask); writer.WriteUInt64(sortedTables); - SerializeRowCounts(writer, metadataSizes.RowCounts, metadataSizes.PresentTablesMask); + MetadataWriterUtilities.SerializeRowCounts(writer, metadataSizes.RowCounts); int endPosition = writer.Position; Debug.Assert(metadataSizes.CalculateTableStreamHeaderSize() == endPosition - startPosition); } - private static void SerializeRowCounts(BlobBuilder writer, ImmutableArray rowCounts, ulong includeTables) - { - for (int i = 0; i < rowCounts.Length; i++) - { - if (((1UL << i) & includeTables) != 0) - { - int rowCount = rowCounts[i]; - if (rowCount > 0) - { - writer.WriteInt32(rowCount); - } - } - } - } - - private void SerializeModuleTable(BlobBuilder writer, MetadataSizes metadataSizes, MetadataHeapsBuilder heaps) + private void SerializeModuleTable(BlobBuilder writer, MetadataSizes metadataSizes) { foreach (var moduleRow in _moduleTable) { writer.WriteUInt16(moduleRow.Generation); - writer.WriteReference((uint)heaps.ResolveStringIndex(moduleRow.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)moduleRow.ModuleVersionId, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)moduleRow.EncId, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)moduleRow.EncBaseId, metadataSizes.GuidIndexSize); + writer.WriteReference((uint)GetHeapOffset(moduleRow.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(moduleRow.ModuleVersionId), metadataSizes.GuidIndexSize); + writer.WriteReference((uint)GetHeapOffset(moduleRow.EncId), metadataSizes.GuidIndexSize); + writer.WriteReference((uint)GetHeapOffset(moduleRow.EncBaseId), metadataSizes.GuidIndexSize); } } @@ -1093,8 +1210,8 @@ private void SerializeTypeRefTable(BlobBuilder writer, MetadataSizes metadataSiz foreach (TypeRefRow typeRef in _typeRefTable) { writer.WriteReference(typeRef.ResolutionScope, metadataSizes.ResolutionScopeCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(typeRef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(typeRef.Namespace), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(typeRef.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(typeRef.Namespace), metadataSizes.StringIndexSize); } } @@ -1103,8 +1220,8 @@ private void SerializeTypeDefTable(BlobBuilder writer, MetadataSizes metadataSiz foreach (TypeDefRow typeDef in _typeDefTable) { writer.WriteUInt32(typeDef.Flags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(typeDef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(typeDef.Namespace), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(typeDef.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(typeDef.Namespace), metadataSizes.StringIndexSize); writer.WriteReference(typeDef.Extends, metadataSizes.TypeDefOrRefCodedIndexSize); writer.WriteReference(typeDef.FieldList, metadataSizes.FieldDefIndexSize); writer.WriteReference(typeDef.MethodList, metadataSizes.MethodDefIndexSize); @@ -1116,8 +1233,8 @@ private void SerializeFieldTable(BlobBuilder writer, MetadataSizes metadataSizes foreach (FieldDefRow fieldDef in _fieldTable) { writer.WriteUInt16(fieldDef.Flags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(fieldDef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(fieldDef.Signature), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(fieldDef.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(fieldDef.Signature), metadataSizes.BlobIndexSize); } } @@ -1125,19 +1242,19 @@ private void SerializeMethodDefTable(BlobBuilder writer, MetadataSizes metadataS { foreach (MethodRow method in _methodDefTable) { - if (method.Rva == -1) + if (method.BodyOffset == -1) { writer.WriteUInt32(0); } else { - writer.WriteUInt32((uint)(methodBodyStreamRva + method.Rva)); + writer.WriteUInt32((uint)(methodBodyStreamRva + method.BodyOffset)); } writer.WriteUInt16(method.ImplFlags); writer.WriteUInt16(method.Flags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(method.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(method.Signature), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(method.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(method.Signature), metadataSizes.BlobIndexSize); writer.WriteReference(method.ParamList, metadataSizes.ParameterIndexSize); } } @@ -1148,7 +1265,7 @@ private void SerializeParamTable(BlobBuilder writer, MetadataSizes metadataSizes { writer.WriteUInt16(param.Flags); writer.WriteUInt16(param.Sequence); - writer.WriteReference((uint)_heaps.ResolveStringIndex(param.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(param.Name), metadataSizes.StringIndexSize); } } @@ -1168,22 +1285,22 @@ private void SerializeMemberRefTable(BlobBuilder writer, MetadataSizes metadataS foreach (MemberRefRow memberRef in _memberRefTable) { writer.WriteReference(memberRef.Class, metadataSizes.MemberRefParentCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(memberRef.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(memberRef.Signature), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(memberRef.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(memberRef.Signature), metadataSizes.BlobIndexSize); } } private void SerializeConstantTable(BlobBuilder writer, MetadataSizes metadataSizes) { // Note: we can sort the table at this point since no other table can reference its rows via RowId or CodedIndex (which would need updating otherwise). - var ordered = _constantTableNeedsSorting ? _constantTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _constantTable; + var ordered = _constantTableNeedsSorting ? (IEnumerable)_constantTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _constantTable; foreach (ConstantRow constant in ordered) { writer.WriteByte(constant.Type); writer.WriteByte(0); writer.WriteReference(constant.Parent, metadataSizes.HasConstantCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(constant.Value), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(constant.Value), metadataSizes.BlobIndexSize); } } @@ -1191,25 +1308,25 @@ private void SerializeCustomAttributeTable(BlobBuilder writer, MetadataSizes met { // Note: we can sort the table at this point since no other table can reference its rows via RowId or CodedIndex (which would need updating otherwise). // OrderBy performs a stable sort, so multiple attributes with the same parent will be sorted in the order they were added to the table. - var ordered = _customAttributeTableNeedsSorting ? _customAttributeTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _customAttributeTable; + var ordered = _customAttributeTableNeedsSorting ? (IEnumerable)_customAttributeTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _customAttributeTable; foreach (CustomAttributeRow customAttribute in ordered) { writer.WriteReference(customAttribute.Parent, metadataSizes.HasCustomAttributeCodedIndexSize); writer.WriteReference(customAttribute.Type, metadataSizes.CustomAttributeTypeCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(customAttribute.Value), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(customAttribute.Value), metadataSizes.BlobIndexSize); } } private void SerializeFieldMarshalTable(BlobBuilder writer, MetadataSizes metadataSizes) { // Note: we can sort the table at this point since no other table can reference its rows via RowId or CodedIndex (which would need updating otherwise). - var ordered = _fieldMarshalTableNeedsSorting ? _fieldMarshalTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _fieldMarshalTable; + var ordered = _fieldMarshalTableNeedsSorting ? (IEnumerable)_fieldMarshalTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _fieldMarshalTable; foreach (FieldMarshalRow fieldMarshal in ordered) { writer.WriteReference(fieldMarshal.Parent, metadataSizes.HasFieldMarshalCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(fieldMarshal.NativeType), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(fieldMarshal.NativeType), metadataSizes.BlobIndexSize); } } @@ -1217,13 +1334,13 @@ private void SerializeDeclSecurityTable(BlobBuilder writer, MetadataSizes metada { // Note: we can sort the table at this point since no other table can reference its rows via RowId or CodedIndex (which would need updating otherwise). // OrderBy performs a stable sort, so multiple attributes with the same parent will be sorted in the order they were added to the table. - var ordered = _declSecurityTableNeedsSorting ? _declSecurityTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _declSecurityTable; + var ordered = _declSecurityTableNeedsSorting ? (IEnumerable)_declSecurityTable.OrderBy((x, y) => (int)x.Parent - (int)y.Parent) : _declSecurityTable; foreach (DeclSecurityRow declSecurity in ordered) { writer.WriteUInt16(declSecurity.Action); writer.WriteReference(declSecurity.Parent, metadataSizes.DeclSecurityCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(declSecurity.PermissionSet), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(declSecurity.PermissionSet), metadataSizes.BlobIndexSize); } } @@ -1262,7 +1379,7 @@ private void SerializeStandAloneSigTable(BlobBuilder writer, MetadataSizes metad { foreach (StandaloneSigRow row in _standAloneSigTable) { - writer.WriteReference((uint)_heaps.ResolveBlobIndex(row.Signature), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Signature), metadataSizes.BlobIndexSize); } } @@ -1280,7 +1397,7 @@ private void SerializeEventTable(BlobBuilder writer, MetadataSizes metadataSizes foreach (EventRow eventRow in _eventTable) { writer.WriteUInt16(eventRow.EventFlags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(eventRow.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(eventRow.Name), metadataSizes.StringIndexSize); writer.WriteReference(eventRow.EventType, metadataSizes.TypeDefOrRefCodedIndexSize); } } @@ -1299,8 +1416,8 @@ private void SerializePropertyTable(BlobBuilder writer, MetadataSizes metadataSi foreach (PropertyRow property in _propertyTable) { writer.WriteUInt16(property.PropFlags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(property.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(property.Type), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(property.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(property.Type), metadataSizes.BlobIndexSize); } } @@ -1308,7 +1425,7 @@ private void SerializeMethodSemanticsTable(BlobBuilder writer, MetadataSizes met { // Note: we can sort the table at this point since no other table can reference its rows via RowId or CodedIndex (which would need updating otherwise). // OrderBy performs a stable sort, so multiple attributes with the same parent will be sorted in the order they were added to the table. - var ordered = _methodSemanticsTableNeedsSorting ? _methodSemanticsTable.OrderBy((x, y) => (int)x.Association - (int)y.Association) : _methodSemanticsTable; + var ordered = _methodSemanticsTableNeedsSorting ? (IEnumerable)_methodSemanticsTable.OrderBy((x, y) => (int)x.Association - (int)y.Association) : _methodSemanticsTable; foreach (MethodSemanticsRow methodSemantic in ordered) { @@ -1338,7 +1455,7 @@ private void SerializeModuleRefTable(BlobBuilder writer, MetadataSizes metadataS { foreach (ModuleRefRow moduleRef in _moduleRefTable) { - writer.WriteReference((uint)_heaps.ResolveStringIndex(moduleRef.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(moduleRef.Name), metadataSizes.StringIndexSize); } } @@ -1346,7 +1463,7 @@ private void SerializeTypeSpecTable(BlobBuilder writer, MetadataSizes metadataSi { foreach (TypeSpecRow typeSpec in _typeSpecTable) { - writer.WriteReference((uint)_heaps.ResolveBlobIndex(typeSpec.Signature), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(typeSpec.Signature), metadataSizes.BlobIndexSize); } } @@ -1362,7 +1479,7 @@ private void SerializeImplMapTable(BlobBuilder writer, MetadataSizes metadataSiz { writer.WriteUInt16(implMap.MappingFlags); writer.WriteReference(implMap.MemberForwarded, metadataSizes.MemberForwardedCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(implMap.ImportName), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(implMap.ImportName), metadataSizes.StringIndexSize); writer.WriteReference(implMap.ImportScope, metadataSizes.ModuleRefIndexSize); } } @@ -1392,9 +1509,9 @@ private void SerializeAssemblyTable(BlobBuilder writer, MetadataSizes metadataSi writer.WriteUInt16((ushort)row.Version.Build); writer.WriteUInt16((ushort)row.Version.Revision); writer.WriteUInt32(row.Flags); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(row.AssemblyKey), metadataSizes.BlobIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(row.AssemblyName), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(row.AssemblyCulture), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.AssemblyKey), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.AssemblyName), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.AssemblyCulture), metadataSizes.StringIndexSize); } } @@ -1407,10 +1524,10 @@ private void SerializeAssemblyRefTable(BlobBuilder writer, MetadataSizes metadat writer.WriteUInt16((ushort)row.Version.Build); writer.WriteUInt16((ushort)row.Version.Revision); writer.WriteUInt32(row.Flags); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(row.PublicKeyToken), metadataSizes.BlobIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(row.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(row.Culture), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(row.HashValue), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.PublicKeyToken), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Culture), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.HashValue), metadataSizes.BlobIndexSize); } } @@ -1419,8 +1536,8 @@ private void SerializeFileTable(BlobBuilder writer, MetadataSizes metadataSizes) foreach (FileTableRow fileReference in _fileTable) { writer.WriteUInt32(fileReference.Flags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(fileReference.FileName), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(fileReference.HashValue), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(fileReference.FileName), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(fileReference.HashValue), metadataSizes.BlobIndexSize); } } @@ -1430,8 +1547,8 @@ private void SerializeExportedTypeTable(BlobBuilder writer, MetadataSizes metada { writer.WriteUInt32((uint)exportedType.Flags); writer.WriteUInt32(exportedType.TypeDefId); - writer.WriteReference((uint)_heaps.ResolveStringIndex(exportedType.TypeName), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(exportedType.TypeNamespace), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(exportedType.TypeName), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(exportedType.TypeNamespace), metadataSizes.StringIndexSize); writer.WriteReference(exportedType.Implementation, metadataSizes.ImplementationCodedIndexSize); } } @@ -1442,7 +1559,7 @@ private void SerializeManifestResourceTable(BlobBuilder writer, MetadataSizes me { writer.WriteUInt32(manifestResource.Offset); writer.WriteUInt32(manifestResource.Flags); - writer.WriteReference((uint)_heaps.ResolveStringIndex(manifestResource.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(manifestResource.Name), metadataSizes.StringIndexSize); writer.WriteReference(manifestResource.Implementation, metadataSizes.ImplementationCodedIndexSize); } } @@ -1477,7 +1594,7 @@ private void SerializeGenericParamTable(BlobBuilder writer, MetadataSizes metada writer.WriteUInt16(genericParam.Number); writer.WriteUInt16(genericParam.Flags); writer.WriteReference(genericParam.Owner, metadataSizes.TypeOrMethodDefCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveStringIndex(genericParam.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(genericParam.Name), metadataSizes.StringIndexSize); } } @@ -1501,7 +1618,7 @@ private void SerializeMethodSpecTable(BlobBuilder writer, MetadataSizes metadata foreach (MethodSpecRow methodSpec in _methodSpecTable) { writer.WriteReference(methodSpec.Method, metadataSizes.MethodDefOrRefCodedIndexSize); - writer.WriteReference((uint)_heaps.ResolveBlobIndex(methodSpec.Instantiation), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(methodSpec.Instantiation), metadataSizes.BlobIndexSize); } } @@ -1509,10 +1626,10 @@ private void SerializeDocumentTable(BlobBuilder writer, MetadataSizes metadataSi { foreach (var row in _documentTable) { - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Name), metadataSizes.BlobIndexSize); - writer.WriteReference(row.HashAlgorithm, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Hash), metadataSizes.BlobIndexSize); - writer.WriteReference(row.Language, metadataSizes.GuidIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Name), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.HashAlgorithm), metadataSizes.GuidIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Hash), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Language), metadataSizes.GuidIndexSize); } } @@ -1521,7 +1638,7 @@ private void SerializeMethodDebugInformationTable(BlobBuilder writer, MetadataSi foreach (var row in _methodDebugInformationTable) { writer.WriteReference(row.Document, metadataSizes.DocumentIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.SequencePoints), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.SequencePoints), metadataSizes.BlobIndexSize); } } @@ -1559,7 +1676,7 @@ private void SerializeLocalVariableTable(BlobBuilder writer, MetadataSizes metad { writer.WriteUInt16(row.Attributes); writer.WriteUInt16(row.Index); - writer.WriteReference((uint)_debugHeapsOpt.ResolveStringIndex(row.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Name), metadataSizes.StringIndexSize); } } @@ -1567,8 +1684,8 @@ private void SerializeLocalConstantTable(BlobBuilder writer, MetadataSizes metad { foreach (var row in _localConstantTable) { - writer.WriteReference((uint)_debugHeapsOpt.ResolveStringIndex(row.Name), metadataSizes.StringIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Signature), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Name), metadataSizes.StringIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Signature), metadataSizes.BlobIndexSize); } } @@ -1577,7 +1694,7 @@ private void SerializeImportScopeTable(BlobBuilder writer, MetadataSizes metadat foreach (var row in _importScopeTable) { writer.WriteReference(row.Parent, metadataSizes.ImportScopeIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Imports), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Imports), metadataSizes.BlobIndexSize); } } @@ -1603,12 +1720,12 @@ private void SerializeCustomDebugInformationTable(BlobBuilder writer, MetadataSi foreach (CustomDebugInformationRow row in _customDebugInformationTable.OrderBy((x, y) => { int result = (int)x.Parent - (int)y.Parent; - return (result != 0) ? result : (int)x.Kind - (int)y.Kind; + return (result != 0) ? result : MetadataTokens.GetHeapOffset(x.Kind) - MetadataTokens.GetHeapOffset(y.Kind); })) { writer.WriteReference(row.Parent, metadataSizes.HasCustomDebugInformationSize); - writer.WriteReference(row.Kind, metadataSizes.GuidIndexSize); - writer.WriteReference((uint)_debugHeapsOpt.ResolveBlobIndex(row.Value), metadataSizes.BlobIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Kind), metadataSizes.GuidIndexSize); + writer.WriteReference((uint)GetHeapOffset(row.Value), metadataSizes.BlobIndexSize); } } diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataSerializer.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataSerializer.cs new file mode 100644 index 0000000000000..2bd745ecf2adf --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataSerializer.cs @@ -0,0 +1,234 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; + +#if SRM +using System.Reflection.PortableExecutable; +#else +using Roslyn.Reflection.PortableExecutable; +#endif + +#if SRM +namespace System.Reflection.Metadata.Ecma335 +#else +namespace Roslyn.Reflection.Metadata.Ecma335 +#endif +{ +#if SRM + public +#endif + sealed class StandaloneDebugMetadataSerializer : MetadataSerializer + { + private const string DebugMetadataVersionString = "PDB v1.0"; + + private Blob _pdbIdBlob; + private readonly MethodDefinitionHandle _entryPoint; + + public StandaloneDebugMetadataSerializer( + MetadataBuilder builder, + ImmutableArray typeSystemRowCounts, + MethodDefinitionHandle entryPoint, + bool isMinimalDelta) + : base(builder, CreateSizes(builder, typeSystemRowCounts, isMinimalDelta, isStandaloneDebugMetadata: true), DebugMetadataVersionString) + { + _entryPoint = entryPoint; + } + + /// + /// Serialized #Pdb stream. + /// + protected override void SerializeStandalonePdbStream(BlobBuilder builder) + { + int startPosition = builder.Position; + + // the id will be filled in later + _pdbIdBlob = builder.ReserveBytes(MetadataSizes.PdbIdSize); + + builder.WriteInt32(_entryPoint.IsNil ? 0 : MetadataTokens.GetToken(_entryPoint)); + + builder.WriteUInt64(MetadataSizes.ExternalTablesMask); + MetadataWriterUtilities.SerializeRowCounts(builder, MetadataSizes.ExternalRowCounts); + + int endPosition = builder.Position; + Debug.Assert(MetadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition); + } + + public void SerializeMetadata(BlobBuilder builder, Func idProvider, out ContentId contentId) + { + SerializeMetadataImpl(builder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0); + + contentId = idProvider(builder); + + // fill in the id: + var idWriter = new BlobWriter(_pdbIdBlob); + idWriter.WriteBytes(contentId.Guid); + idWriter.WriteBytes(contentId.Stamp); + Debug.Assert(idWriter.RemainingBytes == 0); + } + } + +#if SRM + public +#endif + sealed class TypeSystemMetadataSerializer : MetadataSerializer + { + private static readonly ImmutableArray EmptyRowCounts = ImmutableArray.CreateRange(Enumerable.Repeat(0, MetadataTokens.TableCount)); + + public TypeSystemMetadataSerializer( + MetadataBuilder tables, + string metadataVersion, + bool isMinimalDelta) + : base(tables, CreateSizes(tables, EmptyRowCounts, isMinimalDelta, isStandaloneDebugMetadata: false), metadataVersion) + { + + } + + protected override void SerializeStandalonePdbStream(BlobBuilder writer) + { + // nop + } + + public void SerializeMetadata(BlobBuilder metadataWriter, int methodBodyStreamRva, int mappedFieldDataStreamRva) + { + SerializeMetadataImpl(metadataWriter, methodBodyStreamRva, mappedFieldDataStreamRva); + } + } + +#if SRM + public +#endif + abstract class MetadataSerializer + { + protected readonly MetadataBuilder _tables; + private readonly MetadataSizes _sizes; + private readonly string _metadataVersion; + + public MetadataSerializer(MetadataBuilder tables, MetadataSizes sizes, string metadataVersion) + { + _tables = tables; + _sizes = sizes; + _metadataVersion = metadataVersion; + } + + internal static MetadataSizes CreateSizes(MetadataBuilder tables, ImmutableArray externalRowCounts, bool isMinimalDelta, bool isStandaloneDebugMetadata) + { + tables.CompleteHeaps(); + + return new MetadataSizes( + tables.GetRowCounts(), + externalRowCounts, + tables.GetHeapSizes(), + isMinimalDelta, + isStandaloneDebugMetadata); + } + + protected abstract void SerializeStandalonePdbStream(BlobBuilder writer); + + public MetadataSizes MetadataSizes => _sizes; + + protected void SerializeMetadataImpl(BlobBuilder metadataWriter, int methodBodyStreamRva, int mappedFieldDataStreamRva) + { + // header: + SerializeMetadataHeader(metadataWriter); + + // #Pdb stream + SerializeStandalonePdbStream(metadataWriter); + + // #~ or #- stream: + _tables.SerializeMetadataTables(metadataWriter, _sizes, methodBodyStreamRva, mappedFieldDataStreamRva); + + // #Strings, #US, #Guid and #Blob streams: + _tables.WriteHeapsTo(metadataWriter); + } + + private void SerializeMetadataHeader(BlobBuilder writer) + { + int startOffset = writer.Position; + + // signature + writer.WriteUInt32(0x424A5342); + + // major version + writer.WriteUInt16(1); + + // minor version + writer.WriteUInt16(1); + + // reserved + writer.WriteUInt32(0); + + // metadata version length + writer.WriteUInt32(MetadataSizes.MetadataVersionPaddedLength); + + int n = Math.Min(MetadataSizes.MetadataVersionPaddedLength, _metadataVersion.Length); + for (int i = 0; i < n; i++) + { + writer.WriteByte((byte)_metadataVersion[i]); + } + + for (int i = n; i < MetadataSizes.MetadataVersionPaddedLength; i++) + { + writer.WriteByte(0); + } + + // reserved + writer.WriteUInt16(0); + + // number of streams + writer.WriteUInt16((ushort)(5 + (_sizes.IsMinimalDelta ? 1 : 0) + (_sizes.IsStandaloneDebugMetadata ? 1 : 0))); + + // stream headers + int offsetFromStartOfMetadata = _sizes.MetadataHeaderSize; + + // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID + if (_sizes.IsStandaloneDebugMetadata) + { + SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.StandalonePdbStreamSize, "#Pdb", writer); + } + + // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables; + // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard. + // + // Note: EnC delta is stored as uncompressed metadata stream. + SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.MetadataTableStreamSize, (_sizes.IsMetadataTableStreamCompressed ? "#~" : "#-"), writer); + + SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", writer); + SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", writer); + + if (_sizes.IsMinimalDelta) + { + SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", writer); + } + + int endOffset = writer.Position; + Debug.Assert(endOffset - startOffset == _sizes.MetadataHeaderSize); + } + + private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BlobBuilder writer) + { + // 4 for the first uint (offset), 4 for the second uint (padded size), length of stream name + 1 for null terminator (then padded) + int sizeOfStreamHeader = MetadataSizes.GetMetadataStreamHeaderSize(streamName); + writer.WriteInt32(offsetFromStartOfMetadata); + writer.WriteInt32(alignedStreamSize); + foreach (char ch in streamName) + { + writer.WriteByte((byte)ch); + } + + // After offset, size, and stream name, write 0-bytes until we reach our padded size. + for (uint i = 8 + (uint)streamName.Length; i < sizeOfStreamHeader; i++) + { + writer.WriteByte(0); + } + + offsetFromStartOfMetadata += alignedStreamSize; + } + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/MetadataSizes.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataSizes.cs similarity index 89% rename from src/Compilers/Core/Portable/PEWriter/MetadataSizes.cs rename to src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataSizes.cs index ae312cb432c41..2b67eaf5aae46 100644 --- a/src/Compilers/Core/Portable/PEWriter/MetadataSizes.cs +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Ecma335/MetadataSizes.cs @@ -3,11 +3,24 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Metadata.Ecma335; + +#if SRM +using System.Reflection.Internal; +using BitArithmeticUtilities = System.Reflection.Internal.BitArithmetic; +#else using Roslyn.Utilities; +#endif -namespace Microsoft.Cci +#if SRM +namespace System.Reflection.Metadata.Ecma335 +#else +namespace Roslyn.Reflection.Metadata.Ecma335 +#endif { - internal sealed class MetadataSizes +#if SRM + public +#endif + sealed class MetadataSizes { private const int StreamAlignment = 4; @@ -67,6 +80,11 @@ internal sealed class MetadataSizes /// public readonly ImmutableArray RowCounts; + /// + /// External table row counts. + /// + public readonly ImmutableArray ExternalRowCounts; + /// /// Non-empty tables that are emitted into the metadata table stream. /// @@ -99,77 +117,34 @@ internal sealed class MetadataSizes /// public readonly int StandalonePdbStreamSize; - /// - /// The size of IL stream. - /// - public readonly int ILStreamSize; - - /// - /// The size of mapped field data stream. - /// Aligned to . - /// - public readonly int MappedFieldDataSize; - - /// - /// The size of managed resource data stream. - /// Aligned to . - /// - public readonly int ResourceDataSize; - - /// - /// Size of strong name hash. - /// - public readonly int StrongNameSignatureSize; - public MetadataSizes( ImmutableArray rowCounts, + ImmutableArray externalRowCounts, ImmutableArray heapSizes, - int ilStreamSize, - int mappedFieldDataSize, - int resourceDataSize, - int strongNameSignatureSize, bool isMinimalDelta, - bool emitStandaloneDebugMetadata, bool isStandaloneDebugMetadata) { Debug.Assert(rowCounts.Length == MetadataTokens.TableCount); + Debug.Assert(externalRowCounts.Length == MetadataTokens.TableCount); Debug.Assert(heapSizes.Length == MetadataTokens.HeapCount); - Debug.Assert(!isStandaloneDebugMetadata || emitStandaloneDebugMetadata); const byte large = 4; const byte small = 2; this.RowCounts = rowCounts; + this.ExternalRowCounts = externalRowCounts; this.HeapSizes = heapSizes; - this.ResourceDataSize = resourceDataSize; - this.ILStreamSize = ilStreamSize; - this.MappedFieldDataSize = mappedFieldDataSize; - this.StrongNameSignatureSize = strongNameSignatureSize; this.IsMinimalDelta = isMinimalDelta; this.BlobIndexSize = (isMinimalDelta || heapSizes[(int)HeapIndex.Blob] > ushort.MaxValue) ? large : small; this.StringIndexSize = (isMinimalDelta || heapSizes[(int)HeapIndex.String] > ushort.MaxValue) ? large : small; this.GuidIndexSize = (isMinimalDelta || heapSizes[(int)HeapIndex.Guid] > ushort.MaxValue) ? large : small; - ulong allTables = ComputeNonEmptyTableMask(rowCounts); - if (!emitStandaloneDebugMetadata) - { - // all tables - PresentTablesMask = allTables; - ExternalTablesMask = 0; - } - else if (isStandaloneDebugMetadata) - { - // debug tables: - PresentTablesMask = allTables & DebugMetadataTablesMask; - ExternalTablesMask = allTables & ~DebugMetadataTablesMask; - } - else - { - // type-system tables only: - PresentTablesMask = allTables & ~DebugMetadataTablesMask; - ExternalTablesMask = 0; - } + this.PresentTablesMask = ComputeNonEmptyTableMask(rowCounts); + this.ExternalTablesMask = ComputeNonEmptyTableMask(externalRowCounts); + + // table can either be present or external, it can't be both: + Debug.Assert((PresentTablesMask & ExternalTablesMask) == 0); this.CustomAttributeTypeCodedIndexSize = this.GetReferenceByteSize(3, TableIndex.MethodDef, TableIndex.MemberRef); this.DeclSecurityCodedIndexSize = this.GetReferenceByteSize(2, TableIndex.MethodDef, TableIndex.TypeDef); @@ -414,18 +389,11 @@ internal int CalculateTableStreamHeaderSize() internal int CalculateStandalonePdbStreamSize() { - int result = PdbIdSize + // PDB ID - sizeof(int) + // EntryPoint - sizeof(long); // ReferencedTypeSystemTables - - // external table row counts - for (int i = 0; i < RowCounts.Length; i++) - { - if (((1UL << i) & ExternalTablesMask) != 0) - { - result += sizeof(int); - } - } + int result = + PdbIdSize + // PDB ID + sizeof(int) + // EntryPoint + sizeof(long) + // ReferencedTypeSystemTables + BitArithmeticUtilities.CountBits(ExternalTablesMask) * sizeof(int); // External row counts Debug.Assert(result % StreamAlignment == 0); return result; @@ -447,7 +415,7 @@ private static ulong ComputeNonEmptyTableMask(ImmutableArray rowCounts) private int GetTableSize(TableIndex index, int rowSize) { - return (PresentTablesMask & (1UL << (int)index)) != 0 ? RowCounts[(int)index] * rowSize : 0; + return RowCounts[(int)index] * rowSize; } private byte GetReferenceByteSize(int tagBitSize, params TableIndex[] tables) @@ -464,7 +432,10 @@ private bool ReferenceFits(int bitCount, TableIndex[] tables) int maxIndex = (1 << bitCount) - 1; foreach (TableIndex table in tables) { - if (RowCounts[(int)table] > maxIndex) + // table can be either local or external, but not both: + Debug.Assert(RowCounts[(int)table] == 0 || ExternalRowCounts[(int)table] == 0); + + if (RowCounts[(int)table] + ExternalRowCounts[(int)table] > maxIndex) { return false; } diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCode.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCode.cs index a5347482afedd..94add15ddc5c0 100644 --- a/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCode.cs +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCode.cs @@ -1,6 +1,4 @@ -// 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. +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #if SRM namespace System.Reflection.Metadata diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCodeExtensions.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCodeExtensions.cs new file mode 100644 index 0000000000000..10dcfd4183bf2 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/ILOpCodeExtensions.cs @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if !SRM +using System; +#endif + +#if SRM +namespace System.Reflection.Metadata +#else +namespace Microsoft.CodeAnalysis.CodeGen +#endif +{ +#if SRM + public +#endif + static partial class ILOpCodeExtensions + { + /// + /// Returns true of the specified op-code is a branch to a label. + /// + public static bool IsBranch(this ILOpCode opCode) + { + switch (opCode) + { + case ILOpCode.Br: + case ILOpCode.Br_s: + case ILOpCode.Brtrue: + case ILOpCode.Brtrue_s: + case ILOpCode.Brfalse: + case ILOpCode.Brfalse_s: + case ILOpCode.Beq: + case ILOpCode.Beq_s: + case ILOpCode.Bne_un: + case ILOpCode.Bne_un_s: + case ILOpCode.Bge: + case ILOpCode.Bge_s: + case ILOpCode.Bge_un: + case ILOpCode.Bge_un_s: + case ILOpCode.Bgt: + case ILOpCode.Bgt_s: + case ILOpCode.Bgt_un: + case ILOpCode.Bgt_un_s: + case ILOpCode.Ble: + case ILOpCode.Ble_s: + case ILOpCode.Ble_un: + case ILOpCode.Ble_un_s: + case ILOpCode.Blt: + case ILOpCode.Blt_s: + case ILOpCode.Blt_un: + case ILOpCode.Blt_un_s: + case ILOpCode.Leave: + case ILOpCode.Leave_s: + return true; + } + + return false; + } + + /// + /// Calculate the size of the specified branch instruction operand. + /// + /// Branch op-code. + /// 1 if is a short branch or 4 if it is a long branch. + /// Specified is not a branch op-code. + public static int GetBranchOperandSize(this ILOpCode opCode) + { + switch (opCode) + { + case ILOpCode.Br_s: + case ILOpCode.Brfalse_s: + case ILOpCode.Brtrue_s: + case ILOpCode.Beq_s: + case ILOpCode.Bge_s: + case ILOpCode.Bgt_s: + case ILOpCode.Ble_s: + case ILOpCode.Blt_s: + case ILOpCode.Bne_un_s: + case ILOpCode.Bge_un_s: + case ILOpCode.Bgt_un_s: + case ILOpCode.Ble_un_s: + case ILOpCode.Blt_un_s: + case ILOpCode.Leave_s: + return 1; + + case ILOpCode.Br: + case ILOpCode.Brfalse: + case ILOpCode.Brtrue: + case ILOpCode.Beq: + case ILOpCode.Bge: + case ILOpCode.Bgt: + case ILOpCode.Ble: + case ILOpCode.Blt: + case ILOpCode.Bne_un: + case ILOpCode.Bge_un: + case ILOpCode.Bgt_un: + case ILOpCode.Ble_un: + case ILOpCode.Blt_un: + case ILOpCode.Leave: + return 4; + } + + throw new ArgumentException("Expected branch opcode.", nameof(opCode)); + } + + /// + /// Get a short form of the specified branch op-code. + /// + /// Branch op-code. + /// Short form of the branch op-code. + /// Specified is not a branch op-code. + public static ILOpCode GetShortBranch(this ILOpCode opCode) + { + switch (opCode) + { + case ILOpCode.Br_s: + case ILOpCode.Brfalse_s: + case ILOpCode.Brtrue_s: + case ILOpCode.Beq_s: + case ILOpCode.Bge_s: + case ILOpCode.Bgt_s: + case ILOpCode.Ble_s: + case ILOpCode.Blt_s: + case ILOpCode.Bne_un_s: + case ILOpCode.Bge_un_s: + case ILOpCode.Bgt_un_s: + case ILOpCode.Ble_un_s: + case ILOpCode.Blt_un_s: + case ILOpCode.Leave_s: + return opCode; + + case ILOpCode.Br: + return ILOpCode.Br_s; + + case ILOpCode.Brfalse: + return ILOpCode.Brfalse_s; + + case ILOpCode.Brtrue: + return ILOpCode.Brtrue_s; + + case ILOpCode.Beq: + return ILOpCode.Beq_s; + + case ILOpCode.Bge: + return ILOpCode.Bge_s; + + case ILOpCode.Bgt: + return ILOpCode.Bgt_s; + + case ILOpCode.Ble: + return ILOpCode.Ble_s; + + case ILOpCode.Blt: + return ILOpCode.Blt_s; + + case ILOpCode.Bne_un: + return ILOpCode.Bne_un_s; + + case ILOpCode.Bge_un: + return ILOpCode.Bge_un_s; + + case ILOpCode.Bgt_un: + return ILOpCode.Bgt_un_s; + + case ILOpCode.Ble_un: + return ILOpCode.Ble_un_s; + + case ILOpCode.Blt_un: + return ILOpCode.Blt_un_s; + + case ILOpCode.Leave: + return ILOpCode.Leave_s; + } + + throw new ArgumentException("Expected branch opcode.", nameof(opCode)); + } + + /// + /// Get a long form of the specified branch op-code. + /// + /// Branch op-code. + /// Long form of the branch op-code. + /// Specified is not a branch op-code. + public static ILOpCode GetLongBranch(this ILOpCode opCode) + { + switch (opCode) + { + case ILOpCode.Br: + case ILOpCode.Brfalse: + case ILOpCode.Brtrue: + case ILOpCode.Beq: + case ILOpCode.Bge: + case ILOpCode.Bgt: + case ILOpCode.Ble: + case ILOpCode.Blt: + case ILOpCode.Bne_un: + case ILOpCode.Bge_un: + case ILOpCode.Bgt_un: + case ILOpCode.Ble_un: + case ILOpCode.Blt_un: + case ILOpCode.Leave: + return opCode; + + case ILOpCode.Br_s: + return ILOpCode.Br; + + case ILOpCode.Brfalse_s: + return ILOpCode.Brfalse; + + case ILOpCode.Brtrue_s: + return ILOpCode.Brtrue; + + case ILOpCode.Beq_s: + return ILOpCode.Beq; + + case ILOpCode.Bge_s: + return ILOpCode.Bge; + + case ILOpCode.Bgt_s: + return ILOpCode.Bgt; + + case ILOpCode.Ble_s: + return ILOpCode.Ble; + + case ILOpCode.Blt_s: + return ILOpCode.Blt; + + case ILOpCode.Bne_un_s: + return ILOpCode.Bne_un; + + case ILOpCode.Bge_un_s: + return ILOpCode.Bge_un; + + case ILOpCode.Bgt_un_s: + return ILOpCode.Bgt_un; + + case ILOpCode.Ble_un_s: + return ILOpCode.Ble_un; + + case ILOpCode.Blt_un_s: + return ILOpCode.Blt_un; + + case ILOpCode.Leave_s: + return ILOpCode.Leave; + } + + throw new ArgumentException("Expected branch opcode.", nameof(opCode)); + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/ImageFormatLimitationException.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/ImageFormatLimitationException.cs new file mode 100644 index 0000000000000..1ed404df80b25 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/ImageFormatLimitationException.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Reflection.Metadata.Ecma335; + +#if SRM +namespace System.Reflection.Metadata +#else +namespace Roslyn.Reflection.Metadata +#endif +{ +#if SRM + public +#endif + class ImageFormatLimitationException : Exception + { + private ImageFormatLimitationException(string message) + : base(message) + { + } + + internal static void ThrowHeapSizeLimitExceeded(HeapIndex heapIndex) + { + // TODO: localize + throw new ImageFormatLimitationException($"The limit on the size of #{heapIndex} heap has been exceeded."); + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Internal/HeapSizeFlag.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Internal/HeapSizeFlag.cs new file mode 100644 index 0000000000000..e8fd2380b235d --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Internal/HeapSizeFlag.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if SRM +namespace System.Reflection.Metadata.Ecma335 +#else +namespace Roslyn.Reflection.Metadata.Ecma335 +#endif +{ + internal enum HeapSizeFlag : byte + { + StringHeapLarge = 0x01, // 4 byte uint indexes used for string heap offsets + GuidHeapLarge = 0x02, // 4 byte uint indexes used for GUID heap offsets + BlobHeapLarge = 0x04, // 4 byte uint indexes used for Blob heap offsets + EnCDeltas = 0x20, // Indicates only EnC Deltas are present + DeletedMarks = 0x80, // Indicates metadata might contain items marked deleted + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/Metadata/Internal/MetadataWriterUtilities.cs b/src/Compilers/Core/Portable/System/Reflection/Metadata/Internal/MetadataWriterUtilities.cs new file mode 100644 index 0000000000000..6765023f75290 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/Metadata/Internal/MetadataWriterUtilities.cs @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Immutable; +using System.Diagnostics; + +#if SRM +using System.Reflection.Internal; +#else +using System; +using System.Reflection; +using System.Reflection.Metadata; +#endif + +#if SRM +namespace System.Reflection.Metadata.Ecma335 +#else +namespace Roslyn.Reflection.Metadata.Ecma335 +#endif +{ + internal static class MetadataWriterUtilities + { + public static SignatureTypeCode GetConstantTypeCode(object value) + { + if (value == null) + { + // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a zero. + return (SignatureTypeCode)0x12; // TODO + } + + Debug.Assert(!value.GetType().GetTypeInfo().IsEnum); + + // Perf: Note that JIT optimizes each expression val.GetType() == typeof(T) to a single register comparison. + // Also the checks are sorted by commonality of the checked types. + + if (value.GetType() == typeof(int)) + { + return SignatureTypeCode.Int32; + } + + if (value.GetType() == typeof(string)) + { + return SignatureTypeCode.String; + } + + if (value.GetType() == typeof(bool)) + { + return SignatureTypeCode.Boolean; + } + + if (value.GetType() == typeof(char)) + { + return SignatureTypeCode.Char; + } + + if (value.GetType() == typeof(byte)) + { + return SignatureTypeCode.Byte; + } + + if (value.GetType() == typeof(long)) + { + return SignatureTypeCode.Int64; + } + + if (value.GetType() == typeof(double)) + { + return SignatureTypeCode.Double; + } + + if (value.GetType() == typeof(short)) + { + return SignatureTypeCode.Int16; + } + + if (value.GetType() == typeof(ushort)) + { + return SignatureTypeCode.UInt16; + } + + if (value.GetType() == typeof(uint)) + { + return SignatureTypeCode.UInt32; + } + + if (value.GetType() == typeof(sbyte)) + { + return SignatureTypeCode.SByte; + } + + if (value.GetType() == typeof(ulong)) + { + return SignatureTypeCode.UInt64; + } + + if (value.GetType() == typeof(float)) + { + return SignatureTypeCode.Single; + } + + // TODO: localize + throw new ArgumentException("Invalid constant type", nameof(value)); + } + + internal static void SerializeRowCounts(BlobBuilder writer, ImmutableArray rowCounts) + { + for (int i = 0; i < rowCounts.Length; i++) + { + int rowCount = rowCounts[i]; + if (rowCount > 0) + { + writer.WriteInt32(rowCount); + } + } + } + } +} diff --git a/src/Compilers/Core/Portable/PEWriter/ContentId.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ContentId.cs similarity index 81% rename from src/Compilers/Core/Portable/PEWriter/ContentId.cs rename to src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ContentId.cs index 0844725718402..224626489fdff 100644 --- a/src/Compilers/Core/Portable/PEWriter/ContentId.cs +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ContentId.cs @@ -1,17 +1,31 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Immutable; using System.Diagnostics; -namespace Microsoft.Cci +#if SRM +namespace System.Reflection.PortableExecutable +#else +namespace Roslyn.Reflection.PortableExecutable +#endif { - internal struct ContentId +#if SRM + public +#endif + struct ContentId { public const int Size = 20; + // TODO: public surface public readonly byte[] Guid; public readonly byte[] Stamp; + public ContentId(Guid guid, int stamp) + : this(guid.ToByteArray(), BitConverter.GetBytes(stamp)) + { + } + public ContentId(byte[] guid, byte[] stamp) { Debug.Assert(guid.Length == 16 && stamp.Length == 4); diff --git a/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/DirectoryEntry.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/DirectoryEntry.cs new file mode 100644 index 0000000000000..570db4ab8bdf7 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/DirectoryEntry.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if SRM +namespace System.Reflection.PortableExecutable +{ + public struct DirectoryEntry + { + public readonly int RelativeVirtualAddress; + public readonly int Size; + + public DirectoryEntry(int relativeVirtualAddress, int size) + { + RelativeVirtualAddress = relativeVirtualAddress; + Size = size; + } + + internal DirectoryEntry(ref PEBinaryReader reader) + { + RelativeVirtualAddress = reader.ReadInt32(); + Size = reader.ReadInt32(); + } + } +} +#else +namespace Microsoft.Cci +{ + // TODO: merge with System.Reflection.PortableExecutable.DirectoryEntry + internal struct DirectoryEntry + { + public readonly int RelativeVirtualAddress; + public readonly int Size; + + public DirectoryEntry( + int relativeVirtualAddress, + int size) + { + RelativeVirtualAddress = relativeVirtualAddress; + Size = size; + } + } +} +#endif diff --git a/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ManagedPEBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ManagedPEBuilder.cs new file mode 100644 index 0000000000000..816c17634387b --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ManagedPEBuilder.cs @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; + +#if SRM +namespace System.Reflection.PortableExecutable +#else +namespace Roslyn.Reflection.PortableExecutable +#endif +{ +#if !SRM + using Roslyn.Reflection.Metadata.Ecma335; +#endif + +#if SRM + public +#endif + static class ManagedPEBuilder + { + public static void AddManagedSections( + this PEBuilder peBuilder, + PEDirectoriesBuilder peDirectoriesBuilder, + TypeSystemMetadataSerializer metadataSerializer, + BlobBuilder ilStream, + BlobBuilder mappedFieldData, + BlobBuilder managedResourceData, + Action nativeResourceSectionSerializer, // opt + int strongNameSignatureSize, // TODO + MethodDefinitionHandle entryPoint, + string pdbPathOpt, // TODO + ContentId nativePdbContentId, // TODO + ContentId portablePdbContentId, // TODO + CorFlags corFlags) + { + int entryPointAddress = 0; + + // .text + peBuilder.AddSection(".text", SectionCharacteristics.MemRead | SectionCharacteristics.MemExecute | SectionCharacteristics.ContainsCode, location => + { + var sectionBuilder = new BlobBuilder(); + var metadataBuilder = new BlobBuilder(); + + var metadataSizes = metadataSerializer.MetadataSizes; + + var textSection = new ManagedTextSection( + metadataSizes.MetadataSize, + ilStreamSize: ilStream.Count, + mappedFieldDataSize: mappedFieldData.Count, + resourceDataSize: managedResourceData.Count, + strongNameSignatureSize: strongNameSignatureSize, + imageCharacteristics: peBuilder.ImageCharacteristics, + machine: peBuilder.Machine, + pdbPathOpt: pdbPathOpt, + isDeterministic: peBuilder.IsDeterministic); + + int methodBodyStreamRva = location.RelativeVirtualAddress + textSection.OffsetToILStream; + int mappedFieldDataStreamRva = location.RelativeVirtualAddress + textSection.CalculateOffsetToMappedFieldDataStream(); + metadataSerializer.SerializeMetadata(metadataBuilder, methodBodyStreamRva, mappedFieldDataStreamRva); + + BlobBuilder debugTableBuilderOpt; + if (pdbPathOpt != null || peBuilder.IsDeterministic) + { + debugTableBuilderOpt = new BlobBuilder(); + textSection.WriteDebugTable(debugTableBuilderOpt, location, nativePdbContentId, portablePdbContentId); + } + else + { + debugTableBuilderOpt = null; + } + + entryPointAddress = textSection.GetEntryPointAddress(location.RelativeVirtualAddress); + + textSection.Serialize( + sectionBuilder, + location.RelativeVirtualAddress, + entryPoint.IsNil ? 0 : MetadataTokens.GetToken(entryPoint), + corFlags, + peBuilder.ImageBase, + metadataBuilder, + ilStream, + mappedFieldData, + managedResourceData, + debugTableBuilderOpt); + + peDirectoriesBuilder.AddressOfEntryPoint = entryPointAddress; + peDirectoriesBuilder.DebugTable = textSection.GetDebugDirectoryEntry(location.RelativeVirtualAddress); + peDirectoriesBuilder.ImportAddressTable = textSection.GetImportAddressTableDirectoryEntry(location.RelativeVirtualAddress); + peDirectoriesBuilder.ImportTable = textSection.GetImportTableDirectoryEntry(location.RelativeVirtualAddress); + peDirectoriesBuilder.CorHeaderTable = textSection.GetCorHeaderDirectoryEntry(location.RelativeVirtualAddress); + + return sectionBuilder; + }); + + // .rsrc + if (nativeResourceSectionSerializer != null) + { + peBuilder.AddSection(".rsrc", SectionCharacteristics.MemRead | SectionCharacteristics.ContainsInitializedData, location => + { + var sectionBuilder = new BlobBuilder(); + nativeResourceSectionSerializer(sectionBuilder, location); + peDirectoriesBuilder.ResourceTable = new DirectoryEntry(location.RelativeVirtualAddress, sectionBuilder.Count); + return sectionBuilder; + }); + } + + // .reloc + if (peBuilder.Machine == Machine.I386 || peBuilder.Machine == 0) + { + peBuilder.AddSection(".reloc", SectionCharacteristics.MemRead | SectionCharacteristics.MemDiscardable | SectionCharacteristics.ContainsInitializedData, location => + { + var sectionBuilder = new BlobBuilder(); + WriteRelocSection(sectionBuilder, peBuilder.Machine, entryPointAddress); + + peDirectoriesBuilder.BaseRelocationTable = new DirectoryEntry(location.RelativeVirtualAddress, sectionBuilder.Count); + return sectionBuilder; + }); + } + } + + private static void WriteRelocSection(BlobBuilder builder, Machine machine, int entryPointAddress) + { + Debug.Assert(builder.Count == 0); + + builder.WriteUInt32((((uint)entryPointAddress + 2) / 0x1000) * 0x1000); + builder.WriteUInt32((machine == Machine.IA64) ? 14u : 12u); + uint offsetWithinPage = ((uint)entryPointAddress + 2) % 0x1000; + uint relocType = (machine == Machine.Amd64 || machine == Machine.IA64) ? 10u : 3u; + ushort s = (ushort)((relocType << 12) | offsetWithinPage); + builder.WriteUInt16(s); + if (machine == Machine.IA64) + { + builder.WriteUInt32(relocType << 12); + } + + builder.WriteUInt16(0); // next chunk's RVA + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ManagedTextSection.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ManagedTextSection.cs new file mode 100644 index 0000000000000..d91371c696f63 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/ManagedTextSection.cs @@ -0,0 +1,613 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Diagnostics; + +#if SRM +using System.Reflection.Internal; +using BitArithmeticUtilities = System.Reflection.Internal.BitArithmetic; +#else +using System.Reflection.PortableExecutable; +using Roslyn.Utilities; +#endif + +#if SRM +namespace System.Reflection.PortableExecutable +#else +namespace Roslyn.Reflection.PortableExecutable +#endif +{ + /// + /// Managed .text PE section. + /// + /// + /// Contains in the following order: + /// - Import Address Table + /// - COR Header + /// - IL + /// - Metadata + /// - Managed Resource Data + /// - Strong Name Signature + /// - Debug Table + /// - Import Table + /// - Name Table + /// - Runtime Startup Stub + /// - Mapped Field Data + /// +#if SRM + public +#endif + sealed class ManagedTextSection + { + public Characteristics ImageCharacteristics { get; } + public Machine Machine { get; } + public bool IsDeterministic { get; } + public string PdbPathOpt { get; } + + /// + /// Total size of metadata (header and all streams). + /// + public int MetadataSize { get; } + + /// + /// The size of IL stream (unaligned). + /// + public int ILStreamSize { get; } + + /// + /// The size of mapped field data stream. + /// Aligned to . + /// + public int MappedFieldDataSize { get; } + + /// + /// The size of managed resource data stream. + /// Aligned to . + /// + public int ResourceDataSize { get; } + + /// + /// Size of strong name hash. + /// + public int StrongNameSignatureSize { get; } + + public ManagedTextSection( + int metadataSize, + int ilStreamSize, + int mappedFieldDataSize, + int resourceDataSize, + int strongNameSignatureSize, + Characteristics imageCharacteristics, + Machine machine, + string pdbPathOpt, + bool isDeterministic) + { + MetadataSize = metadataSize; + ResourceDataSize = resourceDataSize; + ILStreamSize = ilStreamSize; + MappedFieldDataSize = mappedFieldDataSize; + StrongNameSignatureSize = strongNameSignatureSize; + ImageCharacteristics = imageCharacteristics; + Machine = machine; + PdbPathOpt = pdbPathOpt; + IsDeterministic = isDeterministic; + } + + /// + /// If set, the module must include a machine code stub that transfers control to the virtual execution system. + /// + internal bool RequiresStartupStub => Machine == Machine.I386 || Machine == 0; + + /// + /// If set, the module contains instructions that assume a 64 bit instruction set. For example it may depend on an address being 64 bits. + /// This may be true even if the module contains only IL instructions because of PlatformInvoke and COM interop. + /// + internal bool Requires64bits => Machine == Machine.Amd64 || Machine == Machine.IA64; + + public bool Is32Bit => !Requires64bits; + + public const int ManagedResourcesDataAlignment = 8; + + private const string CorEntryPointDll = "mscoree.dll"; + private string CorEntryPointName => (ImageCharacteristics & Characteristics.Dll) != 0 ? "_CorDllMain" : "_CorExeMain"; + + private int SizeOfImportAddressTable => RequiresStartupStub ? (Is32Bit ? 2 * sizeof(uint) : 2 * sizeof(ulong)) : 0; + + // (_is32bit ? 66 : 70); + private int SizeOfImportTable => + sizeof(uint) + // RVA + sizeof(uint) + // 0 + sizeof(uint) + // 0 + sizeof(uint) + // name RVA + sizeof(uint) + // import address table RVA + 20 + // ? + (Is32Bit ? 3 * sizeof(uint) : 2 * sizeof(ulong)) + // import lookup table + sizeof(ushort) + // hint + CorEntryPointName.Length + + 1; // NUL + + private static int SizeOfNameTable => + CorEntryPointDll.Length + 1 + sizeof(ushort); + + private int SizeOfRuntimeStartupStub => Is32Bit ? 8 : 16; + + public const int MappedFieldDataAlignment = 8; + + public int CalculateOffsetToMappedFieldDataStream() + { + int result = ComputeOffsetToImportTable(); + + if (RequiresStartupStub) + { + result += SizeOfImportTable + SizeOfNameTable; + result = BitArithmeticUtilities.Align(result, Is32Bit ? 4 : 8); //optional padding to make startup stub's target address align on word or double word boundary + result += SizeOfRuntimeStartupStub; + } + + return result; + } + + private int ComputeOffsetToDebugTable() + { + Debug.Assert(MetadataSize % 4 == 0); + Debug.Assert(ResourceDataSize % 4 == 0); + + return + ComputeOffsetToMetadata() + + MetadataSize + + ResourceDataSize + + StrongNameSignatureSize; + } + + private int ComputeOffsetToImportTable() + { + return + ComputeOffsetToDebugTable() + + ComputeSizeOfDebugDirectory(); + } + + private const int CorHeaderSize = + sizeof(int) + // header size + sizeof(short) + // major runtime version + sizeof(short) + // minor runtime version + sizeof(long) + // metadata directory + sizeof(int) + // COR flags + sizeof(int) + // entry point + sizeof(long) + // resources directory + sizeof(long) + // strong name signature directory + sizeof(long) + // code manager table directory + sizeof(long) + // vtable fixups directory + sizeof(long) + // export address table jumps directory + sizeof(long); // managed-native header directory + + public int OffsetToILStream => SizeOfImportAddressTable + CorHeaderSize; + + private int ComputeOffsetToMetadata() + { + return OffsetToILStream + BitArithmeticUtilities.Align(ILStreamSize, 4); + } + + /// + /// The size of a single entry in the "Debug Directory (Image Only)" + /// + private const int ImageDebugDirectoryEntrySize = + sizeof(uint) + // Characteristics + sizeof(uint) + // TimeDataStamp + sizeof(uint) + // Version + sizeof(uint) + // Type + sizeof(uint) + // SizeOfData + sizeof(uint) + // AddressOfRawData + sizeof(uint); // PointerToRawData + + private bool EmitPdb => PdbPathOpt != null; + + /// + /// Minimal size of PDB path in Debug Directory. We pad the path to this minimal size to + /// allow some tools to patch the path without the need to rewrite the entire image. + /// This is a workaround put in place until these tools are retired. + /// + private int MinPdbPath => IsDeterministic ? 0 : 260; + + /// + /// The size of our debug directory: one entry for debug information, and an optional second one indicating + /// that the timestamp is deterministic (i.e. not really a timestamp) + /// + private int ImageDebugDirectoryBaseSize => + (IsDeterministic ? ImageDebugDirectoryEntrySize : 0) + + (EmitPdb ? ImageDebugDirectoryEntrySize : 0); + + private int ComputeSizeOfDebugDirectoryData() + { + // The debug directory data is only needed if this.EmitPdb. + return (!EmitPdb) ? 0 : + 4 + // 4B signature "RSDS" + 16 + // GUID + sizeof(uint) + // Age + Math.Max(BlobUtilities.GetUTF8ByteCount(PdbPathOpt) + 1, MinPdbPath); + } + + private int ComputeSizeOfDebugDirectory() + { + return ImageDebugDirectoryBaseSize + ComputeSizeOfDebugDirectoryData(); + } + + public DirectoryEntry GetDebugDirectoryEntry(int rva) + { + // Only the size of the fixed part of the debug table goes here. + return (EmitPdb || IsDeterministic) ? + new DirectoryEntry(rva + ComputeOffsetToDebugTable(), ImageDebugDirectoryBaseSize) : + default(DirectoryEntry); + } + + public int ComputeSizeOfTextSection() + { + Debug.Assert(MappedFieldDataSize % MappedFieldDataAlignment == 0); + return CalculateOffsetToMappedFieldDataStream() + MappedFieldDataSize; + } + + public int GetEntryPointAddress(int rva) + { + // TODO: constants + return RequiresStartupStub ? + rva + CalculateOffsetToMappedFieldDataStream() - (Is32Bit ? 6 : 10) : + 0; + } + + public DirectoryEntry GetImportAddressTableDirectoryEntry(int rva) + { + return RequiresStartupStub ? + new DirectoryEntry(rva, SizeOfImportAddressTable) : + default(DirectoryEntry); + } + + public DirectoryEntry GetImportTableDirectoryEntry(int rva) + { + // TODO: constants + return RequiresStartupStub ? + new DirectoryEntry(rva + ComputeOffsetToImportTable(), (Is32Bit ? 66 : 70) + 13) : + default(DirectoryEntry); + } + + public DirectoryEntry GetCorHeaderDirectoryEntry(int rva) + { + return new DirectoryEntry(rva + SizeOfImportAddressTable, CorHeaderSize); + } + + #region Serialization + + /// + /// Serializes .text section data into a specified . + /// + /// An empty builder to serialize section data to. + /// Relative virtual address of the section within the containing PE file. + /// Entry point token or RVA () + /// COR Flags (). + /// Base address of the PE image. + /// containing metadata. Must be populated with data. Linked into the and can't be expanded afterwards. + /// containing IL stream. Must be populated with data. Linked into the and can't be expanded afterwards. + /// containing mapped field data. Must be populated with data. Linked into the and can't be expanded afterwards. + /// containing managed resource data. Must be populated with data. Linked into the and can't be expanded afterwards. + /// containing debug table data. Must be populated with data. Linked into the and can't be expanded afterwards. + public void Serialize( + BlobBuilder builder, + int relativeVirtualAddess, + int entryPointTokenOrRelativeVirtualAddress, + CorFlags corFlags, + ulong baseAddress, + BlobBuilder metadataBuilder, + BlobBuilder ilBuilder, + BlobBuilder mappedFieldDataBuilder, + BlobBuilder resourceBuilder, + BlobBuilder debugTableBuilderOpt) + { + Debug.Assert(builder.Count == 0); + Debug.Assert(metadataBuilder.Count == MetadataSize); + Debug.Assert(metadataBuilder.Count % 4 == 0); + Debug.Assert(ilBuilder.Count == ILStreamSize); + Debug.Assert(mappedFieldDataBuilder.Count == MappedFieldDataSize); + Debug.Assert(resourceBuilder.Count == ResourceDataSize); + Debug.Assert(resourceBuilder.Count % 4 == 0); + + // TODO: avoid recalculation + int importTableRva = GetImportTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; + int importAddressTableRva = GetImportAddressTableDirectoryEntry(relativeVirtualAddess).RelativeVirtualAddress; + + if (RequiresStartupStub) + { + WriteImportAddressTable(builder, importTableRva); + } + + WriteCorHeader(builder, relativeVirtualAddess, entryPointTokenOrRelativeVirtualAddress, corFlags); + + // IL: + ilBuilder.Align(4); + builder.LinkSuffix(ilBuilder); + + // metadata: + builder.LinkSuffix(metadataBuilder); + + // managed resources: + builder.LinkSuffix(resourceBuilder); + + // strong name signature: + builder.WriteBytes(0, StrongNameSignatureSize); + + if (debugTableBuilderOpt != null) + { + builder.LinkSuffix(debugTableBuilderOpt); + } + + if (RequiresStartupStub) + { + WriteImportTable(builder, importTableRva, importAddressTableRva); + WriteNameTable(builder); + WriteRuntimeStartupStub(builder, importAddressTableRva, baseAddress); + } + + // mapped field data: + builder.LinkSuffix(mappedFieldDataBuilder); + + Debug.Assert(builder.Count == ComputeSizeOfTextSection()); + } + + private void WriteImportAddressTable(BlobBuilder builder, int importTableRva) + { + int start = builder.Count; + + int ilRva = importTableRva + 40; + int hintRva = ilRva + (Is32Bit ? 12 : 16); + + // Import Address Table + if (Is32Bit) + { + builder.WriteUInt32((uint)hintRva); // 4 + builder.WriteUInt32(0); // 8 + } + else + { + builder.WriteUInt64((uint)hintRva); // 8 + builder.WriteUInt64(0); // 16 + } + + Debug.Assert(builder.Count - start == SizeOfImportAddressTable); + } + + private void WriteImportTable(BlobBuilder builder, int importTableRva, int importAddressTableRva) + { + int start = builder.Count; + + int ilRVA = importTableRva + 40; + int hintRva = ilRVA + (Is32Bit ? 12 : 16); + int nameRva = hintRva + 12 + 2; + + // Import table + builder.WriteUInt32((uint)ilRVA); // 4 + builder.WriteUInt32(0); // 8 + builder.WriteUInt32(0); // 12 + builder.WriteUInt32((uint)nameRva); // 16 + builder.WriteUInt32((uint)importAddressTableRva); // 20 + builder.WriteBytes(0, 20); // 40 + + // Import Lookup table + if (Is32Bit) + { + builder.WriteUInt32((uint)hintRva); // 44 + builder.WriteUInt32(0); // 48 + builder.WriteUInt32(0); // 52 + } + else + { + builder.WriteUInt64((uint)hintRva); // 48 + builder.WriteUInt64(0); // 56 + } + + // Hint table + builder.WriteUInt16(0); // Hint 54|58 + + foreach (char ch in CorEntryPointName) + { + builder.WriteByte((byte)ch); // 65|69 + } + + builder.WriteByte(0); // 66|70 + Debug.Assert(builder.Count - start == SizeOfImportTable); + } + + private static void WriteNameTable(BlobBuilder builder) + { + int start = builder.Count; + + foreach (char ch in CorEntryPointDll) + { + builder.WriteByte((byte)ch); + } + + builder.WriteByte(0); + builder.WriteUInt16(0); + Debug.Assert(builder.Count - start == SizeOfNameTable); + } + + private void WriteCorHeader(BlobBuilder builder, int textSectionRva, int entryPointTokenOrRva, CorFlags corFlags) + { + const ushort majorRuntimeVersion = 2; + const ushort minorRuntimeVersion = 5; + + int metadataRva = textSectionRva + ComputeOffsetToMetadata(); + int resourcesRva = metadataRva + MetadataSize; + int signatureRva = resourcesRva + ResourceDataSize; + + int start = builder.Count; + + // Size: + builder.WriteUInt32(CorHeaderSize); + + // Version: + builder.WriteUInt16(majorRuntimeVersion); + builder.WriteUInt16(minorRuntimeVersion); + + // MetadataDirectory: + builder.WriteUInt32((uint)metadataRva); + builder.WriteUInt32((uint)MetadataSize); + + // COR Flags: + builder.WriteUInt32((uint)corFlags); + + // EntryPoint: + builder.WriteUInt32((uint)entryPointTokenOrRva); + + // ResourcesDirectory: + builder.WriteUInt32((uint)(ResourceDataSize == 0 ? 0 : resourcesRva)); // 28 + builder.WriteUInt32((uint)ResourceDataSize); + + // StrongNameSignatureDirectory: + builder.WriteUInt32((uint)(StrongNameSignatureSize == 0 ? 0 : signatureRva)); // 36 + builder.WriteUInt32((uint)StrongNameSignatureSize); + + // CodeManagerTableDirectory (not supported): + builder.WriteUInt32(0); + builder.WriteUInt32(0); + + // VtableFixupsDirectory (not supported): + builder.WriteUInt32(0); + builder.WriteUInt32(0); + + // ExportAddressTableJumpsDirectory (not supported): + builder.WriteUInt32(0); + builder.WriteUInt32(0); + + // ManagedNativeHeaderDirectory (not supported): + builder.WriteUInt32(0); + builder.WriteUInt32(0); + + Debug.Assert(builder.Count - start == CorHeaderSize); + Debug.Assert(builder.Count % 4 == 0); + } + + /// + /// Write one entry in the "Debug Directory (Image Only)" + /// See https://msdn.microsoft.com/en-us/windows/hardware/gg463119.aspx + /// section 5.1.1 (pages 71-72). + /// + private static void WriteDebugTableEntry( + BlobBuilder writer, + byte[] stamp, + uint version, // major and minor version, combined + uint debugType, + uint sizeOfData, + uint addressOfRawData, + uint pointerToRawData) + { + writer.WriteUInt32(0); // characteristics + Debug.Assert(stamp.Length == 4); + writer.WriteBytes(stamp); + writer.WriteUInt32(version); + writer.WriteUInt32(debugType); + writer.WriteUInt32(sizeOfData); + writer.WriteUInt32(addressOfRawData); + writer.WriteUInt32(pointerToRawData); + } + + private readonly static byte[] zeroStamp = new byte[4]; // four bytes of zero + + /// + /// Write the entire "Debug Directory (Image Only)" along with data that it points to. + /// + internal void WriteDebugTable(BlobBuilder builder, PESectionLocation textSectionLocation, ContentId nativePdbContentId, ContentId portablePdbContentId) + { + Debug.Assert(builder.Count == 0); + + int tableSize = ImageDebugDirectoryBaseSize; + Debug.Assert(tableSize != 0); + Debug.Assert(nativePdbContentId.IsDefault || portablePdbContentId.IsDefault); + Debug.Assert(!EmitPdb || (nativePdbContentId.IsDefault ^ portablePdbContentId.IsDefault)); + + int dataSize = ComputeSizeOfDebugDirectoryData(); + if (EmitPdb) + { + const int IMAGE_DEBUG_TYPE_CODEVIEW = 2; // from PE spec + uint dataOffset = (uint)(ComputeOffsetToDebugTable() + tableSize); + WriteDebugTableEntry(builder, + stamp: nativePdbContentId.Stamp ?? portablePdbContentId.Stamp, + version: portablePdbContentId.IsDefault ? (uint)0 : ('P' << 24 | 'M' << 16 | 0x01 << 8 | 0x00), + debugType: IMAGE_DEBUG_TYPE_CODEVIEW, + sizeOfData: (uint)dataSize, + addressOfRawData: (uint)textSectionLocation.RelativeVirtualAddress + dataOffset, // RVA of the data + pointerToRawData: (uint)textSectionLocation.PointerToRawData + dataOffset); // position of the data in the PE stream + } + + if (IsDeterministic) + { + const int IMAGE_DEBUG_TYPE_NO_TIMESTAMP = 16; // from PE spec + WriteDebugTableEntry(builder, + stamp: zeroStamp, + version: 0, + debugType: IMAGE_DEBUG_TYPE_NO_TIMESTAMP, + sizeOfData: 0, + addressOfRawData: 0, + pointerToRawData: 0); + } + + // We should now have written all and precisely the data we said we'd write for the table entries. + Debug.Assert(builder.Count == tableSize); + + // ==================== + // The following is additional data beyond the debug directory at the offset `dataOffset` + // pointed to by the ImageDebugTypeCodeView entry. + + if (EmitPdb) + { + builder.WriteByte((byte)'R'); + builder.WriteByte((byte)'S'); + builder.WriteByte((byte)'D'); + builder.WriteByte((byte)'S'); + + // PDB id: + builder.WriteBytes(nativePdbContentId.Guid ?? portablePdbContentId.Guid); + + // age + builder.WriteUInt32(1); // TODO: allow specify for native PDBs + + // UTF-8 encoded zero-terminated path to PDB + int pathStart = builder.Count; + builder.WriteUTF8(PdbPathOpt, allowUnpairedSurrogates: true); + builder.WriteByte(0); + + // padding: + builder.WriteBytes(0, Math.Max(0, MinPdbPath - (builder.Count - pathStart))); + } + + // We should now have written all and precisely the data we said we'd write for the table and its data. + Debug.Assert(builder.Count == tableSize + dataSize); + } + + private void WriteRuntimeStartupStub(BlobBuilder sectionBuilder, int importAddressTableRva, ulong baseAddress) + { + // entry point code, consisting of a jump indirect to _CorXXXMain + if (Is32Bit) + { + // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 4 byte boundary. + // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively to the start of the section. + sectionBuilder.Align(4); + + sectionBuilder.WriteUInt16(0); + sectionBuilder.WriteByte(0xff); + sectionBuilder.WriteByte(0x25); //4 + sectionBuilder.WriteUInt32((uint)importAddressTableRva + (uint)baseAddress); //8 + } + else + { + // Write zeros (nops) to pad the entry point code so that the target address is aligned on a 8 byte boundary. + // Note that the section is aligned to FileAlignment, which is at least 512, so we can align relatively to the start of the section. + sectionBuilder.Align(8); + + sectionBuilder.WriteUInt32(0); + sectionBuilder.WriteUInt16(0); + sectionBuilder.WriteByte(0xff); + sectionBuilder.WriteByte(0x25); //8 + sectionBuilder.WriteUInt64((ulong)importAddressTableRva + baseAddress); //16 + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PEBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PEBuilder.cs new file mode 100644 index 0000000000000..204ff53dc4ad7 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PEBuilder.cs @@ -0,0 +1,478 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Reflection.PortableExecutable; + +#if SRM +using System.Reflection.Internal; +using BitArithmeticUtilities = System.Reflection.Internal.BitArithmetic; +#else +using Roslyn.Utilities; +#endif + +#if SRM +namespace System.Reflection.PortableExecutable +#else +namespace Roslyn.Reflection.PortableExecutable +#endif +{ +#if SRM + public +#endif + sealed class PEBuilder + { + // COFF: + public Machine Machine { get; } + public Characteristics ImageCharacteristics { get; set; } + public bool IsDeterministic { get; } + + // PE: + public byte MajorLinkerVersion { get; } + public byte MinorLinkerVersion { get; } + + public ulong ImageBase { get; } + public int SectionAlignment { get; } + public int FileAlignment { get; } + + public ushort MajorOperatingSystemVersion { get; } + public ushort MinorOperatingSystemVersion { get; } + + public ushort MajorImageVersion { get; } + public ushort MinorImageVersion { get; } + + public ushort MajorSubsystemVersion { get; } + public ushort MinorSubsystemVersion { get; } + + public Subsystem Subsystem { get; } + public DllCharacteristics DllCharacteristics { get; } + + public ulong SizeOfStackReserve { get; } + public ulong SizeOfStackCommit { get; } + public ulong SizeOfHeapReserve { get; } + public ulong SizeOfHeapCommit { get; } + + public Func IdProvider { get; } + + private readonly List
_sections; + + private struct Section + { + public readonly string Name; + public readonly SectionCharacteristics Characteristics; + public readonly Func Builder; + + public Section(string name, SectionCharacteristics characteristics, Func builder) + { + Name = name; + Characteristics = characteristics; + Builder = builder; + } + } + + private struct SerializedSection + { + public readonly BlobBuilder Builder; + + public readonly string Name; + public readonly SectionCharacteristics Characteristics; + public readonly int RelativeVirtualAddress; + public readonly int SizeOfRawData; + public readonly int PointerToRawData; + + public SerializedSection(BlobBuilder builder, string name, SectionCharacteristics characteristics, int relativeVirtualAddress, int sizeOfRawData, int pointerToRawData) + { + Name = name; + Characteristics = characteristics; + Builder = builder; + RelativeVirtualAddress = relativeVirtualAddress; + SizeOfRawData = sizeOfRawData; + PointerToRawData = pointerToRawData; + } + + public int VirtualSize => Builder.Count; + } + + public PEBuilder( + Machine machine, + int sectionAlignment, + int fileAlignment, + ulong imageBase, + byte majorLinkerVersion, + byte minorLinkerVersion, + ushort majorOperatingSystemVersion, + ushort minorOperatingSystemVersion, + ushort majorImageVersion, + ushort minorImageVersion, + ushort majorSubsystemVersion, + ushort minorSubsystemVersion, + Subsystem subsystem, + DllCharacteristics dllCharacteristics, + Characteristics imageCharacteristics, + ulong sizeOfStackReserve, + ulong sizeOfStackCommit, + ulong sizeOfHeapReserve, + ulong sizeOfHeapCommit, + Func deterministicIdProvider = null) + { + Machine = machine; + SectionAlignment = sectionAlignment; + FileAlignment = fileAlignment; + ImageBase = imageBase; + MajorLinkerVersion = majorLinkerVersion; + MinorLinkerVersion = minorLinkerVersion; + MajorOperatingSystemVersion = majorOperatingSystemVersion; + MinorOperatingSystemVersion = minorOperatingSystemVersion; + MajorImageVersion = majorImageVersion; + MinorImageVersion = minorImageVersion; + MajorSubsystemVersion = majorSubsystemVersion; + MinorSubsystemVersion = minorSubsystemVersion; + Subsystem = subsystem; + DllCharacteristics = dllCharacteristics; + ImageCharacteristics = imageCharacteristics; + SizeOfStackReserve = sizeOfStackReserve; + SizeOfStackCommit = sizeOfStackCommit; + SizeOfHeapReserve = sizeOfHeapReserve; + SizeOfHeapCommit = sizeOfHeapCommit; + IsDeterministic = deterministicIdProvider != null; + IdProvider = deterministicIdProvider ?? GetCurrentTimeBasedIdProvider(); + + _sections = new List
(); + } + + private static Func GetCurrentTimeBasedIdProvider() + { + // In the PE File Header this is a "Time/Date Stamp" whose description is "Time and date + // the file was created in seconds since January 1st 1970 00:00:00 or 0" + // However, when we want to make it deterministic we fill it in (later) with bits from the hash of the full PE file. + int timestamp = (int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; + return content => new ContentId(Guid.NewGuid(), timestamp); + } + + private bool Is32Bit => Machine != Machine.Amd64 && Machine != Machine.IA64; + + public void AddSection(string name, SectionCharacteristics characteristics, Func builder) + { + _sections.Add(new Section(name, characteristics, builder)); + } + + public void Serialize(BlobBuilder builder, PEDirectoriesBuilder headers, out ContentId contentId) + { + var serializedSections = SerializeSections(); + Blob stampFixup; + + WritePESignature(builder); + WriteCoffHeader(builder, serializedSections, out stampFixup); + WritePEHeader(builder, headers, serializedSections); + WriteSectionHeaders(builder, serializedSections); + builder.Align(FileAlignment); + + foreach (var section in serializedSections) + { + builder.LinkSuffix(section.Builder); + builder.Align(FileAlignment); + } + + contentId = IdProvider(builder); + + // patch timestamp in COFF header: + var stampWriter = new BlobWriter(stampFixup); + stampWriter.WriteBytes(contentId.Stamp); + Debug.Assert(stampWriter.RemainingBytes == 0); + } + + private ImmutableArray SerializeSections() + { + var result = ImmutableArray.CreateBuilder(_sections.Count); + int sizeOfPeHeaders = ComputeSizeOfPeHeaders(_sections.Count, Is32Bit); + + var nextRva = BitArithmeticUtilities.Align(sizeOfPeHeaders, SectionAlignment); + var nextPointer = BitArithmeticUtilities.Align(sizeOfPeHeaders, FileAlignment); + + foreach (var section in _sections) + { + var builder = section.Builder(new PESectionLocation(nextRva, nextPointer)); + + var serialized = new SerializedSection( + builder, + section.Name, + section.Characteristics, + relativeVirtualAddress: nextRva, + sizeOfRawData: BitArithmeticUtilities.Align(builder.Count, FileAlignment), + pointerToRawData: nextPointer); + + result.Add(serialized); + + nextRva = BitArithmeticUtilities.Align(serialized.RelativeVirtualAddress + serialized.VirtualSize, SectionAlignment); + nextPointer = serialized.PointerToRawData + serialized.SizeOfRawData; + } + + return result.MoveToImmutable(); + } + + private static int ComputeSizeOfPeHeaders(int sectionCount, bool is32Bit) + { + // TODO: constants + int sizeOfPeHeaders = 128 + 4 + 20 + 224 + 40 * sectionCount; + if (!is32Bit) + { + sizeOfPeHeaders += 16; + } + + return sizeOfPeHeaders; + } + + private void WritePESignature(BlobBuilder builder) + { + // MS-DOS stub (128 bytes) + builder.WriteBytes(s_dosHeader); + + // PE Signature "PE\0\0" + builder.WriteUInt32(0x00004550); + } + + private static readonly byte[] s_dosHeader = new byte[] + { + 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, + 0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, + 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + private void WriteCoffHeader(BlobBuilder builder, ImmutableArray sections, out Blob stampFixup) + { + // Machine + builder.WriteUInt16((ushort)(Machine == 0 ? Machine.I386 : Machine)); + + // NumberOfSections + builder.WriteUInt16((ushort)sections.Length); + + // TimeDateStamp: + stampFixup = builder.ReserveBytes(sizeof(uint)); + + // PointerToSymbolTable (TODO: not supported): + // The file pointer to the COFF symbol table, or zero if no COFF symbol table is present. + // This value should be zero for a PE image. + builder.WriteUInt32(0); + + // NumberOfSymbols (TODO: not supported): + // The number of entries in the symbol table. This data can be used to locate the string table, + // which immediately follows the symbol table. This value should be zero for a PE image. + builder.WriteUInt32(0); + + // SizeOfOptionalHeader: + // The size of the optional header, which is required for executable files but not for object files. + // This value should be zero for an object file (TODO). + builder.WriteUInt16((ushort)(Is32Bit ? 224 : 240)); + + // Characteristics + builder.WriteUInt16((ushort)ImageCharacteristics); + } + + private void WritePEHeader(BlobBuilder builder, PEDirectoriesBuilder headers, ImmutableArray sections) + { + builder.WriteUInt16((ushort)(Is32Bit ? PEMagic.PE32 : PEMagic.PE32Plus)); + builder.WriteByte(MajorLinkerVersion); + builder.WriteByte(MinorLinkerVersion); + + // SizeOfCode: + builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsCode)); + + // SizeOfInitializedData: + builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsInitializedData)); + + // SizeOfUninitializedData: + builder.WriteUInt32((uint)SumRawDataSizes(sections, SectionCharacteristics.ContainsUninitializedData)); + + // AddressOfEntryPoint: + builder.WriteUInt32((uint)headers.AddressOfEntryPoint); + + // BaseOfCode: + int codeSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsCode); + builder.WriteUInt32((uint)(codeSectionIndex != -1 ? sections[codeSectionIndex].RelativeVirtualAddress : 0)); + + if (Is32Bit) + { + // BaseOfData: + int dataSectionIndex = IndexOfSection(sections, SectionCharacteristics.ContainsInitializedData); + builder.WriteUInt32((uint)(dataSectionIndex != -1 ? sections[dataSectionIndex].RelativeVirtualAddress : 0)); + + builder.WriteUInt32((uint)ImageBase); + } + else + { + builder.WriteUInt64(ImageBase); + } + + // NT additional fields: + builder.WriteUInt32((uint)SectionAlignment); + builder.WriteUInt32((uint)FileAlignment); + builder.WriteUInt16(MajorOperatingSystemVersion); + builder.WriteUInt16(MinorOperatingSystemVersion); + builder.WriteUInt16(MajorImageVersion); + builder.WriteUInt16(MinorImageVersion); + builder.WriteUInt16(MajorSubsystemVersion); + builder.WriteUInt16(MinorSubsystemVersion); + + // Win32VersionValue (reserved, should be 0) + builder.WriteUInt32(0); + + // SizeOfImage: + var lastSection = sections[sections.Length - 1]; + builder.WriteUInt32((uint)BitArithmeticUtilities.Align(lastSection.RelativeVirtualAddress + lastSection.VirtualSize, SectionAlignment)); + + // SizeOfHeaders: + builder.WriteUInt32((uint)BitArithmeticUtilities.Align(ComputeSizeOfPeHeaders(sections.Length, Is32Bit), FileAlignment)); + + // Checksum (TODO: not supported): + builder.WriteUInt32(0); + + builder.WriteUInt16((ushort)Subsystem); + builder.WriteUInt16((ushort)DllCharacteristics); + + if (Is32Bit) + { + builder.WriteUInt32((uint)SizeOfStackReserve); + builder.WriteUInt32((uint)SizeOfStackCommit); + builder.WriteUInt32((uint)SizeOfHeapReserve); + builder.WriteUInt32((uint)SizeOfHeapCommit); + } + else + { + builder.WriteUInt64(SizeOfStackReserve); + builder.WriteUInt64(SizeOfStackCommit); + builder.WriteUInt64(SizeOfHeapReserve); + builder.WriteUInt64(SizeOfHeapCommit); + } + + // LoaderFlags + builder.WriteUInt32(0); + + // The number of data-directory entries in the remainder of the header. + builder.WriteUInt32(16); + + // directory entries: + builder.WriteUInt32((uint)headers.ExportTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.ExportTable.Size); + builder.WriteUInt32((uint)headers.ImportTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.ImportTable.Size); + builder.WriteUInt32((uint)headers.ResourceTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.ResourceTable.Size); + builder.WriteUInt32((uint)headers.ExceptionTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.ExceptionTable.Size); + builder.WriteUInt32((uint)headers.CertificateTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.CertificateTable.Size); + builder.WriteUInt32((uint)headers.BaseRelocationTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.BaseRelocationTable.Size); + builder.WriteUInt32((uint)headers.DebugTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.DebugTable.Size); + builder.WriteUInt32((uint)headers.CopyrightTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.CopyrightTable.Size); + builder.WriteUInt32((uint)headers.GlobalPointerTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.GlobalPointerTable.Size); + builder.WriteUInt32((uint)headers.ThreadLocalStorageTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.ThreadLocalStorageTable.Size); + builder.WriteUInt32((uint)headers.LoadConfigTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.LoadConfigTable.Size); + builder.WriteUInt32((uint)headers.BoundImportTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.BoundImportTable.Size); + builder.WriteUInt32((uint)headers.ImportAddressTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.ImportAddressTable.Size); + builder.WriteUInt32((uint)headers.DelayImportTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.DelayImportTable.Size); + builder.WriteUInt32((uint)headers.CorHeaderTable.RelativeVirtualAddress); + builder.WriteUInt32((uint)headers.CorHeaderTable.Size); + + // Reserved, should be 0 + builder.WriteUInt64(0); + } + + private void WriteSectionHeaders(BlobBuilder builder, ImmutableArray serializedSections) + { + for (int i = 0; i < serializedSections.Length; i++) + { + WriteSectionHeader(builder, _sections[i], serializedSections[i]); + } + } + + private static void WriteSectionHeader(BlobBuilder builder, Section section, SerializedSection serializedSection) + { + if (serializedSection.VirtualSize == 0) + { + return; + } + + for (int j = 0, m = section.Name.Length; j < 8; j++) + { + if (j < m) + { + builder.WriteByte((byte)section.Name[j]); + } + else + { + builder.WriteByte(0); + } + } + + builder.WriteUInt32((uint)serializedSection.VirtualSize); + builder.WriteUInt32((uint)serializedSection.RelativeVirtualAddress); + builder.WriteUInt32((uint)serializedSection.SizeOfRawData); + builder.WriteUInt32((uint)serializedSection.PointerToRawData); + + // PointerToRelocations (TODO: not supported): + builder.WriteUInt32(0); + + // PointerToLinenumbers (TODO: not supported): + builder.WriteUInt32(0); + + // NumberOfRelocations (TODO: not supported): + builder.WriteUInt16(0); + + // NumberOfLinenumbers (TODO: not supported): + builder.WriteUInt16(0); + + builder.WriteUInt32((uint)section.Characteristics); + } + + private static int IndexOfSection(ImmutableArray sections, SectionCharacteristics characteristics) + { + for (int i = 0; i < sections.Length; i++) + { + if ((sections[i].Characteristics & characteristics) == characteristics) + { + return i; + } + } + + return -1; + } + + private static int SumRawDataSizes(ImmutableArray sections,SectionCharacteristics characteristics) + { + int result = 0; + for (int i = 0; i < sections.Length; i++) + { + if ((sections[i].Characteristics & characteristics) == characteristics) + { + result += sections[i].SizeOfRawData; + } + } + + return result; + } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PEDirectoriesBuilder.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PEDirectoriesBuilder.cs new file mode 100644 index 0000000000000..a54ce74a8cb91 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PEDirectoriesBuilder.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection.PortableExecutable; + +#if SRM +namespace System.Reflection.PortableExecutable +#else +namespace Roslyn.Reflection.PortableExecutable +#endif +{ +#if SRM + public +#endif + sealed class PEDirectoriesBuilder + { + public int AddressOfEntryPoint { get; set; } + + public DirectoryEntry ExportTable { get; set; } + public DirectoryEntry ImportTable { get; set; } + public DirectoryEntry ResourceTable { get; set; } + public DirectoryEntry ExceptionTable { get; set; } + public DirectoryEntry CertificateTable { get; set; } + public DirectoryEntry BaseRelocationTable { get; set; } + public DirectoryEntry DebugTable { get; set; } + public DirectoryEntry CopyrightTable { get; set; } + public DirectoryEntry GlobalPointerTable { get; set; } + public DirectoryEntry ThreadLocalStorageTable { get; set; } + public DirectoryEntry LoadConfigTable { get; set; } + public DirectoryEntry BoundImportTable { get; set; } + public DirectoryEntry ImportAddressTable { get; set; } + public DirectoryEntry DelayImportTable { get; set; } + public DirectoryEntry CorHeaderTable { get; set; } + } +} diff --git a/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PESectionLocation.cs b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PESectionLocation.cs new file mode 100644 index 0000000000000..ccf322de77139 --- /dev/null +++ b/src/Compilers/Core/Portable/System/Reflection/PortableExecutable/PESectionLocation.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if SRM +namespace System.Reflection.PortableExecutable +#else +namespace Roslyn.Reflection.PortableExecutable +#endif +{ +#if SRM + public +#endif + struct PESectionLocation + { + public int RelativeVirtualAddress { get; } + public int PointerToRawData { get; } + + public PESectionLocation(int relativeVirtualAddress, int pointerToRawData) + { + RelativeVirtualAddress = relativeVirtualAddress; + PointerToRawData = pointerToRawData; + } + } +} diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb index 432d9b97de0c2..92c46c8ed5a2f 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitArrayInitializer.vb @@ -5,12 +5,15 @@ Imports System.Collections.Generic Imports System.Collections.Immutable Imports System.Diagnostics Imports System.Linq +Imports System.Reflection Imports System.Reflection.Metadata +Imports System.Reflection.Metadata.Ecma335 Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.CodeGen Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax +Imports BlobBuilder = Roslyn.Reflection.BlobBuilder Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Imports ILOpCode = Microsoft.CodeAnalysis.CodeGen.ILOpCode @@ -275,7 +278,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen Return result End Function - Private Sub SerializeArrayRecursive(bw As Cci.BlobBuilder, inits As ImmutableArray(Of BoundExpression)) + Private Sub SerializeArrayRecursive(bw As BlobBuilder, inits As ImmutableArray(Of BoundExpression)) If inits.Length <> 0 Then If inits(0).Kind = BoundKind.ArrayInitialization Then For Each init In inits diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb b/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb index f7dafe473a2c7..1babae49106d3 100644 --- a/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb +++ b/src/Compilers/VisualBasic/Portable/CodeGen/EmitStatement.vb @@ -1445,7 +1445,7 @@ OtherExpressions: slot:=field.SlotIndex, synthesizedKind:=SynthesizedLocalKind.EmitterTemp, id:=Nothing, - pdbAttributes:=Cci.PdbWriter.DefaultLocalAttributesValue, + pdbAttributes:=LocalVariableAttributes.None, constraints:=LocalSlotConstraints.None, isDynamic:=False, dynamicTransformFlags:=Nothing) diff --git a/src/Compilers/VisualBasic/Portable/Emit/ArrayTypeSymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/ArrayTypeSymbolAdapter.vb index 4ac104440e29d..18b25ad25ad9d 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/ArrayTypeSymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/ArrayTypeSymbolAdapter.vb @@ -27,40 +27,24 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Private ReadOnly Property IArrayTypeReferenceLowerBounds As IEnumerable(Of Integer) Implements Cci.IArrayTypeReference.LowerBounds + Private ReadOnly Property IArrayTypeReferenceLowerBounds As ImmutableArray(Of Integer) Implements Cci.IArrayTypeReference.LowerBounds Get - Dim lowerBounds = Me.LowerBounds - - If lowerBounds.IsDefault Then - Return Linq.Enumerable.Repeat(0, Me.Rank) - End If - - Return lowerBounds + Return LowerBounds End Get End Property - Private ReadOnly Property IArrayTypeReferenceRank As UInteger Implements Cci.IArrayTypeReference.Rank + Private ReadOnly Property IArrayTypeReferenceRank As Integer Implements Cci.IArrayTypeReference.Rank Get - Return CType(Me.Rank, UInteger) + Return Rank End Get End Property - Private ReadOnly Property IArrayTypeReferenceSizes As IEnumerable(Of ULong) Implements Cci.IArrayTypeReference.Sizes + Private ReadOnly Property IArrayTypeReferenceSizes As ImmutableArray(Of Integer) Implements Cci.IArrayTypeReference.Sizes Get - If Me.Sizes.IsEmpty Then - Return SpecializedCollections.EmptyEnumerable(Of ULong)() - End If - - Return GetSizes() + Return Sizes End Get End Property - Private Iterator Function GetSizes() As IEnumerable(Of ULong) - For Each size In Me.Sizes - Yield CType(size, ULong) - Next - End Function - Private ReadOnly Property ITypeReferenceIsEnum As Boolean Implements Cci.ITypeReference.IsEnum Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Emit/FieldSymbolAdapter.vb b/src/Compilers/VisualBasic/Portable/Emit/FieldSymbolAdapter.vb index 4311631cfb494..9ef115df369aa 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/FieldSymbolAdapter.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/FieldSymbolAdapter.vb @@ -202,11 +202,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - Private ReadOnly Property IFieldDefinitionOffset As UInteger Implements IFieldDefinition.Offset + Private ReadOnly Property IFieldDefinitionOffset As Integer Implements IFieldDefinition.Offset Get CheckDefinitionInvariant() - Dim offset = Me.TypeLayoutOffset - Return CUInt(If(offset, 0)) + Return If(TypeLayoutOffset, 0) End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb index 7dadc182d3709..1e02e425e3e95 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEAssemblyBuilder.vb @@ -90,15 +90,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return False End Function - Private ReadOnly Property IAssemblyFlags As UInteger Implements Cci.IAssembly.Flags + Private ReadOnly Property IAssemblyFlags As AssemblyFlags Implements Cci.IAssembly.Flags Get - Dim result As System.Reflection.AssemblyNameFlags = m_SourceAssembly.Flags And Not System.Reflection.AssemblyNameFlags.PublicKey + Dim result As AssemblyFlags = m_SourceAssembly.Flags And Not AssemblyFlags.PublicKey If Not m_SourceAssembly.PublicKey.IsDefaultOrEmpty Then - result = result Or System.Reflection.AssemblyNameFlags.PublicKey + result = result Or AssemblyFlags.PublicKey End If - Return CUInt(result) + Return result End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb index 798a38daa8537..c564db53ebd57 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceAssemblySymbol.vb @@ -665,10 +665,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' This represents what the user claimed in source through the AssemblyFlagsAttribute. ''' It may be modified as emitted due to presence or absence of the public key. ''' - Friend ReadOnly Property Flags As AssemblyNameFlags + Friend ReadOnly Property Flags As AssemblyFlags Get - Dim defaultValue As AssemblyNameFlags = AssemblyNameFlags.None - Dim fieldValue = defaultValue + Dim fieldValue As AssemblyFlags = Nothing Dim data = GetSourceDecodedWellKnownAttributeData() If data IsNot Nothing Then @@ -1086,12 +1085,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols If signature <> -1 Then Dim value As Object = attrData.CommonConstructorArguments(0).Value - Dim nameFlags As AssemblyNameFlags + Dim nameFlags As AssemblyFlags If signature = 0 OrElse signature = 1 Then - nameFlags = CType(value, AssemblyNameFlags) + nameFlags = CType(CType(value, AssemblyNameFlags), AssemblyFlags) Else - nameFlags = CType(CUInt(value), AssemblyNameFlags) + nameFlags = CType(CUInt(value), AssemblyFlags) End If arguments.GetOrCreateData(Of CommonAssemblyWellKnownAttributeData)().AssemblyFlagsAttributeSetting = nameFlags diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb index 1b9999cacc5f1..0382173c7b6eb 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Source/SourceMethodSymbol.vb @@ -2,6 +2,7 @@ Imports System.Collections.Immutable Imports System.Globalization +Imports System.Reflection Imports System.Runtime.InteropServices Imports System.Threading Imports Microsoft.Cci @@ -277,20 +278,20 @@ lReportErrorOnTwoTokens: Return New SourceDeclareMethodSymbol(container, name, flags, binder, syntax, importData) End Function - Private Shared Function GetPInvokeAttributes(syntax As DeclareStatementSyntax) As PInvokeAttributes - Dim result As PInvokeAttributes + Private Shared Function GetPInvokeAttributes(syntax As DeclareStatementSyntax) As MethodImportAttributes + Dim result As MethodImportAttributes Select Case syntax.CharsetKeyword.Kind Case SyntaxKind.None, SyntaxKind.AnsiKeyword - result = PInvokeAttributes.CharSetAnsi Or PInvokeAttributes.NoMangle + result = MethodImportAttributes.CharSetAnsi Or MethodImportAttributes.ExactSpelling Case SyntaxKind.UnicodeKeyword - result = PInvokeAttributes.CharSetUnicode Or PInvokeAttributes.NoMangle + result = MethodImportAttributes.CharSetUnicode Or MethodImportAttributes.ExactSpelling Case SyntaxKind.AutoKeyword - result = PInvokeAttributes.CharSetAuto + result = MethodImportAttributes.CharSetAuto End Select - Return result Or PInvokeAttributes.CallConvWinapi Or PInvokeAttributes.SupportsLastError + Return result Or MethodImportAttributes.CallingConventionWinApi Or MethodImportAttributes.SetLastError End Function Friend Shared Function CreateOperator( diff --git a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb index b90a6a7389387..187ae9f9a95fd 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.vb @@ -817,12 +817,12 @@ End Class Assert.Equal(True, info.ThrowOnUnmappableCharacter) Assert.Equal( - Cci.PInvokeAttributes.NoMangle Or - Cci.PInvokeAttributes.CharSetUnicode Or - Cci.PInvokeAttributes.SupportsLastError Or - Cci.PInvokeAttributes.CallConvCdecl Or - Cci.PInvokeAttributes.BestFitEnabled Or - Cci.PInvokeAttributes.ThrowOnUnmappableCharEnabled, DirectCast(info, Cci.IPlatformInvokeInformation).Flags) + MethodImportAttributes.ExactSpelling Or + MethodImportAttributes.CharSetUnicode Or + MethodImportAttributes.SetLastError Or + MethodImportAttributes.CallingConventionCDecl Or + MethodImportAttributes.BestFitMappingEnable Or + MethodImportAttributes.ThrowOnUnmappableCharEnable, DirectCast(info, Cci.IPlatformInvokeInformation).Flags) End Sub CompileAndVerify(source, validator:=validator, symbolValidator:=symValidator) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs index 1d9aa671973c8..a6ca9f6708067 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs @@ -10,6 +10,7 @@ using Roslyn.Utilities; using System.Collections.Immutable; using System.Diagnostics; +using System.Reflection.Metadata; namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator { @@ -120,9 +121,9 @@ private static LocalDefinition ToLocalDefinition(LocalSymbol local, int index) local.Name, (Cci.ITypeReference)type, slot: index, - synthesizedKind: (SynthesizedLocalKind)local.SynthesizedKind, + synthesizedKind: local.SynthesizedKind, id: LocalDebugId.None, - pdbAttributes: Cci.PdbWriter.DefaultLocalAttributesValue, + pdbAttributes: LocalVariableAttributes.None, constraints: constraints, isDynamic: false, dynamicTransformFlags: ImmutableArray.Empty); @@ -148,7 +149,7 @@ public override LocalDefinition GetPreviousLocal( string nameOpt, SynthesizedLocalKind synthesizedKind, LocalDebugId id, - uint pdbAttributes, + LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray dynamicTransformFlags) diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs index abb65e984ddba..86aba4ac6da99 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EvaluationContext.cs @@ -258,7 +258,7 @@ internal override CompileResult CompileExpression( nativePdbWriterOpt: null, pdbPathOpt: null, allowMissingMethodBodies: false, - deterministic: false, + isDeterministic: false, cancellationToken: default(CancellationToken)); if (diagnostics.HasAnyErrors()) @@ -347,7 +347,7 @@ internal override CompileResult CompileAssignment( nativePdbWriterOpt: null, pdbPathOpt: null, allowMissingMethodBodies: false, - deterministic: false, + isDeterministic: false, cancellationToken: default(CancellationToken)); if (diagnostics.HasAnyErrors()) @@ -390,7 +390,7 @@ internal override ReadOnlyCollection CompileGetLocals( nativePdbWriterOpt: null, pdbPathOpt: null, allowMissingMethodBodies: false, - deterministic: false, + isDeterministic: false, cancellationToken: default(CancellationToken)); if (!diagnostics.HasAnyErrors()) diff --git a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/MetadataUtilities.cs b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/MetadataUtilities.cs index 42e4e2c025d94..6f7a4ae830518 100644 --- a/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/MetadataUtilities.cs +++ b/src/ExpressionEvaluator/Core/Source/ExpressionCompiler/MetadataUtilities.cs @@ -370,7 +370,7 @@ internal static ImmutableArray GetLocalNames(this ArrayBuilder entry.Document)} #{_reader.GetHeapOffset(entry.SequencePointsBlob):x}"); + _writer.WriteLine($"{MetadataTokens.GetRowNumber(handle):x}: {Token(() => entry.Document)} #{_reader.GetHeapOffset(entry.SequencePointsBlob):x}"); if (entry.SequencePointsBlob.IsNil) { diff --git a/src/Test/Utilities/Desktop/CommonTestBase.cs b/src/Test/Utilities/Desktop/CommonTestBase.cs index 2e90de0437095..fad63f6d2d70c 100644 --- a/src/Test/Utilities/Desktop/CommonTestBase.cs +++ b/src/Test/Utilities/Desktop/CommonTestBase.cs @@ -502,20 +502,17 @@ internal static Cci.ModulePropertiesForSerialization GetDefaultModulePropertiesF { return new Cci.ModulePropertiesForSerialization( persistentIdentifier: default(Guid), + corFlags: CorFlags.ILOnly, fileAlignment: Cci.ModulePropertiesForSerialization.DefaultFileAlignment32Bit, sectionAlignment: Cci.ModulePropertiesForSerialization.DefaultSectionAlignment, targetRuntimeVersion: "v4.0.30319", machine: 0, - prefer32Bit: false, - trackDebugData: false, baseAddress: Cci.ModulePropertiesForSerialization.DefaultExeBaseAddress32Bit, sizeOfHeapReserve: Cci.ModulePropertiesForSerialization.DefaultSizeOfHeapReserve32Bit, sizeOfHeapCommit: Cci.ModulePropertiesForSerialization.DefaultSizeOfHeapCommit32Bit, sizeOfStackReserve: Cci.ModulePropertiesForSerialization.DefaultSizeOfStackReserve32Bit, sizeOfStackCommit: Cci.ModulePropertiesForSerialization.DefaultSizeOfStackCommit32Bit, - enableHighEntropyVA: true, - strongNameSigned: false, - configureToExecuteInAppContainer: false, + dllCharacteristics: Compilation.GetDllCharacteristics(enableHighEntropyVA: true, configureToExecuteInAppContainer: false), subsystem: Subsystem.WindowsCui, imageCharacteristics: Characteristics.Dll, majorSubsystemVersion: 0, diff --git a/src/Test/Utilities/Portable/CommonTestBase.cs b/src/Test/Utilities/Portable/CommonTestBase.cs index 70e1e89c7bb1a..842d3f54c0736 100644 --- a/src/Test/Utilities/Portable/CommonTestBase.cs +++ b/src/Test/Utilities/Portable/CommonTestBase.cs @@ -443,20 +443,17 @@ internal static Cci.ModulePropertiesForSerialization GetDefaultModulePropertiesF { return new Cci.ModulePropertiesForSerialization( persistentIdentifier: default(Guid), + corFlags: CorFlags.ILOnly, fileAlignment: Cci.ModulePropertiesForSerialization.DefaultFileAlignment32Bit, sectionAlignment: Cci.ModulePropertiesForSerialization.DefaultSectionAlignment, targetRuntimeVersion: "v4.0.30319", machine: 0, - prefer32Bit: false, - trackDebugData: false, baseAddress: Cci.ModulePropertiesForSerialization.DefaultExeBaseAddress32Bit, sizeOfHeapReserve: Cci.ModulePropertiesForSerialization.DefaultSizeOfHeapReserve32Bit, sizeOfHeapCommit: Cci.ModulePropertiesForSerialization.DefaultSizeOfHeapCommit32Bit, sizeOfStackReserve: Cci.ModulePropertiesForSerialization.DefaultSizeOfStackReserve32Bit, sizeOfStackCommit: Cci.ModulePropertiesForSerialization.DefaultSizeOfStackCommit32Bit, - enableHighEntropyVA: true, - strongNameSigned: false, - configureToExecuteInAppContainer: false, + dllCharacteristics: Compilation.GetDllCharacteristics(enableHighEntropyVA: true, configureToExecuteInAppContainer: false), subsystem: Subsystem.WindowsCui, imageCharacteristics: Characteristics.Dll, majorSubsystemVersion: 0, diff --git a/src/Test/Utilities/Shared/Metadata/ILBuilderVisualizer.cs b/src/Test/Utilities/Shared/Metadata/ILBuilderVisualizer.cs index 7b8086c52bce0..2e39b6aaff00b 100644 --- a/src/Test/Utilities/Shared/Metadata/ILBuilderVisualizer.cs +++ b/src/Test/Utilities/Shared/Metadata/ILBuilderVisualizer.cs @@ -198,7 +198,7 @@ private static void DumpBasicBlockIL(ILBuilder.BasicBlock block, StringBuilder s sb.Append(string.Format(" IL_{0:x4}:", block.RegularInstructionsLength + block.Start)); sb.Append(string.Format(" {0,-10}", GetInstructionName(block.BranchCode))); - if (block.BranchCode.IsBranchToLabel()) + if (block.BranchCode.IsBranch()) { var branchBlock = block.BranchBlock; if (branchBlock == null)