From 8749b7ccb56c4596347c8dc7b47fabadbd8df7d4 Mon Sep 17 00:00:00 2001 From: Michal Strehovsky Date: Tue, 6 Mar 2018 01:41:14 -0800 Subject: Avoid generating empty dispatch maps This change makes Project X SharedLibrary 0.9% smaller, and a CoreRT hello world almost 2% smaller. The savings are threefold: * No longer generating empty dispatch maps (4 bytes per dispatch map) * No longer needing optional fields for a lot of types (the only reason was to indicate there was a dispatch map) * No longer needing a pointer to optional fields for a lot of types in the EEType [tfs-changeset: 1690800] --- .../DependencyAnalysis/CanonicalEETypeNode.cs | 2 +- .../DependencyAnalysis/ConstructedEETypeNode.cs | 2 +- .../src/Compiler/DependencyAnalysis/EETypeNode.cs | 2 +- .../DependencyAnalysis/InterfaceDispatchMapNode.cs | 45 +++++++++++++++++++++- .../src/Compiler/DependencyAnalysis/NodeFactory.cs | 2 +- 5 files changed, 48 insertions(+), 5 deletions(-) (limited to 'src') 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 3eeb0909d..5c93df610 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 /// 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; } + /// + /// Gets a value indicating whether '' 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. + /// + 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 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 type) => { - return new InterfaceDispatchMapNode(type); + return new InterfaceDispatchMapNode(this, type); }); _sealedVtableNodes = new NodeCache((TypeDesc type) => -- cgit v1.2.3