Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the performance of the type loader through various tweaks #85743

Merged
merged 29 commits into from
Jun 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ff0e821
Skip type validation by default in ReadyToRun images
davidwrighton Apr 13, 2023
3b8143c
Replace expensive lookups of generic parameter and nested class data …
davidwrighton Apr 20, 2023
0c88982
Store index of MethodDesc as well as ChunkIndex. Makes MethodDesc::Ge…
davidwrighton Apr 21, 2023
910f4c4
Optimize the path for computing if a method is eligible for tiered co…
davidwrighton Apr 22, 2023
418af3c
Remove CanShareVtableChunksFrom concept
davidwrighton May 3, 2023
c1c9983
Merge branch 'main' of github.com:dotnet/runtime into faster_type_load
davidwrighton May 8, 2023
48dfa0e
Fix up some more issues
davidwrighton May 11, 2023
d274c51
Bring back late virtual propagation in the presence of covariant over…
davidwrighton May 11, 2023
5bae879
Check correct flag on EEClass
davidwrighton May 12, 2023
9f9e586
Drive by fix for GetRestoredSlot. We don't need the handling of unres…
davidwrighton May 12, 2023
f5e72a6
Fix composite build with new tables
davidwrighton May 12, 2023
8eaf4a0
Uniquify the mangled names
davidwrighton May 15, 2023
ac7ec65
Add more __
davidwrighton May 17, 2023
1a57a0a
Initial pass at type skip verifation checker
davidwrighton May 19, 2023
5f770c6
Fix logging and some correctness issues
davidwrighton May 19, 2023
52bd220
Enable the more of type checking
davidwrighton May 20, 2023
dfecc6f
Fix build breaks involving new feature of GenericParameterDesc
davidwrighton May 30, 2023
6ef05ec
Merge branch 'main' of github.com:dotnet/runtime into faster_type_load
davidwrighton May 30, 2023
eff81d5
Add documentation for R2R format changes
davidwrighton Jun 1, 2023
db08221
Fix implementation of CompareMethodContraints. instead of using IsGen…
davidwrighton Jun 1, 2023
3b21879
Fix nits noticed by Aaron
davidwrighton Jun 1, 2023
06b6ffd
Add some const correctness to the world
davidwrighton Jun 1, 2023
df3a418
Fix issues noted by Michal, as well as remaining constrain checking i…
davidwrighton Jun 2, 2023
75144c4
Merge branch 'main' of github.com:dotnet/runtime into faster_type_load
davidwrighton Jun 5, 2023
1f44575
Code review details
davidwrighton Jun 5, 2023
e6c0b4b
Merge branch 'main' of github.com:dotnet/runtime into faster_type_load
davidwrighton Jun 9, 2023
0f45839
Merge branch 'main' into faster_type_load
davidwrighton Jun 9, 2023
2648965
Code review from trylek
davidwrighton Jun 12, 2023
bc127bb
Merge branch 'main' of https://github.com/dotnet/runtime into faster_…
davidwrighton Jun 13, 2023
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
30 changes: 30 additions & 0 deletions docs/design/coreclr/botr/readytorun-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ The following section types are defined and described later in this document:
| ManifestAssemblyMvids | 118 | Image (added in V5.3)
| CrossModuleInlineInfo | 119 | Image (added in V6.3)
| HotColdMap | 120 | Image (added in V8.0)
| MethodIsGenericMap | 121 | Assembly (Added in V9.0)
| EnclosingTypeMap | 122 | Assembly (Added in V9.0)
| TypeGenericInfoMap | 123 | Assembly (Added in V9.0)

## ReadyToRunSectionType.CompilerIdentifier

Expand Down Expand Up @@ -654,6 +657,33 @@ The methods in this table are sorted by their hot part runtime function indices,

This section may not exist if no method is split - this happens when the `--hot-cold-splitting` flag is not specified during compilation, or the compiler decides it should not split any methods.

## ReadyToRunSectionType.MethodIsGenericMap (v9.0+)
This optional section holds a bit vector to indicate if the MethodDefs contained within the assembly have generic parameters or not. This allows determining if a method is generic or not by querying a bit vector (which is fast, and efficient) as opposed to examining the GenericParameter table, or the signature of the Method.

The section begins with a single 32 bit integer indicating the number of bits in the bit vector. Following that integer is the actual bit vector of all of the data. The data is grouped into 8 bit bytes, where the least significant bit of the byte is the bit which represents the lowest MethodDef.

For instance, the first byte in the bit vector represents the MethodDefs 06000001 to 06000008, and the least signficant bit of that first byte is the bit representing the IsGeneric bit for MethodDef 06000001.

## ReadyToRunSectionType.EnclosingTypeMap (v9.0+)

