Crossgen2 - precompile generic instantiations (#2154)
authorJan Vorlicek <janvorli@microsoft.com>
Mon, 27 Jan 2020 20:42:34 +0000 (21:42 +0100)
committerGitHub <noreply@github.com>
Mon, 27 Jan 2020 20:42:34 +0000 (21:42 +0100)
* Crossgen2 - precompile generic instantiations

This change adds precompilation of all methods on generic instantiations
of types that are encountered during compilation. In my powershell
startup time experiments, it shaved off about 110 methods from the ones
that needed to be jitted at runtime and looking at e.g.
System.Private.CoreLib.dll precompilation result, it is much closer to
the version we get from the old crossgen now.

* Create a new node type to carry the method dependecies

src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs [new file with mode: 0644]
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/TypeFixupSignature.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRunCodegenNodeFactory.cs
src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj

diff --git a/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs b/src/coreclr/src/tools/crossgen2/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/AllMethodsOnTypeNode.cs
new file mode 100644 (file)
index 0000000..643b35f
--- /dev/null
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+
+using ILCompiler.DependencyAnalysisFramework;
+using Internal.Text;
+using Internal.TypeSystem;
+
+namespace ILCompiler.DependencyAnalysis.ReadyToRun
+{
+    public class AllMethodsOnTypeNode : DependencyNodeCore<NodeFactory>
+    {
+        private readonly TypeDesc _type;
+
+        public AllMethodsOnTypeNode(TypeDesc type)
+        {
+            _type = type;
+        }
+
+        public TypeDesc Type => _type;
+
+        public override bool InterestingForDynamicDependencyAnalysis => false;
+
+        public override bool HasDynamicDependencies => false;
+
+        public override bool HasConditionalStaticDependencies => false;
+
+        public override bool StaticDependenciesAreComputed => true;
+
+        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory context) => null;
+        public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => null;
+
+        public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
+        {
+            DependencyList dependencies = new DependencyList();
+
+            foreach (MethodDesc method in Type.GetAllMethods())
+            {
+                if (!method.IsGenericMethodDefinition && context.CompilationModuleGroup.VersionsWithMethodBody(method))
+                {
+                    dependencies.Add(context.MethodEntrypoint(method), $"Method on type {Type.ToString()}");
+                }
+            }
+
+            return dependencies;
+        }
+
+        protected override string GetName(NodeFactory factory) => $"All methods on type {Type.ToString()}";
+    }
+}
index 19d35d4..aeca3ab 100644 (file)
@@ -68,5 +68,16 @@ namespace ILCompiler.DependencyAnalysis.ReadyToRun
 
             return _signatureContext.CompareTo(otherNode._signatureContext, comparer);
         }
+
+        protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
+        {
+            DependencyList dependencies = new DependencyList();
+
+            if (_typeDesc.HasInstantiation && !_typeDesc.IsGenericDefinition)
+            {
+                dependencies.Add(factory.AllMethodsOnType(_typeDesc), "Methods on generic type instantiation");
+            }
+            return dependencies;
+        }
     }
 }
index 4dd4aae..9055310 100644 (file)
@@ -82,6 +82,12 @@ namespace ILCompiler.DependencyAnalysis
         private void CreateNodeCaches()
         {
             _methodEntrypoints = new NodeCache<MethodDesc, IMethodNode>(CreateMethodEntrypointNode);
+
+            _allMethodsOnType = new NodeCache<TypeDesc, AllMethodsOnTypeNode>(type =>
+            {
+                return new AllMethodsOnTypeNode(type);
+            });
+
             _genericReadyToRunHelpersFromDict = new NodeCache<ReadyToRunGenericHelperKey, ISymbolNode>(CreateGenericLookupFromDictionaryNode);
             _genericReadyToRunHelpersFromType = new NodeCache<ReadyToRunGenericHelperKey, ISymbolNode>(CreateGenericLookupFromTypeNode);
 
@@ -107,6 +113,13 @@ namespace ILCompiler.DependencyAnalysis
             return _methodEntrypoints.GetOrAdd(method);
         }
 
+        private NodeCache<TypeDesc, AllMethodsOnTypeNode> _allMethodsOnType;
+
+        public AllMethodsOnTypeNode AllMethodsOnType(TypeDesc type)
+        {
+            return _allMethodsOnType.GetOrAdd(type);
+        }
+
         private NodeCache<ReadyToRunGenericHelperKey, ISymbolNode> _genericReadyToRunHelpersFromDict;
 
         public ISymbolNode ReadyToRunHelperFromDictionaryLookup(ReadyToRunHelperId id, Object target, TypeSystemEntity dictionaryOwner)
index de109cf..04b7026 100644 (file)
     <Compile Include="..\..\Common\TypeSystem\Interop\InteropTypes.cs" Link="Interop\InteropTypes.cs" />
     <Compile Include="CodeGen\ReadyToRunObjectWriter.cs" />
     <Compile Include="Compiler\CompilationModuleGroup.ReadyToRun.cs" />
+    <Compile Include="Compiler\DependencyAnalysis\AllMethodsOnTypeNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\ArrayOfEmbeddedDataNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\ArrayOfEmbeddedPointersNode.cs" />
     <Compile Include="Compiler\DependencyAnalysis\EmbeddedObjectNode.cs" />