diff options
5 files changed, 48 insertions, 5 deletions
diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs index 807f620b9..6e3bc9f58 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/CanonicalEETypeNode.cs @@ -46,7 +46,7 @@ namespace ILCompiler.DependencyAnalysis DefType closestDefType = _type.GetClosestDefType(); - if (_type.RuntimeInterfaces.Length > 0 && !_type.IsArrayTypeWithoutGenericInterfaces()) + if (InterfaceDispatchMapNode.MightHaveInterfaceDispatchMap(_type, factory)) dependencyList.Add(factory.InterfaceDispatchMap(_type), "Canonical interface dispatch map"); dependencyList.Add(factory.VTable(closestDefType), "VTable"); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs index 4dc900b3e..0dee4d7cb 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/ConstructedEETypeNode.cs @@ -80,7 +80,7 @@ namespace ILCompiler.DependencyAnalysis DefType closestDefType = _type.GetClosestDefType(); - if (_type.RuntimeInterfaces.Length > 0 && !_type.IsArrayTypeWithoutGenericInterfaces()) + if (InterfaceDispatchMapNode.MightHaveInterfaceDispatchMap(_type, factory)) { dependencyList.Add(factory.InterfaceDispatchMap(_type), "Interface dispatch map"); } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs index dfe887c46..8df68bd1d 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/EETypeNode.cs @@ -867,7 +867,7 @@ namespace ILCompiler.DependencyAnalysis /// </summary> protected internal virtual void ComputeOptionalEETypeFields(NodeFactory factory, bool relocsOnly) { - if (!relocsOnly && _type.RuntimeInterfaces.Length > 0 && !_type.IsArrayTypeWithoutGenericInterfaces() && factory.InterfaceDispatchMap(_type).Marked) + if (!relocsOnly && EmitVirtualSlotsAndInterfaces && InterfaceDispatchMapNode.MightHaveInterfaceDispatchMap(_type, factory)) { _optionalFieldsBuilder.SetFieldValue(EETypeOptionalFieldTag.DispatchMap, checked((uint)factory.InterfaceDispatchMapIndirection(Type).IndexFromBeginningOfArray)); } diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs index 71966e20f..b631efaff 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/InterfaceDispatchMapNode.cs @@ -15,12 +15,13 @@ 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; } @@ -62,6 +63,48 @@ 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; + + DefType defType = type.GetClosestDefType(); + + foreach (DefType interfaceType in defType.RuntimeInterfaces) + { + 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 declMethod in slots) + { + if (declMethod.Signature.IsStatic) + continue; + + var implMethod = defType.ResolveInterfaceMethodToVirtualMethodOnType(declMethod); + if (implMethod != null) + return true; + } + } + + return false; + } + void EmitDispatchMap(ref ObjectDataBuilder builder, NodeFactory factory) { var entryCountReservation = builder.ReserveInt(); diff --git a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs index 597b2d55a..35795ed02 100644 --- a/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/ILCompiler.Compiler/src/Compiler/DependencyAnalysis/NodeFactory.cs @@ -379,7 +379,7 @@ namespace ILCompiler.DependencyAnalysis _interfaceDispatchMaps = new NodeCache<TypeDesc, InterfaceDispatchMapNode>((TypeDesc type) => { - return new InterfaceDispatchMapNode(type); + return new InterfaceDispatchMapNode(this, type); }); _sealedVtableNodes = new NodeCache<TypeDesc, SealedVTableNode>((TypeDesc type) => |