This optional section allows for efficient O(1) lookup from the enclosed type to the type which encloses it without requiring the binary search that is necessary if using the ECMA 335 defined NestedClass table (which encodes exactly the same information). This section may only be included in the assembly if the assembly has fewer than 0xFFFE types defined within it.

The structure of this section is:
A single 16 bit unsigned integer listing the count of entries in the map.
This count is followed by a 16 bit unsigned integer for each TypeDef defined in the assembly. This typedef is the RID of the enclosing type, or 0 if the typedef is not enclosed by another type.

## ReadyToRunSectionType.TypeGenericInfoMap (v9.0+)
This optional section represents a condensed view of some generic details about types. This can make it more efficient to load types.

The structure of this section is:
A single 32 bit integer representing the number of entries in the map followed by a series of 4 bit entries, one per type. These 4 bit entries are grouped into bytes, where each byte holds 2 entries, and the entry in the most significant 4 bits of the byte is the entry representing a lower TypeDef RID.

TypeGenericInfoMap entries have 4 bits representing 3 different sets of information.

1. What is the count of generic parameters (0, 1, 2, MoreThanTwo) (This is represented in the least significant 2 bits of the TypeGenericInfoMap entry)
2. Are there any constraints on the generic parameters? (This is the 3rd bit of the entry)
3. Do any of the generic parameters have co or contra variance? (This is the 4th bit of the entry)

# Native Format

Native format is set of encoding patterns that allow persisting type system data in a binary format that is
Expand Down
25 changes: 25 additions & 0 deletions src/coreclr/inc/readytorun.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ enum class ReadyToRunSectionType : uint32_t
ManifestAssemblyMvids = 118, // Added in V5.3
CrossModuleInlineInfo = 119, // Added in V6.2
HotColdMap = 120, // Added in V8.0
MethodIsGenericMap = 121, // Added in V9.0
EnclosingTypeMap = 122, // Added in V9.0
TypeGenericInfoMap = 123, // Added in V9.0

// If you add a new section consider whether it is a breaking or non-breaking change.
// Usually it is non-breaking, but if it is preferable to have older runtimes fail
Expand Down Expand Up @@ -121,6 +124,28 @@ enum class ReadyToRunImportSectionFlags : uint16_t
PCode = 0x0004, // Section contains pointers to code
};

// All values in this enum should within a nibble (4 bits).
enum class ReadyToRunTypeGenericInfo : uint8_t
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
GenericCountMask = 0x3,
HasConstraints = 0x4,
HasVariance = 0x8,
};

// All values in this enum should fit within 2 bits.
enum class ReadyToRunGenericInfoGenericCount : uint32_t
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
Zero = 0,
One = 1,
Two = 2,
MoreThanTwo = 3
};

enum class ReadyToRunEnclosingTypeMap
{
MaxTypeCount = 0xFFFE
};

