-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better BlobBuilder pooling #72383
Better BlobBuilder pooling #72383
Changes from all commits
03a61be
4351f58
06b1763
d2e8a20
fdcf80e
8f30134
1101c64
5e43343
fc23dec
814cd23
e08abbd
869a2eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,14 +33,14 @@ public ExtendedPEBuilder( | |
PEHeaderBuilder header, | ||
MetadataRootBuilder metadataRootBuilder, | ||
BlobBuilder ilStream, | ||
BlobBuilder mappedFieldData, | ||
BlobBuilder managedResources, | ||
ResourceSectionBuilder nativeResources, | ||
DebugDirectoryBuilder debugDirectoryBuilder, | ||
BlobBuilder? mappedFieldData, | ||
BlobBuilder? managedResources, | ||
ResourceSectionBuilder? nativeResources, | ||
DebugDirectoryBuilder? debugDirectoryBuilder, | ||
int strongNameSignatureSize, | ||
MethodDefinitionHandle entryPoint, | ||
CorFlags flags, | ||
Func<IEnumerable<Blob>, BlobContentId> deterministicIdProvider, | ||
Func<IEnumerable<Blob>, BlobContentId>? deterministicIdProvider, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These changes all line up with the declarations on the base type ctor. |
||
bool withMvidSection) | ||
: base(header, metadataRootBuilder, ilStream, mappedFieldData, managedResources, nativeResources, | ||
debugDirectoryBuilder, strongNameSignatureSize, entryPoint, flags, deterministicIdProvider) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Reflection.Metadata; | ||
using System.Reflection.Metadata.Ecma335; | ||
using Microsoft.Cci; | ||
|
||
namespace Microsoft.CodeAnalysis; | ||
|
||
internal static class MetadataBuilderExtensions | ||
{ | ||
internal static BlobHandle GetOrAddBlobAndFree(this MetadataBuilder metadataBuilder, PooledBlobBuilder builder) | ||
{ | ||
var handle = metadataBuilder.GetOrAddBlob(builder); | ||
builder.Free(); | ||
return handle; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -899,27 +899,6 @@ private EntityHandle GetExportedTypeImplementation(INamespaceTypeReference names | |
: GetAssemblyReferenceHandle(aref); | ||
} | ||
|
||
private static uint GetManagedResourceOffset(ManagedResource resource, BlobBuilder resourceWriter) | ||
{ | ||
if (resource.ExternalFile != null) | ||
{ | ||
return resource.Offset; | ||
} | ||
|
||
int result = resourceWriter.Count; | ||
resource.WriteData(resourceWriter); | ||
return (uint)result; | ||
} | ||
|
||
private static uint GetManagedResourceOffset(BlobBuilder resource, BlobBuilder resourceWriter) | ||
{ | ||
int result = resourceWriter.Count; | ||
resourceWriter.WriteInt32(resource.Count); | ||
resource.WriteContentTo(resourceWriter); | ||
resourceWriter.Align(8); | ||
return (uint)result; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These methods are only used in |
||
|
||
public static string GetMetadataName(INamedTypeReference namedType, int generation) | ||
{ | ||
string nameWithGeneration = (generation == 0) ? namedType.Name : namedType.Name + "#" + generation; | ||
|
@@ -1696,7 +1675,8 @@ internal EntityHandle GetDefinitionHandle(IDefinition definition) | |
}; | ||
} | ||
|
||
public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStream, Stream ilStream, Stream portablePdbStreamOpt, out MetadataSizes metadataSizes) | ||
#nullable enable | ||
public void WriteMetadataAndIL(PdbWriter? nativePdbWriterOpt, Stream metadataStream, Stream ilStream, Stream? portablePdbStreamOpt, out MetadataSizes metadataSizes) | ||
{ | ||
Debug.Assert(nativePdbWriterOpt == null ^ portablePdbStreamOpt == null); | ||
|
||
|
@@ -1705,8 +1685,8 @@ public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStre | |
// TODO: we can precalculate the exact size of IL stream | ||
var ilBuilder = new BlobBuilder(1024); | ||
var metadataBuilder = new BlobBuilder(4 * 1024); | ||
var mappedFieldDataBuilder = new BlobBuilder(0); | ||
var managedResourceDataBuilder = new BlobBuilder(0); | ||
PooledBlobBuilder? mappedFieldDataBuilder = null; | ||
PooledBlobBuilder? managedResourceDataBuilder = null; | ||
|
||
// 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. | ||
|
@@ -1721,8 +1701,8 @@ public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStre | |
BuildMetadataAndIL( | ||
nativePdbWriterOpt, | ||
ilBuilder, | ||
mappedFieldDataBuilder, | ||
managedResourceDataBuilder, | ||
out mappedFieldDataBuilder, | ||
out managedResourceDataBuilder, | ||
out Blob mvidFixup, | ||
out Blob mvidStringFixup); | ||
|
||
|
@@ -1731,16 +1711,16 @@ public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStre | |
Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncMap] == 0); | ||
PopulateEncTables(typeSystemRowCounts); | ||
|
||
Debug.Assert(mappedFieldDataBuilder.Count == 0); | ||
Debug.Assert(managedResourceDataBuilder.Count == 0); | ||
Debug.Assert(mappedFieldDataBuilder == null); | ||
Debug.Assert(managedResourceDataBuilder == null); | ||
Debug.Assert(mvidFixup.IsDefault); | ||
Debug.Assert(mvidStringFixup.IsDefault); | ||
|
||
// TODO: Update SRM to not sort Custom Attribute table when emitting EnC delta | ||
// https://github.com/dotnet/roslyn/issues/70389 | ||
if (!IsFullMetadata) | ||
{ | ||
metadata.GetType().GetField("_customAttributeTableNeedsSorting", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(metadata, false); | ||
metadata.GetType().GetField("_customAttributeTableNeedsSorting", BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(metadata, false); | ||
} | ||
|
||
// TODO (https://github.com/dotnet/roslyn/issues/3905): | ||
|
@@ -1783,10 +1763,10 @@ public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStre | |
} | ||
|
||
public void BuildMetadataAndIL( | ||
PdbWriter nativePdbWriterOpt, | ||
PdbWriter? nativePdbWriterOpt, | ||
BlobBuilder ilBuilder, | ||
BlobBuilder mappedFieldDataBuilder, | ||
BlobBuilder managedResourceDataBuilder, | ||
out PooledBlobBuilder? mappedFieldDataBuilder, | ||
out PooledBlobBuilder? managedResourceDataBuilder, | ||
out Blob mvidFixup, | ||
out Blob mvidStringFixup) | ||
{ | ||
|
@@ -1849,15 +1829,17 @@ public void BuildMetadataAndIL( | |
|
||
ReportReferencesToAddedSymbols(); | ||
|
||
BlobBuilder dynamicAnalysisDataOpt = null; | ||
PooledBlobBuilder? dynamicAnalysisData = null; | ||
if (_dynamicAnalysisDataWriterOpt != null) | ||
{ | ||
dynamicAnalysisDataOpt = new BlobBuilder(); | ||
_dynamicAnalysisDataWriterOpt.SerializeMetadataTables(dynamicAnalysisDataOpt); | ||
dynamicAnalysisData = PooledBlobBuilder.GetInstance(); | ||
_dynamicAnalysisDataWriterOpt.SerializeMetadataTables(dynamicAnalysisData); | ||
} | ||
|
||
PopulateTypeSystemTables(methodBodyOffsets, mappedFieldDataBuilder, managedResourceDataBuilder, dynamicAnalysisDataOpt, out mvidFixup); | ||
PopulateTypeSystemTables(methodBodyOffsets, out mappedFieldDataBuilder, out managedResourceDataBuilder, dynamicAnalysisData, out mvidFixup); | ||
dynamicAnalysisData?.Free(); | ||
} | ||
#nullable disable | ||
|
||
public virtual void PopulateEncTables(ImmutableArray<int> typeSystemRowCounts) | ||
{ | ||
|
@@ -1916,7 +1898,8 @@ private ImmutableArray<IGenericParameter> GetSortedGenericParameters() | |
}).ToImmutableArray(); | ||
} | ||
|
||
private void PopulateTypeSystemTables(int[] methodBodyOffsets, BlobBuilder mappedFieldDataWriter, BlobBuilder resourceWriter, BlobBuilder dynamicAnalysisDataOpt, out Blob mvidFixup) | ||
#nullable enable | ||
private void PopulateTypeSystemTables(int[] methodBodyOffsets, out PooledBlobBuilder? mappedFieldDataWriter, out PooledBlobBuilder? resourceWriter, BlobBuilder? dynamicAnalysisData, out Blob mvidFixup) | ||
{ | ||
var sortedGenericParameters = GetSortedGenericParameters(); | ||
|
||
|
@@ -1930,13 +1913,13 @@ private void PopulateTypeSystemTables(int[] methodBodyOffsets, BlobBuilder mappe | |
this.PopulateExportedTypeTableRows(); | ||
this.PopulateFieldLayoutTableRows(); | ||
this.PopulateFieldMarshalTableRows(); | ||
this.PopulateFieldRvaTableRows(mappedFieldDataWriter); | ||
this.PopulateFieldRvaTableRows(out mappedFieldDataWriter); | ||
this.PopulateFieldTableRows(); | ||
this.PopulateFileTableRows(); | ||
this.PopulateGenericParameters(sortedGenericParameters); | ||
this.PopulateImplMapTableRows(); | ||
this.PopulateInterfaceImplTableRows(); | ||
this.PopulateManifestResourceTableRows(resourceWriter, dynamicAnalysisDataOpt); | ||
this.PopulateManifestResourceTableRows(out resourceWriter, dynamicAnalysisData); | ||
this.PopulateMemberRefTableRows(); | ||
this.PopulateMethodImplTableRows(); | ||
this.PopulateMethodTableRows(methodBodyOffsets); | ||
|
@@ -1956,6 +1939,7 @@ private void PopulateTypeSystemTables(int[] methodBodyOffsets, BlobBuilder mappe | |
// This table is populated after the others because it depends on the order of the entries of the generic parameter table. | ||
this.PopulateCustomAttributeTableRows(sortedGenericParameters); | ||
} | ||
#nullable disable | ||
|
||
private void PopulateAssemblyRefTableRows() | ||
{ | ||
|
@@ -2336,15 +2320,20 @@ private void PopulateFieldMarshalTableRows() | |
} | ||
} | ||
|
||
private void PopulateFieldRvaTableRows(BlobBuilder mappedFieldDataWriter) | ||
#nullable enable | ||
private void PopulateFieldRvaTableRows(out PooledBlobBuilder? mappedFieldDataWriter) | ||
{ | ||
mappedFieldDataWriter = null; | ||
|
||
foreach (IFieldDefinition fieldDef in this.GetFieldDefs()) | ||
{ | ||
if (fieldDef.MappedData.IsDefault) | ||
{ | ||
continue; | ||
} | ||
|
||
mappedFieldDataWriter ??= PooledBlobBuilder.GetInstance(); | ||
|
||
// The compiler always aligns each RVA data field to an 8-byte boundary; this accomodates the alignment | ||
// needs for all primitive types, regardless of which type is actually being used, at the expense of | ||
// potentially wasting up to 7 bytes per field if the alignment needs are less. In the future, this | ||
|
@@ -2362,6 +2351,7 @@ private void PopulateFieldRvaTableRows(BlobBuilder mappedFieldDataWriter) | |
offset: offset); | ||
} | ||
} | ||
#nullable disable | ||
|
||
private void PopulateFieldTableRows() | ||
{ | ||
|
@@ -2417,6 +2407,7 @@ private void PopulateConstantTableRows() | |
continue; | ||
} | ||
|
||
Debug.Assert(propDef.DefaultValue != null); | ||
metadata.AddConstant( | ||
parent: GetPropertyDefIndex(propDef), | ||
value: propDef.DefaultValue.Value); | ||
|
@@ -2506,15 +2497,19 @@ private void PopulateInterfaceImplTableRows() | |
} | ||
} | ||
|
||
private void PopulateManifestResourceTableRows(BlobBuilder resourceDataWriter, BlobBuilder dynamicAnalysisDataOpt) | ||
#nullable enable | ||
private void PopulateManifestResourceTableRows(out PooledBlobBuilder? resourceDataWriter, BlobBuilder? dynamicAnalysisData) | ||
{ | ||
if (dynamicAnalysisDataOpt != null) | ||
resourceDataWriter = null; | ||
|
||
if (dynamicAnalysisData != null) | ||
{ | ||
resourceDataWriter = PooledBlobBuilder.GetInstance(); | ||
metadata.AddManifestResource( | ||
attributes: ManifestResourceAttributes.Private, | ||
name: metadata.GetOrAddString("<DynamicAnalysisData>"), | ||
implementation: default(EntityHandle), | ||
offset: GetManagedResourceOffset(dynamicAnalysisDataOpt, resourceDataWriter) | ||
offset: writeBuilderResourceAndGetOffset(dynamicAnalysisData, resourceDataWriter) | ||
); | ||
} | ||
|
||
|
@@ -2536,12 +2531,35 @@ private void PopulateManifestResourceTableRows(BlobBuilder resourceDataWriter, B | |
attributes: resource.IsPublic ? ManifestResourceAttributes.Public : ManifestResourceAttributes.Private, | ||
name: GetStringHandleForNameAndCheckLength(resource.Name), | ||
implementation: implementation, | ||
offset: GetManagedResourceOffset(resource, resourceDataWriter)); | ||
offset: writeManagedResourceAndGetOffset(resource, ref resourceDataWriter)); | ||
} | ||
|
||
// the stream should be aligned: | ||
Debug.Assert((resourceDataWriter.Count % ManagedPEBuilder.ManagedResourcesDataAlignment) == 0); | ||
Debug.Assert(resourceDataWriter == null || (resourceDataWriter.Count % ManagedPEBuilder.ManagedResourcesDataAlignment) == 0); | ||
|
||
static uint writeManagedResourceAndGetOffset(ManagedResource resource, ref PooledBlobBuilder? resourceWriter) | ||
{ | ||
if (resource.ExternalFile != null) | ||
{ | ||
return resource.Offset; | ||
} | ||
|
||
resourceWriter ??= PooledBlobBuilder.GetInstance(); | ||
int result = resourceWriter.Count; | ||
resource.WriteData(resourceWriter); | ||
return (uint)result; | ||
} | ||
|
||
static uint writeBuilderResourceAndGetOffset(BlobBuilder resource, BlobBuilder resourceWriter) | ||
{ | ||
int result = resourceWriter.Count; | ||
resourceWriter.WriteInt32(resource.Count); | ||
resource.WriteContentTo(resourceWriter); | ||
resourceWriter.Align(8); | ||
return (uint)result; | ||
} | ||
} | ||
#nullable disable | ||
|
||
private void PopulateMemberRefTableRows() | ||
{ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This allowed me to avoid a nullable suppression on
getMetadataPeStreamOpt
below.