diff --git a/dotnet/targets/Xamarin.Shared.Sdk.targets b/dotnet/targets/Xamarin.Shared.Sdk.targets index 3d51bcbfefc2..7c03a3e56412 100644 --- a/dotnet/targets/Xamarin.Shared.Sdk.targets +++ b/dotnet/targets/Xamarin.Shared.Sdk.targets @@ -553,6 +553,7 @@ <_UseDynamicDependenciesForGeneratedCodeOptimizations Condition="'$(_UseDynamicDependenciesForGeneratedCodeOptimizations)' == ''">$(_UseDynamicDependenciesInsteadOfMarking) <_UseLinkDescriptionForApplyPreserveAttribute Condition="'$(_UseLinkDescriptionForApplyPreserveAttribute)' == '' And '$(_XamarinRuntime)' == 'NativeAOT'">true <_UseLinkDescriptionForApplyPreserveAttribute Condition="'$(_UseLinkDescriptionForApplyPreserveAttribute)' == ''">$(_UseDynamicDependenciesInsteadOfMarking) + <_UseDynamicDependenciesForMarkStaticRegistrar Condition="'$(_UseDynamicDependenciesForMarkStaticRegistrar)' == ''">$(_UseDynamicDependenciesInsteadOfMarking) @@ -759,6 +760,7 @@ <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.PreserveBlockCodeStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForBlockCodePreservation)' == 'true'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.OptimizeGeneratedCodeStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForGeneratedCodeOptimizations)' == 'true'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.ApplyPreserveAttributeStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseLinkDescriptionForApplyPreserveAttribute)' == 'true'" /> + <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="Xamarin.Linker.Steps.MarkForStaticRegistrarStep" Condition="'$(_AreAnyAssembliesTrimmed)' == 'true' And '$(_UseDynamicDependenciesForMarkStaticRegistrar)' == 'true'" /> <_TrimmerCustomSteps Include="$(_AdditionalTaskAssembly)" BeforeStep="MarkStep" Type="MonoTouch.Tuner.RegistrarRemovalTrackingStep" /> diff --git a/tools/common/DerivedLinkContext.cs b/tools/common/DerivedLinkContext.cs index 1cc8f9e0e187..70ec1490e4f7 100644 --- a/tools/common/DerivedLinkContext.cs +++ b/tools/common/DerivedLinkContext.cs @@ -49,6 +49,7 @@ public class DerivedLinkContext : LinkContext { Dictionary LinkedAwayTypeMap = new Dictionary (); public bool DidRunApplyPreserveAttributeStep { get; set; } + public bool DidRunMarkForStaticRegistrarStep { get; set; } public DerivedLinkContext (LinkerConfiguration configuration, Application app) #if !LEGACY_TOOLS diff --git a/tools/dotnet-linker/MarkForStaticRegistrar.cs b/tools/dotnet-linker/MarkForStaticRegistrar.cs index e78759e16057..9590920980cb 100644 --- a/tools/dotnet-linker/MarkForStaticRegistrar.cs +++ b/tools/dotnet-linker/MarkForStaticRegistrar.cs @@ -23,6 +23,10 @@ public class MarkForStaticRegistrar : ConfigurationAwareSubStep { public override bool IsActiveFor (AssemblyDefinition assembly) { + // It's either this step, or MarkForStaticRegistrarStep. If MarkForStaticRegistrarStep already ran, then we shouldn't run this step. + if (Configuration.DerivedLinkContext.DidRunMarkForStaticRegistrarStep) + return false; + if (Configuration.Application.Optimizations.OptimizeBlockLiteralSetupBlock != true) return false; diff --git a/tools/dotnet-linker/MarkForStaticRegistrarStep.cs b/tools/dotnet-linker/MarkForStaticRegistrarStep.cs new file mode 100644 index 000000000000..55b18ecd053f --- /dev/null +++ b/tools/dotnet-linker/MarkForStaticRegistrarStep.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System.Linq; + +using Mono.Cecil; +using Mono.Linker; +using Registrar; +using Xamarin.Bundler; + +#nullable enable + +namespace Xamarin.Linker.Steps { + + // This class marks APIs referenced by the native code generated by the static registrar. + public class MarkForStaticRegistrarStep : AssemblyModifierStep { + protected override string Name { get => "Mark For Static Registrar"; } + + protected override int ErrorCode { get => 2460; } + + protected override bool IsActiveFor (AssemblyDefinition assembly) + { + if (Configuration.Application.Optimizations.OptimizeBlockLiteralSetupBlock != true) + return false; + + if (Configuration.Application.Registrar != RegistrarMode.Static) + return false; + + return Annotations.GetAction (assembly) == AssemblyAction.Link; + } + + protected override void TryProcess () + { + DerivedLinkContext.DidRunMarkForStaticRegistrarStep = true; + base.TryProcess (); + } + + protected override bool ProcessType (TypeDefinition type) + { + return base.ProcessMethods (type); + } + + protected override bool ProcessMethod (MethodDefinition method) + { + return ProcessDelegateProxyAttribute (method); + } + + // Mark the Invoke method in the type pointed to by the DelegateProxy attribute, + // because it may only be referenced from native code when using the static registrar. + bool ProcessDelegateProxyAttribute (MethodDefinition method) + { + if (!StaticRegistrar.IsDelegate (method.ReturnType.Resolve ())) + return false; + + var getDelegateProxyType = DerivedLinkContext.StaticRegistrar.GetDelegateProxyType (method); + if (getDelegateProxyType is null) + return false; + + var invokeMethod = getDelegateProxyType.Methods.SingleOrDefault (m => m.Name == "Invoke"); + if (invokeMethod is null) + return false; + + return abr.AddDynamicDependencyAttribute (method, invokeMethod); + } + } +}