From 96fa8505fa502300819764cb4c40213621aa1e31 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 6 May 2024 14:49:49 -0700 Subject: [PATCH 1/3] Add EdgeVisitor to trace edges in the graph rather than in Annotations.Mark --- .../DependencyNodes/EdgeVisitor.cs | 52 +++++++++++++++++++ .../DependencyNodes/ITracingNode.cs | 19 +++++++ .../MethodDefinitionNode.cs} | 5 +- .../NodeFactory.cs} | 18 ++++++- .../ProcessCallbackNode.cs} | 0 .../DependencyNodes/RootTracingNode.cs | 47 +++++++++++++++++ .../TypeDefinitionNode.cs} | 6 ++- .../TypeIsRelevantToVariantCastingNode.cs} | 2 +- .../src/linker/Linker.Steps/MarkStep.cs | 23 +++++--- 9 files changed, 158 insertions(+), 14 deletions(-) create mode 100644 src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs create mode 100644 src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.MethodDefinitionNode.cs => DependencyNodes/MethodDefinitionNode.cs} (93%) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.NodeFactory.cs => DependencyNodes/NodeFactory.cs} (71%) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.ProcessCallbackNode.cs => DependencyNodes/ProcessCallbackNode.cs} (100%) create mode 100644 src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.TypeDefinitionNode.cs => DependencyNodes/TypeDefinitionNode.cs} (93%) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.TypeIsRelevantToVariantCastingNode.cs => DependencyNodes/TypeIsRelevantToVariantCastingNode.cs} (96%) diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs new file mode 100644 index 00000000000000..6c7c9f778c43ef --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs @@ -0,0 +1,52 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using ILCompiler.DependencyAnalysisFramework; +using Mono.Linker.Steps; + +namespace Mono.Linker.Steps +{ + public partial class MarkStep + { + internal sealed class EdgeVisitor : IDependencyAnalyzerLogEdgeVisitor + { + MarkStep _markStep; + public EdgeVisitor (MarkStep markStep) => _markStep = markStep; + + private static bool ShouldBeLogged (DependencyNodeCore node, out object? dependencyObject) + { + switch (node) { + case ITracingNode ltn: + dependencyObject = ltn.DependencyObject; + return true; + default: + dependencyObject = null; + return false; + }; + } + + public void VisitEdge (DependencyNodeCore nodeDepender, DependencyNodeCore nodeDependedOn, string reason) + { + if (!(ShouldBeLogged (nodeDependedOn, out var dependee) && ShouldBeLogged (nodeDepender, out var depender))) + return; + Debug.Assert (nodeDependedOn is not RootTracingNode); + DependencyInfo depInfo = new (NodeFactory.StringToDependencyKindMap[reason], depender); + _markStep.Context.Tracer.AddDirectDependency (dependee!, depInfo, true); + } + + public void VisitEdge (string root, DependencyNodeCore dependedOn) + { + Debug.Assert (dependedOn is RootTracingNode or not ITracingNode); + } + + public void VisitEdge (DependencyNodeCore nodeDepender, DependencyNodeCore nodeDependerOther, DependencyNodeCore nodeDependedOn, string reason) + { + if (!(ShouldBeLogged (nodeDependedOn, out var dependee) && ShouldBeLogged (nodeDepender, out var depender))) + return; + DependencyInfo depInfo = new (NodeFactory.StringToDependencyKindMap[reason], depender); + _markStep.Context.Tracer.AddDirectDependency (dependee!, depInfo, true); + } + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs new file mode 100644 index 00000000000000..3a7e93c7a5caf2 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs @@ -0,0 +1,19 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mono.Linker.Steps +{ + public partial class MarkStep + { + internal interface ITracingNode + { + object? DependencyObject { get; } + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs similarity index 93% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionNode.cs rename to src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs index 34dd6e8a8d03e4..09ad3edf306ba1 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps { public partial class MarkStep { - internal sealed class MethodDefinitionNode : DependencyNodeCore + internal sealed class MethodDefinitionNode : DependencyNodeCore, ITracingNode { readonly MethodDefinition method; readonly DependencyInfo reason; @@ -37,7 +37,8 @@ public MethodDefinitionNode (MethodDefinition method, DependencyInfo reason) public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; - protected override string GetName (NodeFactory context) => method.GetDisplayName(); + protected override string GetName (NodeFactory context) => method.GetDisplayName (); + object ITracingNode.DependencyObject => method; } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs similarity index 71% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs rename to src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs index 7e16f7ac25981d..7720a8d896ee0e 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs @@ -2,9 +2,10 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using Mono.Cecil; +using Mono.Linker.Steps; namespace Mono.Linker.Steps { @@ -13,10 +14,18 @@ public partial class MarkStep internal sealed class NodeFactory (MarkStep markStep) { public MarkStep MarkStep { get; } = markStep; - readonly NodeCache _typeNodes = new (static t => new TypeDefinitionNode(t)); + + public static readonly ImmutableDictionary StringToDependencyKindMap = Enum.GetValues ().ToImmutableDictionary (v => v.ToString ()); + public static readonly ImmutableDictionary DependencyKindToStringMap = Enum.GetValues ().ToImmutableDictionary (v => v, v => v.ToString ()); + + readonly NodeCache _typeNodes = new (static t => new TypeDefinitionNode (t)); + readonly NodeCache _methodNodes = new (static _ => throw new InvalidOperationException ("Creation of node requires more than the key.")); + readonly NodeCache _typeIsRelevantToVariantCastingNodes = new (static (t) => new TypeIsRelevantToVariantCastingNode (t)); + readonly NodeCache<(ITracingNode, string, object?), RootTracingNode> _rootTracingNodes = new (static (tup) => new RootTracingNode (tup.Item1, tup.Item2, tup.Item3)); + internal TypeDefinitionNode GetTypeNode (TypeDefinition definition) { return _typeNodes.GetOrAdd (definition); @@ -32,6 +41,11 @@ internal TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNod return _typeIsRelevantToVariantCastingNodes.GetOrAdd (type); } + internal RootTracingNode GetRootTracingNode (ITracingNode newNode, string reason, object? depender) + { + return _rootTracingNodes.GetOrAdd ((newNode, reason, depender)); + } + struct NodeCache where TKey : notnull { // Change to concurrent dictionary if/when multithreaded marking is enabled diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ProcessCallbackNode.cs similarity index 100% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs rename to src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ProcessCallbackNode.cs diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs new file mode 100644 index 00000000000000..1dbc62dc42bf80 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.Generic; +using ILCompiler.DependencyAnalysisFramework; + +namespace Mono.Linker.Steps +{ + public partial class MarkStep + { + /// + /// This node represents a dependency from an item that does not yet have a node to an item that does, in order to enable dependency tracing. + /// Dependencies from this node and the dependee will be traced in the dependency analyzer, and the logger will forward the dependency (depender > dependee) to the trimmer dependency tracing loggers. + /// + internal sealed class RootTracingNode : DependencyNodeCore, ITracingNode + { + readonly ITracingNode _dependee; + readonly string _reason; + readonly object? _depender; + + public RootTracingNode (ITracingNode dep, string reason, object? depender) + { + this._dependee = dep; + this._reason = reason; + this._depender = depender; + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => true; + + public override IEnumerable? GetStaticDependencies (NodeFactory context) + { + return [new DependencyListEntry (_dependee, _reason)]; + } + + public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; + protected override string GetName (NodeFactory context) => _depender?.ToString () ?? "Unknown"; + object? ITracingNode.DependencyObject => _depender; + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs similarity index 93% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs rename to src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs index d26467930afce0..7951376d429875 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs @@ -9,7 +9,7 @@ namespace Mono.Linker.Steps { public partial class MarkStep { - internal sealed class TypeDefinitionNode : DependencyNodeCore + internal sealed class TypeDefinitionNode : DependencyNodeCore, ITracingNode { readonly TypeDefinition type; @@ -34,7 +34,9 @@ public TypeDefinitionNode (TypeDefinition type) public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; - protected override string GetName (NodeFactory context) => type.GetDisplayName(); + protected override string GetName (NodeFactory context) => type.GetDisplayName (); + object? ITracingNode.DependencyObject => type; + } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeIsRelevantToVariantCastingNode.cs similarity index 96% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs rename to src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeIsRelevantToVariantCastingNode.cs index 00f790b5d9d472..c07fcabeaa53cc 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeIsRelevantToVariantCastingNode.cs @@ -29,7 +29,7 @@ internal sealed class TypeIsRelevantToVariantCastingNode : DependencyNodeCore? GetConditionalStaticDependencies (NodeFactory context) => null; public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; - protected override string GetName (NodeFactory context) => $"{type.GetDisplayName()} is relevant to variant casting"; + protected override string GetName (NodeFactory context) => $"{type.GetDisplayName ()} is relevant to variant casting"; protected override void OnMarked (NodeFactory context) { context.MarkStep.Annotations.MarkRelevantToVariantCasting (type); diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 1731eac41d2880..4908effc061005 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -50,7 +50,6 @@ namespace Mono.Linker.Steps { - public partial class MarkStep : IStep { LinkContext? _context; @@ -76,7 +75,7 @@ protected LinkContext Context { // method body scanner. readonly Dictionary _compilerGeneratedMethodRequiresScanner; private readonly NodeFactory _nodeFactory; - private readonly DependencyAnalyzer, NodeFactory> _dependencyGraph; + private readonly DependencyAnalyzer, NodeFactory> _dependencyGraph; MarkStepContext? _markContext; MarkStepContext MarkContext { @@ -234,7 +233,7 @@ public MarkStep () _entireTypesMarked = new HashSet (); _compilerGeneratedMethodRequiresScanner = new Dictionary (); _nodeFactory = new NodeFactory (this); - _dependencyGraph = new DependencyAnalyzer, NodeFactory> (_nodeFactory, null); + _dependencyGraph = new DependencyAnalyzer, NodeFactory> (_nodeFactory, null); } public AnnotationStore Annotations => Context.Annotations; @@ -390,6 +389,7 @@ void Process () _dependencyGraph.ComputeMarkedNodes (); ProcessPendingTypeChecks (); + _dependencyGraph.VisitLogEdges (new EdgeVisitor (this)); bool ProcessAllPendingItems () => ProcessPrimaryQueue () || @@ -1991,7 +1991,9 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in Debug.Assert (Annotations.IsMarked (type)); break; default: - Annotations.Mark (type, reason, ScopeStack.CurrentScope.Origin); +#pragma warning disable CS0618 // We will track the reason for the mark in the dependency graph + Annotations.Mark (type); +#pragma warning restore CS0618 break; } @@ -2016,7 +2018,9 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in if (type.Scope is ModuleDefinition module) MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); - _dependencyGraph.AddRoot (_nodeFactory.GetTypeNode (type), Enum.GetName (reason.Kind)); + var typeNode = _nodeFactory.GetTypeNode (type); + var rootNode = _nodeFactory.GetRootTracingNode (typeNode, NodeFactory.DependencyKindToStringMap[reason.Kind], reason.Source); + _dependencyGraph.AddRoot (rootNode, "Tracing Root"); return type; } @@ -3015,7 +3019,9 @@ void MarkMethodCollection (IList methods, in DependencyInfo re Debug.Assert (Annotations.IsMarked (method)); break; default: - Annotations.Mark (method, reason, origin); +#pragma warning disable CS0618 // We will track the reason for the mark in the dependency graph + Annotations.Mark (method); +#pragma warning restore CS0618 break; } @@ -3035,7 +3041,10 @@ void MarkMethodCollection (IList methods, in DependencyInfo re // We will only enqueue a method to be processed if it hasn't been processed yet. if (!CheckProcessed (method)) _completed = false; - _dependencyGraph.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason), Enum.GetName (reason.Kind)); + + var methodNode = _nodeFactory.GetMethodDefinitionNode (method, reason); + var rootNode = _nodeFactory.GetRootTracingNode (methodNode, NodeFactory.DependencyKindToStringMap[reason.Kind], reason.Source); + _dependencyGraph.AddRoot (rootNode, Enum.GetName (reason.Kind)); return method; } From 85c2d6ff20ca41d17888dfaf7136b1631360822f Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Wed, 8 May 2024 12:28:25 -0700 Subject: [PATCH 2/3] Make reason for RootTracingNode 'Tracing Root' --- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 4908effc061005..774d216dcd5d01 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3044,7 +3044,7 @@ void MarkMethodCollection (IList methods, in DependencyInfo re var methodNode = _nodeFactory.GetMethodDefinitionNode (method, reason); var rootNode = _nodeFactory.GetRootTracingNode (methodNode, NodeFactory.DependencyKindToStringMap[reason.Kind], reason.Source); - _dependencyGraph.AddRoot (rootNode, Enum.GetName (reason.Kind)); + _dependencyGraph.AddRoot (rootNode, "Tracing Root"); return method; } From aef79a79df1bdacd0c69dbd3e72a0fa5349bf3cd Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 13 May 2024 16:48:30 -0500 Subject: [PATCH 3/3] Remove ITracingNode, RootTracingNode, mark parameters in MethodNode.GetStaticDependencies --- .../DependencyNodes/EdgeVisitor.cs | 40 +++++++++------- .../DependencyNodes/ITracingNode.cs | 19 -------- .../DependencyNodes/MethodDefinitionNode.cs | 17 +++++-- .../DependencyNodes/NodeFactory.cs | 8 ---- .../DependencyNodes/RootTracingNode.cs | 47 ------------------- .../DependencyNodes/TypeDefinitionNode.cs | 5 +- .../src/linker/Linker.Steps/MarkStep.cs | 34 +++++--------- .../linker/Linker/DependencyRecorderHelper.cs | 2 +- 8 files changed, 54 insertions(+), 118 deletions(-) delete mode 100644 src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs delete mode 100644 src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs index 6c7c9f778c43ef..a85d5d4f033070 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/EdgeVisitor.cs @@ -14,38 +14,46 @@ internal sealed class EdgeVisitor : IDependencyAnalyzerLogEdgeVisitor _markStep = markStep; - private static bool ShouldBeLogged (DependencyNodeCore node, out object? dependencyObject) + private bool ShouldBeLogged (DependencyNodeCore o) { - switch (node) { - case ITracingNode ltn: - dependencyObject = ltn.DependencyObject; - return true; - default: - dependencyObject = null; + if (o is ProcessCallbackNode) return false; - }; + + if (!_markStep.Context.EnableReducedTracing) + return true; + + var context = _markStep.Context; + + if (o is TypeDefinitionNode t) + return DependencyRecorderHelper.WillAssemblyBeModified (context, t.Type.Module.Assembly); + + return true; } public void VisitEdge (DependencyNodeCore nodeDepender, DependencyNodeCore nodeDependedOn, string reason) { - if (!(ShouldBeLogged (nodeDependedOn, out var dependee) && ShouldBeLogged (nodeDepender, out var depender))) + if (!(ShouldBeLogged (nodeDependedOn) && ShouldBeLogged (nodeDepender))) return; - Debug.Assert (nodeDependedOn is not RootTracingNode); - DependencyInfo depInfo = new (NodeFactory.StringToDependencyKindMap[reason], depender); - _markStep.Context.Tracer.AddDirectDependency (dependee!, depInfo, true); + var dependerName = DependencyNodeCore.GetNodeName (nodeDepender, null!); + var dependeeName = DependencyNodeCore.GetNodeName (nodeDependedOn, null!); + DependencyInfo depInfo = new (NodeFactory.StringToDependencyKindMap[reason], dependerName); + _markStep.Context.Tracer.AddDirectDependency (dependeeName!, depInfo, true); } public void VisitEdge (string root, DependencyNodeCore dependedOn) { - Debug.Assert (dependedOn is RootTracingNode or not ITracingNode); + // Root nodes will be traced in MarkStep.Mark[Type|Method|Field] and not here } public void VisitEdge (DependencyNodeCore nodeDepender, DependencyNodeCore nodeDependerOther, DependencyNodeCore nodeDependedOn, string reason) { - if (!(ShouldBeLogged (nodeDependedOn, out var dependee) && ShouldBeLogged (nodeDepender, out var depender))) + if (!(ShouldBeLogged (nodeDependedOn) && ShouldBeLogged (nodeDepender))) return; - DependencyInfo depInfo = new (NodeFactory.StringToDependencyKindMap[reason], depender); - _markStep.Context.Tracer.AddDirectDependency (dependee!, depInfo, true); + + var dependerName = DependencyNodeCore.GetNodeName (nodeDepender, null!); + var dependeeName = DependencyNodeCore.GetNodeName (nodeDependedOn, null!); + DependencyInfo depInfo = new (NodeFactory.StringToDependencyKindMap[reason], dependerName); + _markStep.Context.Tracer.AddDirectDependency (dependeeName!, depInfo, true); } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs deleted file mode 100644 index 3a7e93c7a5caf2..00000000000000 --- a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/ITracingNode.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Mono.Linker.Steps -{ - public partial class MarkStep - { - internal interface ITracingNode - { - object? DependencyObject { get; } - } - } -} diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs index 09ad3edf306ba1..f2971725588ed5 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/MethodDefinitionNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps { public partial class MarkStep { - internal sealed class MethodDefinitionNode : DependencyNodeCore, ITracingNode + internal sealed class MethodDefinitionNode : DependencyNodeCore { readonly MethodDefinition method; readonly DependencyInfo reason; @@ -31,14 +31,25 @@ public MethodDefinitionNode (MethodDefinition method, DependencyInfo reason) public override IEnumerable? GetStaticDependencies (NodeFactory context) { + using (_ = context.MarkStep.ScopeStack.PushLocalScope (new MessageOrigin (method))) { + if (method.HasMetadataParameters ()) { +#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave the code as is for now + foreach (ParameterDefinition pd in method.Parameters) { + var type = context.MarkStep.MarkType (pd.ParameterType, new DependencyInfo (DependencyKind.ParameterType, method), null, false); + if (type is not null) + yield return new (context.GetTypeNode (type), nameof (DependencyKind.ParameterType)); + context.MarkStep.MarkCustomAttributes (pd, new DependencyInfo (DependencyKind.ParameterAttribute, method)); + context.MarkStep.MarkMarshalSpec (pd, new DependencyInfo (DependencyKind.ParameterMarshalSpec, method)); + } +#pragma warning restore RS0030 + } + } context.MarkStep.ProcessMethod (method, reason); - return null; } public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; protected override string GetName (NodeFactory context) => method.GetDisplayName (); - object ITracingNode.DependencyObject => method; } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs index 7720a8d896ee0e..88f45c5cd4228a 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/NodeFactory.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using Mono.Cecil; -using Mono.Linker.Steps; namespace Mono.Linker.Steps { @@ -24,8 +23,6 @@ internal sealed class NodeFactory (MarkStep markStep) readonly NodeCache _typeIsRelevantToVariantCastingNodes = new (static (t) => new TypeIsRelevantToVariantCastingNode (t)); - readonly NodeCache<(ITracingNode, string, object?), RootTracingNode> _rootTracingNodes = new (static (tup) => new RootTracingNode (tup.Item1, tup.Item2, tup.Item3)); - internal TypeDefinitionNode GetTypeNode (TypeDefinition definition) { return _typeNodes.GetOrAdd (definition); @@ -41,11 +38,6 @@ internal TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNod return _typeIsRelevantToVariantCastingNodes.GetOrAdd (type); } - internal RootTracingNode GetRootTracingNode (ITracingNode newNode, string reason, object? depender) - { - return _rootTracingNodes.GetOrAdd ((newNode, reason, depender)); - } - struct NodeCache where TKey : notnull { // Change to concurrent dictionary if/when multithreaded marking is enabled diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs deleted file mode 100644 index 1dbc62dc42bf80..00000000000000 --- a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/RootTracingNode.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using ILCompiler.DependencyAnalysisFramework; - -namespace Mono.Linker.Steps -{ - public partial class MarkStep - { - /// - /// This node represents a dependency from an item that does not yet have a node to an item that does, in order to enable dependency tracing. - /// Dependencies from this node and the dependee will be traced in the dependency analyzer, and the logger will forward the dependency (depender > dependee) to the trimmer dependency tracing loggers. - /// - internal sealed class RootTracingNode : DependencyNodeCore, ITracingNode - { - readonly ITracingNode _dependee; - readonly string _reason; - readonly object? _depender; - - public RootTracingNode (ITracingNode dep, string reason, object? depender) - { - this._dependee = dep; - this._reason = reason; - this._depender = depender; - } - - public override bool InterestingForDynamicDependencyAnalysis => false; - - public override bool HasDynamicDependencies => false; - - public override bool HasConditionalStaticDependencies => false; - - public override bool StaticDependenciesAreComputed => true; - - public override IEnumerable? GetStaticDependencies (NodeFactory context) - { - return [new DependencyListEntry (_dependee, _reason)]; - } - - public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; - protected override string GetName (NodeFactory context) => _depender?.ToString () ?? "Unknown"; - object? ITracingNode.DependencyObject => _depender; - } - } -} diff --git a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs index 7951376d429875..6e38aa2a21af6b 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DependencyNodes/TypeDefinitionNode.cs @@ -9,9 +9,10 @@ namespace Mono.Linker.Steps { public partial class MarkStep { - internal sealed class TypeDefinitionNode : DependencyNodeCore, ITracingNode + internal sealed class TypeDefinitionNode : DependencyNodeCore { readonly TypeDefinition type; + public TypeDefinition Type => type; public TypeDefinitionNode (TypeDefinition type) { @@ -35,8 +36,6 @@ public TypeDefinitionNode (TypeDefinition type) public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; protected override string GetName (NodeFactory context) => type.GetDisplayName (); - object? ITracingNode.DependencyObject => type; - } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 774d216dcd5d01..f5a9fb480d3817 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -1954,14 +1954,14 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in MarkStaticConstructor (type, reason, origin); } - /// /// Marks the specified as referenced. /// /// The type reference to mark. /// The reason why the marking is occuring + /// Whether to add the node to the dependency graph /// The resolved type definition if the reference can be resolved - protected internal virtual TypeDefinition? MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) + protected internal virtual TypeDefinition? MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null, bool addToGraphAsRoot = true) { #if DEBUG if (!_typeReasons.Contains (reason.Kind)) @@ -1991,8 +1991,11 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in Debug.Assert (Annotations.IsMarked (type)); break; default: -#pragma warning disable CS0618 // We will track the reason for the mark in the dependency graph - Annotations.Mark (type); + if (addToGraphAsRoot) + Annotations.Mark (type, reason, ScopeStack.CurrentScope.Origin); + else +#pragma warning disable CS0618 // Mark with a reason: We add the reason in the dependency graph edge visitor + Annotations.Mark (type); #pragma warning restore CS0618 break; } @@ -2018,9 +2021,10 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in if (type.Scope is ModuleDefinition module) MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); - var typeNode = _nodeFactory.GetTypeNode (type); - var rootNode = _nodeFactory.GetRootTracingNode (typeNode, NodeFactory.DependencyKindToStringMap[reason.Kind], reason.Source); - _dependencyGraph.AddRoot (rootNode, "Tracing Root"); + if(addToGraphAsRoot) { + var typeNode = _nodeFactory.GetTypeNode (type); + _dependencyGraph.AddRoot (typeNode, NodeFactory.DependencyKindToStringMap[reason.Kind]); + } return type; } @@ -3019,9 +3023,7 @@ void MarkMethodCollection (IList methods, in DependencyInfo re Debug.Assert (Annotations.IsMarked (method)); break; default: -#pragma warning disable CS0618 // We will track the reason for the mark in the dependency graph - Annotations.Mark (method); -#pragma warning restore CS0618 + Annotations.Mark (method, reason, origin); break; } @@ -3043,8 +3045,7 @@ void MarkMethodCollection (IList methods, in DependencyInfo re _completed = false; var methodNode = _nodeFactory.GetMethodDefinitionNode (method, reason); - var rootNode = _nodeFactory.GetRootTracingNode (methodNode, NodeFactory.DependencyKindToStringMap[reason.Kind], reason.Source); - _dependencyGraph.AddRoot (rootNode, "Tracing Root"); + _dependencyGraph.AddRoot (methodNode, NodeFactory.DependencyKindToStringMap[reason.Kind]); return method; } @@ -3214,15 +3215,6 @@ protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo MarkEvent (@event, new DependencyInfo (PropagateDependencyKindToAccessors (reason.Kind, DependencyKind.EventOfEventMethod), method)); } - if (method.HasMetadataParameters ()) { -#pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave the code as is for now - foreach (ParameterDefinition pd in method.Parameters) { - MarkType (pd.ParameterType, new DependencyInfo (DependencyKind.ParameterType, method)); - MarkCustomAttributes (pd, new DependencyInfo (DependencyKind.ParameterAttribute, method)); - MarkMarshalSpec (pd, new DependencyInfo (DependencyKind.ParameterMarshalSpec, method)); - } -#pragma warning restore RS0030 - } if (method.HasOverrides) { var assembly = Context.Resolve (method.DeclaringType.Scope); diff --git a/src/tools/illink/src/linker/Linker/DependencyRecorderHelper.cs b/src/tools/illink/src/linker/Linker/DependencyRecorderHelper.cs index 6780a893954b61..5570a4d9bb16e9 100644 --- a/src/tools/illink/src/linker/Linker/DependencyRecorderHelper.cs +++ b/src/tools/illink/src/linker/Linker/DependencyRecorderHelper.cs @@ -48,7 +48,7 @@ public static string TokenString (LinkContext context, object? o) return "Other:" + o; } - static bool WillAssemblyBeModified (LinkContext context, AssemblyDefinition assembly) + internal static bool WillAssemblyBeModified (LinkContext context, AssemblyDefinition assembly) { switch (context.Annotations.GetAction (assembly)) { case AssemblyAction.Link: