Permalink
Switch branches/tags
version-2.9.0 version-2.8.2 version-2.8.0 version-2.7.0-beta3 version-2.6.0-beta3 version-2.4.0 version-2.3.5 version-2.3.4 version-2.3.2 version-2.3.2-beta1 version-2.3.0-beta3 version-2.3.0-beta2 version-2.3.0-beta1 version-2.2.0 version-2.1.0 version-2.0.0 version-2.0.0-rc4 version-2.0.0-rc3 version-2.0.0-rc2 version-2.0.0-rc version-2.0.0-beta5 version-2.0.0-beta4 version-2.0.0-beta3 version-2.0.0-beta1 version-1.3.2 version-1.3.1 version-1.3.0 version-1.3.0-beta1-20160429-01 version-1.2.2 version-1.2.1 version-1.2.0 version-1.2.0-beta1-20160108-01 version-1.2.0-beta version-1.2.0-beta-20151211-01 version-1.1.1 version-1.1.0 version-1.1.0-rc1-20151109-01 version-1.0.0 version-1.0.0-beta1-20141031-01 toolset_5 toolset_3 toolset_2 toolset_1_1 toolset_1 Visual.Studio.2015.Update.1.RC Visual.Studio.2015.Update.1.CTP Visual-Studio-2017 Visual-Studio-2017-Version-15.8 Visual-Studio-2017-Version-15.7.2 Visual-Studio-2017-Version-15.7 Visual-Studio-2017-Version-15.6 Visual-Studio-2017-Version-15.5 Visual-Studio-2017-Version-15.4 Visual-Studio-2017-Version-15.3.5 Visual-Studio-2017-Version-15.3.4 Visual-Studio-2017-Version-15.3.2 Visual-Studio-2017-Version-15.3 Visual-Studio-2017-Version-15.2 Visual-Studio-2017-Version-15.1 Visual-Studio-2017-RC4 Visual-Studio-2017-RC3 Visual-Studio-2017-RC2 Visual-Studio-2017-RC Visual-Studio-2017-Preview-Version-15.3 Visual-Studio-2017-Preview-6-Version-15.7 Visual-Studio-2017-Preview-3-Version-15.4 Visual-Studio-2017-Preview-3-Version-15.3 Visual-Studio-2017-Preview-2-Version-15.4 Visual-Studio-2017-Preview-2-Version-15.3 Visual-Studio-2017-Preview-1-Version-15.4 Visual-Studio-2015 Visual-Studio-2015-Update-3 Visual-Studio-2015-Update-3-Micro-Update-1 Visual-Studio-2015-Update-2 Visual-Studio-2015-Update-2-RC Visual-Studio-2015-Update-2-Micro-Update-3 Visual-Studio-2015-Update-2-Micro-Update-1 Visual-Studio-2015-Update-1 Visual-Studio-2015-Update-1-RC Visual-Studio-2015-Update-1-CTP Visual-Studio-2015-RC Visual-Studio-2015-Preview Visual-Studio-2015-CTP-6 Visual-Studio-2015-CTP-5 Visual-Studio-15-Preview Visual-Studio-15-Preview-5 Visual-Studio-15-Preview-4 Visual-Studio-15-Preview-3 VS.Toolset.Roslyn.1.1.0-beta1-20150727-01 VS.Tools.X86.Managed.V45.1.0.150513.2 Oss.Scan.2015.03.13 Oss.Scan.2013.03.13 NetFx.Toolset.150729
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
4188 lines (3520 sloc) 168 KB
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.DiaSymReader;
using Roslyn.Utilities;
namespace Microsoft.Cci
{
internal abstract partial class MetadataWriter
{
internal static readonly Encoding s_utf8Encoding = Encoding.UTF8;
/// <summary>
/// This is the maximum length of a type or member name in metadata, assuming
/// the name is in UTF-8 format and not (yet) null-terminated.
/// </summary>
/// <remarks>
/// Source names may have to be shorter still to accommodate mangling.
/// Used for event names, field names, property names, field names, method def names,
/// member ref names, type def (full) names, type ref (full) names, exported type
/// (full) names, parameter names, manifest resource names, and unmanaged method names
/// (ImplMap table).
///
/// See CLI Part II, section 22.
/// </remarks>
internal const int NameLengthLimit = 1024 - 1; //MAX_CLASS_NAME = 1024 in dev11
/// <summary>
/// This is the maximum length of a path in metadata, assuming the path is in UTF-8
/// format and not (yet) null-terminated.
/// </summary>
/// <remarks>
/// Used for file names, module names, and module ref names.
///
/// See CLI Part II, section 22.
/// </remarks>
internal const int PathLengthLimit = 260 - 1; //MAX_PATH = 1024 in dev11
/// <summary>
/// This is the maximum length of a string in the PDB, assuming it is in UTF-8 format
/// and not (yet) null-terminated.
/// </summary>
/// <remarks>
/// Used for import strings, locals, and local constants.
/// </remarks>
internal const int PdbLengthLimit = 2046; // Empirical, based on when ISymUnmanagedWriter2 methods start throwing.
private readonly int _numTypeDefsEstimate;
private readonly bool _deterministic;
internal readonly bool MetadataOnly;
internal readonly bool EmitTestCoverageData;
// A map of method body before token translation to RVA. Used for deduplication of small bodies.
private readonly Dictionary<ImmutableArray<byte>, int> _smallMethodBodies;
private const byte TinyFormat = 2;
private const int ThrowNullCodeSize = 2;
private static readonly ImmutableArray<byte> ThrowNullEncodedBody =
ImmutableArray.Create(
(byte)((ThrowNullCodeSize << 2) | TinyFormat),
(byte)ILOpCode.Ldnull,
(byte)ILOpCode.Throw);
protected MetadataWriter(
MetadataBuilder metadata,
MetadataBuilder debugMetadataOpt,
DynamicAnalysisDataWriter dynamicAnalysisDataWriterOpt,
EmitContext context,
CommonMessageProvider messageProvider,
bool metadataOnly,
bool deterministic,
bool emitTestCoverageData,
CancellationToken cancellationToken)
{
Debug.Assert(metadata != debugMetadataOpt);
this.module = context.Module;
_deterministic = deterministic;
this.MetadataOnly = metadataOnly;
this.EmitTestCoverageData = emitTestCoverageData;
// EDMAURER provide some reasonable size estimates for these that will avoid
// much of the reallocation that would occur when growing these from empty.
_signatureIndex = new Dictionary<ISignature, KeyValuePair<BlobHandle, ImmutableArray<byte>>>(module.HintNumberOfMethodDefinitions); //ignores field signatures
_numTypeDefsEstimate = module.HintNumberOfMethodDefinitions / 6;
_exportedTypeList = new List<ITypeReference>(_numTypeDefsEstimate);
this.Context = context;
this.messageProvider = messageProvider;
_cancellationToken = cancellationToken;
this.metadata = metadata;
_debugMetadataOpt = debugMetadataOpt;
_dynamicAnalysisDataWriterOpt = dynamicAnalysisDataWriterOpt;
_smallMethodBodies = new Dictionary<ImmutableArray<byte>, int>(ByteSequenceComparer.Instance);
}
private int NumberOfTypeDefsEstimate { get { return _numTypeDefsEstimate; } }
/// <summary>
/// Returns true if writing full metadata, false if writing delta.
/// </summary>
internal bool IsFullMetadata
{
get { return this.Generation == 0; }
}
/// <summary>
/// True if writing delta metadata in a minimal format.
/// </summary>
private bool IsMinimalDelta
{
get { return !IsFullMetadata; }
}
/// <summary>
/// NetModules and EnC deltas don't have AssemblyDef record.
/// We don't emit it for EnC deltas since assembly identity has to be preserved across generations (CLR/debugger get confused otherwise).
/// </summary>
private bool EmitAssemblyDefinition => module.OutputKind != OutputKind.NetModule && !IsMinimalDelta;
/// <summary>
/// Returns metadata generation ordinal. Zero for
/// full metadata and non-zero for delta.
/// </summary>
protected abstract ushort Generation { get; }
/// <summary>
/// Returns unique Guid for this delta, or default(Guid)
/// if full metadata.
/// </summary>
protected abstract Guid EncId { get; }
/// <summary>
/// Returns Guid of previous delta, or default(Guid)
/// if full metadata or generation 1 delta.
/// </summary>
protected abstract Guid EncBaseId { get; }
/// <summary>
/// Returns true and full metadata handle of the type definition
/// if the type definition is recognized. Otherwise returns false.
/// </summary>
protected abstract bool TryGetTypeDefinitionHandle(ITypeDefinition def, out TypeDefinitionHandle handle);
/// <summary>
/// Get full metadata handle of the type definition.
/// </summary>
protected abstract TypeDefinitionHandle GetTypeDefinitionHandle(ITypeDefinition def);
/// <summary>
/// The type definition corresponding to full metadata type handle.
/// Deltas are only required to support indexing into current generation.
/// </summary>
protected abstract ITypeDefinition GetTypeDef(TypeDefinitionHandle handle);
/// <summary>
/// The type definitions to be emitted, in row order. These
/// are just the type definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<ITypeDefinition> GetTypeDefs();
/// <summary>
/// Get full metadata handle of the event definition.
/// </summary>
protected abstract EventDefinitionHandle GetEventDefinitionHandle(IEventDefinition def);
/// <summary>
/// The event definitions to be emitted, in row order. These
/// are just the event definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<IEventDefinition> GetEventDefs();
/// <summary>
/// Get full metadata handle of the field definition.
/// </summary>
protected abstract FieldDefinitionHandle GetFieldDefinitionHandle(IFieldDefinition def);
/// <summary>
/// The field definitions to be emitted, in row order. These
/// are just the field definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<IFieldDefinition> GetFieldDefs();
/// <summary>
/// Returns true and handle of the method definition
/// if the method definition is recognized. Otherwise returns false.
/// The index is into the full metadata.
/// </summary>
protected abstract bool TryGetMethodDefinitionHandle(IMethodDefinition def, out MethodDefinitionHandle handle);
/// <summary>
/// Get full metadata handle of the method definition.
/// </summary>
protected abstract MethodDefinitionHandle GetMethodDefinitionHandle(IMethodDefinition def);
/// <summary>
/// The method definition corresponding to full metadata method handle.
/// Deltas are only required to support indexing into current generation.
/// </summary>
protected abstract IMethodDefinition GetMethodDef(MethodDefinitionHandle handle);
/// <summary>
/// The method definitions to be emitted, in row order. These
/// are just the method definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<IMethodDefinition> GetMethodDefs();
/// <summary>
/// Get full metadata handle of the property definition.
/// </summary>
protected abstract PropertyDefinitionHandle GetPropertyDefIndex(IPropertyDefinition def);
/// <summary>
/// The property definitions to be emitted, in row order. These
/// are just the property definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<IPropertyDefinition> GetPropertyDefs();
/// <summary>
/// The full metadata handle of the parameter definition.
/// </summary>
protected abstract ParameterHandle GetParameterHandle(IParameterDefinition def);
/// <summary>
/// The parameter definitions to be emitted, in row order. These
/// are just the parameter definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<IParameterDefinition> GetParameterDefs();
/// <summary>
/// The generic parameter definitions to be emitted, in row order. These
/// are just the generic parameter definitions from the current generation.
/// </summary>
protected abstract IReadOnlyList<IGenericParameter> GetGenericParameters();
/// <summary>
/// The handle of the first field of the type.
/// </summary>
protected abstract FieldDefinitionHandle GetFirstFieldDefinitionHandle(INamedTypeDefinition typeDef);
/// <summary>
/// The handle of the first method of the type.
/// </summary>
protected abstract MethodDefinitionHandle GetFirstMethodDefinitionHandle(INamedTypeDefinition typeDef);
/// <summary>
/// The handle of the first parameter of the method.
/// </summary>
protected abstract ParameterHandle GetFirstParameterHandle(IMethodDefinition methodDef);
/// <summary>
/// Return full metadata handle of the assembly reference, adding
/// the reference to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract AssemblyReferenceHandle GetOrAddAssemblyReferenceHandle(IAssemblyReference reference);
/// <summary>
/// The assembly references to be emitted, in row order. These
/// are just the assembly references from the current generation.
/// </summary>
protected abstract IReadOnlyList<AssemblyIdentity> GetAssemblyRefs();
// ModuleRef table contains module names for TypeRefs that target types in netmodules (represented by IModuleReference),
// and module names specified by P/Invokes (plain strings). Names in the table must be unique and are case sensitive.
//
// Spec 22.31 (ModuleRef : 0x1A)
// "Name should match an entry in the Name column of the File table. Moreover, that entry shall enable the
// CLI to locate the target module (typically it might name the file used to hold the module)"
//
// This is not how the Dev10 compilers and ILASM work. An entry is added to File table only for resources and netmodules.
// Entries aren't added for P/Invoked modules.
/// <summary>
/// Return full metadata handle of the module reference, adding
/// the reference to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract ModuleReferenceHandle GetOrAddModuleReferenceHandle(string reference);
/// <summary>
/// The module references to be emitted, in row order. These
/// are just the module references from the current generation.
/// </summary>
protected abstract IReadOnlyList<string> GetModuleRefs();
/// <summary>
/// Return full metadata handle of the member reference, adding
/// the reference to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract MemberReferenceHandle GetOrAddMemberReferenceHandle(ITypeMemberReference reference);
/// <summary>
/// The member references to be emitted, in row order. These
/// are just the member references from the current generation.
/// </summary>
protected abstract IReadOnlyList<ITypeMemberReference> GetMemberRefs();
/// <summary>
/// Return full metadata handle of the method spec, adding
/// the spec to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract MethodSpecificationHandle GetOrAddMethodSpecificationHandle(IGenericMethodInstanceReference reference);
/// <summary>
/// The method specs to be emitted, in row order. These
/// are just the method specs from the current generation.
/// </summary>
protected abstract IReadOnlyList<IGenericMethodInstanceReference> GetMethodSpecs();
/// <summary>
/// The greatest index given to any method definition.
/// </summary>
protected abstract int GreatestMethodDefIndex { get; }
/// <summary>
/// Return true and full metadata handle of the type reference
/// if the reference is available in the current generation.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract bool TryGetTypeReferenceHandle(ITypeReference reference, out TypeReferenceHandle handle);
/// <summary>
/// Return full metadata handle of the type reference, adding
/// the reference to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract TypeReferenceHandle GetOrAddTypeReferenceHandle(ITypeReference reference);
/// <summary>
/// The type references to be emitted, in row order. These
/// are just the type references from the current generation.
/// </summary>
protected abstract IReadOnlyList<ITypeReference> GetTypeRefs();
/// <summary>
/// Returns full metadata handle of the type spec, adding
/// the spec to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract TypeSpecificationHandle GetOrAddTypeSpecificationHandle(ITypeReference reference);
/// <summary>
/// The type specs to be emitted, in row order. These
/// are just the type specs from the current generation.
/// </summary>
protected abstract IReadOnlyList<ITypeReference> GetTypeSpecs();
/// <summary>
/// Returns full metadata handle the standalone signature, adding
/// the signature to the index for this generation if missing.
/// Deltas are not required to return rows from previous generations.
/// </summary>
protected abstract StandaloneSignatureHandle GetOrAddStandaloneSignatureHandle(BlobHandle handle);
/// <summary>
/// The signature blob handles to be emitted, in row order. These
/// are just the signature indices from the current generation.
/// </summary>
protected abstract IReadOnlyList<BlobHandle> GetStandaloneSignatureBlobHandles();
protected abstract IEnumerable<INamespaceTypeDefinition> GetTopLevelTypes(CommonPEModuleBuilder module);
protected abstract void CreateIndicesForNonTypeMembers(ITypeDefinition typeDef);
/// <summary>
/// Return a visitor for traversing all references to be emitted.
/// </summary>
protected abstract ReferenceIndexer CreateReferenceVisitor();
/// <summary>
/// Populate EventMap table.
/// </summary>
protected abstract void PopulateEventMapTableRows();
/// <summary>
/// Populate PropertyMap table.
/// </summary>
protected abstract void PopulatePropertyMapTableRows();
/// <summary>
/// Populate EncLog table.
/// </summary>
protected abstract void PopulateEncLogTableRows(ImmutableArray<int> rowCounts);
/// <summary>
/// Populate EncMap table.
/// </summary>
protected abstract void PopulateEncMapTableRows(ImmutableArray<int> rowCounts);
protected abstract void ReportReferencesToAddedSymbols();
// If true, it is allowed to have methods not have bodies (for emitting metadata-only
// assembly)
private readonly CancellationToken _cancellationToken;
protected readonly CommonPEModuleBuilder module;
public readonly EmitContext Context;
protected readonly CommonMessageProvider messageProvider;
// progress:
private bool _tableIndicesAreComplete;
private EntityHandle[] _pseudoSymbolTokenToTokenMap;
private IReference[] _pseudoSymbolTokenToReferenceMap;
private UserStringHandle[] _pseudoStringTokenToTokenMap;
private bool _userStringTokenOverflow;
private List<string> _pseudoStringTokenToStringMap;
private ReferenceIndexer _referenceVisitor;
protected readonly MetadataBuilder metadata;
// A builder for Portable or Embedded PDB metadata, or null if we are not emitting Portable/Embedded PDB.
protected readonly MetadataBuilder _debugMetadataOpt;
internal bool EmitPortableDebugMetadata => _debugMetadataOpt != null;
private readonly DynamicAnalysisDataWriter _dynamicAnalysisDataWriterOpt;
private readonly Dictionary<ICustomAttribute, BlobHandle> _customAttributeSignatureIndex = new Dictionary<ICustomAttribute, BlobHandle>();
private readonly Dictionary<ITypeReference, BlobHandle> _typeSpecSignatureIndex = new Dictionary<ITypeReference, BlobHandle>();
private readonly List<ITypeReference> _exportedTypeList;
private readonly Dictionary<string, int> _fileRefIndex = new Dictionary<string, int>(32); // more than enough in most cases, value is a RowId
private readonly List<IFileReference> _fileRefList = new List<IFileReference>(32);
private readonly Dictionary<IFieldReference, BlobHandle> _fieldSignatureIndex = new Dictionary<IFieldReference, BlobHandle>();
// We need to keep track of both the index of the signature and the actual blob to support VB static local naming scheme.
private readonly Dictionary<ISignature, KeyValuePair<BlobHandle, ImmutableArray<byte>>> _signatureIndex;
private readonly Dictionary<IMarshallingInformation, BlobHandle> _marshallingDescriptorIndex = new Dictionary<IMarshallingInformation, BlobHandle>();
protected readonly List<MethodImplementation> methodImplList = new List<MethodImplementation>();
private readonly Dictionary<IGenericMethodInstanceReference, BlobHandle> _methodInstanceSignatureIndex = new Dictionary<IGenericMethodInstanceReference, BlobHandle>();
// Well known dummy cor library types whose refs are used for attaching assembly attributes off within net modules
// There is no guarantee the types actually exist in a cor library
internal const string dummyAssemblyAttributeParentNamespace = "System.Runtime.CompilerServices";
internal const string dummyAssemblyAttributeParentName = "AssemblyAttributesGoHere";
internal static readonly string[,] dummyAssemblyAttributeParentQualifier = { { "", "M" }, { "S", "SM" } };
private readonly TypeReferenceHandle[,] _dummyAssemblyAttributeParent = { { default(TypeReferenceHandle), default(TypeReferenceHandle) }, { default(TypeReferenceHandle), default(TypeReferenceHandle) } };
internal CommonPEModuleBuilder Module => module;
private void CreateMethodBodyReferenceIndex()
{
int count;
var referencesInIL = module.ReferencesInIL(out count);
_pseudoSymbolTokenToTokenMap = new EntityHandle[count];
_pseudoSymbolTokenToReferenceMap = new IReference[count];
int cur = 0;
foreach (IReference o in referencesInIL)
{
_pseudoSymbolTokenToReferenceMap[cur] = o;
cur++;
}
}
private void CreateIndices()
{
_cancellationToken.ThrowIfCancellationRequested();
this.CreateUserStringIndices();
this.CreateInitialAssemblyRefIndex();
this.CreateInitialFileRefIndex();
this.CreateIndicesForModule();
// Find all references and assign tokens.
_referenceVisitor = this.CreateReferenceVisitor();
_referenceVisitor.Visit(module);
this.CreateMethodBodyReferenceIndex();
this.OnIndicesCreated();
}
private void CreateUserStringIndices()
{
_pseudoStringTokenToStringMap = new List<string>();
foreach (string str in this.module.GetStrings())
{
_pseudoStringTokenToStringMap.Add(str);
}
_pseudoStringTokenToTokenMap = new UserStringHandle[_pseudoStringTokenToStringMap.Count];
}
private void CreateIndicesForModule()
{
var nestedTypes = new Queue<INestedTypeDefinition>();
foreach (INamespaceTypeDefinition typeDef in this.GetTopLevelTypes(this.module))
{
this.CreateIndicesFor(typeDef, nestedTypes);
}
while (nestedTypes.Count > 0)
{
var nestedType = nestedTypes.Dequeue();
this.CreateIndicesFor(nestedType, nestedTypes);
}
}
protected virtual void OnIndicesCreated()
{
}
private void CreateIndicesFor(ITypeDefinition typeDef, Queue<INestedTypeDefinition> nestedTypes)
{
_cancellationToken.ThrowIfCancellationRequested();
this.CreateIndicesForNonTypeMembers(typeDef);
// Metadata spec:
// The TypeDef table has a special ordering constraint:
// the definition of an enclosing class shall precede the definition of all classes it encloses.
foreach (var nestedType in typeDef.GetNestedTypes(Context))
{
nestedTypes.Enqueue(nestedType);
}
}
protected IEnumerable<IGenericTypeParameter> GetConsolidatedTypeParameters(ITypeDefinition typeDef)
{
INestedTypeDefinition nestedTypeDef = typeDef.AsNestedTypeDefinition(Context);
if (nestedTypeDef == null)
{
if (typeDef.IsGeneric)
{
return typeDef.GenericParameters;
}
return null;
}
return this.GetConsolidatedTypeParameters(typeDef, typeDef);
}
private List<IGenericTypeParameter> GetConsolidatedTypeParameters(ITypeDefinition typeDef, ITypeDefinition owner)
{
List<IGenericTypeParameter> result = null;
INestedTypeDefinition nestedTypeDef = typeDef.AsNestedTypeDefinition(Context);
if (nestedTypeDef != null)
{
result = this.GetConsolidatedTypeParameters(nestedTypeDef.ContainingTypeDefinition, owner);
}
if (typeDef.GenericParameterCount > 0)
{
ushort index = 0;
if (result == null)
{
result = new List<IGenericTypeParameter>();
}
else
{
index = (ushort)result.Count;
}
if (typeDef == owner && index == 0)
{
result.AddRange(typeDef.GenericParameters);
}
else
{
foreach (IGenericTypeParameter genericParameter in typeDef.GenericParameters)
{
result.Add(new InheritedTypeParameter(index++, owner, genericParameter));
}
}
}
return result;
}
protected ImmutableArray<IParameterDefinition> GetParametersToEmit(IMethodDefinition methodDef)
{
if (methodDef.ParameterCount == 0 && !(methodDef.ReturnValueIsMarshalledExplicitly || IteratorHelper.EnumerableIsNotEmpty(methodDef.GetReturnValueAttributes(Context))))
{
return ImmutableArray<IParameterDefinition>.Empty;
}
return GetParametersToEmitCore(methodDef);
}
private ImmutableArray<IParameterDefinition> GetParametersToEmitCore(IMethodDefinition methodDef)
{
ArrayBuilder<IParameterDefinition> builder = null;
var parameters = methodDef.Parameters;
if (methodDef.ReturnValueIsMarshalledExplicitly || IteratorHelper.EnumerableIsNotEmpty(methodDef.GetReturnValueAttributes(Context)))
{
builder = ArrayBuilder<IParameterDefinition>.GetInstance(parameters.Length + 1);
builder.Add(new ReturnValueParameter(methodDef));
}
for (int i = 0; i < parameters.Length; i++)
{
IParameterDefinition parDef = parameters[i];
// No explicit param row is needed if param has no flags (other than optionally IN),
// no name and no references to the param row, such as CustomAttribute, Constant, or FieldMarshal
if (parDef.Name != String.Empty ||
parDef.HasDefaultValue || parDef.IsOptional || parDef.IsOut || parDef.IsMarshalledExplicitly ||
IteratorHelper.EnumerableIsNotEmpty(parDef.GetAttributes(Context)))
{
if (builder != null)
{
builder.Add(parDef);
}
}
else
{
// we have a parameter that does not need to be emitted (not common)
if (builder == null)
{
builder = ArrayBuilder<IParameterDefinition>.GetInstance(parameters.Length);
builder.AddRange(parameters, i);
}
}
}
return builder?.ToImmutableAndFree() ?? parameters;
}
/// <summary>
/// Returns a reference to the unit that defines the given referenced type. If the referenced type is a structural type, such as a pointer or a generic type instance,
/// then the result is null.
/// </summary>
public static IUnitReference GetDefiningUnitReference(ITypeReference typeReference, EmitContext context)
{
INestedTypeReference nestedTypeReference = typeReference.AsNestedTypeReference;
while (nestedTypeReference != null)
{
if (nestedTypeReference.AsGenericTypeInstanceReference != null)
{
return null;
}
typeReference = nestedTypeReference.GetContainingType(context);
nestedTypeReference = typeReference.AsNestedTypeReference;
}
INamespaceTypeReference namespaceTypeReference = typeReference.AsNamespaceTypeReference;
if (namespaceTypeReference == null)
{
return null;
}
Debug.Assert(namespaceTypeReference.AsGenericTypeInstanceReference == null);
return namespaceTypeReference.GetUnit(context);
}
private void CreateInitialAssemblyRefIndex()
{
Debug.Assert(!_tableIndicesAreComplete);
foreach (IAssemblyReference assemblyRef in this.module.GetAssemblyReferences(Context))
{
this.GetOrAddAssemblyReferenceHandle(assemblyRef);
}
}
private void CreateInitialFileRefIndex()
{
Debug.Assert(!_tableIndicesAreComplete);
foreach (IFileReference fileRef in module.GetFiles(Context))
{
string key = fileRef.FileName;
if (!_fileRefIndex.ContainsKey(key))
{
_fileRefList.Add(fileRef);
_fileRefIndex.Add(key, _fileRefList.Count);
}
}
}
internal AssemblyReferenceHandle GetAssemblyReferenceHandle(IAssemblyReference assemblyReference)
{
var containingAssembly = this.module.GetContainingAssembly(Context);
if (containingAssembly != null && ReferenceEquals(assemblyReference, containingAssembly))
{
return default(AssemblyReferenceHandle);
}
return this.GetOrAddAssemblyReferenceHandle(assemblyReference);
}
internal ModuleReferenceHandle GetModuleReferenceHandle(string moduleName)
{
return this.GetOrAddModuleReferenceHandle(moduleName);
}
private BlobHandle GetCustomAttributeSignatureIndex(ICustomAttribute customAttribute)
{
BlobHandle result;
if (_customAttributeSignatureIndex.TryGetValue(customAttribute, out result))
{
return result;
}
var writer = PooledBlobBuilder.GetInstance();
this.SerializeCustomAttributeSignature(customAttribute, writer);
result = metadata.GetOrAddBlob(writer);
_customAttributeSignatureIndex.Add(customAttribute, result);
writer.Free();
return result;
}
private EntityHandle GetCustomAttributeTypeCodedIndex(IMethodReference methodReference)
{
IMethodDefinition methodDef = null;
IUnitReference definingUnit = GetDefiningUnitReference(methodReference.GetContainingType(Context), Context);
if (definingUnit != null && ReferenceEquals(definingUnit, this.module))
{
methodDef = methodReference.GetResolvedMethod(Context);
}
return methodDef != null
? (EntityHandle)GetMethodDefinitionHandle(methodDef)
: GetMemberReferenceHandle(methodReference);
}
public static EventAttributes GetEventAttributes(IEventDefinition eventDef)
{
EventAttributes result = 0;
if (eventDef.IsSpecialName)
{
result |= EventAttributes.SpecialName;
}
if (eventDef.IsRuntimeSpecial)
{
result |= EventAttributes.RTSpecialName;
}
return result;
}
public static FieldAttributes GetFieldAttributes(IFieldDefinition fieldDef)
{
var result = (FieldAttributes)fieldDef.Visibility;
if (fieldDef.IsStatic)
{
result |= FieldAttributes.Static;
}
if (fieldDef.IsReadOnly)
{
result |= FieldAttributes.InitOnly;
}
if (fieldDef.IsCompileTimeConstant)
{
result |= FieldAttributes.Literal;
}
if (fieldDef.IsNotSerialized)
{
result |= FieldAttributes.NotSerialized;
}
if (!fieldDef.MappedData.IsDefault)
{
result |= FieldAttributes.HasFieldRVA;
}
if (fieldDef.IsSpecialName)
{
result |= FieldAttributes.SpecialName;
}
if (fieldDef.IsRuntimeSpecial)
{
result |= FieldAttributes.RTSpecialName;
}
if (fieldDef.IsMarshalledExplicitly)
{
result |= FieldAttributes.HasFieldMarshal;
}
if (fieldDef.IsCompileTimeConstant)
{
result |= FieldAttributes.HasDefault;
}
return result;
}
internal BlobHandle GetFieldSignatureIndex(IFieldReference fieldReference)
{
BlobHandle result;
ISpecializedFieldReference specializedFieldReference = fieldReference.AsSpecializedFieldReference;
if (specializedFieldReference != null)
{
fieldReference = specializedFieldReference.UnspecializedVersion;
}
if (_fieldSignatureIndex.TryGetValue(fieldReference, out result))
{
return result;
}
var writer = PooledBlobBuilder.GetInstance();
this.SerializeFieldSignature(fieldReference, writer);
result = metadata.GetOrAddBlob(writer);
_fieldSignatureIndex.Add(fieldReference, result);
writer.Free();
return result;
}
internal EntityHandle GetFieldHandle(IFieldReference fieldReference)
{
IFieldDefinition fieldDef = null;
IUnitReference definingUnit = GetDefiningUnitReference(fieldReference.GetContainingType(Context), Context);
if (definingUnit != null && ReferenceEquals(definingUnit, this.module))
{
fieldDef = fieldReference.GetResolvedField(Context);
}
return fieldDef != null
? (EntityHandle)GetFieldDefinitionHandle(fieldDef)
: GetMemberReferenceHandle(fieldReference);
}
internal AssemblyFileHandle GetAssemblyFileHandle(IFileReference fileReference)
{
string key = fileReference.FileName;
int index;
if (!_fileRefIndex.TryGetValue(key, out index))
{
Debug.Assert(!_tableIndicesAreComplete);
_fileRefList.Add(fileReference);
_fileRefIndex.Add(key, index = _fileRefList.Count);
}
return MetadataTokens.AssemblyFileHandle(index);
}
private AssemblyFileHandle GetAssemblyFileHandle(IModuleReference mref)
{
return MetadataTokens.AssemblyFileHandle(_fileRefIndex[mref.Name]);
}
private static GenericParameterAttributes GetGenericParameterAttributes(IGenericParameter genPar)
{
GenericParameterAttributes result = 0;
switch (genPar.Variance)
{
case TypeParameterVariance.Covariant:
result |= GenericParameterAttributes.Covariant;
break;
case TypeParameterVariance.Contravariant:
result |= GenericParameterAttributes.Contravariant;
break;
}
if (genPar.MustBeReferenceType)
{
result |= GenericParameterAttributes.ReferenceTypeConstraint;
}
if (genPar.MustBeValueType)
{
result |= GenericParameterAttributes.NotNullableValueTypeConstraint;
}
if (genPar.MustHaveDefaultConstructor)
{
result |= GenericParameterAttributes.DefaultConstructorConstraint;
}
return result;
}
private EntityHandle GetExportedTypeImplementation(INamespaceTypeReference namespaceRef)
{
IUnitReference uref = namespaceRef.GetUnit(Context);
var aref = uref as IAssemblyReference;
if (aref != null)
{
return GetAssemblyReferenceHandle(aref);
}
var mref = (IModuleReference)uref;
aref = mref.GetContainingAssembly(Context);
return aref == null || ReferenceEquals(aref, this.module.GetContainingAssembly(Context))
? (EntityHandle)GetAssemblyFileHandle(mref)
: GetAssemblyReferenceHandle(aref);
}
private static uint GetManagedResourceOffset(ManagedResource resource, BlobBuilder resourceWriter)
{
if (resource.ExternalFile != null)
{
return resource.Offset;
}
int result = resourceWriter.Count;
resource.WriteData(resourceWriter);
return (uint)result;
}
private static uint GetManagedResourceOffset(BlobBuilder resource, BlobBuilder resourceWriter)
{
int result = resourceWriter.Count;
resourceWriter.WriteInt32(resource.Count);
resource.WriteContentTo(resourceWriter);
resourceWriter.Align(8);
return (uint)result;
}
public static string GetMangledName(INamedTypeReference namedType)
{
string unmangledName = namedType.Name;
return namedType.MangleName
? MetadataHelpers.ComposeAritySuffixedMetadataName(unmangledName, namedType.GenericParameterCount)
: unmangledName;
}
internal MemberReferenceHandle GetMemberReferenceHandle(ITypeMemberReference memberRef)
{
return this.GetOrAddMemberReferenceHandle(memberRef);
}
internal EntityHandle GetMemberReferenceParent(ITypeMemberReference memberRef)
{
ITypeDefinition parentTypeDef = memberRef.GetContainingType(Context).AsTypeDefinition(Context);
if (parentTypeDef != null)
{
TypeDefinitionHandle parentTypeDefHandle;
TryGetTypeDefinitionHandle(parentTypeDef, out parentTypeDefHandle);
if (!parentTypeDefHandle.IsNil)
{
if (memberRef is IFieldReference)
{
return parentTypeDefHandle;
}
IMethodReference methodRef = memberRef as IMethodReference;
if (methodRef != null)
{
if (methodRef.AcceptsExtraArguments)
{
MethodDefinitionHandle methodHandle;
if (this.TryGetMethodDefinitionHandle(methodRef.GetResolvedMethod(Context), out methodHandle))
{
return methodHandle;
}
}
return parentTypeDefHandle;
}
// TODO: error
}
}
// TODO: special treatment for global fields and methods. Object model support would be nice.
var containingType = memberRef.GetContainingType(Context);
return containingType.IsTypeSpecification()
? (EntityHandle)GetTypeSpecificationHandle(containingType)
: GetTypeReferenceHandle(containingType);
}
internal EntityHandle GetMethodDefinitionOrReferenceHandle(IMethodReference methodReference)
{
IMethodDefinition methodDef = null;
IUnitReference definingUnit = GetDefiningUnitReference(methodReference.GetContainingType(Context), Context);
if (definingUnit != null && ReferenceEquals(definingUnit, this.module))
{
methodDef = methodReference.GetResolvedMethod(Context);
}
return methodDef != null
? (EntityHandle)GetMethodDefinitionHandle(methodDef)
: GetMemberReferenceHandle(methodReference);
}
public static MethodAttributes GetMethodAttributes(IMethodDefinition methodDef)
{
var result = (MethodAttributes)methodDef.Visibility;
if (methodDef.IsStatic)
{
result |= MethodAttributes.Static;
}
if (methodDef.IsSealed)
{
result |= MethodAttributes.Final;
}
if (methodDef.IsVirtual)
{
result |= MethodAttributes.Virtual;
}
if (methodDef.IsHiddenBySignature)
{
result |= MethodAttributes.HideBySig;
}
if (methodDef.IsNewSlot)
{
result |= MethodAttributes.NewSlot;
}
if (methodDef.IsAccessCheckedOnOverride)
{
result |= MethodAttributes.CheckAccessOnOverride;
}
if (methodDef.IsAbstract)
{
result |= MethodAttributes.Abstract;
}
if (methodDef.IsSpecialName)
{
result |= MethodAttributes.SpecialName;
}
if (methodDef.IsRuntimeSpecial)
{
result |= MethodAttributes.RTSpecialName;
}
if (methodDef.IsPlatformInvoke)
{
result |= MethodAttributes.PinvokeImpl;
}
if (methodDef.HasDeclarativeSecurity)
{
result |= MethodAttributes.HasSecurity;
}
if (methodDef.RequiresSecurityObject)
{
result |= MethodAttributes.RequireSecObject;
}
return result;
}
internal BlobHandle GetMethodSpecificationSignatureHandle(IGenericMethodInstanceReference methodInstanceReference)
{
BlobHandle result;
if (_methodInstanceSignatureIndex.TryGetValue(methodInstanceReference, out result))
{
return result;
}
var builder = PooledBlobBuilder.GetInstance();
var encoder = new BlobEncoder(builder).MethodSpecificationSignature(methodInstanceReference.GetGenericMethod(Context).GenericParameterCount);
foreach (ITypeReference typeReference in methodInstanceReference.GetGenericArguments(Context))
{
var typeRef = typeReference;
SerializeTypeReference(encoder.AddArgument(), typeRef);
}
result = metadata.GetOrAddBlob(builder);
_methodInstanceSignatureIndex.Add(methodInstanceReference, result);
builder.Free();
return result;
}
private BlobHandle GetMarshallingDescriptorHandle(IMarshallingInformation marshallingInformation)
{
BlobHandle result;
if (_marshallingDescriptorIndex.TryGetValue(marshallingInformation, out result))
{
return result;
}
var writer = PooledBlobBuilder.GetInstance();
this.SerializeMarshallingDescriptor(marshallingInformation, writer);
result = metadata.GetOrAddBlob(writer);
_marshallingDescriptorIndex.Add(marshallingInformation, result);
writer.Free();
return result;
}
private BlobHandle GetMarshallingDescriptorHandle(ImmutableArray<byte> descriptor)
{
return metadata.GetOrAddBlob(descriptor);
}
private BlobHandle GetMemberReferenceSignatureHandle(ITypeMemberReference memberRef)
{
IFieldReference fieldReference = memberRef as IFieldReference;
if (fieldReference != null)
{
return this.GetFieldSignatureIndex(fieldReference);
}
IMethodReference methodReference = memberRef as IMethodReference;
if (methodReference != null)
{
return this.GetMethodSignatureHandle(methodReference);
}
throw ExceptionUtilities.Unreachable;
}
internal BlobHandle GetMethodSignatureHandle(IMethodReference methodReference)
{
ImmutableArray<byte> signatureBlob;
return GetMethodSignatureHandleAndBlob(methodReference, out signatureBlob);
}
internal byte[] GetMethodSignature(IMethodReference methodReference)
{
ImmutableArray<byte> signatureBlob;
GetMethodSignatureHandleAndBlob(methodReference, out signatureBlob);
return signatureBlob.ToArray();
}
private BlobHandle GetMethodSignatureHandleAndBlob(IMethodReference methodReference, out ImmutableArray<byte> signatureBlob)
{
BlobHandle result;
ISpecializedMethodReference specializedMethodReference = methodReference.AsSpecializedMethodReference;
if (specializedMethodReference != null)
{
methodReference = specializedMethodReference.UnspecializedVersion;
}
KeyValuePair<BlobHandle, ImmutableArray<byte>> existing;
if (_signatureIndex.TryGetValue(methodReference, out existing))
{
signatureBlob = existing.Value;
return existing.Key;
}
Debug.Assert((methodReference.CallingConvention & CallingConvention.Generic) != 0 == (methodReference.GenericParameterCount > 0));
var builder = PooledBlobBuilder.GetInstance();
var encoder = new BlobEncoder(builder).MethodSignature(
new SignatureHeader((byte)methodReference.CallingConvention).CallingConvention,
methodReference.GenericParameterCount,
isInstanceMethod: (methodReference.CallingConvention & CallingConvention.HasThis) != 0);
SerializeReturnValueAndParameters(encoder, methodReference, methodReference.ExtraParameters);
signatureBlob = builder.ToImmutableArray();
result = metadata.GetOrAddBlob(signatureBlob);
_signatureIndex.Add(methodReference, KeyValuePairUtil.Create(result, signatureBlob));
builder.Free();
return result;
}
private BlobHandle GetMethodSpecificationBlobHandle(IGenericMethodInstanceReference genericMethodInstanceReference)
{
var writer = PooledBlobBuilder.GetInstance();
SerializeMethodSpecificationSignature(writer, genericMethodInstanceReference);
BlobHandle result = metadata.GetOrAddBlob(writer);
writer.Free();
return result;
}
private MethodSpecificationHandle GetMethodSpecificationHandle(IGenericMethodInstanceReference methodSpec)
{
return this.GetOrAddMethodSpecificationHandle(methodSpec);
}
internal EntityHandle GetMethodHandle(IMethodReference methodReference)
{
MethodDefinitionHandle methodDefHandle;
IMethodDefinition methodDef = null;
IUnitReference definingUnit = GetDefiningUnitReference(methodReference.GetContainingType(Context), Context);
if (definingUnit != null && ReferenceEquals(definingUnit, this.module))
{
methodDef = methodReference.GetResolvedMethod(Context);
}
if (methodDef != null && (methodReference == methodDef || !methodReference.AcceptsExtraArguments) && this.TryGetMethodDefinitionHandle(methodDef, out methodDefHandle))
{
return methodDefHandle;
}
IGenericMethodInstanceReference methodSpec = methodReference.AsGenericMethodInstanceReference;
return methodSpec != null
? (EntityHandle)GetMethodSpecificationHandle(methodSpec)
: GetMemberReferenceHandle(methodReference);
}
public static ParameterAttributes GetParameterAttributes(IParameterDefinition parDef)
{
ParameterAttributes result = 0;
if (parDef.IsIn)
{
result |= ParameterAttributes.In;
}
if (parDef.IsOut)
{
result |= ParameterAttributes.Out;
}
if (parDef.IsOptional)
{
result |= ParameterAttributes.Optional;
}
if (parDef.HasDefaultValue)
{
result |= ParameterAttributes.HasDefault;
}
if (parDef.IsMarshalledExplicitly)
{
result |= ParameterAttributes.HasFieldMarshal;
}
return result;
}
private BlobHandle GetPermissionSetBlobHandle(ImmutableArray<ICustomAttribute> permissionSet)
{
var writer = PooledBlobBuilder.GetInstance();
BlobHandle result;
try
{
writer.WriteByte((byte)'.');
writer.WriteCompressedInteger(permissionSet.Length);
this.SerializePermissionSet(permissionSet, writer);
result = metadata.GetOrAddBlob(writer);
}
finally
{
writer.Free();
}
return result;
}
public static PropertyAttributes GetPropertyAttributes(IPropertyDefinition propertyDef)
{
PropertyAttributes result = 0;
if (propertyDef.IsSpecialName)
{
result |= PropertyAttributes.SpecialName;
}
if (propertyDef.IsRuntimeSpecial)
{
result |= PropertyAttributes.RTSpecialName;
}
if (propertyDef.HasDefaultValue)
{
result |= PropertyAttributes.HasDefault;
}
return result;
}
private BlobHandle GetPropertySignatureHandle(IPropertyDefinition propertyDef)
{
KeyValuePair<BlobHandle, ImmutableArray<byte>> existing;
if (_signatureIndex.TryGetValue(propertyDef, out existing))
{
return existing.Key;
}
var builder = PooledBlobBuilder.GetInstance();
var encoder = new BlobEncoder(builder).PropertySignature(
isInstanceProperty: (propertyDef.CallingConvention & CallingConvention.HasThis) != 0);
SerializeReturnValueAndParameters(encoder, propertyDef, ImmutableArray<IParameterTypeInformation>.Empty);
var blob = builder.ToImmutableArray();
var result = metadata.GetOrAddBlob(blob);
_signatureIndex.Add(propertyDef, KeyValuePairUtil.Create(result, blob));
builder.Free();
return result;
}
private EntityHandle GetResolutionScopeHandle(IUnitReference unitReference)
{
var aref = unitReference as IAssemblyReference;
if (aref != null)
{
return GetAssemblyReferenceHandle(aref);
}
// If this is a module from a referenced multi-module assembly,
// the assembly should be used as the resolution scope.
var mref = (IModuleReference)unitReference;
aref = mref.GetContainingAssembly(Context);
if (aref != null && aref != module.GetContainingAssembly(Context))
{
return GetAssemblyReferenceHandle(aref);
}
return GetModuleReferenceHandle(mref.Name);
}
private StringHandle GetStringHandleForPathAndCheckLength(string path, INamedEntity errorEntity = null)
{
CheckPathLength(path, errorEntity);
return metadata.GetOrAddString(path);
}
private StringHandle GetStringHandleForNameAndCheckLength(string name, INamedEntity errorEntity = null)
{
CheckNameLength(name, errorEntity);
return metadata.GetOrAddString(name);
}
/// <summary>
/// The Microsoft CLR requires that {namespace} + "." + {name} fit in MAX_CLASS_NAME
/// (even though the name and namespace are stored separately in the Microsoft
/// implementation). Note that the namespace name of a nested type is always blank
/// (since comes from the container).
/// </summary>
/// <param name="namespaceType">We're trying to add the containing namespace of this type to the string heap.</param>
/// <param name="mangledTypeName">Namespace names are never used on their own - this is the type that is adding the namespace name.
/// Used only for length checking.</param>
private StringHandle GetStringHandleForNamespaceAndCheckLength(INamespaceTypeReference namespaceType, string mangledTypeName)
{
string namespaceName = namespaceType.NamespaceName;
if (namespaceName.Length == 0) // Optimization: CheckNamespaceLength is relatively expensive.
{
return default(StringHandle);
}
CheckNamespaceLength(namespaceName, mangledTypeName, namespaceType);
return metadata.GetOrAddString(namespaceName);
}
private void CheckNameLength(string name, INamedEntity errorEntity)
{
// NOTE: ildasm shows quotes around some names (e.g. explicit implementations of members of generic interfaces)
// but that seems to be tool-specific - they don't seem to and up in the string heap (so they don't count against
// the length limit).
if (IsTooLongInternal(name, NameLengthLimit))
{
Location location = GetNamedEntityLocation(errorEntity);
this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.ERR_MetadataNameTooLong, location, name));
}
}
private void CheckPathLength(string path, INamedEntity errorEntity = null)
{
if (IsTooLongInternal(path, PathLengthLimit))
{
Location location = GetNamedEntityLocation(errorEntity);
this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.ERR_MetadataNameTooLong, location, path));
}
}
private void CheckNamespaceLength(string namespaceName, string mangledTypeName, INamespaceTypeReference errorEntity)
{
// It's never useful to report that the namespace name is too long.
// If it's too long, then the full name is too long and that string is
// more helpful.
// PERF: We expect to check this A LOT, so we'll aggressively inline some
// of the helpers (esp IsTooLongInternal) in a way that allows us to forego
// string concatenation (unless a diagnostic is actually reported).
if (namespaceName.Length + 1 + mangledTypeName.Length > NameLengthLimit / 3)
{
int utf8Length =
s_utf8Encoding.GetByteCount(namespaceName) +
1 + // dot
s_utf8Encoding.GetByteCount(mangledTypeName);
if (utf8Length > NameLengthLimit)
{
Location location = GetNamedEntityLocation(errorEntity);
this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.ERR_MetadataNameTooLong, location, namespaceName + "." + mangledTypeName));
}
}
}
internal bool IsUsingStringTooLong(string usingString, INamedEntity errorEntity = null)
{
if (IsTooLongInternal(usingString, PdbLengthLimit))
{
Location location = GetNamedEntityLocation(errorEntity);
this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.WRN_PdbUsingNameTooLong, location, usingString));
return true;
}
return false;
}
internal bool IsLocalNameTooLong(ILocalDefinition localDefinition)
{
string name = localDefinition.Name;
if (IsTooLongInternal(name, PdbLengthLimit))
{
this.Context.Diagnostics.Add(this.messageProvider.CreateDiagnostic(this.messageProvider.WRN_PdbLocalNameTooLong, localDefinition.Location, name));
return true;
}
return false;
}
/// <summary>
/// Test the given name to see if it fits in metadata.
/// </summary>
/// <param name="str">String to test (non-null).</param>
/// <param name="maxLength">Max length for name. (Expected to be at least 5.)</param>
/// <returns>True if the name is too long.</returns>
/// <remarks>Internal for test purposes.</remarks>
internal static bool IsTooLongInternal(string str, int maxLength)
{
Debug.Assert(str != null); // No need to handle in an internal utility.
if (str.Length < maxLength / 3) //UTF-8 uses at most 3 bytes per char
{
return false;
}
int utf8Length = s_utf8Encoding.GetByteCount(str);
return utf8Length > maxLength;
}
private static Location GetNamedEntityLocation(INamedEntity errorEntity)
{
return GetSymbolLocation(errorEntity as ISymbol);
}
protected static Location GetSymbolLocation(ISymbol symbolOpt)
{
return symbolOpt != null && !symbolOpt.Locations.IsDefaultOrEmpty ? symbolOpt.Locations[0] : Location.None;
}
internal TypeAttributes GetTypeAttributes(ITypeDefinition typeDef)
{
return GetTypeAttributes(typeDef, Context);
}
public static TypeAttributes GetTypeAttributes(ITypeDefinition typeDef, EmitContext context)
{
TypeAttributes result = 0;
switch (typeDef.Layout)
{
case LayoutKind.Sequential:
result |= TypeAttributes.SequentialLayout;
break;
case LayoutKind.Explicit:
result |= TypeAttributes.ExplicitLayout;
break;
}
if (typeDef.IsInterface)
{
result |= TypeAttributes.Interface;
}
if (typeDef.IsAbstract)
{
result |= TypeAttributes.Abstract;
}
if (typeDef.IsSealed)
{
result |= TypeAttributes.Sealed;
}
if (typeDef.IsSpecialName)
{
result |= TypeAttributes.SpecialName;
}
if (typeDef.IsRuntimeSpecial)
{
result |= TypeAttributes.RTSpecialName;
}
if (typeDef.IsComObject)
{
result |= TypeAttributes.Import;
}
if (typeDef.IsSerializable)
{
result |= TypeAttributes.Serializable;
}
if (typeDef.IsWindowsRuntimeImport)
{
result |= TypeAttributes.WindowsRuntime;
}
switch (typeDef.StringFormat)
{
case CharSet.Unicode:
result |= TypeAttributes.UnicodeClass;
break;
case Constants.CharSet_Auto:
result |= TypeAttributes.AutoClass;
break;
}
if (typeDef.HasDeclarativeSecurity)
{
result |= TypeAttributes.HasSecurity;
}
if (typeDef.IsBeforeFieldInit)
{
result |= TypeAttributes.BeforeFieldInit;
}
INestedTypeDefinition nestedTypeDef = typeDef.AsNestedTypeDefinition(context);
if (nestedTypeDef != null)
{
switch (((ITypeDefinitionMember)typeDef).Visibility)
{
case TypeMemberVisibility.Public:
result |= TypeAttributes.NestedPublic;
break;
case TypeMemberVisibility.Private:
result |= TypeAttributes.NestedPrivate;
break;
case TypeMemberVisibility.Family:
result |= TypeAttributes.NestedFamily;
break;
case TypeMemberVisibility.Assembly:
result |= TypeAttributes.NestedAssembly;
break;
case TypeMemberVisibility.FamilyAndAssembly:
result |= TypeAttributes.NestedFamANDAssem;
break;
case TypeMemberVisibility.FamilyOrAssembly:
result |= TypeAttributes.NestedFamORAssem;
break;
}
return result;
}
INamespaceTypeDefinition namespaceTypeDef = typeDef.AsNamespaceTypeDefinition(context);
if (namespaceTypeDef != null && namespaceTypeDef.IsPublic)
{
result |= TypeAttributes.Public;
}
return result;
}
private EntityHandle GetDeclaringTypeOrMethodHandle(IGenericParameter genPar)
{
IGenericTypeParameter genTypePar = genPar.AsGenericTypeParameter;
if (genTypePar != null)
{
return GetTypeDefinitionHandle(genTypePar.DefiningType);
}
IGenericMethodParameter genMethPar = genPar.AsGenericMethodParameter;
if (genMethPar != null)
{
return GetMethodDefinitionHandle(genMethPar.DefiningMethod);
}
throw ExceptionUtilities.Unreachable;
}
private TypeReferenceHandle GetTypeReferenceHandle(ITypeReference typeReference)
{
TypeReferenceHandle result;
if (this.TryGetTypeReferenceHandle(typeReference, out result))
{
return result;
}
// NOTE: Even though CLR documentation does not explicitly specify any requirements
// NOTE: to the order of records in TypeRef table, some tools and/or APIs (e.g.
// NOTE: IMetaDataEmit::MergeEnd) assume that the containing type referenced as
// NOTE: ResolutionScope for its nested types should appear in TypeRef table
// NOTE: *before* any of its nested types.
// SEE ALSO: bug#570975 and test Bug570975()
INestedTypeReference nestedTypeRef = typeReference.AsNestedTypeReference;
if (nestedTypeRef != null)
{
GetTypeReferenceHandle(nestedTypeRef.GetContainingType(this.Context));
}
return this.GetOrAddTypeReferenceHandle(typeReference);
}
private TypeSpecificationHandle GetTypeSpecificationHandle(ITypeReference typeReference)
{
return this.GetOrAddTypeSpecificationHandle(typeReference);
}
internal ITypeDefinition GetTypeDefinition(int token)
{
// The token must refer to a TypeDef row since we are
// only handling indexes into the full metadata (in EnC)
// for def tables. Other tables contain deltas only.
return GetTypeDef(MetadataTokens.TypeDefinitionHandle(token));
}
internal IMethodDefinition GetMethodDefinition(int token)
{
// Must be a def table. (See comment in GetTypeDefinition.)
return GetMethodDef(MetadataTokens.MethodDefinitionHandle(token));
}
internal INestedTypeReference GetNestedTypeReference(int token)
{
// Must be a def table. (See comment in GetTypeDefinition.)
return GetTypeDef(MetadataTokens.TypeDefinitionHandle(token)).AsNestedTypeReference;
}
internal BlobHandle GetTypeSpecSignatureIndex(ITypeReference typeReference)
{
BlobHandle result;
if (_typeSpecSignatureIndex.TryGetValue(typeReference, out result))
{
return result;
}
var builder = PooledBlobBuilder.GetInstance();
this.SerializeTypeReference(new BlobEncoder(builder).TypeSpecificationSignature(), typeReference);
result = metadata.GetOrAddBlob(builder);
_typeSpecSignatureIndex.Add(typeReference, result);
builder.Free();
return result;
}
internal EntityHandle GetTypeHandle(ITypeReference typeReference, bool treatRefAsPotentialTypeSpec = true)
{
TypeDefinitionHandle handle;
var typeDefinition = typeReference.AsTypeDefinition(this.Context);
if (typeDefinition != null && this.TryGetTypeDefinitionHandle(typeDefinition, out handle))
{
return handle;
}
return treatRefAsPotentialTypeSpec && typeReference.IsTypeSpecification()
? (EntityHandle)GetTypeSpecificationHandle(typeReference)
: GetTypeReferenceHandle(typeReference);
}
internal EntityHandle GetDefinitionHandle(IDefinition definition)
{
ITypeDefinition typeDef = definition as ITypeDefinition;
if (typeDef != null)
{
return GetTypeDefinitionHandle(typeDef);
}
IMethodDefinition methodDef = definition as IMethodDefinition;
if (methodDef != null)
{
return GetMethodDefinitionHandle(methodDef);
}
IFieldDefinition fieldDef = definition as IFieldDefinition;
if (fieldDef != null)
{
return GetFieldDefinitionHandle(fieldDef);
}
IEventDefinition eventDef = definition as IEventDefinition;
if (eventDef != null)
{
return GetEventDefinitionHandle(eventDef);
}
IPropertyDefinition propertyDef = definition as IPropertyDefinition;
if (propertyDef != null)
{
return GetPropertyDefIndex(propertyDef);
}
throw ExceptionUtilities.Unreachable;
}
public void WriteMetadataAndIL(PdbWriter nativePdbWriterOpt, Stream metadataStream, Stream ilStream, Stream portablePdbStreamOpt, out MetadataSizes metadataSizes)
{
Debug.Assert(nativePdbWriterOpt == null ^ portablePdbStreamOpt == null);
nativePdbWriterOpt?.SetMetadataEmitter(this);
// TODO: we can precalculate the exact size of IL stream
var ilBuilder = new BlobBuilder(1024);
var metadataBuilder = new BlobBuilder(4 * 1024);
var mappedFieldDataBuilder = new BlobBuilder(0);
var managedResourceDataBuilder = new BlobBuilder(0);
// Add 4B of padding to the start of the separated IL stream,
// so that method RVAs, which are offsets to this stream, are never 0.
ilBuilder.WriteUInt32(0);
// this is used to handle edit-and-continue emit, so we should have a module
// version ID that is imposed by the caller (the same as the previous module version ID).
// Therefore we do not have to fill in a new module version ID in the generated metadata
// stream.
Debug.Assert(module.SerializationProperties.PersistentIdentifier != default(Guid));
BuildMetadataAndIL(
nativePdbWriterOpt,
ilBuilder,
mappedFieldDataBuilder,
managedResourceDataBuilder,
out Blob mvidFixup,
out Blob mvidStringFixup);
var typeSystemRowCounts = metadata.GetRowCounts();
PopulateEncTables(typeSystemRowCounts);
Debug.Assert(mappedFieldDataBuilder.Count == 0);
Debug.Assert(managedResourceDataBuilder.Count == 0);
Debug.Assert(mvidFixup.IsDefault);
Debug.Assert(mvidStringFixup.IsDefault);
// TODO (https://github.com/dotnet/roslyn/issues/3905):
// InterfaceImpl table emitted by Roslyn is not compliant with ECMA spec.
// Once fixed enable validation in DEBUG builds.
var rootBuilder = new MetadataRootBuilder(metadata, module.SerializationProperties.TargetRuntimeVersion, suppressValidation: true);
rootBuilder.Serialize(metadataBuilder, methodBodyStreamRva: 0, mappedFieldDataStreamRva: 0);
metadataSizes = rootBuilder.Sizes;
try
{
ilBuilder.WriteContentTo(ilStream);
metadataBuilder.WriteContentTo(metadataStream);
}
catch (Exception e) when (!(e is OperationCanceledException))
{
throw new PeWritingException(e);
}
if (portablePdbStreamOpt != null)
{
var portablePdbBuilder = GetPortablePdbBuilder(
typeSystemRowCounts,
debugEntryPoint: default(MethodDefinitionHandle),
deterministicIdProviderOpt: null);
var portablePdbBlob = new BlobBuilder();
portablePdbBuilder.Serialize(portablePdbBlob);
try
{
portablePdbBlob.WriteContentTo(portablePdbStreamOpt);
}
catch (Exception e) when (!(e is OperationCanceledException))
{
throw new SymUnmanagedWriterException(e.Message, e);
}
}
}
public void BuildMetadataAndIL(
PdbWriter nativePdbWriterOpt,
BlobBuilder ilBuilder,
BlobBuilder mappedFieldDataBuilder,
BlobBuilder managedResourceDataBuilder,
out Blob mvidFixup,
out Blob mvidStringFixup)
{
// Extract information from object model into tables, indices and streams
CreateIndices();
if (_debugMetadataOpt != null)
{
DefineModuleImportScope();
if (module.SourceLinkStreamOpt != null)
{
EmbedSourceLink(module.SourceLinkStreamOpt);
}
}
int[] methodBodyOffsets;
if (MetadataOnly)
{
methodBodyOffsets = SerializeThrowNullMethodBodies(ilBuilder);
mvidStringFixup = default(Blob);
}
else
{
methodBodyOffsets = SerializeMethodBodies(ilBuilder, nativePdbWriterOpt, out mvidStringFixup);
}
_cancellationToken.ThrowIfCancellationRequested();
// method body serialization adds Stand Alone Signatures
_tableIndicesAreComplete = true;
ReportReferencesToAddedSymbols();
BlobBuilder dynamicAnalysisDataOpt = null;
if (_dynamicAnalysisDataWriterOpt != null)
{
dynamicAnalysisDataOpt = new BlobBuilder();
_dynamicAnalysisDataWriterOpt.SerializeMetadataTables(dynamicAnalysisDataOpt);
}
PopulateTypeSystemTables(methodBodyOffsets, mappedFieldDataBuilder, managedResourceDataBuilder, dynamicAnalysisDataOpt, out mvidFixup);
}
public void PopulateEncTables(ImmutableArray<int> typeSystemRowCounts)
{
Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncLog] == 0);
Debug.Assert(typeSystemRowCounts[(int)TableIndex.EncMap] == 0);
PopulateEncLogTableRows(typeSystemRowCounts);
PopulateEncMapTableRows(typeSystemRowCounts);
}
public MetadataRootBuilder GetRootBuilder()
{
// TODO (https://github.com/dotnet/roslyn/issues/3905):
// InterfaceImpl table emitted by Roslyn is not compliant with ECMA spec.
// Once fixed enable validation in DEBUG builds.
return new MetadataRootBuilder(metadata, module.SerializationProperties.TargetRuntimeVersion, suppressValidation: true);
}
public PortablePdbBuilder GetPortablePdbBuilder(ImmutableArray<int> typeSystemRowCounts, MethodDefinitionHandle debugEntryPoint, Func<IEnumerable<Blob>, BlobContentId> deterministicIdProviderOpt)
{
return new PortablePdbBuilder(_debugMetadataOpt, typeSystemRowCounts, debugEntryPoint, deterministicIdProviderOpt);
}
internal void GetEntryPoints(out MethodDefinitionHandle entryPointHandle, out MethodDefinitionHandle debugEntryPointHandle)
{
if (IsFullMetadata && !MetadataOnly)
{
// PE entry point is set for executable programs
IMethodReference entryPoint = module.PEEntryPoint;
entryPointHandle = entryPoint != null ? (MethodDefinitionHandle)GetMethodHandle((IMethodDefinition)entryPoint.AsDefinition(Context)) : default(MethodDefinitionHandle);
// debug entry point may be different from PE entry point, it may also be set for libraries
IMethodReference debugEntryPoint = module.DebugEntryPoint;
if (debugEntryPoint != null && debugEntryPoint != entryPoint)
{
debugEntryPointHandle = (MethodDefinitionHandle)GetMethodHandle((IMethodDefinition)debugEntryPoint.AsDefinition(Context));
}
else
{
debugEntryPointHandle = entryPointHandle;
}
}
else
{
entryPointHandle = debugEntryPointHandle = default(MethodDefinitionHandle);
}
}
private ImmutableArray<IGenericParameter> GetSortedGenericParameters()
{
return GetGenericParameters().OrderBy((x, y) =>
{
// Spec: GenericParam table is sorted by Owner and then by Number.
int result = CodedIndex.TypeOrMethodDef(GetDeclaringTypeOrMethodHandle(x)) - CodedIndex.TypeOrMethodDef(GetDeclaringTypeOrMethodHandle(y));
if (result != 0)
{
return result;
}
return x.Index - y.Index;
}).ToImmutableArray();
}
private void PopulateTypeSystemTables(int[] methodBodyOffsets, BlobBuilder mappedFieldDataWriter, BlobBuilder resourceWriter, BlobBuilder dynamicAnalysisDataOpt, out Blob mvidFixup)
{
var sortedGenericParameters = GetSortedGenericParameters();
this.PopulateAssemblyRefTableRows();
this.PopulateAssemblyTableRows();
this.PopulateClassLayoutTableRows();
this.PopulateConstantTableRows();
this.PopulateDeclSecurityTableRows();
this.PopulateEventMapTableRows();
this.PopulateEventTableRows();
this.PopulateExportedTypeTableRows();
this.PopulateFieldLayoutTableRows();
this.PopulateFieldMarshalTableRows();
this.PopulateFieldRvaTableRows(mappedFieldDataWriter);
this.PopulateFieldTableRows();
this.PopulateFileTableRows();
this.PopulateGenericParameters(sortedGenericParameters);
this.PopulateImplMapTableRows();
this.PopulateInterfaceImplTableRows();
this.PopulateManifestResourceTableRows(resourceWriter, dynamicAnalysisDataOpt);
this.PopulateMemberRefTableRows();
this.PopulateMethodImplTableRows();
this.PopulateMethodTableRows(methodBodyOffsets);
this.PopulateMethodSemanticsTableRows();
this.PopulateMethodSpecTableRows();
this.PopulateModuleRefTableRows();
this.PopulateModuleTableRow(out mvidFixup);
this.PopulateNestedClassTableRows();
this.PopulateParamTableRows();
this.PopulatePropertyMapTableRows();
this.PopulatePropertyTableRows();
this.PopulateTypeDefTableRows();
this.PopulateTypeRefTableRows();
this.PopulateTypeSpecTableRows();
this.PopulateStandaloneSignatures();
// This table is populated after the others because it depends on the order of the entries of the generic parameter table.
this.PopulateCustomAttributeTableRows(sortedGenericParameters);
}
private void PopulateAssemblyRefTableRows()
{
var assemblyRefs = this.GetAssemblyRefs();
metadata.SetCapacity(TableIndex.AssemblyRef, assemblyRefs.Count);
foreach (var identity in assemblyRefs)
{
// reference has token, not full public key
metadata.AddAssemblyReference(
name: GetStringHandleForPathAndCheckLength(identity.Name),
version: identity.Version,
culture: metadata.GetOrAddString(identity.CultureName),
publicKeyOrToken: metadata.GetOrAddBlob(identity.PublicKeyToken),
flags: (AssemblyFlags)((int)identity.ContentType << 9) | (identity.IsRetargetable ? AssemblyFlags.Retargetable : 0),
hashValue: default(BlobHandle));
}
}
private void PopulateAssemblyTableRows()
{
if (!EmitAssemblyDefinition)
{
return;
}
var sourceAssembly = module.SourceAssemblyOpt;
Debug.Assert(sourceAssembly != null);
var flags = sourceAssembly.AssemblyFlags & ~AssemblyFlags.PublicKey;
if (!sourceAssembly.Identity.PublicKey.IsDefaultOrEmpty)
{
flags |= AssemblyFlags.PublicKey;
}
metadata.AddAssembly(
flags: flags,
hashAlgorithm: sourceAssembly.HashAlgorithm,
version: sourceAssembly.Identity.Version,
publicKey: metadata.GetOrAddBlob(sourceAssembly.Identity.PublicKey),
name: GetStringHandleForPathAndCheckLength(module.Name, module),
culture: metadata.GetOrAddString(sourceAssembly.Identity.CultureName));
}
private void PopulateCustomAttributeTableRows(ImmutableArray<IGenericParameter> sortedGenericParameters)
{
if (this.IsFullMetadata)
{
this.AddAssemblyAttributesToTable();
}
this.AddCustomAttributesToTable(GetMethodDefs(), def => GetMethodDefinitionHandle(def));
this.AddCustomAttributesToTable(GetFieldDefs(), def => GetFieldDefinitionHandle(def));
// this.AddCustomAttributesToTable(this.typeRefList, 2);
var typeDefs = GetTypeDefs();
this.AddCustomAttributesToTable(typeDefs, def => GetTypeDefinitionHandle(def));
this.AddCustomAttributesToTable(GetParameterDefs(), def => GetParameterHandle(def));
// TODO: attributes on member reference entries 6
if (this.IsFullMetadata)
{
this.AddModuleAttributesToTable(module);
}
// TODO: declarative security entries 8
this.AddCustomAttributesToTable(GetPropertyDefs(), def => GetPropertyDefIndex(def));
this.AddCustomAttributesToTable(GetEventDefs(), def => GetEventDefinitionHandle(def));
// TODO: standalone signature entries 11
// TODO: type spec entries 13
// this.AddCustomAttributesToTable(this.module.AssemblyReferences, 15);
// TODO: this.AddCustomAttributesToTable(assembly.Files, 16);
// TODO: exported types 17
// TODO: this.AddCustomAttributesToTable(assembly.Resources, 18);
this.AddCustomAttributesToTable(sortedGenericParameters, TableIndex.GenericParam);
}
private void AddAssemblyAttributesToTable()
{
bool writingNetModule = module.OutputKind == OutputKind.NetModule;
if (writingNetModule)
{
// When writing netmodules, assembly security attributes are not emitted by PopulateDeclSecurityTableRows().
// Instead, here we make sure they are emitted as regular attributes, attached off the appropriate placeholder
// System.Runtime.CompilerServices.AssemblyAttributesGoHere* type refs. This is the contract for publishing
// assembly attributes in netmodules so they may be migrated to containing/referencing multi-module assemblies,
// at multi-module assembly build time.
AddAssemblyAttributesToTable(
this.module.GetSourceAssemblySecurityAttributes().Select(sa => sa.Attribute),
needsDummyParent: true,
isSecurity: true);
}
AddAssemblyAttributesToTable(
this.module.GetSourceAssemblyAttributes(Context.IsRefAssembly),
needsDummyParent: writingNetModule,
isSecurity: false);
}
private void AddAssemblyAttributesToTable(IEnumerable<ICustomAttribute> assemblyAttributes, bool needsDummyParent, bool isSecurity)
{
Debug.Assert(this.IsFullMetadata); // parentToken is not relative
EntityHandle parentHandle = Handle.AssemblyDefinition;
foreach (ICustomAttribute customAttribute in assemblyAttributes)
{
if (needsDummyParent)
{
// When writing netmodules, assembly attributes are attached off the appropriate placeholder
// System.Runtime.CompilerServices.AssemblyAttributesGoHere* type refs. This is the contract for publishing
// assembly attributes in netmodules so they may be migrated to containing/referencing multi-module assemblies,
// at multi-module assembly build time.
parentHandle = GetDummyAssemblyAttributeParent(isSecurity, customAttribute.AllowMultiple);
}
AddCustomAttributeToTable(parentHandle, customAttribute);
}
}
private TypeReferenceHandle GetDummyAssemblyAttributeParent(bool isSecurity, bool allowMultiple)
{
// Lazily get or create placeholder assembly attribute parent type ref for the given combination of
// whether isSecurity and allowMultiple. Convert type ref row id to corresponding attribute parent tag.
// Note that according to the defacto contract, although the placeholder type refs have CorLibrary as their
// resolution scope, the types backing the placeholder type refs need not actually exist.
int iS = isSecurity ? 1 : 0;
int iM = allowMultiple ? 1 : 0;
if (_dummyAssemblyAttributeParent[iS, iM].IsNil)
{
_dummyAssemblyAttributeParent[iS, iM] = metadata.AddTypeReference(
resolutionScope: GetResolutionScopeHandle(module.GetCorLibrary(Context)),
@namespace: metadata.GetOrAddString(dummyAssemblyAttributeParentNamespace),
name: metadata.GetOrAddString(dummyAssemblyAttributeParentName + dummyAssemblyAttributeParentQualifier[iS, iM]));
}
return _dummyAssemblyAttributeParent[iS, iM];
}
private void AddModuleAttributesToTable(CommonPEModuleBuilder module)
{
Debug.Assert(this.IsFullMetadata);
foreach (ICustomAttribute customAttribute in module.GetSourceModuleAttributes())
{
AddCustomAttributeToTable(EntityHandle.ModuleDefinition, customAttribute);
}
}
private void AddCustomAttributesToTable<T>(IEnumerable<T> parentList, TableIndex tableIndex)
where T : IReference
{
int parentRowId = 1;
foreach (var parent in parentList)
{
var parentHandle = MetadataTokens.Handle(tableIndex, parentRowId++);
foreach (ICustomAttribute customAttribute in parent.GetAttributes(Context))
{
AddCustomAttributeToTable(parentHandle, customAttribute);
}
}
}
private void AddCustomAttributesToTable<T>(IEnumerable<T> parentList, Func<T, EntityHandle> getDefinitionHandle)
where T : IReference
{
foreach (var parent in parentList)
{
EntityHandle parentHandle = getDefinitionHandle(parent);
foreach (ICustomAttribute customAttribute in parent.GetAttributes(Context))
{
AddCustomAttributeToTable(parentHandle, customAttribute);
}
}
}
private void AddCustomAttributesToTable(
EntityHandle handle,
ImmutableArray<ICustomAttribute> attributes)
{
foreach (var attr in attributes)
{
AddCustomAttributeToTable(handle, attr);
}
}
private void AddCustomAttributesToTable(IEnumerable<TypeReferenceWithAttributes> typeRefsWithAttributes)
{
foreach (var typeRefWithAttributes in typeRefsWithAttributes)
{
var ifaceHandle = GetTypeHandle(typeRefWithAttributes.TypeRef);
foreach (var customAttribute in typeRefWithAttributes.Attributes)
{
AddCustomAttributeToTable(ifaceHandle, customAttribute);
}
}
}
private void AddCustomAttributeToTable(EntityHandle parentHandle, ICustomAttribute customAttribute)
{
IMethodReference constructor = customAttribute.Constructor(Context, reportDiagnostics: true);
if (constructor != null)
{
metadata.AddCustomAttribute(
parent: parentHandle,
constructor: GetCustomAttributeTypeCodedIndex(constructor),
value: GetCustomAttributeSignatureIndex(customAttribute));
}
}
private void PopulateDeclSecurityTableRows()
{
if (module.OutputKind != OutputKind.NetModule)
{
this.PopulateDeclSecurityTableRowsFor(EntityHandle.AssemblyDefinition, module.GetSourceAssemblySecurityAttributes());
}
foreach (ITypeDefinition typeDef in this.GetTypeDefs())
{
if (!typeDef.HasDeclarativeSecurity)
{
continue;
}
this.PopulateDeclSecurityTableRowsFor(GetTypeDefinitionHandle(typeDef), typeDef.SecurityAttributes);
}
foreach (IMethodDefinition methodDef in this.GetMethodDefs())
{
if (!methodDef.HasDeclarativeSecurity)
{
continue;
}
this.PopulateDeclSecurityTableRowsFor(GetMethodDefinitionHandle(methodDef), methodDef.SecurityAttributes);
}
}
private void PopulateDeclSecurityTableRowsFor(EntityHandle parentHandle, IEnumerable<SecurityAttribute> attributes)
{
OrderPreservingMultiDictionary<DeclarativeSecurityAction, ICustomAttribute> groupedSecurityAttributes = null;
foreach (SecurityAttribute securityAttribute in attributes)
{
groupedSecurityAttributes = groupedSecurityAttributes ?? OrderPreservingMultiDictionary<DeclarativeSecurityAction, ICustomAttribute>.GetInstance();
groupedSecurityAttributes.Add(securityAttribute.Action, securityAttribute.Attribute);
}
if (groupedSecurityAttributes == null)
{
return;
}
foreach (DeclarativeSecurityAction securityAction in groupedSecurityAttributes.Keys)
{
metadata.AddDeclarativeSecurityAttribute(
parent: parentHandle,
action: securityAction,
permissionSet: GetPermissionSetBlobHandle(groupedSecurityAttributes[securityAction]));
}
groupedSecurityAttributes.Free();
}
private void PopulateEventTableRows()
{
var eventDefs = this.GetEventDefs();
metadata.SetCapacity(TableIndex.Event, eventDefs.Count);
foreach (IEventDefinition eventDef in eventDefs)
{
metadata.AddEvent(
attributes: GetEventAttributes(eventDef),
name: GetStringHandleForNameAndCheckLength(eventDef.Name, eventDef),
type: GetTypeHandle(eventDef.GetType(Context)));
}
}
private void PopulateExportedTypeTableRows()
{
if (!IsFullMetadata)
{
return;
}
var exportedTypes = module.GetExportedTypes(Context.Diagnostics);
if (exportedTypes.Length == 0)
{
return;
}
metadata.SetCapacity(TableIndex.ExportedType, exportedTypes.Length);
foreach (var exportedType in exportedTypes)
{
INestedTypeReference nestedRef;
INamespaceTypeReference namespaceTypeRef;
TypeAttributes attributes;
StringHandle typeName;
StringHandle typeNamespace;
EntityHandle implementation;
if ((namespaceTypeRef = exportedType.Type.AsNamespaceTypeReference) != null)
{
string mangledTypeName = GetMangledName(namespaceTypeRef);
typeName = GetStringHandleForNameAndCheckLength(mangledTypeName, namespaceTypeRef);
typeNamespace = GetStringHandleForNamespaceAndCheckLength(namespaceTypeRef, mangledTypeName);
implementation = GetExportedTypeImplementation(namespaceTypeRef);
attributes = exportedType.IsForwarder ? TypeAttributes.NotPublic | Constants.TypeAttributes_TypeForwarder : TypeAttributes.Public;
}
else if ((nestedRef = exportedType.Type.AsNestedTypeReference) != null)
{
Debug.Assert(exportedType.ParentIndex != -1);
typeName = GetStringHandleForNameAndCheckLength(GetMangledName(nestedRef), nestedRef);
typeNamespace = default(StringHandle);
implementation = MetadataTokens.ExportedTypeHandle(exportedType.ParentIndex + 1);
attributes = exportedType.IsForwarder ? TypeAttributes.NotPublic : TypeAttributes.NestedPublic;
}
else
{
throw ExceptionUtilities.UnexpectedValue(exportedType);
}
metadata.AddExportedType(
attributes: attributes,
@namespace: typeNamespace,
name: typeName,
implementation: implementation,
typeDefinitionId: exportedType.IsForwarder ? 0 : MetadataTokens.GetToken(exportedType.Type.TypeDef));
}
}
private void PopulateFieldLayoutTableRows()
{
foreach (IFieldDefinition fieldDef in this.GetFieldDefs())
{
if (fieldDef.ContainingTypeDefinition.Layout != LayoutKind.Explicit || fieldDef.IsStatic)
{
continue;
}
metadata.AddFieldLayout(
field: GetFieldDefinitionHandle(fieldDef),
offset: fieldDef.Offset);
}
}
private void PopulateFieldMarshalTableRows()
{
foreach (IFieldDefinition fieldDef in this.GetFieldDefs())
{
if (!fieldDef.IsMarshalledExplicitly)
{
continue;
}
var marshallingInformation = fieldDef.MarshallingInformation;
BlobHandle descriptor = (marshallingInformation != null)
? GetMarshallingDescriptorHandle(marshallingInformation)
: GetMarshallingDescriptorHandle(fieldDef.MarshallingDescriptor);
metadata.AddMarshallingDescriptor(
parent: GetFieldDefinitionHandle(fieldDef),
descriptor: descriptor);
}
foreach (IParameterDefinition parDef in this.GetParameterDefs())
{
if (!parDef.IsMarshalledExplicitly)
{
continue;
}
var marshallingInformation = parDef.MarshallingInformation;
BlobHandle descriptor = (marshallingInformation != null)
? GetMarshallingDescriptorHandle(marshallingInformation)
: GetMarshallingDescriptorHandle(parDef.MarshallingDescriptor);
metadata.AddMarshallingDescriptor(
parent: GetParameterHandle(parDef),
descriptor: descriptor);
}
}
private void PopulateFieldRvaTableRows(BlobBuilder mappedFieldDataWriter)
{
foreach (IFieldDefinition fieldDef in this.GetFieldDefs())
{
if (fieldDef.MappedData.IsDefault)
{
continue;
}
int offset = mappedFieldDataWriter.Count;
mappedFieldDataWriter.WriteBytes(fieldDef.MappedData);
mappedFieldDataWriter.Align(ManagedPEBuilder.MappedFieldDataAlignment);
metadata.AddFieldRelativeVirtualAddress(
field: GetFieldDefinitionHandle(fieldDef),
offset: offset);
}
}
private void PopulateFieldTableRows()
{
var fieldDefs = this.GetFieldDefs();
metadata.SetCapacity(TableIndex.Field, fieldDefs.Count);
foreach (IFieldDefinition fieldDef in fieldDefs)
{
if (fieldDef.IsContextualNamedEntity)
{
((IContextualNamedEntity)fieldDef).AssociateWithMetadataWriter(this);
}
metadata.AddFieldDefinition(
attributes: GetFieldAttributes(fieldDef),
name: GetStringHandleForNameAndCheckLength(fieldDef.Name, fieldDef),
signature: GetFieldSignatureIndex(fieldDef));
}
}
private void PopulateConstantTableRows()
{
foreach (IFieldDefinition fieldDef in this.GetFieldDefs())
{
var constant = fieldDef.GetCompileTimeValue(Context);
if (constant == null)
{
continue;
}
metadata.AddConstant(
parent: GetFieldDefinitionHandle(fieldDef),
value: constant.Value);
}
foreach (IParameterDefinition parDef in this.GetParameterDefs())
{
var defaultValue = parDef.GetDefaultValue(Context);
if (defaultValue == null)
{
continue;
}
metadata.AddConstant(
parent: GetParameterHandle(parDef),
value: defaultValue.Value);
}
foreach (IPropertyDefinition propDef in this.GetPropertyDefs())
{
if (!propDef.HasDefaultValue)
{
continue;
}
metadata.AddConstant(
parent: GetPropertyDefIndex(propDef),
value: propDef.DefaultValue.Value);
}
}
private void PopulateFileTableRows()
{
ISourceAssemblySymbolInternal assembly = module.SourceAssemblyOpt;
if (assembly == null)
{
return;
}
var hashAlgorithm = assembly.HashAlgorithm;
metadata.SetCapacity(TableIndex.File, _fileRefList.Count);
foreach (IFileReference fileReference in _fileRefList)
{
metadata.AddAssemblyFile(
name: GetStringHandleForPathAndCheckLength(fileReference.FileName),
hashValue: metadata.GetOrAddBlob(fileReference.GetHashValue(hashAlgorithm)),
containsMetadata: fileReference.HasMetadata);
}
}
private void PopulateGenericParameters(
ImmutableArray<IGenericParameter> sortedGenericParameters)
{
foreach (IGenericParameter genericParameter in sortedGenericParameters)
{
// CONSIDER: The CLI spec doesn't mention a restriction on the Name column of the GenericParam table,
// but they go in the same string heap as all the other declaration names, so it stands to reason that
// they should be restricted in the same way.
var genericParameterHandle = metadata.AddGenericParameter(
parent: GetDeclaringTypeOrMethodHandle(genericParameter),
attributes: GetGenericParameterAttributes(genericParameter),
name: GetStringHandleForNameAndCheckLength(genericParameter.Name, genericParameter),
index: genericParameter.Index);
foreach (var refWithAttributes in genericParameter.GetConstraints(Context))
{
var genericConstraintHandle = metadata.AddGenericParameterConstraint(
genericParameter: genericParameterHandle,
constraint: GetTypeHandle(refWithAttributes.TypeRef));
AddCustomAttributesToTable(genericConstraintHandle, refWithAttributes.Attributes);
}
}
}
private void PopulateImplMapTableRows()
{
foreach (IMethodDefinition methodDef in this.GetMethodDefs())
{
if (!methodDef.IsPlatformInvoke)
{
continue;
}
var data = methodDef.PlatformInvokeData;
string entryPointName = data.EntryPointName;
StringHandle importName = (entryPointName != null)
? GetStringHandleForNameAndCheckLength(entryPointName, methodDef)
: metadata.GetOrAddString(methodDef.Name); // Length checked while populating the method def table.
metadata.AddMethodImport(
method: GetMethodDefinitionHandle(methodDef),
attributes: data.Flags,
name: importName,
module: GetModuleReferenceHandle(data.ModuleName));
}
}
private void PopulateInterfaceImplTableRows()
{
foreach (ITypeDefinition typeDef in this.GetTypeDefs())
{
var typeDefHandle = GetTypeDefinitionHandle(typeDef);
foreach (var interfaceImpl in typeDef.Interfaces(Context))
{
var handle = metadata.AddInterfaceImplementation(
type: typeDefHandle,
implementedInterface: GetTypeHandle(interfaceImpl.TypeRef));
AddCustomAttributesToTable(handle, interfaceImpl.Attributes);
}
}
}
private void PopulateManifestResourceTableRows(BlobBuilder resourceDataWriter, BlobBuilder dynamicAnalysisDataOpt)
{
if (dynamicAnalysisDataOpt != null)
{
metadata.AddManifestResource(
attributes: ManifestResourceAttributes.Private,
name: metadata.GetOrAddString("<DynamicAnalysisData>"),
implementation: default(EntityHandle),
offset: GetManagedResourceOffset(dynamicAnalysisDataOpt, resourceDataWriter)
);
}
foreach (var resource in this.module.GetResources(Context))
{
EntityHandle implementation;
if (resource.ExternalFile != null)
{
// Length checked on insertion into the file table.
implementation = GetAssemblyFileHandle(resource.ExternalFile);
}
else
{
// This is an embedded resource, we don't support references to resources from referenced assemblies.
implementation = default(EntityHandle);
}
metadata.AddManifestResource(
attributes: resource.IsPublic ? ManifestResourceAttributes.Public : ManifestResourceAttributes.Private,
name: GetStringHandleForNameAndCheckLength(resource.Name),
implementation: implementation,
offset: GetManagedResourceOffset(resource, resourceDataWriter));
}
// the stream should be aligned:
Debug.Assert((resourceDataWriter.Count % ManagedPEBuilder.ManagedResourcesDataAlignment) == 0);
}
private void PopulateMemberRefTableRows()
{
var memberRefs = this.GetMemberRefs();
metadata.SetCapacity(TableIndex.MemberRef, memberRefs.Count);
foreach (ITypeMemberReference memberRef in memberRefs)
{
metadata.AddMemberReference(
parent: GetMemberReferenceParent(memberRef),
name: GetStringHandleForNameAndCheckLength(memberRef.Name, memberRef),
signature: GetMemberReferenceSignatureHandle(memberRef));
}
}
private void PopulateMethodImplTableRows()
{
metadata.SetCapacity(TableIndex.MethodImpl, methodImplList.Count);
foreach (MethodImplementation methodImplementation in this.methodImplList)
{
metadata.AddMethodImplementation(
type: GetTypeDefinitionHandle(methodImplementation.ContainingType),
methodBody: GetMethodDefinitionOrReferenceHandle(methodImplementation.ImplementingMethod),
methodDeclaration: GetMethodDefinitionOrReferenceHandle(methodImplementation.ImplementedMethod));
}
}
private void PopulateMethodSpecTableRows()
{
var methodSpecs = this.GetMethodSpecs();
metadata.SetCapacity(TableIndex.MethodSpec, methodSpecs.Count);
foreach (IGenericMethodInstanceReference genericMethodInstanceReference in methodSpecs)
{
metadata.AddMethodSpecification(
method: GetMethodDefinitionOrReferenceHandle(genericMethodInstanceReference.GetGenericMethod(Context)),
instantiation: GetMethodSpecificationBlobHandle(genericMethodInstanceReference));
}
}
private void PopulateMethodTableRows(int[] methodBodyOffsets)
{
var methodDefs = this.GetMethodDefs();
metadata.SetCapacity(TableIndex.MethodDef, methodDefs.Count);
int i = 0;
foreach (IMethodDefinition methodDef in methodDefs)
{
metadata.AddMethodDefinition(
attributes: GetMethodAttributes(methodDef),
implAttributes: methodDef.GetImplementationAttributes(Context),
name: GetStringHandleForNameAndCheckLength(methodDef.Name, methodDef),
signature: GetMethodSignatureHandle(methodDef),
bodyOffset: methodBodyOffsets[i],
parameterList: GetFirstParameterHandle(methodDef));
i++;
}
}
private void PopulateMethodSemanticsTableRows()
{
var propertyDefs = this.GetPropertyDefs();
var eventDefs = this.GetEventDefs();
// an estimate, not necessarily accurate.
metadata.SetCapacity(TableIndex.MethodSemantics, propertyDefs.Count * 2 + eventDefs.Count * 2);
foreach (IPropertyDefinition propertyDef in this.GetPropertyDefs())
{
var association = GetPropertyDefIndex(propertyDef);
foreach (IMethodReference accessorMethod in propertyDef.GetAccessors(Context))
{
MethodSemanticsAttributes semantics;
if (accessorMethod == propertyDef.Setter)
{
semantics = MethodSemanticsAttributes.Setter;
}
else if (accessorMethod == propertyDef.Getter)
{
semantics = MethodSemanticsAttributes.Getter;
}
else
{
semantics = MethodSemanticsAttributes.Other;
}
metadata.AddMethodSemantics(
association: association,
semantics: semantics,
methodDefinition: GetMethodDefinitionHandle(accessorMethod.GetResolvedMethod(Context)));
}
}
foreach (IEventDefinition eventDef in this.GetEventDefs())
{
var association = GetEventDefinitionHandle(eventDef);
foreach (IMethodReference accessorMethod in eventDef.GetAccessors(Context))
{
MethodSemanticsAttributes semantics;
if (accessorMethod == eventDef.Adder)
{
semantics = MethodSemanticsAttributes.Adder;
}
else if (accessorMethod == eventDef.Remover)
{
semantics = MethodSemanticsAttributes.Remover;
}
else if (accessorMethod == eventDef.Caller)
{
semantics = MethodSemanticsAttributes.Raiser;
}
else
{
semantics = MethodSemanticsAttributes.Other;
}
metadata.AddMethodSemantics(
association: association,
semantics: semantics,
methodDefinition: GetMethodDefinitionHandle(accessorMethod.GetResolvedMethod(Context)));
}
}
}
private void PopulateModuleRefTableRows()
{
var moduleRefs = this.GetModuleRefs();
metadata.SetCapacity(TableIndex.ModuleRef, moduleRefs.Count);
foreach (string moduleName in moduleRefs)
{
metadata.AddModuleReference(GetStringHandleForPathAndCheckLength(moduleName));
}
}
private void PopulateModuleTableRow(out Blob mvidFixup)
{
CheckPathLength(this.module.ModuleName);
GuidHandle mvidHandle;
Guid mvid = this.module.SerializationProperties.PersistentIdentifier;
if (mvid != default(Guid))
{
// MVID is specified upfront when emitting EnC delta:
mvidHandle = metadata.GetOrAddGuid(mvid);
mvidFixup = default(Blob);
}
else
{
// The guid will be filled in later:
var reservedGuid = metadata.ReserveGuid();
mvidFixup = reservedGuid.Content;
mvidHandle = reservedGuid.Handle;
reservedGuid.CreateWriter().WriteBytes(0, mvidFixup.Length);
}
metadata.AddModule(
generation: this.Generation,
moduleName: metadata.GetOrAddString(this.module.ModuleName),
mvid: mvidHandle,
encId: metadata.GetOrAddGuid(EncId),
encBaseId: metadata.GetOrAddGuid(EncBaseId));
}
private void PopulateParamTableRows()
{
var parameterDefs = this.GetParameterDefs();
metadata.SetCapacity(TableIndex.Param, parameterDefs.Count);
foreach (IParameterDefinition parDef in parameterDefs)
{
metadata.AddParameter(
attributes: GetParameterAttributes(parDef),
sequenceNumber: (parDef is ReturnValueParameter) ? 0 : parDef.Index + 1,
name: GetStringHandleForNameAndCheckLength(parDef.Name, parDef));
}
}
private void PopulatePropertyTableRows()
{
var propertyDefs = this.GetPropertyDefs();
metadata.SetCapacity(TableIndex.Property, propertyDefs.Count);
foreach (IPropertyDefinition propertyDef in propertyDefs)
{
metadata.AddProperty(
attributes: GetPropertyAttributes(propertyDef),
name: GetStringHandleForNameAndCheckLength(propertyDef.Name, propertyDef),
signature: GetPropertySignatureHandle(propertyDef));
}
}
private void PopulateTypeDefTableRows()
{
var typeDefs = this.GetTypeDefs();
metadata.SetCapacity(TableIndex.TypeDef, typeDefs.Count);
foreach (INamedTypeDefinition typeDef in typeDefs)
{
INamespaceTypeDefinition namespaceType = typeDef.AsNamespaceTypeDefinition(Context);
string mangledTypeName = GetMangledName(typeDef);
ITypeReference baseType = typeDef.GetBaseClass(Context);
metadata.AddTypeDefinition(
attributes: GetTypeAttributes(typeDef),
@namespace: (namespaceType != null) ? GetStringHandleForNamespaceAndCheckLength(namespaceType, mangledTypeName) : default(StringHandle),
name: GetStringHandleForNameAndCheckLength(mangledTypeName, typeDef),
baseType: (baseType != null) ? GetTypeHandle(baseType) : default(EntityHandle),
fieldList: GetFirstFieldDefinitionHandle(typeDef),
methodList: GetFirstMethodDefinitionHandle(typeDef));
}
}
private void PopulateNestedClassTableRows()
{