From afe89903fc19ccf0ac950b66ac6b2b7738081f97 Mon Sep 17 00:00:00 2001 From: vitek-karas <10670590+vitek-karas@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:19:07 -0700 Subject: [PATCH 01/28] MarkStep runs inside dependency framework --- .../tools/Common/Sorting/ArrayAccessor.cs | 2 + .../Common/Sorting/ICompareAsEqualAction.cs | 2 + .../Sorting/ISortableDataStructureAccessor.cs | 2 + .../tools/Common/Sorting/ListAccessor.cs | 2 + src/coreclr/tools/Common/Sorting/MergeSort.cs | 2 + .../tools/Common/Sorting/MergeSortCore.cs | 2 + .../ComputedStaticDependencyNode.cs | 2 + .../DependencyAnalyzer.cs | 2 + .../DependencyAnalyzerBase.cs | 2 + .../DependencyNode.cs | 2 + .../DependencyNodeCore.cs | 2 + .../DgmlWriter.cs | 2 + .../EventSourceLogStrategy.cs | 2 + .../FirstMarkLogStrategy.cs | 2 + .../FullGraphLogStrategy.cs | 2 + .../IDependencyAnalysisMarkStrategy.cs | 2 + .../IDependencyAnalyzerLogEdgeVisitor.cs | 2 + .../IDependencyAnalyzerLogNodeVisitor.cs | 2 + .../IDependencyNode.cs | 2 + .../NoLogStrategy.cs | 2 + .../PerfEventSource.cs | 2 + .../src/linker/Linker.Steps/MarkStep.cs | 53 +++++++++++++- .../illink/src/linker/Mono.Linker.csproj | 71 +++++++++++++++++++ 23 files changed, 163 insertions(+), 3 deletions(-) diff --git a/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs b/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs index 2c73dc16bff72b..ac9dbe395d489c 100644 --- a/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs +++ b/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs @@ -3,6 +3,8 @@ using System; +#nullable disable + namespace ILCompiler.Sorting.Implementation { internal struct ArrayAccessor : ISortableDataStructureAccessor diff --git a/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs b/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs index 09fe5716b4fcc1..ca9accc71fdc8e 100644 --- a/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs +++ b/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs @@ -3,6 +3,8 @@ using System.Diagnostics; +#nullable disable + namespace ILCompiler { internal interface ICompareAsEqualAction diff --git a/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs b/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs index c2ec9f24b84f96..ec0319f562efc6 100644 --- a/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs +++ b/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable disable + namespace ILCompiler { internal interface ISortableDataStructureAccessor diff --git a/src/coreclr/tools/Common/Sorting/ListAccessor.cs b/src/coreclr/tools/Common/Sorting/ListAccessor.cs index f26f1ff5acaa8b..27c78e92182f79 100644 --- a/src/coreclr/tools/Common/Sorting/ListAccessor.cs +++ b/src/coreclr/tools/Common/Sorting/ListAccessor.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; +#nullable disable + namespace ILCompiler.Sorting.Implementation { internal struct ListAccessor : ISortableDataStructureAccessor> diff --git a/src/coreclr/tools/Common/Sorting/MergeSort.cs b/src/coreclr/tools/Common/Sorting/MergeSort.cs index 7faf01aeafb5b8..35768d444c931a 100644 --- a/src/coreclr/tools/Common/Sorting/MergeSort.cs +++ b/src/coreclr/tools/Common/Sorting/MergeSort.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using ILCompiler.Sorting.Implementation; +#nullable disable + namespace ILCompiler { public static class MergeSortApi diff --git a/src/coreclr/tools/Common/Sorting/MergeSortCore.cs b/src/coreclr/tools/Common/Sorting/MergeSortCore.cs index 5b054eedb0157c..29070c5d5078a3 100644 --- a/src/coreclr/tools/Common/Sorting/MergeSortCore.cs +++ b/src/coreclr/tools/Common/Sorting/MergeSortCore.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Threading.Tasks; +#nullable disable + namespace ILCompiler.Sorting.Implementation { internal static class MergeSortCore diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs index 8e043a74a3916f..6a7a0717078285 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Diagnostics; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public abstract class ComputedStaticDependencyNode : DependencyNodeCore diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs index e7f7503bb7d7db..58f78290e72fb3 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs @@ -6,6 +6,8 @@ using System.Collections.Immutable; using System.Diagnostics; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { /// diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs index 38d3e7c7023586..f4a11e8f3023ba 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Collections.Immutable; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { /// diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs index d8913b8022c48d..dac07277eea106 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs @@ -3,6 +3,8 @@ using System.Diagnostics; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public abstract class DependencyNode : IDependencyNode diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs index 0f8ed436ed4ffe..5a991bcf87044d 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs @@ -4,6 +4,8 @@ using System; using System.Collections.Generic; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public abstract class DependencyNodeCore : DependencyNode, IDependencyNode diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs index a0570393335955..4bb0b9dcca0341 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs @@ -7,6 +7,8 @@ using System.IO; using System.Diagnostics; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public class DgmlWriter diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs index a5f70a0fa0bcf2..e917d1136a48d6 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs @@ -7,6 +7,8 @@ using System.Diagnostics.Tracing; using System.Runtime.InteropServices; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { [EventSource(Name = "Microsoft-ILCompiler-DependencyGraph")] diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs index 655fb43a35c1cf..c2fbc5e3dafa4d 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Diagnostics; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public struct FirstMarkLogStrategy : IDependencyAnalysisMarkStrategy diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs index 4847782fd3f78f..aa02ae16a90998 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.Diagnostics; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public struct FullGraphLogStrategy : IDependencyAnalysisMarkStrategy diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs index 23b4384ea64677..86308a997a54ea 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyAnalysisMarkStrategy diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs index 4c55ba328b4e03..fa2b0ff61069f8 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyAnalyzerLogEdgeVisitor diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs index 9d3b027a81b18d..d8fc79a39be579 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs @@ -3,6 +3,8 @@ using System; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyAnalyzerLogNodeVisitor diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs index 76365d9c68bc59..fe865e36f668fe 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyNode diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs index 55cf4174fd129d..e4570ade4d16d3 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; +#nullable disable + namespace ILCompiler.DependencyAnalysisFramework { /// diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs index 2c0d474c94afdf..1ff01e9227d97d 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs @@ -4,6 +4,8 @@ using System; using System.Diagnostics.Tracing; +#nullable disable + /// /// Performance events specific to the dependency graph. /// diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 5ab71a490740c4..ff23a3bcdee16f 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -38,6 +38,7 @@ using System.Reflection.Runtime.TypeParsing; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; +using ILCompiler.DependencyAnalysisFramework; using ILLink.Shared; using ILLink.Shared.TrimAnalysis; using ILLink.Shared.TypeSystemProxy; @@ -412,14 +413,60 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason) void Process () { - while (ProcessPrimaryQueue () || + var analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (new MarkStepNodeFactory(this), null); + analyzer.ComputeDependencyRoutine += (List> nodes) => { + foreach (DependencyNodeCore node in nodes) { + if (node is ProcessCallbackDependencyNode processNode) + processNode.Process (); + } + }; + analyzer.AddRoot (new ProcessCallbackDependencyNode (ProcessAllPendingItems), "start"); + analyzer.ComputeMarkedNodes (); + + ProcessPendingTypeChecks (); + + bool ProcessAllPendingItems () + => ProcessPrimaryQueue () || ProcessMarkedPending () || ProcessLazyAttributes () || ProcessLateMarkedAttributes () || MarkFullyPreservedAssemblies () || - ProcessInternalsVisibleAttributes ()) ; + ProcessInternalsVisibleAttributes (); + } - ProcessPendingTypeChecks (); + public class MarkStepNodeFactory (MarkStep markStep) + { + public MarkStep MarkStep { get; } = markStep; + } + + sealed class ProcessCallbackDependencyNode : DependencyNodeCore + { + Func _processAction; + DependencyList? _dependencies; + + public ProcessCallbackDependencyNode (Func action) => _processAction = action; + + public void Process() + { + _dependencies = new DependencyList (); + if (_processAction ()) { + _dependencies.Add (new ProcessCallbackDependencyNode (_processAction), "Some processing was done, continuation required"); + } + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => _dependencies != null; + + public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) => _dependencies; + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "Process"; } static bool IsFullyPreservedAction (AssemblyAction action) => action == AssemblyAction.Copy || action == AssemblyAction.Save; diff --git a/src/tools/illink/src/linker/Mono.Linker.csproj b/src/tools/illink/src/linker/Mono.Linker.csproj index e5cdbb86c5eb76..b0a7c1bae1d2f0 100644 --- a/src/tools/illink/src/linker/Mono.Linker.csproj +++ b/src/tools/illink/src/linker/Mono.Linker.csproj @@ -75,6 +75,77 @@ + + $(CoreClrProjectRoot)\tools\aot\ILCompiler.DependencyAnalysisFramework + $(CoreClrProjectRoot)\tools\Common + + + + + DependencyAnalysisFramework\ComputedStaticDependencyNode.cs + + + DependencyAnalysisFramework\DependencyAnalyzer.cs + + + DependencyAnalysisFramework\DependencyAnalyzerBase.cs + + + DependencyAnalysisFramework\DependencyNode.cs + + + DependencyAnalysisFramework\DependencyNodeCore.cs + + + DependencyAnalysisFramework\DgmlWriter.cs + + + DependencyAnalysisFramework\EventSourceLogStrategy.cs + + + DependencyAnalysisFramework\FirstMarkLogStrategy.cs + + + DependencyAnalysisFramework\FullGraphLogStrategy.cs + + + DependencyAnalysisFramework\IDependencyAnalyzerLogEdgeVisitor.cs + + + DependencyAnalysisFramework\IDependencyAnalyzerLogNodeVisitor.cs + + + DependencyAnalysisFramework\IDependencyAnalysisMarkStrategy.cs + + + DependencyAnalysisFramework\IDependencyNode.cs + + + DependencyAnalysisFramework\NoLogStrategy.cs + + + DependencyAnalysisFramework\PerfEventSource.cs + + + DependencyAnalysisFramework\Sorting\ArrayAccessor.cs + + + DependencyAnalysisFramework\Sorting\ICompareAsEqualAction.cs + + + DependencyAnalysisFramework\Sorting\ISortableDataStructureAccessor.cs + + + DependencyAnalysisFramework\Sorting\ListAccessor.cs + + + DependencyAnalysisFramework\Sorting\MergeSort.cs + + + DependencyAnalysisFramework\Sorting\MergeSortCore.cs + + + all From 76fe92352236cb073e375a6e0ff51d88fab1a10a Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:20:04 -0700 Subject: [PATCH 02/28] Put MarkType into DependencyFramework --- .../src/linker/Linker.Steps/MarkStep.cs | 385 ++++++++++-------- .../DataFlowTests.g.cs | 6 - 2 files changed, 215 insertions(+), 176 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 9b797a607cb92c..f7dbc2a28464ec 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -230,6 +230,7 @@ public MarkStep () _pending_isinst_instr = new List<(TypeDefinition, MethodBody, Instruction)> (); _entireTypesMarked = new HashSet (); _compilerGeneratedMethodRequiresScanner = new Dictionary (); + _analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (new MarkStepNodeFactory(this), null); } public AnnotationStore Annotations => Context.Annotations; @@ -373,17 +374,17 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason) } } + DependencyAnalyzer, MarkStepNodeFactory> _analyzer; void Process () { - var analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (new MarkStepNodeFactory(this), null); - analyzer.ComputeDependencyRoutine += (List> nodes) => { + _analyzer.ComputeDependencyRoutine += (List> nodes) => { foreach (DependencyNodeCore node in nodes) { if (node is ProcessCallbackDependencyNode processNode) processNode.Process (); } }; - analyzer.AddRoot (new ProcessCallbackDependencyNode (ProcessAllPendingItems), "start"); - analyzer.ComputeMarkedNodes (); + _analyzer.AddRoot (new ProcessCallbackDependencyNode (ProcessAllPendingItems), "start"); + _analyzer.ComputeMarkedNodes (); ProcessPendingTypeChecks (); @@ -392,7 +393,8 @@ bool ProcessAllPendingItems () ProcessMarkedPending () || ProcessLazyAttributes () || ProcessLateMarkedAttributes () || - MarkFullyPreservedAssemblies ()) ; + MarkFullyPreservedAssemblies () ; + } public class MarkStepNodeFactory (MarkStep markStep) { @@ -429,6 +431,202 @@ public void Process() protected override string GetName (MarkStepNodeFactory context) => "Process"; } + public class TypeDependencyNode: DependencyNodeCore + { + public TypeDependencyNode(TypeReference reference, DependencyInfo reason, MessageOrigin? origin, MarkStep markStep) + { + this.reference = reference; + this.reason = reason; + this.origin = origin; + this.markStep = markStep; + this.Context = markStep.Context; + } + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => true; + + TypeReference reference { get; set; } + DependencyInfo reason { get; set; } + MessageOrigin? origin { get; } + + readonly MarkStep markStep; + + LinkContext Context { get; } + + public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) + { + yield break; + } + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "TypeNode"; + protected override void OnMarked (MarkStepNodeFactory context) + { +#if DEBUG + if (!_typeReasons.Contains (reason.Kind)) + throw new ArgumentOutOfRangeException ($"Internal error: unsupported type dependency {reason.Kind}"); +#endif + if (reference == null) + return; + + using MarkScopeStack.LocalScope? localScope = origin.HasValue ? markStep.ScopeStack.PushLocalScope (origin.Value) : null; + + (reference, reason) = markStep.GetOriginalType (reference, reason); + + if (reference is FunctionPointerType) + return; + + if (reference is GenericParameter) + return; + + TypeDefinition? type = Context.Resolve (reference); + + if (type == null) + return; + + // Track a mark reason for each call to MarkType. + switch (reason.Kind) { + case DependencyKind.AlreadyMarked: + Debug.Assert (markStep.Annotations.IsMarked (type)); + break; + default: + markStep.Annotations.Mark (type, reason, markStep.ScopeStack.CurrentScope.Origin); + break; + } + + // Treat cctors triggered by a called method specially and mark this case up-front. + if (type.HasMethods && markStep.ShouldMarkTypeStaticConstructor (type) && reason.Kind == DependencyKind.DeclaringTypeOfCalledMethod) + markStep.MarkStaticConstructor (type, new DependencyInfo (DependencyKind.TriggersCctorForCalledMethod, reason.Source), markStep.ScopeStack.CurrentScope.Origin); + + if (markStep.Annotations.HasLinkerAttribute (type)) { + // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute + // will call MarkType on the attribute type itself). + // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 + // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. + // Also don't warn when the type is marked due to an assembly being rooted. + if (!(reason.Source is IMemberDefinition sourceMemberDefinition && sourceMemberDefinition.DeclaringType == type) && + reason.Kind is not DependencyKind.TypeInAssembly) + Context.LogWarning (markStep.ScopeStack.CurrentScope.Origin, DiagnosticId.AttributeIsReferencedButTrimmerRemoveAllInstances, type.GetDisplayName ()); + } + + if (markStep.CheckProcessed (type)) + return; + + if (type.Scope is ModuleDefinition module) + markStep.MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); + + using var typeScope = markStep.ScopeStack.PushLocalScope (new MessageOrigin (type)); + + foreach (Action handleMarkType in markStep.MarkContext.MarkTypeActions) + handleMarkType (type); + + markStep.MarkType (type.BaseType, new DependencyInfo (DependencyKind.BaseType, type)); + + // The DynamicallyAccessedMembers hierarchy processing must be done after the base type was marked + // (to avoid inconsistencies in the cache), but before anything else as work done below + // might need the results of the processing here. + markStep.DynamicallyAccessedMembersTypeHierarchy.ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (type); + + if (type.DeclaringType != null) + markStep.MarkType (type.DeclaringType, new DependencyInfo (DependencyKind.DeclaringType, type)); + markStep.MarkCustomAttributes (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); + markStep.MarkSecurityDeclarations (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); + + if (Context.TryResolve (type.BaseType) is TypeDefinition baseType && + !markStep.Annotations.HasLinkerAttribute (type) && + markStep.Annotations.TryGetLinkerAttribute (baseType, out RequiresUnreferencedCodeAttribute? effectiveRequiresUnreferencedCode)) { + + var currentOrigin = markStep.ScopeStack.CurrentScope.Origin; + + string arg1 = MessageFormat.FormatRequiresAttributeMessageArg (effectiveRequiresUnreferencedCode.Message); + string arg2 = MessageFormat.FormatRequiresAttributeUrlArg (effectiveRequiresUnreferencedCode.Url); + Context.LogWarning (currentOrigin, DiagnosticId.RequiresUnreferencedCodeOnBaseClass, type.GetDisplayName (), type.BaseType.GetDisplayName (), arg1, arg2); + } + + + if (type.IsMulticastDelegate ()) { + markStep.MarkMulticastDelegate (type); + } + + if (type.IsClass && type.BaseType == null && type.Name == "Object" && markStep.ShouldMarkSystemObjectFinalize) + markStep.MarkMethodIf (type.Methods, m => m.Name == "Finalize", new DependencyInfo (DependencyKind.MethodForSpecialType, type), markStep.ScopeStack.CurrentScope.Origin); + + markStep.MarkSerializable (type); + + // This marks static fields of KeyWords/OpCodes/Tasks subclasses of an EventSource type. + // The special handling of EventSource is still needed in .NET6 in library mode + if ((!Context.DisableEventSourceSpecialHandling || Context.GetTargetRuntimeVersion () < TargetRuntimeVersion.NET6) && BCL.EventTracingForWindows.IsEventSourceImplementation (type, Context)) { + markStep.MarkEventSourceProviders (type); + } + + // This marks properties for [EventData] types as well as other attribute dependencies. + markStep.MarkTypeSpecialCustomAttributes (type); + + markStep.MarkGenericParameterProvider (type); + + // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated + // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type -- Note this is not true for static interfaces + // However, for some other types there is no benefit to deferring + if (type.IsInterface) { + // There's no benefit to deferring processing of an interface type until we know a type implementing that interface is marked + markStep.MarkRequirementsForInstantiatedTypes (type); + } else if (type.IsValueType) { + // Note : Technically interfaces could be removed from value types in some of the same cases as reference types, however, it's harder to know when + // a value type instance could exist. You'd have to track initobj and maybe locals types. Going to punt for now. + markStep.MarkRequirementsForInstantiatedTypes (type); + } else if (markStep.IsFullyPreserved (type)) { + // Here for a couple reasons: + // * Edge case to cover a scenario where a type has preserve all, implements interfaces, but does not have any instance ctors. + // Normally TypePreserve.All would cause an instance ctor to be marked and that would in turn lead to MarkInterfaceImplementations being called + // Without an instance ctor, MarkInterfaceImplementations is not called and then TypePreserve.All isn't truly respected. + // * If an assembly has the action Copy and had ResolveFromAssemblyStep ran for the assembly, then InitializeType will have led us here + // When the entire assembly is preserved, then all interfaces, base, etc will be preserved on the type, so we need to make sure + // all of these types are marked. For example, if an interface implementation is of a type in another assembly that is linked, + // and there are no other usages of that interface type, then we need to make sure the interface type is still marked because + // this type is going to retain the interface implementation + markStep.MarkRequirementsForInstantiatedTypes (type); + } else if (markStep.AlwaysMarkTypeAsInstantiated (type)) { + markStep.MarkRequirementsForInstantiatedTypes (type); + } + + // Save for later once we know which interfaces are marked and then determine which interface implementations and methods to keep + if (type.HasInterfaces) + markStep._typesWithInterfaces.Add ((type, markStep.ScopeStack.CurrentScope)); + + if (type.HasMethods) { + // TODO: MarkMethodIfNeededByBaseMethod should include logic for IsMethodNeededByTypeDueToPreservedScope: https://github.com/dotnet/linker/issues/3090 + foreach (var method in type.Methods) { + markStep.MarkMethodIfNeededByBaseMethod (method); + if (markStep.IsMethodNeededByTypeDueToPreservedScope (method)) { + // For methods that must be preserved, blame the declaring type. + markStep.MarkMethod (method, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type), markStep.ScopeStack.CurrentScope.Origin); + } + } + if (markStep.ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { + using (markStep.ScopeStack.PopToParentScope ()) + markStep.MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), markStep.ScopeStack.CurrentScope.Origin); + } + } + + markStep.DoAdditionalTypeProcessing (type); + + markStep.ApplyPreserveInfo (type); + markStep.ApplyPreserveMethods (type); + + } + + } + + protected internal virtual void MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) + { + _analyzer.AddRoot(new TypeDependencyNode(reference, reason, origin, this), "MarkedType"); + } + static bool IsFullyPreservedAction (AssemblyAction action) => action == AssemblyAction.Copy || action == AssemblyAction.Save; bool MarkFullyPreservedAssemblies () @@ -1942,7 +2140,7 @@ protected virtual void MarkSerializable (TypeDefinition type) MarkMethodsIf (type.Methods, HasOnSerializeOrDeserializeAttribute, new DependencyInfo (DependencyKind.SerializationMethodForType, type), ScopeStack.CurrentScope.Origin); } - protected internal virtual TypeDefinition? MarkTypeVisibleToReflection (TypeReference type, TypeDefinition definition, in DependencyInfo reason, in MessageOrigin origin) + protected internal virtual void MarkTypeVisibleToReflection (TypeReference type, TypeDefinition definition, in DependencyInfo reason, in MessageOrigin origin) { // If a type is visible to reflection, we need to stop doing optimization that could cause observable difference // in reflection APIs. This includes APIs like MakeGenericType (where variant castability of the produced type @@ -1953,7 +2151,7 @@ protected virtual void MarkSerializable (TypeDefinition type) MarkImplicitlyUsedFields (definition); - return MarkType (type, reason, origin); + MarkType (type, reason, origin); } internal void MarkMethodVisibleToReflection (MethodReference method, in DependencyInfo reason, in MessageOrigin origin) @@ -1998,168 +2196,6 @@ 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 - /// The resolved type definition if the reference can be resolved - protected internal virtual TypeDefinition? MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) - { -#if DEBUG - if (!_typeReasons.Contains (reason.Kind)) - throw new ArgumentOutOfRangeException ($"Internal error: unsupported type dependency {reason.Kind}"); -#endif - if (reference == null) - return null; - - using MarkScopeStack.LocalScope? localScope = origin.HasValue ? ScopeStack.PushLocalScope (origin.Value) : null; - - (reference, reason) = GetOriginalType (reference, reason); - - if (reference is FunctionPointerType) - return null; - - if (reference is GenericParameter) - return null; - - TypeDefinition? type = Context.Resolve (reference); - - if (type == null) - return null; - - // Track a mark reason for each call to MarkType. - switch (reason.Kind) { - case DependencyKind.AlreadyMarked: - Debug.Assert (Annotations.IsMarked (type)); - break; - default: - Annotations.Mark (type, reason, ScopeStack.CurrentScope.Origin); - break; - } - - // Treat cctors triggered by a called method specially and mark this case up-front. - if (type.HasMethods && ShouldMarkTypeStaticConstructor (type) && reason.Kind == DependencyKind.DeclaringTypeOfCalledMethod) - MarkStaticConstructor (type, new DependencyInfo (DependencyKind.TriggersCctorForCalledMethod, reason.Source), ScopeStack.CurrentScope.Origin); - - if (Annotations.HasLinkerAttribute (type)) { - // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute - // will call MarkType on the attribute type itself). - // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 - // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. - // Also don't warn when the type is marked due to an assembly being rooted. - if (!(reason.Source is IMemberDefinition sourceMemberDefinition && sourceMemberDefinition.DeclaringType == type) && - reason.Kind is not DependencyKind.TypeInAssembly) - Context.LogWarning (ScopeStack.CurrentScope.Origin, DiagnosticId.AttributeIsReferencedButTrimmerRemoveAllInstances, type.GetDisplayName ()); - } - - if (CheckProcessed (type)) - return type; - - if (type.Scope is ModuleDefinition module) - MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); - - using var typeScope = ScopeStack.PushLocalScope (new MessageOrigin (type)); - - foreach (Action handleMarkType in MarkContext.MarkTypeActions) - handleMarkType (type); - - MarkType (type.BaseType, new DependencyInfo (DependencyKind.BaseType, type)); - - // The DynamicallyAccessedMembers hierarchy processing must be done after the base type was marked - // (to avoid inconsistencies in the cache), but before anything else as work done below - // might need the results of the processing here. - DynamicallyAccessedMembersTypeHierarchy.ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (type); - - if (type.DeclaringType != null) - MarkType (type.DeclaringType, new DependencyInfo (DependencyKind.DeclaringType, type)); - MarkCustomAttributes (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); - MarkSecurityDeclarations (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); - - if (Context.TryResolve (type.BaseType) is TypeDefinition baseType && - !Annotations.HasLinkerAttribute (type) && - Annotations.TryGetLinkerAttribute (baseType, out RequiresUnreferencedCodeAttribute? effectiveRequiresUnreferencedCode)) { - - var currentOrigin = ScopeStack.CurrentScope.Origin; - - string arg1 = MessageFormat.FormatRequiresAttributeMessageArg (effectiveRequiresUnreferencedCode.Message); - string arg2 = MessageFormat.FormatRequiresAttributeUrlArg (effectiveRequiresUnreferencedCode.Url); - Context.LogWarning (currentOrigin, DiagnosticId.RequiresUnreferencedCodeOnBaseClass, type.GetDisplayName (), type.BaseType.GetDisplayName (), arg1, arg2); - } - - - if (type.IsMulticastDelegate ()) { - MarkMulticastDelegate (type); - } - - if (type.IsClass && type.BaseType == null && type.Name == "Object" && ShouldMarkSystemObjectFinalize) - MarkMethodIf (type.Methods, m => m.Name == "Finalize", new DependencyInfo (DependencyKind.MethodForSpecialType, type), ScopeStack.CurrentScope.Origin); - - MarkSerializable (type); - - // This marks static fields of KeyWords/OpCodes/Tasks subclasses of an EventSource type. - // The special handling of EventSource is still needed in .NET6 in library mode - if ((!Context.DisableEventSourceSpecialHandling || Context.GetTargetRuntimeVersion () < TargetRuntimeVersion.NET6) && BCL.EventTracingForWindows.IsEventSourceImplementation (type, Context)) { - MarkEventSourceProviders (type); - } - - // This marks properties for [EventData] types as well as other attribute dependencies. - MarkTypeSpecialCustomAttributes (type); - - MarkGenericParameterProvider (type); - - // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated - // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type -- Note this is not true for static interfaces - // However, for some other types there is no benefit to deferring - if (type.IsInterface) { - // There's no benefit to deferring processing of an interface type until we know a type implementing that interface is marked - MarkRequirementsForInstantiatedTypes (type); - } else if (type.IsValueType) { - // Note : Technically interfaces could be removed from value types in some of the same cases as reference types, however, it's harder to know when - // a value type instance could exist. You'd have to track initobj and maybe locals types. Going to punt for now. - MarkRequirementsForInstantiatedTypes (type); - } else if (IsFullyPreserved (type)) { - // Here for a couple reasons: - // * Edge case to cover a scenario where a type has preserve all, implements interfaces, but does not have any instance ctors. - // Normally TypePreserve.All would cause an instance ctor to be marked and that would in turn lead to MarkInterfaceImplementations being called - // Without an instance ctor, MarkInterfaceImplementations is not called and then TypePreserve.All isn't truly respected. - // * If an assembly has the action Copy and had ResolveFromAssemblyStep ran for the assembly, then InitializeType will have led us here - // When the entire assembly is preserved, then all interfaces, base, etc will be preserved on the type, so we need to make sure - // all of these types are marked. For example, if an interface implementation is of a type in another assembly that is linked, - // and there are no other usages of that interface type, then we need to make sure the interface type is still marked because - // this type is going to retain the interface implementation - MarkRequirementsForInstantiatedTypes (type); - } else if (AlwaysMarkTypeAsInstantiated (type)) { - MarkRequirementsForInstantiatedTypes (type); - } - - // Save for later once we know which interfaces are marked and then determine which interface implementations and methods to keep - if (type.HasInterfaces) - _typesWithInterfaces.Add ((type, ScopeStack.CurrentScope)); - - if (type.HasMethods) { - // TODO: MarkMethodIfNeededByBaseMethod should include logic for IsMethodNeededByTypeDueToPreservedScope: https://github.com/dotnet/linker/issues/3090 - foreach (var method in type.Methods) { - MarkMethodIfNeededByBaseMethod (method); - if (IsMethodNeededByTypeDueToPreservedScope (method)) { - // For methods that must be preserved, blame the declaring type. - MarkMethod (method, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type), ScopeStack.CurrentScope.Origin); - } - } - if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { - using (ScopeStack.PopToParentScope ()) - MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin); - } - } - - DoAdditionalTypeProcessing (type); - - ApplyPreserveInfo (type); - ApplyPreserveMethods (type); - - return type; - } - /// /// Allow subclasses to disable marking of System.Object.Finalize() /// @@ -2805,7 +2841,7 @@ void MarkGenericArguments (IGenericInstance instance) var argument = arguments[i]; var parameter = parameters[i]; - TypeDefinition? argumentTypeDef = MarkType (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)); + MarkType (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)); if (Annotations.FlowAnnotations.RequiresGenericArgumentDataFlowAnalysis (parameter)) { // The only two implementations of IGenericInstance both derive from MemberReference @@ -2816,6 +2852,15 @@ void MarkGenericArguments (IGenericInstance instance) scanner.ProcessGenericArgumentDataFlow (parameter, argument); } + (argument, _) = GetOriginalType (argument, new DependencyInfo(DependencyKind.GenericArgumentType, argument)); + if (argument is FunctionPointerType) + continue; + + if (argument is GenericParameter) + continue; + + TypeDefinition? argumentTypeDef = Context.Resolve (argument); + if (argumentTypeDef == null) continue; diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs index 0a390275ea81c4..5c3bd5a9d6654f 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/DataFlowTests.g.cs @@ -19,12 +19,6 @@ public Task GenericParameterDataFlowMarking () return RunTest (allowMissingWarnings: true); } - [Fact] - public Task MakeGenericDataflowIntrinsics () - { - return RunTest (allowMissingWarnings: true); - } - [Fact] public Task MethodByRefParameterDataFlow () { From b3ccd6630a0de5b3e9681da869a23139c27be1f5 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:26:05 -0700 Subject: [PATCH 03/28] Leave MarkType in MarkStep, use captured MarkStep to call it --- .../src/linker/Linker.Steps/MarkStep.cs | 335 +++++++++--------- 1 file changed, 167 insertions(+), 168 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index f7dbc2a28464ec..5567845735151c 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -439,7 +439,6 @@ public TypeDependencyNode(TypeReference reference, DependencyInfo reason, Messag this.reason = reason; this.origin = origin; this.markStep = markStep; - this.Context = markStep.Context; } public override bool InterestingForDynamicDependencyAnalysis => false; @@ -449,13 +448,11 @@ public TypeDependencyNode(TypeReference reference, DependencyInfo reason, Messag public override bool StaticDependenciesAreComputed => true; - TypeReference reference { get; set; } - DependencyInfo reason { get; set; } + TypeReference reference { get; } + DependencyInfo reason { get; } MessageOrigin? origin { get; } - readonly MarkStep markStep; - - LinkContext Context { get; } + MarkStep markStep { get; } public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) { @@ -467,159 +464,8 @@ public TypeDependencyNode(TypeReference reference, DependencyInfo reason, Messag protected override string GetName (MarkStepNodeFactory context) => "TypeNode"; protected override void OnMarked (MarkStepNodeFactory context) { -#if DEBUG - if (!_typeReasons.Contains (reason.Kind)) - throw new ArgumentOutOfRangeException ($"Internal error: unsupported type dependency {reason.Kind}"); -#endif - if (reference == null) - return; - - using MarkScopeStack.LocalScope? localScope = origin.HasValue ? markStep.ScopeStack.PushLocalScope (origin.Value) : null; - - (reference, reason) = markStep.GetOriginalType (reference, reason); - - if (reference is FunctionPointerType) - return; - - if (reference is GenericParameter) - return; - - TypeDefinition? type = Context.Resolve (reference); - - if (type == null) - return; - - // Track a mark reason for each call to MarkType. - switch (reason.Kind) { - case DependencyKind.AlreadyMarked: - Debug.Assert (markStep.Annotations.IsMarked (type)); - break; - default: - markStep.Annotations.Mark (type, reason, markStep.ScopeStack.CurrentScope.Origin); - break; - } - - // Treat cctors triggered by a called method specially and mark this case up-front. - if (type.HasMethods && markStep.ShouldMarkTypeStaticConstructor (type) && reason.Kind == DependencyKind.DeclaringTypeOfCalledMethod) - markStep.MarkStaticConstructor (type, new DependencyInfo (DependencyKind.TriggersCctorForCalledMethod, reason.Source), markStep.ScopeStack.CurrentScope.Origin); - - if (markStep.Annotations.HasLinkerAttribute (type)) { - // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute - // will call MarkType on the attribute type itself). - // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 - // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. - // Also don't warn when the type is marked due to an assembly being rooted. - if (!(reason.Source is IMemberDefinition sourceMemberDefinition && sourceMemberDefinition.DeclaringType == type) && - reason.Kind is not DependencyKind.TypeInAssembly) - Context.LogWarning (markStep.ScopeStack.CurrentScope.Origin, DiagnosticId.AttributeIsReferencedButTrimmerRemoveAllInstances, type.GetDisplayName ()); - } - - if (markStep.CheckProcessed (type)) - return; - - if (type.Scope is ModuleDefinition module) - markStep.MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); - - using var typeScope = markStep.ScopeStack.PushLocalScope (new MessageOrigin (type)); - - foreach (Action handleMarkType in markStep.MarkContext.MarkTypeActions) - handleMarkType (type); - - markStep.MarkType (type.BaseType, new DependencyInfo (DependencyKind.BaseType, type)); - - // The DynamicallyAccessedMembers hierarchy processing must be done after the base type was marked - // (to avoid inconsistencies in the cache), but before anything else as work done below - // might need the results of the processing here. - markStep.DynamicallyAccessedMembersTypeHierarchy.ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (type); - - if (type.DeclaringType != null) - markStep.MarkType (type.DeclaringType, new DependencyInfo (DependencyKind.DeclaringType, type)); - markStep.MarkCustomAttributes (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); - markStep.MarkSecurityDeclarations (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); - - if (Context.TryResolve (type.BaseType) is TypeDefinition baseType && - !markStep.Annotations.HasLinkerAttribute (type) && - markStep.Annotations.TryGetLinkerAttribute (baseType, out RequiresUnreferencedCodeAttribute? effectiveRequiresUnreferencedCode)) { - - var currentOrigin = markStep.ScopeStack.CurrentScope.Origin; - - string arg1 = MessageFormat.FormatRequiresAttributeMessageArg (effectiveRequiresUnreferencedCode.Message); - string arg2 = MessageFormat.FormatRequiresAttributeUrlArg (effectiveRequiresUnreferencedCode.Url); - Context.LogWarning (currentOrigin, DiagnosticId.RequiresUnreferencedCodeOnBaseClass, type.GetDisplayName (), type.BaseType.GetDisplayName (), arg1, arg2); - } - - - if (type.IsMulticastDelegate ()) { - markStep.MarkMulticastDelegate (type); - } - - if (type.IsClass && type.BaseType == null && type.Name == "Object" && markStep.ShouldMarkSystemObjectFinalize) - markStep.MarkMethodIf (type.Methods, m => m.Name == "Finalize", new DependencyInfo (DependencyKind.MethodForSpecialType, type), markStep.ScopeStack.CurrentScope.Origin); - - markStep.MarkSerializable (type); - - // This marks static fields of KeyWords/OpCodes/Tasks subclasses of an EventSource type. - // The special handling of EventSource is still needed in .NET6 in library mode - if ((!Context.DisableEventSourceSpecialHandling || Context.GetTargetRuntimeVersion () < TargetRuntimeVersion.NET6) && BCL.EventTracingForWindows.IsEventSourceImplementation (type, Context)) { - markStep.MarkEventSourceProviders (type); - } - - // This marks properties for [EventData] types as well as other attribute dependencies. - markStep.MarkTypeSpecialCustomAttributes (type); - - markStep.MarkGenericParameterProvider (type); - - // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated - // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type -- Note this is not true for static interfaces - // However, for some other types there is no benefit to deferring - if (type.IsInterface) { - // There's no benefit to deferring processing of an interface type until we know a type implementing that interface is marked - markStep.MarkRequirementsForInstantiatedTypes (type); - } else if (type.IsValueType) { - // Note : Technically interfaces could be removed from value types in some of the same cases as reference types, however, it's harder to know when - // a value type instance could exist. You'd have to track initobj and maybe locals types. Going to punt for now. - markStep.MarkRequirementsForInstantiatedTypes (type); - } else if (markStep.IsFullyPreserved (type)) { - // Here for a couple reasons: - // * Edge case to cover a scenario where a type has preserve all, implements interfaces, but does not have any instance ctors. - // Normally TypePreserve.All would cause an instance ctor to be marked and that would in turn lead to MarkInterfaceImplementations being called - // Without an instance ctor, MarkInterfaceImplementations is not called and then TypePreserve.All isn't truly respected. - // * If an assembly has the action Copy and had ResolveFromAssemblyStep ran for the assembly, then InitializeType will have led us here - // When the entire assembly is preserved, then all interfaces, base, etc will be preserved on the type, so we need to make sure - // all of these types are marked. For example, if an interface implementation is of a type in another assembly that is linked, - // and there are no other usages of that interface type, then we need to make sure the interface type is still marked because - // this type is going to retain the interface implementation - markStep.MarkRequirementsForInstantiatedTypes (type); - } else if (markStep.AlwaysMarkTypeAsInstantiated (type)) { - markStep.MarkRequirementsForInstantiatedTypes (type); + markStep.MarkTypeImpl (reference, reason, origin); } - - // Save for later once we know which interfaces are marked and then determine which interface implementations and methods to keep - if (type.HasInterfaces) - markStep._typesWithInterfaces.Add ((type, markStep.ScopeStack.CurrentScope)); - - if (type.HasMethods) { - // TODO: MarkMethodIfNeededByBaseMethod should include logic for IsMethodNeededByTypeDueToPreservedScope: https://github.com/dotnet/linker/issues/3090 - foreach (var method in type.Methods) { - markStep.MarkMethodIfNeededByBaseMethod (method); - if (markStep.IsMethodNeededByTypeDueToPreservedScope (method)) { - // For methods that must be preserved, blame the declaring type. - markStep.MarkMethod (method, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type), markStep.ScopeStack.CurrentScope.Origin); - } - } - if (markStep.ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { - using (markStep.ScopeStack.PopToParentScope ()) - markStep.MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), markStep.ScopeStack.CurrentScope.Origin); - } - } - - markStep.DoAdditionalTypeProcessing (type); - - markStep.ApplyPreserveInfo (type); - markStep.ApplyPreserveMethods (type); - - } - } protected internal virtual void MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) @@ -2196,6 +2042,168 @@ 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 + /// The resolved type definition if the reference can be resolved + protected internal virtual TypeDefinition? MarkTypeImpl (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) + { +#if DEBUG + if (!_typeReasons.Contains (reason.Kind)) + throw new ArgumentOutOfRangeException ($"Internal error: unsupported type dependency {reason.Kind}"); +#endif + if (reference == null) + return null; + + using MarkScopeStack.LocalScope? localScope = origin.HasValue ? ScopeStack.PushLocalScope (origin.Value) : null; + + (reference, reason) = GetOriginalType (reference, reason); + + if (reference is FunctionPointerType) + return null; + + if (reference is GenericParameter) + return null; + + TypeDefinition? type = Context.Resolve (reference); + + if (type == null) + return null; + + // Track a mark reason for each call to MarkType. + switch (reason.Kind) { + case DependencyKind.AlreadyMarked: + Debug.Assert (Annotations.IsMarked (type)); + break; + default: + Annotations.Mark (type, reason, ScopeStack.CurrentScope.Origin); + break; + } + + // Treat cctors triggered by a called method specially and mark this case up-front. + if (type.HasMethods && ShouldMarkTypeStaticConstructor (type) && reason.Kind == DependencyKind.DeclaringTypeOfCalledMethod) + MarkStaticConstructor (type, new DependencyInfo (DependencyKind.TriggersCctorForCalledMethod, reason.Source), ScopeStack.CurrentScope.Origin); + + if (Annotations.HasLinkerAttribute (type)) { + // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute + // will call MarkType on the attribute type itself). + // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 + // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. + // Also don't warn when the type is marked due to an assembly being rooted. + if (!(reason.Source is IMemberDefinition sourceMemberDefinition && sourceMemberDefinition.DeclaringType == type) && + reason.Kind is not DependencyKind.TypeInAssembly) + Context.LogWarning (ScopeStack.CurrentScope.Origin, DiagnosticId.AttributeIsReferencedButTrimmerRemoveAllInstances, type.GetDisplayName ()); + } + + if (CheckProcessed (type)) + return type; + + if (type.Scope is ModuleDefinition module) + MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); + + using var typeScope = ScopeStack.PushLocalScope (new MessageOrigin (type)); + + foreach (Action handleMarkType in MarkContext.MarkTypeActions) + handleMarkType (type); + + MarkType (type.BaseType, new DependencyInfo (DependencyKind.BaseType, type)); + + // The DynamicallyAccessedMembers hierarchy processing must be done after the base type was marked + // (to avoid inconsistencies in the cache), but before anything else as work done below + // might need the results of the processing here. + DynamicallyAccessedMembersTypeHierarchy.ProcessMarkedTypeForDynamicallyAccessedMembersHierarchy (type); + + if (type.DeclaringType != null) + MarkType (type.DeclaringType, new DependencyInfo (DependencyKind.DeclaringType, type)); + MarkCustomAttributes (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); + MarkSecurityDeclarations (type, new DependencyInfo (DependencyKind.CustomAttribute, type)); + + if (Context.TryResolve (type.BaseType) is TypeDefinition baseType && + !Annotations.HasLinkerAttribute (type) && + Annotations.TryGetLinkerAttribute (baseType, out RequiresUnreferencedCodeAttribute? effectiveRequiresUnreferencedCode)) { + + var currentOrigin = ScopeStack.CurrentScope.Origin; + + string arg1 = MessageFormat.FormatRequiresAttributeMessageArg (effectiveRequiresUnreferencedCode.Message); + string arg2 = MessageFormat.FormatRequiresAttributeUrlArg (effectiveRequiresUnreferencedCode.Url); + Context.LogWarning (currentOrigin, DiagnosticId.RequiresUnreferencedCodeOnBaseClass, type.GetDisplayName (), type.BaseType.GetDisplayName (), arg1, arg2); + } + + + if (type.IsMulticastDelegate ()) { + MarkMulticastDelegate (type); + } + + if (type.IsClass && type.BaseType == null && type.Name == "Object" && ShouldMarkSystemObjectFinalize) + MarkMethodIf (type.Methods, m => m.Name == "Finalize", new DependencyInfo (DependencyKind.MethodForSpecialType, type), ScopeStack.CurrentScope.Origin); + + MarkSerializable (type); + + // This marks static fields of KeyWords/OpCodes/Tasks subclasses of an EventSource type. + // The special handling of EventSource is still needed in .NET6 in library mode + if ((!Context.DisableEventSourceSpecialHandling || Context.GetTargetRuntimeVersion () < TargetRuntimeVersion.NET6) && BCL.EventTracingForWindows.IsEventSourceImplementation (type, Context)) { + MarkEventSourceProviders (type); + } + + // This marks properties for [EventData] types as well as other attribute dependencies. + MarkTypeSpecialCustomAttributes (type); + + MarkGenericParameterProvider (type); + + // There are a number of markings we can defer until later when we know it's possible a reference type could be instantiated + // For example, if no instance of a type exist, then we don't need to mark the interfaces on that type -- Note this is not true for static interfaces + // However, for some other types there is no benefit to deferring + if (type.IsInterface) { + // There's no benefit to deferring processing of an interface type until we know a type implementing that interface is marked + MarkRequirementsForInstantiatedTypes (type); + } else if (type.IsValueType) { + // Note : Technically interfaces could be removed from value types in some of the same cases as reference types, however, it's harder to know when + // a value type instance could exist. You'd have to track initobj and maybe locals types. Going to punt for now. + MarkRequirementsForInstantiatedTypes (type); + } else if (IsFullyPreserved (type)) { + // Here for a couple reasons: + // * Edge case to cover a scenario where a type has preserve all, implements interfaces, but does not have any instance ctors. + // Normally TypePreserve.All would cause an instance ctor to be marked and that would in turn lead to MarkInterfaceImplementations being called + // Without an instance ctor, MarkInterfaceImplementations is not called and then TypePreserve.All isn't truly respected. + // * If an assembly has the action Copy and had ResolveFromAssemblyStep ran for the assembly, then InitializeType will have led us here + // When the entire assembly is preserved, then all interfaces, base, etc will be preserved on the type, so we need to make sure + // all of these types are marked. For example, if an interface implementation is of a type in another assembly that is linked, + // and there are no other usages of that interface type, then we need to make sure the interface type is still marked because + // this type is going to retain the interface implementation + MarkRequirementsForInstantiatedTypes (type); + } else if (AlwaysMarkTypeAsInstantiated (type)) { + MarkRequirementsForInstantiatedTypes (type); + } + + // Save for later once we know which interfaces are marked and then determine which interface implementations and methods to keep + if (type.HasInterfaces) + _typesWithInterfaces.Add ((type, ScopeStack.CurrentScope)); + + if (type.HasMethods) { + // TODO: MarkMethodIfNeededByBaseMethod should include logic for IsMethodNeededByTypeDueToPreservedScope: https://github.com/dotnet/linker/issues/3090 + foreach (var method in type.Methods) { + MarkMethodIfNeededByBaseMethod (method); + if (IsMethodNeededByTypeDueToPreservedScope (method)) { + // For methods that must be preserved, blame the declaring type. + MarkMethod (method, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type), ScopeStack.CurrentScope.Origin); + } + } + if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { + using (ScopeStack.PopToParentScope ()) + MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin); + } + } + + DoAdditionalTypeProcessing (type); + + ApplyPreserveInfo (type); + ApplyPreserveMethods (type); + + return type; + } + /// /// Allow subclasses to disable marking of System.Object.Finalize() /// @@ -2841,7 +2849,7 @@ void MarkGenericArguments (IGenericInstance instance) var argument = arguments[i]; var parameter = parameters[i]; - MarkType (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)); + var argumentTypeDef = MarkTypeImpl (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)); if (Annotations.FlowAnnotations.RequiresGenericArgumentDataFlowAnalysis (parameter)) { // The only two implementations of IGenericInstance both derive from MemberReference @@ -2852,15 +2860,6 @@ void MarkGenericArguments (IGenericInstance instance) scanner.ProcessGenericArgumentDataFlow (parameter, argument); } - (argument, _) = GetOriginalType (argument, new DependencyInfo(DependencyKind.GenericArgumentType, argument)); - if (argument is FunctionPointerType) - continue; - - if (argument is GenericParameter) - continue; - - TypeDefinition? argumentTypeDef = Context.Resolve (argument); - if (argumentTypeDef == null) continue; From eb5e33332cce9090d627893d489d7b2e2995c53c Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:29:06 -0700 Subject: [PATCH 04/28] Format --- .../src/linker/Linker.Steps/MarkStep.cs | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 5567845735151c..59a5cb8f4a1ec8 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -230,7 +230,7 @@ public MarkStep () _pending_isinst_instr = new List<(TypeDefinition, MethodBody, Instruction)> (); _entireTypesMarked = new HashSet (); _compilerGeneratedMethodRequiresScanner = new Dictionary (); - _analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (new MarkStepNodeFactory(this), null); + _analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (new MarkStepNodeFactory (this), null); } public AnnotationStore Annotations => Context.Annotations; @@ -393,7 +393,7 @@ bool ProcessAllPendingItems () ProcessMarkedPending () || ProcessLazyAttributes () || ProcessLateMarkedAttributes () || - MarkFullyPreservedAssemblies () ; + MarkFullyPreservedAssemblies (); } public class MarkStepNodeFactory (MarkStep markStep) @@ -408,7 +408,7 @@ sealed class ProcessCallbackDependencyNode : DependencyNodeCore action) => _processAction = action; - public void Process() + public void Process () { _dependencies = new DependencyList (); if (_processAction ()) { @@ -431,9 +431,14 @@ public void Process() protected override string GetName (MarkStepNodeFactory context) => "Process"; } - public class TypeDependencyNode: DependencyNodeCore + public class TypeDependencyNode : DependencyNodeCore { - public TypeDependencyNode(TypeReference reference, DependencyInfo reason, MessageOrigin? origin, MarkStep markStep) + readonly TypeReference reference; + readonly DependencyInfo reason; + readonly MessageOrigin? origin; + readonly MarkStep markStep; + + public TypeDependencyNode (TypeReference reference, DependencyInfo reason, MessageOrigin? origin, MarkStep markStep) { this.reference = reference; this.reason = reason; @@ -448,14 +453,9 @@ public TypeDependencyNode(TypeReference reference, DependencyInfo reason, Messag public override bool StaticDependenciesAreComputed => true; - TypeReference reference { get; } - DependencyInfo reason { get; } - MessageOrigin? origin { get; } - - MarkStep markStep { get; } - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) { + // Add other types that are marked in MarkType yield break; } @@ -470,7 +470,7 @@ protected override void OnMarked (MarkStepNodeFactory context) protected internal virtual void MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) { - _analyzer.AddRoot(new TypeDependencyNode(reference, reason, origin, this), "MarkedType"); + _analyzer.AddRoot (new TypeDependencyNode (reference, reason, origin, this), "MarkedType"); } static bool IsFullyPreservedAction (AssemblyAction action) => action == AssemblyAction.Copy || action == AssemblyAction.Save; @@ -756,7 +756,7 @@ void ProcessVirtualMethod (MethodDefinition method) MarkMethod (dimInfo.Override, new DependencyInfo (DependencyKind.Override, dimInfo.Base), ScopeStack.CurrentScope.Origin); } } - List? overridingMethods = (List?)Annotations.GetOverrides (method); + List? overridingMethods = (List?) Annotations.GetOverrides (method); if (overridingMethods is not null) { for (int i = 0; i < overridingMethods.Count; i++) { OverrideInformation ov = overridingMethods[i]; From e1270bbcf07c665bca58e65371849da1efb6d782 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 19 Apr 2024 16:21:39 -0700 Subject: [PATCH 05/28] Use DF for TypeDefinition and MethodDefinition --- .../MarkStep.MarkStepNodeFactory.cs | 43 +++ ...MarkStep.MethodDefinitionDependencyNode.cs | 109 ++++++++ .../MarkStep.ProcessCallbackDependencyNode.cs | 72 +++++ .../MarkStep.TypeDependencyNode.cs | 79 ++++++ ...Step.TypeIsRelevantToVariantCastingNode.cs | 70 +++++ .../src/linker/Linker.Steps/MarkStep.cs | 245 +++++++----------- .../src/linker/Linker/DictionaryExtensions.cs | 21 ++ 7 files changed, 493 insertions(+), 146 deletions(-) create mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs create mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs create mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs create mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs create mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs new file mode 100644 index 00000000000000..e841eb587a1c42 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs @@ -0,0 +1,43 @@ +// 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. + +// +// MarkStep.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +namespace Mono.Linker.Steps +{ + + public partial class MarkStep + { + public class MarkStepNodeFactory (MarkStep markStep) + { + public MarkStep MarkStep { get; } = markStep; + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs new file mode 100644 index 00000000000000..997e896a79bc2f --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs @@ -0,0 +1,109 @@ +// 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. + +// +// MarkStep.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Collections.Generic; +using ILCompiler.DependencyAnalysisFramework; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + + public partial class MarkStep + { + public class PostPoneMethodMarkingNode : DependencyNodeCore + { + readonly MethodDefinition method; + readonly DependencyInfo reason; + readonly MessageOrigin origin; + + public PostPoneMethodMarkingNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + { + this.method = method; + this.reason = reason; + this.origin = origin; + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => true; + + public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) + { + yield return new DependencyListEntry(context.MarkStep.GetMethodDefinitionNode (method, reason, origin), "Needed"); + } + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "PostPoneMethodMarkingProxy"; + } + + public class MethodDefinitionDependencyNode : DependencyNodeCore + { + readonly MethodDefinition method; + readonly MessageOrigin origin; + readonly DependencyInfo reason; + + public MethodDefinitionDependencyNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + { + this.method = method; + this.origin = origin; + this.reason = reason; + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => true; + + public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) + { + // Add other types that are marked in MarkType + yield break; + } + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "MethodDefinition"; + protected override void OnMarked (MarkStepNodeFactory context) + { + context.MarkStep.ProcessMethod (method, reason, origin); + } + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs new file mode 100644 index 00000000000000..ff233207f7bc67 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs @@ -0,0 +1,72 @@ +// 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. + +// +// MarkStep.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using ILCompiler.DependencyAnalysisFramework; + +namespace Mono.Linker.Steps +{ + + public partial class MarkStep + { + sealed class ProcessCallbackDependencyNode : DependencyNodeCore + { + Func _processAction; + DependencyList? _dependencies; + + public ProcessCallbackDependencyNode (Func action) => _processAction = action; + + public void Process () + { + _dependencies = new DependencyList (); + if (_processAction ()) { + _dependencies.Add (new ProcessCallbackDependencyNode (_processAction), "Some processing was done, continuation required"); + } + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => _dependencies != null; + + public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) => _dependencies; + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "Process"; + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs new file mode 100644 index 00000000000000..06e11dc153e552 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs @@ -0,0 +1,79 @@ +// 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. + +// +// MarkStep.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Collections.Generic; +using ILCompiler.DependencyAnalysisFramework; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + + public partial class MarkStep + { + public class TypeDefinitionDependencyNode : DependencyNodeCore + { + readonly TypeDefinition type; + readonly MessageOrigin? origin; + readonly DependencyInfo reason; + + public TypeDefinitionDependencyNode (TypeDefinition type, DependencyInfo reason, MessageOrigin? origin) + { + this.type = type; + this.origin = origin; + this.reason = reason; + } + + public override bool InterestingForDynamicDependencyAnalysis => false; + + public override bool HasDynamicDependencies => false; + + public override bool HasConditionalStaticDependencies => false; + + public override bool StaticDependenciesAreComputed => true; + + public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) + { + // Add other types that are marked in MarkType + yield break; + } + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "TypeNode"; + protected override void OnMarked (MarkStepNodeFactory context) + { + using MarkScopeStack.LocalScope? localScope = origin.HasValue ? context.MarkStep.ScopeStack.PushLocalScope (origin.Value) : null; + context.MarkStep.MarkTypeImpl (type, reason, origin); + } + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs new file mode 100644 index 00000000000000..b55ef50334be65 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs @@ -0,0 +1,70 @@ +// 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. + +// +// MarkStep.cs +// +// Author: +// Jb Evain (jbevain@gmail.com) +// +// (C) 2006 Jb Evain +// (C) 2007 Novell, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System.Collections.Generic; +using ILCompiler.DependencyAnalysisFramework; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + + public partial class MarkStep + { + public class TypeIsRelevantToVariantCastingNode : DependencyNodeCore + { + TypeDefinition type; + public TypeIsRelevantToVariantCastingNode (TypeDefinition type) => this.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? GetStaticDependencies (MarkStepNodeFactory context) + { + // Add other types that are marked in MarkType + yield break; + } + + public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; + protected override string GetName (MarkStepNodeFactory context) => "TypeIsRelevantToVariantCasting"; + protected override void OnMarked (MarkStepNodeFactory 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 59a5cb8f4a1ec8..16ef66ac998786 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -37,6 +37,7 @@ using System.Linq; using System.Reflection.Metadata.Ecma335; using System.Reflection.Runtime.TypeParsing; +using System.Runtime.CompilerServices; using System.Text.RegularExpressions; using ILCompiler.DependencyAnalysisFramework; using ILLink.Shared; @@ -396,81 +397,105 @@ bool ProcessAllPendingItems () MarkFullyPreservedAssemblies (); } - public class MarkStepNodeFactory (MarkStep markStep) + private readonly Dictionary _typeNodes = new (); + public TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) { - public MarkStep MarkStep { get; } = markStep; + return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionDependencyNode (k, reason, origin)); } - sealed class ProcessCallbackDependencyNode : DependencyNodeCore + private readonly Dictionary _methodNodes = new (); + public MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) { - Func _processAction; - DependencyList? _dependencies; - - public ProcessCallbackDependencyNode (Func action) => _processAction = action; + return _methodNodes.GetOrAdd(method, (k) => new MethodDefinitionDependencyNode (k, reason, origin)); + } - public void Process () - { - _dependencies = new DependencyList (); - if (_processAction ()) { - _dependencies.Add (new ProcessCallbackDependencyNode (_processAction), "Some processing was done, continuation required"); - } - } + private readonly Dictionary _typeIsRelevantToVariantCastingNodes = new (); + TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNode (TypeDefinition type) + { + return _typeIsRelevantToVariantCastingNodes.GetOrAdd (type, static (t) => new TypeIsRelevantToVariantCastingNode (t)); + } - public override bool InterestingForDynamicDependencyAnalysis => false; + protected internal virtual TypeDefinition? MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) + { +#if DEBUG + if (!_typeReasons.Contains (reason.Kind)) + throw new ArgumentOutOfRangeException ($"Internal error: unsupported type dependency {reason.Kind}"); +#endif + if (reference == null) + return null; - public override bool HasDynamicDependencies => false; + using MarkScopeStack.LocalScope? localScope = origin.HasValue ? ScopeStack.PushLocalScope (origin.Value) : null; - public override bool HasConditionalStaticDependencies => false; + (reference, reason) = GetOriginalType (reference, reason); - public override bool StaticDependenciesAreComputed => _dependencies != null; + if (reference is FunctionPointerType) + return null; - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) => _dependencies; + if (reference is GenericParameter) + return null; - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "Process"; - } + TypeDefinition? type = Context.Resolve (reference); - public class TypeDependencyNode : DependencyNodeCore - { - readonly TypeReference reference; - readonly DependencyInfo reason; - readonly MessageOrigin? origin; - readonly MarkStep markStep; + if (type == null) + return null; - public TypeDependencyNode (TypeReference reference, DependencyInfo reason, MessageOrigin? origin, MarkStep markStep) - { - this.reference = reference; - this.reason = reason; - this.origin = origin; - this.markStep = markStep; + // Track a mark reason for each call to MarkType. + switch (reason.Kind) { + case DependencyKind.AlreadyMarked: + Debug.Assert (Annotations.IsMarked (type)); + break; + default: + Annotations.Mark (type, reason, ScopeStack.CurrentScope.Origin); + break; } - public override bool InterestingForDynamicDependencyAnalysis => false; - public override bool HasDynamicDependencies => false; + // Treat cctors triggered by a called method specially and mark this case up-front. + if (type.HasMethods && ShouldMarkTypeStaticConstructor (type) && reason.Kind == DependencyKind.DeclaringTypeOfCalledMethod) + MarkStaticConstructor (type, new DependencyInfo (DependencyKind.TriggersCctorForCalledMethod, reason.Source), ScopeStack.CurrentScope.Origin); - public override bool HasConditionalStaticDependencies => false; + if (Annotations.HasLinkerAttribute (type)) { + // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute + // will call MarkType on the attribute type itself). + // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 + // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. + // Also don't warn when the type is marked due to an assembly being rooted. + if (!(reason.Source is IMemberDefinition sourceMemberDefinition && sourceMemberDefinition.DeclaringType == type) && + reason.Kind is not DependencyKind.TypeInAssembly) + Context.LogWarning (ScopeStack.CurrentScope.Origin, DiagnosticId.AttributeIsReferencedButTrimmerRemoveAllInstances, type.GetDisplayName ()); + } - public override bool StaticDependenciesAreComputed => true; + if (CheckProcessed (type)) + return type; - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) - { - // Add other types that are marked in MarkType - yield break; - } + _analyzer.AddRoot (GetTypeNode (type, reason, origin), "MarkedType"); + return type; - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "TypeNode"; - protected override void OnMarked (MarkStepNodeFactory context) + (TypeReference, DependencyInfo) GetOriginalType (TypeReference type, DependencyInfo reason) { - markStep.MarkTypeImpl (reference, reason, origin); + while (type is TypeSpecification specification) { + if (type is GenericInstanceType git) { + MarkGenericArguments (git); + Debug.Assert (!(specification.ElementType is TypeSpecification)); + } + + if (type is IModifierType mod) + MarkModifierType (mod); + + if (type is FunctionPointerType fnptr) { + MarkParameters (fnptr); + MarkType (fnptr.ReturnType, new DependencyInfo (DependencyKind.ReturnType, fnptr)); + break; // FunctionPointerType is the original type + } + + // Blame the type reference (which isn't marked) on the original reason. + Tracer.AddDirectDependency (specification, reason, marked: false); + // Blame the outgoing element type on the specification. + (type, reason) = (specification.ElementType, new DependencyInfo (DependencyKind.ElementType, specification)); + } + + return (type, reason); } - } - protected internal virtual void MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) - { - _analyzer.AddRoot (new TypeDependencyNode (reference, reason, origin, this), "MarkedType"); } static bool IsFullyPreservedAction (AssemblyAction action) => action == AssemblyAction.Copy || action == AssemblyAction.Save; @@ -605,8 +630,9 @@ void ProcessPendingTypeChecks () void ProcessQueue () { while (!QueueIsEmpty ()) { - (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) = _methods.Dequeue (); - ProcessMethod (method, reason, origin); + _methods.Clear (); + //(MethodDefinition method, DependencyInfo reason, MessageOrigin origin) = _methods.Dequeue (); + //ProcessMethod (method, reason, origin); } } @@ -615,11 +641,6 @@ bool QueueIsEmpty () return _methods.Count == 0; } - protected virtual void EnqueueMethod (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin) - { - _methods.Enqueue ((method, reason, origin)); - } - void ProcessVirtualMethods () { foreach ((var method, var scope) in _virtual_methods) { @@ -2042,64 +2063,8 @@ 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 - /// The resolved type definition if the reference can be resolved - protected internal virtual TypeDefinition? MarkTypeImpl (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) + protected internal virtual void MarkTypeImpl (TypeDefinition type, DependencyInfo reason, MessageOrigin? origin = null) { -#if DEBUG - if (!_typeReasons.Contains (reason.Kind)) - throw new ArgumentOutOfRangeException ($"Internal error: unsupported type dependency {reason.Kind}"); -#endif - if (reference == null) - return null; - - using MarkScopeStack.LocalScope? localScope = origin.HasValue ? ScopeStack.PushLocalScope (origin.Value) : null; - - (reference, reason) = GetOriginalType (reference, reason); - - if (reference is FunctionPointerType) - return null; - - if (reference is GenericParameter) - return null; - - TypeDefinition? type = Context.Resolve (reference); - - if (type == null) - return null; - - // Track a mark reason for each call to MarkType. - switch (reason.Kind) { - case DependencyKind.AlreadyMarked: - Debug.Assert (Annotations.IsMarked (type)); - break; - default: - Annotations.Mark (type, reason, ScopeStack.CurrentScope.Origin); - break; - } - - // Treat cctors triggered by a called method specially and mark this case up-front. - if (type.HasMethods && ShouldMarkTypeStaticConstructor (type) && reason.Kind == DependencyKind.DeclaringTypeOfCalledMethod) - MarkStaticConstructor (type, new DependencyInfo (DependencyKind.TriggersCctorForCalledMethod, reason.Source), ScopeStack.CurrentScope.Origin); - - if (Annotations.HasLinkerAttribute (type)) { - // Don't warn about references from the removed attribute itself (for example the .ctor on the attribute - // will call MarkType on the attribute type itself). - // If for some reason we do keep the attribute type (could be because of previous reference which would cause IL2045 - // or because of a copy assembly with a reference and so on) then we should not spam the warnings due to the type itself. - // Also don't warn when the type is marked due to an assembly being rooted. - if (!(reason.Source is IMemberDefinition sourceMemberDefinition && sourceMemberDefinition.DeclaringType == type) && - reason.Kind is not DependencyKind.TypeInAssembly) - Context.LogWarning (ScopeStack.CurrentScope.Origin, DiagnosticId.AttributeIsReferencedButTrimmerRemoveAllInstances, type.GetDisplayName ()); - } - - if (CheckProcessed (type)) - return type; - if (type.Scope is ModuleDefinition module) MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); @@ -2137,7 +2102,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in } if (type.IsClass && type.BaseType == null && type.Name == "Object" && ShouldMarkSystemObjectFinalize) - MarkMethodIf (type.Methods, m => m.Name == "Finalize", new DependencyInfo (DependencyKind.MethodForSpecialType, type), ScopeStack.CurrentScope.Origin); + MarkMethodIf (type.Methods, static m => m.Name == "Finalize", new DependencyInfo (DependencyKind.MethodForSpecialType, type), ScopeStack.CurrentScope.Origin); MarkSerializable (type); @@ -2201,7 +2166,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in ApplyPreserveInfo (type); ApplyPreserveMethods (type); - return type; + return; } /// @@ -2791,31 +2756,6 @@ protected virtual void MarkMulticastDelegate (TypeDefinition type) MarkMethodsIf (type.Methods, m => m.Name == ".ctor" || m.Name == "Invoke", new DependencyInfo (DependencyKind.MethodForSpecialType, type), ScopeStack.CurrentScope.Origin); } - protected (TypeReference, DependencyInfo) GetOriginalType (TypeReference type, DependencyInfo reason) - { - while (type is TypeSpecification specification) { - if (type is GenericInstanceType git) { - MarkGenericArguments (git); - Debug.Assert (!(specification.ElementType is TypeSpecification)); - } - - if (type is IModifierType mod) - MarkModifierType (mod); - - if (type is FunctionPointerType fnptr) { - MarkParameters (fnptr); - MarkType (fnptr.ReturnType, new DependencyInfo (DependencyKind.ReturnType, fnptr)); - break; // FunctionPointerType is the original type - } - - // Blame the type reference (which isn't marked) on the original reason. - Tracer.AddDirectDependency (specification, reason, marked: false); - // Blame the outgoing element type on the specification. - (type, reason) = (specification.ElementType, new DependencyInfo (DependencyKind.ElementType, specification)); - } - - return (type, reason); - } void MarkParameters (FunctionPointerType fnptr) { @@ -2849,7 +2789,9 @@ void MarkGenericArguments (IGenericInstance instance) var argument = arguments[i]; var parameter = parameters[i]; - var argumentTypeDef = MarkTypeImpl (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)); + //var argumentTypeDef = MarkTypeImpl (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)); + + MarkType (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance), ScopeStack.CurrentScope.Origin); if (Annotations.FlowAnnotations.RequiresGenericArgumentDataFlowAnalysis (parameter)) { // The only two implementations of IGenericInstance both derive from MemberReference @@ -2860,10 +2802,15 @@ void MarkGenericArguments (IGenericInstance instance) scanner.ProcessGenericArgumentDataFlow (parameter, argument); } + //var originalType = GetOriginalType (argument, new DependencyInfo (DependencyKind.GenericArgumentType, instance)).Item1; + //if (originalType is null) + //continue; + var argumentTypeDef = Context.TryResolve (argument); if (argumentTypeDef == null) continue; - Annotations.MarkRelevantToVariantCasting (argumentTypeDef); + //Annotations.MarkRelevantToVariantCasting (argumentTypeDef); + _analyzer.AddRoot (GetTypeIsRelevantToVariantCastingNode (argumentTypeDef), "Generic Argument"); if (parameter.HasDefaultConstructorConstraint) MarkDefaultConstructor (argumentTypeDef, new DependencyInfo (DependencyKind.DefaultCtorForNewConstrainedGenericArgument, instance)); @@ -3117,8 +3064,14 @@ 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)) EnqueueMethod (method, reason, origin); + _analyzer.AddRoot (new PostPoneMethodMarkingNode (method, reason, origin), "Method marked"); return method; + + void EnqueueMethod (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin) + { + _methods.Enqueue ((method, reason, origin)); + } } bool ShouldWarnForReflectionAccessToCompilerGeneratedCode (MethodDefinition method, bool isCoveredByAnnotations) diff --git a/src/tools/illink/src/linker/Linker/DictionaryExtensions.cs b/src/tools/illink/src/linker/Linker/DictionaryExtensions.cs index 9cf8945fe480c5..8263ec78761ca7 100644 --- a/src/tools/illink/src/linker/Linker/DictionaryExtensions.cs +++ b/src/tools/illink/src/linker/Linker/DictionaryExtensions.cs @@ -1,6 +1,7 @@ // 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; namespace Mono.Linker @@ -16,5 +17,25 @@ public static void AddToList (this Dictionary (this Dictionary> me, TKey key, TElement value) + where TKey : notnull + { + if (!me.TryGetValue (key, out HashSet? valueList)) { + valueList = new (); + me[key] = valueList; + } + valueList.Add (value); + } + + public static U GetOrAdd (this Dictionary dict, T key, Func createValue) where T : notnull + { + if (dict.TryGetValue (key, out var value)) { + return value; + } + U val = createValue (key); + dict.Add (key, val); + return val; + } } } From 2d12aded8498778740feed3800a429594c3cd3fa Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 19 Apr 2024 20:00:24 -0700 Subject: [PATCH 06/28] Rename MarkTypeImpl to ProcessType and clean up code --- .../src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs | 2 +- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 7 +++---- .../illink/src/linker/Linker/MethodReferenceExtensions.cs | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs index 06e11dc153e552..972720ba2f1e75 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs @@ -72,7 +72,7 @@ public TypeDefinitionDependencyNode (TypeDefinition type, DependencyInfo reason, protected override void OnMarked (MarkStepNodeFactory context) { using MarkScopeStack.LocalScope? localScope = origin.HasValue ? context.MarkStep.ScopeStack.PushLocalScope (origin.Value) : null; - context.MarkStep.MarkTypeImpl (type, reason, origin); + context.MarkStep.ProcessType (type, reason, origin); } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 16ef66ac998786..0712f98a77a507 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -558,6 +558,7 @@ bool ProcessPrimaryQueue () ProcessPendingBodies (); DoAdditionalProcessing (); } + ProcessVirtualMethods (); return true; } @@ -630,9 +631,7 @@ void ProcessPendingTypeChecks () void ProcessQueue () { while (!QueueIsEmpty ()) { - _methods.Clear (); - //(MethodDefinition method, DependencyInfo reason, MessageOrigin origin) = _methods.Dequeue (); - //ProcessMethod (method, reason, origin); + (MethodDefinition _, DependencyInfo _, MessageOrigin _) = _methods.Dequeue (); } } @@ -2063,7 +2062,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in MarkStaticConstructor (type, reason, origin); } - protected internal virtual void MarkTypeImpl (TypeDefinition type, DependencyInfo reason, MessageOrigin? origin = null) + protected internal virtual void ProcessType (TypeDefinition type, DependencyInfo reason, MessageOrigin? origin = null) { if (type.Scope is ModuleDefinition module) MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); diff --git a/src/tools/illink/src/linker/Linker/MethodReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/MethodReferenceExtensions.cs index 4240d3277a0028..80eaf1640fa724 100644 --- a/src/tools/illink/src/linker/Linker/MethodReferenceExtensions.cs +++ b/src/tools/illink/src/linker/Linker/MethodReferenceExtensions.cs @@ -23,7 +23,7 @@ public static string GetDisplayName (this MethodReference method) string name = methodDefinition.IsSetter ? string.Concat (methodDefinition.Name.AsSpan (4), ".set") : string.Concat (methodDefinition.Name.AsSpan (4), ".get"); sb.Append (name); // Insert declaring type name and namespace - sb.Insert (0, '.').Insert (0, method.DeclaringType.GetDisplayName ()); + sb.Insert (0, '.').Insert (0, methodDefinition.DeclaringType.GetDisplayName ()); return sb.ToString (); } @@ -37,7 +37,7 @@ public static string GetDisplayName (this MethodReference method) }; sb.Append (name); // Insert declaring type name and namespace - sb.Insert (0, '.').Insert (0, method.DeclaringType.GetDisplayName ()); + sb.Insert (0, '.').Insert (0, methodDefinition.DeclaringType.GetDisplayName ()); return sb.ToString (); } From 1dc80db0b19291425b31592fa27149450dc0aac5 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 19 Apr 2024 20:09:56 -0700 Subject: [PATCH 07/28] Clean up code a bit more --- .../MarkStep.MethodDefinitionDependencyNode.cs | 9 ++++++--- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 6 ++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs index 997e896a79bc2f..1d21ca8648a778 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs @@ -39,13 +39,16 @@ namespace Mono.Linker.Steps public partial class MarkStep { - public class PostPoneMethodMarkingNode : DependencyNodeCore + /// + /// A dummy node to postpone processing of a method in the current call stack. The analyzer will process the MethodDefinitionNode dependency later. + /// + public class PostPoneMethodProcessingNode : DependencyNodeCore { readonly MethodDefinition method; readonly DependencyInfo reason; readonly MessageOrigin origin; - public PostPoneMethodMarkingNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + public PostPoneMethodProcessingNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) { this.method = method; this.reason = reason; @@ -62,7 +65,7 @@ public PostPoneMethodMarkingNode (MethodDefinition method, DependencyInfo reason public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) { - yield return new DependencyListEntry(context.MarkStep.GetMethodDefinitionNode (method, reason, origin), "Needed"); + yield return new DependencyListEntry(context.MarkStep.GetMethodDefinitionNode (method, reason, origin), "Needed by dummy node"); } public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 0712f98a77a507..8f74bda4da60ce 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -630,9 +630,7 @@ void ProcessPendingTypeChecks () void ProcessQueue () { - while (!QueueIsEmpty ()) { - (MethodDefinition _, DependencyInfo _, MessageOrigin _) = _methods.Dequeue (); - } + _methods.Clear(); } bool QueueIsEmpty () @@ -3063,7 +3061,7 @@ 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)) EnqueueMethod (method, reason, origin); - _analyzer.AddRoot (new PostPoneMethodMarkingNode (method, reason, origin), "Method marked"); + _analyzer.AddRoot (new PostPoneMethodProcessingNode (method, reason, origin), "Method marked"); return method; From 991f7a0b40496dbc515a0bbac7793dcd5114c0ca Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 12:07:33 -0700 Subject: [PATCH 08/28] Use ProjectReference for DAF, and undo method moves --- ...ompiler.DependencyAnalysisFramework.csproj | 2 + .../MarkStep.TypeDependencyNode.cs | 1 - ...Step.TypeIsRelevantToVariantCastingNode.cs | 1 - .../src/linker/Linker.Steps/MarkStep.cs | 187 +++++++++--------- .../src/linker/Linker/DictionaryExtensions.cs | 10 - .../Linker/MethodReferenceExtensions.cs | 4 +- .../illink/src/linker/Mono.Linker.csproj | 66 +------ 7 files changed, 96 insertions(+), 175 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj index 28aa33b5afe733..46312c6189665c 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj @@ -8,6 +8,8 @@ x64;x86 AnyCPU false + + <_RequiresLiveILLink>false + $(NoWarn);CS8002 $(TargetsForTfmSpecificContentInPackage);_AddReferenceAssemblyToPackage $(DefineConstants);ILLINK @@ -82,69 +84,7 @@ - - DependencyAnalysisFramework\ComputedStaticDependencyNode.cs - - - DependencyAnalysisFramework\DependencyAnalyzer.cs - - - DependencyAnalysisFramework\DependencyAnalyzerBase.cs - - - DependencyAnalysisFramework\DependencyNode.cs - - - DependencyAnalysisFramework\DependencyNodeCore.cs - - - DependencyAnalysisFramework\DgmlWriter.cs - - - DependencyAnalysisFramework\EventSourceLogStrategy.cs - - - DependencyAnalysisFramework\FirstMarkLogStrategy.cs - - - DependencyAnalysisFramework\FullGraphLogStrategy.cs - - - DependencyAnalysisFramework\IDependencyAnalyzerLogEdgeVisitor.cs - - - DependencyAnalysisFramework\IDependencyAnalyzerLogNodeVisitor.cs - - - DependencyAnalysisFramework\IDependencyAnalysisMarkStrategy.cs - - - DependencyAnalysisFramework\IDependencyNode.cs - - - DependencyAnalysisFramework\NoLogStrategy.cs - - - DependencyAnalysisFramework\PerfEventSource.cs - - - DependencyAnalysisFramework\Sorting\ArrayAccessor.cs - - - DependencyAnalysisFramework\Sorting\ICompareAsEqualAction.cs - - - DependencyAnalysisFramework\Sorting\ISortableDataStructureAccessor.cs - - - DependencyAnalysisFramework\Sorting\ListAccessor.cs - - - DependencyAnalysisFramework\Sorting\MergeSort.cs - - - DependencyAnalysisFramework\Sorting\MergeSortCore.cs - + From c1670ebf66a003b012207d447309c82916a2de59 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 14:43:56 -0700 Subject: [PATCH 09/28] Don't have additional virtualmethods processing --- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 1 - 1 file changed, 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 04ec4c2058c13f..4bed7304c0a159 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -475,7 +475,6 @@ bool ProcessPrimaryQueue () ProcessPendingBodies (); DoAdditionalProcessing (); } - ProcessVirtualMethods (); return true; } From 5bf5ece1e8682e64714876f43a32534ece8ad89b Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:34:34 -0700 Subject: [PATCH 10/28] Remove old header comment copied from MarkStep --- .../MarkStep.MarkStepNodeFactory.cs | 29 ------------------- ...MarkStep.MethodDefinitionDependencyNode.cs | 29 ------------------- .../MarkStep.ProcessCallbackDependencyNode.cs | 29 ------------------- .../MarkStep.TypeDependencyNode.cs | 29 ------------------- ...Step.TypeIsRelevantToVariantCastingNode.cs | 29 ------------------- .../src/linker/Linker.Steps/MarkStep.cs | 6 ++-- 6 files changed, 3 insertions(+), 148 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs index e841eb587a1c42..6af205a9a177e7 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs @@ -1,35 +1,6 @@ // 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. -// -// MarkStep.cs -// -// Author: -// Jb Evain (jbevain@gmail.com) -// -// (C) 2006 Jb Evain -// (C) 2007 Novell, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - namespace Mono.Linker.Steps { diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs index 1d21ca8648a778..a67156f7c2f97c 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs @@ -1,35 +1,6 @@ // 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. -// -// MarkStep.cs -// -// Author: -// Jb Evain (jbevain@gmail.com) -// -// (C) 2006 Jb Evain -// (C) 2007 Novell, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - using System.Collections.Generic; using ILCompiler.DependencyAnalysisFramework; using Mono.Cecil; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs index ff233207f7bc67..0e8e321705abf2 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs @@ -1,35 +1,6 @@ // 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. -// -// MarkStep.cs -// -// Author: -// Jb Evain (jbevain@gmail.com) -// -// (C) 2006 Jb Evain -// (C) 2007 Novell, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - using System; using System.Collections.Generic; using ILCompiler.DependencyAnalysisFramework; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs index ac0c24b189cfcf..7a2f2f92c95454 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs @@ -1,35 +1,6 @@ // 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. -// -// MarkStep.cs -// -// Author: -// Jb Evain (jbevain@gmail.com) -// -// (C) 2006 Jb Evain -// (C) 2007 Novell, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - using System.Collections.Generic; using ILCompiler.DependencyAnalysisFramework; using Mono.Cecil; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs index 758214e41f63f4..049b48b9192176 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs @@ -1,35 +1,6 @@ // 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. -// -// MarkStep.cs -// -// Author: -// Jb Evain (jbevain@gmail.com) -// -// (C) 2006 Jb Evain -// (C) 2007 Novell, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - using System.Collections.Generic; using ILCompiler.DependencyAnalysisFramework; using Mono.Cecil; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index f53f776300cc01..19d47311a6d754 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -75,6 +75,9 @@ protected LinkContext Context { // Stores, for compiler-generated methods only, whether they require the reflection // method body scanner. readonly Dictionary _compilerGeneratedMethodRequiresScanner; + private readonly Dictionary _typeNodes = new (); + private readonly Dictionary _methodNodes = new (); + private readonly Dictionary _typeIsRelevantToVariantCastingNodes = new (); MarkStepContext? _markContext; MarkStepContext MarkContext { @@ -397,19 +400,16 @@ bool ProcessAllPendingItems () MarkFullyPreservedAssemblies (); } - private readonly Dictionary _typeNodes = new (); public TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) { return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionDependencyNode (k, reason, origin)); } - private readonly Dictionary _methodNodes = new (); public MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) { return _methodNodes.GetOrAdd (method, (k) => new MethodDefinitionDependencyNode (k, reason, origin)); } - private readonly Dictionary _typeIsRelevantToVariantCastingNodes = new (); TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNode (TypeDefinition type) { return _typeIsRelevantToVariantCastingNodes.GetOrAdd (type, static (t) => new TypeIsRelevantToVariantCastingNode (t)); From e6edbce536a71acb25b6482f5c4793a655587e9a Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:41:15 -0700 Subject: [PATCH 11/28] Remove nullable directives from ilc files --- src/coreclr/tools/Common/Sorting/ArrayAccessor.cs | 2 -- src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs | 2 -- .../tools/Common/Sorting/ISortableDataStructureAccessor.cs | 2 -- src/coreclr/tools/Common/Sorting/ListAccessor.cs | 2 -- src/coreclr/tools/Common/Sorting/MergeSort.cs | 2 -- src/coreclr/tools/Common/Sorting/MergeSortCore.cs | 2 -- .../ComputedStaticDependencyNode.cs | 2 -- .../DependencyAnalyzer.cs | 2 -- .../DependencyAnalyzerBase.cs | 2 -- .../ILCompiler.DependencyAnalysisFramework/DependencyNode.cs | 2 -- .../DependencyNodeCore.cs | 2 -- .../aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs | 2 -- .../EventSourceLogStrategy.cs | 2 -- .../FirstMarkLogStrategy.cs | 2 -- .../FullGraphLogStrategy.cs | 2 -- .../IDependencyAnalysisMarkStrategy.cs | 2 -- .../IDependencyAnalyzerLogEdgeVisitor.cs | 2 -- .../IDependencyAnalyzerLogNodeVisitor.cs | 2 -- .../ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs | 2 -- .../aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs | 2 -- .../ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs | 2 -- 21 files changed, 42 deletions(-) diff --git a/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs b/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs index ac9dbe395d489c..2c73dc16bff72b 100644 --- a/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs +++ b/src/coreclr/tools/Common/Sorting/ArrayAccessor.cs @@ -3,8 +3,6 @@ using System; -#nullable disable - namespace ILCompiler.Sorting.Implementation { internal struct ArrayAccessor : ISortableDataStructureAccessor diff --git a/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs b/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs index ca9accc71fdc8e..09fe5716b4fcc1 100644 --- a/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs +++ b/src/coreclr/tools/Common/Sorting/ICompareAsEqualAction.cs @@ -3,8 +3,6 @@ using System.Diagnostics; -#nullable disable - namespace ILCompiler { internal interface ICompareAsEqualAction diff --git a/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs b/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs index ec0319f562efc6..c2ec9f24b84f96 100644 --- a/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs +++ b/src/coreclr/tools/Common/Sorting/ISortableDataStructureAccessor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - namespace ILCompiler { internal interface ISortableDataStructureAccessor diff --git a/src/coreclr/tools/Common/Sorting/ListAccessor.cs b/src/coreclr/tools/Common/Sorting/ListAccessor.cs index 27c78e92182f79..f26f1ff5acaa8b 100644 --- a/src/coreclr/tools/Common/Sorting/ListAccessor.cs +++ b/src/coreclr/tools/Common/Sorting/ListAccessor.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; -#nullable disable - namespace ILCompiler.Sorting.Implementation { internal struct ListAccessor : ISortableDataStructureAccessor> diff --git a/src/coreclr/tools/Common/Sorting/MergeSort.cs b/src/coreclr/tools/Common/Sorting/MergeSort.cs index 35768d444c931a..7faf01aeafb5b8 100644 --- a/src/coreclr/tools/Common/Sorting/MergeSort.cs +++ b/src/coreclr/tools/Common/Sorting/MergeSort.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using ILCompiler.Sorting.Implementation; -#nullable disable - namespace ILCompiler { public static class MergeSortApi diff --git a/src/coreclr/tools/Common/Sorting/MergeSortCore.cs b/src/coreclr/tools/Common/Sorting/MergeSortCore.cs index 29070c5d5078a3..5b054eedb0157c 100644 --- a/src/coreclr/tools/Common/Sorting/MergeSortCore.cs +++ b/src/coreclr/tools/Common/Sorting/MergeSortCore.cs @@ -4,8 +4,6 @@ using System.Collections.Generic; using System.Threading.Tasks; -#nullable disable - namespace ILCompiler.Sorting.Implementation { internal static class MergeSortCore diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs index 6a7a0717078285..8e043a74a3916f 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ComputedStaticDependencyNode.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public abstract class ComputedStaticDependencyNode : DependencyNodeCore diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs index 58f78290e72fb3..e7f7503bb7d7db 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzer.cs @@ -6,8 +6,6 @@ using System.Collections.Immutable; using System.Diagnostics; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { /// diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs index f4a11e8f3023ba..38d3e7c7023586 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyAnalyzerBase.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { /// diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs index dac07277eea106..d8913b8022c48d 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNode.cs @@ -3,8 +3,6 @@ using System.Diagnostics; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public abstract class DependencyNode : IDependencyNode diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs index 5a991bcf87044d..0f8ed436ed4ffe 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DependencyNodeCore.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public abstract class DependencyNodeCore : DependencyNode, IDependencyNode diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs index 4bb0b9dcca0341..a0570393335955 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/DgmlWriter.cs @@ -7,8 +7,6 @@ using System.IO; using System.Diagnostics; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public class DgmlWriter diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs index e917d1136a48d6..a5f70a0fa0bcf2 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/EventSourceLogStrategy.cs @@ -7,8 +7,6 @@ using System.Diagnostics.Tracing; using System.Runtime.InteropServices; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { [EventSource(Name = "Microsoft-ILCompiler-DependencyGraph")] diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs index c2fbc5e3dafa4d..655fb43a35c1cf 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FirstMarkLogStrategy.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public struct FirstMarkLogStrategy : IDependencyAnalysisMarkStrategy diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs index aa02ae16a90998..4847782fd3f78f 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/FullGraphLogStrategy.cs @@ -5,8 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public struct FullGraphLogStrategy : IDependencyAnalysisMarkStrategy diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs index 86308a997a54ea..23b4384ea64677 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalysisMarkStrategy.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyAnalysisMarkStrategy diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs index fa2b0ff61069f8..4c55ba328b4e03 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogEdgeVisitor.cs @@ -1,8 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyAnalyzerLogEdgeVisitor diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs index d8fc79a39be579..9d3b027a81b18d 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyAnalyzerLogNodeVisitor.cs @@ -3,8 +3,6 @@ using System; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyAnalyzerLogNodeVisitor diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs index fe865e36f668fe..76365d9c68bc59 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/IDependencyNode.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { public interface IDependencyNode diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs index 8aa4b8b03ac583..fefb9dbad8916b 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/NoLogStrategy.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; -#nullable disable - namespace ILCompiler.DependencyAnalysisFramework { /// diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs index 1ff01e9227d97d..2c0d474c94afdf 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/PerfEventSource.cs @@ -4,8 +4,6 @@ using System; using System.Diagnostics.Tracing; -#nullable disable - /// /// Performance events specific to the dependency graph. /// From 10a5c5779f197a7ff9c919d41c98b033a00bea52 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:04:17 -0700 Subject: [PATCH 12/28] Sign DAF instead of nowarn on trimmer --- .../ILCompiler.DependencyAnalysisFramework.csproj | 2 ++ src/tools/illink/src/linker/Mono.Linker.csproj | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj index 46312c6189665c..27493074532da1 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj @@ -10,6 +10,8 @@ false <_RequiresLiveILLink>false + + true - $(NoWarn);CS8002 $(TargetsForTfmSpecificContentInPackage);_AddReferenceAssemblyToPackage $(DefineConstants);ILLINK From 166d2d530fe297ba89cf04deb27ed8cac2416b8a Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 16:51:34 -0700 Subject: [PATCH 13/28] Re-add doc comment; Make types internal --- .../MarkStep.MarkStepNodeFactory.cs | 2 +- ...MarkStep.MethodDefinitionDependencyNode.cs | 2 +- .../MarkStep.TypeDependencyNode.cs | 2 +- ...Step.TypeIsRelevantToVariantCastingNode.cs | 2 +- .../src/linker/Linker.Steps/MarkStep.cs | 23 +++++++++++++++---- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs index 6af205a9a177e7..3d31f7b2e1661d 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs @@ -6,7 +6,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - public class MarkStepNodeFactory (MarkStep markStep) + internal class MarkStepNodeFactory (MarkStep markStep) { public MarkStep MarkStep { get; } = markStep; } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs index a67156f7c2f97c..a0e35f6dc7894a 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs @@ -13,7 +13,7 @@ public partial class MarkStep /// /// A dummy node to postpone processing of a method in the current call stack. The analyzer will process the MethodDefinitionNode dependency later. /// - public class PostPoneMethodProcessingNode : DependencyNodeCore + internal class PostPoneMethodProcessingNode : DependencyNodeCore { readonly MethodDefinition method; readonly DependencyInfo reason; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs index 7a2f2f92c95454..51f8ac7e9ffcf1 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - public class TypeDefinitionDependencyNode : DependencyNodeCore + internal class TypeDefinitionDependencyNode : DependencyNodeCore { readonly TypeDefinition type; readonly MessageOrigin? origin; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs index 049b48b9192176..a94bb72247cfc3 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - public class TypeIsRelevantToVariantCastingNode : DependencyNodeCore + internal class TypeIsRelevantToVariantCastingNode : DependencyNodeCore { TypeDefinition type; public TypeIsRelevantToVariantCastingNode (TypeDefinition type) => this.type = type; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 19d47311a6d754..6db691ccc8987f 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -69,6 +69,7 @@ protected LinkContext Context { protected HashSet _dynamicInterfaceCastableImplementationTypesDiscovered; protected List _dynamicInterfaceCastableImplementationTypes; protected List<(MethodBody, MarkScopeStack.Scope)> _unreachableBodies; + private bool _steadyState; readonly List<(TypeDefinition Type, MethodBody Body, Instruction Instr)> _pending_isinst_instr; @@ -464,10 +465,10 @@ bool MarkFullyPreservedAssemblies () bool ProcessPrimaryQueue () { - if (QueueIsEmpty ()) + if (ReachedSteadyState ()) return false; - while (!QueueIsEmpty ()) { + while (!ReachedSteadyState ()) { ProcessQueue (); ProcessInterfaceMethods (); ProcessMarkedTypesWithInterfaces (); @@ -549,14 +550,19 @@ void ProcessQueue () _methods.Clear (); } - bool QueueIsEmpty () + bool ReachedSteadyState () { - return _methods.Count == 0; + var oldState = _steadyState; + _steadyState = true; + return oldState; } void EnqueueMethod (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin) { - _methods.Enqueue ((method, reason, origin)); + _ = method; + _ = reason; + _ = origin; + _steadyState = false; } void ProcessInterfaceMethods () @@ -1985,6 +1991,13 @@ 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 + /// The resolved type definition if the reference can be resolved protected internal virtual TypeDefinition? MarkType (TypeReference reference, DependencyInfo reason, MessageOrigin? origin = null) { #if DEBUG From 01f3a795a9efc789039831f217bc0463fb4a9593 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 17:39:16 -0700 Subject: [PATCH 14/28] Undo Queue changes, fix visibility issues --- .../Linker.Steps/MarkStep.MarkStepNodeFactory.cs | 2 +- .../MarkStep.MethodDefinitionDependencyNode.cs | 4 ++-- .../Linker.Steps/MarkStep.TypeDependencyNode.cs | 2 +- .../MarkStep.TypeIsRelevantToVariantCastingNode.cs | 2 +- .../illink/src/linker/Linker.Steps/MarkStep.cs | 14 ++++---------- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs index 3d31f7b2e1661d..ee68fcf36a658e 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs @@ -6,7 +6,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - internal class MarkStepNodeFactory (MarkStep markStep) + internal sealed class MarkStepNodeFactory (MarkStep markStep) { public MarkStep MarkStep { get; } = markStep; } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs index a0e35f6dc7894a..1e705dcaf80cdc 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs @@ -13,7 +13,7 @@ public partial class MarkStep /// /// A dummy node to postpone processing of a method in the current call stack. The analyzer will process the MethodDefinitionNode dependency later. /// - internal class PostPoneMethodProcessingNode : DependencyNodeCore + internal sealed class PostPoneMethodProcessingNode : DependencyNodeCore { readonly MethodDefinition method; readonly DependencyInfo reason; @@ -44,7 +44,7 @@ public PostPoneMethodProcessingNode (MethodDefinition method, DependencyInfo rea protected override string GetName (MarkStepNodeFactory context) => "PostPoneMethodMarkingProxy"; } - public class MethodDefinitionDependencyNode : DependencyNodeCore + internal sealed class MethodDefinitionDependencyNode : DependencyNodeCore { readonly MethodDefinition method; readonly MessageOrigin origin; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs index 51f8ac7e9ffcf1..06e762ee40faab 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - internal class TypeDefinitionDependencyNode : DependencyNodeCore + internal sealed class TypeDefinitionDependencyNode : DependencyNodeCore { readonly TypeDefinition type; readonly MessageOrigin? origin; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs index a94bb72247cfc3..c28965b28f209e 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - internal class TypeIsRelevantToVariantCastingNode : DependencyNodeCore + internal sealed class TypeIsRelevantToVariantCastingNode : DependencyNodeCore { TypeDefinition type; public TypeIsRelevantToVariantCastingNode (TypeDefinition type) => this.type = type; diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 6db691ccc8987f..2378721e26e2ac 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -69,7 +69,6 @@ protected LinkContext Context { protected HashSet _dynamicInterfaceCastableImplementationTypesDiscovered; protected List _dynamicInterfaceCastableImplementationTypes; protected List<(MethodBody, MarkScopeStack.Scope)> _unreachableBodies; - private bool _steadyState; readonly List<(TypeDefinition Type, MethodBody Body, Instruction Instr)> _pending_isinst_instr; @@ -401,12 +400,12 @@ bool ProcessAllPendingItems () MarkFullyPreservedAssemblies (); } - public TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) + internal TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) { return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionDependencyNode (k, reason, origin)); } - public MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + internal MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) { return _methodNodes.GetOrAdd (method, (k) => new MethodDefinitionDependencyNode (k, reason, origin)); } @@ -552,17 +551,12 @@ void ProcessQueue () bool ReachedSteadyState () { - var oldState = _steadyState; - _steadyState = true; - return oldState; + return _methods.Count == 0; } void EnqueueMethod (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin) { - _ = method; - _ = reason; - _ = origin; - _steadyState = false; + _methods.Enqueue ((method, reason, origin)); } void ProcessInterfaceMethods () From 098f7bcc926ac414f4df10c664c11eaf11a2e58a Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Mon, 22 Apr 2024 21:29:31 -0700 Subject: [PATCH 15/28] Rename TypeDefinitionDependencyNode file to match class --- ...DependencyNode.cs => MarkStep.TypeDefinitionDependencyNode.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.TypeDependencyNode.cs => MarkStep.TypeDefinitionDependencyNode.cs} (100%) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionDependencyNode.cs similarity index 100% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDependencyNode.cs rename to src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionDependencyNode.cs From 25ec8ceeb1ae4ba3f90040e2cb973245c73ca8c8 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Tue, 23 Apr 2024 11:02:48 -0700 Subject: [PATCH 16/28] PR feedback: - Remove PostPone node and call ProcessMethod in GetStaticDependencies - Move node creation methods to MarkStepNodeFactory --- .../MarkStep.MarkStepNodeFactory.cs | 53 ++++++++++++++++++- ...MarkStep.MethodDefinitionDependencyNode.cs | 44 ++------------- .../src/linker/Linker.Steps/MarkStep.cs | 30 +++-------- 3 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs index ee68fcf36a658e..549db071714446 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs @@ -1,14 +1,65 @@ // 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.Concurrent; +using System.Collections.Generic; +using Mono.Cecil; + namespace Mono.Linker.Steps { - public partial class MarkStep { internal sealed class MarkStepNodeFactory (MarkStep markStep) { public MarkStep MarkStep { get; } = markStep; + readonly NodeCache _typeNodes = new (static _ => throw new InvalidOperationException ("Creation of node requires more than the key.")); + 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)); + + internal TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) + { + return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionDependencyNode (k, reason, origin)); + } + + internal MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + { + return _methodNodes.GetOrAdd (method, (k) => new MethodDefinitionDependencyNode (k, reason, origin)); + } + + internal TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNode (TypeDefinition type) + { + return _typeIsRelevantToVariantCastingNodes.GetOrAdd (type); + } + + struct NodeCache where TKey : notnull + { + // Change to concurrent dictionary if/when multithreaded marking is enabled + readonly Dictionary _cache; + readonly Func _creator; + + public NodeCache (Func creator, IEqualityComparer comparer) + { + _creator = creator; + _cache = new (comparer); + } + + public NodeCache (Func creator) + { + _creator = creator; + _cache = new (); + } + + public TValue GetOrAdd (TKey key) + { + return _cache.GetOrAdd (key, _creator); + } + + public TValue GetOrAdd (TKey key, Func creator) + { + return _cache.GetOrAdd (key, creator); + } + } } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs index 1e705dcaf80cdc..925fb908243026 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs @@ -1,49 +1,15 @@ // 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 ILCompiler.DependencyAnalysisFramework; using Mono.Cecil; namespace Mono.Linker.Steps { - public partial class MarkStep { - /// - /// A dummy node to postpone processing of a method in the current call stack. The analyzer will process the MethodDefinitionNode dependency later. - /// - internal sealed class PostPoneMethodProcessingNode : DependencyNodeCore - { - readonly MethodDefinition method; - readonly DependencyInfo reason; - readonly MessageOrigin origin; - - public PostPoneMethodProcessingNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) - { - this.method = method; - this.reason = reason; - this.origin = origin; - } - - public override bool InterestingForDynamicDependencyAnalysis => false; - - public override bool HasDynamicDependencies => false; - - public override bool HasConditionalStaticDependencies => false; - - public override bool StaticDependenciesAreComputed => true; - - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) - { - yield return new DependencyListEntry(context.MarkStep.GetMethodDefinitionNode (method, reason, origin), "Needed by dummy node"); - } - - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "PostPoneMethodMarkingProxy"; - } - internal sealed class MethodDefinitionDependencyNode : DependencyNodeCore { readonly MethodDefinition method; @@ -67,17 +33,13 @@ public MethodDefinitionDependencyNode (MethodDefinition method, DependencyInfo r public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) { - // Add other types that are marked in MarkType - yield break; + context.MarkStep.ProcessMethod (method, reason, origin); + return null; } public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; protected override string GetName (MarkStepNodeFactory context) => "MethodDefinition"; - protected override void OnMarked (MarkStepNodeFactory context) - { - context.MarkStep.ProcessMethod (method, reason, origin); - } } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 2378721e26e2ac..421131c6e454da 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -75,9 +75,8 @@ protected LinkContext Context { // Stores, for compiler-generated methods only, whether they require the reflection // method body scanner. readonly Dictionary _compilerGeneratedMethodRequiresScanner; - private readonly Dictionary _typeNodes = new (); - private readonly Dictionary _methodNodes = new (); - private readonly Dictionary _typeIsRelevantToVariantCastingNodes = new (); + private readonly MarkStepNodeFactory _nodeFactory; + private readonly DependencyAnalyzer, MarkStepNodeFactory> _analyzer; MarkStepContext? _markContext; MarkStepContext MarkContext { @@ -234,7 +233,8 @@ public MarkStep () _pending_isinst_instr = new List<(TypeDefinition, MethodBody, Instruction)> (); _entireTypesMarked = new HashSet (); _compilerGeneratedMethodRequiresScanner = new Dictionary (); - _analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (new MarkStepNodeFactory (this), null); + _nodeFactory = new MarkStepNodeFactory (this); + _analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (_nodeFactory, null); } public AnnotationStore Annotations => Context.Annotations; @@ -378,7 +378,6 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason) } } - DependencyAnalyzer, MarkStepNodeFactory> _analyzer; void Process () { _analyzer.ComputeDependencyRoutine += (List> nodes) => { @@ -400,21 +399,6 @@ bool ProcessAllPendingItems () MarkFullyPreservedAssemblies (); } - internal TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) - { - return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionDependencyNode (k, reason, origin)); - } - - internal MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) - { - return _methodNodes.GetOrAdd (method, (k) => new MethodDefinitionDependencyNode (k, reason, origin)); - } - - TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNode (TypeDefinition type) - { - return _typeIsRelevantToVariantCastingNodes.GetOrAdd (type, static (t) => new TypeIsRelevantToVariantCastingNode (t)); - } - static bool IsFullyPreservedAction (AssemblyAction action) => action == AssemblyAction.Copy || action == AssemblyAction.Save; bool MarkFullyPreservedAssemblies () @@ -2044,7 +2028,7 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in if (CheckProcessed (type)) return type; - _analyzer.AddRoot (GetTypeNode (type, reason, origin), "MarkedType"); + _analyzer.AddRoot (_nodeFactory.GetTypeNode (type, reason, origin), Enum.GetName(reason.Kind)); return type; } @@ -2813,7 +2797,7 @@ void MarkGenericArguments (IGenericInstance instance) if (argumentTypeDef == null) continue; - _analyzer.AddRoot (GetTypeIsRelevantToVariantCastingNode (argumentTypeDef), "Generic Argument"); + _analyzer.AddRoot (_nodeFactory.GetTypeIsRelevantToVariantCastingNode (argumentTypeDef), "Generic Argument"); if (parameter.HasDefaultConstructorConstraint) MarkDefaultConstructor (argumentTypeDef, new DependencyInfo (DependencyKind.DefaultCtorForNewConstrainedGenericArgument, instance)); @@ -3067,7 +3051,7 @@ 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)) EnqueueMethod (method, reason, origin); - _analyzer.AddRoot (new PostPoneMethodProcessingNode (method, reason, origin), "Method marked"); + _analyzer.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason, origin), Enum.GetName(reason.Kind)); return method; } From 9ef134343615e09c93be77a1f1c2aabbc8a0bd00 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:13:30 -0700 Subject: [PATCH 17/28] PR Feedback: - Remove extra properties in project file - Move usages of MessageOrigin from ProcessMethod to MarkMethod - Remove MessageOrigin from MethodDefinitionNode - Move all usages of MessageOrigin and DependencyInfo from ProcessMethod to MarkMethod - Remove MessageOrigin and Reason from TypeDefinitionNode - Remove extra ScopeStack pushes and pops --- .../src/linker/Linker.Steps/MarkScopeStack.cs | 5 -- ...de.cs => MarkStep.MethodDefinitionNode.cs} | 16 +++--- ...NodeFactory.cs => MarkStep.NodeFactory.cs} | 14 +++--- ...ode.cs => MarkStep.ProcessCallbackNode.cs} | 14 +++--- .../MarkStep.TypeDefinitionDependencyNode.cs | 49 ------------------- .../MarkStep.TypeDefinitionNode.cs | 41 ++++++++++++++++ ...Step.TypeIsRelevantToVariantCastingNode.cs | 12 ++--- .../src/linker/Linker.Steps/MarkStep.cs | 41 ++++++++-------- .../illink/src/linker/Mono.Linker.csproj | 7 +-- 9 files changed, 90 insertions(+), 109 deletions(-) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.MethodDefinitionDependencyNode.cs => MarkStep.MethodDefinitionNode.cs} (59%) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.MarkStepNodeFactory.cs => MarkStep.NodeFactory.cs} (67%) rename src/tools/illink/src/linker/Linker.Steps/{MarkStep.ProcessCallbackDependencyNode.cs => MarkStep.ProcessCallbackNode.cs} (60%) delete mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionDependencyNode.cs create mode 100644 src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkScopeStack.cs b/src/tools/illink/src/linker/Linker.Steps/MarkScopeStack.cs index ab1ad448754fcc..6b5add70314cdb 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkScopeStack.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkScopeStack.cs @@ -88,11 +88,6 @@ internal LocalScope PushLocalScope (in Scope scope) return new LocalScope (scope, this); } - internal ParentScope PopToParentScope () - { - return new ParentScope (this); - } - public IDisposable PushScope (in MessageOrigin origin) { return new LocalScope (origin, this); diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionNode.cs similarity index 59% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs rename to src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionNode.cs index 925fb908243026..34dd6e8a8d03e4 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.MethodDefinitionNode.cs @@ -10,16 +10,14 @@ namespace Mono.Linker.Steps { public partial class MarkStep { - internal sealed class MethodDefinitionDependencyNode : DependencyNodeCore + internal sealed class MethodDefinitionNode : DependencyNodeCore { readonly MethodDefinition method; - readonly MessageOrigin origin; readonly DependencyInfo reason; - public MethodDefinitionDependencyNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + public MethodDefinitionNode (MethodDefinition method, DependencyInfo reason) { this.method = method; - this.origin = origin; this.reason = reason; } @@ -31,15 +29,15 @@ public MethodDefinitionDependencyNode (MethodDefinition method, DependencyInfo r public override bool StaticDependenciesAreComputed => true; - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) + public override IEnumerable? GetStaticDependencies (NodeFactory context) { - context.MarkStep.ProcessMethod (method, reason, origin); + context.MarkStep.ProcessMethod (method, reason); return null; } - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "MethodDefinition"; + 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(); } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs similarity index 67% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs rename to src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs index 549db071714446..347124328d29ad 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.MarkStepNodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs @@ -10,21 +10,21 @@ namespace Mono.Linker.Steps { public partial class MarkStep { - internal sealed class MarkStepNodeFactory (MarkStep markStep) + internal sealed class NodeFactory (MarkStep markStep) { public MarkStep MarkStep { get; } = markStep; - readonly NodeCache _typeNodes = new (static _ => throw new InvalidOperationException ("Creation of node requires more than the key.")); - readonly NodeCache _methodNodes = new (static _ => throw new InvalidOperationException ("Creation of node requires more than the key.")); + readonly NodeCache _typeNodes = new (static _ => throw new InvalidOperationException ("Creation of node requires more than the key.")); + 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)); - internal TypeDefinitionDependencyNode GetTypeNode (TypeDefinition reference, DependencyInfo reason, MessageOrigin? origin) + internal TypeDefinitionNode GetTypeNode (TypeDefinition reference) { - return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionDependencyNode (k, reason, origin)); + return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionNode (k)); } - internal MethodDefinitionDependencyNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) + internal MethodDefinitionNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason) { - return _methodNodes.GetOrAdd (method, (k) => new MethodDefinitionDependencyNode (k, reason, origin)); + return _methodNodes.GetOrAdd (method, (k) => new MethodDefinitionNode (k, reason)); } internal TypeIsRelevantToVariantCastingNode GetTypeIsRelevantToVariantCastingNode (TypeDefinition type) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs similarity index 60% rename from src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs rename to src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs index 0e8e321705abf2..aae8e2193487cb 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackDependencyNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs @@ -10,18 +10,18 @@ namespace Mono.Linker.Steps public partial class MarkStep { - sealed class ProcessCallbackDependencyNode : DependencyNodeCore + sealed class ProcessCallbackNode : DependencyNodeCore { Func _processAction; DependencyList? _dependencies; - public ProcessCallbackDependencyNode (Func action) => _processAction = action; + public ProcessCallbackNode (Func action) => _processAction = action; public void Process () { _dependencies = new DependencyList (); if (_processAction ()) { - _dependencies.Add (new ProcessCallbackDependencyNode (_processAction), "Some processing was done, continuation required"); + _dependencies.Add (new ProcessCallbackNode (_processAction), "Some processing was done, continuation required"); } } @@ -33,11 +33,11 @@ public void Process () public override bool StaticDependenciesAreComputed => _dependencies != null; - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) => _dependencies; + public override IEnumerable? GetStaticDependencies (NodeFactory context) => _dependencies; - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "Process"; + public override IEnumerable? GetConditionalStaticDependencies (NodeFactory context) => null; + public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, NodeFactory context) => null; + protected override string GetName (NodeFactory context) => "Process"; } } } diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionDependencyNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionDependencyNode.cs deleted file mode 100644 index 06e762ee40faab..00000000000000 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionDependencyNode.cs +++ /dev/null @@ -1,49 +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; -using Mono.Cecil; - -namespace Mono.Linker.Steps -{ - - public partial class MarkStep - { - internal sealed class TypeDefinitionDependencyNode : DependencyNodeCore - { - readonly TypeDefinition type; - readonly MessageOrigin? origin; - readonly DependencyInfo reason; - - public TypeDefinitionDependencyNode (TypeDefinition type, DependencyInfo reason, MessageOrigin? origin) - { - this.type = type; - this.origin = origin; - this.reason = reason; - } - - public override bool InterestingForDynamicDependencyAnalysis => false; - - public override bool HasDynamicDependencies => false; - - public override bool HasConditionalStaticDependencies => false; - - public override bool StaticDependenciesAreComputed => true; - - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) - { - yield break; - } - - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "TypeNode"; - protected override void OnMarked (MarkStepNodeFactory context) - { - using MarkScopeStack.LocalScope? localScope = origin.HasValue ? context.MarkStep.ScopeStack.PushLocalScope (origin.Value) : null; - context.MarkStep.ProcessType (type, reason, origin); - } - } - } -} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs new file mode 100644 index 00000000000000..dc33c026beb8a4 --- /dev/null +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs @@ -0,0 +1,41 @@ +// 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; +using Mono.Cecil; + +namespace Mono.Linker.Steps +{ + + public partial class MarkStep + { + internal sealed class TypeDefinitionNode : DependencyNodeCore + { + readonly TypeDefinition type; + + public TypeDefinitionNode (TypeDefinition type) + { + this.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? GetStaticDependencies (NodeFactory context) + { + context.MarkStep.ProcessType (type); + 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) => type.GetDisplayName(); + } + } +} diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs index c28965b28f209e..127f65c8731c26 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs @@ -10,7 +10,7 @@ namespace Mono.Linker.Steps public partial class MarkStep { - internal sealed class TypeIsRelevantToVariantCastingNode : DependencyNodeCore + internal sealed class TypeIsRelevantToVariantCastingNode : DependencyNodeCore { TypeDefinition type; public TypeIsRelevantToVariantCastingNode (TypeDefinition type) => this.type = type; @@ -23,15 +23,15 @@ internal sealed class TypeIsRelevantToVariantCastingNode : DependencyNodeCore true; - public override IEnumerable? GetStaticDependencies (MarkStepNodeFactory context) + public override IEnumerable? GetStaticDependencies (NodeFactory context) { yield break; } - public override IEnumerable? GetConditionalStaticDependencies (MarkStepNodeFactory context) => null; - public override IEnumerable? SearchDynamicDependencies (List> markedNodes, int firstNode, MarkStepNodeFactory context) => null; - protected override string GetName (MarkStepNodeFactory context) => "TypeIsRelevantToVariantCasting"; - protected override void OnMarked (MarkStepNodeFactory context) + 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()} 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 421131c6e454da..1f2651157f77b4 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -75,8 +75,8 @@ protected LinkContext Context { // Stores, for compiler-generated methods only, whether they require the reflection // method body scanner. readonly Dictionary _compilerGeneratedMethodRequiresScanner; - private readonly MarkStepNodeFactory _nodeFactory; - private readonly DependencyAnalyzer, MarkStepNodeFactory> _analyzer; + private readonly NodeFactory _nodeFactory; + private readonly DependencyAnalyzer, NodeFactory> _analyzer; MarkStepContext? _markContext; MarkStepContext MarkContext { @@ -233,8 +233,8 @@ public MarkStep () _pending_isinst_instr = new List<(TypeDefinition, MethodBody, Instruction)> (); _entireTypesMarked = new HashSet (); _compilerGeneratedMethodRequiresScanner = new Dictionary (); - _nodeFactory = new MarkStepNodeFactory (this); - _analyzer = new DependencyAnalyzer, MarkStepNodeFactory> (_nodeFactory, null); + _nodeFactory = new NodeFactory (this); + _analyzer = new DependencyAnalyzer, NodeFactory> (_nodeFactory, null); } public AnnotationStore Annotations => Context.Annotations; @@ -380,13 +380,13 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason) void Process () { - _analyzer.ComputeDependencyRoutine += (List> nodes) => { - foreach (DependencyNodeCore node in nodes) { - if (node is ProcessCallbackDependencyNode processNode) + _analyzer.ComputeDependencyRoutine += (List> nodes) => { + foreach (DependencyNodeCore node in nodes) { + if (node is ProcessCallbackNode processNode) processNode.Process (); } }; - _analyzer.AddRoot (new ProcessCallbackDependencyNode (ProcessAllPendingItems), "start"); + _analyzer.AddRoot (new ProcessCallbackNode (ProcessAllPendingItems), "start"); _analyzer.ComputeMarkedNodes (); ProcessPendingTypeChecks (); @@ -2028,15 +2028,21 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in if (CheckProcessed (type)) return type; - _analyzer.AddRoot (_nodeFactory.GetTypeNode (type, reason, origin), Enum.GetName(reason.Kind)); - return type; - } + if (type.HasMethods) { + if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { + MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin); + } + } - protected internal virtual void ProcessType (TypeDefinition type, DependencyInfo reason, MessageOrigin? origin = null) - { if (type.Scope is ModuleDefinition module) MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); + _analyzer.AddRoot (_nodeFactory.GetTypeNode (type), Enum.GetName(reason.Kind)); + return type; + } + + protected internal virtual void ProcessType (TypeDefinition type) + { using var typeScope = ScopeStack.PushLocalScope (new MessageOrigin (type)); foreach (Action handleMarkType in MarkContext.MarkTypeActions) @@ -2124,10 +2130,6 @@ protected internal virtual void ProcessType (TypeDefinition type, DependencyInfo MarkMethod (method, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type), ScopeStack.CurrentScope.Origin); } } - if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { - using (ScopeStack.PopToParentScope ()) - MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin); - } } DoAdditionalTypeProcessing (type); @@ -3051,7 +3053,7 @@ 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)) EnqueueMethod (method, reason, origin); - _analyzer.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason, origin), Enum.GetName(reason.Kind)); + _analyzer.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason), Enum.GetName(reason.Kind)); return method; } @@ -3182,14 +3184,13 @@ internal static void ReportRequiresUnreferencedCode (string displayName, Require return (method, reason); } - protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin) + protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo reason) { #if DEBUG if (!_methodReasons.Contains (reason.Kind)) throw new InternalErrorException ($"Unsupported method dependency {reason.Kind}"); #endif ScopeStack.AssertIsEmpty (); - using var parentScope = ScopeStack.PushLocalScope (new MarkScopeStack.Scope (origin)); using var methodScope = ScopeStack.PushLocalScope (new MessageOrigin (method)); bool markedForCall = diff --git a/src/tools/illink/src/linker/Mono.Linker.csproj b/src/tools/illink/src/linker/Mono.Linker.csproj index 9cc5aeff4ab094..24c4eba87ef35e 100644 --- a/src/tools/illink/src/linker/Mono.Linker.csproj +++ b/src/tools/illink/src/linker/Mono.Linker.csproj @@ -76,13 +76,8 @@ - - $(CoreClrProjectRoot)\tools\aot\ILCompiler.DependencyAnalysisFramework - $(CoreClrProjectRoot)\tools\Common - - - + From d50d70c9a8e124c42f9ad4717b629ee482ae235c Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:39:13 -0700 Subject: [PATCH 18/28] Use static lambda for TypeDefinitionNode creation --- .../illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs index 347124328d29ad..7e16f7ac25981d 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.NodeFactory.cs @@ -13,13 +13,13 @@ public partial class MarkStep internal sealed class NodeFactory (MarkStep markStep) { public MarkStep MarkStep { get; } = markStep; - readonly NodeCache _typeNodes = new (static _ => throw new InvalidOperationException ("Creation of node requires more than the key.")); + 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)); - internal TypeDefinitionNode GetTypeNode (TypeDefinition reference) + internal TypeDefinitionNode GetTypeNode (TypeDefinition definition) { - return _typeNodes.GetOrAdd (reference, (k) => new TypeDefinitionNode (k)); + return _typeNodes.GetOrAdd (definition); } internal MethodDefinitionNode GetMethodDefinitionNode (MethodDefinition method, DependencyInfo reason) From dfe51f2392a3e1ac58af5cb5d58ec541c72d32d7 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:17:12 -0700 Subject: [PATCH 19/28] Only warn on duplicate members within a single descriptors file --- .../src/linker/Linker.Steps/DescriptorMarker.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs index a527ca2e0df60b..6181a73092ed11 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; @@ -23,14 +24,18 @@ public class DescriptorMarker : ProcessLinkerXmlBase static readonly string[] _accessorsAll = new string[] { "all" }; static readonly char[] _accessorsSep = new char[] { ';' }; + protected readonly HashSet _preservedMembers; + public DescriptorMarker (LinkContext context, Stream documentStream, string xmlDocumentLocation) : base (context, documentStream, xmlDocumentLocation) { + _preservedMembers = new (); } public DescriptorMarker (LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "") : base (context, documentStream, resource, resourceAssembly, xmlDocumentLocation) { + _preservedMembers = new (); } public void Mark () @@ -147,7 +152,7 @@ protected static TypePreserve GetTypePreserve (XPathNavigator nav) protected override void ProcessField (TypeDefinition type, FieldDefinition field, XPathNavigator nav) { - if (_context.Annotations.IsMarked (field)) + if (!_preservedMembers.Add (field)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, field.FullName); _context.Annotations.Mark (field, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition (nav)); @@ -155,7 +160,7 @@ protected override void ProcessField (TypeDefinition type, FieldDefinition field protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { - if (_context.Annotations.IsMarked (method)) + if (!_preservedMembers.Add (method)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, method.GetDisplayName ()); _context.Annotations.MarkIndirectlyCalledMethod (method); @@ -212,7 +217,7 @@ public static string GetMethodSignature (MethodDefinition meth, bool includeGene protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { - if (_context.Annotations.IsMarked (@event)) + if (!_preservedMembers.Add (@event)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, @event.FullName); ProcessMethod (type, @event.AddMethod, nav, customData); @@ -224,7 +229,7 @@ protected override void ProcessProperty (TypeDefinition type, PropertyDefinition { string[] accessors = fromSignature ? GetAccessors (nav) : _accessorsAll; - if (_context.Annotations.IsMarked (property)) + if (!_preservedMembers.Add (property)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, property.FullName); if (Array.IndexOf (accessors, "all") >= 0) { From afedfb797361589a2b4074e220f85e0a79115821 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 25 Apr 2024 14:17:12 -0700 Subject: [PATCH 20/28] Only warn on duplicate members within a single descriptors file --- .../src/linker/Linker.Steps/DescriptorMarker.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs index a527ca2e0df60b..6181a73092ed11 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; @@ -23,14 +24,18 @@ public class DescriptorMarker : ProcessLinkerXmlBase static readonly string[] _accessorsAll = new string[] { "all" }; static readonly char[] _accessorsSep = new char[] { ';' }; + protected readonly HashSet _preservedMembers; + public DescriptorMarker (LinkContext context, Stream documentStream, string xmlDocumentLocation) : base (context, documentStream, xmlDocumentLocation) { + _preservedMembers = new (); } public DescriptorMarker (LinkContext context, Stream documentStream, EmbeddedResource resource, AssemblyDefinition resourceAssembly, string xmlDocumentLocation = "") : base (context, documentStream, resource, resourceAssembly, xmlDocumentLocation) { + _preservedMembers = new (); } public void Mark () @@ -147,7 +152,7 @@ protected static TypePreserve GetTypePreserve (XPathNavigator nav) protected override void ProcessField (TypeDefinition type, FieldDefinition field, XPathNavigator nav) { - if (_context.Annotations.IsMarked (field)) + if (!_preservedMembers.Add (field)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, field.FullName); _context.Annotations.Mark (field, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition (nav)); @@ -155,7 +160,7 @@ protected override void ProcessField (TypeDefinition type, FieldDefinition field protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { - if (_context.Annotations.IsMarked (method)) + if (!_preservedMembers.Add (method)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, method.GetDisplayName ()); _context.Annotations.MarkIndirectlyCalledMethod (method); @@ -212,7 +217,7 @@ public static string GetMethodSignature (MethodDefinition meth, bool includeGene protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { - if (_context.Annotations.IsMarked (@event)) + if (!_preservedMembers.Add (@event)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, @event.FullName); ProcessMethod (type, @event.AddMethod, nav, customData); @@ -224,7 +229,7 @@ protected override void ProcessProperty (TypeDefinition type, PropertyDefinition { string[] accessors = fromSignature ? GetAccessors (nav) : _accessorsAll; - if (_context.Annotations.IsMarked (property)) + if (!_preservedMembers.Add (property)) LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, property.FullName); if (Array.IndexOf (accessors, "all") >= 0) { From a6003482405133df0a955b84a38bb65885c5fd84 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 26 Apr 2024 11:48:43 -0700 Subject: [PATCH 21/28] Make duplicate preserve an info message --- .../src/linker/Linker.Steps/DescriptorMarker.cs | 14 ++++++++++---- .../illink/src/linker/Linker/MessageContainer.cs | 5 +++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs index 6181a73092ed11..f07200ab47e4b8 100644 --- a/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs +++ b/src/tools/illink/src/linker/Linker.Steps/DescriptorMarker.cs @@ -38,6 +38,12 @@ public DescriptorMarker (LinkContext context, Stream documentStream, EmbeddedRes _preservedMembers = new (); } + protected void LogDuplicatePreserve(string memberName, XPathNavigator duplicatePosition) + { + var origin = GetMessageOriginForPosition (duplicatePosition); + _context.LogMessage (MessageContainer.CreateInfoMessage (origin, $"Duplicate preserve of '{memberName}'")); + } + public void Mark () { bool stripDescriptors = _context.IsOptimizationEnabled (CodeOptimizations.RemoveDescriptors, _resource?.Assembly); @@ -153,7 +159,7 @@ protected static TypePreserve GetTypePreserve (XPathNavigator nav) protected override void ProcessField (TypeDefinition type, FieldDefinition field, XPathNavigator nav) { if (!_preservedMembers.Add (field)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, field.FullName); + LogDuplicatePreserve (field.FullName, nav); _context.Annotations.Mark (field, new DependencyInfo (DependencyKind.XmlDescriptor, _xmlDocumentLocation), GetMessageOriginForPosition (nav)); } @@ -161,7 +167,7 @@ protected override void ProcessField (TypeDefinition type, FieldDefinition field protected override void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNavigator nav, object? customData) { if (!_preservedMembers.Add (method)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, method.GetDisplayName ()); + LogDuplicatePreserve (method.GetDisplayName (), nav); _context.Annotations.MarkIndirectlyCalledMethod (method); _context.Annotations.SetAction (method, MethodAction.Parse); @@ -218,7 +224,7 @@ public static string GetMethodSignature (MethodDefinition meth, bool includeGene protected override void ProcessEvent (TypeDefinition type, EventDefinition @event, XPathNavigator nav, object? customData) { if (!_preservedMembers.Add (@event)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, @event.FullName); + LogDuplicatePreserve(@event.FullName, nav); ProcessMethod (type, @event.AddMethod, nav, customData); ProcessMethod (type, @event.RemoveMethod, nav, customData); @@ -230,7 +236,7 @@ protected override void ProcessProperty (TypeDefinition type, PropertyDefinition string[] accessors = fromSignature ? GetAccessors (nav) : _accessorsAll; if (!_preservedMembers.Add (property)) - LogWarning (nav, DiagnosticId.XmlDuplicatePreserveMember, property.FullName); + LogDuplicatePreserve(property.FullName, nav); if (Array.IndexOf (accessors, "all") >= 0) { ProcessMethodIfNotNull (type, property.GetMethod, nav, customData); diff --git a/src/tools/illink/src/linker/Linker/MessageContainer.cs b/src/tools/illink/src/linker/Linker/MessageContainer.cs index eb1fe94a53cfdf..e652c48e12740f 100644 --- a/src/tools/illink/src/linker/Linker/MessageContainer.cs +++ b/src/tools/illink/src/linker/Linker/MessageContainer.cs @@ -253,6 +253,11 @@ public static MessageContainer CreateInfoMessage (string text) return new MessageContainer (MessageCategory.Info, text, null); } + public static MessageContainer CreateInfoMessage (MessageOrigin origin, string text) + { + return new MessageContainer (MessageCategory.Info, text, null, "", origin); + } + /// /// Create a diagnostics message. /// From b27bc04d1fe22be98450dd374e5d62b8fd5222d9 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 26 Apr 2024 16:45:53 -0700 Subject: [PATCH 22/28] Update expectations in xml warnings tests --- .../LinkXml/LinkXmlErrorCases.cs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs index 467831cbb69fcd..e9021db105d4e8 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/LinkXml/LinkXmlErrorCases.cs @@ -6,6 +6,7 @@ namespace Mono.Linker.Tests.Cases.LinkXml { [SetupLinkerDescriptorFile ("LinkXmlErrorCases.xml")] [SetupLinkerArgument ("--skip-unresolved", "true")] + [SetupLinkerArgument ("--verbose")] [ExpectedWarning ("IL2001", "TypeWithNoFields", FileName = "LinkXmlErrorCases.xml", SourceLine = 3, SourceColumn = 6)] [ExpectedWarning ("IL2002", "TypeWithNoMethods", FileName = "LinkXmlErrorCases.xml", SourceLine = 4, SourceColumn = 6)] @@ -17,10 +18,15 @@ namespace Mono.Linker.Tests.Cases.LinkXml [ExpectedWarning ("IL2017", "NonExistentProperty", "TypeWithNoProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 21, SourceColumn = 8)] [ExpectedWarning ("IL2018", "SetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 25, SourceColumn = 8)] [ExpectedWarning ("IL2019", "GetOnlyProperty", "TypeWithProperties", FileName = "LinkXmlErrorCases.xml", SourceLine = 26, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Method", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 39, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Event", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 40, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Field", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 41, SourceColumn = 8)] - [ExpectedWarning ("IL2025", "Property", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 42, SourceColumn = 8)] + [LogContains ("Duplicate preserve of 'System.Int32 Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases/TypeWithEverything::Field'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.TypeWithEverything()'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Method()'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'System.EventHandler Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases/TypeWithEverything::Event'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Event.add'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Event.remove'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'System.Int32 Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases/TypeWithEverything::Property()'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Property.get'", ProducedBy = Tool.Trimmer)] + [LogContains ("Duplicate preserve of 'Mono.Linker.Tests.Cases.LinkXml.LinkXmlErrorCases.TypeWithEverything.Property.set'", ProducedBy = Tool.Trimmer)] // NativeAOT doesn't support wildcard * and will skip usages of it, including if they would warn // https://github.com/dotnet/runtime/issues/80466 [ExpectedWarning ("IL2100", Tool.Trimmer, "", FileName = "LinkXmlErrorCases.xml", SourceLine = 50, SourceColumn = 4)] From 1abe4b37d9c5fa1fc4a8667aa6b969ac6aec5a3f Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 26 Apr 2024 17:02:52 -0700 Subject: [PATCH 23/28] Make method internal for API compat --- src/tools/illink/src/linker/Linker/MessageContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker/MessageContainer.cs b/src/tools/illink/src/linker/Linker/MessageContainer.cs index e652c48e12740f..0de844bd6e8002 100644 --- a/src/tools/illink/src/linker/Linker/MessageContainer.cs +++ b/src/tools/illink/src/linker/Linker/MessageContainer.cs @@ -253,7 +253,7 @@ public static MessageContainer CreateInfoMessage (string text) return new MessageContainer (MessageCategory.Info, text, null); } - public static MessageContainer CreateInfoMessage (MessageOrigin origin, string text) + internal static MessageContainer CreateInfoMessage (MessageOrigin origin, string text) { return new MessageContainer (MessageCategory.Info, text, null, "", origin); } From 3ca9f9a8f9413636ba9e99d644b30a6dd0645f0b Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 2 May 2024 11:15:16 -0700 Subject: [PATCH 24/28] PR Feedback: - Rename dependency analyzer - Remove empty lines - Remove methods queue - Move static ctor marking --- .../MarkStep.ProcessCallbackNode.cs | 1 - .../MarkStep.TypeDefinitionNode.cs | 1 - ...Step.TypeIsRelevantToVariantCastingNode.cs | 1 - .../src/linker/Linker.Steps/MarkStep.cs | 52 ++++++------------- 4 files changed, 17 insertions(+), 38 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs index aae8e2193487cb..9fe4821f44381c 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.ProcessCallbackNode.cs @@ -7,7 +7,6 @@ namespace Mono.Linker.Steps { - public partial class MarkStep { sealed class ProcessCallbackNode : DependencyNodeCore diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs index dc33c026beb8a4..d26467930afce0 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeDefinitionNode.cs @@ -7,7 +7,6 @@ namespace Mono.Linker.Steps { - public partial class MarkStep { internal sealed class TypeDefinitionNode : DependencyNodeCore diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs index 127f65c8731c26..00f790b5d9d472 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.TypeIsRelevantToVariantCastingNode.cs @@ -7,7 +7,6 @@ namespace Mono.Linker.Steps { - public partial class MarkStep { internal sealed class TypeIsRelevantToVariantCastingNode : DependencyNodeCore diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 1f2651157f77b4..4dbbe33fe46302 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -61,7 +61,7 @@ protected LinkContext Context { } } - protected Queue<(MethodDefinition, DependencyInfo, MessageOrigin)> _methods; + private bool _completed; protected Dictionary _interface_methods; protected Queue _assemblyLevelAttributes; protected Queue<(AttributeProviderPair, DependencyInfo, MarkScopeStack.Scope)> _lateMarkedAttributes; @@ -76,7 +76,7 @@ protected LinkContext Context { // method body scanner. readonly Dictionary _compilerGeneratedMethodRequiresScanner; private readonly NodeFactory _nodeFactory; - private readonly DependencyAnalyzer, NodeFactory> _analyzer; + private readonly DependencyAnalyzer, NodeFactory> _dependencyGraph; MarkStepContext? _markContext; MarkStepContext MarkContext { @@ -222,7 +222,7 @@ internal DynamicallyAccessedMembersTypeHierarchy DynamicallyAccessedMembersTypeH public MarkStep () { - _methods = new Queue<(MethodDefinition, DependencyInfo, MessageOrigin)> (); + _completed = false; _interface_methods = new Dictionary (); _assemblyLevelAttributes = new Queue (); _lateMarkedAttributes = new Queue<(AttributeProviderPair, DependencyInfo, MarkScopeStack.Scope)> (); @@ -234,7 +234,7 @@ public MarkStep () _entireTypesMarked = new HashSet (); _compilerGeneratedMethodRequiresScanner = new Dictionary (); _nodeFactory = new NodeFactory (this); - _analyzer = new DependencyAnalyzer, NodeFactory> (_nodeFactory, null); + _dependencyGraph = new DependencyAnalyzer, NodeFactory> (_nodeFactory, null); } public AnnotationStore Annotations => Context.Annotations; @@ -380,14 +380,14 @@ internal void MarkEntireType (TypeDefinition type, in DependencyInfo reason) void Process () { - _analyzer.ComputeDependencyRoutine += (List> nodes) => { + _dependencyGraph.ComputeDependencyRoutine += (List> nodes) => { foreach (DependencyNodeCore node in nodes) { if (node is ProcessCallbackNode processNode) processNode.Process (); } }; - _analyzer.AddRoot (new ProcessCallbackNode (ProcessAllPendingItems), "start"); - _analyzer.ComputeMarkedNodes (); + _dependencyGraph.AddRoot (new ProcessCallbackNode (ProcessAllPendingItems), "start"); + _dependencyGraph.ComputeMarkedNodes (); ProcessPendingTypeChecks (); @@ -448,11 +448,11 @@ bool MarkFullyPreservedAssemblies () bool ProcessPrimaryQueue () { - if (ReachedSteadyState ()) + if (_completed) return false; - while (!ReachedSteadyState ()) { - ProcessQueue (); + while (!_completed) { + _completed = true; ProcessInterfaceMethods (); ProcessMarkedTypesWithInterfaces (); ProcessDynamicCastableImplementationInterfaces (); @@ -528,21 +528,6 @@ void ProcessPendingTypeChecks () } } - void ProcessQueue () - { - _methods.Clear (); - } - - bool ReachedSteadyState () - { - return _methods.Count == 0; - } - - void EnqueueMethod (MethodDefinition method, in DependencyInfo reason, in MessageOrigin origin) - { - _methods.Enqueue ((method, reason, origin)); - } - void ProcessInterfaceMethods () { foreach ((var method, var scope) in _interface_methods) { @@ -2028,16 +2013,10 @@ internal void MarkStaticConstructorVisibleToReflection (TypeDefinition type, in if (CheckProcessed (type)) return type; - if (type.HasMethods) { - if (ShouldMarkTypeStaticConstructor (type) && reason.Kind != DependencyKind.TriggersCctorForCalledMethod) { - MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin); - } - } - if (type.Scope is ModuleDefinition module) MarkModule (module, new DependencyInfo (DependencyKind.ScopeOfType, type)); - _analyzer.AddRoot (_nodeFactory.GetTypeNode (type), Enum.GetName(reason.Kind)); + _dependencyGraph.AddRoot (_nodeFactory.GetTypeNode (type), Enum.GetName(reason.Kind)); return type; } @@ -2130,6 +2109,9 @@ protected internal virtual void ProcessType (TypeDefinition type) MarkMethod (method, new DependencyInfo (DependencyKind.VirtualNeededDueToPreservedScope, type), ScopeStack.CurrentScope.Origin); } } + if (ShouldMarkTypeStaticConstructor (type)) { + MarkStaticConstructor (type, new DependencyInfo (DependencyKind.CctorForType, type), ScopeStack.CurrentScope.Origin); + } } DoAdditionalTypeProcessing (type); @@ -2799,7 +2781,7 @@ void MarkGenericArguments (IGenericInstance instance) if (argumentTypeDef == null) continue; - _analyzer.AddRoot (_nodeFactory.GetTypeIsRelevantToVariantCastingNode (argumentTypeDef), "Generic Argument"); + _dependencyGraph.AddRoot (_nodeFactory.GetTypeIsRelevantToVariantCastingNode (argumentTypeDef), "Generic Argument"); if (parameter.HasDefaultConstructorConstraint) MarkDefaultConstructor (argumentTypeDef, new DependencyInfo (DependencyKind.DefaultCtorForNewConstrainedGenericArgument, instance)); @@ -3052,8 +3034,8 @@ 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)) - EnqueueMethod (method, reason, origin); - _analyzer.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason), Enum.GetName(reason.Kind)); + _completed = false; + _dependencyGraph.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason), Enum.GetName(reason.Kind)); return method; } From 30011248d67b14a8ef7cd5dbdd8e1e9c868aaf94 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Thu, 2 May 2024 11:53:30 -0700 Subject: [PATCH 25/28] Add space before method call parentheses --- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 4dbbe33fe46302..1731eac41d2880 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -2016,7 +2016,7 @@ 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)); + _dependencyGraph.AddRoot (_nodeFactory.GetTypeNode (type), Enum.GetName (reason.Kind)); return type; } @@ -3035,7 +3035,7 @@ 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)); + _dependencyGraph.AddRoot (_nodeFactory.GetMethodDefinitionNode (method, reason), Enum.GetName (reason.Kind)); return method; } From f003f7409a21380524386da09a3b2b9a5038c547 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 3 May 2024 13:12:22 -0700 Subject: [PATCH 26/28] Don't pass TargetOS and TargetArch to ILLink.Tasks when using live illink --- eng/liveILLink.targets | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/eng/liveILLink.targets b/eng/liveILLink.targets index f18b89622982d9..4dc767a631588e 100644 --- a/eng/liveILLink.targets +++ b/eng/liveILLink.targets @@ -30,11 +30,13 @@ + + SetConfiguration="Configuration=$(ToolsConfiguration)" + GlobalPropertiesToRemove="TargetArchitecture;TargetOS" > TargetFramework=$(NetCoreAppToolCurrent) TargetFramework=$(NetFrameworkToolCurrent) From d358b42399eb42349a05ba63571637c3ca69dfc0 Mon Sep 17 00:00:00 2001 From: Jackson Schuster <36744439+jtschuster@users.noreply.github.com> Date: Fri, 3 May 2024 14:56:12 -0700 Subject: [PATCH 27/28] Update comment in liveILLink.targets --- eng/liveILLink.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/liveILLink.targets b/eng/liveILLink.targets index 4dc767a631588e..6b45e00a49d5ed 100644 --- a/eng/liveILLink.targets +++ b/eng/liveILLink.targets @@ -30,7 +30,7 @@ - + Date: Fri, 3 May 2024 16:25:43 -0700 Subject: [PATCH 28/28] Don't append platform to output dirs --- src/coreclr/Directory.Build.props | 2 +- .../ILCompiler.DependencyAnalysisFramework.csproj | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/coreclr/Directory.Build.props b/src/coreclr/Directory.Build.props index 233bfbeacebf0c..2f86002cccf44c 100644 --- a/src/coreclr/Directory.Build.props +++ b/src/coreclr/Directory.Build.props @@ -1,6 +1,6 @@ - true + true $(__BuildType) diff --git a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj index 27493074532da1..763d6bfbc27bf8 100644 --- a/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj +++ b/src/coreclr/tools/aot/ILCompiler.DependencyAnalysisFramework/ILCompiler.DependencyAnalysisFramework.csproj @@ -1,4 +1,8 @@ - + + + AnyCPU + + Library ILCompiler.DependencyAnalysisFramework @@ -54,4 +58,5 @@ Sorting\MergeSortCore.cs +