Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reduce the number of forced
MethodTable
s (#79594)
When we're doing an optimized build, we go over the whole program twice: * First time to build a whole program view: at this point we e.g. scan the IL method bodies to see what they depend on, or analyze reflection use within the program * The second time to do actual codegen: this time we no longer analyze reflection use and expect that the first phase would have rooted everything that's necessary from reflection perspective. In both phases, we assume any type with a "constructed" `MethodTable` is visible to reflection because one can just call `object.GetType()` and reflect on stuff. We need to pass a list of constructed `MethodTable`s from the first phase to the second phase because some `MethodTable`s could be the result of reflection analysis and we need to make sure they're compiled. But crucially, up until now we didn't really track which `MethodTable`s are actual reflection roots and which ones just showed up in the dependency graph because the analyzed program happened to use it. We don't actually need to pass the latter ones as roots to compilation because the compilation phase is going to figure them out if they're needed anyway and if the compilation doesn't come up with some, that's fine because one wouldn't be able to call `object.GetType` on those anyway, because they're _not actually part of the program_. Passing all of the MethodTables we saw from scanning to compilation is actually size bloat because scanning overapproximates things (by necessity, since it doesn't have a whole program view). In this pull request I'm introducing `ReflectedTypeNode` to model `MethodTable`s that are actual targets of reflection. Only those will get passed as roots to the compilation phase. From now on we need to be mindful of how we refer to types. If a reference to a type is a result of non-code dependency, we should use `ReflectedType` to model it. Saves about 1.2% (32 kB) in size on a Hello World. I'm seeing it helps in two patterns: https://github.com/dotnet/runtime/blob/b1a2080b9ce5833802fe2d632f79de6402097f14/src/libraries/System.Private.CoreLib/src/System/Byte.cs#L1088-L1093 RyuJIT is able to eliminate the dead code in the if branch, but we were still rooting the type within the branch from the box. The second pattern seems to be around RyuJIT devirtualizing things and preventing a box, which now eliminates the `MethodTable`.
- Loading branch information
1 parent
7ac3cde
commit edadf5f
Showing
21 changed files
with
230 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedTypeNode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System.Collections.Generic; | ||
|
||
using ILCompiler.DependencyAnalysisFramework; | ||
|
||
using Internal.TypeSystem; | ||
|
||
using Debug = System.Diagnostics.Debug; | ||
|
||
namespace ILCompiler.DependencyAnalysis | ||
{ | ||
/// <summary> | ||
/// Represents a type that is forced to be visible from reflection. | ||
/// The system needs to implicitly assume that any allocated type could be visible from | ||
/// reflection due to <see cref="object.GetType" />, so presence of this node is not | ||
/// a necessary condition for a type to be reflection visible. However, the presence of this | ||
/// node indicates that a new reflectable type was forced into existence by e.g. dataflow | ||
/// analysis, and is not just a byproduct of allocating an instance of this type. | ||
/// </summary> | ||
public class ReflectedTypeNode : DependencyNodeCore<NodeFactory> | ||
{ | ||
private readonly TypeDesc _type; | ||
|
||
public ReflectedTypeNode(TypeDesc type) | ||
{ | ||
Debug.Assert(!type.IsCanonicalSubtype(CanonicalFormKind.Any) | ||
|| type.ConvertToCanonForm(CanonicalFormKind.Specific) == type); | ||
_type = type; | ||
} | ||
|
||
public TypeDesc Type => _type; | ||
|
||
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory) | ||
{ | ||
return new DependencyListEntry[] | ||
{ | ||
new DependencyListEntry(factory.MaximallyConstructableType(_type), "Reflection target"), | ||
}; | ||
} | ||
protected override string GetName(NodeFactory factory) | ||
{ | ||
return "Reflectable type: " + _type.ToString(); | ||
} | ||
|
||
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 factory) => null; | ||
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory) => null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.