Skip to content

Commit 8042fac

Browse files
Improve the performance of the type loader through various tweaks (#85743)
* Skip type validation by default in ReadyToRun images - Technically, this is a breaking change, so I've provided a means for disabling the type validation skip - The model is that the C# compile won't get these details wrong, so disable the checks when run through crossgen2. The idea is that we'll get these things checked during normal, non-R2R usage of the app, and publish won't check these details. * Replace expensive lookups of generic parameter and nested class data with R2R optimized forms * Store index of MethodDesc as well as ChunkIndex. Makes MethodDesc::GetTemporaryEntryPoint *much* faster * Optimize the path for computing if a method is eligible for tiered compilation * Remove CanShareVtableChunksFrom concept - it was only needed to support NGen * Fix up some more issues * Bring back late virtual propagation in the presence of covariant overrides only * Check correct flag on EEClass * Drive by fix for GetRestoredSlot. We don't need the handling of unrestored slots anymore * Fix composite build with new tables * Uniquify the mangled names * Add more __ * Initial pass at type skip verifation checker * Fix logging and some correctness issues * Enable the more of type checking - Notably, the recursive stuff now works - Also fix a bug in constraint checking involving open types in the type system * Fix build breaks involving new feature of GenericParameterDesc * Add documentation for R2R format changes Fix command line parameter to be more reasonable, and allow logging on command Fix the rest of issues noted in crossgen2 testing * Fix implementation of CompareMethodContraints. instead of using IsGeneric map, check to see if the method is generic in the first place. It turns out we have an efficient way to check in every place that matters * Fix nits noticed by Aaron * Add some const correctness to the world * Fix issues noted by Michal, as well as remaining constrain checking issues * Code review details * Code review from trylek
1 parent 1087766 commit 8042fac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1814
-532
lines changed

docs/design/coreclr/botr/readytorun-format.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,9 @@ The following section types are defined and described later in this document:
180180
| ManifestAssemblyMvids | 118 | Image (added in V5.3)
181181
| CrossModuleInlineInfo | 119 | Image (added in V6.3)
182182
| HotColdMap | 120 | Image (added in V8.0)
183+
| MethodIsGenericMap | 121 | Assembly (Added in V9.0)
184+
| EnclosingTypeMap | 122 | Assembly (Added in V9.0)
185+
| TypeGenericInfoMap | 123 | Assembly (Added in V9.0)
183186

184187
## ReadyToRunSectionType.CompilerIdentifier
185188

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

655658
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.
656659

660+
## ReadyToRunSectionType.MethodIsGenericMap (v9.0+)
661+
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.
662+
663+
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.
664+
665+
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.
666+
667+
## ReadyToRunSectionType.EnclosingTypeMap (v9.0+)
668+
669+
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.
670+
671+
The structure of this section is:
672+
A single 16 bit unsigned integer listing the count of entries in the map.
673+
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.
674+
675+
## ReadyToRunSectionType.TypeGenericInfoMap (v9.0+)
676+
This optional section represents a condensed view of some generic details about types. This can make it more efficient to load types.
677+
678+
The structure of this section is:
679+
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.
680+
681+
TypeGenericInfoMap entries have 4 bits representing 3 different sets of information.
682+
683+
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)
684+
2. Are there any constraints on the generic parameters? (This is the 3rd bit of the entry)
685+
3. Do any of the generic parameters have co or contra variance? (This is the 4th bit of the entry)
686+
657687
# Native Format
658688

659689
Native format is set of encoding patterns that allow persisting type system data in a binary format that is

src/coreclr/inc/readytorun.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ enum class ReadyToRunSectionType : uint32_t
9292
ManifestAssemblyMvids = 118, // Added in V5.3
9393
CrossModuleInlineInfo = 119, // Added in V6.2
9494
HotColdMap = 120, // Added in V8.0
95+
MethodIsGenericMap = 121, // Added in V9.0
96+
EnclosingTypeMap = 122, // Added in V9.0
97+
TypeGenericInfoMap = 123, // Added in V9.0
9598

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

