diff --git a/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeNode.cs b/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeNode.cs index 8480d51ad6..29d2d0c9a8 100644 --- a/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeNode.cs +++ b/src/Ryujinx.Common/Collections/IntrusiveRedBlackTreeNode.cs @@ -5,10 +5,10 @@ namespace Ryujinx.Common.Collections /// public class IntrusiveRedBlackTreeNode where T : IntrusiveRedBlackTreeNode { - internal bool Color = true; - internal T Left; - internal T Right; - internal T Parent; + public bool Color = true; + public T Left; + public T Right; + public T Parent; public T Predecessor => IntrusiveRedBlackTreeImpl.PredecessorOf((T)this); public T Successor => IntrusiveRedBlackTreeImpl.SuccessorOf((T)this); diff --git a/src/Ryujinx.Cpu/Jit/AddressIntrusiveRedBlackTree.cs b/src/Ryujinx.Cpu/Jit/AddressIntrusiveRedBlackTree.cs new file mode 100644 index 0000000000..3084d16d10 --- /dev/null +++ b/src/Ryujinx.Cpu/Jit/AddressIntrusiveRedBlackTree.cs @@ -0,0 +1,35 @@ +using Ryujinx.Common.Collections; +using System; + +namespace Ryujinx.Cpu.Jit +{ + internal class AddressIntrusiveRedBlackTree : IntrusiveRedBlackTree where T : IntrusiveRedBlackTreeNode, IComparable, IComparable + { + /// + /// Retrieve the node that is considered equal to the specified address by the comparator. + /// + /// Address to compare with + /// Node that is equal to + public T GetNode(ulong address) + { + T node = Root; + while (node != null) + { + int cmp = node.CompareTo(address); + if (cmp < 0) + { + node = node.Left; + } + else if (cmp > 0) + { + node = node.Right; + } + else + { + return node; + } + } + return null; + } + } +} diff --git a/src/Ryujinx.Cpu/Jit/AddressSpacePartition.cs b/src/Ryujinx.Cpu/Jit/AddressSpacePartition.cs index 8d40c25037..6e13c1eb94 100644 --- a/src/Ryujinx.Cpu/Jit/AddressSpacePartition.cs +++ b/src/Ryujinx.Cpu/Jit/AddressSpacePartition.cs @@ -35,7 +35,7 @@ namespace Ryujinx.Cpu.Jit Private, } - private class Mapping : IntrusiveRedBlackTreeNode, IComparable + private class Mapping : IntrusiveRedBlackTreeNode, IComparable, IComparable { public ulong Address { get; private set; } public ulong Size { get; private set; } @@ -87,9 +87,25 @@ namespace Ryujinx.Cpu.Jit return 1; } } + + public int CompareTo(ulong address) + { + if (address < Address) + { + return -1; + } + else if (address <= EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } } - private class PrivateMapping : IntrusiveRedBlackTreeNode, IComparable + private class PrivateMapping : IntrusiveRedBlackTreeNode, IComparable, IComparable { public ulong Address { get; private set; } public ulong Size { get; private set; } @@ -158,13 +174,30 @@ namespace Ryujinx.Cpu.Jit return 1; } } + + public int CompareTo(ulong address) + { + if (address < Address) + { + return -1; + } + else if (address <= EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } } private readonly MemoryBlock _backingMemory; private readonly AddressSpacePartitionMultiAllocation _baseMemory; private readonly PrivateMemoryAllocator _privateMemoryAllocator; - private readonly IntrusiveRedBlackTree _mappingTree; - private readonly IntrusiveRedBlackTree _privateTree; + + private readonly AddressIntrusiveRedBlackTree _mappingTree; + private readonly AddressIntrusiveRedBlackTree _privateTree; private readonly ReaderWriterLockSlim _treeLock; @@ -186,8 +219,8 @@ namespace Ryujinx.Cpu.Jit public AddressSpacePartition(AddressSpacePartitionAllocation baseMemory, MemoryBlock backingMemory, ulong address, ulong size) { _privateMemoryAllocator = new PrivateMemoryAllocator(DefaultBlockAlignment, MemoryAllocationFlags.Mirrorable); - _mappingTree = new IntrusiveRedBlackTree(); - _privateTree = new IntrusiveRedBlackTree(); + _mappingTree = new AddressIntrusiveRedBlackTree(); + _privateTree = new AddressIntrusiveRedBlackTree(); _treeLock = new ReaderWriterLockSlim(); _mappingTree.Add(new Mapping(address, size, MappingType.None)); @@ -212,7 +245,7 @@ namespace Ryujinx.Cpu.Jit try { - Mapping map = _mappingTree.GetNode(new Mapping(Address, Size, MappingType.None)); + Mapping map = _mappingTree.GetNode(Address); return map != null && map.Address == Address && map.Size == Size && map.Type == MappingType.None; } @@ -425,7 +458,7 @@ namespace Ryujinx.Cpu.Jit try { - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(Address, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(Address); if (map != null && map.PrivateAllocation.IsValid) { @@ -448,7 +481,7 @@ namespace Ryujinx.Cpu.Jit { ulong pageAddress = EndAddress - _hostPageSize; - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(pageAddress, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(pageAddress); if (map != null && map.PrivateAllocation.IsValid) { @@ -469,7 +502,7 @@ namespace Ryujinx.Cpu.Jit try { - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(va); if (map != null && map.PrivateAllocation.IsValid) { @@ -490,7 +523,7 @@ namespace Ryujinx.Cpu.Jit try { - Mapping map = _mappingTree.GetNode(new Mapping(va, 1UL, MappingType.None)); + Mapping map = _mappingTree.GetNode(va); Update(map, va, pa, size, type); } @@ -584,7 +617,7 @@ namespace Ryujinx.Cpu.Jit ulong vaAligned = BitUtils.AlignDown(va, alignment); ulong endAddressAligned = BitUtils.AlignUp(endAddress, alignment); - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(va); for (; map != null; map = map.Successor) { @@ -628,7 +661,7 @@ namespace Ryujinx.Cpu.Jit return; } - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(vaAligned, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(vaAligned); for (; map != null; map = map.Successor) { @@ -688,7 +721,7 @@ namespace Ryujinx.Cpu.Jit // Map all existing private allocations. // This is necessary to ensure mirrors that are lazily created have the same mappings as the main one. - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(Address, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(Address); for (; map != null; map = map.Successor) { @@ -705,7 +738,7 @@ namespace Ryujinx.Cpu.Jit try { - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, 1UL, default)); + PrivateMapping map = _privateTree.GetNode(va); nextVa = map.EndAddress; @@ -733,7 +766,7 @@ namespace Ryujinx.Cpu.Jit try { - PrivateMapping map = _privateTree.GetNode(new PrivateMapping(va, size, default)); + PrivateMapping map = _privateTree.GetNode(va); if (map != null && map.PrivateAllocation.IsValid) { diff --git a/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs b/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs index 568a9bcda8..5bb7947023 100644 --- a/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs +++ b/src/Ryujinx.Cpu/Jit/AddressSpacePartitionAllocator.cs @@ -65,7 +65,7 @@ namespace Ryujinx.Cpu.Jit private readonly Func _readPtCallback; private readonly MemoryEhMeilleure _memoryEh; - private class Mapping : IntrusiveRedBlackTreeNode, IComparable + private class Mapping : IntrusiveRedBlackTreeNode, IComparable, IComparable { public ulong Address { get; } public ulong Size { get; } @@ -98,9 +98,25 @@ namespace Ryujinx.Cpu.Jit return 1; } } + + public int CompareTo(ulong address) + { + if (address < Address) + { + return -1; + } + else if (address <= EndAddress - 1UL) + { + return 0; + } + else + { + return 1; + } + } } - private readonly IntrusiveRedBlackTree _mappingTree; + private readonly AddressIntrusiveRedBlackTree _mappingTree; private readonly object _lock; public Block(MemoryTracking tracking, Func readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size) @@ -119,7 +135,7 @@ namespace Ryujinx.Cpu.Jit public void RemoveMapping(ulong offset, ulong size) { - _mappingTree.Remove(_mappingTree.GetNode(new Mapping(offset, size, 0, 0, 0))); + _mappingTree.Remove(_mappingTree.GetNode(offset)); } private ulong VirtualMemoryEvent(ulong address, ulong size, bool write) @@ -128,7 +144,7 @@ namespace Ryujinx.Cpu.Jit lock (_lock) { - map = _mappingTree.GetNode(new Mapping(address, size, 0, 0, 0)); + map = _mappingTree.GetNode(address); } if (map == null)