diff --git a/Tests/Cosmos.Compiler.Tests.Bcl/System/Collections/Generic/ListTest.cs b/Tests/Cosmos.Compiler.Tests.Bcl/System/Collections/Generic/ListTest.cs index 1597474bd..c3090a0c6 100644 --- a/Tests/Cosmos.Compiler.Tests.Bcl/System/Collections/Generic/ListTest.cs +++ b/Tests/Cosmos.Compiler.Tests.Bcl/System/Collections/Generic/ListTest.cs @@ -2,33 +2,71 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; + using Cosmos.TestRunner; namespace Cosmos.Compiler.Tests.Bcl.System.Collections.Generic { public static class ListTest { - public static void Execute() { var xList = new List(); + Assert.AreEqual(0, xList.Count, "Count != 0 at start!"); + xList.Add(0); xList.Add(1); xList.Add(2); + Assert.AreEqual(3, xList.Count, "After adding 3 items, count != 3"); - Assert.AreEqual(0, xList[0], "List[0] != 0"); - Assert.AreEqual(1, xList[1], "List[1] != 1"); - Assert.AreEqual(2, xList[2], "List[2] != 2"); + Assert.AreEqual(0, xList[0], "List.Add: xList[0] != 0"); + Assert.AreEqual(1, xList[1], "List.Add: xList[1] != 1"); + Assert.AreEqual(2, xList[2], "List.Add: xList[2] != 2"); var xArray = xList.ToArray(); - Assert.AreEqual(3, xArray.Length, "xArray.Length != 3"); - Assert.AreEqual(0, xArray[0], "xArray[0] != 0"); - Assert.AreEqual(1, xArray[1], "xArray[1] != 1"); - Assert.AreEqual(2, xArray[2], "xArray[2] != 2"); + Assert.AreEqual(3, xArray.Length, "List.ToArray: xArray.Length != 3"); + Assert.AreEqual(0, xArray[0], "List.ToArray: xArray[0] != 0"); + Assert.AreEqual(1, xArray[1], "List.ToArray: xArray[1] != 1"); + Assert.AreEqual(2, xArray[2], "List.ToArray: xArray[2] != 2"); + xList.Insert(1, 5); + Assert.AreEqual(0, xList[0], "List.Insert: xList[0] != 0"); + Assert.AreEqual(5, xList[1], "List.Insert: xList[1] != 5"); + Assert.AreEqual(1, xList[2], "List.Insert: xList[2] != 1"); + Assert.AreEqual(2, xList[3], "List.Insert: xList[3] != 2"); + + xList.RemoveAt(2); + + Assert.AreEqual(0, xList[0], "List.RemoveAt: xList[0] != 0"); + Assert.AreEqual(5, xList[1], "List.RemoveAt: xList[1] != 5"); + Assert.AreEqual(2, xList[2], "List.RemoveAt: xList[2] != 2"); + + // Commented tests depend on #583 + + //xList.AddRange(new List() { 3, 4, 5 }); + + //Assert.AreEqual(0, xList[0], "List.AddRange: xList[0] != 0"); + //Assert.AreEqual(5, xList[1], "List.AddRange: xList[1] != 5"); + //Assert.AreEqual(2, xList[2], "List.AddRange: xList[2] != 2"); + //Assert.AreEqual(3, xList[2], "List.AddRange: xList[3] != 3"); + //Assert.AreEqual(4, xList[2], "List.AddRange: xList[4] != 4"); + //Assert.AreEqual(5, xList[2], "List.AddRange: xList[5] != 5"); + + //xList.RemoveRange(2, 2); + + //Assert.AreEqual(0, xList[0], "List.RemoveRange: xList[0] != 0"); + //Assert.AreEqual(5, xList[1], "List.RemoveRange: xList[1] != 5"); + //Assert.AreEqual(4, xList[2], "List.RemoveRange: xList[2] != 4"); + //Assert.AreEqual(5, xList[2], "List.RemoveRange: xList[3] != 5"); + + //var xRange = xList.GetRange(1, 3); + + //Assert.AreEqual(5, xRange[0], "List.GetRange: xRange[0] != 5"); + //Assert.AreEqual(4, xRange[1], "List.GetRange: xRange[1] != 4"); + //Assert.AreEqual(5, xRange[2], "List.GetRange: xRange[2] != 5"); } } -} \ No newline at end of file +} diff --git a/source/Cosmos.Core_Asm/Array/ArrayInternalCopyAsm.cs b/source/Cosmos.Core_Asm/Array/ArrayInternalCopyAsm.cs index b74d47d6e..63a4a0502 100644 --- a/source/Cosmos.Core_Asm/Array/ArrayInternalCopyAsm.cs +++ b/source/Cosmos.Core_Asm/Array/ArrayInternalCopyAsm.cs @@ -1,14 +1,15 @@ -using XSharp.Assembler; using Cosmos.IL2CPU.API; using XSharp; -using CPUx86 = XSharp.Assembler.x86; +using XSharp.Assembler; +using XSharp.Assembler.x86; +using static XSharp.XSRegisters; namespace Cosmos.Core_Asm { public class ArrayInternalCopyAsm : AssemblerMethod { private const int SourceArrayDisplacement = 36; - private const int SourceIndexDisplacement = 32; + private const int SourceIndexDisplacement = 28; private const int DestinationArrayDisplacement = 24; private const int DestinationIndexDisplacement = 16; private const int LengthDisplacement = 12; @@ -24,40 +25,152 @@ namespace Cosmos.Core_Asm public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { + var xArrayCopyReverseLabel = "ArrayCopy_Reverse"; + var xArrayCopyReverseLoopLabel = "ArrayCopy_Reverse_Loop"; + var xArrayCopyEndLabel = "ArrayCopy_End"; + XS.Comment("Source"); XS.Comment("Element size"); - XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: SourceArrayDisplacement); - XS.Add(XSRegisters.EAX, ObjectUtils.FieldDataOffset); - XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true); // element size + XS.Set(EAX, EBP, sourceDisplacement: SourceArrayDisplacement); + XS.Add(EAX, ObjectUtils.FieldDataOffset); + XS.Set(EAX, EAX, sourceIsIndirect: true); // element size XS.Comment("Source ptr"); - XS.Set(XSRegisters.EBX, XSRegisters.EBP, sourceDisplacement: SourceIndexDisplacement); - XS.Multiply(XSRegisters.EBX); - XS.Add(XSRegisters.EAX, ObjectUtils.FieldDataOffset + 4); // first element - XS.Set(XSRegisters.ESI, XSRegisters.EBP, sourceDisplacement: SourceArrayDisplacement); - XS.Add(XSRegisters.ESI, XSRegisters.EAX); // source ptr + XS.Set(EBX, EBP, sourceDisplacement: SourceIndexDisplacement); + XS.Multiply(EBX); + XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // first element + XS.Set(ESI, EBP, sourceDisplacement: SourceArrayDisplacement); + XS.Add(ESI, EAX); // source ptr XS.Comment("Destination"); XS.Comment("Element size"); - XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: DestinationArrayDisplacement); - XS.Add(XSRegisters.EAX, ObjectUtils.FieldDataOffset); - XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true); // element size + XS.Set(EAX, EBP, sourceDisplacement: DestinationArrayDisplacement); + XS.Add(EAX, ObjectUtils.FieldDataOffset); + XS.Set(EAX, EAX, sourceIsIndirect: true); // element size XS.Comment("Destination ptr"); - XS.Set(XSRegisters.ECX, XSRegisters.EBP, sourceDisplacement: DestinationIndexDisplacement); - XS.Multiply(XSRegisters.ECX); - XS.Add(XSRegisters.EAX, ObjectUtils.FieldDataOffset + 4); // first element - XS.Set(XSRegisters.EDI, XSRegisters.EBP, sourceDisplacement: DestinationArrayDisplacement); - XS.Add(XSRegisters.EDI, XSRegisters.EAX); // destination ptr + XS.Set(ECX, EBP, sourceDisplacement: DestinationIndexDisplacement); + XS.Multiply(ECX); + XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // first element + XS.Set(EDI, EBP, sourceDisplacement: DestinationArrayDisplacement); + XS.Add(EDI, EAX); // destination ptr + + XS.Compare(EDI, ESI); + XS.Jump(ConditionalTestEnum.Equal, xArrayCopyEndLabel); XS.Comment("Copy byte count"); XS.Comment("Element size"); - XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: DestinationArrayDisplacement); - XS.Add(XSRegisters.EAX, ObjectUtils.FieldDataOffset); - XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true); // element size + XS.Set(EAX, EBP, sourceDisplacement: DestinationArrayDisplacement); + XS.Add(EAX, ObjectUtils.FieldDataOffset); + XS.Set(EAX, EAX, sourceIsIndirect: true); // element size XS.Comment("Count"); - XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: LengthDisplacement); - XS.Multiply(XSRegisters.EDX); - XS.Set(XSRegisters.ECX, XSRegisters.EAX); - new CPUx86.Movs { Size = 8, Prefixes = CPUx86.InstructionPrefixes.Repeat }; + XS.Set(EDX, EBP, sourceDisplacement: LengthDisplacement); + + // if length is 0, jump to end + XS.Compare(EDX, 0); + XS.Jump(ConditionalTestEnum.Equal, xArrayCopyEndLabel); + + XS.Multiply(EDX); + XS.Set(ECX, EAX); + + // if source and destination are equal, jump to end + XS.Set(EAX, ESI); + XS.Add(EAX, ECX); + XS.Compare(EDI, EAX); + XS.Jump(ConditionalTestEnum.Equal, xArrayCopyEndLabel); + XS.Jump(ConditionalTestEnum.LessThanOrEqualTo, xArrayCopyReverseLabel); + + new Movs { Size = 8, Prefixes = InstructionPrefixes.Repeat }; + + XS.Jump(xArrayCopyEndLabel); + + // source ptr + size >= destination ptr + XS.Label(xArrayCopyReverseLabel); + + XS.Comment("Array Reverse Copy: source ptr + size >= destination ptr"); + + XS.Add(ESI, ECX); + XS.Add(EDI, ECX); + + XS.Label(xArrayCopyReverseLoopLabel); + + XS.Decrement(ESI); + XS.Decrement(EDI); + XS.Decrement(ECX); + + XS.Set(AL, ESI, sourceIsIndirect: true); + XS.Set(EDI, AL, destinationIsIndirect: true); + + XS.Compare(ECX, 0); + XS.Jump(ConditionalTestEnum.NotEqual, xArrayCopyReverseLoopLabel); + + XS.Label(xArrayCopyEndLabel); } } } + +// Old implementation +// (it's a good memcpy implementation, as it doesn't check for array overlapping, so it can't be used for Array.Copy) + +//using Cosmos.Assembler; +//using Cosmos.Assembler.x86; +//using Cosmos.IL2CPU.API; +//using XSharp.Common; +//using static XSharp.Common.XSRegisters; + +//namespace Cosmos.Core_Asm +//{ +// public class ArrayInternalCopyAsm : AssemblerMethod +// { +// private const int SourceArrayDisplacement = 36; +// private const int SourceIndexDisplacement = 28; +// private const int DestinationArrayDisplacement = 24; +// private const int DestinationIndexDisplacement = 16; +// private const int LengthDisplacement = 12; + +// /* void Copy( +// * Array sourceArray, ebp + 36 +// * int sourceIndex, ebp + 28 +// * Array destinationArray, ebp + 24 +// * int destinationIndex, ebp + 16 +// * int length, ebp + 12 +// * bool reliable); ebp + 8 +// */ + +// public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) +// { +// XS.Comment("Source"); +// XS.Comment("Element size"); +// XS.Set(EAX, EBP, sourceDisplacement: SourceArrayDisplacement); +// XS.Add(EAX, ObjectUtils.FieldDataOffset); +// XS.Set(EAX, EAX, sourceIsIndirect: true); // element size +// XS.Comment("Source ptr"); +// XS.Set(EBX, EBP, sourceDisplacement: SourceIndexDisplacement); +// XS.Multiply(EBX); +// XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // first element +// XS.Set(ESI, EBP, sourceDisplacement: SourceArrayDisplacement); +// XS.Add(ESI, EAX); // source ptr + +// XS.Comment("Destination"); +// XS.Comment("Element size"); +// XS.Set(EAX, EBP, sourceDisplacement: DestinationArrayDisplacement); +// XS.Add(EAX, ObjectUtils.FieldDataOffset); +// XS.Set(EAX, EAX, sourceIsIndirect: true); // element size +// XS.Comment("Destination ptr"); +// XS.Set(ECX, EBP, sourceDisplacement: DestinationIndexDisplacement); +// XS.Multiply(ECX); +// XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // first element +// XS.Set(EDI, EBP, sourceDisplacement: DestinationArrayDisplacement); +// XS.Add(EDI, EAX); // destination ptr + +// XS.Comment("Copy byte count"); +// XS.Comment("Element size"); +// XS.Set(EAX, EBP, sourceDisplacement: DestinationArrayDisplacement); +// XS.Add(EAX, ObjectUtils.FieldDataOffset); +// XS.Set(EAX, EAX, sourceIsIndirect: true); // element size +// XS.Comment("Count"); +// XS.Set(EDX, EBP, sourceDisplacement: LengthDisplacement); +// XS.Multiply(EDX); +// XS.Set(ECX, EAX); +// new Movs { Size = 8, Prefixes = InstructionPrefixes.Repeat }; +// } +// } +//} diff --git a/source/Cosmos.Core_Asm/Buffer/BufferBlockCopyAsm.cs b/source/Cosmos.Core_Asm/Buffer/BufferBlockCopyAsm.cs index 841f54c08..fa8dfc10f 100644 --- a/source/Cosmos.Core_Asm/Buffer/BufferBlockCopyAsm.cs +++ b/source/Cosmos.Core_Asm/Buffer/BufferBlockCopyAsm.cs @@ -14,9 +14,9 @@ namespace Cosmos.Core_Asm private const int CountDisplacement = 8; /*public static void BlockCopy( - * Array src, [ebp + 24] - * int srcOffset, [ebp + 20] - * Array dst, [ebp + 16] + * Array src, [ebp + 32] + * int srcOffset, [ebp + 24] + * Array dst, [ebp + 20] * int dstOffset, [ebp + 12] * int count); [ebp + 8] */ diff --git a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs index 9b741d099..7d64409da 100644 --- a/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs +++ b/source/Cosmos.Core_Asm/CPU/CPUUpdateIDTAsm.cs @@ -8,7 +8,6 @@ using static XSharp.XSRegisters; namespace Cosmos.Core_Asm { - //TODO: This asm refs Hardware.. should not.. its a higher ring public class CPUUpdateIDTAsm : AssemblerMethod { private static MethodBase GetMethodDef(Assembly aAssembly, string aType, string aMethodName, bool aErrorWhenNotFound)