-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
AggressiveInlining for custom markup extensions #17622
Comments
Pooling could be a simpler strategy for high-use extensions, such as localization. |
It might be obsolete with .NET 9/10 optimizations, as these should eliminate short living objects. |
What about:
Where it restricts markup extension, without allowing parameter options. |
maybe sometime it will be implemented and maybe it will work in some cases, hopefully case above, but let's be real :) |
maybe making a custom struct markup extension will work well, but still, the goal is not 4 lines of code, but 1, like x:Static. |
Ah, that's the exact same idea I had in my (now rather long) todo list! |
public static class FastMarkupExtension
{
public static struct FastMarkupExtensionParameters
{
public IServiceProvider ServiceProvider; // optional, special naming
public IProvideValueTarget ProvideValueTarget; // optional, special naming
[ConstructorArgument]
public string Arg1;
public string Arg2;
}
public static string ProvideValue(ref FastMarkupExtensionParameters args);
} |
Out of interest, I tried a couple of options in sharplab, to see how generated IL code looks like. For relatively simple ProvideValue implementation, there was virtually zero difference between ref or non-ref struct param, JIT was able to inline either of them, eliminating struct completely. And class markup extension wasn't inlined at all, allocating an object... In .NET Framework that is, and older Core runtimes.
I haven't tested, but complex ProvideValue code will likely prevent inlining, and likely return object allocation. But if ProvideValue kept simple enough by redirecting call to another static method, it might work good enough. |
Yep. Implemented inlining-friendly static resource extension, and it completely eliminated object allocation. - object? Old(IServiceProvider serviceProvider)
+ object? New(IServiceProvider serviceProvider)
{
- var ex = new StaticResourceExtension("SystemAccentColor");
+ var ex = new StaticResource2Extension("SystemAccentColor");
return ex.ProvideValue(serviceProvider);
} -; Assembly listing for method AvaloniaApplication5.CustomTheme:Old(System.IServiceProvider):System.Object:this (FullOpts)
+; Assembly listing for method AvaloniaApplication5.CustomTheme:New(System.IServiceProvider):System.Object:this (FullOpts)
; Emitting BLENDED_CODE for X64 with AVX - Windows
; FullOpts code
; optimized code
; rsp based frame
; fully interruptible
; No PGO data
-; 0 inlinees with PGO data; 3 single block inlinees; 0 inlinees without PGO data
+; 0 inlinees with PGO data; 5 single block inlinees; 0 inlinees without PGO data
G_M000_IG01:
- push rbx
- sub rsp, 32
- mov rbx, rdx
G_M000_IG02:
- mov rcx, 0xD1FFAB1E
- call CORINFO_HELP_NEWSFAST
- mov rcx, 0xD1FFAB1E
- mov gword ptr [rax+0x08], rcx
- mov rcx, rax
- mov rdx, rbx
+ mov rcx, rdx
+ mov rdx, 0xD1FFAB1E
G_M000_IG03:
- add rsp, 32
- pop rbx
- tail.jmp [Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension:ProvideValue(System.IServiceProvider):System.Object:this]
+ tail.jmp [Avalonia.Markup.Xaml.MarkupExtensions.StaticResource2Extension:ProvideValue(System.IServiceProvider,System.Object):System.Object]
-; Total bytes of code 54
+; Total bytes of code 19 |
Is your feature request related to a problem? Please describe.
We use around ~3k markup extensions in our app's markup - this is causing 10-100k redundant MarkupExtensions objects allocations on launch.
here is how
x:Static
works after xaml compilation forData="{x:Static Icons.Bool_Union}”
here is how markup extension works for
Header="{Loc BoolOperations_Union}"
Describe the solution you'd like
I see 2 solutions:
Describe alternatives you've considered
usage of x:Static is an option, but adds a lot of boilerplate on a large scale.
Compare:
{Loc AppHeader} - with an 10-line markup extension code
{x:Static Loc.AppHeader} and large code-generated 10k lines Loc static class with all the possible Loc properties.
Additional context
No response
The text was updated successfully, but these errors were encountered: