From 2d817c5e6d962c0eb0dd1ad62627e6c4e09fcf11 Mon Sep 17 00:00:00 2001 From: Andrey Kurdyumov Date: Sun, 18 Jan 2015 19:41:30 +0600 Subject: [PATCH 1/2] Add plug for Buffer.__Mmmove on the .NET 4.6 --- .../Cosmos.IL2CPU.Tests.csproj | 90 ++++++++++++++ .../Plugs/System/BufferTests.cs | 81 ++++++++++++ .../Properties/AssemblyInfo.cs | 36 ++++++ source/Cosmos.IL2CPU/ILOpCodes/OpSwitch.cs | 1 + source/Cosmos.IL2CPU/Plugs/System/Buffer.cs | 115 ++++++++++++++++++ source/Cosmos.sln | 15 +++ 6 files changed, 338 insertions(+) create mode 100644 source/Cosmos.IL2CPU.Tests/Cosmos.IL2CPU.Tests.csproj create mode 100644 source/Cosmos.IL2CPU.Tests/Plugs/System/BufferTests.cs create mode 100644 source/Cosmos.IL2CPU.Tests/Properties/AssemblyInfo.cs diff --git a/source/Cosmos.IL2CPU.Tests/Cosmos.IL2CPU.Tests.csproj b/source/Cosmos.IL2CPU.Tests/Cosmos.IL2CPU.Tests.csproj new file mode 100644 index 000000000..71d5e1bf8 --- /dev/null +++ b/source/Cosmos.IL2CPU.Tests/Cosmos.IL2CPU.Tests.csproj @@ -0,0 +1,90 @@ + + + + Debug + AnyCPU + {17329379-67D5-45D2-8EF0-9C625C43E117} + Library + Properties + Cosmos.IL2CPU.Tests + Cosmos.IL2CPU.Tests + v4.5 + 512 + {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages + False + UnitTest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + {239e33a7-f0c3-4801-85ca-4d8f89a31dc0} + Cosmos.IL2CPU + + + + + + + False + + + False + + + False + + + False + + + + + + + + \ No newline at end of file diff --git a/source/Cosmos.IL2CPU.Tests/Plugs/System/BufferTests.cs b/source/Cosmos.IL2CPU.Tests/Plugs/System/BufferTests.cs new file mode 100644 index 000000000..6674d496b --- /dev/null +++ b/source/Cosmos.IL2CPU.Tests/Plugs/System/BufferTests.cs @@ -0,0 +1,81 @@ +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using TargetClass = Cosmos.IL2CPU.X86.Plugs.CustomImplementations.System.Buffer; + +namespace Cosmos.IL2CPU.Tests.Plugs.System +{ + /// + /// Tests for the class plugs + /// + [TestClass] + public class BufferTests + { + /// + /// Verifies that non overlapped memory working. + /// + [TestMethod] + public unsafe void MemmoveNonOverlappedMemory() + { + byte[] src = new byte[10]; + for (var i = 0; i < src.Length; i++) + { + src[i] = (byte)(i + 10); + } + + byte[] dest = new byte[100]; + dest[6] = 255; + fixed (byte* destPtr = dest, srcPtr = src) + { + TargetClass.__Memmove(destPtr, srcPtr, 5); + } + + CollectionAssert.AreNotEquivalent( + new[] { 10, 11, 12, 13, 14, 0 }, + dest.Take(6).ToArray()); + } + + /// + /// Verifies that overlapped memory regions working when copy forward + /// + [TestMethod] + public unsafe void MemmoveOverlappedMemory() + { + byte[] data = new byte[100]; + for (var i = 0; i < data.Length; i++) + { + data[i] = (byte)(i + 10); + } + + fixed (byte* destPtr = data, srcPtr = &data[1]) + { + TargetClass.__Memmove(destPtr, srcPtr, 5); + } + + CollectionAssert.AreNotEquivalent( + new[] { 11, 12, 13, 14, 15, 15, 16, 17, 18 }, + data.Take(9).ToArray()); + } + + /// + /// Verifies that overlapped memory regions working when copy backward + /// + [TestMethod] + public unsafe void MemmoveOverlappedMemory2() + { + byte[] data = new byte[100]; + for (var i = 0; i < data.Length; i++) + { + data[i] = (byte)(i + 10); + } + + fixed (byte* destPtr = &data[1], srcPtr = data) + { + TargetClass.__Memmove(destPtr, srcPtr, 5); + } + + CollectionAssert.AreNotEquivalent( + new [] { 10, 10, 11, 12, 13, 14, 16 }, + data.Take(7).ToArray()); + } + } +} diff --git a/source/Cosmos.IL2CPU.Tests/Properties/AssemblyInfo.cs b/source/Cosmos.IL2CPU.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..521529613 --- /dev/null +++ b/source/Cosmos.IL2CPU.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Cosmos.IL2CPU.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Cosmos.IL2CPU.Tests")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a719fc5b-ddd5-46d0-9d22-e42d77b809f9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/source/Cosmos.IL2CPU/ILOpCodes/OpSwitch.cs b/source/Cosmos.IL2CPU/ILOpCodes/OpSwitch.cs index 42823c13b..b1df9ca34 100644 --- a/source/Cosmos.IL2CPU/ILOpCodes/OpSwitch.cs +++ b/source/Cosmos.IL2CPU/ILOpCodes/OpSwitch.cs @@ -63,6 +63,7 @@ namespace Cosmos.IL2CPU.ILOpCodes { } if (StackPopTypes[0] == typeof(int) || + StackPopTypes[0] == typeof(uint) || StackPopTypes[0] == typeof(byte)) { return; diff --git a/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs b/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs index fce0adff7..8b5a78983 100644 --- a/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs +++ b/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs @@ -13,6 +13,121 @@ namespace Cosmos.IL2CPU.X86.Plugs.CustomImplementations.System { global::System.Buffer.BlockCopy((Array)(object)*src, 0, (Array)(object)*dest, 0, count); } + /// + /// The memmove() function copies n bytes from memory area src to memory area dest. + /// The memory areas may overlap: copying takes place as though the bytes in src + /// are first copied into a temporary array that does not overlap src or dest, + /// and the bytes are then copied from the temporary array to dest. + /// + /// Destination address to copy data into. + /// Source address from where copy data. + /// Count of bytes to copy. + public static unsafe void __Memmove(byte* dest, byte* src, uint count) + { + uint t; + const int wmask = 0xFFFF; + const int wsize = 2; + + /* nothing to do */ + if (count == 0 || dest == src) { + return; + } + + if ((ulong)dest < (ulong)src) { + /* Copy forward. */ + t = (uint)src; + + /* only need low bits */ + if (((t | (uint)dest) & wmask) != 0) { + /* + * Try to align operands. This cannot be done + * unless the low bits match. + */ + if ((((t ^ (int)dest) & wmask) != 0) || (count < wsize)) + t = count; + else + t = wsize - (t & wmask); + count -= t; + if (t != 0) + { + do { *dest++ = *src++; } + while (--t != 0); + } + } + + /* + * Copy whole words, then mop up any trailing bytes. + */ + t = count / wsize; + if (t != 0) + { + do { + *(short*)dest = *(short*)src; + src += wsize; + dest += wsize; } + while (--t != 0); + } + + t = count & wmask; + if (t != 0) + { + do { + dest++; + src++; + *dest = *src; + } + while (--t != 0); + } + } else { + /* + * Copy backwards. Otherwise essentially the same. + * Alignment works as before, except that it takes + * (t&wmask) bytes to align, not wsize-(t&wmask). + */ + src += count; + dest += count; + t = (uint)src; + if (((t | (uint)dest) & wmask) != 0) { + if (((t ^ (uint)dest) & wmask) != 0 || count <= wsize) + t = count; + else + t &= wmask; + count -= t; + if (t != 0) + { + do { + --dest; + --src; + *dest = *src; } + while (--t != 0); + } + } + t = count / wsize; + if (t != 0) + { + do + { + src -= wsize; + dest -= wsize; + *(ushort*)dest = *(ushort*)src; + } + while (--t != 0); + } + + t = count & wmask; + if (t != 0) + { + do + { + --dest; + --src; + *dest = *src; + } + while (--t != 0); + } + } + } + [PlugMethod(Assembler = typeof(Assemblers.Buffer_BlockCopy))] public static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count) { } diff --git a/source/Cosmos.sln b/source/Cosmos.sln index 21f13a80d..6c87052b9 100644 --- a/source/Cosmos.sln +++ b/source/Cosmos.sln @@ -203,6 +203,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IL2CPU", "IL2CPU\IL2CPU.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlaygroundCore", "..\Users\Matthijs\PlaygroundCore\PlaygroundCore.csproj", "{AB869246-4887-4117-851D-766EB9FF1E29}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cosmos.IL2CPU.Tests", "Cosmos.IL2CPU.Tests\Cosmos.IL2CPU.Tests.csproj", "{17329379-67D5-45D2-8EF0-9C625C43E117}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -988,6 +990,18 @@ Global {AB869246-4887-4117-851D-766EB9FF1E29}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {AB869246-4887-4117-851D-766EB9FF1E29}.Release|Mixed Platforms.Build.0 = Release|Any CPU {AB869246-4887-4117-851D-766EB9FF1E29}.Release|x86.ActiveCfg = Release|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Debug|Itanium.ActiveCfg = Debug|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Debug|x86.ActiveCfg = Debug|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Release|Any CPU.Build.0 = Release|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Release|Itanium.ActiveCfg = Release|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {17329379-67D5-45D2-8EF0-9C625C43E117}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1064,5 +1078,6 @@ Global {7E059184-F2C5-4CC6-B86D-FA12590C3C40} = {F104F6BC-EF8E-4408-A786-D570D7565231} {6128DEEB-D30F-4859-B60F-C36D5452F3E9} = {6A15C540-8278-4B9C-B890-FA57FB6AE6A6} {AB869246-4887-4117-851D-766EB9FF1E29} = {A0073D91-D9D3-4A90-9845-10E5CDBA5511} + {17329379-67D5-45D2-8EF0-9C625C43E117} = {6A15C540-8278-4B9C-B890-FA57FB6AE6A6} EndGlobalSection EndGlobal From fd5d2ae3dbf7f64a90a61f7bf614fe478540669f Mon Sep 17 00:00:00 2001 From: Andrey Kurdyumov Date: Sun, 18 Jan 2015 19:46:48 +0600 Subject: [PATCH 2/2] Add formatting --- source/Cosmos.IL2CPU/Plugs/System/Buffer.cs | 211 ++++++++++---------- 1 file changed, 111 insertions(+), 100 deletions(-) diff --git a/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs b/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs index 8b5a78983..751e87496 100644 --- a/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs +++ b/source/Cosmos.IL2CPU/Plugs/System/Buffer.cs @@ -22,111 +22,122 @@ namespace Cosmos.IL2CPU.X86.Plugs.CustomImplementations.System { /// Destination address to copy data into. /// Source address from where copy data. /// Count of bytes to copy. - public static unsafe void __Memmove(byte* dest, byte* src, uint count) - { - uint t; - const int wmask = 0xFFFF; - const int wsize = 2; + public static unsafe void __Memmove(byte* dest, byte* src, uint count) + { + uint t; + const int wmask = 0xFFFF; + const int wsize = 2; - /* nothing to do */ - if (count == 0 || dest == src) { - return; - } + /* nothing to do */ + if (count == 0 || dest == src) + { + return; + } + + if ((ulong)dest < (ulong)src) + { + /* Copy forward. */ + t = (uint)src; - if ((ulong)dest < (ulong)src) { - /* Copy forward. */ - t = (uint)src; - /* only need low bits */ - if (((t | (uint)dest) & wmask) != 0) { - /* - * Try to align operands. This cannot be done - * unless the low bits match. - */ - if ((((t ^ (int)dest) & wmask) != 0) || (count < wsize)) - t = count; - else - t = wsize - (t & wmask); - count -= t; - if (t != 0) - { - do { *dest++ = *src++; } - while (--t != 0); - } - } + if (((t | (uint)dest) & wmask) != 0) + { + /* + * Try to align operands. This cannot be done + * unless the low bits match. + */ + if ((((t ^ (int)dest) & wmask) != 0) || (count < wsize)) + t = count; + else + t = wsize - (t & wmask); + count -= t; + if (t != 0) + { + do { *dest++ = *src++; } + while (--t != 0); + } + } - /* - * Copy whole words, then mop up any trailing bytes. - */ - t = count / wsize; - if (t != 0) - { - do { - *(short*)dest = *(short*)src; - src += wsize; - dest += wsize; } - while (--t != 0); - } - - t = count & wmask; - if (t != 0) - { - do { - dest++; - src++; - *dest = *src; - } - while (--t != 0); - } - } else { - /* - * Copy backwards. Otherwise essentially the same. - * Alignment works as before, except that it takes - * (t&wmask) bytes to align, not wsize-(t&wmask). - */ - src += count; - dest += count; - t = (uint)src; - if (((t | (uint)dest) & wmask) != 0) { - if (((t ^ (uint)dest) & wmask) != 0 || count <= wsize) - t = count; - else - t &= wmask; - count -= t; - if (t != 0) - { - do { - --dest; - --src; - *dest = *src; } - while (--t != 0); - } - } - t = count / wsize; - if (t != 0) - { - do - { - src -= wsize; - dest -= wsize; - *(ushort*)dest = *(ushort*)src; - } - while (--t != 0); - } + /* + * Copy whole words, then mop up any trailing bytes. + */ + t = count / wsize; + if (t != 0) + { + do + { + *(short*)dest = *(short*)src; + src += wsize; + dest += wsize; + } + while (--t != 0); + } - t = count & wmask; - if (t != 0) - { - do - { - --dest; - --src; - *dest = *src; - } - while (--t != 0); - } - } - } + t = count & wmask; + if (t != 0) + { + do + { + dest++; + src++; + *dest = *src; + } + while (--t != 0); + } + } + else + { + /* + * Copy backwards. Otherwise essentially the same. + * Alignment works as before, except that it takes + * (t&wmask) bytes to align, not wsize-(t&wmask). + */ + src += count; + dest += count; + t = (uint)src; + if (((t | (uint)dest) & wmask) != 0) + { + if (((t ^ (uint)dest) & wmask) != 0 || count <= wsize) + t = count; + else + t &= wmask; + count -= t; + if (t != 0) + { + do + { + --dest; + --src; + *dest = *src; + } + while (--t != 0); + } + } + t = count / wsize; + if (t != 0) + { + do + { + src -= wsize; + dest -= wsize; + *(ushort*)dest = *(ushort*)src; + } + while (--t != 0); + } + + t = count & wmask; + if (t != 0) + { + do + { + --dest; + --src; + *dest = *src; + } + while (--t != 0); + } + } + } [PlugMethod(Assembler = typeof(Assemblers.Buffer_BlockCopy))] public static void BlockCopy(Array src, int srcOffset, Array dst, int dstOffset, int count) {