From 0e4f45976dab7d713e0fa70786943286b603d12d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 29 Apr 2021 14:41:23 -0700 Subject: [PATCH 01/12] Pass custom steps separately from msbuild --- dotnet/targets/Xamarin.Shared.Sdk.targets | 60 ++++++++++++-- tools/dotnet-linker/SetupStep.cs | 83 ------------------- .../Steps/ApplyPreserveDispatcher.cs | 11 +++ .../Steps/MarkNSObjectsDispatcher.cs | 11 +++ .../Steps/RemoveAttributesDispatcher.cs | 11 +++ .../Steps/RemoveUserResourcesDispatcher.cs | 11 +++ .../StoreMembersAndAttributesDispatcher.cs | 14 ++++ 7 files changed, 113 insertions(+), 88 deletions(-) create mode 100644 tools/dotnet-linker/Steps/ApplyPreserveDispatcher.cs create mode 100644 tools/dotnet-linker/Steps/MarkNSObjectsDispatcher.cs create mode 100644 tools/dotnet-linker/Steps/RemoveAttributesDispatcher.cs create mode 100644 tools/dotnet-linker/Steps/RemoveUserResourcesDispatcher.cs create mode 100644 tools/dotnet-linker/Steps/StoreMembersAndAttributesDispatcher.cs diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 88e78a4a3cca..c25fd1be7a0e 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -314,11 +314,61 @@ - - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)"> - MarkStep - Xamarin.SetupStep - + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.SetupStep" /> + + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.CollectAssembliesStep" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackigStep" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.StoreMembersAndAttributesDispatcher" /> + + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.ApplyPreserveDispatcher" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.MarkNSObjectsDispatcher" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" /> + + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.RemoveAttributesDispatcher" /> + + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.LoadNonSkippedAssembliesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ExtractBindingLibrariesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.RemoveUserResourcesDispatcher" /> + + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.RegistrarStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GenerateMainStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GenerateReferencesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GatherFrameworksStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.ComputeNativeBuildFlagsStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.ComputeAOTArguments" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.DoneStep" /> diff --git a/tools/dotnet-linker/SetupStep.cs b/tools/dotnet-linker/SetupStep.cs index 82193174621c..1be19cb0dd8f 100644 --- a/tools/dotnet-linker/SetupStep.cs +++ b/tools/dotnet-linker/SetupStep.cs @@ -28,92 +28,9 @@ public List Steps { } } - List _markHandlers; - List MarkHandlers { - get { - if (_markHandlers == null) { - var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null); - _markHandlers = (List) pipeline.GetType ().GetProperty ("MarkHandlers").GetValue (pipeline); - } - return _markHandlers; - } - } - - void InsertBefore (IStep step, string stepName) - { - for (int i = 0; i < Steps.Count; i++) { - if (Steps [i].GetType ().Name == stepName) { - Steps.Insert (i, step); - return; - } - } - DumpSteps (); - throw new InvalidOperationException ($"Could not insert {step} before {stepName} because {stepName} wasn't found."); - } - - void InsertAfter (IStep step, string stepName) - { - for (int i = 0; i < Steps.Count;) { - if (Steps [i++].GetType ().Name == stepName) { - Steps.Insert (i, step); - return; - } - } - DumpSteps (); - throw new InvalidOperationException ($"Could not insert {step} after {stepName} because {stepName} wasn't found."); - } protected override void TryProcess () { - // Don't use --custom-step to load each step, because this assembly - // is loaded into the current process once per --custom-step, - // which makes it very difficult to share state between steps. - - // Load the list of assemblies loaded by the linker. - // This would not be needed of LinkContext.GetAssemblies () was exposed to us. - InsertBefore (new CollectAssembliesStep (), "MarkStep"); - - // the final decision to remove/keep the dynamic registrar must be done before the linking step - InsertBefore (new RegistrarRemovalTrackingStep (), "MarkStep"); - - var pre_mark_substeps = new DotNetSubStepDispatcher (); - InsertBefore (pre_mark_substeps, "MarkStep"); - - var post_sweep_substeps = new DotNetSubStepDispatcher (); - InsertAfter (post_sweep_substeps, "SweepStep"); - - if (Configuration.LinkMode != LinkMode.None) { - MarkHandlers.Add (new PreserveBlockCodeHandler ()); - - // We need to run the ApplyPreserveAttribute step even we're only linking sdk assemblies, because even - // though we know that sdk assemblies will never have Preserve attributes, user assemblies may have - // [assembly: LinkSafe] attributes, which means we treat them as sdk assemblies and those may have - // Preserve attributes. - MarkHandlers.Add (new DotNetMarkAssemblySubStepDispatcher (new ApplyPreserveAttribute ())); - MarkHandlers.Add (new OptimizeGeneratedCodeHandler ()); - MarkHandlers.Add (new DotNetMarkAssemblySubStepDispatcher (new MarkNSObjects ())); - MarkHandlers.Add (new PreserveSmartEnumConversionsHandler ()); - - // This step could be run after Mark to avoid tracking all members: - // https://github.com/xamarin/xamarin-macios/issues/11447 - pre_mark_substeps.Add (new CollectUnmarkedMembersSubStep ()); - pre_mark_substeps.Add (new StoreAttributesStep ()); - - post_sweep_substeps.Add (new RemoveAttributesStep ()); - } - - InsertBefore (new ListExportedSymbols (null), "OutputStep"); - InsertBefore (new LoadNonSkippedAssembliesStep (), "OutputStep"); - InsertBefore (new ExtractBindingLibrariesStep (), "OutputStep"); - InsertBefore (new DotNetSubStepDispatcher (new RemoveUserResourcesSubStep ()), "OutputStep"); - Steps.Add (new RegistrarStep ()); - Steps.Add (new GenerateMainStep ()); - Steps.Add (new GenerateReferencesStep ()); - Steps.Add (new GatherFrameworksStep ()); - Steps.Add (new ComputeNativeBuildFlagsStep ()); - Steps.Add (new ComputeAOTArguments ()); - Steps.Add (new DoneStep ()); // Must be the last step. - Configuration.Write (); if (Configuration.Verbosity > 0) { diff --git a/tools/dotnet-linker/Steps/ApplyPreserveDispatcher.cs b/tools/dotnet-linker/Steps/ApplyPreserveDispatcher.cs new file mode 100644 index 000000000000..52cca85890c1 --- /dev/null +++ b/tools/dotnet-linker/Steps/ApplyPreserveDispatcher.cs @@ -0,0 +1,11 @@ +using Mono.Linker.Steps; +using Xamarin.Linker; + +namespace Xamarin.Linker.Steps { + class ApplyPreserveDispatcher : MarkSubStepsDispatcher { + public ApplyPreserveDispatcher () + : base (new [] { new ApplyPreserveAttribute () }) + { + } + } +} diff --git a/tools/dotnet-linker/Steps/MarkNSObjectsDispatcher.cs b/tools/dotnet-linker/Steps/MarkNSObjectsDispatcher.cs new file mode 100644 index 000000000000..4e20f13ba8e8 --- /dev/null +++ b/tools/dotnet-linker/Steps/MarkNSObjectsDispatcher.cs @@ -0,0 +1,11 @@ +using Mono.Linker.Steps; +using Xamarin.Linker; + +namespace Xamarin.Linker.Steps { + class MarkNSObjectsDispatcher : MarkSubStepsDispatcher { + public MarkNSObjectsDispatcher () + : base (new [] { new MarkNSObjects () }) + { + } + } +} diff --git a/tools/dotnet-linker/Steps/RemoveAttributesDispatcher.cs b/tools/dotnet-linker/Steps/RemoveAttributesDispatcher.cs new file mode 100644 index 000000000000..79e5ec0aed3c --- /dev/null +++ b/tools/dotnet-linker/Steps/RemoveAttributesDispatcher.cs @@ -0,0 +1,11 @@ +using Mono.Linker.Steps; +using Xamarin.Linker; + +namespace Xamarin.Linker.Steps { + class RemoveAttributesDispatcher : SubStepsDispatcher { + public RemoveAttributesDispatcher () + : base (new [] { new RemoveAttributesStep () }) + { + } + } +} diff --git a/tools/dotnet-linker/Steps/RemoveUserResourcesDispatcher.cs b/tools/dotnet-linker/Steps/RemoveUserResourcesDispatcher.cs new file mode 100644 index 000000000000..12031d523211 --- /dev/null +++ b/tools/dotnet-linker/Steps/RemoveUserResourcesDispatcher.cs @@ -0,0 +1,11 @@ +using Mono.Linker.Steps; +using Xamarin.Linker; + +namespace Xamarin.Linker.Steps { + class RemoveUserResourcesDispatcher : SubStepsDispatcher { + public RemoveUserResourcesDispatcher () + : base (new [] { new RemoveUserResourcesSubStep () }) + { + } + } +} diff --git a/tools/dotnet-linker/Steps/StoreMembersAndAttributesDispatcher.cs b/tools/dotnet-linker/Steps/StoreMembersAndAttributesDispatcher.cs new file mode 100644 index 000000000000..da1b825f049d --- /dev/null +++ b/tools/dotnet-linker/Steps/StoreMembersAndAttributesDispatcher.cs @@ -0,0 +1,14 @@ +using Mono.Linker.Steps; +using Xamarin.Linker; + +namespace Xamarin.Linker.Steps { + class StoreMembersAndAttributesDispatcher : SubStepsDispatcher { + public StoreMembersAndAttributesDispatcher () + : base (new BaseSubStep [] { + new CollectUnmarkedMembersSubStep (), + new StoreAttributesStep () + }) + { + } + } +} From abdc699db085977937e07fff62eeee40d4355dcf Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 30 Apr 2021 16:39:54 -0700 Subject: [PATCH 02/12] Remove reflection over linker pipeline --- tools/dotnet-linker/SetupStep.cs | 34 -------------------------------- 1 file changed, 34 deletions(-) diff --git a/tools/dotnet-linker/SetupStep.cs b/tools/dotnet-linker/SetupStep.cs index 1be19cb0dd8f..855d990dfbc6 100644 --- a/tools/dotnet-linker/SetupStep.cs +++ b/tools/dotnet-linker/SetupStep.cs @@ -17,46 +17,12 @@ public class SetupStep : ConfigurationAwareStep { protected override string Name { get; } = "Setup"; protected override int ErrorCode { get; } = 2300; - List _steps; - public List Steps { - get { - if (_steps == null) { - var pipeline = typeof (LinkContext).GetProperty ("Pipeline").GetGetMethod ().Invoke (Context, null); - _steps = (List) pipeline.GetType ().GetField ("_steps", BindingFlags.Instance | BindingFlags.NonPublic).GetValue (pipeline); - } - return _steps; - } - } - - protected override void TryProcess () { Configuration.Write (); - - if (Configuration.Verbosity > 0) { - DumpSteps (); - } - ErrorHelper.Platform = Configuration.Platform; Directory.CreateDirectory (Configuration.ItemsDirectory); Directory.CreateDirectory (Configuration.CacheDirectory); } - - void DumpSteps () - { - Console.WriteLine (); - Console.WriteLine ("Pipeline Steps:"); - foreach (var step in Steps) { - Console.WriteLine ($" {step}"); - if (step is SubStepsDispatcher) { - var substeps = typeof (SubStepsDispatcher).GetField ("substeps", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue (step) as IEnumerable; - if (substeps != null) { - foreach (var substep in substeps) { - Console.WriteLine ($" {substep}"); - } - } - } - } - } } } From 65a0517b3427423f79aaadbfada4a22908544fba Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 3 May 2021 11:02:16 -0700 Subject: [PATCH 03/12] Fix ListExportedSymbols ctor --- tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs index 00beef6806b6..105afae92bd6 100644 --- a/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs +++ b/tools/linker/MonoTouch.Tuner/ListExportedSymbols.cs @@ -28,6 +28,10 @@ public DerivedLinkContext DerivedLinkContext { } } + public ListExportedSymbols () : this (null) + { + } + internal ListExportedSymbols (PInvokeWrapperGenerator state, bool skip_sdk_assemblies = false) { this.state = state; From 9be3344bf796063eb014e7ffba075e2f20394649 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 27 May 2021 15:30:10 -0700 Subject: [PATCH 04/12] Add CoreTypeMapStep --- dotnet/targets/Xamarin.Shared.Sdk.targets | 6 +- tools/dotnet-linker/Extensions.cs | 32 ++++++ tools/dotnet-linker/LinkerConfiguration.cs | 3 +- .../Steps/CollectAssembliesStep.cs | 4 + .../Steps/DotNetMarkAssemblyDispatcher.cs | 11 -- tools/dotnet-linker/dotnet-linker.csproj | 3 + tools/linker/CoreTypeMapStep.cs | 106 +++++++++++++++++- tools/linker/MarkNSObjects.cs | 1 - tools/linker/ObjCExtensions.cs | 14 ++- 9 files changed, 157 insertions(+), 23 deletions(-) create mode 100644 tools/dotnet-linker/Extensions.cs delete mode 100644 tools/dotnet-linker/Steps/DotNetMarkAssemblyDispatcher.cs diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index c25fd1be7a0e..1e0405803ab1 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -318,11 +318,12 @@ pre-mark custom steps --> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.SetupStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.CoreTypeMapStep" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.CollectAssembliesStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackigStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.StoreMembersAndAttributesDispatcher" /> @@ -331,11 +332,10 @@ --> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" /> diff --git a/tools/dotnet-linker/Extensions.cs b/tools/dotnet-linker/Extensions.cs new file mode 100644 index 000000000000..351e88fa9f17 --- /dev/null +++ b/tools/dotnet-linker/Extensions.cs @@ -0,0 +1,32 @@ +using Mono.Cecil; +using Mono.Linker; +using Mono.Tuner; +using System; + +namespace Xamarin.Linker { + public static class Extensions { + public static bool Inherits (this TypeReference self, string @namespace, string name, IMetadataResolver resolver) + { + if (@namespace == null) + throw new ArgumentNullException ("namespace"); + if (name == null) + throw new ArgumentNullException ("name"); + if (self == null) + return false; + + TypeReference current = resolver.Resolve (self); + while (current != null) { + if (current.Is (@namespace, name)) + return true; + if (current.Is ("System", "Object")) + return false; + + TypeDefinition td = resolver.Resolve (current); + if (td == null) + return false; // could not resolve type + current = td.BaseType; + } + return false; + } + } +} diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 14a6524840e7..3ddab878e65d 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -47,7 +47,8 @@ public class LinkerConfiguration { // The list of assemblies is populated in CollectAssembliesStep. public List Assemblies = new List (); - + public Dictionary AssembliesByName = new Dictionary (); + string user_optimize_flags; Dictionary> msbuild_items = new Dictionary> (); diff --git a/tools/dotnet-linker/Steps/CollectAssembliesStep.cs b/tools/dotnet-linker/Steps/CollectAssembliesStep.cs index dc9d08dd3489..34832e88cb75 100644 --- a/tools/dotnet-linker/Steps/CollectAssembliesStep.cs +++ b/tools/dotnet-linker/Steps/CollectAssembliesStep.cs @@ -19,6 +19,10 @@ protected override void TryProcess () var getReferencedAssemblies = Configuration.Context.GetType ().GetMethod ("GetReferencedAssemblies"); var assemblies = (IEnumerable) getReferencedAssemblies.Invoke (Configuration.Context, new object [0]); Configuration.Assemblies.AddRange (assemblies); + foreach (var assembly in assemblies) { + if (!Configuration.AssembliesByName.TryAdd (assembly.Name.Name, assembly)) + throw new InvalidOperationException ($"Multiple assemblies with the same name: {assembly.Name.Name}"); + } } } } diff --git a/tools/dotnet-linker/Steps/DotNetMarkAssemblyDispatcher.cs b/tools/dotnet-linker/Steps/DotNetMarkAssemblyDispatcher.cs deleted file mode 100644 index 4daac49d8d85..000000000000 --- a/tools/dotnet-linker/Steps/DotNetMarkAssemblyDispatcher.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Mono.Linker.Steps; - -namespace Xamarin.Linker.Steps { - // MarkSubStepsDispatcher is abstract, so create a subclass we can instantiate. - // Can be removed when we update to the preview4 linker, which makes MarkSubStepsDispatcher non-abstract. - class DotNetMarkAssemblySubStepDispatcher : MarkSubStepsDispatcher { - public DotNetMarkAssemblySubStepDispatcher (params BaseSubStep[] subSteps) : base (subSteps) - { - } - } -} diff --git a/tools/dotnet-linker/dotnet-linker.csproj b/tools/dotnet-linker/dotnet-linker.csproj index e1fb81a5e5b4..c55a0a793917 100644 --- a/tools/dotnet-linker/dotnet-linker.csproj +++ b/tools/dotnet-linker/dotnet-linker.csproj @@ -106,6 +106,9 @@ external\tools\linker\CoreOptimizeGeneratedCode.cs + + external\tools\linker\CoreTypeMapStep.cs + external\src\ObjCRuntime\Registrar.cs diff --git a/tools/linker/CoreTypeMapStep.cs b/tools/linker/CoreTypeMapStep.cs index bc26f120d206..a7dbda39d0a5 100644 --- a/tools/linker/CoreTypeMapStep.cs +++ b/tools/linker/CoreTypeMapStep.cs @@ -20,27 +20,101 @@ namespace MonoTouch.Tuner { // This class is shared between Xamarin.Mac and Xamarin.iOS - public class CoreTypeMapStep : TypeMapStep { - HashSet cached_isnsobject = new HashSet (); - Dictionary isdirectbinding_value = new Dictionary (); + public class CoreTypeMapStep : +#if NET + ConfigurationAwareStep +#else + TypeMapStep +#endif + { + +#if NET + protected override string Name { get; } = "CoreTypeMap"; + protected override int ErrorCode { get; } = 2381; + + Profile Profile => new Profile (Configuration); + + Dictionary _transitivelyReferencesProduct = new Dictionary (); + bool TransitivelyReferencesProduct (AssemblyDefinition assembly) + { + if (_transitivelyReferencesProduct.TryGetValue (assembly, out bool result)) + return result; + + if (Profile.IsProductAssembly (assembly)) { + _transitivelyReferencesProduct.Add (assembly, true); + return true; + } + + foreach (var reference in assembly.MainModule.AssemblyReferences) { + if (!Configuration.AssembliesByName.TryGetValue (reference.Name, out AssemblyDefinition resolvedReference)) + continue; + + if (TransitivelyReferencesProduct (resolvedReference)) { + _transitivelyReferencesProduct.Add (assembly, true); + return true; + } + } + + _transitivelyReferencesProduct.Add (assembly, false); + return false; + } + + protected override void TryProcessAssembly (AssemblyDefinition assembly) + { + // We are only interested in types transitively derived from NSObject, + // which lives in the product assembly. + if (!TransitivelyReferencesProduct (assembly)) + return; + + foreach (var type in assembly.MainModule.Types) + ProcessType (type); + } + + void ProcessType (TypeDefinition type) + { + MapType (type); + + if (!type.HasNestedTypes) + return; + foreach (var nestedType in type.NestedTypes) + ProcessType (nestedType); + } + + DerivedLinkContext LinkContext => Configuration.DerivedLinkContext; +#else DerivedLinkContext LinkContext { get { return (DerivedLinkContext) base.Context; } } +#endif + + HashSet cached_isnsobject = new HashSet (); + Dictionary isdirectbinding_value = new Dictionary (); +#if NET + protected override void TryEndProcess () + { +#else protected override void EndProcess () { base.EndProcess (); +#endif LinkContext.CachedIsNSObject = cached_isnsobject; LinkContext.IsDirectBindingValue = isdirectbinding_value; } - protected override void MapType (TypeDefinition type) + protected +#if !NET + override +#endif + void MapType (TypeDefinition type) { +#if !NET base.MapType (type); +#endif // additional checks for NSObject to check if the type is a *generated* bindings // bonus: we cache, for every type, whether or not it inherits from NSObject (very useful later) @@ -77,7 +151,13 @@ bool IsCIFilter (TypeReference type) bool rv; if (!ci_filter_types.TryGetValue (type, out rv)) { - rv = type.Is (Namespaces.CoreImage, "CIFilter") || IsCIFilter (type.Resolve ().BaseType); + rv = type.Is (Namespaces.CoreImage, "CIFilter") || IsCIFilter ( +#if NET + Context.Resolve (type).BaseType +#else + type.Resolve ().BaseType +#endif + ); ci_filter_types [type] = rv; } return rv; @@ -97,10 +177,18 @@ void SetIsDirectBindingValue (TypeDefinition type) // * https://bugzilla.xamarin.com/show_bug.cgi?id=15465 if (IsCIFilter (type)) { isdirectbinding_value [type] = null; +#if NET + var base_type = Context.Resolve (type.BaseType); +#else var base_type = type.BaseType.Resolve (); +#endif while (base_type != null && IsNSObject (base_type)) { isdirectbinding_value [base_type] = null; +#if NET + base_type = Context.Resolve (base_type.BaseType); +#else base_type = base_type.BaseType.Resolve (); +#endif } return; } @@ -111,11 +199,19 @@ void SetIsDirectBindingValue (TypeDefinition type) isdirectbinding_value [type] = false; // We must clear IsDirectBinding for any wrapper superclasses. +#if NET + var base_type = Context.Resolve (type.BaseType); +#else var base_type = type.BaseType.Resolve (); +#endif while (base_type != null && IsNSObject (base_type)) { if (IsWrapperType (base_type)) isdirectbinding_value [base_type] = null; +#if NET + base_type = Context.Resolve (base_type.BaseType); +#else base_type = base_type.BaseType.Resolve (); +#endif } } else { isdirectbinding_value [type] = true; // Let's try 'true' first, any derived non-wrapper classes will clear it if needed diff --git a/tools/linker/MarkNSObjects.cs b/tools/linker/MarkNSObjects.cs index f2d7d0591f33..22cefe45025d 100644 --- a/tools/linker/MarkNSObjects.cs +++ b/tools/linker/MarkNSObjects.cs @@ -85,7 +85,6 @@ void PreserveExportedMethods (TypeDefinition type) continue; // not optimal if "Link all" is used as the override might be removed later - // this may miss some overrides with the .NET6 linker (https://github.com/xamarin/xamarin-macios/issues/11449) if (!IsOverridenInUserCode (method)) continue; diff --git a/tools/linker/ObjCExtensions.cs b/tools/linker/ObjCExtensions.cs index 52767f5e8cb9..af12ecdfcf84 100644 --- a/tools/linker/ObjCExtensions.cs +++ b/tools/linker/ObjCExtensions.cs @@ -84,7 +84,13 @@ static class ObjCExtensions { const string INativeObject = Namespaces.ObjCRuntime + ".INativeObject"; public static bool IsNSObject (this TypeReference type, DerivedLinkContext link_context) { - return type.Resolve ().IsNSObject (link_context); + return +#if NET + link_context.LinkerConfiguration.Context.Resolve (type) +#else + type.Resolve () +#endif + .IsNSObject (link_context); } // warning: *Is* means does 'type' inherits from MonoTouch.Foundation.NSObject ? @@ -93,7 +99,11 @@ public static bool IsNSObject (this TypeDefinition type, DerivedLinkContext link if (link_context?.CachedIsNSObject != null) return link_context.CachedIsNSObject.Contains (type); - return type.Inherits (Namespaces.Foundation, "NSObject"); + return type.Inherits (Namespaces.Foundation, "NSObject" +#if NET + , link_context.LinkerConfiguration.Context +#endif + ); } public static bool IsNativeObject (this TypeDefinition type) From 84a5531762c8c505eb852d15237d87c730881947 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 1 Jun 2021 15:28:59 -0700 Subject: [PATCH 05/12] PR feedback - Avoid unnecessary tracking of loaded assemblies (Use GetLoadedAssembly instead) - Create extension method on LinkContext to avoid conditional code - Rename dispatchers to reflect when they run --- dotnet/targets/Xamarin.Shared.Sdk.targets | 11 ++++---- tools/dotnet-linker/LinkerConfiguration.cs | 1 - .../Steps/ApplyPreserveDispatcher.cs | 11 -------- .../Steps/CollectAssembliesStep.cs | 4 --- tools/dotnet-linker/Steps/MarkDispatcher.cs | 14 ++++++++++ .../Steps/MarkNSObjectsDispatcher.cs | 11 -------- ...esDispatcher.cs => PostSweepDispatcher.cs} | 4 +-- ...utesDispatcher.cs => PreMarkDispatcher.cs} | 4 +-- ...esDispatcher.cs => PreOutputDispatcher.cs} | 4 +-- tools/linker/CoreTypeMapStep.cs | 27 +++---------------- tools/linker/MonoTouch.Tuner/Extensions.cs | 9 +++++++ 11 files changed, 37 insertions(+), 63 deletions(-) delete mode 100644 tools/dotnet-linker/Steps/ApplyPreserveDispatcher.cs create mode 100644 tools/dotnet-linker/Steps/MarkDispatcher.cs delete mode 100644 tools/dotnet-linker/Steps/MarkNSObjectsDispatcher.cs rename tools/dotnet-linker/Steps/{RemoveAttributesDispatcher.cs => PostSweepDispatcher.cs} (60%) rename tools/dotnet-linker/Steps/{StoreMembersAndAttributesDispatcher.cs => PreMarkDispatcher.cs} (64%) rename tools/dotnet-linker/Steps/{RemoveUserResourcesDispatcher.cs => PreOutputDispatcher.cs} (59%) diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 1e0405803ab1..063e0de4fdcf 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -325,7 +325,7 @@ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.StoreMembersAndAttributesDispatcher" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.ApplyPreserveDispatcher" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" /> - - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.MarkNSObjectsDispatcher" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.MarkDispatcher" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveSmartEnumConversionsHandler" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.RemoveAttributesDispatcher" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="SweepStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PostSweepDispatcher" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.RegistrarStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GenerateMainStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GenerateReferencesStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.GatherFrameworksStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.ComputeNativeBuildFlagsStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.ComputeAOTArguments" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.RegistrarStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GenerateMainStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GenerateReferencesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.GatherFrameworksStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.ComputeNativeBuildFlagsStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.ComputeAOTArguments" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Type="Xamarin.Linker.DoneStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" AfterStep="OutputStep" Type="Xamarin.Linker.DoneStep" /> From 6a4d06b306df62b6d856e4f006b330ade52207a8 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 4 Jun 2021 08:58:13 -0700 Subject: [PATCH 08/12] Fix other order-dependent steps, test asserts --- dotnet/targets/Xamarin.Shared.Sdk.targets | 18 ++++++++++-------- tests/dotnet/UnitTests/ProjectTest.cs | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 61d385bdf7cd..21513cc86305 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -320,15 +320,16 @@ - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.SetupStep" /> + + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" /> + + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.CoreTypeMapStep" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.CollectAssembliesStep" /> - - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" /> - - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreMarkDispatcher" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.SetupStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.LoadNonSkippedAssembliesStep" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ExtractBindingLibrariesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.PreOutputDispatcher" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.ExtractBindingLibrariesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.LoadNonSkippedAssembliesStep" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="OutputStep" Type="Xamarin.Linker.Steps.ListExportedSymbols" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.PreserveBlockCodeHandler" /> - <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.OptimizeGeneratedCodeHandler" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" Condition="'$(_LinkMode)' != 'None'" Type="Xamarin.Linker.Steps.MarkDispatcher" /> diff --git a/tools/dotnet-linker/LinkerConfiguration.cs b/tools/dotnet-linker/LinkerConfiguration.cs index 73f7f32fd441..14a6524840e7 100644 --- a/tools/dotnet-linker/LinkerConfiguration.cs +++ b/tools/dotnet-linker/LinkerConfiguration.cs @@ -47,7 +47,7 @@ public class LinkerConfiguration { // The list of assemblies is populated in CollectAssembliesStep. public List Assemblies = new List (); - + string user_optimize_flags; Dictionary> msbuild_items = new Dictionary> (); diff --git a/tools/linker/ApplyPreserveAttribute.cs b/tools/linker/ApplyPreserveAttribute.cs index ba65906968a2..2239b20f6f9e 100644 --- a/tools/linker/ApplyPreserveAttribute.cs +++ b/tools/linker/ApplyPreserveAttribute.cs @@ -17,6 +17,10 @@ public class ApplyPreserveAttribute : ApplyPreserveAttributeBase { HashSet preserve_synonyms; #endif + // We need to run the ApplyPreserveAttribute step even if we're only linking sdk assemblies, because even + // though we know that sdk assemblies will never have Preserve attributes, user assemblies may have + // [assembly: LinkSafe] attributes, which means we treat them as sdk assemblies and those may have + // Preserve attributes. public override bool IsActiveFor (AssemblyDefinition assembly) { return Annotations.GetAction (assembly) == AssemblyAction.Link; diff --git a/tools/linker/CoreTypeMapStep.cs b/tools/linker/CoreTypeMapStep.cs index bd9a64d751e0..2830f03dba7c 100644 --- a/tools/linker/CoreTypeMapStep.cs +++ b/tools/linker/CoreTypeMapStep.cs @@ -172,11 +172,11 @@ void MapType (TypeDefinition type) // bonus: we cache, for every type, whether or not it inherits from NSObject (very useful later) if (!IsNSObject (type)) return; - + // if not, it's a user type, the IsDirectBinding check is required by all ancestors SetIsDirectBindingValue (type); } - + // called once for each 'type' so it's a nice place to cache the result // and ensure later steps re-use the same, pre-computed, result bool IsNSObject (TypeDefinition type) @@ -208,7 +208,7 @@ bool IsCIFilter (TypeReference type) } return rv; } - + void SetIsDirectBindingValue (TypeDefinition type) { if (isdirectbinding_value.ContainsKey (type)) @@ -248,4 +248,4 @@ void SetIsDirectBindingValue (TypeDefinition type) } } } -} +} \ No newline at end of file