//
// READYTORUN_IMPORT_SECTION describes image range with references to code or runtime data structures
//
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,25 @@ internal class RuntimeGenericParameterDesc : GenericParameterDesc
{
private readonly GenericParameterKind _kind;
private readonly int _index;
private readonly TypeSystemContext _context;
private readonly GenericVariance _variance;
private readonly TypeSystemEntity _associatedTypeOrMethod;

public RuntimeGenericParameterDesc(GenericParameterKind kind, int index, TypeSystemContext context, GenericVariance variance)
public RuntimeGenericParameterDesc(GenericParameterKind kind, int index, TypeSystemEntity associatedTypeOrMethod, GenericVariance variance)
{
_kind = kind;
_index = index;
_context = context;
_associatedTypeOrMethod = associatedTypeOrMethod;
_variance = variance;
}

public override GenericParameterKind Kind => _kind;

public override int Index => _index;

public override TypeSystemContext Context => _context;
public override TypeSystemContext Context => _associatedTypeOrMethod.Context;

public override GenericVariance Variance => _variance;

public override TypeSystemEntity AssociatedTypeOrMethod => _associatedTypeOrMethod;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ public override Instantiation Instantiation
TypeDesc[] genericParameters = new TypeDesc[genericArgCount];
for (int i = 0; i < genericParameters.Length; i++)
{
genericParameters[i] = new RuntimeGenericParameterDesc(GenericParameterKind.Method, i, Context, GenericVariance.None);
var newGenericParameter = new RuntimeGenericParameterDesc(GenericParameterKind.Method, i, this, GenericVariance.None);
genericParameters[i] = newGenericParameter;
}
_instantiation = new Instantiation(genericParameters);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,46 @@ internal class NoMetadataType : DefType
// "_baseType == this" means "base type was not initialized yet"
private DefType _baseType;

public NoMetadataType(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, DefType genericTypeDefinitionAsDefType, Instantiation instantiation, int hashcode)
public unsafe NoMetadataType(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, int instantiationLength, ReadOnlySpan<Runtime.GenericVariance> runtimeVarianceData, int hashcode)
{
TypeDesc[] genericParameters;
if (instantiationLength == 0)
{
genericParameters = Array.Empty<TypeDesc>();
}
else
{
genericParameters = new TypeDesc[instantiationLength];
for (int i = 0; i < genericParameters.Length; i++)
{
GenericVariance variance = runtimeVarianceData.Length == 0 ? GenericVariance.None : runtimeVarianceData[i] switch
{
Runtime.GenericVariance.Contravariant => GenericVariance.Contravariant,
Runtime.GenericVariance.Covariant => GenericVariance.Covariant,
Runtime.GenericVariance.NonVariant or Runtime.GenericVariance.ArrayCovariant => GenericVariance.None,
_ => throw new NotImplementedException()
};
genericParameters[i] = new RuntimeGenericParameterDesc(GenericParameterKind.Type, i, this, variance);
}
}

Instantiation instantiation = new Instantiation(genericParameters);
Init(context, genericTypeDefinition, null, instantiation, hashcode);
}

public unsafe NoMetadataType(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, DefType genericTypeDefinitionAsDefType, Instantiation instantiation, int hashcode)
{
Init(context, genericTypeDefinition, genericTypeDefinitionAsDefType, instantiation, hashcode);
}

private void Init(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, DefType genericTypeDefinitionAsDefType, Instantiation instantiation, int hashcode)
{
_hashcode = hashcode;
_context = context;
_genericTypeDefinition = genericTypeDefinition;
_genericTypeDefinitionAsDefType = genericTypeDefinitionAsDefType;
_genericTypeDefinitionAsDefType ??= this;

_instantiation = instantiation;

// Instantiation must either be:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,19 +200,9 @@ public TypeDesc ResolveRuntimeTypeHandle(RuntimeTypeHandle rtth)
TypeDesc[] genericParameters = new TypeDesc[rtth.ToEETypePtr()->GenericParameterCount];
Runtime.GenericVariance* runtimeVariance = rtth.ToEETypePtr()->HasGenericVariance ?
rtth.ToEETypePtr()->GenericVariance : null;
for (int i = 0; i < genericParameters.Length; i++)
{
GenericVariance variance = runtimeVariance == null ? GenericVariance.None : runtimeVariance[i] switch
{
Runtime.GenericVariance.Contravariant => GenericVariance.Contravariant,
Runtime.GenericVariance.Covariant => GenericVariance.Covariant,
Runtime.GenericVariance.NonVariant or Runtime.GenericVariance.ArrayCovariant => GenericVariance.None,
_ => throw new NotImplementedException()
};
genericParameters[i] = genericParameters[i] = new RuntimeGenericParameterDesc(GenericParameterKind.Type, i, this, variance);
}
ReadOnlySpan<Runtime.GenericVariance> varianceData = new ReadOnlySpan<Runtime.GenericVariance>(runtimeVariance, runtimeVariance == null ? 0 : genericParameters.Length);

returnedType = new NoMetadataType(this, rtth, null, new Instantiation(genericParameters), rtth.GetHashCode());
returnedType = new NoMetadataType(this, rtth, genericParameters.Length, varianceData, rtth.GetHashCode());
}
}
else if (RuntimeAugments.IsGenericType(rtth))
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ public enum ReadyToRunSectionType
ManifestAssemblyMvids = 118, // Added in 5.3
CrossModuleInlineInfo = 119, // Added in 6.3
HotColdMap = 120, // Added in 8.0
MethodIsGenericMap = 121, // Added in V9.0
EnclosingTypeMap = 122, // Added in V9.0
TypeGenericInfoMap = 123, // Added in V9.0

//
// NativeAOT ReadyToRun sections
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ namespace Internal.ReadyToRunConstants
public enum ReadyToRunFlags
{
READYTORUN_FLAG_PlatformNeutralSource = 0x00000001, // Set if the original IL assembly was platform-neutral
READYTORUN_FLAG_SkipTypeValidation = 0x00000002, // Set of methods with native code was determined using profile data
READYTORUN_FLAG_Partial = 0x00000004,
READYTORUN_FLAG_SkipTypeValidation = 0x00000002, // Runtime should trust that the metadata for the types defined in this module is correct
READYTORUN_FLAG_Partial = 0x00000004, // Set of methods with native code was determined using profile data
READYTORUN_FLAG_NonSharedPInvokeStubs = 0x00000008, // PInvoke stubs compiled into image are non-shareable (no secret parameter)
READYTORUN_FLAG_EmbeddedMSIL = 0x00000010, // MSIL is embedded in the composite R2R executable
READYTORUN_FLAG_Component = 0x00000020, // This is the header describing a component assembly of composite R2R
Expand Down Expand Up @@ -89,6 +89,27 @@ internal enum ReadyToRunCrossModuleInlineFlags : uint
InlinerRidShift = 1,
};

