[XamlC] fix loading ulongs, optimize bytecode for ulongs (#611)
authorStephane Delcroix <stephane@delcroix.org>
Mon, 12 Dec 2016 09:57:01 +0000 (10:57 +0100)
committerGitHub <noreply@github.com>
Mon, 12 Dec 2016 09:57:01 +0000 (10:57 +0100)
Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
Xamarin.Forms.Build.Tasks/XamlCTask.cs
Xamarin.Forms.Xaml.UnitTests/I8.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/I8.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/MockCompiler.cs
Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj

index 0c9b9e6..ec06879 100644 (file)
@@ -128,11 +128,11 @@ namespace Xamarin.Forms.Build.Tasks
                        else if (targetTypeRef.FullName == "System.Byte")
                                yield return Instruction.Create(OpCodes.Ldc_I4, Byte.Parse(str, CultureInfo.InvariantCulture));
                        else if (targetTypeRef.FullName == "System.UInt16")
-                               yield return Instruction.Create(OpCodes.Ldc_I4, UInt16.Parse(str, CultureInfo.InvariantCulture));
+                               yield return Instruction.Create(OpCodes.Ldc_I4, unchecked((int)UInt16.Parse(str, CultureInfo.InvariantCulture)));
                        else if (targetTypeRef.FullName == "System.UInt32")
                                yield return Instruction.Create(OpCodes.Ldc_I4, UInt32.Parse(str, CultureInfo.InvariantCulture));
                        else if (targetTypeRef.FullName == "System.UInt64")
-                               yield return Instruction.Create(OpCodes.Ldc_I8, UInt64.Parse(str, CultureInfo.InvariantCulture));
+                               yield return Instruction.Create(OpCodes.Ldc_I8, unchecked((long)UInt64.Parse(str, CultureInfo.InvariantCulture)));
                        else if (targetTypeRef.FullName == "System.Single")
                                yield return Instruction.Create(OpCodes.Ldc_R4, Single.Parse(str, CultureInfo.InvariantCulture));
                        else if (targetTypeRef.FullName == "System.Double")
index eda44a9..5127efd 100644 (file)
@@ -185,6 +185,7 @@ namespace Xamarin.Forms.Build.Tasks
                                        if (OptimizeIL)
                                        {
                                                Logger.LogString(2, "   Optimizing IL... ");
+                                               OptimizeLongs(initComp.Body);
                                                initComp.Body.OptimizeMacros();
                                                Logger.LogLine(2, "done");
                                        }
@@ -236,6 +237,28 @@ namespace Xamarin.Forms.Build.Tasks
                        return success;
                }
 
+               static void ExpandMacro(Instruction instruction, OpCode opcode, object operand)
+               {
+                       instruction.OpCode = opcode;
+                       instruction.Operand = operand;
+               }
+
+               //this can be removed if/when https://github.com/jbevain/cecil/pull/307 is released in a nuget we consume
+               static void OptimizeLongs(MethodBody self)
+               {
+                       var method = self.Method;
+                       for (var i = 0; i < self.Instructions.Count; i++) {
+                               var instruction = self.Instructions[i];
+                               if (instruction.OpCode.Code != Code.Ldc_I8)
+                                       continue;
+                               var l = (long)instruction.Operand;
+                               if (l < int.MinValue || l > int.MaxValue)
+                                       continue;
+                               ExpandMacro(instruction, OpCodes.Ldc_I4, unchecked((int)l));
+                               self.Instructions.Insert(++i, Instruction.Create(OpCodes.Conv_I8));
+                       }
+               }
+
                bool TryCoreCompile(MethodDefinition initComp, MethodDefinition initCompRuntime, ILRootNode rootnode, out Exception exception)
                {
                        try {
diff --git a/Xamarin.Forms.Xaml.UnitTests/I8.xaml b/Xamarin.Forms.Xaml.UnitTests/I8.xaml
new file mode 100644 (file)
index 0000000..09f2712
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ContentPage
+               xmlns="http://xamarin.com/schemas/2014/forms"
+               xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+               x:Class="Xamarin.Forms.Xaml.UnitTests.I8"
+               l0="0"
+               l1="2147483647"
+               l2="4294967295"
+               l3="9223372036854775807"
+               l4="-2147483647"
+               l5="-4294967295"
+               l6="-9223372036854775807"
+               l7="256"
+               l8="-256"
+               l9="127"
+               ul0="0"
+               ul1="2147483647"
+               ul2="4294967295"
+               ul3="9223372036854775807"
+               ul4="18446744073709551615"
+               ul5="256">
+</ContentPage>
diff --git a/Xamarin.Forms.Xaml.UnitTests/I8.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/I8.xaml.cs
new file mode 100644 (file)
index 0000000..4d7d874
--- /dev/null
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using Xamarin.Forms;
+using Xamarin.Forms.Core.UnitTests;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       public partial class I8 : ContentPage
+       {
+               public long l0 { get; set; }
+               public long l1 { get; set; }
+               public long l2 { get; set; }
+               public long l3 { get; set; }
+               public long l4 { get; set; }
+               public long l5 { get; set; }
+               public long l6 { get; set; }
+               public long l7 { get; set; }
+               public long l8 { get; set; }
+               public long l9 { get; set; }
+               public ulong ul0 { get; set; }
+               public ulong ul1 { get; set; }
+               public ulong ul2 { get; set; }
+               public ulong ul3 { get; set; }
+               public ulong ul4 { get; set; }
+               public ulong ul5 { get; set; }
+
+               public I8()
+               {
+                       InitializeComponent();
+               }
+
+               public I8(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;
+                       }
+
+                       [TestCase(false)]
+                       [TestCase(true)]
+                       public void I8AreConverted(bool useCompiledXaml)
+                       {
+                               var p = new I8(useCompiledXaml);
+                               Assert.AreEqual(0L, p.l0);
+                               Assert.AreEqual((long)int.MaxValue, p.l1);
+                               Assert.AreEqual((long)uint.MaxValue, p.l2);
+                               Assert.AreEqual(long.MaxValue, p.l3);
+                               Assert.AreEqual((long)-int.MaxValue, p.l4);
+                               Assert.AreEqual((long)-uint.MaxValue, p.l5);
+                               Assert.AreEqual(-long.MaxValue, p.l6);
+                               Assert.AreEqual((long)256, p.l7);
+                               Assert.AreEqual((long)-256, p.l8);
+                               Assert.AreEqual((long)127, p.l9);
+                               Assert.AreEqual(0L, p.ul0);
+                               Assert.AreEqual((long)int.MaxValue, p.ul1);
+                               Assert.AreEqual((long)uint.MaxValue, p.ul2);
+                               Assert.AreEqual(long.MaxValue, p.ul3);
+                               Assert.AreEqual(ulong.MaxValue, p.ul4);
+                               Assert.AreEqual((ulong)256, p.ul5);
+                       }
+               }
+       }
+}
\ No newline at end of file
index ccbfa20..6e63f6a 100644 (file)
@@ -19,6 +19,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                Assembly = assembly,
                                ReferencePath = string.Join(";", refs),
                                KeepXamlResources = true,
+                               OptimizeIL = true,
                                Type = type.FullName
                        };
 
index 5ce458c..2234c7f 100644 (file)
     <Compile Include="Issues\Bz46921.xaml.cs">
       <DependentUpon>Bz46921.xaml</DependentUpon>
     </Compile>
+     <Compile Include="I8.xaml.cs">
+       <DependentUpon>I8.xaml</DependentUpon>
+     </Compile>
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
     <EmbeddedResource Include="Issues\Bz46921.xaml">
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
+    <EmbeddedResource Include="I8.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />