Skip to content

Commit

Permalink
[net10.0] [dotnet] Rework aggressive attribute trimming. Fixes #20906. (
Browse files Browse the repository at this point in the history
#21314)

The aggressive attribute trimming as exposed by ILLink is undocumented and has
problematic behavior, so disable it (it can't be statically validated) -
ILLink already removed support for it anyway.

However, this has a somewhat significant size increase for our apps, and it
would affect pretty much every app, so re-implement the aggressive attribute
trimming ourselves.

This is accomplished by copying ILLink's list of attributes to remove into our
own xml definition, which we then pass to ILLink.

I tested a release build of monotouch-test for all platforms, and the final
size is almost entirely unchanged, except for a minimal size decrease.

Here's the results for iOS: https://gist.github.com/rolfbjarne/dac3e08620a3ae499ad1fc134765e0d2

Fixes #20906.
  • Loading branch information
rolfbjarne authored Oct 15, 2024
1 parent 2e29f35 commit b7a9096
Show file tree
Hide file tree
Showing 4 changed files with 390 additions and 19 deletions.
82 changes: 82 additions & 0 deletions docs/build-apps/build-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,85 @@ Example:
```

This property was introduced in .NET 9.

## MobileAggressiveAttributeTrimming

This property determines whether numerous attributes that are very rarely
needed at runtime should be trimmed away.

This is enabled by default.

Note that while the attributes that are removed are very rarely used, it's
technically possible that the removal can change runtime behavior.

For example, System.Xml.Serialization will behave differently if a constructor
has the `[Obsolete]` attribute (which is one of the attributes that are
removed). This is low enough risk to justify removing these attributes by
default because of the size savings.

The list of attributes that are removed may change in the future, but at the
time of this writing (for .NET 10), these are the attributes:

* Microsoft.CodeAnalysis.EmbeddedAttribute
* System.CLSCompliantAttribute
* System.CodeDom.Compiler.GeneratedCodeAttribute
* System.ComponentModel.EditorBrowsableAttribute
* System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute
* System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute
* System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute
* System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute
* System.Diagnostics.CodeAnalysis.ExperimentalAttribute
* System.Diagnostics.CodeAnalysis.FeatureGuardAttribute
* System.Diagnostics.CodeAnalysis.FeatureSwitchDefinitionAttribute
* System.Diagnostics.CodeAnalysis.MemberNotNullAttribute
* System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute
* System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute
* System.Diagnostics.CodeAnalysis.NotNullWhenAttribute
* System.Diagnostics.CodeAnalysis.RequiresAssemblyFilesAttribute
* System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute
* System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute
* System.Diagnostics.CodeAnalysis.StringSyntaxAttribute
* System.Diagnostics.CodeAnalysis.SuppressMessageAttribute
* System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute
* System.Diagnostics.CodeAnalysis.UnscopedRefAttribute
* System.ObsoleteAttribute
* System.Reflection.AssemblyCompanyAttribute
* System.Reflection.AssemblyConfigurationAttribute
* System.Reflection.AssemblyCopyrightAttribute
* System.Reflection.AssemblyDefaultAliasAttribute
* System.Reflection.AssemblyDescriptionAttribute
* System.Reflection.AssemblyMetadataAttribute
* System.Reflection.AssemblyProductAttribute
* System.Reflection.AssemblyTitleAttribute
* System.Runtime.CompilerServices.AsyncMethodBuilderAttribute
* System.Runtime.CompilerServices.CallerArgumentExpressionAttribute
* System.Runtime.CompilerServices.CallerFilePathAttribute
* System.Runtime.CompilerServices.CallerLineNumberAttribute
* System.Runtime.CompilerServices.CallerMemberNameAttribute
* System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute
* System.Runtime.CompilerServices.CompilerGlobalScopeAttribute
* System.Runtime.CompilerServices.EnumeratorCancellationAttribute
* System.Runtime.CompilerServices.ExtensionAttribute
* System.Runtime.CompilerServices.InterpolatedStringHandlerArgumentAttribute
* System.Runtime.CompilerServices.InterpolatedStringHandlerAttribute
* System.Runtime.CompilerServices.IntrinsicAttribute
* System.Runtime.CompilerServices.IsReadOnlyAttribute
* System.Runtime.CompilerServices.IsUnmanagedAttribute
* System.Runtime.CompilerServices.NativeIntegerAttribute
* System.Runtime.CompilerServices.RefSafetyRulesAttribute
* System.Runtime.CompilerServices.ScopedRefAttribute
* System.Runtime.CompilerServices.SkipLocalsInitAttribute
* System.Runtime.CompilerServices.TupleElementNamesAttribute
* System.Runtime.InteropServices.LibraryImportAttribute
* System.Runtime.InteropServices.Marshalling.ContiguousCollectionMarshallerAttribute
* System.Runtime.InteropServices.Marshalling.CustomMarshallerAttribute
* System.Runtime.InteropServices.Marshalling.MarshalUsingAttribute
* System.Runtime.InteropServices.Marshalling.NativeMarshallingAttribute
* System.Runtime.Versioning.NonVersionableAttribute
* System.Runtime.Versioning.ObsoletedOSPlatformAttribute
* System.Runtime.Versioning.RequiresPreviewFeaturesAttribute
* System.Runtime.Versioning.SupportedOSPlatformAttribute
* System.Runtime.Versioning.SupportedOSPlatformGuardAttribute
* System.Runtime.Versioning.TargetPlatformAttribute
* System.Runtime.Versioning.UnsupportedOSPlatformAttribute
* System.Runtime.Versioning.UnsupportedOSPlatformGuardAttribute
25 changes: 6 additions & 19 deletions dotnet/targets/Xamarin.Shared.Sdk.targets
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,6 @@
<!-- We don't need to generate reference assemblies for apps or app extensions -->
<ProduceReferenceAssembly Condition="'$(ProduceReferenceAssembly)' == '' And ('$(OutputType)' == 'Exe' Or '$(IsAppExtension)' == 'true')">false</ProduceReferenceAssembly>

<!--
With NativeAOT we want to prevent ILLink from removing attributes like `IsTrimmable` so further trimming can be done by the NativeAOT toolchain.
For this reason, in case of NativeAOT, we set _AggressiveAttributeTrimming to false by default and store the overwriten default in
_OriginalAggressiveAttributeTrimming property, which is later used to properly configure NativeAOT trimming.
-->
<_OriginalAggressiveAttributeTrimming>$(_AggressiveAttributeTrimming)</_OriginalAggressiveAttributeTrimming>
<_AggressiveAttributeTrimming Condition="'$(_UseNativeAot)' == 'true'">false</_AggressiveAttributeTrimming>
<_AggressiveAttributeTrimming Condition="'$(_AggressiveAttributeTrimming)' == ''">true</_AggressiveAttributeTrimming>

<!-- This property is also defined in Xamarin.Shared.props, but that file is imported too late for us to use the definition, and we can't remove it from Xamarin.Shared.props quite yet, because that would break legacy
(in other words: once we drop support for legacy Xamarin, we can remove the other definition) -->
<_CanOutputAppBundle Condition="'$(_CanOutputAppBundle)' == '' And ('$(OutputType)' == 'Exe' Or '$(IsAppExtension)' == 'true' Or '$(IsWatchApp)' == 'true')">true</_CanOutputAppBundle>
Expand Down Expand Up @@ -679,10 +670,16 @@
<!-- Linker -->
<_AdditionalTaskAssemblyDirectory>$(_XamarinSdkRootDirectoryOnMac)tools/dotnet-linker/</_AdditionalTaskAssemblyDirectory>
<_AdditionalTaskAssembly>$(_AdditionalTaskAssemblyDirectory)dotnet-linker.dll</_AdditionalTaskAssembly>

<MobileAggressiveAttributeTrimming Condition="'$(MobileAggressiveAttributeTrimming)' == ''">true</MobileAggressiveAttributeTrimming>
<_TrimAttributesLinkDescriptionPath>$(_XamarinSdkRootDirectory)tools/TrimAttributes.LinkDescription.xml</_TrimAttributesLinkDescriptionPath>
<_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --link-attributes $(_TrimAttributesLinkDescriptionPath)</_ExtraTrimmerArgs>
</PropertyGroup>

<ItemGroup>
<!-- Configure linker features -->
<RuntimeHostConfigurationOption Include="ObjCRuntime.AggressiveAttributeTrimming" Value="true" Trim="true" Condition="'$(MobileAggressiveAttributeTrimming)' == 'true'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.AggressiveAttributeTrimmingMono" Value="true" Trim="true" Condition="'$(MobileAggressiveAttributeTrimming)' == 'true' And '$(_XamarinRuntime)' == 'MonoVM'" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.Arch.IsSimulator" Value="$(_IsSimulatorFeature)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsManagedStaticRegistrar" Value="$(_IsManagedStaticRegistrarFeature)" Trim="true" />
<RuntimeHostConfigurationOption Include="ObjCRuntime.Runtime.IsNativeAOT" Value="$(_IsNativeAOTFeature)" Trim="true" />
Expand Down Expand Up @@ -1342,16 +1339,6 @@

<!-- Link in the output from ILC -->
<_NativeExecutableObjectFiles Include="$(NativeObject)" />

<!-- By default perform aggressive attribute trimming, except when explicitly disabled -->
<_TrimmerFeatureSettings Condition="'$(_OriginalAggressiveAttributeTrimming)' != 'false' and '%(Identity)' == 'System.AggressiveAttributeTrimming'">
<Value>true</Value>
<Trim>true</Trim>
</_TrimmerFeatureSettings>
<RuntimeHostConfigurationOption Condition="'$(_OriginalAggressiveAttributeTrimming)' != 'false' and '%(Identity)' == 'System.AggressiveAttributeTrimming'">
<Value>true</Value>
<Trim>true</Trim>
</RuntimeHostConfigurationOption>
</ItemGroup>

<ItemGroup>
Expand Down
11 changes: 11 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,17 @@ endef
# BuildDotNetPlatformAssembly (platform, platform.ToUpper (), platform.ToLower (), bitness)
$(foreach platform,$(DOTNET_PLATFORMS),$(foreach bitness, $(DOTNET_$(shell echo $(platform) | tr '[:lower:]' '[:upper:]')_BITNESSES), $(eval $(call BuildDotNetPlatformAssembly,$(platform),$(shell echo $(platform) | tr '[:lower:]' '[:upper:]'),$(shell echo $(platform) | tr '[:upper:]' '[:lower:]'),$(bitness)))))

define DefineTargets
$(1)_NUGET_TARGETS = \
$(DOTNET_DESTDIR)/$($(1)_NUGET_SDK_NAME)/tools/TrimAttributes.LinkDescription.xml \

$(DOTNET_DESTDIR)/$($(1)_NUGET_SDK_NAME)/tools/TrimAttributes.LinkDescription.xml: TrimAttributes.LinkDescription.xml
$$(Q) $(CP) $$< $$@

DOTNET_TARGETS += $$($(1)_NUGET_TARGETS)
endef
$(foreach platform,$(DOTNET_PLATFORMS),$(eval $(call DefineTargets,$(platform))))

#
# Global targets
#
Expand Down
Loading

6 comments on commit b7a9096

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ API diff for current PR / commit

.NET (No breaking changes)

✅ API diff vs stable

.NET (No breaking changes)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: b7a9096cd11963e47b3cc53be722c29872452a39 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build] Windows Integration Tests passed 💻

All Windows Integration Tests passed.

Pipeline on Agent
Hash: b7a9096cd11963e47b3cc53be722c29872452a39 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build] Tests on macOS X64 - Mac Sonoma (14) passed 💻

All tests on macOS X64 - Mac Sonoma (14) passed.

Pipeline on Agent
Hash: b7a9096cd11963e47b3cc53be722c29872452a39 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build] Tests on macOS M1 - Mac Monterey (12) passed 💻

All tests on macOS M1 - Mac Monterey (12) passed.

Pipeline on Agent
Hash: b7a9096cd11963e47b3cc53be722c29872452a39 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💻 [CI Build] Tests on macOS M1 - Mac Ventura (13) passed 💻

All tests on macOS M1 - Mac Ventura (13) passed.

Pipeline on Agent
Hash: b7a9096cd11963e47b3cc53be722c29872452a39 [CI build]

@vs-mobiletools-engineering-service2
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥 [CI Build] Test results 🔥

Test results

❌ Tests failed on VSTS: test results

1 tests crashed, 0 tests failed, 98 tests passed.

Failures

❌ dotnettests tests (tvOS)

🔥 Failed catastrophically on VSTS: test results - dotnettests_tvos (no summary found).

Html Report (VSDrops) Download

Successes

✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 1 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker: All 40 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 7 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 8 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 9 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 7 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

Pipeline on Agent
Hash: b7a9096cd11963e47b3cc53be722c29872452a39 [CI build]

Please sign in to comment.