<data name="ExpectedListOfSize" xml:space="preserve">
<value>Expected list of size {0}.</value>
</data>
+ <data name="ExpectedArrayOfSize" xml:space="preserve">
+ <value>Expected array of size {0}.</value>
+ </data>
<data name="ExpectedNonEmptyList" xml:space="preserve">
<value>Expected non-empty list.</value>
</data>
<data name="MustNotReturnNull" xml:space="preserve">
<value>{0} must not return null.</value>
</data>
+ <data name="MetadataVersionTooLong" xml:space="preserve">
+ <value>Metadata version too long.</value>
+ </data>
+ <data name="RowCountMustBeZero" xml:space="preserve">
+ <value>Row count must be zero for table #{0}.</value>
+ </data>
+ <data name="RowCountOutOfRange" xml:space="preserve">
+ <value>Row count specified for table index {0} is out of allowed range.</value>
+ </data>
</root>
<Compile Include="System\Reflection\Metadata\Ecma335\Encoding\FunctionPointerAttributes.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\Encoding\MethodBodiesEncoder.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\Encoding\MethodBodyAttributes.cs" />
+ <Compile Include="System\Reflection\Metadata\Ecma335\MetadataBuilder.cs" />
+ <Compile Include="System\Reflection\Metadata\Ecma335\MetadataRootBuilder.cs" />
+ <Compile Include="System\Reflection\Metadata\Ecma335\SerializedMetadataHeaps.cs" />
<Compile Include="System\Reflection\Metadata\EntityHandle.cs" />
<Compile Include="System\Reflection\Metadata\PooledBlobBuilder.cs" />
<Compile Include="System\Reflection\Metadata\Blob.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\Encoding\LabelHandle.cs" />
<Compile Include="System\Reflection\Metadata\IL\ILOpCode.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\CodedIndex.cs" />
- <Compile Include="System\Reflection\Metadata\Ecma335\MetadataSerializer.cs" />
+ <Compile Include="System\Reflection\Metadata\Ecma335\PortablePdbBuilder.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\MetadataBuilder.Tables.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\Encoding\BlobEncoders.cs" />
<Compile Include="System\Reflection\Metadata\Ecma335\Encoding\MethodBodyEncoder.cs" />
// internal for testing
internal static RowCounts[][] GetBaseRowCounts(IReadOnlyList<int> baseRowCounts, int generations)
{
- var rowCounts = new RowCounts[TableIndexExtensions.Count][];
+ var rowCounts = new RowCounts[MetadataTokens.TableCount][];
for (int t = 0; t < rowCounts.Length; t++)
{
// #String heap
private Dictionary<string, StringHandle> _strings = new Dictionary<string, StringHandle>(256);
- private readonly HeapBlobBuilder _stringBuilder = new HeapBlobBuilder(4 * 1024);
private readonly int _stringHeapStartOffset;
-
- // map allocated when the String heap is serialized:
- private int[] _stringVirtualIndexToHeapOffsetMap;
- private bool HeapsCompleted => _stringVirtualIndexToHeapOffsetMap != null;
+ private int _stringHeapCapacity = 4 * 1024;
// #Blob heap
private readonly Dictionary<ImmutableArray<byte>, BlobHandle> _blobs = new Dictionary<ImmutableArray<byte>, BlobHandle>(1024, ByteSequenceComparer.Instance);
break;
case HeapIndex.String:
- _stringBuilder.SetCapacity(byteCount);
+ _stringHeapCapacity = byteCount;
break;
case HeapIndex.UserString:
}
// internal for testing
- internal int SerializeHandle(StringHandle handle) => _stringVirtualIndexToHeapOffsetMap[handle.GetWriterVirtualIndex()];
+ internal int SerializeHandle(ImmutableArray<int> map, StringHandle handle) => map[handle.GetWriterVirtualIndex()];
internal int SerializeHandle(BlobHandle handle) => handle.GetHeapOffset();
internal int SerializeHandle(GuidHandle handle) => handle.Index;
internal int SerializeHandle(UserStringHandle handle) => handle.GetHeapOffset();
BlobHandle handle;
if (!_blobs.TryGetValue(value, out handle))
{
- Debug.Assert(!HeapsCompleted);
-
handle = BlobHandle.FromOffset(_blobHeapStartOffset + _blobHeapSize);
_blobs.Add(value, handle);
private GuidHandle GetNewGuidHandle()
{
- Debug.Assert(!HeapsCompleted);
-
// Unlike #Blob, #String and #US streams delta #GUID stream is padded to the
// size of the previous generation #GUID stream before new GUIDs are added.
// The first GUID added in a delta will thus have an index that equals the number
}
else if (!_strings.TryGetValue(value, out handle))
{
- Debug.Assert(!HeapsCompleted);
handle = StringHandle.FromWriterVirtualIndex(_strings.Count + 1); // idx 0 is reserved for empty string
_strings.Add(value, handle);
}
UserStringHandle handle;
if (!_userStrings.TryGetValue(value, out handle))
{
- Debug.Assert(!HeapsCompleted);
handle = GetNewUserStringHandle();
_userStrings.Add(value, handle);
return UserStringHandle.FromOffset(offset);
}
- internal void CompleteHeaps()
- {
- Debug.Assert(!HeapsCompleted);
- SerializeStringHeap();
- }
-
- public ImmutableArray<int> GetHeapSizes()
- {
- var heapSizes = new int[MetadataTokens.HeapCount];
-
- heapSizes[(int)HeapIndex.UserString] = _userStringBuilder.Count;
- heapSizes[(int)HeapIndex.String] = _stringBuilder.Count;
- heapSizes[(int)HeapIndex.Blob] = _blobHeapSize;
- heapSizes[(int)HeapIndex.Guid] = _guidBuilder.Count;
-
- return ImmutableArray.CreateRange(heapSizes);
- }
-
/// <summary>
/// Fills in stringIndexMap with data from stringIndex and write to stringWriter.
/// Releases stringIndex as the stringTable is sealed after this point.
/// </summary>
- private void SerializeStringHeap()
+ private static ImmutableArray<int> SerializeStringHeap(
+ BlobBuilder heapBuilder,
+ Dictionary<string, StringHandle> strings,
+ int stringHeapStartOffset)
{
// Sort by suffix and remove stringIndex
- var sorted = new List<KeyValuePair<string, StringHandle>>(_strings);
- sorted.Sort(new SuffixSort());
- _strings = null;
+ var sorted = new List<KeyValuePair<string, StringHandle>>(strings);
+ sorted.Sort(SuffixSort.Instance);
// Create VirtIdx to Idx map and add entry for empty string
- _stringVirtualIndexToHeapOffsetMap = new int[sorted.Count + 1];
+ int totalCount = sorted.Count + 1;
+ var stringVirtualIndexToHeapOffsetMap = ImmutableArray.CreateBuilder<int>(totalCount);
+ stringVirtualIndexToHeapOffsetMap.Count = totalCount;
- _stringVirtualIndexToHeapOffsetMap[0] = 0;
- _stringBuilder.WriteByte(0);
+ stringVirtualIndexToHeapOffsetMap[0] = 0;
+ heapBuilder.WriteByte(0);
// Find strings that can be folded
string prev = string.Empty;
foreach (KeyValuePair<string, StringHandle> entry in sorted)
{
- int position = _stringHeapStartOffset + _stringBuilder.Count;
+ int position = stringHeapStartOffset + heapBuilder.Count;
// It is important to use ordinal comparison otherwise we'll use the current culture!
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.
- _stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1);
+ stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1);
}
else
{
- _stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position;
- _stringBuilder.WriteUTF8(entry.Key, allowUnpairedSurrogates: false);
- _stringBuilder.WriteByte(0);
+ stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position;
+ heapBuilder.WriteUTF8(entry.Key, allowUnpairedSurrogates: false);
+ heapBuilder.WriteByte(0);
}
prev = entry.Key;
}
+
+ return stringVirtualIndexToHeapOffsetMap.MoveToImmutable();
}
/// <summary>
/// </summary>
private sealed class SuffixSort : IComparer<KeyValuePair<string, StringHandle>>
{
+ internal static SuffixSort Instance = new SuffixSort();
+
public int Compare(KeyValuePair<string, StringHandle> xPair, KeyValuePair<string, StringHandle> yPair)
{
string x = xPair.Key;
}
}
- internal void WriteHeapsTo(BlobBuilder builder)
+ internal void WriteHeapsTo(BlobBuilder builder, BlobBuilder stringHeap)
{
- Debug.Assert(HeapsCompleted);
-
- WriteAligned(_stringBuilder, builder);
+ WriteAligned(stringHeap, builder);
WriteAligned(_userStringBuilder, builder);
WriteAligned(_guidBuilder, builder);
WriteAlignedBlobHeap(builder);
}
}
+ /// <summary>
+ /// Returns the current number of entires in the specified table.
+ /// </summary>
+ /// <param name="table">Table index.</param>
+ /// <returns>The number of entires in the table.</returns>
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="table"/> is not a valid table index.</exception>
+ public int GetRowCount(TableIndex table)
+ {
+ switch (table)
+ {
+ case TableIndex.Assembly : return _assemblyRow.HasValue ? 1 : 0;
+ case TableIndex.AssemblyRef : return _assemblyRefTable.Count;
+ case TableIndex.ClassLayout : return _classLayoutTable.Count;
+ case TableIndex.Constant : return _constantTable.Count;
+ case TableIndex.CustomAttribute : return _customAttributeTable.Count;
+ case TableIndex.DeclSecurity : return _declSecurityTable.Count;
+ case TableIndex.EncLog : return _encLogTable.Count;
+ case TableIndex.EncMap : return _encMapTable.Count;
+ case TableIndex.EventMap : return _eventMapTable.Count;
+ case TableIndex.Event : return _eventTable.Count;
+ case TableIndex.ExportedType : return _exportedTypeTable.Count;
+ case TableIndex.FieldLayout : return _fieldLayoutTable.Count;
+ case TableIndex.FieldMarshal : return _fieldMarshalTable.Count;
+ case TableIndex.FieldRva : return _fieldRvaTable.Count;
+ case TableIndex.Field : return _fieldTable.Count;
+ case TableIndex.File : return _fileTable.Count;
+ case TableIndex.GenericParamConstraint : return _genericParamConstraintTable.Count;
+ case TableIndex.GenericParam : return _genericParamTable.Count;
+ case TableIndex.ImplMap : return _implMapTable.Count;
+ case TableIndex.InterfaceImpl : return _interfaceImplTable.Count;
+ case TableIndex.ManifestResource : return _manifestResourceTable.Count;
+ case TableIndex.MemberRef : return _memberRefTable.Count;
+ case TableIndex.MethodImpl : return _methodImplTable.Count;
+ case TableIndex.MethodSemantics : return _methodSemanticsTable.Count;
+ case TableIndex.MethodSpec : return _methodSpecTable.Count;
+ case TableIndex.MethodDef : return _methodDefTable.Count;
+ case TableIndex.ModuleRef : return _moduleRefTable.Count;
+ case TableIndex.Module : return _moduleRow.HasValue ? 1 : 0;
+ case TableIndex.NestedClass : return _nestedClassTable.Count;
+ case TableIndex.Param : return _paramTable.Count;
+ case TableIndex.PropertyMap : return _propertyMapTable.Count;
+ case TableIndex.Property : return _propertyTable.Count;
+ case TableIndex.StandAloneSig : return _standAloneSigTable.Count;
+ case TableIndex.TypeDef : return _typeDefTable.Count;
+ case TableIndex.TypeRef : return _typeRefTable.Count;
+ case TableIndex.TypeSpec : return _typeSpecTable.Count;
+ case TableIndex.Document : return _documentTable.Count;
+ case TableIndex.MethodDebugInformation : return _methodDebugInformationTable.Count;
+ case TableIndex.LocalScope : return _localScopeTable.Count;
+ case TableIndex.LocalVariable : return _localVariableTable.Count;
+ case TableIndex.LocalConstant : return _localConstantTable.Count;
+ case TableIndex.StateMachineMethod : return _stateMachineMethodTable.Count;
+ case TableIndex.ImportScope : return _importScopeTable.Count;
+ case TableIndex.CustomDebugInformation : return _customDebugInformationTable.Count;
+
+ case TableIndex.AssemblyOS:
+ case TableIndex.AssemblyProcessor:
+ case TableIndex.AssemblyRefOS:
+ case TableIndex.AssemblyRefProcessor:
+ case TableIndex.EventPtr:
+ case TableIndex.FieldPtr:
+ case TableIndex.MethodPtr:
+ case TableIndex.ParamPtr:
+ case TableIndex.PropertyPtr:
+ return 0;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(table));
+ }
+ }
+
+ /// <summary>
+ /// Returns the current number of entires in each table.
+ /// </summary>
+ /// <returns>
+ /// An array of size <see cref="MetadataTokens.TableCount"/> with each item filled with the current row count of the corresponding table.
+ /// </returns>
+ public ImmutableArray<int> GetRowCounts()
+ {
+ var rowCounts = ImmutableArray.CreateBuilder<int>(MetadataTokens.TableCount);
+ rowCounts.Count = MetadataTokens.TableCount;
+
+ rowCounts[(int)TableIndex.Assembly] = _assemblyRow.HasValue ? 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] = _fieldTable.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] = _methodDefTable.Count;
+ rowCounts[(int)TableIndex.ModuleRef] = _moduleRefTable.Count;
+ rowCounts[(int)TableIndex.Module] = _moduleRow.HasValue ? 1 : 0;
+ 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] = _standAloneSigTable.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 rowCounts.MoveToImmutable();
+ }
+
#region Building
// Note on argument value checking:
#endregion
- public ImmutableArray<int> GetRowCounts()
- {
- var rowCounts = new int[MetadataTokens.TableCount];
-
- rowCounts[(int)TableIndex.Assembly] = _assemblyRow.HasValue ? 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] = _fieldTable.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] = _methodDefTable.Count;
- rowCounts[(int)TableIndex.ModuleRef] = _moduleRefTable.Count;
- rowCounts[(int)TableIndex.Module] = _moduleRow.HasValue ? 1 : 0;
- 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] = _standAloneSigTable.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);
- }
-
#region Serialization
internal void SerializeMetadataTables(
BlobBuilder writer,
MetadataSizes metadataSizes,
+ ImmutableArray<int> stringMap,
int methodBodyStreamRva,
int mappedFieldDataStreamRva)
{
int startPosition = writer.Count;
- this.SerializeTablesHeader(writer, metadataSizes);
+ SerializeTablesHeader(writer, metadataSizes);
if (metadataSizes.IsPresent(TableIndex.Module))
{
- SerializeModuleTable(writer, metadataSizes);
+ SerializeModuleTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.TypeRef))
{
- this.SerializeTypeRefTable(writer, metadataSizes);
+ SerializeTypeRefTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.TypeDef))
{
- this.SerializeTypeDefTable(writer, metadataSizes);
+ SerializeTypeDefTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.Field))
{
- this.SerializeFieldTable(writer, metadataSizes);
+ SerializeFieldTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.MethodDef))
{
- this.SerializeMethodDefTable(writer, metadataSizes, methodBodyStreamRva);
+ SerializeMethodDefTable(writer, stringMap, metadataSizes, methodBodyStreamRva);
}
if (metadataSizes.IsPresent(TableIndex.Param))
{
- this.SerializeParamTable(writer, metadataSizes);
+ SerializeParamTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.InterfaceImpl))
{
- this.SerializeInterfaceImplTable(writer, metadataSizes);
+ SerializeInterfaceImplTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.MemberRef))
{
- this.SerializeMemberRefTable(writer, metadataSizes);
+ SerializeMemberRefTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.Constant))
{
- this.SerializeConstantTable(writer, metadataSizes);
+ SerializeConstantTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.CustomAttribute))
{
- this.SerializeCustomAttributeTable(writer, metadataSizes);
+ SerializeCustomAttributeTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.FieldMarshal))
{
- this.SerializeFieldMarshalTable(writer, metadataSizes);
+ SerializeFieldMarshalTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.DeclSecurity))
{
- this.SerializeDeclSecurityTable(writer, metadataSizes);
+ SerializeDeclSecurityTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.ClassLayout))
{
- this.SerializeClassLayoutTable(writer, metadataSizes);
+ SerializeClassLayoutTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.FieldLayout))
{
- this.SerializeFieldLayoutTable(writer, metadataSizes);
+ SerializeFieldLayoutTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.StandAloneSig))
{
- this.SerializeStandAloneSigTable(writer, metadataSizes);
+ SerializeStandAloneSigTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.EventMap))
{
- this.SerializeEventMapTable(writer, metadataSizes);
+ SerializeEventMapTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.Event))
{
- this.SerializeEventTable(writer, metadataSizes);
+ SerializeEventTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.PropertyMap))
{
- this.SerializePropertyMapTable(writer, metadataSizes);
+ SerializePropertyMapTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.Property))
{
- this.SerializePropertyTable(writer, metadataSizes);
+ SerializePropertyTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.MethodSemantics))
{
- this.SerializeMethodSemanticsTable(writer, metadataSizes);
+ SerializeMethodSemanticsTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.MethodImpl))
{
- this.SerializeMethodImplTable(writer, metadataSizes);
+ SerializeMethodImplTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.ModuleRef))
{
- this.SerializeModuleRefTable(writer, metadataSizes);
+ SerializeModuleRefTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.TypeSpec))
{
- this.SerializeTypeSpecTable(writer, metadataSizes);
+ SerializeTypeSpecTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.ImplMap))
{
- this.SerializeImplMapTable(writer, metadataSizes);
+ SerializeImplMapTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.FieldRva))
{
- this.SerializeFieldRvaTable(writer, metadataSizes, mappedFieldDataStreamRva);
+ SerializeFieldRvaTable(writer, metadataSizes, mappedFieldDataStreamRva);
}
if (metadataSizes.IsPresent(TableIndex.EncLog))
{
- this.SerializeEncLogTable(writer);
+ SerializeEncLogTable(writer);
}
if (metadataSizes.IsPresent(TableIndex.EncMap))
{
- this.SerializeEncMapTable(writer);
+ SerializeEncMapTable(writer);
}
if (metadataSizes.IsPresent(TableIndex.Assembly))
{
- this.SerializeAssemblyTable(writer, metadataSizes);
+ SerializeAssemblyTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.AssemblyRef))
{
- this.SerializeAssemblyRefTable(writer, metadataSizes);
+ SerializeAssemblyRefTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.File))
{
- this.SerializeFileTable(writer, metadataSizes);
+ SerializeFileTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.ExportedType))
{
- this.SerializeExportedTypeTable(writer, metadataSizes);
+ SerializeExportedTypeTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.ManifestResource))
{
- this.SerializeManifestResourceTable(writer, metadataSizes);
+ SerializeManifestResourceTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.NestedClass))
{
- this.SerializeNestedClassTable(writer, metadataSizes);
+ SerializeNestedClassTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.GenericParam))
{
- this.SerializeGenericParamTable(writer, metadataSizes);
+ SerializeGenericParamTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.MethodSpec))
{
- this.SerializeMethodSpecTable(writer, metadataSizes);
+ SerializeMethodSpecTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.GenericParamConstraint))
{
- this.SerializeGenericParamConstraintTable(writer, metadataSizes);
+ SerializeGenericParamConstraintTable(writer, metadataSizes);
}
// debug tables
if (metadataSizes.IsPresent(TableIndex.Document))
{
- this.SerializeDocumentTable(writer, metadataSizes);
+ SerializeDocumentTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.MethodDebugInformation))
{
- this.SerializeMethodDebugInformationTable(writer, metadataSizes);
+ SerializeMethodDebugInformationTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.LocalScope))
{
- this.SerializeLocalScopeTable(writer, metadataSizes);
+ SerializeLocalScopeTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.LocalVariable))
{
- this.SerializeLocalVariableTable(writer, metadataSizes);
+ SerializeLocalVariableTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.LocalConstant))
{
- this.SerializeLocalConstantTable(writer, metadataSizes);
+ SerializeLocalConstantTable(writer, stringMap, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.ImportScope))
{
- this.SerializeImportScopeTable(writer, metadataSizes);
+ SerializeImportScopeTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.StateMachineMethod))
{
- this.SerializeStateMachineMethodTable(writer, metadataSizes);
+ SerializeStateMachineMethodTable(writer, metadataSizes);
}
if (metadataSizes.IsPresent(TableIndex.CustomDebugInformation))
{
- this.SerializeCustomDebugInformationTable(writer, metadataSizes);
+ SerializeCustomDebugInformationTable(writer, metadataSizes);
}
writer.WriteByte(0);
heapSizes |= HeapSizeFlag.BlobHeapLarge;
}
- if (metadataSizes.IsMinimalDelta)
+ if (metadataSizes.IsEncDelta)
{
- heapSizes |= (HeapSizeFlag.EnCDeltas | HeapSizeFlag.DeletedMarks);
+ heapSizes |= (HeapSizeFlag.EncDeltas | HeapSizeFlag.DeletedMarks);
}
ulong sortedDebugTables = metadataSizes.PresentTablesMask & MetadataSizes.SortedDebugTables;
}
// internal for testing
- internal void SerializeModuleTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ internal void SerializeModuleTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
if (_moduleRow.HasValue)
{
writer.WriteUInt16(_moduleRow.Value.Generation);
- writer.WriteReference(SerializeHandle(_moduleRow.Value.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, _moduleRow.Value.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(_moduleRow.Value.ModuleVersionId), metadataSizes.GuidReferenceIsSmall);
writer.WriteReference(SerializeHandle(_moduleRow.Value.EncId), metadataSizes.GuidReferenceIsSmall);
writer.WriteReference(SerializeHandle(_moduleRow.Value.EncBaseId), metadataSizes.GuidReferenceIsSmall);
}
}
- private void SerializeTypeRefTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeTypeRefTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (TypeRefRow typeRef in _typeRefTable)
{
writer.WriteReference(typeRef.ResolutionScope, metadataSizes.ResolutionScopeCodedIndexIsSmall);
- writer.WriteReference(SerializeHandle(typeRef.Name), metadataSizes.StringReferenceIsSmall);
- writer.WriteReference(SerializeHandle(typeRef.Namespace), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, typeRef.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, typeRef.Namespace), metadataSizes.StringReferenceIsSmall);
}
}
- private void SerializeTypeDefTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeTypeDefTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (TypeDefRow typeDef in _typeDefTable)
{
writer.WriteUInt32(typeDef.Flags);
- writer.WriteReference(SerializeHandle(typeDef.Name), metadataSizes.StringReferenceIsSmall);
- writer.WriteReference(SerializeHandle(typeDef.Namespace), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, typeDef.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, typeDef.Namespace), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(typeDef.Extends, metadataSizes.TypeDefOrRefCodedIndexIsSmall);
writer.WriteReference(typeDef.FieldList, metadataSizes.FieldDefReferenceIsSmall);
writer.WriteReference(typeDef.MethodList, metadataSizes.MethodDefReferenceIsSmall);
}
}
- private void SerializeFieldTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeFieldTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (FieldDefRow fieldDef in _fieldTable)
{
writer.WriteUInt16(fieldDef.Flags);
- writer.WriteReference(SerializeHandle(fieldDef.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, fieldDef.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(fieldDef.Signature), metadataSizes.BlobReferenceIsSmall);
}
}
- private void SerializeMethodDefTable(BlobBuilder writer, MetadataSizes metadataSizes, int methodBodyStreamRva)
+ private void SerializeMethodDefTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes, int methodBodyStreamRva)
{
foreach (MethodRow method in _methodDefTable)
{
writer.WriteUInt16(method.ImplFlags);
writer.WriteUInt16(method.Flags);
- writer.WriteReference(SerializeHandle(method.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, method.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(method.Signature), metadataSizes.BlobReferenceIsSmall);
writer.WriteReference(method.ParamList, metadataSizes.ParameterReferenceIsSmall);
}
}
- private void SerializeParamTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeParamTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (ParamRow param in _paramTable)
{
writer.WriteUInt16(param.Flags);
writer.WriteUInt16(param.Sequence);
- writer.WriteReference(SerializeHandle(param.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, param.Name), metadataSizes.StringReferenceIsSmall);
}
}
}
}
- private void SerializeMemberRefTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeMemberRefTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (MemberRefRow memberRef in _memberRefTable)
{
writer.WriteReference(memberRef.Class, metadataSizes.MemberRefParentCodedIndexIsSmall);
- writer.WriteReference(SerializeHandle(memberRef.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, memberRef.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(memberRef.Signature), metadataSizes.BlobReferenceIsSmall);
}
}
}
}
- private void SerializeEventTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeEventTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (EventRow eventRow in _eventTable)
{
writer.WriteUInt16(eventRow.EventFlags);
- writer.WriteReference(SerializeHandle(eventRow.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, eventRow.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(eventRow.EventType, metadataSizes.TypeDefOrRefCodedIndexIsSmall);
}
}
}
}
- private void SerializePropertyTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializePropertyTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (PropertyRow property in _propertyTable)
{
writer.WriteUInt16(property.PropFlags);
- writer.WriteReference(SerializeHandle(property.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, property.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(property.Type), metadataSizes.BlobReferenceIsSmall);
}
}
}
}
- private void SerializeModuleRefTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeModuleRefTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (ModuleRefRow moduleRef in _moduleRefTable)
{
- writer.WriteReference(SerializeHandle(moduleRef.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, moduleRef.Name), metadataSizes.StringReferenceIsSmall);
}
}
}
}
- private void SerializeImplMapTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeImplMapTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
#if DEBUG
for (int i = 1; i < _implMapTable.Count; i++)
{
writer.WriteUInt16(implMap.MappingFlags);
writer.WriteReference(implMap.MemberForwarded, metadataSizes.MemberForwardedCodedIndexIsSmall);
- writer.WriteReference(SerializeHandle(implMap.ImportName), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, implMap.ImportName), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(implMap.ImportScope, metadataSizes.ModuleRefReferenceIsSmall);
}
}
}
}
- private void SerializeAssemblyTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeAssemblyTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
if (_assemblyRow.HasValue)
{
writer.WriteUInt16((ushort)version.Revision);
writer.WriteUInt32(_assemblyRow.Value.Flags);
writer.WriteReference(SerializeHandle(_assemblyRow.Value.AssemblyKey), metadataSizes.BlobReferenceIsSmall);
- writer.WriteReference(SerializeHandle(_assemblyRow.Value.AssemblyName), metadataSizes.StringReferenceIsSmall);
- writer.WriteReference(SerializeHandle(_assemblyRow.Value.AssemblyCulture), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, _assemblyRow.Value.AssemblyName), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, _assemblyRow.Value.AssemblyCulture), metadataSizes.StringReferenceIsSmall);
}
}
- private void SerializeAssemblyRefTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeAssemblyRefTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (AssemblyRefTableRow row in _assemblyRefTable)
{
writer.WriteUInt16((ushort)row.Version.Revision);
writer.WriteUInt32(row.Flags);
writer.WriteReference(SerializeHandle(row.PublicKeyToken), metadataSizes.BlobReferenceIsSmall);
- writer.WriteReference(SerializeHandle(row.Name), metadataSizes.StringReferenceIsSmall);
- writer.WriteReference(SerializeHandle(row.Culture), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, row.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, row.Culture), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(row.HashValue), metadataSizes.BlobReferenceIsSmall);
}
}
- private void SerializeFileTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeFileTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (FileTableRow fileReference in _fileTable)
{
writer.WriteUInt32(fileReference.Flags);
- writer.WriteReference(SerializeHandle(fileReference.FileName), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, fileReference.FileName), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(fileReference.HashValue), metadataSizes.BlobReferenceIsSmall);
}
}
- private void SerializeExportedTypeTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeExportedTypeTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (ExportedTypeRow exportedType in _exportedTypeTable)
{
writer.WriteUInt32(exportedType.Flags);
writer.WriteInt32(exportedType.TypeDefId);
- writer.WriteReference(SerializeHandle(exportedType.TypeName), metadataSizes.StringReferenceIsSmall);
- writer.WriteReference(SerializeHandle(exportedType.TypeNamespace), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, exportedType.TypeName), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, exportedType.TypeNamespace), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(exportedType.Implementation, metadataSizes.ImplementationCodedIndexIsSmall);
}
}
- private void SerializeManifestResourceTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeManifestResourceTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (ManifestResourceRow manifestResource in _manifestResourceTable)
{
writer.WriteUInt32(manifestResource.Offset);
writer.WriteUInt32(manifestResource.Flags);
- writer.WriteReference(SerializeHandle(manifestResource.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, manifestResource.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(manifestResource.Implementation, metadataSizes.ImplementationCodedIndexIsSmall);
}
}
}
}
- private void SerializeGenericParamTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeGenericParamTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
#if DEBUG
for (int i = 1; i < _genericParamTable.Count; i++)
writer.WriteUInt16(genericParam.Number);
writer.WriteUInt16(genericParam.Flags);
writer.WriteReference(genericParam.Owner, metadataSizes.TypeOrMethodDefCodedIndexIsSmall);
- writer.WriteReference(SerializeHandle(genericParam.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, genericParam.Name), metadataSizes.StringReferenceIsSmall);
}
}
}
}
- private void SerializeLocalVariableTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeLocalVariableTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (var row in _localVariableTable)
{
writer.WriteUInt16(row.Attributes);
writer.WriteUInt16(row.Index);
- writer.WriteReference(SerializeHandle(row.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, row.Name), metadataSizes.StringReferenceIsSmall);
}
}
- private void SerializeLocalConstantTable(BlobBuilder writer, MetadataSizes metadataSizes)
+ private void SerializeLocalConstantTable(BlobBuilder writer, ImmutableArray<int> stringMap, MetadataSizes metadataSizes)
{
foreach (var row in _localConstantTable)
{
- writer.WriteReference(SerializeHandle(row.Name), metadataSizes.StringReferenceIsSmall);
+ writer.WriteReference(SerializeHandle(stringMap, row.Name), metadataSizes.StringReferenceIsSmall);
writer.WriteReference(SerializeHandle(row.Signature), metadataSizes.BlobReferenceIsSmall);
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Reflection.Internal;
+
+namespace System.Reflection.Metadata.Ecma335
+{
+ public sealed partial class MetadataBuilder
+ {
+ internal SerializedMetadata GetSerializedMetadata(ImmutableArray<int> externalRowCounts, int metadataVersionByteCount, bool isStandaloneDebugMetadata)
+ {
+ var stringHeapBuilder = new HeapBlobBuilder(_stringHeapCapacity);
+ var stringMap = SerializeStringHeap(stringHeapBuilder, _strings, _stringHeapStartOffset);
+
+ Debug.Assert(HeapIndex.UserString == 0);
+ Debug.Assert((int)HeapIndex.String == 1);
+ Debug.Assert((int)HeapIndex.Blob == 2);
+ Debug.Assert((int)HeapIndex.Guid == 3);
+
+ var heapSizes = ImmutableArray.Create(
+ _userStringBuilder.Count,
+ stringHeapBuilder.Count,
+ _blobHeapSize,
+ _guidBuilder.Count);
+
+ var sizes = new MetadataSizes(GetRowCounts(), externalRowCounts, heapSizes, metadataVersionByteCount, isStandaloneDebugMetadata);
+
+ return new SerializedMetadata(sizes, stringHeapBuilder, stringMap);
+ }
+
+ internal static void SerializeMetadataHeader(BlobBuilder builder, string metadataVersion, MetadataSizes sizes)
+ {
+ int startOffset = builder.Count;
+
+ // signature
+ builder.WriteUInt32(0x424A5342);
+
+ // major version
+ builder.WriteUInt16(1);
+
+ // minor version
+ builder.WriteUInt16(1);
+
+ // reserved
+ builder.WriteUInt32(0);
+
+ // Spec (section 24.2.1 Metadata Root):
+ // Length ... Number of bytes allocated to hold version string (including null terminator), call this x.
+ // Call the length of the string (including the terminator) m (we require m <= 255);
+ // the length x is m rounded up to a multiple of four.
+ builder.WriteInt32(sizes.MetadataVersionPaddedLength);
+
+ int metadataVersionStart = builder.Count;
+ builder.WriteUTF8(metadataVersion);
+ builder.WriteByte(0);
+ int metadataVersionEnd = builder.Count;
+
+ for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++)
+ {
+ builder.WriteByte(0);
+ }
+
+ // reserved
+ builder.WriteUInt16(0);
+
+ // number of streams
+ builder.WriteUInt16((ushort)(5 + (sizes.IsEncDelta ? 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", builder);
+ }
+
+ // 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.IsCompressed ? "#~" : "#-"), builder);
+
+ SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder);
+ SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder);
+ SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder);
+ SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder);
+
+ if (sizes.IsEncDelta)
+ {
+ SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder);
+ }
+
+ int endOffset = builder.Count;
+ Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize);
+ }
+
+ private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BlobBuilder builder)
+ {
+ // 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);
+ builder.WriteInt32(offsetFromStartOfMetadata);
+ builder.WriteInt32(alignedStreamSize);
+ foreach (char ch in streamName)
+ {
+ builder.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++)
+ {
+ builder.WriteByte(0);
+ }
+
+ offsetFromStartOfMetadata += alignedStreamSize;
+ }
+ }
+}
Throw.ArgumentNull(nameof(reader));
}
- if ((int)tableIndex >= TableIndexExtensions.Count)
+ if ((int)tableIndex >= MetadataTokens.TableCount)
{
Throw.TableIndexOutOfRange();
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Linq;
+
+namespace System.Reflection.Metadata.Ecma335
+{
+ /// <summary>
+ /// Builder of a Metadata Root to be embedded in a Portable Executable image.
+ /// </summary>
+ /// <remarks>
+ /// Metadata root constitutes of a metadata header followed by metadata streams (#~, #Strings, #US, #Guid and #Blob).
+ /// </remarks>
+ public sealed class MetadataRootBuilder
+ {
+ private const string DefaultMetadataVersionString = "v4.0.30319";
+
+ // internal for testing
+ internal static readonly ImmutableArray<int> EmptyRowCounts = ImmutableArray.CreateRange(Enumerable.Repeat(0, MetadataTokens.TableCount));
+
+ private readonly MetadataBuilder _tablesAndHeaps;
+ private readonly SerializedMetadata _serializedMetadata;
+
+ /// <summary>
+ /// Creates a builder of a metadata root.
+ /// </summary>
+ /// <param name="tablesAndHeaps">
+ /// Builder populated with metadata entities stored in tables and values stored in heaps.
+ /// The entities and values will be enumerated when serializing the metadata root.
+ /// </param>
+ /// <param name="metadataVersion">
+ /// The version string written to the metadata header. The default value is "v4.0.30319".
+ /// </param>
+ /// <exception cref="ArgumentNullException"><paramref name="tablesAndHeaps"/> is null.</exception>
+ /// <exception cref="ArgumentException"><paramref name="metadataVersion"/> is too long (the number of bytes when UTF8-encoded must be less than 255).</exception>
+ public MetadataRootBuilder(MetadataBuilder tablesAndHeaps, string metadataVersion = null)
+ {
+ if (tablesAndHeaps == null)
+ {
+ Throw.ArgumentNull(nameof(tablesAndHeaps));
+ }
+
+ Debug.Assert(BlobUtilities.GetUTF8ByteCount(DefaultMetadataVersionString) == DefaultMetadataVersionString.Length);
+ int metadataVersionByteCount = metadataVersion != null ? BlobUtilities.GetUTF8ByteCount(metadataVersion) : DefaultMetadataVersionString.Length;
+
+ if (metadataVersionByteCount > MetadataSizes.MaxMetadataVersionByteCount)
+ {
+ Throw.InvalidArgument(SR.MetadataVersionTooLong, nameof(metadataVersion));
+ }
+
+ _tablesAndHeaps = tablesAndHeaps;
+ MetadataVersion = metadataVersion ?? DefaultMetadataVersionString;
+ _serializedMetadata = tablesAndHeaps.GetSerializedMetadata(EmptyRowCounts, metadataVersionByteCount, isStandaloneDebugMetadata: false);
+ }
+
+ /// <summary>
+ /// Metadata version string.
+ /// </summary>
+ public string MetadataVersion { get; }
+
+ /// <summary>
+ /// Returns sizes of various metadata structures.
+ /// </summary>
+ public MetadataSizes Sizes => _serializedMetadata.Sizes;
+
+ /// <summary>
+ /// Serialized the metadata root content into the given <see cref="BlobBuilder"/>.
+ /// </summary>
+ /// <param name="builder">Builder to write to.</param>
+ /// <param name="methodBodyStreamRva">
+ /// The relative virtual address of the start of the method body stream.
+ /// Used to calculate the final value of RVA fields of MethodDef table.
+ /// </param>
+ /// <param name="mappedFieldDataStreamRva">
+ /// The relative virtual address of the start of the field init data stream.
+ /// Used to calculate the final value of RVA fields of FieldRVA table.
+ /// </param>
+ /// <exception cref="ArgumentNullException"><paramref name="builder"/> is null.</exception>
+ /// <exception cref="ArgumentOutOfRangeException"><paramref name="methodBodyStreamRva"/> or <paramref name="mappedFieldDataStreamRva"/> is negative.</exception>
+ public void Serialize(BlobBuilder builder, int methodBodyStreamRva, int mappedFieldDataStreamRva)
+ {
+ if (builder == null)
+ {
+ Throw.ArgumentNull(nameof(builder));
+ }
+
+ if (methodBodyStreamRva < 0)
+ {
+ Throw.ArgumentOutOfRange(nameof(methodBodyStreamRva));
+ }
+
+ if (mappedFieldDataStreamRva < 0)
+ {
+ Throw.ArgumentOutOfRange(nameof(mappedFieldDataStreamRva));
+ }
+
+ // header:
+ MetadataBuilder.SerializeMetadataHeader(builder, MetadataVersion, _serializedMetadata.Sizes);
+
+ // #~ or #- stream:
+ _tablesAndHeaps.SerializeMetadataTables(builder, _serializedMetadata.Sizes, _serializedMetadata.StringMap, methodBodyStreamRva, mappedFieldDataStreamRva);
+
+ // #Strings, #US, #Guid and #Blob streams:
+ _tablesAndHeaps.WriteHeapsTo(builder, _serializedMetadata.StringHeap);
+ }
+ }
+}
+++ /dev/null
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection.PortableExecutable;
-
-namespace System.Reflection.Metadata.Ecma335
-{
- public sealed class StandaloneDebugMetadataSerializer : MetadataSerializer
- {
- private const string DebugMetadataVersionString = "PDB v1.0";
- public ushort FormatVersion => 0x0100;
-
- private Blob _pdbIdBlob;
- private readonly MethodDefinitionHandle _entryPoint;
- public Func<IEnumerable<Blob>, BlobContentId> IdProvider { get; }
-
- public StandaloneDebugMetadataSerializer(
- MetadataBuilder builder,
- ImmutableArray<int> typeSystemRowCounts,
- MethodDefinitionHandle entryPoint,
- bool isMinimalDelta,
- Func<IEnumerable<Blob>, BlobContentId> deterministicIdProvider = null)
- : base(builder, CreateSizes(builder, typeSystemRowCounts, isMinimalDelta, isStandaloneDebugMetadata: true), DebugMetadataVersionString)
- {
- _entryPoint = entryPoint;
- IdProvider = deterministicIdProvider ?? BlobContentId.GetTimeBasedProvider();
- }
-
- /// <summary>
- /// Serialized #Pdb stream.
- /// </summary>
- protected override void SerializeStandalonePdbStream(BlobBuilder builder)
- {
- int startPosition = builder.Count;
-
- // 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.Count;
- Debug.Assert(MetadataSizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition);
- }
-
- public void SerializeMetadata(BlobBuilder builder, out BlobContentId contentId)
- {
- SerializeMetadataImpl(builder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0);
-
- contentId = IdProvider(builder.GetBlobs());
-
- // fill in the id:
- var idWriter = new BlobWriter(_pdbIdBlob);
- idWriter.WriteGuid(contentId.Guid);
- idWriter.WriteUInt32(contentId.Stamp);
- Debug.Assert(idWriter.RemainingBytes == 0);
- }
- }
-
- public sealed class TypeSystemMetadataSerializer : MetadataSerializer
- {
- private static readonly ImmutableArray<int> EmptyRowCounts = ImmutableArray.CreateRange(Enumerable.Repeat(0, MetadataTokens.TableCount));
-
- public TypeSystemMetadataSerializer(
- MetadataBuilder builder,
- string metadataVersion,
- bool isMinimalDelta)
- : base(builder, CreateSizes(builder, EmptyRowCounts, isMinimalDelta, isStandaloneDebugMetadata: false), metadataVersion)
- {
-
- }
-
- protected override void SerializeStandalonePdbStream(BlobBuilder builder)
- {
- // nop
- }
-
- public void SerializeMetadata(BlobBuilder builder, int methodBodyStreamRva, int mappedFieldDataStreamRva)
- {
- SerializeMetadataImpl(builder, methodBodyStreamRva, mappedFieldDataStreamRva);
- }
- }
-
- public abstract class MetadataSerializer
- {
- protected readonly MetadataBuilder _builder;
- private readonly MetadataSizes _sizes;
- private readonly string _metadataVersion;
-
- public MetadataSerializer(MetadataBuilder builder, MetadataSizes sizes, string metadataVersion)
- {
- _builder = builder;
- _sizes = sizes;
- _metadataVersion = metadataVersion;
- }
-
- internal static MetadataSizes CreateSizes(MetadataBuilder builder, ImmutableArray<int> externalRowCounts, bool isMinimalDelta, bool isStandaloneDebugMetadata)
- {
- builder.CompleteHeaps();
-
- return new MetadataSizes(
- builder.GetRowCounts(),
- externalRowCounts,
- builder.GetHeapSizes(),
- isMinimalDelta,
- isStandaloneDebugMetadata);
- }
-
- protected abstract void SerializeStandalonePdbStream(BlobBuilder builder);
-
- public MetadataSizes MetadataSizes => _sizes;
-
- protected void SerializeMetadataImpl(BlobBuilder builder, int methodBodyStreamRva, int mappedFieldDataStreamRva)
- {
- // header:
- SerializeMetadataHeader(builder);
-
- // #Pdb stream
- SerializeStandalonePdbStream(builder);
-
- // #~ or #- stream:
- _builder.SerializeMetadataTables(builder, _sizes, methodBodyStreamRva, mappedFieldDataStreamRva);
-
- // #Strings, #US, #Guid and #Blob streams:
- _builder.WriteHeapsTo(builder);
- }
-
- private void SerializeMetadataHeader(BlobBuilder builder)
- {
- int startOffset = builder.Count;
-
- // signature
- builder.WriteUInt32(0x424A5342);
-
- // major version
- builder.WriteUInt16(1);
-
- // minor version
- builder.WriteUInt16(1);
-
- // reserved
- builder.WriteUInt32(0);
-
- // metadata version length
- builder.WriteUInt32(MetadataSizes.MetadataVersionPaddedLength);
-
- int n = Math.Min(MetadataSizes.MetadataVersionPaddedLength, _metadataVersion.Length);
- for (int i = 0; i < n; i++)
- {
- builder.WriteByte((byte)_metadataVersion[i]);
- }
-
- for (int i = n; i < MetadataSizes.MetadataVersionPaddedLength; i++)
- {
- builder.WriteByte(0);
- }
-
- // reserved
- builder.WriteUInt16(0);
-
- // number of streams
- builder.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", builder);
- }
-
- // 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 ? "#~" : "#-"), builder);
-
- SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder);
- SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder);
- SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder);
- SerializeStreamHeader(ref offsetFromStartOfMetadata, _sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder);
-
- if (_sizes.IsMinimalDelta)
- {
- SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder);
- }
-
- int endOffset = builder.Count;
- Debug.Assert(endOffset - startOffset == _sizes.MetadataHeaderSize);
- }
-
- private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BlobBuilder builder)
- {
- // 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);
- builder.WriteInt32(offsetFromStartOfMetadata);
- builder.WriteInt32(alignedStreamSize);
- foreach (char ch in streamName)
- {
- builder.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++)
- {
- builder.WriteByte(0);
- }
-
- offsetFromStartOfMetadata += alignedStreamSize;
- }
- }
-}
namespace System.Reflection.Metadata.Ecma335
{
+ /// <summary>
+ /// Provides information on sizes of various metadata structures.
+ /// </summary>
public sealed class MetadataSizes
{
private const int StreamAlignment = 4;
+ // Call the length of the string (including the terminator) m (we require m <= 255);
+ internal const int MaxMetadataVersionByteCount = 0xff - 1;
+
+ internal readonly int MetadataVersionPaddedLength;
+
internal const ulong SortedDebugTables =
1UL << (int)TableIndex.LocalScope |
1UL << (int)TableIndex.StateMachineMethod |
1UL << (int)TableIndex.CustomDebugInformation;
- internal readonly bool IsMinimalDelta;
-
- // EnC delta tables are stored as uncompressed metadata table stream
- internal bool IsMetadataTableStreamCompressed => !IsMinimalDelta;
+ internal readonly bool IsEncDelta;
+ internal readonly bool IsCompressed;
internal readonly bool BlobReferenceIsSmall;
internal readonly bool StringReferenceIsSmall;
ImmutableArray<int> rowCounts,
ImmutableArray<int> externalRowCounts,
ImmutableArray<int> heapSizes,
- bool isMinimalDelta,
+ int metadataVersionByteCount,
bool isStandaloneDebugMetadata)
{
Debug.Assert(rowCounts.Length == MetadataTokens.TableCount);
RowCounts = rowCounts;
ExternalRowCounts = externalRowCounts;
HeapSizes = heapSizes;
- IsMinimalDelta = isMinimalDelta;
- BlobReferenceIsSmall = !isMinimalDelta && heapSizes[(int)HeapIndex.Blob] <= ushort.MaxValue;
- StringReferenceIsSmall = !isMinimalDelta && heapSizes[(int)HeapIndex.String] <= ushort.MaxValue;
- GuidReferenceIsSmall = !isMinimalDelta && heapSizes[(int)HeapIndex.Guid] <= ushort.MaxValue;
+ // +1 for NUL terminator
+ MetadataVersionPaddedLength = BitArithmetic.Align(metadataVersionByteCount + 1, 4);
PresentTablesMask = ComputeNonEmptyTableMask(rowCounts);
ExternalTablesMask = ComputeNonEmptyTableMask(externalRowCounts);
+ // Auto-detect EnC delta from presence of EnC tables.
+ // EnC delta tables are stored as uncompressed metadata table stream, other metadata use compressed stream.
+ // We could support uncompress non-EnC metadata in future if we needed to.
+ bool isEncDelta = IsPresent(TableIndex.EncLog) || IsPresent(TableIndex.EncMap);
+ bool isCompressed = !isEncDelta;
+
+ IsEncDelta = isEncDelta;
+ IsCompressed = isCompressed;
+
+ BlobReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.Blob] <= ushort.MaxValue;
+ StringReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.String] <= ushort.MaxValue;
+ GuidReferenceIsSmall = isCompressed && heapSizes[(int)HeapIndex.Guid] <= ushort.MaxValue;
+
// table can either be present or external, it can't be both:
Debug.Assert((PresentTablesMask & ExternalTablesMask) == 0);
get
{
const int RegularStreamHeaderSizes = 76;
- const int MinimalDeltaMarkerStreamHeaderSize = 16;
+ const int EncDeltaMarkerStreamHeaderSize = 16;
const int StandalonePdbStreamHeaderSize = 16;
Debug.Assert(RegularStreamHeaderSizes ==
GetMetadataStreamHeaderSize("#GUID") +
GetMetadataStreamHeaderSize("#Blob"));
- Debug.Assert(MinimalDeltaMarkerStreamHeaderSize == GetMetadataStreamHeaderSize("#JTD"));
+ Debug.Assert(EncDeltaMarkerStreamHeaderSize == GetMetadataStreamHeaderSize("#JTD"));
Debug.Assert(StandalonePdbStreamHeaderSize == GetMetadataStreamHeaderSize("#Pdb"));
return
sizeof(ushort) + // stream count
(IsStandaloneDebugMetadata ? StandalonePdbStreamHeaderSize : 0) +
RegularStreamHeaderSizes +
- (IsMinimalDelta ? MinimalDeltaMarkerStreamHeaderSize : 0);
+ (IsEncDelta ? EncDeltaMarkerStreamHeaderSize : 0);
}
}
- // version must be 12 chars long, this observation is not supported by the standard
- internal const int MetadataVersionPaddedLength = 12;
-
internal static int GetMetadataStreamHeaderSize(string streamName)
{
return
private bool IsReferenceSmall(int tagBitSize, params TableIndex[] tables)
{
const int smallBitCount = 16;
- return IsMetadataTableStreamCompressed && ReferenceFits(smallBitCount - tagBitSize, tables);
+ return IsCompressed && ReferenceFits(smallBitCount - tagBitSize, tables);
}
private bool ReferenceFits(int bitCount, TableIndex[] tables)
/// <summary>
/// Maximum number of tables that can be present in Ecma335 metadata.
/// </summary>
- public static readonly int TableCount = TableIndexExtensions.Count;
+ public static readonly int TableCount = 64; // headers use 64bit table masks
/// <summary>
/// Maximum number of tables that can be present in Ecma335 metadata.
/// </summary>
/// <param name="type">Handle type.</param>
/// <param name="index">Table index.</param>
- /// <returns>True if the handle type corresponds to an Ecma335 table, false otherwise.</returns>
+ /// <returns>True if the handle type corresponds to an Ecma335 or Portable PDB table, false otherwise.</returns>
public static bool TryGetTableIndex(HandleKind type, out TableIndex index)
{
- if ((int)type < TableIndexExtensions.Count)
+ // We don't have a HandleKind for PropertyMap, EventMap, MethodSemantics, *Ptr, AssemblyOS, etc. tables,
+ // but one can get ahold of one by creating a handle from a token and getting its Kind.
+ if ((int)type < TableCount && ((1UL << (int)type) & (ulong)TableMask.AllTables) != 0)
{
index = (TableIndex)type;
return true;
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Linq;
+
+namespace System.Reflection.Metadata.Ecma335
+{
+ /// <summary>
+ /// Builder of a Portable PDB image.
+ /// </summary>
+ public sealed class PortablePdbBuilder
+ {
+ public string MetadataVersion => "PDB v1.0";
+ public ushort FormatVersion => 0x0100;
+
+ private Blob _pdbIdBlob;
+ private readonly MethodDefinitionHandle _entryPoint;
+ private readonly MetadataBuilder _builder;
+ private readonly SerializedMetadata _serializedMetadata;
+
+ public Func<IEnumerable<Blob>, BlobContentId> IdProvider { get; }
+
+ /// <summary>
+ /// Creates a builder of a Portable PDB image.
+ /// </summary>
+ /// <param name="tablesAndHeaps">
+ /// Builder populated with debug metadata entities stored in tables and values stored in heaps.
+ /// The entities and values will be enumerated when serializing the Portable PDB image.
+ /// </param>
+ /// <param name="typeSystemRowCounts">
+ /// Row counts of all tables that the associated type-system metadata contain.
+ /// Each slot in the array corresponds to a table (<see cref="TableIndex"/>).
+ /// The length of the array must be equal to <see cref="MetadataTokens.TableCount"/>.
+ /// </param>
+ /// <param name="entryPoint">
+ /// Entry point method definition handle.
+ /// </param>
+ /// <param name="idProvider">
+ /// Function calculating id of content represented as a sequence of blobs.
+ /// If not specified a default function that ignores the content and returns current time-based content id is used
+ /// (<see cref="BlobContentId.GetTimeBasedProvider()"/>).
+ /// You must specify a deterministic function to produce a deterministic Portable PDB image.
+ /// </param>
+ /// <exception cref="ArgumentNullException"><paramref name="tablesAndHeaps"/> or <paramref name="typeSystemRowCounts"/> is null.</exception>
+ public PortablePdbBuilder(
+ MetadataBuilder tablesAndHeaps,
+ ImmutableArray<int> typeSystemRowCounts,
+ MethodDefinitionHandle entryPoint,
+ Func<IEnumerable<Blob>, BlobContentId> idProvider = null)
+ {
+ if (tablesAndHeaps == null)
+ {
+ Throw.ArgumentNull(nameof(tablesAndHeaps));
+ }
+
+ ValidateTypeSystemRowCounts(typeSystemRowCounts);
+
+ _builder = tablesAndHeaps;
+ _entryPoint = entryPoint;
+
+ Debug.Assert(BlobUtilities.GetUTF8ByteCount(MetadataVersion) == MetadataVersion.Length);
+ _serializedMetadata = tablesAndHeaps.GetSerializedMetadata(typeSystemRowCounts, MetadataVersion.Length, isStandaloneDebugMetadata: true);
+
+ IdProvider = idProvider ?? BlobContentId.GetTimeBasedProvider();
+ }
+
+ private static void ValidateTypeSystemRowCounts(ImmutableArray<int> typeSystemRowCounts)
+ {
+ if (typeSystemRowCounts.IsDefault)
+ {
+ Throw.ArgumentNull(nameof(typeSystemRowCounts));
+ }
+
+ if (typeSystemRowCounts.Length != MetadataTokens.TableCount)
+ {
+ throw new ArgumentException(SR.Format(SR.ExpectedArrayOfSize, MetadataTokens.TableCount), nameof(typeSystemRowCounts));
+ }
+
+ for (int i = 0; i < typeSystemRowCounts.Length; i++)
+ {
+ if (typeSystemRowCounts[i] == 0)
+ {
+ continue;
+ }
+
+ if ((unchecked((uint)typeSystemRowCounts[i]) & ~TokenTypeIds.RIDMask) != 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(typeSystemRowCounts), SR.Format(SR.RowCountOutOfRange, i));
+ }
+
+ if (((1UL << i) & (ulong)TableMask.ValidPortablePdbExternalTables) == 0)
+ {
+ throw new ArgumentException(SR.Format(SR.RowCountMustBeZero, i), nameof(typeSystemRowCounts));
+ }
+ }
+ }
+
+ /// <summary>
+ /// Serialized #Pdb stream.
+ /// </summary>
+ private void SerializeStandalonePdbStream(BlobBuilder builder)
+ {
+ int startPosition = builder.Count;
+
+ // the id will be filled in later
+ _pdbIdBlob = builder.ReserveBytes(MetadataSizes.PdbIdSize);
+
+ builder.WriteInt32(_entryPoint.IsNil ? 0 : MetadataTokens.GetToken(_entryPoint));
+
+ builder.WriteUInt64(_serializedMetadata.Sizes.ExternalTablesMask);
+ MetadataWriterUtilities.SerializeRowCounts(builder, _serializedMetadata.Sizes.ExternalRowCounts);
+
+ int endPosition = builder.Count;
+ Debug.Assert(_serializedMetadata.Sizes.CalculateStandalonePdbStreamSize() == endPosition - startPosition);
+ }
+
+ /// <summary>
+ /// Serializes Portable PDB content into the given <see cref="BlobBuilder"/>.
+ /// </summary>
+ /// <param name="builder">Builder to write to.</param>
+ /// <returns>The id of the serialized content.</returns>
+ /// <exception cref="ArgumentNullException"><paramref name="builder"/> is null.</exception>
+ public BlobContentId Serialize(BlobBuilder builder)
+ {
+ if (builder == null)
+ {
+ Throw.ArgumentNull(nameof(builder));
+ }
+
+ // header:
+ MetadataBuilder.SerializeMetadataHeader(builder, MetadataVersion, _serializedMetadata.Sizes);
+
+ // #Pdb stream
+ SerializeStandalonePdbStream(builder);
+
+ // #~ or #- stream:
+ _builder.SerializeMetadataTables(builder, _serializedMetadata.Sizes, _serializedMetadata.StringMap, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0);
+
+ // #Strings, #US, #Guid and #Blob streams:
+ _builder.WriteHeapsTo(builder, _serializedMetadata.StringHeap);
+
+ var contentId = IdProvider(builder.GetBlobs());
+
+ // fill in the id:
+ var idWriter = new BlobWriter(_pdbIdBlob);
+ idWriter.WriteGuid(contentId.Guid);
+ idWriter.WriteUInt32(contentId.Stamp);
+ Debug.Assert(idWriter.RemainingBytes == 0);
+
+ return contentId;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+
+namespace System.Reflection.Metadata.Ecma335
+{
+ internal sealed class SerializedMetadata
+ {
+ internal readonly ImmutableArray<int> StringMap;
+ internal readonly BlobBuilder StringHeap;
+ internal readonly MetadataSizes Sizes;
+
+ public SerializedMetadata(
+ MetadataSizes sizes,
+ BlobBuilder stringHeap,
+ ImmutableArray<int> stringMap)
+ {
+ Sizes = sizes;
+ StringHeap = stringHeap;
+ StringMap = stringMap;
+ }
+ }
+}
StateMachineMethod = 0x36,
CustomDebugInformation = 0x37,
}
-
- internal static class TableIndexExtensions
- {
- internal const int Count = (int)TableIndex.CustomDebugInformation + 1;
- }
}
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
+ EncDeltas = 0x20, // Indicates only EnC Deltas are present
DeletedMarks = 0x80, // Indicates metadata might contain items marked deleted
}
}
| EventPtr
| PropertyPtr,
- V2_0_TablesMask =
- Module
+ EncTables =
+ EnCLog
+ | EnCMap,
+
+ TypeSystemTables =
+ PtrTables
+ | EncTables
+ | Module
| TypeRef
| TypeDef
- | FieldPtr
| Field
- | MethodPtr
| MethodDef
- | ParamPtr
| Param
| InterfaceImpl
| MemberRef
| FieldLayout
| StandAloneSig
| EventMap
- | EventPtr
| Event
| PropertyMap
- | PropertyPtr
| Property
| MethodSemantics
| MethodImpl
| TypeSpec
| ImplMap
| FieldRva
- | EnCLog
- | EnCMap
| Assembly
| AssemblyRef
| File
| MethodSpec
| GenericParamConstraint,
- PortablePdb_TablesMask =
+ DebugTables =
Document
| MethodDebugInformation
| LocalScope
| StateMachineMethod
| CustomDebugInformation,
- V3_0_TablesMask =
- V2_0_TablesMask
- | PortablePdb_TablesMask,
+ AllTables =
+ TypeSystemTables |
+ DebugTables,
+
+ ValidPortablePdbExternalTables =
+ TypeSystemTables & ~PtrTables & ~EncTables
}
internal enum HeapSizes : byte
// We will not be checking version values. We will continue checking that the set of
// present tables is within the set we understand.
- ulong validTables = (ulong)TableMask.V3_0_TablesMask;
+ ulong validTables = (ulong)(TableMask.TypeSystemTables | TableMask.DebugTables);
if ((presentTables & ~validTables) != 0)
{
{
ulong currentTableBit = 1;
- var rowCounts = new int[TableIndexExtensions.Count];
+ var rowCounts = new int[MetadataTokens.TableCount];
for (int i = 0; i < rowCounts.Length; i++)
{
if ((presentTableMask & currentTableBit) != 0)
ulong externalTableMask = reader.ReadUInt64();
// EnC & Ptr tables can't be referenced from standalone PDB metadata:
- const ulong validTables = (ulong)(TableMask.V2_0_TablesMask & ~TableMask.PtrTables & ~TableMask.EnCLog & ~TableMask.EnCMap);
+ const ulong validTables = (ulong)TableMask.ValidPortablePdbExternalTables;
if ((externalTableMask & ~validTables) != 0)
{
bool isAllReferencedTablesSmall = true;
ulong tablesReferencedMask = (ulong)tablesReferenced;
- for (int tableIndex = 0; tableIndex < TableIndexExtensions.Count; tableIndex++)
+ for (int tableIndex = 0; tableIndex < MetadataTokens.TableCount; tableIndex++)
{
if ((tablesReferencedMask & 1) != 0)
{
private const string RelocationSectionName = ".reloc";
private readonly PEDirectoriesBuilder _peDirectoriesBuilder;
- private readonly TypeSystemMetadataSerializer _metadataSerializer;
+ private readonly MetadataRootBuilder _metadataRootBuilder;
private readonly BlobBuilder _ilStream;
private readonly BlobBuilder _mappedFieldDataOpt;
private readonly BlobBuilder _managedResourcesOpt;
public ManagedPEBuilder(
PEHeaderBuilder header,
- TypeSystemMetadataSerializer metadataSerializer,
+ MetadataRootBuilder metadataRootBuilder,
BlobBuilder ilStream,
BlobBuilder mappedFieldData = null,
BlobBuilder managedResources = null,
Throw.ArgumentNull(nameof(header));
}
- if (metadataSerializer == null)
+ if (metadataRootBuilder == null)
{
- Throw.ArgumentNull(nameof(metadataSerializer));
+ Throw.ArgumentNull(nameof(metadataRootBuilder));
}
if (ilStream == null)
Throw.ArgumentOutOfRange(nameof(strongNameSignatureSize));
}
- _metadataSerializer = metadataSerializer;
+ _metadataRootBuilder = metadataRootBuilder;
_ilStream = ilStream;
_mappedFieldDataOpt = mappedFieldData;
_managedResourcesOpt = managedResources;
var sectionBuilder = new BlobBuilder();
var metadataBuilder = new BlobBuilder();
- var metadataSizes = _metadataSerializer.MetadataSizes;
+ var metadataSizes = _metadataRootBuilder.Sizes;
var textSection = new ManagedTextSection(
imageCharacteristics: Header.ImageCharacteristics,
int methodBodyStreamRva = location.RelativeVirtualAddress + textSection.OffsetToILStream;
int mappedFieldDataStreamRva = location.RelativeVirtualAddress + textSection.CalculateOffsetToMappedFieldDataStream();
- _metadataSerializer.SerializeMetadata(metadataBuilder, methodBodyStreamRva, mappedFieldDataStreamRva);
+ _metadataRootBuilder.Serialize(metadataBuilder, methodBodyStreamRva, mappedFieldDataStreamRva);
DirectoryEntry debugDirectoryEntry;
BlobBuilder debugTableBuilderOpt;
}
[MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void InvalidArgument(string message, string parameterName)
+ {
+ throw new ArgumentException(message, parameterName);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
internal static void InvalidArgument_OffsetForVirtualHeapHandle()
{
throw new ArgumentException(SR.CantGetOffsetForVirtualHeapHandle, "handle");
var builder = new MetadataBuilder();
builder.AddModule(default(int), default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Module]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Module));
builder.AddAssembly(default(StringHandle), new Version(0, 0, 0, 0), default(StringHandle), default(BlobHandle), default(AssemblyFlags), default(AssemblyHashAlgorithm));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Assembly]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Assembly));
var assemblyReference = builder.AddAssemblyReference(default(StringHandle), new Version(0, 0, 0, 0), default(StringHandle), default(BlobHandle), default(AssemblyFlags), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.AssemblyRef]);
+ Assert.Equal(1, builder.GetRowCount(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, builder.GetRowCount(TableIndex.TypeDef));
Assert.Equal(1, MetadataTokens.GetRowNumber(typeDefinition));
builder.AddTypeLayout(default(TypeDefinitionHandle), default(ushort), default(uint));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ClassLayout]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.ClassLayout));
builder.AddInterfaceImplementation(MetadataTokens.TypeDefinitionHandle(1), MetadataTokens.TypeDefinitionHandle(1));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.InterfaceImpl]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.InterfaceImpl));
builder.AddNestedType(default(TypeDefinitionHandle), default(TypeDefinitionHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.NestedClass]);
+ Assert.Equal(1, builder.GetRowCount(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]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.TypeRef));
builder.AddTypeSpecification(default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.TypeSpec]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.TypeSpec));
builder.AddStandaloneSignature(default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.StandAloneSig]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.StandAloneSig));
builder.AddProperty(default(PropertyAttributes), default(StringHandle), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Property]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Property));
builder.AddPropertyMap(default(TypeDefinitionHandle), default(PropertyDefinitionHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.PropertyMap]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.PropertyMap));
builder.AddEvent(default(EventAttributes), default(StringHandle), MetadataTokens.TypeDefinitionHandle(1));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Event]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Event));
builder.AddEventMap(default(TypeDefinitionHandle), default(EventDefinitionHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.EventMap]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.EventMap));
builder.AddConstant(MetadataTokens.FieldDefinitionHandle(1), default(object));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Constant]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Constant));
builder.AddMethodSemantics(MetadataTokens.EventDefinitionHandle(1), default(ushort), default(MethodDefinitionHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodSemantics]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.MethodSemantics));
builder.AddCustomAttribute(MetadataTokens.TypeDefinitionHandle(1), MetadataTokens.MethodDefinitionHandle(1), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.CustomAttribute]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.CustomAttribute));
builder.AddMethodSpecification(MetadataTokens.MethodDefinitionHandle(1), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodSpec]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.MethodSpec));
builder.AddModuleReference(default(StringHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ModuleRef]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.ModuleRef));
builder.AddParameter(default(ParameterAttributes), default(StringHandle), default(int));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Param]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Param));
var genericParameter = builder.AddGenericParameter(MetadataTokens.MethodDefinitionHandle(1), default(GenericParameterAttributes), default(StringHandle), default(int));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.GenericParam]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.GenericParam));
Assert.Equal(1, MetadataTokens.GetRowNumber(genericParameter));
builder.AddGenericParameterConstraint(default(GenericParameterHandle), MetadataTokens.TypeDefinitionHandle(1));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.GenericParamConstraint]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.GenericParamConstraint));
builder.AddFieldDefinition(default(FieldAttributes), default(StringHandle), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.Field]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.Field));
builder.AddFieldLayout(default(FieldDefinitionHandle), default(int));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.FieldLayout]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.FieldLayout));
builder.AddMarshallingDescriptor(MetadataTokens.FieldDefinitionHandle(1), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.FieldMarshal]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.FieldMarshal));
builder.AddFieldRelativeVirtualAddress(default(FieldDefinitionHandle), default(int));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.FieldRva]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.FieldRva));
var methodDefinition = builder.AddMethodDefinition(default(MethodAttributes), default(MethodImplAttributes), default(StringHandle), default(BlobHandle), default(int), default(ParameterHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodDef]);
+ Assert.Equal(1, builder.GetRowCount(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]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.ImplMap));
builder.AddMethodImplementation(default(TypeDefinitionHandle), MetadataTokens.MethodDefinitionHandle(1), MetadataTokens.MethodDefinitionHandle(1));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodImpl]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.MethodImpl));
var memberReference = builder.AddMemberReference(MetadataTokens.TypeDefinitionHandle(1), default(StringHandle), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MemberRef]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.MemberRef));
Assert.Equal(1, MetadataTokens.GetRowNumber(memberReference));
builder.AddManifestResource(default(ManifestResourceAttributes), default(StringHandle), MetadataTokens.AssemblyFileHandle(1), default(uint));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ManifestResource]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.ManifestResource));
builder.AddAssemblyFile(default(StringHandle), default(BlobHandle), default(Boolean));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.File]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.File));
builder.AddExportedType(default(TypeAttributes), default(StringHandle), default(StringHandle), MetadataTokens.AssemblyFileHandle(1), default(int));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.ExportedType]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.ExportedType));
builder.AddDeclarativeSecurityAttribute(MetadataTokens.TypeDefinitionHandle(1), default(DeclarativeSecurityAction), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.DeclSecurity]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.DeclSecurity));
builder.AddEncLogEntry(MetadataTokens.TypeDefinitionHandle(1), default(EditAndContinueOperation));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.EncLog]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.EncLog));
builder.AddEncMapEntry(MetadataTokens.TypeDefinitionHandle(1));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.EncMap]);
+ Assert.Equal(1, builder.GetRowCount(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, builder.GetRowCount(TableIndex.Document));
Assert.Equal(1, MetadataTokens.GetRowNumber(document));
builder.AddMethodDebugInformation(default(DocumentHandle), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.MethodDebugInformation]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.MethodDebugInformation));
var localScope = builder.AddLocalScope(default(MethodDefinitionHandle), default(ImportScopeHandle), default(LocalVariableHandle), default(LocalConstantHandle), default(int), default(int));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.LocalScope]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.LocalScope));
Assert.Equal(1, MetadataTokens.GetRowNumber(localScope));
var localVariable = builder.AddLocalVariable(default(LocalVariableAttributes), default(int), default(StringHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.LocalVariable]);
+ Assert.Equal(1, builder.GetRowCount(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, builder.GetRowCount(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, builder.GetRowCount(TableIndex.ImportScope));
Assert.Equal(1, MetadataTokens.GetRowNumber(importScope));
builder.AddStateMachineMethod(default(MethodDefinitionHandle), default(MethodDefinitionHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.StateMachineMethod]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.StateMachineMethod));
builder.AddCustomDebugInformation(default(EntityHandle), default(GuidHandle), default(BlobHandle));
- Assert.Equal(1, builder.GetRowCounts()[(int)TableIndex.CustomDebugInformation]);
+ Assert.Equal(1, builder.GetRowCount(TableIndex.CustomDebugInformation));
+
+ Assert.Equal(0, builder.GetRowCount(TableIndex.AssemblyOS));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.AssemblyProcessor));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.AssemblyRefOS));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.AssemblyRefProcessor));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.EventPtr));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.FieldPtr));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.MethodPtr));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.ParamPtr));
+ Assert.Equal(0, builder.GetRowCount(TableIndex.PropertyPtr));
+
+ var rowCounts = builder.GetRowCounts();
+ Assert.Equal(MetadataTokens.TableCount, rowCounts.Length);
+ foreach (TableIndex tableIndex in Enum.GetValues(typeof(TableIndex)))
+ {
+ Assert.Equal(builder.GetRowCount(tableIndex), rowCounts[(int)tableIndex]);
+ }
+ }
+
+ [Fact]
+ public void GetRowCount_Errors()
+ {
+ var builder = new MetadataBuilder();
+ Assert.Throws<ArgumentOutOfRangeException>(() => builder.GetRowCount((TableIndex)0x2D));
+ Assert.Throws<ArgumentOutOfRangeException>(() => builder.GetRowCount((TableIndex)0x2E));
+ Assert.Throws<ArgumentOutOfRangeException>(() => builder.GetRowCount((TableIndex)0x2F));
+ Assert.Throws<ArgumentOutOfRangeException>(() => builder.GetRowCount((TableIndex)0x38));
+ Assert.Throws<ArgumentOutOfRangeException>(() => builder.GetRowCount((TableIndex)0x39));
+ Assert.Throws<ArgumentOutOfRangeException>(() => builder.GetRowCount((TableIndex)255));
}
/// <summary>
public void Heaps_Empty()
{
var mdBuilder = new MetadataBuilder();
- mdBuilder.CompleteHeaps();
+ var serialized = mdBuilder.GetSerializedMetadata(MetadataRootBuilder.EmptyRowCounts, 12, isStandaloneDebugMetadata: false);
var builder = new BlobBuilder();
- mdBuilder.WriteHeapsTo(builder);
+ mdBuilder.WriteHeapsTo(builder, serialized.StringHeap);
AssertEx.Equal(new byte[]
{
var b1 = mdBuilder.GetOrAddBlob(new byte[] { 1, 2 });
Assert.Equal(1, b1.GetHeapOffset());
- mdBuilder.CompleteHeaps();
+ var serialized = mdBuilder.GetSerializedMetadata(MetadataRootBuilder.EmptyRowCounts, 12, isStandaloneDebugMetadata: false);
Assert.Equal(0, mdBuilder.SerializeHandle(g0));
Assert.Equal(1, mdBuilder.SerializeHandle(g1));
- Assert.Equal(0, mdBuilder.SerializeHandle(s0));
- Assert.Equal(1, mdBuilder.SerializeHandle(s1));
+ Assert.Equal(0, mdBuilder.SerializeHandle(serialized.StringMap, s0));
+ Assert.Equal(1, mdBuilder.SerializeHandle(serialized.StringMap, s1));
Assert.Equal(1, mdBuilder.SerializeHandle(us0));
Assert.Equal(3, mdBuilder.SerializeHandle(us1));
Assert.Equal(0, mdBuilder.SerializeHandle(b0));
Assert.Equal(1, mdBuilder.SerializeHandle(b1));
var heaps = new BlobBuilder();
- mdBuilder.WriteHeapsTo(heaps);
+ mdBuilder.WriteHeapsTo(heaps, serialized.StringHeap);
AssertEx.Equal(new byte[]
{
var b1 = mdBuilder.GetOrAddBlob(new byte[] { 1, 2 });
Assert.Equal(0x31, b1.GetHeapOffset());
- mdBuilder.CompleteHeaps();
+ var serialized = mdBuilder.GetSerializedMetadata(MetadataRootBuilder.EmptyRowCounts, 12, isStandaloneDebugMetadata: false);
Assert.Equal(5, mdBuilder.SerializeHandle(g));
- Assert.Equal(0, mdBuilder.SerializeHandle(s0));
- Assert.Equal(0x21, mdBuilder.SerializeHandle(s1));
+ Assert.Equal(0, mdBuilder.SerializeHandle(serialized.StringMap, s0));
+ Assert.Equal(0x21, mdBuilder.SerializeHandle(serialized.StringMap, s1));
Assert.Equal(0x11, mdBuilder.SerializeHandle(us0));
Assert.Equal(0x13, mdBuilder.SerializeHandle(us1));
Assert.Equal(0, mdBuilder.SerializeHandle(b0));
Assert.Equal(0x31, mdBuilder.SerializeHandle(b1));
var heaps = new BlobBuilder();
- mdBuilder.WriteHeapsTo(heaps);
+ mdBuilder.WriteHeapsTo(heaps, serialized.StringHeap);
AssertEx.Equal(new byte[]
{
Assert.Equal(MetadataTokens.GuidHandle(1), mdBuilder.ReserveGuid(out guidFixup));
Assert.Equal(MetadataTokens.UserStringHandle(1), mdBuilder.ReserveUserString(3, out usFixup));
- mdBuilder.CompleteHeaps();
+ var serialized = mdBuilder.GetSerializedMetadata(MetadataRootBuilder.EmptyRowCounts, 12, isStandaloneDebugMetadata: false);
var builder = new BlobBuilder();
- mdBuilder.WriteHeapsTo(builder);
+ mdBuilder.WriteHeapsTo(builder, serialized.StringHeap);
AssertEx.Equal(new byte[]
{
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Reflection.Metadata.Tests;
+using Xunit;
+
+namespace System.Reflection.Metadata.Ecma335.Tests
+{
+ public class MetadataRootBuilderTests
+ {
+ private string ReadVersion(BlobBuilder metadata)
+ {
+ using (var provider = MetadataReaderProvider.FromMetadataImage(metadata.ToImmutableArray()))
+ {
+ return provider.GetMetadataReader().MetadataVersion;
+ }
+ }
+
+ [Fact]
+ public void Ctor_Errors()
+ {
+ var mdBuilder = new MetadataBuilder();
+
+ Assert.Throws<ArgumentNullException>(() => new MetadataRootBuilder(null));
+ Assert.Throws<ArgumentException>(() => new MetadataRootBuilder(mdBuilder, new string('x', 255)));
+ }
+
+ [Fact]
+ public void Serialize_Errors()
+ {
+ var mdBuilder = new MetadataBuilder();
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
+ var builder = new BlobBuilder();
+
+ Assert.Throws<ArgumentNullException>(() => rootBuilder.Serialize(null, 0, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => rootBuilder.Serialize(builder, -1, 0));
+ Assert.Throws<ArgumentOutOfRangeException>(() => rootBuilder.Serialize(builder, 0, -1));
+ }
+
+ [Fact]
+ public void Headers()
+ {
+ var mdBuilder = new MetadataBuilder();
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
+
+ var builder = new BlobBuilder();
+ rootBuilder.Serialize(builder, 0, 0);
+
+ AssertEx.Equal(new byte[]
+ {
+ // signature:
+ 0x42, 0x53, 0x4A, 0x42,
+ // major version (1)
+ 0x01, 0x00,
+ // minor version (1)
+ 0x01, 0x00,
+ // reserved (0)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // padded version length:
+ 0x0C, 0x00, 0x00, 0x00,
+
+ // padded version:
+ (byte)'v', (byte)'4', (byte)'.', (byte)'0', (byte)'.', (byte)'3', (byte)'0', (byte)'3', (byte)'1', (byte)'9', 0x00, 0x00,
+
+ // flags (0):
+ 0x00, 0x00,
+
+ // stream count:
+ 0x05, 0x00,
+
+ // stream headers:
+ 0x6C, 0x00, 0x00, 0x00,
+ 0x1C, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'~', 0x00, 0x00,
+
+ 0x88, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'S', (byte)'t', (byte)'r', (byte)'i', (byte)'n', (byte)'g', (byte)'s', 0x00, 0x00, 0x00, 0x00,
+
+ 0x8C, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'U', (byte)'S', 0x00,
+
+ 0x90, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'G', (byte)'U', (byte)'I', (byte)'D', 0x00, 0x00, 0x00,
+
+ 0x90, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'B', (byte)'l', (byte)'o', (byte)'b', 0x00, 0x00, 0x00,
+
+ // --------
+ // #~
+ // --------
+
+ // Reserved (0)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // Major Version (2)
+ 0x02,
+
+ // Minor Version (0)
+ 0x00,
+
+ // Heap Sizes
+ 0x00,
+
+ // Reserved (1)
+ 0x01,
+
+ // Present tables
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // Sorted tables
+ 0x00, 0xFA, 0x01, 0x33, 0x00, 0x16, 0x00, 0x00,
+
+ // Rows (empty)
+ // Tables (empty)
+
+ // Padding and alignment
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #Strings
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #US
+ // --------
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #GUID
+ // --------
+
+ // --------
+ // #Blob
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+ }, builder.ToArray());
+ }
+
+ [Fact]
+ public void EncHeaders()
+ {
+ var mdBuilder = new MetadataBuilder();
+ mdBuilder.AddEncLogEntry(MetadataTokens.MethodDefinitionHandle(1), EditAndContinueOperation.AddMethod);
+
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
+
+ var builder = new BlobBuilder();
+ rootBuilder.Serialize(builder, 0, 0);
+
+ AssertEx.Equal(new byte[]
+ {
+ // signature:
+ 0x42, 0x53, 0x4A, 0x42,
+ // major version (1)
+ 0x01, 0x00,
+ // minor version (1)
+ 0x01, 0x00,
+ // reserved (0)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // padded version length:
+ 0x0C, 0x00, 0x00, 0x00,
+
+ // padded version:
+ (byte)'v', (byte)'4', (byte)'.', (byte)'0', (byte)'.', (byte)'3', (byte)'0', (byte)'3', (byte)'1', (byte)'9', 0x00, 0x00,
+
+ // flags (0):
+ 0x00, 0x00,
+
+ // stream count:
+ 0x06, 0x00,
+
+ // stream headers:
+ 0x7C, 0x00, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'-', 0x00, 0x00,
+
+ 0xA4, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'S', (byte)'t', (byte)'r', (byte)'i', (byte)'n', (byte)'g', (byte)'s', 0x00, 0x00, 0x00, 0x00,
+
+ 0xA8, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'U', (byte)'S', 0x00,
+
+ 0xAC, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'G', (byte)'U', (byte)'I', (byte)'D', 0x00, 0x00, 0x00,
+
+ 0xAC, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'B', (byte)'l', (byte)'o', (byte)'b', 0x00, 0x00, 0x00,
+
+ 0xB0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'J', (byte)'T', (byte)'D', 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #-
+ // --------
+
+ // Reserved (0)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // Major Version (2)
+ 0x02,
+
+ // Minor Version (0)
+ 0x00,
+
+ // Heap Sizes
+ 0xA7,
+
+ // Reserved (1)
+ 0x01,
+
+ // Present tables
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00,
+
+ // Sorted tables
+ 0x00, 0xFA, 0x01, 0x33, 0x00, 0x16, 0x00, 0x00,
+
+ // Rows
+ 0x01, 0x00, 0x00, 0x00,
+
+ //
+ // EncLog Table (token, operation)
+ //
+
+ 0x01, 0x00, 0x00, 0x06,
+ 0x01, 0x00, 0x00, 0x00,
+
+ // Padding and alignment
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #Strings
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #US
+ // --------
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #GUID
+ // --------
+
+ // --------
+ // #Blob
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #JTD
+ // --------
+ }, builder.ToArray());
+ }
+
+ [Fact]
+ public void MetadataVersion_Default()
+ {
+ var mdBuilder = new MetadataBuilder();
+ mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
+
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
+
+ var builder = new BlobBuilder();
+ rootBuilder.Serialize(builder, 0, 0);
+
+ AssertEx.Equal(new byte[]
+ {
+ // padded version length:
+ 0x0C, 0x00, 0x00, 0x00,
+
+ // padded version:
+ (byte)'v', (byte)'4', (byte)'.', (byte)'0', (byte)'.', (byte)'3', (byte)'0', (byte)'3', (byte)'1', (byte)'9', 0x00, 0x00,
+ }, builder.Slice(12, -132));
+
+ Assert.Equal(rootBuilder.MetadataVersion, ReadVersion(builder));
+ }
+
+ [Fact]
+ public void MetadataVersion_Empty()
+ {
+ var version = "";
+
+ var mdBuilder = new MetadataBuilder();
+ mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
+
+ var rootBuilder = new MetadataRootBuilder(mdBuilder, version);
+
+ var builder = new BlobBuilder();
+ rootBuilder.Serialize(builder, 0, 0);
+
+ AssertEx.Equal(new byte[]
+ {
+ // padded version length:
+ 0x04, 0x00, 0x00, 0x00,
+
+ // padded version:
+ 0x00, 0x00, 0x00, 0x00,
+ }, builder.Slice(12, -132));
+
+ Assert.Equal(version, ReadVersion(builder));
+ }
+
+ [Fact]
+ public void MetadataVersion_MaxLength()
+ {
+ var version = new string('x', 254);
+
+ var mdBuilder = new MetadataBuilder();
+ mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
+
+ var rootBuilder = new MetadataRootBuilder(mdBuilder, version);
+
+ var builder = new BlobBuilder();
+ rootBuilder.Serialize(builder, 0, 0);
+
+ AssertEx.Equal(new byte[]
+ {
+ // padded version length:
+ 0x00, 0x01, 0x00, 0x00,
+
+ // padded version:
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x00, 0x00
+ }, builder.Slice(12, -132));
+
+ Assert.Equal(version, ReadVersion(builder));
+ }
+
+ [Fact]
+ public void MetadataVersion()
+ {
+ var version = "\u1234\ud800";
+
+ var mdBuilder = new MetadataBuilder();
+ mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
+
+ var rootBuilder = new MetadataRootBuilder(mdBuilder, version);
+
+ var builder = new BlobBuilder();
+ rootBuilder.Serialize(builder, 0, 0);
+
+ AssertEx.Equal(new byte[]
+ {
+ // padded version length:
+ 0x08, 0x00, 0x00, 0x00,
+
+ // padded version:
+ 0xE1, 0x88, 0xB4, 0xED, 0xA0, 0x80, 0x00, 0x00,
+ }, builder.Slice(12, -132));
+
+ // the default decoder replaces bad byte sequences by U+FFFD
+ Assert.Equal("\u1234\ufffd\ufffd", ReadVersion(builder));
+ }
+ }
+}
// 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.Linq;
+using System.Reflection.Metadata.Tests;
using Xunit;
namespace System.Reflection.Metadata.Ecma335.Tests
}
[Fact]
+ public void TryGetTableIndex()
+ {
+ var kinds =
+ from i in Enumerable.Range(0, 255)
+ let index = new Func<HandleKind, TableIndex?>(k =>
+ {
+ TableIndex ti;
+ if (MetadataTokens.TryGetTableIndex(k, out ti))
+ {
+ Assert.Equal((int)k, (int)ti);
+ return ti;
+ }
+
+ return null;
+ })((HandleKind)i)
+ where index != null
+ select index.Value;
+
+ AssertEx.Equal(new TableIndex[]
+ {
+ TableIndex.Module,
+ TableIndex.TypeRef,
+ TableIndex.TypeDef,
+ TableIndex.FieldPtr,
+ TableIndex.Field,
+ TableIndex.MethodPtr,
+ TableIndex.MethodDef,
+ TableIndex.ParamPtr,
+ TableIndex.Param,
+ TableIndex.InterfaceImpl,
+ TableIndex.MemberRef,
+ TableIndex.Constant,
+ TableIndex.CustomAttribute,
+ TableIndex.FieldMarshal,
+ TableIndex.DeclSecurity,
+ TableIndex.ClassLayout,
+ TableIndex.FieldLayout,
+ TableIndex.StandAloneSig,
+ TableIndex.EventMap,
+ TableIndex.EventPtr,
+ TableIndex.Event,
+ TableIndex.PropertyMap,
+ TableIndex.PropertyPtr,
+ TableIndex.Property,
+ TableIndex.MethodSemantics,
+ TableIndex.MethodImpl,
+ TableIndex.ModuleRef,
+ TableIndex.TypeSpec,
+ TableIndex.ImplMap,
+ TableIndex.FieldRva,
+ TableIndex.EncLog,
+ TableIndex.EncMap,
+ TableIndex.Assembly,
+ TableIndex.AssemblyRef,
+ TableIndex.File,
+ TableIndex.ExportedType,
+ TableIndex.ManifestResource,
+ TableIndex.NestedClass,
+ TableIndex.GenericParam,
+ TableIndex.MethodSpec,
+ TableIndex.GenericParamConstraint,
+ TableIndex.Document,
+ TableIndex.MethodDebugInformation,
+ TableIndex.LocalScope,
+ TableIndex.LocalVariable,
+ TableIndex.LocalConstant,
+ TableIndex.ImportScope,
+ TableIndex.StateMachineMethod,
+ TableIndex.CustomDebugInformation
+ }, kinds);
+ }
+
+ [Fact]
+ public void TryGetHeapIndex()
+ {
+ HeapIndex index;
+ Assert.True(MetadataTokens.TryGetHeapIndex(HandleKind.Blob, out index));
+ Assert.Equal(HeapIndex.Blob, index);
+
+ Assert.True(MetadataTokens.TryGetHeapIndex(HandleKind.String, out index));
+ Assert.Equal(HeapIndex.String, index);
+
+ Assert.True(MetadataTokens.TryGetHeapIndex(HandleKind.UserString, out index));
+ Assert.Equal(HeapIndex.UserString, index);
+
+ Assert.True(MetadataTokens.TryGetHeapIndex(HandleKind.NamespaceDefinition, out index));
+ Assert.Equal(HeapIndex.String, index);
+
+ Assert.True(MetadataTokens.TryGetHeapIndex(HandleKind.Guid, out index));
+ Assert.Equal(HeapIndex.Guid, index);
+
+ Assert.False(MetadataTokens.TryGetHeapIndex(HandleKind.Constant, out index));
+ Assert.False(MetadataTokens.TryGetHeapIndex((HandleKind)255, out index));
+ }
+
+ [Fact]
public void HandleFactories_FromToken()
{
Assert.Equal(s_assemblyRefHandle, MetadataTokens.Handle(0x23000001));
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using System.Reflection.Metadata.Tests;
+using Xunit;
+
+namespace System.Reflection.Metadata.Ecma335.Tests
+{
+ public class PortablePdbBuilderTests
+ {
+ [Fact]
+ public void Ctor_Errors()
+ {
+ var mdBuilder = new MetadataBuilder();
+
+ Assert.Throws<ArgumentNullException>(() => new PortablePdbBuilder(null, MetadataRootBuilder.EmptyRowCounts, default(MethodDefinitionHandle)));
+ Assert.Throws<ArgumentNullException>(() => new PortablePdbBuilder(mdBuilder, default(ImmutableArray<int>), default(MethodDefinitionHandle)));
+
+ var rowCounts = new int[128];
+ rowCounts[64] = 1;
+ Assert.Throws<ArgumentException>(() => new PortablePdbBuilder(mdBuilder, ImmutableArray.Create(rowCounts), default(MethodDefinitionHandle)));
+
+ rowCounts = new int[64];
+ rowCounts[63] = 1;
+ Assert.Throws<ArgumentException>(() => new PortablePdbBuilder(mdBuilder, ImmutableArray.Create(rowCounts), default(MethodDefinitionHandle)));
+
+ rowCounts = new int[64];
+ rowCounts[(int)TableIndex.EventPtr] = 1;
+ Assert.Throws<ArgumentException>(() => new PortablePdbBuilder(mdBuilder, ImmutableArray.Create(rowCounts), default(MethodDefinitionHandle)));
+
+ rowCounts = new int[64];
+ rowCounts[(int)TableIndex.CustomDebugInformation] = 1;
+ Assert.Throws<ArgumentException>(() => new PortablePdbBuilder(mdBuilder, ImmutableArray.Create(rowCounts), default(MethodDefinitionHandle)));
+
+ rowCounts = new int[64];
+ rowCounts[(int)TableIndex.MethodDef] = -1;
+ Assert.Throws<ArgumentOutOfRangeException>(() => new PortablePdbBuilder(mdBuilder, ImmutableArray.Create(rowCounts), default(MethodDefinitionHandle)));
+
+ rowCounts = new int[64];
+ rowCounts[(int)TableIndex.GenericParamConstraint] = 0x01000000;
+ Assert.Throws<ArgumentOutOfRangeException>(() => new PortablePdbBuilder(mdBuilder, ImmutableArray.Create(rowCounts), default(MethodDefinitionHandle)));
+ }
+
+ [Fact]
+ public void Serialize_Errors()
+ {
+ var mdBuilder = new MetadataBuilder();
+ var pdbBuilder = new PortablePdbBuilder(mdBuilder, MetadataRootBuilder.EmptyRowCounts, default(MethodDefinitionHandle));
+ var builder = new BlobBuilder();
+
+ Assert.Throws<ArgumentNullException>(() => pdbBuilder.Serialize(null));
+ }
+
+ [Fact]
+ public void Headers()
+ {
+ var mdBuilder = new MetadataBuilder();
+ var pdbBuilder = new PortablePdbBuilder(
+ mdBuilder,
+ MetadataRootBuilder.EmptyRowCounts,
+ MetadataTokens.MethodDefinitionHandle(0x123456),
+ _ => new BlobContentId(new Guid("44332211-6655-8877-AA99-010203040506"), 0xFFEEDDCC));
+
+ var builder = new BlobBuilder();
+ pdbBuilder.Serialize(builder);
+
+ AssertEx.Equal(new byte[]
+ {
+ // signature:
+ 0x42, 0x53, 0x4A, 0x42,
+ // major version (1)
+ 0x01, 0x00,
+ // minor version (1)
+ 0x01, 0x00,
+ // reserved (0)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // padded version length:
+ 0x0C, 0x00, 0x00, 0x00,
+
+ // padded version:
+ (byte)'P', (byte)'D', (byte)'B', (byte)' ', (byte)'v', (byte)'1', (byte)'.', (byte)'0', 0x00, 0x00, 0x00, 0x00,
+
+ // flags (0):
+ 0x00, 0x00,
+
+ // stream count:
+ 0x06, 0x00,
+
+ // stream headers (offset, size, padded name)
+ 0x7C, 0x00, 0x00, 0x00,
+ 0x20, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'P', (byte)'d', (byte)'b', 0x00, 0x00, 0x00, 0x00,
+
+ 0x9C, 0x00, 0x00, 0x00,
+ 0x1C, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'~', 0x00, 0x00,
+
+ 0xB8, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'S', (byte)'t', (byte)'r', (byte)'i', (byte)'n', (byte)'g', (byte)'s', 0x00, 0x00, 0x00, 0x00,
+
+ 0xBC, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'U', (byte)'S', 0x00,
+
+ 0xC0, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'G', (byte)'U', (byte)'I', (byte)'D', 0x00, 0x00, 0x00,
+
+ 0xC0, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
+ (byte)'#', (byte)'B', (byte)'l', (byte)'o', (byte)'b', 0x00, 0x00, 0x00,
+
+ // --------
+ // #Pdb
+ // --------
+
+ // PDB ID
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xAA, 0x99, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0xCC, 0xDD, 0xEE, 0xFF,
+
+ // EntryPoint
+ 0x56, 0x34, 0x12, 0x06,
+
+ // ReferencedTypeSystemTables
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // TypeSystemTableRows (empty)
+
+ // --------
+ // #~
+ // --------
+
+ // Reserved (0)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // Major Version (2)
+ 0x02,
+
+ // Minor Version (0)
+ 0x00,
+
+ // Heap Sizes
+ 0x00,
+
+ // Reserved (1)
+ 0x01,
+
+ // Present tables
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // Sorted tables
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // Rows (empty)
+ // Tables (empty)
+
+ // Padding and alignment
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #Strings
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #US
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+
+ // --------
+ // #GUID
+ // --------
+
+ // --------
+ // #Blob
+ // --------
+
+ 0x00, 0x00, 0x00, 0x00,
+
+ }, builder.ToArray());
+ }
+
+ [Fact]
+ public void PdbStream_TypeSystemRowCounts()
+ {
+ var rowCounts = new int[MetadataTokens.TableCount];
+ rowCounts[(int)TableIndex.MethodDef] = 0xFFFFFF;
+ rowCounts[(int)TableIndex.TypeDef] = 0x123456;
+
+ var mdBuilder = new MetadataBuilder();
+ var pdbBuilder = new PortablePdbBuilder(
+ mdBuilder,
+ ImmutableArray.Create(rowCounts),
+ MetadataTokens.MethodDefinitionHandle(0x123456),
+ _ => new BlobContentId(new Guid("44332211-6655-8877-AA99-010203040506"), 0xFFEEDDCC));
+
+ var builder = new BlobBuilder();
+ pdbBuilder.Serialize(builder);
+
+ AssertEx.Equal(new byte[]
+ {
+ // PDB ID
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0xAA, 0x99, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0xCC, 0xDD, 0xEE, 0xFF,
+
+ // EntryPoint
+ 0x56, 0x34, 0x12, 0x06,
+
+ // ReferencedTypeSystemTables
+ 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // TypeSystemTableRows
+ 0x56, 0x34, 0x12, 0x00,
+ 0xFF, 0xFF, 0xFF, 0x00
+
+ }, builder.Slice(124, -40));
+ }
+ }
+}
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
mdBuilder.AddModule(0, default(StringHandle), default(GuidHandle), default(GuidHandle), default(GuidHandle));
- var mdSerializer = new TypeSystemMetadataSerializer(mdBuilder, "v4.0.30319", isMinimalDelta: false);
+ var rootBuilder = new MetadataRootBuilder(mdBuilder);
var mdBlob = new BlobBuilder();
- mdSerializer.SerializeMetadata(mdBlob, 0, 0);
+ rootBuilder.Serialize(mdBlob, 0, 0);
// validate sizes table rows that reference guids:
using (var mdProvider = MetadataReaderProvider.FromMetadataImage(mdBlob.ToImmutableArray()))
{
var peBuilder = new ManagedPEBuilder(
entryPointHandle.IsNil ? PEHeaderBuilder.CreateLibraryHeader() : PEHeaderBuilder.CreateExecutableHeader(),
- new TypeSystemMetadataSerializer(metadataBuilder, "v4.0.30319", isMinimalDelta: false),
+ new MetadataRootBuilder(metadataBuilder),
ilBuilder,
entryPoint: entryPointHandle,
flags: CorFlags.ILOnly | (privateKeyOpt != null ? CorFlags.StrongNameSigned : 0),
public void ManagedPEBuilder_Errors()
{
var hdr = new PEHeaderBuilder();
- var ms = new TypeSystemMetadataSerializer(new MetadataBuilder(), "v4.0.30319", false);
+ var ms = new MetadataRootBuilder(new MetadataBuilder());
var il = new BlobBuilder();
Assert.Throws<ArgumentNullException>(() => new ManagedPEBuilder(null, ms, il));
var peBuilder = new ManagedPEBuilder(
PEHeaderBuilder.CreateLibraryHeader(),
- new TypeSystemMetadataSerializer(metadataBuilder, "v4.0.30319", false),
+ new MetadataRootBuilder(metadataBuilder),
ilBuilder,
nativeResources: new TestResourceSectionBuilder(),
deterministicIdProvider: content => s_contentId);
var peBuilder = new ManagedPEBuilder(
PEHeaderBuilder.CreateLibraryHeader(),
- new TypeSystemMetadataSerializer(metadataBuilder, "v4.0.30319", false),
+ new MetadataRootBuilder(metadataBuilder),
ilBuilder,
nativeResources: new BadResourceSectionBuilder(),
deterministicIdProvider: content => s_contentId);
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<Compile Include="Metadata\BlobTests.cs" />
<Compile Include="Metadata\BlobUtilitiesTests.cs" />
<Compile Include="Metadata\Ecma335\CodedIndexTests.cs" />
+ <Compile Include="Metadata\Ecma335\MetadataRootBuilderTests.cs" />
+ <Compile Include="Metadata\Ecma335\PortablePdbBuilderTests.cs" />
<Compile Include="Metadata\LargeTablesAndHeapsTests.cs" />
<Compile Include="Metadata\TypeSystem\ClassLayoutRow.cs" />
<Compile Include="Metadata\Decoding\CustomAttributeDecoderTests.cs" />
<Compile Include="Metadata\PortablePdb\DocumentNameTests.cs" />
<Compile Include="PortableExecutable\DebugDirectoryBuilderTests.cs" />
<Compile Include="PortableExecutable\PEMemoryBlockTests.cs" />
+ <Compile Include="TestUtilities\ByteArrayUtilities.cs" />
<Compile Include="TestUtilities\PinnedBlob.cs" />
<Compile Include="TestUtilities\SigningUtilities.cs" />
<Compile Include="Utilities\AbstractMemoryBlockTests.cs" />
{
if (itemInspector == null)
{
- if (expected is IEnumerable<byte>)
+ if (typeof(T) == typeof(byte))
{
itemInspector = b => $"0x{b:X2}";
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Reflection.Metadata.Tests
+{
+ public static class ByteArrayUtilities
+ {
+ public static byte[] Slice(this BlobBuilder bytes, int start, int end)
+ {
+ return Slice(bytes.ToArray(), start, end);
+ }
+
+ public static byte[] Slice(this byte[] bytes, int start, int end)
+ {
+ if (end < 0)
+ {
+ end = bytes.Length + end;
+ }
+
+ var result = new byte[end - start];
+ Array.Copy(bytes, start, result, 0, result.Length);
+ return result;
+ }
+ }
+}