-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[X] Simplify OnPlatformExtension (#4829)
When the platform is known at compile time, and it's known by default as we are multitargetting, replace OnPlatfomExtension by the actual value. This is done early in the parsing so every other optimization is unaffected. From a perf point of view, there are multiple gains: - OnPlatformExtension is executed at runtime, and makes use of reflection. Removing OnPlatformExtensions from the tree reduces this to nothing. - Values in OnPlatformExtension never benefitted from compiledtypeconverters - not generating the IL for the OnPlatform is huge win too. The unitest goes from 189 instructions to 42. fixes #4716
- Loading branch information
1 parent
48502e5
commit 43ca83b
Showing
8 changed files
with
158 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#nullable disable | ||
|
||
namespace Microsoft.Maui.Controls.Xaml | ||
{ | ||
class SimplifyOnPlatformVisitor : IXamlNodeVisitor | ||
{ | ||
public SimplifyOnPlatformVisitor(string targetFramework) | ||
{ | ||
TargetFramework = targetFramework; | ||
} | ||
|
||
public string TargetFramework { get; } | ||
|
||
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp; | ||
public bool StopOnDataTemplate => false; | ||
public bool VisitNodeOnDataTemplate => true; | ||
public bool StopOnResourceDictionary => false; | ||
public bool IsResourceDictionary(ElementNode node) => false; | ||
public bool SkipChildren(INode node, INode parentNode) => false; | ||
|
||
public void Visit(ValueNode node, INode parentNode) | ||
{ | ||
} | ||
|
||
public void Visit(MarkupNode node, INode parentNode) | ||
{ | ||
} | ||
|
||
public void Visit(ElementNode node, INode parentNode) | ||
{ | ||
if (node.XmlType.Name != nameof(OnPlatformExtension) || node.XmlType.NamespaceUri != XamlParser.MauiUri) | ||
return; | ||
if (string.IsNullOrEmpty(TargetFramework)) | ||
return; | ||
|
||
string target = null; | ||
if (TargetFramework.Contains("-android")) | ||
target = nameof(OnPlatformExtension.Android); | ||
if (TargetFramework.Contains("-ios")) | ||
target = nameof(OnPlatformExtension.iOS); | ||
if (TargetFramework.Contains("-macos")) | ||
target = nameof(OnPlatformExtension.macOS); | ||
if (TargetFramework.Contains("-maccatalyst")) | ||
target = nameof(OnPlatformExtension.MacCatalyst); | ||
|
||
if (target is null) | ||
return; | ||
|
||
if ( node.Properties.TryGetValue(new XmlName("", target), out INode targetNode) | ||
|| node.Properties.TryGetValue(new XmlName("", nameof(OnPlatformExtension.Default)), out targetNode)) | ||
{ | ||
if (!ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out XmlName name)) | ||
return; | ||
if (parentNode is IElementNode parentEnode) | ||
parentEnode.Properties[name] = targetNode; | ||
} | ||
else //no prop for target and no Default set | ||
{ | ||
if (!ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out XmlName name)) | ||
return; | ||
//if there's no value for the targetPlatform, ignore the node. | ||
//this is slightly different than what OnPlatform does (return default(T)) | ||
if (parentNode is IElementNode parentEnode) | ||
parentEnode.Properties.Remove(name); | ||
} | ||
|
||
} | ||
|
||
public void Visit(RootNode node, INode parentNode) | ||
{ | ||
} | ||
|
||
public void Visit(ListNode node, INode parentNode) | ||
{ | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
src/Controls/tests/Xaml.UnitTests/OnPlatformOptimization.xaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.OnPlatformOptimization"> | ||
<StackLayout> | ||
<Label x:Name="label0" | ||
Text="{OnPlatform Android='john', iOS='paul', Default='ringo' }" | ||
Padding="{OnPlatform iOS='2,3,4,5'}" /> | ||
|
||
</StackLayout> | ||
</ContentPage> |
50 changes: 50 additions & 0 deletions
50
src/Controls/tests/Xaml.UnitTests/OnPlatformOptimization.xaml.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using Microsoft.Maui.Controls; | ||
using Microsoft.Maui.Controls.Core.UnitTests; | ||
using Microsoft.Maui.Essentials; | ||
using NUnit.Framework; | ||
using Mono.Cecil.Cil; | ||
using Mono.Cecil; | ||
|
||
namespace Microsoft.Maui.Controls.Xaml.UnitTests | ||
{ | ||
public partial class OnPlatformOptimization : ContentPage | ||
{ | ||
public OnPlatformOptimization() | ||
{ | ||
InitializeComponent(); | ||
} | ||
|
||
public OnPlatformOptimization(bool useCompiledXaml) | ||
{ | ||
//this stub will be replaced at compile time | ||
} | ||
|
||
[TestFixture] | ||
public class Tests | ||
{ | ||
[SetUp] public void Setup() => Device.PlatformServices = new MockPlatformServices(); | ||
[TearDown] public void TearDown() => Device.PlatformServices = null; | ||
|
||
[Test] | ||
public void OnPlatformExtensionsAreSimplified([Values("net6.0-ios", "net6.0-android")] string targetFramework) | ||
{ | ||
MockCompiler.Compile(typeof(OnPlatformOptimization), out var methodDef, targetFramework); | ||
Assert.That(!methodDef.Body.Instructions.Any(instr=>InstructionIsOnPlatformExtensionCtor(methodDef, instr)), "This Xaml still generates a new OnPlatformExtension()"); | ||
} | ||
|
||
bool InstructionIsOnPlatformExtensionCtor(MethodDefinition methodDef, Mono.Cecil.Cil.Instruction instruction) | ||
{ | ||
if (instruction.OpCode != OpCodes.Newobj) | ||
return false; | ||
if (!(instruction.Operand is MethodReference methodRef)) | ||
return false; | ||
if (!Build.Tasks.TypeRefComparer.Default.Equals(methodRef.DeclaringType, methodDef.Module.ImportReference(typeof(OnPlatformExtension)))) | ||
return false; | ||
return true; | ||
} | ||
} | ||
} | ||
} |