From 831f55796ef84dd1115cfda940b78008841f1bc8 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Fri, 6 Nov 2020 16:13:37 +0100 Subject: [PATCH] [dotnet-linker] Add a StoreAttributesStep to store attributes that are removed by the linker. Add a StoreAttributesStep to store attributes that are removed by the linker, but that the static registrar needs. In particular, in .NET 6 the linker removes the System.Runtime.CompilerServices.ExtensionAttribute, which the static registrar needs to handle category methods properly. This involved copying and slightly modifying the RemoveAttributesBase code. --- tools/dotnet-linker/SetupStep.cs | 1 + .../Steps/AttributeIteratorBaseStep.cs | 104 ++++++++++++++++++ .../Steps/RemoveAttributesStep.cs | 22 ++-- .../Steps/StoreAttributesStep.cs | 30 +++++ tools/dotnet-linker/dotnet-linker.csproj | 3 - 5 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 tools/dotnet-linker/Steps/AttributeIteratorBaseStep.cs create mode 100644 tools/dotnet-linker/Steps/StoreAttributesStep.cs diff --git a/tools/dotnet-linker/SetupStep.cs b/tools/dotnet-linker/SetupStep.cs index 0281906cba..81c3ba450a 100644 --- a/tools/dotnet-linker/SetupStep.cs +++ b/tools/dotnet-linker/SetupStep.cs @@ -80,6 +80,7 @@ namespace Xamarin { prelink_substeps.Add (new MarkNSObjects ()); prelink_substeps.Add (new PreserveSmartEnumConversionsSubStep ()); prelink_substeps.Add (new CollectUnmarkedMembersSubStep ()); + prelink_substeps.Add (new StoreAttributesStep ()); post_sweep_substeps.Add (new RemoveAttributesStep ()); } diff --git a/tools/dotnet-linker/Steps/AttributeIteratorBaseStep.cs b/tools/dotnet-linker/Steps/AttributeIteratorBaseStep.cs new file mode 100644 index 0000000000..8c0c1affb3 --- /dev/null +++ b/tools/dotnet-linker/Steps/AttributeIteratorBaseStep.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections; + +using Mono.Linker; +using Mono.Linker.Steps; + +using Mono.Cecil; +using Xamarin.Tuner; + +namespace Xamarin.Linker.Steps { + + public abstract class AttributeIteratorBaseStep : BaseSubStep { + + protected DerivedLinkContext LinkContext { + get { + return LinkerConfiguration.GetInstance (Context).DerivedLinkContext; + } + } + + public override SubStepTargets Targets { + get { + return SubStepTargets.Assembly + | SubStepTargets.Type + | SubStepTargets.Field + | SubStepTargets.Method + | SubStepTargets.Property + | SubStepTargets.Event; + } + } + + public override bool IsActiveFor (AssemblyDefinition assembly) + { + return Annotations.GetAction (assembly) == AssemblyAction.Link; + } + + public override void ProcessAssembly (AssemblyDefinition assembly) + { + ProcessAttributeProvider (assembly); + ProcessAttributeProvider (assembly.MainModule); + } + + public override void ProcessType (TypeDefinition type) + { + ProcessAttributeProvider (type); + + if (type.HasGenericParameters) + ProcessAttributeProviderCollection (type.GenericParameters); + } + + void ProcessAttributeProviderCollection (IList list) + { + for (int i = 0; i < list.Count; i++) + ProcessAttributeProvider ((ICustomAttributeProvider) list [i]); + } + + public override void ProcessField (FieldDefinition field) + { + ProcessAttributeProvider (field); + } + + public override void ProcessMethod (MethodDefinition method) + { + ProcessMethodAttributeProvider (method); + } + + void ProcessMethodAttributeProvider (MethodDefinition method) + { + ProcessAttributeProvider (method); + ProcessAttributeProvider (method.MethodReturnType); + + if (method.HasParameters) + ProcessAttributeProviderCollection (method.Parameters); + + if (method.HasGenericParameters) + ProcessAttributeProviderCollection (method.GenericParameters); + } + + public override void ProcessProperty (PropertyDefinition property) + { + ProcessAttributeProvider (property); + } + + public override void ProcessEvent (EventDefinition @event) + { + ProcessAttributeProvider (@event); + } + + void ProcessAttributeProvider (ICustomAttributeProvider provider) + { + if (!provider.HasCustomAttributes) + return; + + for (int i = 0; i < provider.CustomAttributes.Count; i++) { + var attrib = provider.CustomAttributes [i]; + ProcessAttribute (provider, attrib, out var remove); + + if (remove) + provider.CustomAttributes.RemoveAt (i--); + } + } + + protected abstract void ProcessAttribute (ICustomAttributeProvider provider, CustomAttribute attribute, out bool remove); + } +} diff --git a/tools/dotnet-linker/Steps/RemoveAttributesStep.cs b/tools/dotnet-linker/Steps/RemoveAttributesStep.cs index f9f9f0ad5f..1710626d55 100644 --- a/tools/dotnet-linker/Steps/RemoveAttributesStep.cs +++ b/tools/dotnet-linker/Steps/RemoveAttributesStep.cs @@ -1,8 +1,6 @@ using System; using Mono.Cecil; -using Mono.Tuner; -using Xamarin.Tuner; namespace Xamarin.Linker.Steps { // The .NET linker comes with a way to remove attributes (by passing '--link-attributes @@ -22,14 +20,16 @@ namespace Xamarin.Linker.Steps { // // The end result is that a custom step is the best solution for now. - public class RemoveAttributesStep : RemoveAttributesBase { - protected DerivedLinkContext LinkContext { - get { - return LinkerConfiguration.GetInstance (Context).DerivedLinkContext; - } + public class RemoveAttributesStep : AttributeIteratorBaseStep { + protected override void ProcessAttribute (ICustomAttributeProvider provider, CustomAttribute attribute, out bool remove) + { + remove = IsRemovedAttribute (attribute); + + if (remove) + LinkContext.StoreCustomAttribute (provider, attribute); } - protected override bool IsRemovedAttribute (CustomAttribute attribute) + bool IsRemovedAttribute (CustomAttribute attribute) { // this avoids calling FullName (which allocates a string) var attr_type = attribute.Constructor.DeclaringType; @@ -51,11 +51,5 @@ namespace Xamarin.Linker.Steps { return false; } } - - protected override void WillRemoveAttribute (ICustomAttributeProvider provider, CustomAttribute attribute) - { - LinkContext.StoreCustomAttribute (provider, attribute); - base.WillRemoveAttribute (provider, attribute); - } } } diff --git a/tools/dotnet-linker/Steps/StoreAttributesStep.cs b/tools/dotnet-linker/Steps/StoreAttributesStep.cs new file mode 100644 index 0000000000..88816daeeb --- /dev/null +++ b/tools/dotnet-linker/Steps/StoreAttributesStep.cs @@ -0,0 +1,30 @@ +using System; + +using Mono.Cecil; + +namespace Xamarin.Linker.Steps { + // The registrar needs some of the system attributes that the linker might remove, so store those elsewhere for the static registrar's use. + public class StoreAttributesStep : AttributeIteratorBaseStep { + protected override void ProcessAttribute (ICustomAttributeProvider provider, CustomAttribute attribute, out bool remove) + { + // don't remove any of these + remove = false; + + // this avoids calling FullName (which allocates a string) + var attr_type = attribute.Constructor.DeclaringType; + var store = false; + switch (attr_type.Namespace) { + case "System.Runtime.CompilerServices": + switch (attr_type.Name) { + case "ExtensionAttribute": + store = true; + break; + } + break; + } + + if (store) + LinkContext.StoreCustomAttribute (provider, attribute); + } + } +} diff --git a/tools/dotnet-linker/dotnet-linker.csproj b/tools/dotnet-linker/dotnet-linker.csproj index 39ece52afd..c51b421b61 100644 --- a/tools/dotnet-linker/dotnet-linker.csproj +++ b/tools/dotnet-linker/dotnet-linker.csproj @@ -176,9 +176,6 @@ external\mono-archive\Mono.Tuner\CecilRocks.cs - - external\mono-archive\Mono.Tuner\RemoveAttributesBase.cs - external\Xamarin.MacDev\Xamarin.MacDev\PListObject.cs