Description
Description
In .NET 9 we enabled managed-static registrar to be the default setting when targeting iOS platforms with Mono.
This change regressed MAUI sample application size when targeting iOS by ~2-3%
as reported in: #20174
The reason for the regression is generating more managed code which needs to be AOT-compiled.
During some investigation I noticed that after we run ILStrip (Mono's size-optimization task which removes unneeded IL code from assemblies which are preserved mostly for metadata information and reflection support) we keep UnmanagedCallersOnly
attributes data on methods which are generated for the new registrar, for example:
.class auto ansi sealed nested assembly __Registrar_Callbacks__
extends [System.Private.CoreLib]System.Object
{
.method public hidebysig static valuetype [Microsoft.iOS]ObjCRuntime.NativeHandle
callback_0_Eone_AppDelegate_get_Window(native int pobj,
native int sel,
native int* exception_gchandle) cil managed noinlining
{
.custom instance void [System.Private.CoreLib]System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute::.ctor() = ( 01 00 01 00 53 0E 0A 45 6E 74 72 79 50 6F 69 6E // ....S..EntryPoin
74 26 63 61 6C 6C 62 61 63 6B 5F 30 5F 45 6F 6E // t&callback_0_Eon
65 5F 41 70 70 44 65 6C 65 67 61 74 65 5F 67 65 // e_AppDelegate_ge
74 5F 57 69 6E 64 6F 77 ) // t_Window
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method __Registrar_Callbacks__::callback_0_Eone_AppDelegate_get_Window
...
Here we can see a size-saving opportunity, specifically in regard to EntryPoint
values on UCO methods which are not needed or used during runtime.
SIze-saving
By creating a simple Mono.Cecil
task which strips out only custom attributes from methods defined on __Registrar_Callbacks__
types from stripped assemblies of the app, it has been estimated that with a dotnet new maui
app and .NET 9 GA SDK we could save ~2%
of the application size when using Mono with this approach.
NOTE: The save saving is currently applicable only to Mono, as with Native AOT we do not need/keep managed assemblies in the application bundle.
Comparing managed-static registrar without and with UCO EntryPoint
stripping with .NET 9 GA
dotnet new maui | managed-static | managed-static w stripped UCOs | diff (%) |
---|---|---|---|
SOD (MB) | 44,08 | 43,04 | -2,36% |
.ipa (MB) | 15,45 | 15,07 | -2,46% |
Comparing static with managed-static registrar and UCO EntryPoint
stripping with .NET 9 GA
Such an improvement would make the app sizes between the new managed-static and the old static registrar almost identical.
dotnet new maui | static | managed-static w stripped UCOs | diff (%) |
---|---|---|---|
SOD (MB) | 42,87 | 43,04 | 0,39% |
.ipa (MB) | 15,14 | 15,07 | -0,47% |
Proposal
Investigate adapting https://github.com/dotnet/runtime/tree/e7d837da5b1aacd9325a8b8f2214cfaf4d3f0ff6/src/tasks/MonoTargetsTasks/ILStrip/AssemblyStripper
so that it strips out EntryPoint
values on UCO methods introduced for managed-static registrar and measure the actual size saving.