From 252bc502cfd550b4a4de5c8b3945ec5e0fe4c23e Mon Sep 17 00:00:00 2001 From: Sebastien Pouliot Date: Tue, 14 May 2019 09:41:09 -0700 Subject: [PATCH 1/3] [linker] Add the custom attributes removal step as an configurable optimization. Fix #3655 This allows the optimization to be disabled in cases where one, or many, a custom attribute(s) are required by the application at runtime. While not ideal disabling this single step is much better than disabling linking for the whole application. A better approach is described in https://github.com/xamarin/xamarin-macios/issues/6048 but this configuration optimization makes sense independently of it. Fix https://github.com/xamarin/xamarin-macios/issues/3655 --- docs/website/optimizations.md | 18 ++++++++++++++++++ tools/common/Optimizations.cs | 11 +++++++++++ tools/mmp/Tuning.cs | 35 ++++++++++++++++++++++------------- tools/mtouch/Tuning.cs | 4 ++-- 4 files changed, 53 insertions(+), 15 deletions(-) diff --git a/docs/website/optimizations.md b/docs/website/optimizations.md index 8808be9bdc15..295ce47972ba 100644 --- a/docs/website/optimizations.md +++ b/docs/website/optimizations.md @@ -737,3 +737,21 @@ disabled until the correct linker annotations (e.g. The default behavior can be overridden by passing `--optimize=[+|-]cctor-beforefieldinit` to `mtouch` or `mmp`. + +## Custom Attributes Removal + +This optimization requires the linker to be enabled and is applied globally +on all assemblies inside the application. + +This optimization removes a number of, rarely used, custom attributes from +assemblies. In turn this allows the linker to later remove the associated +code from the base class libraries (BCL). This help reduce both the +metadata and code size for your application. + +This optimization is enabled, by default, on both Xamarin.iOS and +Xamarin.Mac. If some of the removed custom attributes are required for +your application you can disable this optimization, without totally +disabling the managed linker. + +The default behavior can be overridden by passing +`--optimize=[+|-]custom-attributes-removal` to `mtouch`. diff --git a/tools/common/Optimizations.cs b/tools/common/Optimizations.cs index 8ed3f2323cd4..cd091ad25983 100644 --- a/tools/common/Optimizations.cs +++ b/tools/common/Optimizations.cs @@ -41,6 +41,7 @@ public class Optimizations "", // dummy value to make indices match up between XM and XI #endif "cctor-beforefieldinit", + "custom-attributes-removal", }; enum Opt @@ -60,6 +61,7 @@ enum Opt InlineIsARM64CallingConvention, SealAndDevirtualize, StaticConstructorBeforeFieldInit, + CustomAttributesRemoval, } bool? all; @@ -138,6 +140,11 @@ public bool? StaticConstructorBeforeFieldInit { set { values [(int) Opt.StaticConstructorBeforeFieldInit] = value; } } + public bool? CustomAttributesRemoval { + get { return values [(int) Opt.CustomAttributesRemoval]; } + set { values [(int) Opt.CustomAttributesRemoval] = value; } + } + public Optimizations () { values = new bool? [opt_names.Length]; @@ -294,6 +301,10 @@ public void Initialize (Application app) if (!StaticConstructorBeforeFieldInit.HasValue) StaticConstructorBeforeFieldInit = true; + // by default we remove rarely used custom attributes + if (!CustomAttributesRemoval.HasValue) + CustomAttributesRemoval = true; + if (Driver.Verbosity > 3) Driver.Log (4, "Enabled optimizations: {0}", string.Join (", ", values.Select ((v, idx) => v == true ? opt_names [idx] : string.Empty).Where ((v) => !string.IsNullOrEmpty (v)))); } diff --git a/tools/mmp/Tuning.cs b/tools/mmp/Tuning.cs index 78a572345e76..b2924840b6d4 100644 --- a/tools/mmp/Tuning.cs +++ b/tools/mmp/Tuning.cs @@ -160,19 +160,7 @@ static Pipeline CreatePipeline (LinkerOptions options) if (options.LinkMode != LinkMode.None) { pipeline.AppendStep (new CoreTypeMapStep ()); - var subdispatcher = new SubStepDispatcher { - new ApplyPreserveAttribute (), - new OptimizeGeneratedCodeSubStep (options), - new RemoveUserResourcesSubStep (), - new CoreRemoveAttributes (), - new CoreHttpMessageHandler (options), - new MarkNSObjects (), - }; - // CoreRemoveSecurity can modify non-linked assemblies - // but the conditions for this cannot happen if only the platform assembly is linked - if (options.LinkMode != LinkMode.Platform) - subdispatcher.Add (new CoreRemoveSecurity ()); - pipeline.AppendStep (subdispatcher); + pipeline.AppendStep (GetSubSteps (options)); pipeline.AppendStep (new MonoMacPreserveCode (options)); pipeline.AppendStep (new PreserveCrypto ()); @@ -200,6 +188,27 @@ static Pipeline CreatePipeline (LinkerOptions options) return pipeline; } + static SubStepDispatcher GetSubSteps (LinkerOptions options) + { + SubStepDispatcher sub = new SubStepDispatcher (); + sub.Add (new ApplyPreserveAttribute ()); + sub.Add (new OptimizeGeneratedCodeSubStep (options)); + sub.Add (new RemoveUserResourcesSubStep ()); + // OptimizeGeneratedCodeSubStep and RemoveUserResourcesSubStep needs [GeneratedCode] so it must occurs before RemoveAttributes + if (options.Application.Optimizations.CustomAttributesRemoval == true) + sub.Add (new CoreRemoveAttributes ()); + + sub.Add (new CoreHttpMessageHandler (options)); + sub.Add (new MarkNSObjects ()); + + // CoreRemoveSecurity can modify non-linked assemblies + // but the conditions for this cannot happen if only the platform assembly is linked + if (options.LinkMode != LinkMode.Platform) + sub.Add (new CoreRemoveSecurity ()); + + return sub; + } + static List ListAssemblies (LinkContext context) { var list = new List (); diff --git a/tools/mtouch/Tuning.cs b/tools/mtouch/Tuning.cs index edd05ca37b8e..72d46867f4d0 100644 --- a/tools/mtouch/Tuning.cs +++ b/tools/mtouch/Tuning.cs @@ -150,8 +150,8 @@ static SubStepDispatcher GetSubSteps (LinkerOptions options) sub.Add (new CoreRemoveSecurity ()); sub.Add (new OptimizeGeneratedCodeSubStep (options)); sub.Add (new RemoveUserResourcesSubStep (options)); - // OptimizeGeneratedCodeSubStep and RemoveUserResourcesSubStep needs [GeneratedCode] so it must occurs before RemoveAttributes - sub.Add (new RemoveAttributes ()); + if (options.Application.Optimizations.CustomAttributesRemoval == true) + sub.Add (new RemoveAttributes ()); // http://bugzilla.xamarin.com/show_bug.cgi?id=1408 if (options.LinkAway) sub.Add (new RemoveCode (options)); From 6944e1d678196315f8486c8279538d442d9834cd Mon Sep 17 00:00:00 2001 From: Sebastien Pouliot Date: Tue, 14 May 2019 10:10:01 -0700 Subject: [PATCH 2/3] Update docs/website/optimizations.md Co-Authored-By: Rolf Bjarne Kvinge --- docs/website/optimizations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/website/optimizations.md b/docs/website/optimizations.md index 295ce47972ba..18bf371facfd 100644 --- a/docs/website/optimizations.md +++ b/docs/website/optimizations.md @@ -754,4 +754,4 @@ your application you can disable this optimization, without totally disabling the managed linker. The default behavior can be overridden by passing -`--optimize=[+|-]custom-attributes-removal` to `mtouch`. +`--optimize=[+|-]custom-attributes-removal` to `mtouch` or `mmp`. From a1390133e3f17dc49a4b2530a69bfaaea1a47e79 Mon Sep 17 00:00:00 2001 From: Sebastien Pouliot Date: Wed, 15 May 2019 09:33:59 -0700 Subject: [PATCH 3/3] [tests] Adjust tests to consider the new optimization --- tests/mmptest/src/MMPTest.cs | 2 +- tests/mtouch/MTouch.cs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/mmptest/src/MMPTest.cs b/tests/mmptest/src/MMPTest.cs index b0bfb03cb7ab..fb41a7c21732 100644 --- a/tests/mmptest/src/MMPTest.cs +++ b/tests/mmptest/src/MMPTest.cs @@ -646,7 +646,7 @@ public void MM0132 (string opt) "Full", }; var rv = TI.TestUnifiedExecutable (test, shouldFail: false); - rv.Messages.AssertWarning (132, $"Unknown optimization: '{opt}'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, blockliteral-setupblock, register-protocols, inline-dynamic-registration-supported, static-block-to-delegate-lookup, trim-architectures, inline-is-arm64-calling-convention, cctor-beforefieldinit."); + rv.Messages.AssertWarning (132, $"Unknown optimization: '{opt}'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, blockliteral-setupblock, register-protocols, inline-dynamic-registration-supported, static-block-to-delegate-lookup, trim-architectures, inline-is-arm64-calling-convention, cctor-beforefieldinit, custom-attributes-removal."); rv.Messages.AssertErrorCount (0); }); } diff --git a/tests/mtouch/MTouch.cs b/tests/mtouch/MTouch.cs index 0fd6ef8ce0c2..8b64263d798b 100644 --- a/tests/mtouch/MTouch.cs +++ b/tests/mtouch/MTouch.cs @@ -1752,7 +1752,7 @@ public void MT0132 () mtouch.Linker = MTouchLinker.LinkSdk; mtouch.Optimize = new string [] { "foo" }; mtouch.AssertExecute (MTouchAction.BuildSim, "build"); - mtouch.AssertWarning (132, "Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, inline-runtime-arch, blockliteral-setupblock, register-protocols, inline-dynamic-registration-supported, static-block-to-delegate-lookup, remove-dynamic-registrar, remove-unsupported-il-for-bitcode, inline-is-arm64-calling-convention, seal-and-devirtualize, cctor-beforefieldinit."); + mtouch.AssertWarning (132, "Unknown optimization: 'foo'. Valid optimizations are: remove-uithread-checks, dead-code-elimination, inline-isdirectbinding, inline-intptr-size, inline-runtime-arch, blockliteral-setupblock, register-protocols, inline-dynamic-registration-supported, static-block-to-delegate-lookup, remove-dynamic-registrar, remove-unsupported-il-for-bitcode, inline-is-arm64-calling-convention, seal-and-devirtualize, cctor-beforefieldinit, custom-attributes-removal."); } } @@ -3575,7 +3575,8 @@ public void MT2003 () mtouch.AssertWarning (2003, "Option '--optimize=inline-is-arm64-calling-convention' will be ignored since linking is disabled"); mtouch.AssertWarning (2003, "Option '--optimize=seal-and-devirtualize' will be ignored since linking is disabled"); mtouch.AssertWarning (2003, "Option '--optimize=cctor-beforefieldinit' will be ignored since linking is disabled"); - mtouch.AssertWarningCount (13); + mtouch.AssertWarning (2003, "Option '--optimize=custom-attributes-removal' will be ignored since linking is disabled"); + mtouch.AssertWarningCount (14); } using (var mtouch = new MTouchTool ()) {