Skip to content

Commit 5faa346

Browse files
Introduce MetadataEEType node halfway between Constructed and Necessary (#118060)
1 parent 1722487 commit 5faa346

38 files changed

+526
-139
lines changed

src/coreclr/tools/Common/Compiler/DevirtualizationManager.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,12 @@ protected virtual MethodDesc ResolveVirtualMethod(MethodDesc declMethod, DefType
210210
/// </summary>
211211
public virtual bool CanReferenceConstructedMethodTable(TypeDesc type) => true;
212212

213+
/// <summary>
214+
/// Gets a value indicating whether it might be possible to obtain a metadata type data structure for the given type
215+
/// in this compilation (i.e. is it possible to reference a metadata MethodTable symbol for this).
216+
/// </summary>
217+
public virtual bool CanReferenceMetadataMethodTable(TypeDesc type) => true;
218+
213219
/// <summary>
214220
/// Gets a value indicating whether a (potentially canonically-equlivalent) constructed MethodTable could
215221
/// exist. This is similar to <see cref="CanReferenceConstructedMethodTable"/>, but will return true

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Compilation.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ public bool NeedsRuntimeLookup(ReadyToRunHelperId lookupKind, object targetOfLoo
241241
{
242242
case ReadyToRunHelperId.TypeHandle:
243243
case ReadyToRunHelperId.NecessaryTypeHandle:
244+
case ReadyToRunHelperId.MetadataTypeHandle:
244245
case ReadyToRunHelperId.DefaultConstructor:
245246
case ReadyToRunHelperId.TypeHandleForCasting:
246247
case ReadyToRunHelperId.ObjectAllocator:
@@ -271,13 +272,17 @@ public ReadyToRunHelperId GetLdTokenHelperForType(TypeDesc type)
271272
// We need to make a small exception for canonical definitions because of RuntimeAugments.GetCanonType
272273
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Any) || type.IsCanonicalDefinitionType(CanonicalFormKind.Any));
273274

274-
bool canPotentiallyConstruct = ConstructedEETypeNode.CreationAllowed(type)
275-
&& NodeFactory.DevirtualizationManager.CanReferenceConstructedMethodTable(type.NormalizeInstantiation());
276-
if (canPotentiallyConstruct)
277-
return ReadyToRunHelperId.TypeHandle;
278-
279275
if (type.IsGenericDefinition && NodeFactory.DevirtualizationManager.IsGenericDefinitionMethodTableReflectionVisible(type))
280-
return ReadyToRunHelperId.TypeHandle;
276+
return ReadyToRunHelperId.MetadataTypeHandle;
277+
278+
if (ConstructedEETypeNode.CreationAllowed(type))
279+
{
280+
if (NodeFactory.DevirtualizationManager.CanReferenceConstructedMethodTable(type.NormalizeInstantiation()))
281+
return ReadyToRunHelperId.TypeHandle;
282+
283+
if (NodeFactory.DevirtualizationManager.CanReferenceMetadataMethodTable(type.NormalizeInstantiation()))
284+
return ReadyToRunHelperId.MetadataTypeHandle;
285+
}
281286

282287
return ReadyToRunHelperId.NecessaryTypeHandle;
283288
}
@@ -307,6 +312,8 @@ public ISymbolNode ComputeConstantLookup(ReadyToRunHelperId lookupKind, object t
307312
{
308313
case ReadyToRunHelperId.TypeHandle:
309314
return NodeFactory.ConstructedTypeSymbol((TypeDesc)targetOfLookup);
315+
case ReadyToRunHelperId.MetadataTypeHandle:
316+
return NodeFactory.MetadataTypeSymbol((TypeDesc)targetOfLookup);
310317
case ReadyToRunHelperId.NecessaryTypeHandle:
311318
return NecessaryTypeSymbolIfPossible((TypeDesc)targetOfLookup);
312319
case ReadyToRunHelperId.TypeHandleForCasting:

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,16 @@ public ConstructedEETypeNode(NodeFactory factory, TypeDesc type) : base(factory,
2222

2323
protected override bool EmitVirtualSlots => true;
2424

25+
protected override bool IsReflectionVisible => true;
26+
2527
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
2628
{
2729
DependencyList dependencyList = base.ComputeNonRelocationBasedDependencies(factory);
2830

29-
// Ensure that we track the necessary type symbol if we are working with a constructed type symbol.
31+
// Ensure that we track the metadata type symbol if we are working with a constructed type symbol.
3032
// The emitter will ensure we don't emit both, but this allows us assert that we only generate
3133
// relocs to nodes we emit.
32-
dependencyList.Add(factory.NecessaryTypeSymbol(_type), "NecessaryType for constructed type");
33-
34-
if (_type is MetadataType mdType)
35-
ModuleUseBasedDependencyAlgorithm.AddDependenciesDueToModuleUse(ref dependencyList, factory, mdType.Module);
34+
dependencyList.Add(factory.MetadataTypeSymbol(_type), "MetadataType for constructed type");
3635

3736
DefType closestDefType = _type.GetClosestDefType();
3837

@@ -63,9 +62,6 @@ protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFact
6362
}
6463
else
6564
{
66-
// Ask the metadata manager if we have any dependencies due to the presence of the EEType.
67-
factory.MetadataManager.GetDependenciesDueToEETypePresence(ref dependencyList, factory, _type);
68-
6965
factory.InteropStubManager.AddInterestingInteropConstructedTypeDependencies(ref dependencyList, factory, _type);
7066
}
7167

@@ -80,7 +76,7 @@ protected override ISymbolNode GetBaseTypeNode(NodeFactory factory)
8076
protected override FrozenRuntimeTypeNode GetFrozenRuntimeTypeNode(NodeFactory factory)
8177
{
8278
Debug.Assert(!_type.IsCanonicalSubtype(CanonicalFormKind.Any));
83-
return factory.SerializedConstructedRuntimeTypeObject(_type);
79+
return factory.SerializedMetadataRuntimeTypeObject(_type);
8480
}
8581

8682
protected override ISymbolNode GetNonNullableValueTypeArrayElementTypeNode(NodeFactory factory)

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DictionaryLayoutNode.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,13 +212,23 @@ public override bool TryGetSlotForEntry(GenericLookupResult entry, out int slot)
212212
{
213213
slot = Array.IndexOf(_layout, entry);
214214

215-
// If we're looking for a necessary type handle and it doesn't exist, check for a constructed type handle.
216-
if (slot < 0 && entry is NecessaryTypeHandleGenericLookupResult necessaryLookup)
215+
216+
// If we're looking for a low type handle load level and it doesn't exist, check for a higher load level.
217+
var necessaryLookup = entry as NecessaryTypeHandleGenericLookupResult;
218+
var metadataLookup = entry as MetadataTypeHandleGenericLookupResult;
219+
if (slot < 0
220+
&& (necessaryLookup != null || metadataLookup != null))
217221
{
218222
for (int i = 0; i < _layout.Length; i++)
219223
{
220-
if (_layout[i] is TypeHandleGenericLookupResult other
221-
&& other.Type == necessaryLookup.Type)
224+
if (_layout[i] is TypeHandleGenericLookupResult thOther
225+
&& (thOther.Type == necessaryLookup?.Type || thOther.Type == metadataLookup?.Type))
226+
{
227+
slot = i;
228+
return true;
229+
}
230+
if (_layout[i] is MetadataTypeHandleGenericLookupResult mdOther
231+
&& mdOther.Type == necessaryLookup?.Type)
222232
{
223233
slot = i;
224234
return true;

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EETypeNode.cs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,7 @@ protected bool MightHaveInterfaceDispatchMap(NodeFactory factory)
200200

201201
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
202202
{
203-
// If there is a constructed version of this node in the graph, emit that instead
204-
if (ConstructedEETypeNode.CreationAllowed(_type))
205-
return factory.ConstructedTypeSymbol(_type).Marked;
206-
207-
return false;
203+
return factory.MetadataTypeSymbol(_type).Marked;
208204
}
209205

210206
public virtual ISymbolNode NodeForLinkage(NodeFactory factory)
@@ -226,6 +222,8 @@ protected override ObjectNodeSection GetDehydratedSection(NodeFactory factory)
226222

227223
protected virtual bool EmitVirtualSlots => false;
228224

225+
protected virtual bool IsReflectionVisible => false;
226+
229227
public override bool InterestingForDynamicDependencyAnalysis
230228
=> (_virtualMethodAnalysisFlags & VirtualMethodAnalysisFlags.InterestingForDynamicDependencies) != 0;
231229

@@ -283,6 +281,9 @@ public override bool HasConditionalStaticDependencies
283281
if (_type.RuntimeInterfaces.Length > 0)
284282
return true;
285283

284+
if (IsReflectionVisible && _hasConditionalDependenciesFromMetadataManager)
285+
return true;
286+
286287
if (!EmitVirtualSlots)
287288
return false;
288289

@@ -312,14 +313,31 @@ public override bool HasConditionalStaticDependencies
312313
currentType = currentType.BaseType;
313314
}
314315

315-
return _hasConditionalDependenciesFromMetadataManager;
316+
return false;
316317
}
317318
}
318319

319320
public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
320321
{
321322
List<CombinedDependencyListEntry> result = new List<CombinedDependencyListEntry>();
322323

324+
if (IsReflectionVisible)
325+
{
326+
factory.MetadataManager.GetConditionalDependenciesDueToEETypePresence(ref result, factory, _type, allocated: EmitVirtualSlots);
327+
328+
if (!_type.IsCanonicalSubtype(CanonicalFormKind.Any))
329+
{
330+
foreach (DefType iface in _type.RuntimeInterfaces)
331+
{
332+
var ifaceDefinition = (DefType)iface.GetTypeDefinition();
333+
result.Add(new CombinedDependencyListEntry(
334+
GetInterfaceTypeNode(factory, iface),
335+
factory.InterfaceUse(ifaceDefinition),
336+
"Interface definition was visible"));
337+
}
338+
}
339+
}
340+
323341
IEETypeNode maximallyConstructableType = factory.MaximallyConstructableType(_type);
324342

325343
if (maximallyConstructableType != this)
@@ -343,18 +361,6 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep
343361
"Information about static bases for type with template"));
344362
}
345363

346-
if (!_type.IsCanonicalSubtype(CanonicalFormKind.Any))
347-
{
348-
foreach (DefType iface in _type.RuntimeInterfaces)
349-
{
350-
var ifaceDefinition = (DefType)iface.GetTypeDefinition();
351-
result.Add(new CombinedDependencyListEntry(
352-
GetInterfaceTypeNode(factory, iface),
353-
factory.InterfaceUse(ifaceDefinition),
354-
"Interface definition was visible"));
355-
}
356-
}
357-
358364
if (!EmitVirtualSlots)
359365
return result;
360366

@@ -555,8 +561,6 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep
555561
}
556562
}
557563

558-
factory.MetadataManager.GetConditionalDependenciesDueToEETypePresence(ref result, factory, _type);
559-
560564
return result;
561565
}
562566

