Update several methods to use GetNode directly and avoid array allocations

This commit is contained in:
gdk 2022-08-30 22:15:16 -03:00 committed by Mary-nyan
parent 65f2a82b97
commit c646638680

View File

@ -89,9 +89,12 @@ namespace Ryujinx.Memory.WindowsShared
lock (_mappings) lock (_mappings)
{ {
RangeNode<ulong> node = _mappings.GetNode(new RangeNode<ulong>(address, address + 1UL, default)); RangeNode<ulong> node = _mappings.GetNode(new RangeNode<ulong>(address, address + 1UL, default));
RangeNode<ulong> successorNode;
for (; node != null; node = node.Successor) for (; node != null; node = successorNode)
{ {
successorNode = node.Successor;
if (IsMapped(node.Value)) if (IsMapped(node.Value))
{ {
if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)node.Start, 2)) if (!WindowsApi.UnmapViewOfFile2(WindowsApi.CurrentProcessHandle, (IntPtr)node.Start, 2))
@ -372,25 +375,25 @@ namespace Ryujinx.Memory.WindowsShared
ulong endAddress = address + size; ulong endAddress = address + size;
ulong blockAddress = (ulong)owner.Pointer; ulong blockAddress = (ulong)owner.Pointer;
ulong blockEnd = blockAddress + owner.Size; ulong blockEnd = blockAddress + owner.Size;
var overlaps = new RangeNode<ulong>[InitialOverlapsSize];
int unmappedCount = 0; int unmappedCount = 0;
lock (_mappings) lock (_mappings)
{ {
int count = _mappings.GetNodes(address, endAddress, ref overlaps); RangeNode<ulong> node = _mappings.GetNode(new RangeNode<ulong>(address, address + 1UL, default));
if (count == 0) if (node == null)
{ {
// Nothing to coalesce if we no overlaps. // Nothing to coalesce if we have no overlaps.
return; return;
} }
RangeNode<ulong> predecessor = overlaps[0].Predecessor; RangeNode<ulong> predecessor = node.Predecessor;
RangeNode<ulong> successor = overlaps[count - 1].Successor; RangeNode<ulong> successor = null;
for (int index = 0; index < count; index++) for (; node != null; node = successor)
{ {
var overlap = overlaps[index]; successor = node.Successor;
var overlap = node;
if (!IsMapped(overlap.Value)) if (!IsMapped(overlap.Value))
{ {
@ -400,6 +403,11 @@ namespace Ryujinx.Memory.WindowsShared
_mappings.Remove(overlap); _mappings.Remove(overlap);
unmappedCount++; unmappedCount++;
} }
if (node.End >= endAddress)
{
break;
}
} }
if (predecessor != null && !IsMapped(predecessor.Value) && predecessor.Start >= blockAddress) if (predecessor != null && !IsMapped(predecessor.Value) && predecessor.Start >= blockAddress)
@ -469,46 +477,50 @@ namespace Ryujinx.Memory.WindowsShared
ulong reprotectSize = (ulong)size; ulong reprotectSize = (ulong)size;
ulong endAddress = reprotectAddress + reprotectSize; ulong endAddress = reprotectAddress + reprotectSize;
var overlaps = new RangeNode<ulong>[InitialOverlapsSize]; bool success = true;
int count;
lock (_mappings) lock (_mappings)
{ {
count = _mappings.GetNodes(reprotectAddress, endAddress, ref overlaps); RangeNode<ulong> node = _mappings.GetNode(new RangeNode<ulong>(reprotectAddress, reprotectAddress + 1UL, default));
} RangeNode<ulong> successorNode;
bool success = true; for (; node != null; node = successorNode)
for (int index = 0; index < count; index++)
{
var overlap = overlaps[index];
ulong mappedAddress = overlap.Start;
ulong mappedSize = overlap.End - overlap.Start;
if (mappedAddress < reprotectAddress)
{ {
ulong delta = reprotectAddress - mappedAddress; successorNode = node.Successor;
mappedAddress = reprotectAddress; var overlap = node;
mappedSize -= delta;
}
ulong mappedEndAddress = mappedAddress + mappedSize; ulong mappedAddress = overlap.Start;
ulong mappedSize = overlap.End - overlap.Start;
if (mappedEndAddress > endAddress) if (mappedAddress < reprotectAddress)
{
ulong delta = mappedEndAddress - endAddress;
mappedSize -= delta;
}
if (!WindowsApi.VirtualProtect((IntPtr)mappedAddress, (IntPtr)mappedSize, WindowsApi.GetProtection(permission), out _))
{
if (throwOnError)
{ {
throw new WindowsApiException("VirtualProtect"); ulong delta = reprotectAddress - mappedAddress;
mappedAddress = reprotectAddress;
mappedSize -= delta;
} }
success = false; ulong mappedEndAddress = mappedAddress + mappedSize;
if (mappedEndAddress > endAddress)
{
ulong delta = mappedEndAddress - endAddress;
mappedSize -= delta;
}
if (!WindowsApi.VirtualProtect((IntPtr)mappedAddress, (IntPtr)mappedSize, WindowsApi.GetProtection(permission), out _))
{
if (throwOnError)
{
throw new WindowsApiException("VirtualProtect");
}
success = false;
}
if (node.End >= endAddress)
{
break;
}
} }
} }
@ -565,26 +577,27 @@ namespace Ryujinx.Memory.WindowsShared
private void UpdateProtection(ulong address, ulong size, MemoryPermission permission) private void UpdateProtection(ulong address, ulong size, MemoryPermission permission)
{ {
ulong endAddress = address + size; ulong endAddress = address + size;
var overlaps = new RangeNode<MemoryPermission>[InitialOverlapsSize];
int count;
lock (_protections) lock (_protections)
{ {
count = _protections.GetNodes(address, endAddress, ref overlaps); RangeNode<MemoryPermission> node = _protections.GetNode(new RangeNode<MemoryPermission>(address, address + 1UL, default));
if (count == 1 && if (node != null &&
overlaps[0].Start <= address && node.Start <= address &&
overlaps[0].End >= endAddress && node.End >= endAddress &&
overlaps[0].Value == permission) node.Value == permission)
{ {
return; return;
} }
RangeNode<MemoryPermission> successorNode;
ulong startAddress = address; ulong startAddress = address;
for (int index = 0; index < count; index++) for (; node != null; node = successorNode)
{ {
var protection = overlaps[index]; successorNode = node.Successor;
var protection = node;
ulong protAddress = protection.Start; ulong protAddress = protection.Start;
ulong protEndAddress = protection.End; ulong protEndAddress = protection.End;
@ -616,6 +629,11 @@ namespace Ryujinx.Memory.WindowsShared
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission)); _protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
} }
} }
if (node.End >= endAddress)
{
break;
}
} }
_protections.Add(new RangeNode<MemoryPermission>(startAddress, endAddress, permission)); _protections.Add(new RangeNode<MemoryPermission>(startAddress, endAddress, permission));
@ -630,16 +648,16 @@ namespace Ryujinx.Memory.WindowsShared
private void RemoveProtection(ulong address, ulong size) private void RemoveProtection(ulong address, ulong size)
{ {
ulong endAddress = address + size; ulong endAddress = address + size;
var overlaps = new RangeNode<MemoryPermission>[InitialOverlapsSize];
int count;
lock (_protections) lock (_protections)
{ {
count = _protections.GetNodes(address, endAddress, ref overlaps); RangeNode<MemoryPermission> node = _protections.GetNode(new RangeNode<MemoryPermission>(address, address + 1UL, default));
RangeNode<MemoryPermission> successorNode;
for (int index = 0; index < count; index++) for (; node != null; node = successorNode)
{ {
var protection = overlaps[index]; successorNode = node.Successor;
var protection = node;
ulong protAddress = protection.Start; ulong protAddress = protection.Start;
ulong protEndAddress = protection.End; ulong protEndAddress = protection.End;
@ -656,6 +674,11 @@ namespace Ryujinx.Memory.WindowsShared
{ {
_protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission)); _protections.Add(new RangeNode<MemoryPermission>(endAddress, protEndAddress, protPermission));
} }
if (node.End >= endAddress)
{
break;
}
} }
} }
} }