Skip to content
Draft
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
5 changes: 4 additions & 1 deletion src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
// src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h
// If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION`
// and handle pending work.
#define READYTORUN_MAJOR_VERSION 27
#define READYTORUN_MAJOR_VERSION 28
#define READYTORUN_MINOR_VERSION 0x0000

#define MINIMUM_READYTORUN_MAJOR_VERSION 26
#define READYTORUN_TYPEMAP_TAGGED_TYPES_MAJOR_VERSION 28

// R2R Version 2.1 adds the InliningInfo section
// R2R Version 2.2 adds the ProfileDataInfo section
Expand Down Expand Up @@ -68,6 +69,8 @@
// R2R Version 26 changes ARM64 NativeVarInfo register encoding to include V0-V31
// R2R Version 26.1 adds READYTORUN_FIXUP_StoreMultiCallableAddrOfCode for storing a method's MultiCallableAddrOfCode into a location in the R2R image (used on WebAssembly)
// R2R Version 27 redefines READYTORUN_FIXUP_DeclaringTypeHandle to be encoded as a method signature instead of a pair of type signatures
// R2R Version 28 adds tagged fixup or serialized-name type references to the ExternalTypeMaps and ProxyTypeMaps sections.
// Older supported versions use untagged import-section and fixup-index pairs in these sections.

struct READYTORUN_CORE_HEADER
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ struct ReadyToRunHeaderConstants
{
static const uint32_t Signature = 0x00525452; // 'RTR'

static const uint32_t CurrentMajorVersion = 27;
static const uint32_t CurrentMajorVersion = 28;
static const uint32_t CurrentMinorVersion = 0;
};

Expand Down
192 changes: 168 additions & 24 deletions src/coreclr/tools/Common/Compiler/TypeMapMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,94 @@ private enum TypeMapAttributeKind
TypeMapAssociation
}

private readonly struct TypeWithSerializedName
{
public TypeWithSerializedName(TypeDesc type, string serializedName)
{
Type = type;
SerializedName = serializedName;
}

public TypeDesc Type { get; }
public string SerializedName { get; }
}

private readonly struct TypeMapCustomAttributeTypeProvider : ICustomAttributeTypeProvider<TypeWithSerializedName>
{
private readonly CustomAttributeTypeProvider _provider;

public TypeMapCustomAttributeTypeProvider(EcmaModule module)
{
_provider = new CustomAttributeTypeProvider(module);
}

public TypeWithSerializedName GetPrimitiveType(PrimitiveTypeCode typeCode)
=> new TypeWithSerializedName(_provider.GetPrimitiveType(typeCode), null);

public TypeWithSerializedName GetSystemType()
=> new TypeWithSerializedName(_provider.GetSystemType(), null);

public TypeWithSerializedName GetSZArrayType(TypeWithSerializedName elementType)
=> new TypeWithSerializedName(_provider.GetSZArrayType(elementType.Type), null);

public TypeWithSerializedName GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
=> new TypeWithSerializedName(_provider.GetTypeFromDefinition(reader, handle, rawTypeKind), null);

public TypeWithSerializedName GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
=> new TypeWithSerializedName(_provider.GetTypeFromReference(reader, handle, rawTypeKind), null);

public TypeWithSerializedName GetTypeFromSpecification(MetadataReader reader, TypeSpecificationHandle handle, byte rawTypeKind)
=> new TypeWithSerializedName(_provider.GetTypeFromSpecification(reader, handle, rawTypeKind), null);

public TypeWithSerializedName GetTypeFromSerializedName(string name)
=> new TypeWithSerializedName(_provider.GetTypeFromSerializedName(name), name);

public PrimitiveTypeCode GetUnderlyingEnumType(TypeWithSerializedName type)
=> _provider.GetUnderlyingEnumType(type.Type);

public bool IsSystemType(TypeWithSerializedName type)
=> _provider.IsSystemType(type.Type);
}

internal readonly struct ExternalTypeMapEntry
{
public ExternalTypeMapEntry(
TypeDesc type,
string serializedTypeName,
TypeDesc trimmingType,
string serializedTrimmingTypeName,
ModuleDesc declaringModule)
{
Type = type;
SerializedTypeName = serializedTypeName;
TrimmingType = trimmingType;
SerializedTrimmingTypeName = serializedTrimmingTypeName;
DeclaringModule = declaringModule;
}

public TypeDesc Type { get; }
public string SerializedTypeName { get; }
public TypeDesc TrimmingType { get; }
public string SerializedTrimmingTypeName { get; }
public ModuleDesc DeclaringModule { get; }
}