@@ -1132,16 +1136,16 @@ protected void OutputGenericInstantiationDetails(NodeFactory factory, ref Object
11321136
{
11331137
if (!_type.IsTypeDefinition)
11341138
{
1135-
IEETypeNode typeDefNode = factory.MaximallyConstructableType(_type) == this ?
1136-
factory.ConstructedTypeSymbol(_type.GetTypeDefinition()) : factory.NecessaryTypeSymbol(_type.GetTypeDefinition());
1139+
IEETypeNode typeDefNode = IsReflectionVisible ?
1140+
factory.MetadataTypeSymbol(_type.GetTypeDefinition()) : factory.NecessaryTypeSymbol(_type.GetTypeDefinition());
11371141
if (factory.Target.SupportsRelativePointers)
11381142
objData.EmitReloc(typeDefNode, RelocType.IMAGE_REL_BASED_RELPTR32);
11391143
else
11401144
objData.EmitPointerReloc(typeDefNode);
11411145

11421146
ISymbolNode compositionNode;
11431147

1144-
if (this == factory.MaximallyConstructableType(_type)
1148+
if (IsReflectionVisible
11451149
&& factory.MetadataManager.IsTypeInstantiationReflectionVisible(_type))
11461150
{
11471151
compositionNode = _type.Instantiation.Length > 1

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenRuntimeTypeNode.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ namespace ILCompiler.DependencyAnalysis
1212
public sealed class FrozenRuntimeTypeNode : FrozenObjectNode
1313
{
1414
private readonly TypeDesc _type;
15-
private readonly bool _constructed;
15+
private readonly bool _withMetadata;
1616

17-
public FrozenRuntimeTypeNode(TypeDesc type, bool constructed)
17+
public FrozenRuntimeTypeNode(TypeDesc type, bool withMetadata)
1818
{
1919
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Any));
2020
_type = type;
21-
_constructed = constructed;
21+
_withMetadata = withMetadata;
2222
}
2323

2424
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
@@ -30,8 +30,8 @@ public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilde
3030

3131
public override void EncodeContents(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
3232
{
33-
IEETypeNode typeSymbol = _constructed
34-
? factory.ConstructedTypeSymbol(_type)
33+
IEETypeNode typeSymbol = _withMetadata
34+
? factory.MetadataTypeSymbol(_type)
3535
: factory.NecessaryTypeSymbol(_type);
3636

3737
dataBuilder.EmitPointerReloc(factory.ConstructedTypeSymbol(ObjectType));

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDefinitionEETypeNode.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public ReflectionInvisibleGenericDefinitionEETypeNode(NodeFactory factory, TypeD
6969

7070
public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
7171
{
72-
return factory.ConstructedTypeSymbol(_type).Marked;
72+
return factory.MetadataTypeSymbol(_type).Marked;
7373
}
7474

7575
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
@@ -93,7 +93,7 @@ public override bool ShouldSkipEmittingObjectNode(NodeFactory factory)
9393

9494
protected override FrozenRuntimeTypeNode GetFrozenRuntimeTypeNode(NodeFactory factory)
9595
{
96-
return factory.SerializedConstructedRuntimeTypeObject(_type);
96+
return factory.SerializedMetadataRuntimeTypeObject(_type);
9797
}
9898

9999
protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler) + " reflection visible";

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericLookupResult.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,60 @@ protected override bool EqualsImpl(GenericLookupResult obj)
269269
}
270270
}
271271

272+
/// <summary>
273+
/// Generic lookup result that points to an MethodTable.
274+
/// </summary>
275+
public sealed class MetadataTypeHandleGenericLookupResult : GenericLookupResult
276+
{
277+
private TypeDesc _type;
278+
279+
protected override int ClassCode => -4892308;
280+
281+
public MetadataTypeHandleGenericLookupResult(TypeDesc type)
282+
{
283+
Debug.Assert(type.IsRuntimeDeterminedSubtype, "Concrete type in a generic dictionary?");
284+
_type = type;
285+
}
286+
287+
public override ISymbolNode GetTarget(NodeFactory factory, GenericLookupResultContext dictionary)
288+
{
289+
TypeDesc instantiatedType = _type.GetNonRuntimeDeterminedTypeFromRuntimeDeterminedSubtypeViaSubstitution(dictionary.TypeInstantiation, dictionary.MethodInstantiation);
290+
291+
factory.TypeSystemContext.DetectGenericCycles(dictionary.Context, instantiatedType);
292+
293+
return factory.MetadataTypeSymbol(instantiatedType);
294+
}
295+
296+
public override void AppendMangledName(NameMangler nameMangler, Utf8StringBuilder sb)
297+
{
298+
sb.Append("MetadataTypeHandle_"u8);
299+
sb.Append(nameMangler.GetMangledTypeName(_type));
300+
}
301+
302+
public TypeDesc Type => _type;
303+
public override string ToString() => $"MetadataTypeHandle: {_type}";
304+
305+
public override NativeLayoutVertexNode TemplateDictionaryNode(NodeFactory factory)
306+
{
307+
return factory.NativeLayout.TypeHandleDictionarySlot(_type);
308+
}
309+
310+
protected override int CompareToImpl(GenericLookupResult other, TypeSystemComparer comparer)
311+
{
312+
return comparer.Compare(_type, ((MetadataTypeHandleGenericLookupResult)other)._type);
313+
}
314+
315+
protected override int GetHashCodeImpl()
316+
{
317+
return _type.GetHashCode();
318+
}
319+
320+
protected override bool EqualsImpl(GenericLookupResult obj)
321+
{
322+
return ((MetadataTypeHandleGenericLookupResult)obj)._type == _type;
323+
}
324+
}
325+
272326
/// <summary>
273327
/// Generic lookup result that points to an MethodTable where if the type is Nullable&lt;X&gt; the MethodTable is X
274328
/// </summary>

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericVirtualMethodTableNode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ public static void GetGenericVirtualMethodImplementationDependencies(ref Depende
5454
MethodDesc openImplementationMethod = implementationMethod.GetTypicalMethodDefinition();
5555

5656
factory.MetadataManager.GetNativeLayoutMetadataDependencies(ref dependencies, factory, openCallingMethod);
57+
dependencies.Add(factory.NecessaryTypeSymbol(openCallingMethod.OwningType), "Owning type of GVM declaration");
5758
factory.MetadataManager.GetNativeLayoutMetadataDependencies(ref dependencies, factory, openImplementationMethod);
59+
dependencies.Add(factory.NecessaryTypeSymbol(openImplementationMethod.OwningType), "Owning type of GVM implementation");
5860
}
5961

6062
private void AddGenericVirtualMethodImplementation(MethodDesc callingMethod, MethodDesc implementationMethod)

0 commit comments

Comments
 (0)