diff --git a/docs/website/optimizations.md b/docs/website/optimizations.md
index 8808be9bdc15..18bf371facfd 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` or `mmp`.
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 ()) {
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));