internal readonly struct ProxyTypeMapEntry
{
public ProxyTypeMapEntry(TypeDesc type, string serializedSourceTypeName, string serializedTypeName, ModuleDesc declaringModule)
{
Type = type;
SerializedSourceTypeName = serializedSourceTypeName;
SerializedTypeName = serializedTypeName;
DeclaringModule = declaringModule;
}

public TypeDesc Type { get; }
public string SerializedSourceTypeName { get; }
public string SerializedTypeName { get; }
public ModuleDesc DeclaringModule { get; }
}

private static TypeMapAttributeKind LookupTypeMapType(TypeDesc attrType)
{
var typeDef = attrType.GetTypeDefinition() as MetadataType;
Expand All @@ -41,13 +129,13 @@ private static TypeMapAttributeKind LookupTypeMapType(TypeDesc attrType)

internal interface IExternalTypeMap
{
IReadOnlyDictionary<string, (TypeDesc type, TypeDesc trimmingType)> TypeMap { get; }
IReadOnlyDictionary<string, ExternalTypeMapEntry> TypeMap { get; }
MethodDesc ThrowingMethodStub { get; }
}

internal interface IProxyTypeMap
{
IReadOnlyDictionary<TypeDesc, TypeDesc> TypeMap { get; }
IReadOnlyDictionary<TypeDesc, ProxyTypeMapEntry> TypeMap { get; }
MethodDesc ThrowingMethodStub { get; }
}

Expand Down Expand Up @@ -95,8 +183,8 @@ protected override int CompareToImpl(MethodDesc other, TypeSystemComparer compar
public override TypeSystemContext Context => OwningType.Context;
}

private readonly Dictionary<TypeDesc, TypeDesc> _associatedTypeMap = [];
private readonly Dictionary<string, (TypeDesc type, TypeDesc trimmingTarget)> _externalTypeMap = [];
private readonly Dictionary<TypeDesc, ProxyTypeMapEntry> _associatedTypeMap = [];
private readonly Dictionary<string, ExternalTypeMapEntry> _externalTypeMap = [];
private readonly List<ModuleDesc> _targetModules = [];
private ThrowingMethodStub _externalTypeMapExceptionStub;
private ThrowingMethodStub _associatedTypeMapExceptionStub;
Expand All @@ -116,16 +204,31 @@ public Map(TypeDesc typeMapGroup)
/// </summary>
public bool HasAssemblyTargetAttributes { get; set; }

public void AddAssociatedTypeMapEntry(TypeDesc type, TypeDesc associatedType)
public void AddAssociatedTypeMapEntry(
TypeDesc type,
string serializedTypeName,
TypeDesc associatedType,
string serializedAssociatedTypeName,
ModuleDesc declaringModule)
{
if (!_associatedTypeMap.TryAdd(type, associatedType))
if (!_associatedTypeMap.TryAdd(
type,
new ProxyTypeMapEntry(associatedType, serializedTypeName, serializedAssociatedTypeName, declaringModule)))
{
ThrowHelper.ThrowBadImageFormatException();
}
}
public void AddExternalTypeMapEntry(string typeName, TypeDesc type, TypeDesc trimmingTarget)
public void AddExternalTypeMapEntry(
string typeName,
TypeDesc type,
string serializedTypeName,
TypeDesc trimmingTarget,
string serializedTrimmingTypeName,
ModuleDesc declaringModule)
{
if (!_externalTypeMap.TryAdd(typeName, (type, trimmingTarget)))
if (!_externalTypeMap.TryAdd(
typeName,
new ExternalTypeMapEntry(type, serializedTypeName, trimmingTarget, serializedTrimmingTypeName, declaringModule)))
{
ThrowHelper.ThrowBadImageFormatException();
}
Expand Down Expand Up @@ -165,9 +268,14 @@ public void MergePendingMap(ModuleDesc stubModule, Map pendingMap)
{
try
{
foreach (KeyValuePair<TypeDesc, TypeDesc> kvp in pendingMap._associatedTypeMap)
foreach (KeyValuePair<TypeDesc, ProxyTypeMapEntry> kvp in pendingMap._associatedTypeMap)
{
AddAssociatedTypeMapEntry(kvp.Key, kvp.Value);
AddAssociatedTypeMapEntry(
kvp.Key,
kvp.Value.SerializedSourceTypeName,
kvp.Value.Type,
kvp.Value.SerializedTypeName,
kvp.Value.DeclaringModule);
}
}
catch (TypeSystemException ex)
Expand Down Expand Up @@ -195,9 +303,15 @@ public void MergePendingMap(ModuleDesc stubModule, Map pendingMap)
{
try
{
foreach (KeyValuePair<string, (TypeDesc type, TypeDesc trimmingTarget)> kvp in pendingMap._externalTypeMap)
foreach (KeyValuePair<string, ExternalTypeMapEntry> kvp in pendingMap._externalTypeMap)
{
AddExternalTypeMapEntry(kvp.Key, kvp.Value.type, kvp.Value.trimmingTarget);
AddExternalTypeMapEntry(
kvp.Key,
kvp.Value.Type,
kvp.Value.SerializedTypeName,
kvp.Value.TrimmingType,
kvp.Value.SerializedTrimmingTypeName,
kvp.Value.DeclaringModule);
}
}
catch (TypeSystemException ex)
Expand Down Expand Up @@ -227,11 +341,11 @@ public void AddTargetModule(ModuleDesc targetModule)
/// </summary>
public IReadOnlyList<ModuleDesc> TargetModules => _targetModules;

IReadOnlyDictionary<string, (TypeDesc type, TypeDesc trimmingType)> IExternalTypeMap.TypeMap => _externalTypeMap;
IReadOnlyDictionary<string, ExternalTypeMapEntry> IExternalTypeMap.TypeMap => _externalTypeMap;

MethodDesc IExternalTypeMap.ThrowingMethodStub => _externalTypeMapExceptionStub;

IReadOnlyDictionary<TypeDesc, TypeDesc> IProxyTypeMap.TypeMap => _associatedTypeMap;
IReadOnlyDictionary<TypeDesc, ProxyTypeMapEntry> IProxyTypeMap.TypeMap => _associatedTypeMap;

MethodDesc IProxyTypeMap.ThrowingMethodStub => _associatedTypeMapExceptionStub;
}
Expand Down Expand Up @@ -328,7 +442,7 @@ public static TypeMapMetadata CreateFromAssembly(EcmaAssembly assembly, ModuleDe
continue;
}

CustomAttributeValue<TypeDesc> attrValue = attr.DecodeValue(new CustomAttributeTypeProvider(currentAssembly));
CustomAttributeValue<TypeWithSerializedName> attrValue = attr.DecodeValue(new TypeMapCustomAttributeTypeProvider(currentAssembly));

TypeDesc typeMapGroup = type.Instantiation[0];

Expand Down Expand Up @@ -420,7 +534,7 @@ public static TypeMapMetadata CreateFromAssembly(EcmaAssembly assembly, ModuleDe
scannedAssemblies.Add((currentAssembly, currentTypeMapGroup));
}

void ProcessTypeMapAssemblyTargetAttribute(CustomAttributeValue<TypeDesc> attrValue, Map typeMapState)
void ProcessTypeMapAssemblyTargetAttribute(CustomAttributeValue<TypeWithSerializedName> attrValue, Map typeMapState)
{
typeMapState.HasAssemblyTargetAttributes = true;

Expand All @@ -442,19 +556,40 @@ void ProcessTypeMapAssemblyTargetAttribute(CustomAttributeValue<TypeDesc> attrVa
}
}

void ProcessTypeMapAttribute(CustomAttributeValue<TypeDesc> attrValue, Map typeMapState)
void ProcessTypeMapAttribute(CustomAttributeValue<TypeWithSerializedName> attrValue, Map typeMapState)
{
switch (attrValue.FixedArguments)
{
case [{ Value: string typeName }, { Value: TypeDesc targetType }]:
case
[
{ Value: string typeName },
{ Value: TypeWithSerializedName { Type: TypeDesc targetType, SerializedName: string serializedTargetTypeName } }
]:
{
typeMapState.AddExternalTypeMapEntry(typeName, targetType, null);
typeMapState.AddExternalTypeMapEntry(
typeName,
targetType,
serializedTargetTypeName,
null,
null,
currentAssembly);
break;
}

case [{ Value: string typeName }, { Value: TypeDesc targetType }, { Value: TypeDesc trimTargetType }]:
case
[
{ Value: string typeName },
{ Value: TypeWithSerializedName { Type: TypeDesc targetType, SerializedName: string serializedTargetTypeName } },
{ Value: TypeWithSerializedName { Type: TypeDesc trimTargetType, SerializedName: string serializedTrimTargetTypeName } }
]:
{
typeMapState.AddExternalTypeMapEntry(typeName, targetType, trimTargetType);
typeMapState.AddExternalTypeMapEntry(
typeName,
targetType,
serializedTargetTypeName,
trimTargetType,
serializedTrimTargetTypeName,
currentAssembly);
break;
}

Expand All @@ -464,17 +599,26 @@ void ProcessTypeMapAttribute(CustomAttributeValue<TypeDesc> attrValue, Map typeM
}
}

void ProcessTypeMapAssociationAttribute(CustomAttributeValue<TypeDesc> attrValue, Map typeMapState)
void ProcessTypeMapAssociationAttribute(CustomAttributeValue<TypeWithSerializedName> attrValue, Map typeMapState)
{
// If attribute is TypeMapAssociationAttribute, we need to extract the generic argument (type map group)
// and process it.
if (attrValue.FixedArguments is not [{ Value: TypeDesc type }, { Value: TypeDesc associatedType }])
if (attrValue.FixedArguments is not
[
{ Value: TypeWithSerializedName { Type: TypeDesc type, SerializedName: string serializedTypeName } },
{ Value: TypeWithSerializedName { Type: TypeDesc associatedType, SerializedName: string serializedAssociatedTypeName } }
])
{
ThrowHelper.ThrowBadImageFormatException();
return;
}

typeMapState.AddAssociatedTypeMapEntry(type, associatedType);
typeMapState.AddAssociatedTypeMapEntry(
type,
serializedTypeName,
associatedType,
serializedAssociatedTypeName,
currentAssembly);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal struct ReadyToRunHeaderConstants
{
public const uint Signature = 0x00525452; // 'RTR'

public const ushort CurrentMajorVersion = 27;
public const ushort CurrentMajorVersion = 28;
public const ushort CurrentMinorVersion = 0;
}
#if READYTORUN
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ namespace ILCompiler.DependencyAnalysis
{
internal sealed class ExternalTypeMapNode : SortableDependencyNode, IExternalTypeMapNode
{
private readonly IEnumerable<KeyValuePair<string, (TypeDesc targetType, TypeDesc trimmingTargetType)>> _mapEntries;
private readonly IEnumerable<KeyValuePair<string, TypeMapMetadata.ExternalTypeMapEntry>> _mapEntries;

public ExternalTypeMapNode(TypeDesc typeMapGroup, IEnumerable<KeyValuePair<string, (TypeDesc targetType, TypeDesc trimmingTargetType)>> mapEntries)
public ExternalTypeMapNode(TypeDesc typeMapGroup, IEnumerable<KeyValuePair<string, TypeMapMetadata.ExternalTypeMapEntry>> mapEntries)
{
_mapEntries = mapEntries;
TypeMapGroup = typeMapGroup;
Expand All @@ -37,7 +37,8 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep

foreach (var entry in _mapEntries)
{
var (targetType, trimmingTargetType) = entry.Value;
TypeDesc targetType = entry.Value.Type;
TypeDesc trimmingTargetType = entry.Value.TrimmingType;
if (trimmingTargetType is not null)
{
IEETypeNode effectiveTrimTargetType = GetEffectiveTrimTargetType(context, trimmingTargetType);
Expand All @@ -58,7 +59,8 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
{
foreach (var entry in _mapEntries)
{
var (targetType, trimmingTargetType) = entry.Value;
TypeDesc targetType = entry.Value.Type;
TypeDesc trimmingTargetType = entry.Value.TrimmingType;
if (trimmingTargetType is null)
{
yield return new DependencyListEntry(
Expand All @@ -83,7 +85,8 @@ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer
{
foreach (var entry in _mapEntries)
{
var (targetType, trimmingTargetType) = entry.Value;
TypeDesc targetType = entry.Value.Type;
TypeDesc trimmingTargetType = entry.Value.TrimmingType;

if (trimmingTargetType is null
|| GetEffectiveTrimTargetType(factory, trimmingTargetType).Marked)
Expand Down
Loading
Loading