127+
// All values in this enum should within a nibble (4 bits).
128+
enum class ReadyToRunTypeGenericInfo : uint8_t
129+
{
130+
GenericCountMask = 0x3,
131+
HasConstraints = 0x4,
132+
HasVariance = 0x8,
133+
};
134+
135+
// All values in this enum should fit within 2 bits.
136+
enum class ReadyToRunGenericInfoGenericCount : uint32_t
137+
{
138+
Zero = 0,
139+
One = 1,
140+
Two = 2,
141+
MoreThanTwo = 3
142+
};
143+
144+
enum class ReadyToRunEnclosingTypeMap
145+
{
146+
MaxTypeCount = 0xFFFE
147+
};
148+
124149
//
125150
// READYTORUN_IMPORT_SECTION describes image range with references to code or runtime data structures
126151
//

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeGenericParameterDesc.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,25 @@ internal class RuntimeGenericParameterDesc : GenericParameterDesc
77
{
88
private readonly GenericParameterKind _kind;
99
private readonly int _index;
10-
private readonly TypeSystemContext _context;
1110
private readonly GenericVariance _variance;
11+
private readonly TypeSystemEntity _associatedTypeOrMethod;
1212

13-
public RuntimeGenericParameterDesc(GenericParameterKind kind, int index, TypeSystemContext context, GenericVariance variance)
13+
public RuntimeGenericParameterDesc(GenericParameterKind kind, int index, TypeSystemEntity associatedTypeOrMethod, GenericVariance variance)
1414
{
1515
_kind = kind;
1616
_index = index;
17-
_context = context;
17+
_associatedTypeOrMethod = associatedTypeOrMethod;
1818
_variance = variance;
1919
}
2020

2121
public override GenericParameterKind Kind => _kind;
2222

2323
public override int Index => _index;
2424

25-
public override TypeSystemContext Context => _context;
25+
public override TypeSystemContext Context => _associatedTypeOrMethod.Context;
2626

2727
public override GenericVariance Variance => _variance;
28+
29+
public override TypeSystemEntity AssociatedTypeOrMethod => _associatedTypeOrMethod;
2830
}
2931
}

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeMethodDesc.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public override Instantiation Instantiation
5252
TypeDesc[] genericParameters = new TypeDesc[genericArgCount];
5353
for (int i = 0; i < genericParameters.Length; i++)
5454
{
55-
genericParameters[i] = new RuntimeGenericParameterDesc(GenericParameterKind.Method, i, Context, GenericVariance.None);
55+
var newGenericParameter = new RuntimeGenericParameterDesc(GenericParameterKind.Method, i, this, GenericVariance.None);
56+
genericParameters[i] = newGenericParameter;
5657
}
5758
_instantiation = new Instantiation(genericParameters);
5859
}

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/RuntimeNoMetadataType.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,46 @@ internal class NoMetadataType : DefType
3434
// "_baseType == this" means "base type was not initialized yet"
3535
private DefType _baseType;
3636

