diff options
author | Michal Strehovsky <michals@microsoft.com> | 2018-03-06 12:41:14 +0300 |
---|---|---|
committer | Michal Strehovsky <michals@microsoft.com> | 2018-03-06 12:41:14 +0300 |
commit | 8749b7ccb56c4596347c8dc7b47fabadbd8df7d4 (patch) | |
tree | bf63b4601965fbc228c187a9b5a212c09aaa1d66 /src | |
parent | 6272cad0d0599a78170c7c621282d31dcceae9eb (diff) |
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]
Diffstat (limited to 'src')
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 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 /// </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) => |