You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Mono.Android] avoid System.Reflection.Emit usage for common calls
`dotnet new android` calls `JNINativeWrapper.CreateDelegate()` twice,
while `dotnet new maui` ends up calling it 58 times during startup.
This code path calls System.Reflection.Emit to generate a
`System.Delegate` at runtime to be invoked. After some thought, it is
possible to "hard code" common delegate types and avoid SRE:
private static Delegate CreateBuiltInDelegate (Delegate dlg, Type delegateType)
{
switch (delegateType.Name) {
case nameof (_JniMarshal_PP_V): {
_JniMarshal_PP_V callback = (_JniMarshal_PP_V) Delegate.CreateDelegate (typeof (_JniMarshal_PP_V), dlg.Target, dlg.Method);
_JniMarshal_PP_V result = (jnienv, klazz) => {
JNIEnv.WaitForBridgeProcessing ();
try {
callback (jnienv, klazz);
} catch (Exception e) {
bool filter = Debugger.IsAttached || !JNIEnv.PropagateExceptions;
if (filter && JNIEnv.mono_unhandled_exception != null) {
JNIEnv.mono_unhandled_exception (e);
}
AndroidEnvironment.UnhandledException (e);
if (filter)
throw;
}
};
return result;
}
// etc.
`dotnet new maui`'s startup can be covered if we hardcoded:
_JniMarshal_PP_V
_JniMarshal_PPI_V
_JniMarshal_PPL_L
_JniMarshal_PPL_V
_JniMarshal_PPL_Z
_JniMarshal_PPII_V
_JniMarshal_PPLI_V
_JniMarshal_PPLL_V
_JniMarshal_PPLL_Z
_JniMarshal_PPIIL_V
_JniMarshal_PPILL_V
_JniMarshal_PPLIL_Z
_JniMarshal_PPLLL_L
_JniMarshal_PPLLL_Z
_JniMarshal_PPIIII_V
_JniMarshal_PPLLLL_V
_JniMarshal_PPLIIII_V
_JniMarshal_PPZIIII_V
_JniMarshal_PPLIIIIIIII_V
Then System.Reflection.Emit isn't used at all.
Other changes:
* `TypeManager.GetActivateHandler()` needs to use
`_JniMarshal_PPLLLL_V` instead of `Action<IntPtr, IntPtr, IntPtr,
IntPtr, IntPtr, IntPtr>`, so the fast path can be used.
* Added a log message for `debug.mono.log assembly`:
Falling back to System.Reflection.Emit for delegate type '{delegateType}': {dlg.Method}
* I was also able to remove `mono_unhandled_exception_method` from
`JNINativeWrapper` as we already has this value in `JNIEnv`.
~~ Results ~~
Testing `dotnet new maui` with version:
msbuild Xamarin.Android.sln -t:InstallMaui -bl -p:MauiVersion=6.0.200-preview.13.2536
A `Release` build on a Pixel 5 device, total startup time:
Before:
01-21 11:58:39.030 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s83ms
01-21 11:58:41.297 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s127ms
01-21 11:58:43.429 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s68ms
01-21 11:58:45.702 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s113ms
01-21 11:58:47.906 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s125ms
01-21 11:58:50.082 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s92ms
01-21 11:58:52.297 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s133ms
01-21 11:58:54.465 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s102ms
01-21 11:58:56.673 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s126ms
01-21 11:58:58.848 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s94ms
Average(ms): 1106.3
Std Err(ms): 6.91865433287267
Std Dev(ms): 21.8787060352704
After:
01-21 12:00:33.312 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s61ms
01-21 12:00:35.513 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s79ms
01-21 12:00:37.724 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s85ms
01-21 12:00:39.928 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s83ms
01-21 12:00:42.117 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s60ms
01-21 12:00:44.337 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s59ms
01-21 12:00:46.612 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s106ms
01-21 12:00:48.782 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s47ms
01-21 12:00:51.018 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s75ms
01-21 12:00:53.200 1867 2226 I ActivityTaskManager: Displayed com.companyname.bar/crc6474063b540de74d1e.MainActivity: +1s53ms
Average(ms): 1070.8
Std Err(ms): 5.68584988272544
Std Dev(ms): 17.9802360632137
This might save ~35ms on average?
If I time the message for one call, such as:
01-21 12:14:01.132 29819 29819 I monodroid-timing: Runtime.register: registering type `Microsoft.Maui.MauiApplication, Microsoft.Maui, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null`
01-21 12:14:01.150 29819 29819 I monodroid-timing: Runtime.register: end time; elapsed: 0s:17::794845
https://github.com/dotnet/maui/blob/bfba62ed796d3416c4fcaa7cfbea86dc8d5e04c2/src/Compatibility/ControlGallery/src/Android/MainApplication.cs
The result is:
Before:
01-21 13:21:22.261 9359 9359 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::868440
01-21 13:21:24.446 9424 9424 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::875159
01-21 13:21:26.639 9497 9497 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::829742
01-21 13:21:28.842 9570 9570 I monodroid-timing: Runtime.register: end time; elapsed: 0s:24::165211
01-21 13:21:31.021 9631 9631 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::976721
01-21 13:21:33.221 9697 9697 I monodroid-timing: Runtime.register: end time; elapsed: 0s:24::237034
01-21 13:21:35.418 9759 9759 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::857346
01-21 13:21:37.585 9821 9821 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::872138
01-21 13:21:39.805 9884 9884 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::840107
01-21 13:21:42.014 9952 9952 I monodroid-timing: Runtime.register: end time; elapsed: 0s:23::723805
Average(ms): 23.9245703
Std Err(ms): 0.0502830551065224
Std Dev(ms): 0.159008981848371
After:
01-21 13:22:28.004 10226 10226 I monodroid-timing: Runtime.register: end time; elapsed: 0s:18::12345
01-21 13:22:30.261 10298 10298 I monodroid-timing: Runtime.register: end time; elapsed: 0s:18::338022
01-21 13:22:32.443 10362 10362 I monodroid-timing: Runtime.register: end time; elapsed: 0s:18::56251
01-21 13:22:34.664 10427 10427 I monodroid-timing: Runtime.register: end time; elapsed: 0s:17::997397
01-21 13:22:36.902 10497 10497 I monodroid-timing: Runtime.register: end time; elapsed: 0s:17::787554
01-21 13:22:39.117 10563 10563 I monodroid-timing: Runtime.register: end time; elapsed: 0s:17::801772
01-21 13:22:41.306 10630 10630 I monodroid-timing: Runtime.register: end time; elapsed: 0s:18::28752
01-21 13:22:43.552 10695 10695 I monodroid-timing: Runtime.register: end time; elapsed: 0s:18::75522
01-21 13:22:45.761 10759 10759 I monodroid-timing: Runtime.register: end time; elapsed: 0s:17::958075
01-21 13:22:47.978 10823 10823 I monodroid-timing: Runtime.register: end time; elapsed: 0s:18::961773
Average(ms): 18.1017463
Std Err(ms): 0.107071213504746
Std Dev(ms): 0.338588906513177
Saving ~5.8ms for this one call.
monodroid_log(LogLevel.Warn,LogCategories.Default,$"typemap: failed to map managed type to Java type: {type.AssemblyQualifiedName} (Module ID: {type.Module.ModuleVersionId}; Type token: {type.MetadataToken})");
0 commit comments