Skip to content

Commit

Permalink
[X] generate less IL for x:Array (#21615)
Browse files Browse the repository at this point in the history
- fixes #20745
  • Loading branch information
StephaneDelcroix committed May 20, 2024
1 parent 60a46c5 commit db7a6ff
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@ IEnumerable<Instruction> ProvideValue(TypeReference typeTypeRef, IReadOnlyList<I

for (var i = 0; i < n; i++)
{
var vardef = context.Variables[items[i] as IElementNode];
var node = items[i] as IElementNode;
var vardef = context.Variables[node];
var vardefref = new VariableDefinitionReference(vardef);
context.IL.Append(SetPropertiesVisitor.ProvideValue(vardefref, context, module, node as ElementNode));
if (vardef != vardefref.VariableDefinition)
{
vardef = vardefref.VariableDefinition;
context.Body.Variables.Add(vardef);
context.Variables[node] = vardef;
}

if (typeTypeRef.IsValueType)
{
yield return Instruction.Create(OpCodes.Dup);
Expand Down
60 changes: 32 additions & 28 deletions src/Controls/src/Build.Tasks/CreateObjectVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,38 @@ public void Visit(ElementNode node, INode parentNode)
var typeref = Module.ImportReference(node.XmlType.GetTypeReference(Context.Cache, Module, node));
TypeDefinition typedef = typeref.ResolveCached(Context.Cache);

if (typeref.FullName == "Microsoft.Maui.Controls.Xaml.ArrayExtension")
{
var visitor = new SetPropertiesVisitor(Context);
var children = node.Properties.Values.ToList();
children.AddRange(node.CollectionItems);
foreach (var cnode in children)
{
if (cnode is not IElementNode en)
continue;
foreach (var n in en.Properties.Values.ToList())
n.Accept(visitor, cnode);
foreach (var n in en.CollectionItems)
n.Accept(visitor, cnode);
}

var il = new ArrayExtension().ProvideValue(node, Module, Context, out typeref);
var vardef = new VariableDefinition(typeref);
Context.Variables[node] = vardef;
Context.Body.Variables.Add(vardef);

Context.IL.Append(il);
Context.IL.Emit(OpCodes.Stloc, vardef);

//clean the node as it has been fully exhausted
foreach (var prop in node.Properties)
if (!node.SkipProperties.Contains(prop.Key))
node.SkipProperties.Add(prop.Key);
node.CollectionItems.Clear();

return;
}

if (IsXaml2009LanguagePrimitive(node))
{
var vardef = new VariableDefinition(typeref);
Expand Down Expand Up @@ -216,34 +248,6 @@ public void Visit(ElementNode node, INode parentNode)
Context.IL.Emit(OpCodes.Ldloca, vardef);
Context.IL.Emit(OpCodes.Initobj, Module.ImportReference(typedef));
}

if (typeref.FullName == "Microsoft.Maui.Controls.Xaml.ArrayExtension")
{
var visitor = new SetPropertiesVisitor(Context);
foreach (var cnode in node.Properties.Values.ToList())
cnode.Accept(visitor, node);
foreach (var cnode in node.CollectionItems)
cnode.Accept(visitor, node);

markupProvider = new ArrayExtension();

var il = markupProvider.ProvideValue(node, Module, Context, out typeref);

vardef = new VariableDefinition(typeref);
Context.Variables[node] = vardef;
Context.Body.Variables.Add(vardef);

Context.IL.Append(il);
Context.IL.Emit(OpCodes.Stloc, vardef);

//clean the node as it has been fully exhausted
foreach (var prop in node.Properties)
if (!node.SkipProperties.Contains(prop.Key))
node.SkipProperties.Add(prop.Key);
node.CollectionItems.Clear();

return;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Controls/tests/Xaml.UnitTests/XArray.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:Microsoft.Maui.Controls.Xaml.UnitTests;assembly=Microsoft.Maui.Controls.Xaml.UnitTests"
x:Class="Microsoft.Maui.Controls.Xaml.UnitTests.XArray">
<x:Array Type="{x:Type sys:String}" x:Key="array">
<x:Array Type="{x:Type sys:String}" >
<x:String>Hello</x:String>
<x:String>World</x:String>
</x:Array>
Expand Down
24 changes: 21 additions & 3 deletions src/Controls/tests/Xaml.UnitTests/XArray.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using Microsoft.Maui.Controls;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
using NUnit.Framework;

namespace Microsoft.Maui.Controls.Xaml.UnitTests
Expand Down Expand Up @@ -38,6 +38,24 @@ public void SupportsXArray(bool useCompiledXaml)
Assert.AreEqual("Hello", ((string[])layout.Content)[0]);
Assert.AreEqual("World", ((string[])layout.Content)[1]);
}

[Test]
public void ArrayExtensionNotPresentInGeneratedCode([Values(false)] bool useCompiledXaml)
{
MockCompiler.Compile(typeof(XArray), out var methodDef);
Assert.That(!methodDef.Body.Instructions.Any(instr => InstructionIsArrayExtensionCtor(methodDef, instr)), "This Xaml still generates a new ArrayExtension()");
}

bool InstructionIsArrayExtensionCtor(MethodDefinition methodDef, Mono.Cecil.Cil.Instruction instruction)
{
if (instruction.OpCode != OpCodes.Newobj)
return false;
if (instruction.Operand is not MethodReference methodRef)
return false;
if (!Build.Tasks.TypeRefComparer.Default.Equals(methodRef.DeclaringType, methodDef.Module.ImportReference(typeof(ArrayExtension))))
return false;
return true;
}
}
}
}

0 comments on commit db7a6ff

Please sign in to comment.