[Flags]
public enum ReadyToRunTypeGenericInfo : byte
{
GenericCountMask = 0x3,
HasConstraints = 0x4,
HasVariance = 0x8,
}

public enum ReadyToRunGenericInfoGenericCount : uint
{
Zero = 0,
One = 1,
Two = 2,
MoreThanTwo = 3
}

AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
public enum ReadyToRunEnclosingTypeMap : uint
{
MaxTypeCount = 0xFFFE
}

public enum DictionaryEntryKind
{
EmptySlot = 0,
Expand Down
14 changes: 13 additions & 1 deletion src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,21 @@ private static bool CanCastGenericParameterTo(this GenericParameterDesc thisType
return true;
}

Instantiation typeInstantiation;
Instantiation methodInstantiation = default(Instantiation);
if (thisType.AssociatedTypeOrMethod is MethodDesc method)
{
typeInstantiation = method.OwningType.Instantiation;
methodInstantiation = method.Instantiation;
}
else
{
typeInstantiation = ((TypeDesc)thisType.AssociatedTypeOrMethod).Instantiation;
}
foreach (var typeConstraint in thisType.TypeConstraints)
{
if (typeConstraint.CanCastToInternal(otherType, protect))
TypeDesc instantiatedConstraint = typeConstraint.InstantiateSignature(typeInstantiation, methodInstantiation);
if (instantiatedConstraint.CanCastToInternal(otherType, protect))
{
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public virtual string Name
/// </summary>
public abstract int Index { get; }

/// <summary>
/// The associated type or method which defines this Generic Parameter
/// </summary>
public abstract TypeSystemEntity AssociatedTypeOrMethod { get; }

/// <summary>
/// Gets a value indicating the variance of this generic parameter.
/// </summary>
Expand Down Expand Up @@ -120,6 +125,9 @@ public virtual IEnumerable<TypeDesc> TypeConstraints
}
}

/// <summary>
/// Does this generic parameter have the NotNullableValueType constraint flag
/// </summary>
public bool HasNotNullableValueTypeConstraint
{
get
Expand All @@ -128,6 +136,9 @@ public bool HasNotNullableValueTypeConstraint
}
}

/// <summary>
/// Does this generic parameter have the ReferenceType constraint flag
/// </summary>
public bool HasReferenceTypeConstraint
{
get
Expand All @@ -136,6 +147,9 @@ public bool HasReferenceTypeConstraint
}
}

/// <summary>
/// Does this generic parameter have the DefaultConstructor constraint flag
/// </summary>
public bool HasDefaultConstructorConstraint
{
get
Expand All @@ -144,6 +158,20 @@ public bool HasDefaultConstructorConstraint
}
}

/// <summary>
/// Does this generic parameter have the AcceptByRefLike flag
/// </summary>
public bool HasAcceptByRefLikeConstraint
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
get
{
return (Constraints & GenericConstraints.AcceptByRefLike) != 0;
}
}

/// <summary>
/// Is this generic parameter Covariant
/// </summary>
public bool IsCovariant
{
get
Expand All @@ -152,6 +180,9 @@ public bool IsCovariant
}
}

/// <summary>
/// Is this generic parameter Contravariant
/// </summary>
public bool IsContravariant
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ protected override TypeFlags ComputeTypeFlags(TypeFlags mask)
flags |= TypeFlags.SignatureTypeVariable;
}

flags |= TypeFlags.AttributeCacheComputed;

return flags;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@

using System;
using System.Diagnostics;
using Internal.IL;
using Internal.TypeSystem;

namespace ILVerify
namespace Internal.TypeSystem
{
internal class SimpleArrayOfTRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm
public class SimpleArrayOfTRuntimeInterfacesAlgorithm : RuntimeInterfacesAlgorithm
{
private DefType[] _arrayRuntimeInterfaces;
private MetadataType[] _genericRuntimeInterfaces;
private ModuleDesc _systemModule;

private static readonly string[] s_genericRuntimeInterfacesNames =
private static readonly string[] s_genericRuntimeInterfacesNames =
{
"IEnumerable`1",
"ICollection`1",
Expand All @@ -28,7 +26,7 @@ public SimpleArrayOfTRuntimeInterfacesAlgorithm(ModuleDesc systemModule)
_systemModule = systemModule;

// initialize interfaces
_arrayRuntimeInterfaces = _systemModule.GetType("System", "Array")?.RuntimeInterfaces
_arrayRuntimeInterfaces = _systemModule.GetType("System", "Array")?.RuntimeInterfaces
?? Array.Empty<DefType>();

_genericRuntimeInterfaces = new MetadataType[s_genericRuntimeInterfacesNames.Length];
Expand Down
Loading