37-
public NoMetadataType(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, DefType genericTypeDefinitionAsDefType, Instantiation instantiation, int hashcode)
37+
public unsafe NoMetadataType(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, int instantiationLength, ReadOnlySpan<Runtime.GenericVariance> runtimeVarianceData, int hashcode)
38+
{
39+
TypeDesc[] genericParameters;
40+
if (instantiationLength == 0)
41+
{
42+
genericParameters = Array.Empty<TypeDesc>();
43+
}
44+
else
45+
{
46+
genericParameters = new TypeDesc[instantiationLength];
47+
for (int i = 0; i < genericParameters.Length; i++)
48+
{
49+
GenericVariance variance = runtimeVarianceData.Length == 0 ? GenericVariance.None : runtimeVarianceData[i] switch
50+
{
51+
Runtime.GenericVariance.Contravariant => GenericVariance.Contravariant,
52+
Runtime.GenericVariance.Covariant => GenericVariance.Covariant,
53+
Runtime.GenericVariance.NonVariant or Runtime.GenericVariance.ArrayCovariant => GenericVariance.None,
54+
_ => throw new NotImplementedException()
55+
};
56+
genericParameters[i] = new RuntimeGenericParameterDesc(GenericParameterKind.Type, i, this, variance);
57+
}
58+
}
59+
60+
Instantiation instantiation = new Instantiation(genericParameters);
61+
Init(context, genericTypeDefinition, null, instantiation, hashcode);
62+
}
63+
64+
public unsafe NoMetadataType(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, DefType genericTypeDefinitionAsDefType, Instantiation instantiation, int hashcode)
65+
{
66+
Init(context, genericTypeDefinition, genericTypeDefinitionAsDefType, instantiation, hashcode);
67+
}
68+
69+
private void Init(TypeSystemContext context, RuntimeTypeHandle genericTypeDefinition, DefType genericTypeDefinitionAsDefType, Instantiation instantiation, int hashcode)
3870
{
3971
_hashcode = hashcode;
4072
_context = context;
4173
_genericTypeDefinition = genericTypeDefinition;
4274
_genericTypeDefinitionAsDefType = genericTypeDefinitionAsDefType;
4375
_genericTypeDefinitionAsDefType ??= this;
76+
4477
_instantiation = instantiation;
4578

4679
// Instantiation must either be:

src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/TypeSystem/TypeSystemContext.Runtime.cs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -200,19 +200,9 @@ public TypeDesc ResolveRuntimeTypeHandle(RuntimeTypeHandle rtth)
200200
TypeDesc[] genericParameters = new TypeDesc[rtth.ToEETypePtr()->GenericParameterCount];
201201
Runtime.GenericVariance* runtimeVariance = rtth.ToEETypePtr()->HasGenericVariance ?
202202
rtth.ToEETypePtr()->GenericVariance : null;
203-
for (int i = 0; i < genericParameters.Length; i++)
204-
{
205-
GenericVariance variance = runtimeVariance == null ? GenericVariance.None : runtimeVariance[i] switch
206-
{
207-
Runtime.GenericVariance.Contravariant => GenericVariance.Contravariant,
208-
Runtime.GenericVariance.Covariant => GenericVariance.Covariant,
209-
Runtime.GenericVariance.NonVariant or Runtime.GenericVariance.ArrayCovariant => GenericVariance.None,
210-
_ => throw new NotImplementedException()
211-
};
212-
genericParameters[i] = genericParameters[i] = new RuntimeGenericParameterDesc(GenericParameterKind.Type, i, this, variance);
213-
}
203+
ReadOnlySpan<Runtime.GenericVariance> varianceData = new ReadOnlySpan<Runtime.GenericVariance>(runtimeVariance, runtimeVariance == null ? 0 : genericParameters.Length);
214204

215-
returnedType = new NoMetadataType(this, rtth, null, new Instantiation(genericParameters), rtth.GetHashCode());
205+
returnedType = new NoMetadataType(this, rtth, genericParameters.Length, varianceData, rtth.GetHashCode());
216206
}
217207
}
218208
else if (RuntimeAugments.IsGenericType(rtth))

src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ public enum ReadyToRunSectionType
7171
ManifestAssemblyMvids = 118, // Added in 5.3
7272
CrossModuleInlineInfo = 119, // Added in 6.3
7373
HotColdMap = 120, // Added in 8.0
74+
MethodIsGenericMap = 121, // Added in V9.0
75+
EnclosingTypeMap = 122, // Added in V9.0
76+
TypeGenericInfoMap = 123, // Added in V9.0
7477

7578
//
7679
// NativeAOT ReadyToRun sections

src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ namespace Internal.ReadyToRunConstants
1212
public enum ReadyToRunFlags
1313
{
1414
READYTORUN_FLAG_PlatformNeutralSource = 0x00000001, // Set if the original IL assembly was platform-neutral
15-
READYTORUN_FLAG_SkipTypeValidation = 0x00000002, // Set of methods with native code was determined using profile data
16-
READYTORUN_FLAG_Partial = 0x00000004,
15+
READYTORUN_FLAG_SkipTypeValidation = 0x00000002, // Runtime should trust that the metadata for the types defined in this module is correct
16+
READYTORUN_FLAG_Partial = 0x00000004, // Set of methods with native code was determined using profile data
1717
READYTORUN_FLAG_NonSharedPInvokeStubs = 0x00000008, // PInvoke stubs compiled into image are non-shareable (no secret parameter)
1818
READYTORUN_FLAG_EmbeddedMSIL = 0x00000010, // MSIL is embedded in the composite R2R executable
1919
READYTORUN_FLAG_Component = 0x00000020, // This is the header describing a component assembly of composite R2R
@@ -89,6 +89,27 @@ internal enum ReadyToRunCrossModuleInlineFlags : uint
8989
InlinerRidShift = 1,
9090
};
9191

