Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/tools/ilasm/src/ILAssembler/CIL.g4
Original file line number Diff line number Diff line change
Expand Up @@ -558,12 +558,12 @@ classAttr:
| 'private'
| VALUE
| ENUM
| 'interface'
| INTERFACE
| 'sealed'
| 'abstract'
| 'auto'
| 'sequential'
| 'explicit'
| EXPLICIT
| 'extended'
| ANSI
| 'unicode'
Expand Down
2 changes: 2 additions & 0 deletions src/tools/ilasm/src/ILAssembler/Diagnostic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public static class DiagnosticIds
public const string UnknownGenericParameter = "ILA0028";
public const string ParameterIndexOutOfRange = "ILA0029";
public const string DuplicateMethod = "ILA0030";
public const string MissingExportedTypeImplementation = "ILA0031";
}

internal static class DiagnosticMessageTemplates
Expand Down Expand Up @@ -84,4 +85,5 @@ internal static class DiagnosticMessageTemplates
public const string UnknownGenericParameter = "Unknown generic parameter '{0}'";
public const string ParameterIndexOutOfRange = "Parameter index {0} is out of range";
public const string DuplicateMethod = "Duplicate method definition";
public const string MissingExportedTypeImplementation = "Undefined implementation in ExportedType '{0}' -- ExportedType not emitted";
}
110 changes: 97 additions & 13 deletions src/tools/ilasm/src/ILAssembler/EntityRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ public IReadOnlyList<EntityBase> GetSeenEntities(TableIndex table)

public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadOnlyDictionary<string, int> mappedFieldDataNames)
{
// Set the assembly handle early since DeclarativeSecurityAttribute needs it
// The assembly definition handle is always row 1 (there's only ever one assembly per module)
// Assembly table token = 0x20000001
if (Assembly is not null)
{
((IHasHandle)Assembly).SetHandle(MetadataTokens.EntityHandle(0x20000001));
}

// Now that we've seen all of the entities, we can write them out in the correct order.
// Record the entities in the correct order so they are assigned handles.
// After this, we'll write out the content of the entities in the correct order.
Expand All @@ -109,11 +117,21 @@ public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadO
// or other rows that would refer to it.
if (param.Name is not null
|| param.MarshallingDescriptor.Count != 0
|| param.HasCustomAttributes)
|| param.HasCustomAttributes
|| param.HasConstant)
{
RecordEntityInTable(TableIndex.Param, param);
}
}
// Record generic parameters for methods
foreach (var genericParam in method.GenericParameters)
{
RecordEntityInTable(TableIndex.GenericParam, genericParam);
}
foreach (var constraint in method.GenericParameterConstraints)
{
RecordEntityInTable(TableIndex.GenericParamConstraint, constraint);
}
}
foreach (var field in type.Fields)
{
Expand Down Expand Up @@ -269,6 +287,11 @@ public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadO
{
builder.AddMarshallingDescriptor(param.Handle, builder.GetOrAddBlob(param.MarshallingDescriptor));
}

if (param.HasConstant)
{
builder.AddConstant(param.Handle, param.ConstantValue);
}
}

foreach (InterfaceImplementationEntity impl in GetSeenEntities(TableIndex.InterfaceImpl))
Expand Down Expand Up @@ -324,6 +347,11 @@ public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadO
{
builder.AddMethodSemantics(prop.Handle, accessor.Semantic, (MethodDefinitionHandle)accessor.Method.Handle);
}

if (prop.HasConstant)
{
builder.AddConstant(prop.Handle, prop.ConstantValue);
}
}

foreach (ModuleReferenceEntity moduleRef in GetSeenEntities(TableIndex.ModuleRef))
Expand All @@ -349,12 +377,14 @@ public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadO

if (Assembly is not null)
{
// Combine the base flags with the architecture bits
var assemblyFlags = Assembly.Flags | (AssemblyFlags)((int)Assembly.ProcessorArchitecture << 4);
builder.AddAssembly(
builder.GetOrAddString(Assembly.Name),
Assembly.Version ?? new Version(),
Assembly.Culture is null ? default : builder.GetOrAddString(Assembly.Culture),
Assembly.PublicKeyOrToken is null ? default : builder.GetOrAddBlob(Assembly.PublicKeyOrToken),
Assembly.Flags,
assemblyFlags,
Assembly.HashAlgorithm);
}

Expand All @@ -368,11 +398,17 @@ public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadO

foreach (ExportedTypeEntity exportedType in GetSeenEntities(TableIndex.ExportedType))
{
// Implementation must be a valid handle type: AssemblyFileHandle, AssemblyReferenceHandle, or ExportedTypeHandle
// COMPAT: If implementation is null, skip emitting this exported type
if (exportedType.Implementation is null)
{
continue;
}
builder.AddExportedType(
exportedType.Attributes,
builder.GetOrAddString(exportedType.Namespace),
builder.GetOrAddString(exportedType.Name),
exportedType.Implementation?.Handle ?? default,
exportedType.Implementation.Handle,
exportedType.TypeDefinitionId);
}

Expand All @@ -390,6 +426,22 @@ public void WriteContentTo(MetadataBuilder builder, BlobBuilder ilStream, IReadO
builder.AddMethodSpecification(methodSpec.Parent.Handle, builder.GetOrAddBlob(methodSpec.Signature));
}

