mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-23 05:35:47 +00:00
Memory Changes part 2 (ryubing/ryujinx!123)
See merge request ryubing/ryujinx!123
This commit is contained in:
@@ -10,7 +10,7 @@ namespace Ryujinx.Memory.Range
|
||||
/// A range list that assumes ranges are non-overlapping, with list items that can be split in two to avoid overlaps.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the range.</typeparam>
|
||||
public class NonOverlappingRangeList<T> : RangeListBase<T> where T : INonOverlappingRange
|
||||
public unsafe class NonOverlappingRangeList<T> : RangeListBase<T> where T : class, INonOverlappingRange
|
||||
{
|
||||
private readonly Dictionary<ulong, RangeItem<T>> _quickAccess = new(AddressEqualityComparer.Comparer);
|
||||
private readonly Dictionary<ulong, RangeItem<T>> _fastQuickAccess = new(AddressEqualityComparer.Comparer);
|
||||
@@ -196,6 +196,16 @@ namespace Ryujinx.Memory.Range
|
||||
int startIndex = BinarySearch(startItem.Address);
|
||||
int endIndex = BinarySearch(endItem.Address);
|
||||
|
||||
for (int i = startIndex; i <= endIndex; i++)
|
||||
{
|
||||
_quickAccess.Remove(Items[i].Address);
|
||||
foreach (ulong addr in Items[i].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (endIndex < Count - 1)
|
||||
{
|
||||
Items[endIndex + 1].Previous = startIndex > 0 ? Items[startIndex - 1] : null;
|
||||
@@ -213,17 +223,6 @@ namespace Ryujinx.Memory.Range
|
||||
}
|
||||
|
||||
Count -= endIndex - startIndex + 1;
|
||||
|
||||
while (startItem != endItem.Next)
|
||||
{
|
||||
_quickAccess.Remove(startItem.Address);
|
||||
foreach (ulong addr in startItem.QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
startItem = startItem.Next;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -240,19 +239,22 @@ namespace Ryujinx.Memory.Range
|
||||
return;
|
||||
}
|
||||
|
||||
RangeItem<T> startItem = Items[startIndex];
|
||||
|
||||
int endIndex = startIndex;
|
||||
|
||||
while (startItem is not null && startItem.Address < address + size)
|
||||
while (Items[endIndex] is not null && Items[endIndex].Address < address + size)
|
||||
{
|
||||
_quickAccess.Remove(startItem.Address);
|
||||
foreach (ulong addr in startItem.QuickAccessAddresses)
|
||||
_quickAccess.Remove(Items[endIndex].Address);
|
||||
foreach (ulong addr in Items[endIndex].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(addr);
|
||||
_fastQuickAccess.Remove(addr);
|
||||
}
|
||||
startItem = startItem.Next;
|
||||
|
||||
if (endIndex == Count - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,37 +6,6 @@ using System.Threading;
|
||||
|
||||
namespace Ryujinx.Memory.Range
|
||||
{
|
||||
public class RangeItem<TValue>(TValue value) where TValue : IRange
|
||||
{
|
||||
public RangeItem<TValue> Next;
|
||||
public RangeItem<TValue> Previous;
|
||||
|
||||
public readonly ulong Address = value.Address;
|
||||
public readonly ulong EndAddress = value.Address + value.Size;
|
||||
|
||||
public readonly TValue Value = value;
|
||||
|
||||
public readonly List<ulong> QuickAccessAddresses = [];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool OverlapsWith(ulong address, ulong endAddress)
|
||||
{
|
||||
return Address < endAddress && address < EndAddress;
|
||||
}
|
||||
}
|
||||
|
||||
class AddressEqualityComparer : IEqualityComparer<ulong>
|
||||
{
|
||||
public bool Equals(ulong u1, ulong u2)
|
||||
{
|
||||
return u1 == u2;
|
||||
}
|
||||
|
||||
public int GetHashCode(ulong value) => (int)(value >> 5);
|
||||
|
||||
public static readonly AddressEqualityComparer Comparer = new();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of an Overlaps Finder function. WARNING: if the result is from the optimized
|
||||
/// Overlaps Finder, the StartIndex will be -1 even when the result isn't empty
|
||||
@@ -209,43 +178,46 @@ namespace Ryujinx.Memory.Range
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void RemoveRange(RangeItem<T> startItem, RangeItem<T> endItem)
|
||||
{
|
||||
if (endItem.Next is not null)
|
||||
if (startItem is null)
|
||||
{
|
||||
endItem.Next.Previous = startItem.Previous;
|
||||
return;
|
||||
}
|
||||
|
||||
if (startItem == endItem)
|
||||
{
|
||||
Remove(startItem.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (startItem.Previous is not null)
|
||||
{
|
||||
startItem.Previous.Next = endItem.Next;
|
||||
}
|
||||
int startIndex = BinarySearch(startItem.Address);
|
||||
int endIndex = BinarySearch(endItem.Address);
|
||||
|
||||
RangeItem<T> current = startItem;
|
||||
while (current != endItem.Next)
|
||||
for (int i = startIndex; i <= endIndex; i++)
|
||||
{
|
||||
foreach (ulong address in current.QuickAccessAddresses)
|
||||
_quickAccess.Remove(Items[i].Address);
|
||||
foreach (ulong addr in Items[i].QuickAccessAddresses)
|
||||
{
|
||||
_quickAccess.Remove(address);
|
||||
_quickAccess.Remove(addr);
|
||||
}
|
||||
|
||||
current = current.Next;
|
||||
}
|
||||
|
||||
RangeItem<T>[] array = [];
|
||||
OverlapResult<T> overlapResult = FindOverlaps(startItem.Address, endItem.EndAddress, ref array);
|
||||
if (endIndex < Count - 1)
|
||||
{
|
||||
Items[endIndex + 1].Previous = startIndex > 0 ? Items[startIndex - 1] : null;
|
||||
}
|
||||
|
||||
if (startIndex > 0)
|
||||
{
|
||||
Items[startIndex - 1].Next = endIndex < Count - 1 ? Items[endIndex + 1] : null;
|
||||
}
|
||||
|
||||
if (overlapResult.EndIndex < Count)
|
||||
|
||||
if (endIndex < Count - 1)
|
||||
{
|
||||
Array.Copy(Items, overlapResult.EndIndex, Items, overlapResult.StartIndex, Count - overlapResult.EndIndex);
|
||||
Count -= overlapResult.Count;
|
||||
}
|
||||
else if (overlapResult.EndIndex == Count)
|
||||
{
|
||||
Count = overlapResult.StartIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Assert(false);
|
||||
Array.Copy(Items, endIndex + 1, Items, startIndex, Count - endIndex - 1);
|
||||
}
|
||||
|
||||
Count -= endIndex - startIndex + 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,9 +4,40 @@ using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.Memory.Range
|
||||
{
|
||||
public abstract class RangeListBase<T> : IEnumerable<T> where T : IRange
|
||||
public class RangeItem<TValue>(TValue value) where TValue : IRange
|
||||
{
|
||||
protected const int BackingInitialSize = 1024;
|
||||
public RangeItem<TValue> Next;
|
||||
public RangeItem<TValue> Previous;
|
||||
|
||||
public readonly ulong Address = value.Address;
|
||||
public readonly ulong EndAddress = value.Address + value.Size;
|
||||
|
||||
public readonly TValue Value = value;
|
||||
|
||||
public readonly List<ulong> QuickAccessAddresses = [];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool OverlapsWith(ulong address, ulong endAddress)
|
||||
{
|
||||
return Address < endAddress && address < EndAddress;
|
||||
}
|
||||
}
|
||||
|
||||
class AddressEqualityComparer : IEqualityComparer<ulong>
|
||||
{
|
||||
public bool Equals(ulong u1, ulong u2)
|
||||
{
|
||||
return u1 == u2;
|
||||
}
|
||||
|
||||
public int GetHashCode(ulong value) => (int)(value >> 5);
|
||||
|
||||
public static readonly AddressEqualityComparer Comparer = new();
|
||||
}
|
||||
|
||||
public unsafe abstract class RangeListBase<T> : IEnumerable<T> where T : IRange
|
||||
{
|
||||
private const int BackingInitialSize = 1024;
|
||||
|
||||
protected RangeItem<T>[] Items;
|
||||
protected readonly int BackingGrowthSize;
|
||||
|
||||
@@ -36,10 +36,12 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
|
||||
class RangeNode<T> : IntrusiveRedBlackTreeNode<RangeNode<T>>, IComparable<RangeNode<T>>, IComparable<ulong>
|
||||
{
|
||||
public ulong Start { get; }
|
||||
public ulong Start { get; private set; }
|
||||
public ulong End { get; private set; }
|
||||
public T Value { get; }
|
||||
public T Value { get; private set; }
|
||||
|
||||
public RangeNode() { }
|
||||
|
||||
public RangeNode(ulong start, ulong end, T value)
|
||||
{
|
||||
Start = start;
|
||||
@@ -47,6 +49,22 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public RangeNode<T> Init(ulong start, ulong end, T value)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
Value = value;
|
||||
|
||||
Color = true;
|
||||
Left = null;
|
||||
Right = null;
|
||||
Parent = null;
|
||||
Predecessor = null;
|
||||
Successor = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Extend(ulong sizeDelta)
|
||||
{
|
||||
End += sizeDelta;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Collections;
|
||||
using Ryujinx.Common.Memory.PartialUnmaps;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Versioning;
|
||||
@@ -8,6 +9,24 @@ using System.Threading;
|
||||
|
||||
namespace Ryujinx.Memory.WindowsShared
|
||||
{
|
||||
public class ObjectPool<T>
|
||||
{
|
||||
private readonly Stack<T> _objects;
|
||||
private readonly Func<T> _objectGenerator;
|
||||
|
||||
public ObjectPool(Func<T> objectGenerator)
|
||||
{
|
||||
_objectGenerator = objectGenerator ?? throw new ArgumentNullException(nameof(objectGenerator));
|
||||
_objects = new Stack<T>();
|
||||
}
|
||||
|
||||
public T Get() => _objects.Count > 0 ? _objects.Pop() : _objectGenerator();
|
||||
|
||||
public void Return(T item) => _objects.Push(item);
|
||||
|
||||
public void Clear() => _objects.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Windows memory placeholder manager.
|
||||
/// </summary>
|
||||
@@ -18,6 +37,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
|
||||
private readonly MappingTree<ulong> _mappings;
|
||||
private readonly MappingTree<MemoryPermission> _protections;
|
||||
private readonly ObjectPool<RangeNode<MemoryPermission>> _protectionObjectPool;
|
||||
private readonly nint _partialUnmapStatePtr;
|
||||
private readonly Thread _partialUnmapTrimThread;
|
||||
|
||||
@@ -28,6 +48,8 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
{
|
||||
_mappings = new MappingTree<ulong>();
|
||||
_protections = new MappingTree<MemoryPermission>();
|
||||
|
||||
_protectionObjectPool = new ObjectPool<RangeNode<MemoryPermission>>(() => new RangeNode<MemoryPermission>());
|
||||
|
||||
_partialUnmapStatePtr = PartialUnmapState.GlobalState;
|
||||
|
||||
@@ -70,12 +92,12 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
{
|
||||
lock (_mappings)
|
||||
{
|
||||
_mappings.Add(new RangeNode<ulong>(address, address + size, ulong.MaxValue));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(address, address + size, ulong.MaxValue));
|
||||
}
|
||||
|
||||
lock (_protections)
|
||||
{
|
||||
_protections.Add(new RangeNode<MemoryPermission>(address, address + size, MemoryPermission.None));
|
||||
_protections.Add(_protectionObjectPool.Get().Init(address, address + size, MemoryPermission.None));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +236,8 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
(nint)size,
|
||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||
|
||||
_mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
||||
_mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(overlapStart, address, overlapValue));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(endAddress, overlapEnd, AddBackingOffset(overlapValue, endAddress - overlapStart)));
|
||||
}
|
||||
else if (overlapStartsBefore)
|
||||
{
|
||||
@@ -226,7 +248,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
(nint)overlappedSize,
|
||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||
|
||||
_mappings.Add(new RangeNode<ulong>(overlapStart, address, overlapValue));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(overlapStart, address, overlapValue));
|
||||
}
|
||||
else if (overlapEndsAfter)
|
||||
{
|
||||
@@ -237,10 +259,10 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
(nint)overlappedSize,
|
||||
AllocationType.Release | AllocationType.PreservePlaceholder));
|
||||
|
||||
_mappings.Add(new RangeNode<ulong>(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(endAddress, overlapEnd, AddBackingOffset(overlapValue, overlappedSize)));
|
||||
}
|
||||
|
||||
_mappings.Add(new RangeNode<ulong>(address, endAddress, backingOffset));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(address, endAddress, backingOffset));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +328,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
lock (_mappings)
|
||||
{
|
||||
_mappings.Remove(overlap);
|
||||
_mappings.Add(new RangeNode<ulong>(overlap.Start, overlap.End, ulong.MaxValue));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(overlap.Start, overlap.End, ulong.MaxValue));
|
||||
}
|
||||
|
||||
bool overlapStartsBefore = overlap.Start < startAddress;
|
||||
@@ -433,7 +455,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
unmappedCount++;
|
||||
}
|
||||
|
||||
_mappings.Add(new RangeNode<ulong>(address, endAddress, ulong.MaxValue));
|
||||
_mappings.Add(new RangeNode<ulong>().Init(address, endAddress, ulong.MaxValue));
|
||||
}
|
||||
|
||||
if (unmappedCount > 1)
|
||||
@@ -628,14 +650,16 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
{
|
||||
if (startAddress > protAddress)
|
||||
{
|
||||
_protections.Add(new RangeNode<MemoryPermission>(protAddress, startAddress, protPermission));
|
||||
_protections.Add(_protectionObjectPool.Get().Init(protAddress, startAddress, protPermission));
|
||||
}
|
||||
|
||||
if (endAddress < protEndAddress)
|
||||
{
|
||||
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
||||
_protections.Add(_protectionObjectPool.Get().Init(endAddress, protEndAddress, protPermission));
|
||||
}
|
||||
}
|
||||
|
||||
_protectionObjectPool.Return(protection);
|
||||
|
||||
if (node.End >= endAddress)
|
||||
{
|
||||
@@ -643,7 +667,7 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
}
|
||||
}
|
||||
|
||||
_protections.Add(new RangeNode<MemoryPermission>(startAddress, endAddress, permission));
|
||||
_protections.Add(_protectionObjectPool.Get().Init(startAddress, endAddress, permission));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,14 +698,16 @@ namespace Ryujinx.Memory.WindowsShared
|
||||
|
||||
if (address > protAddress)
|
||||
{
|
||||
_protections.Add(new RangeNode<MemoryPermission>(protAddress, address, protPermission));
|
||||
_protections.Add(_protectionObjectPool.Get().Init(protAddress, address, protPermission));
|
||||
}
|
||||
|
||||
if (endAddress < protEndAddress)
|
||||
{
|
||||
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
|
||||
_protections.Add(_protectionObjectPool.Get().Init(endAddress, protEndAddress, protPermission));
|
||||
}
|
||||
|
||||
_protectionObjectPool.Return(protection);
|
||||
|
||||
if (node.End >= endAddress)
|
||||
{
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user