92+
[Flags]
93+
public enum ReadyToRunTypeGenericInfo : byte
94+
{
95+
GenericCountMask = 0x3,
96+
HasConstraints = 0x4,
97+
HasVariance = 0x8,
98+
}
99+
100+
public enum ReadyToRunGenericInfoGenericCount : uint
101+
{
102+
Zero = 0,
103+
One = 1,
104+
Two = 2,
105+
MoreThanTwo = 3
106+
}
107+
108+
public enum ReadyToRunEnclosingTypeMap : uint
109+
{
110+
MaxTypeCount = 0xFFFE
111+
}
112+
92113
public enum DictionaryEntryKind
93114
{
94115
EmptySlot = 0,

src/coreclr/tools/Common/TypeSystem/Common/CastingHelper.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,21 @@ private static bool CanCastGenericParameterTo(this GenericParameterDesc thisType
195195
return true;
196196
}
197197

198+
Instantiation typeInstantiation;
199+
Instantiation methodInstantiation = default(Instantiation);
200+
if (thisType.AssociatedTypeOrMethod is MethodDesc method)
201+
{
202+
typeInstantiation = method.OwningType.Instantiation;
203+
methodInstantiation = method.Instantiation;
204+
}
205+
else
206+
{
207+
typeInstantiation = ((TypeDesc)thisType.AssociatedTypeOrMethod).Instantiation;
208+
}
198209
foreach (var typeConstraint in thisType.TypeConstraints)
199210
{
200-
if (typeConstraint.CanCastToInternal(otherType, protect))
211+
TypeDesc instantiatedConstraint = typeConstraint.InstantiateSignature(typeInstantiation, methodInstantiation);
212+
if (instantiatedConstraint.CanCastToInternal(otherType, protect))
201213
{
202214
return true;
203215
}

src/coreclr/tools/Common/TypeSystem/Common/GenericParameterDesc.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ public virtual string Name
8787
/// </summary>
8888
public abstract int Index { get; }
8989

90+
/// <summary>
91+
/// The associated type or method which defines this Generic Parameter
92+
/// </summary>
93+
public abstract TypeSystemEntity AssociatedTypeOrMethod { get; }
94+
9095
/// <summary>
9196
/// Gets a value indicating the variance of this generic parameter.
9297
/// </summary>
@@ -120,6 +125,9 @@ public virtual IEnumerable<TypeDesc> TypeConstraints
120125
}
121126
}
122127

128+
/// <summary>
129+
/// Does this generic parameter have the NotNullableValueType constraint flag
130+
/// </summary>
123131
public bool HasNotNullableValueTypeConstraint
124132
{
125133
get
@@ -128,6 +136,9 @@ public bool HasNotNullableValueTypeConstraint
128136
}
129137
}
130138

139+
/// <summary>
140+
/// Does this generic parameter have the ReferenceType constraint flag
141+
/// </summary>
131142
public bool HasReferenceTypeConstraint
132143
{
133144
get
@@ -136,6 +147,9 @@ public bool HasReferenceTypeConstraint
136147
}
137148
}
138149

150+
/// <summary>
151+
/// Does this generic parameter have the DefaultConstructor constraint flag
152+
/// </summary>
139153
public bool HasDefaultConstructorConstraint
140154
{
141155
get
@@ -144,6 +158,20 @@ public bool HasDefaultConstructorConstraint
144158
}
145159
}
146160

161+
/// <summary>
162+
/// Does this generic parameter have the AcceptByRefLike flag
163+
/// </summary>
164+
public bool HasAcceptByRefLikeConstraint
165+
{
166+
get
167+
{
168+
return (Constraints & GenericConstraints.AcceptByRefLike) != 0;
169+
}
170+
}
171+
172+
/// <summary>
173+
/// Is this generic parameter Covariant
174+
/// </summary>
147175
public bool IsCovariant
148176
{
149177
get
@@ -152,6 +180,9 @@ public bool IsCovariant
152180
}
153181
}
154182

183+
/// <summary>
184+
/// Is this generic parameter Contravariant
185+
/// </summary>
155186
public bool IsContravariant
156187
{
157188
get

0 commit comments

Comments
 (0)