foreach (GenericParameterEntity genericParam in GetSeenEntities(TableIndex.GenericParam))
{
builder.AddGenericParameter(
genericParam.Owner!.Handle,
genericParam.Attributes,
builder.GetOrAddString(genericParam.Name),
genericParam.Index);
}

foreach (GenericParameterConstraintEntity constraint in GetSeenEntities(TableIndex.GenericParamConstraint))
{
builder.AddGenericParameterConstraint(
(GenericParameterHandle)constraint.Owner!.Handle,
constraint.BaseType.Handle);
}

static FieldDefinitionHandle GetFieldHandleForList(IReadOnlyList<EntityBase> list, IReadOnlyList<EntityBase> listOwner, Func<EntityBase, IReadOnlyList<EntityBase>> getList, int ownerIndex)
=> (FieldDefinitionHandle)GetHandleForList(list, listOwner, getList, ownerIndex, TableIndex.Field);

Expand All @@ -407,20 +459,26 @@ static ParameterHandle GetParameterHandleForList(IReadOnlyList<EntityBase> list,

static EntityHandle GetHandleForList(IReadOnlyList<EntityBase> list, IReadOnlyList<EntityBase> listOwner, Func<EntityBase, IReadOnlyList<EntityBase>> getList, int ownerIndex, TableIndex tokenType)
{
// Return the first entry in the list.
// If the list is empty, return the start of the next list.
// Return the first entry in the list that has a handle.
// If no item has a handle, return the start of the next list.
// If there is no next list, return one past the end of the previous list.
if (list.Count != 0 && !list[0].Handle.IsNil)
foreach (var item in list)
{
return list[0].Handle;
if (!item.Handle.IsNil)
{
return item.Handle;
}
}

for (int i = 0; i < listOwner.Count; i++)
for (int i = ownerIndex + 1; i < listOwner.Count; i++)
{
var otherList = getList(listOwner[i]);
if (otherList.Count != 0 && !otherList[0].Handle.IsNil)
foreach (var item in otherList)
{
return otherList[0].Handle;
if (!item.Handle.IsNil)
{
return item.Handle;
}
}
}

Expand Down Expand Up @@ -1020,8 +1078,10 @@ public ManifestResourceEntity CreateManifestResource(string name, uint offset)

public ExportedTypeEntity GetOrCreateExportedType(EntityBase? implementation, string @namespace, string name, Action<ExportedTypeEntity> onCreateType)
{
// We only key on the implementation if the type is nested.
return GetOrCreateEntity((implementation as ExportedTypeEntity, @namespace, name), TableIndex.ExportedType, _seenExportedTypes, (key) => new(key.Item3, key.Item2, key.Item1), onCreateType);
// We only key on the implementation if the type is nested (ExportedTypeEntity).
// For forwarders, implementation is AssemblyReferenceEntity which is not used in the key.
// However, we need to pass the actual implementation to the entity constructor.
return GetOrCreateEntity((implementation as ExportedTypeEntity, @namespace, name), TableIndex.ExportedType, _seenExportedTypes, (key) => new(key.Item3, key.Item2, implementation), onCreateType);
}

public ExportedTypeEntity? FindExportedType(ExportedTypeEntity? containingType, string @namespace, string @name)
Expand Down Expand Up @@ -1232,6 +1292,26 @@ public sealed class MethodDefinitionEntity(TypeDefinitionEntity containingType,
/// Debug information for this method (sequence points, document).
/// </summary>
public MethodDebugInfo DebugInfo { get; } = new();

/// <summary>
/// Export ordinal for this method (from .export directive). -1 means not exported.
/// </summary>
public int ExportOrdinal { get; set; } = -1;

/// <summary>
/// Export alias name (from .export [n] as alias). Null means use method name.
/// </summary>
public string? ExportAlias { get; set; }

/// <summary>
/// 1-based VTable entry index (from .vtentry directive). 0 means not in vtable.
/// </summary>
public int VTableEntry { get; set; }

/// <summary>
/// 1-based slot within the VTable entry (from .vtentry directive). 0 means not in vtable.
/// </summary>
public int VTableSlot { get; set; }
}

public sealed class ParameterEntity(ParameterAttributes attributes, string? name, BlobBuilder marshallingDescriptor, int sequence) : EntityBase
Expand All @@ -1241,6 +1321,8 @@ public sealed class ParameterEntity(ParameterAttributes attributes, string? name
public BlobBuilder MarshallingDescriptor { get; set; } = marshallingDescriptor;
public bool HasCustomAttributes { get; set; }
public int Sequence { get; } = sequence;
public bool HasConstant { get; set; }
public object? ConstantValue { get; set; }
}

public sealed class MemberReferenceEntity(EntityBase parent, string name, BlobBuilder signature) : EntityBase
Expand Down Expand Up @@ -1342,9 +1424,11 @@ public sealed class EventEntity(EventAttributes attributes, TypeEntity type, str

public sealed class PropertyEntity(PropertyAttributes attributes, BlobBuilder type, string name) : EntityBase
{
public PropertyAttributes Attributes { get; } = attributes;
public PropertyAttributes Attributes { get; set; } = attributes;
public BlobBuilder Type { get; } = type;
public string Name { get; } = name;
public bool HasConstant { get; set; }
public object? ConstantValue { get; set; }

public List<(MethodSemanticsAttributes Semantic, EntityBase Method)> Accessors { get; } = new();
}
Expand Down
Loading
Loading