Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs')
-rw-r--r--src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs97
1 files changed, 82 insertions, 15 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs
index e2f6a6535..2da7c8d02 100644
--- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs
+++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs
@@ -15,8 +15,14 @@ namespace ILCompiler.DependencyAnalysis
{
TypeDesc _type;
- public InterfaceDispatchMapNode(TypeDesc type)
+ public InterfaceDispatchMapNode(NodeFactory factory, TypeDesc type)
{
+ // Multidimensional arrays should not get a sealed vtable or a dispatch map. Runtime should use the
+ // sealed vtable and dispatch map of the System.Array basetype instead.
+ // Pointer arrays also follow the same path
+ Debug.Assert(!type.IsArrayTypeWithoutGenericInterfaces());
+ Debug.Assert(MightHaveInterfaceDispatchMap(type, factory));
+
_type = type;
}
@@ -57,14 +63,71 @@ namespace ILCompiler.DependencyAnalysis
return result;
}
+ /// <summary>
+ /// Gets a value indicating whether '<paramref name="type"/>' might have a non-empty dispatch map.
+ /// Note that this is only an approximation because we might not be able to take into account
+ /// whether the interface methods are actually used.
+ /// </summary>
+ public static bool MightHaveInterfaceDispatchMap(TypeDesc type, NodeFactory factory)
+ {
+ if (type.IsArrayTypeWithoutGenericInterfaces())
+ return false;
+
+ if (!type.IsArray && !type.IsDefType)
+ return false;
+
+ TypeDesc declType = type.GetClosestDefType();
+
+ for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++)
+ {
+ DefType interfaceType = declType.RuntimeInterfaces[interfaceIndex];
+ InstantiatedType interfaceOnDefinitionType = interfaceType.IsTypeDefinition ?
+ null :
+ (InstantiatedType)declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex];
+
+ IEnumerable<MethodDesc> slots;
+
+ // If the vtable has fixed slots, we can query it directly.
+ // If it's a lazily built vtable, we might not be able to query slots
+ // just yet, so approximate by looking at all methods.
+ VTableSliceNode vtableSlice = factory.VTable(interfaceType);
+ if (vtableSlice.HasFixedSlots)
+ slots = vtableSlice.Slots;
+ else
+ slots = interfaceType.GetAllMethods();
+
+ foreach (MethodDesc slotMethod in slots)
+ {
+ MethodDesc declMethod = slotMethod;
+ if (interfaceOnDefinitionType != null)
+ declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), interfaceOnDefinitionType);
+
+ if (declMethod.Signature.IsStatic)
+ continue;
+
+ var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod);
+ if (implMethod != null)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory)
{
var entryCountReservation = builder.ReserveInt();
int entryCount = 0;
-
- for (int interfaceIndex = 0; interfaceIndex < _type.RuntimeInterfaces.Length; interfaceIndex++)
+
+ TypeDesc declType = _type.GetClosestDefType();
+
+ // Catch any runtime interface collapsing. We shouldn't have any
+ Debug.Assert(declType.RuntimeInterfaces.Length == declType.GetTypeDefinition().RuntimeInterfaces.Length);
+
+ for (int interfaceIndex = 0; interfaceIndex < declType.RuntimeInterfaces.Length; interfaceIndex++)
{
- var interfaceType = _type.RuntimeInterfaces[interfaceIndex];
+ var interfaceType = declType.RuntimeInterfaces[interfaceIndex];
+ var interfaceDefinitionType = declType.GetTypeDefinition().RuntimeInterfaces[interfaceIndex];
Debug.Assert(interfaceType.IsInterface);
IReadOnlyList<MethodDesc> virtualSlots = factory.VTable(interfaceType).Slots;
@@ -72,15 +135,26 @@ namespace ILCompiler.DependencyAnalysis
for (int interfaceMethodSlot = 0; interfaceMethodSlot < virtualSlots.Count; interfaceMethodSlot++)
{
MethodDesc declMethod = virtualSlots[interfaceMethodSlot];
- var implMethod = _type.GetClosestDefType().ResolveInterfaceMethodToVirtualMethodOnType(declMethod);
+ if(!interfaceType.IsTypeDefinition)
+ declMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(declMethod.GetTypicalMethodDefinition(), (InstantiatedType)interfaceDefinitionType);
+
+ var implMethod = declType.GetTypeDefinition().ResolveInterfaceMethodToVirtualMethodOnType(declMethod);
// Interface methods first implemented by a base type in the hierarchy will return null for the implMethod (runtime interface
// dispatch will walk the inheritance chain).
if (implMethod != null)
{
+ TypeDesc implType = declType;
+ while (!implType.HasSameTypeDefinition(implMethod.OwningType))
+ implType = implType.BaseType;
+
+ MethodDesc targetMethod = implMethod;
+ if (!implType.IsTypeDefinition)
+ targetMethod = factory.TypeSystemContext.GetMethodForInstantiatedType(implMethod.GetTypicalMethodDefinition(), (InstantiatedType)implType);
+
builder.EmitShort(checked((short)interfaceIndex));
builder.EmitShort(checked((short)(interfaceMethodSlot + (interfaceType.HasGenericDictionarySlot() ? 1 : 0))));
- builder.EmitShort(checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, implMethod)));
+ builder.EmitShort(checked((short)VirtualMethodSlotHelper.GetVirtualMethodSlot(factory, targetMethod, declType)));
entryCount++;
}
}
@@ -103,18 +177,11 @@ namespace ILCompiler.DependencyAnalysis
return objData.ToObjectData();
}
- protected internal override int ClassCode => 848664602;
+ public override int ClassCode => 848664602;
- protected internal override int CompareToImpl(SortableDependencyNode other, CompilerComparer comparer)
+ public override int CompareToImpl(ISortableNode other, CompilerComparer comparer)
{
return comparer.Compare(_type, ((InterfaceDispatchMapNode)other)._type);
}
-
- int ISortableSymbolNode.ClassCode => ClassCode;
-
- int ISortableSymbolNode.CompareToImpl(ISortableSymbolNode other, CompilerComparer comparer)
- {
- return CompareToImpl((ObjectNode)other, comparer);
- }
}
}