aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Memory
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-01-10 19:16:59 -0300
committerGitHub <noreply@github.com>2023-01-10 19:16:59 -0300
commit5e0f8e873857ce3ca3f532aff0936beb28e412c8 (patch)
tree576e5110c076b7d1f4d94e608ee21493f5b48879 /Ryujinx.Memory
parentd16288a2a87f0979df30ba69d4fe10660177b6ac (diff)
Implement JIT Arm64 backend (#4114)
* Implement JIT Arm64 backend * PPTC version bump * Address some feedback from Arm64 JIT PR * Address even more PR feedback * Remove unused IsPageAligned function * Sync Qc flag before calls * Fix comment and remove unused enum * Address riperiperi PR feedback * Delete Breakpoint IR instruction that was only implemented for Arm64
Diffstat (limited to 'Ryujinx.Memory')
-rw-r--r--Ryujinx.Memory/MemoryAllocationFlags.cs14
-rw-r--r--Ryujinx.Memory/MemoryBlock.cs70
-rw-r--r--Ryujinx.Memory/MemoryManagement.cs12
-rw-r--r--Ryujinx.Memory/MemoryManagementUnix.cs31
-rw-r--r--Ryujinx.Memory/MemoryManagerUnixHelper.cs9
5 files changed, 77 insertions, 59 deletions
diff --git a/Ryujinx.Memory/MemoryAllocationFlags.cs b/Ryujinx.Memory/MemoryAllocationFlags.cs
index 313f33e5..6f0ef1aa 100644
--- a/Ryujinx.Memory/MemoryAllocationFlags.cs
+++ b/Ryujinx.Memory/MemoryAllocationFlags.cs
@@ -35,6 +35,18 @@ namespace Ryujinx.Memory
/// Indicates that the memory block should support mapping views of a mirrorable memory block.
/// The block that is to have their views mapped should be created with the <see cref="Mirrorable"/> flag.
/// </summary>
- ViewCompatible = 1 << 3
+ ViewCompatible = 1 << 3,
+
+ /// <summary>
+ /// If used with the <see cref="Mirrorable"/> flag, indicates that the memory block will only be used as
+ /// backing storage and will never be accessed directly, so the memory for the block will not be mapped.
+ /// </summary>
+ NoMap = 1 << 4,
+
+ /// <summary>
+ /// Indicates that the memory will be used to store JIT generated code.
+ /// On some platforms, this requires special flags to be passed that will allow the memory to be executable.
+ /// </summary>
+ Jit = 1 << 5
}
}
diff --git a/Ryujinx.Memory/MemoryBlock.cs b/Ryujinx.Memory/MemoryBlock.cs
index 6b9d852d..e1f19c27 100644
--- a/Ryujinx.Memory/MemoryBlock.cs
+++ b/Ryujinx.Memory/MemoryBlock.cs
@@ -1,6 +1,6 @@
using System;
-using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using System.Threading;
namespace Ryujinx.Memory
@@ -13,10 +13,9 @@ namespace Ryujinx.Memory
private readonly bool _usesSharedMemory;
private readonly bool _isMirror;
private readonly bool _viewCompatible;
+ private readonly bool _forJit;
private IntPtr _sharedMemory;
private IntPtr _pointer;
- private ConcurrentDictionary<MemoryBlock, byte> _viewStorages;
- private int _viewCount;
/// <summary>
/// Pointer to the memory block data.
@@ -40,24 +39,27 @@ namespace Ryujinx.Memory
if (flags.HasFlag(MemoryAllocationFlags.Mirrorable))
{
_sharedMemory = MemoryManagement.CreateSharedMemory(size, flags.HasFlag(MemoryAllocationFlags.Reserve));
- _pointer = MemoryManagement.MapSharedMemory(_sharedMemory, size);
+
+ if (!flags.HasFlag(MemoryAllocationFlags.NoMap))
+ {
+ _pointer = MemoryManagement.MapSharedMemory(_sharedMemory, size);
+ }
+
_usesSharedMemory = true;
}
else if (flags.HasFlag(MemoryAllocationFlags.Reserve))
{
_viewCompatible = flags.HasFlag(MemoryAllocationFlags.ViewCompatible);
- _pointer = MemoryManagement.Reserve(size, _viewCompatible);
+ _forJit = flags.HasFlag(MemoryAllocationFlags.Jit);
+ _pointer = MemoryManagement.Reserve(size, _forJit, _viewCompatible);
}
else
{
- _pointer = MemoryManagement.Allocate(size);
+ _forJit = flags.HasFlag(MemoryAllocationFlags.Jit);
+ _pointer = MemoryManagement.Allocate(size, _forJit);
}
Size = size;
-
- _viewStorages = new ConcurrentDictionary<MemoryBlock, byte>();
- _viewStorages.TryAdd(this, 0);
- _viewCount = 1;
}
/// <summary>
@@ -104,7 +106,7 @@ namespace Ryujinx.Memory
/// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception>
public bool Commit(ulong offset, ulong size)
{
- return MemoryManagement.Commit(GetPointerInternal(offset, size), size);
+ return MemoryManagement.Commit(GetPointerInternal(offset, size), size, _forJit);
}
/// <summary>
@@ -138,11 +140,6 @@ namespace Ryujinx.Memory
throw new ArgumentException("The source memory block is not mirrorable, and thus cannot be mapped on the current block.");
}
- if (_viewStorages.TryAdd(srcBlock, 0))
- {
- srcBlock.IncrementViewCount();
- }
-
MemoryManagement.MapView(srcBlock._sharedMemory, srcOffset, GetPointerInternal(dstOffset, size), size, this);
}
@@ -403,33 +400,16 @@ namespace Ryujinx.Memory
{
MemoryManagement.Free(ptr, Size);
}
-
- foreach (MemoryBlock viewStorage in _viewStorages.Keys)
- {
- viewStorage.DecrementViewCount();
- }
-
- _viewStorages.Clear();
}
- }
-
- /// <summary>
- /// Increments the number of views that uses this memory block as storage.
- /// </summary>
- private void IncrementViewCount()
- {
- Interlocked.Increment(ref _viewCount);
- }
- /// <summary>
- /// Decrements the number of views that uses this memory block as storage.
- /// </summary>
- private void DecrementViewCount()
- {
- if (Interlocked.Decrement(ref _viewCount) == 0 && _sharedMemory != IntPtr.Zero && !_isMirror)
+ if (!_isMirror)
{
- MemoryManagement.DestroySharedMemory(_sharedMemory);
- _sharedMemory = IntPtr.Zero;
+ IntPtr sharedMemory = Interlocked.Exchange(ref _sharedMemory, IntPtr.Zero);
+
+ if (sharedMemory != IntPtr.Zero)
+ {
+ MemoryManagement.DestroySharedMemory(sharedMemory);
+ }
}
}
@@ -453,6 +433,16 @@ namespace Ryujinx.Memory
return true;
}
+ public static ulong GetPageSize()
+ {
+ if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
+ {
+ return 1UL << 14;
+ }
+
+ return 1UL << 12;
+ }
+
private static void ThrowInvalidMemoryRegionException() => throw new InvalidMemoryRegionException();
}
}
diff --git a/Ryujinx.Memory/MemoryManagement.cs b/Ryujinx.Memory/MemoryManagement.cs
index 7c042eba..c4b5ac4c 100644
--- a/Ryujinx.Memory/MemoryManagement.cs
+++ b/Ryujinx.Memory/MemoryManagement.cs
@@ -4,7 +4,7 @@ namespace Ryujinx.Memory
{
public static class MemoryManagement
{
- public static IntPtr Allocate(ulong size)
+ public static IntPtr Allocate(ulong size, bool forJit)
{
if (OperatingSystem.IsWindows())
{
@@ -12,7 +12,7 @@ namespace Ryujinx.Memory
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
- return MemoryManagementUnix.Allocate(size);
+ return MemoryManagementUnix.Allocate(size, forJit);
}
else
{
@@ -20,7 +20,7 @@ namespace Ryujinx.Memory
}
}
- public static IntPtr Reserve(ulong size, bool viewCompatible)
+ public static IntPtr Reserve(ulong size, bool forJit, bool viewCompatible)
{
if (OperatingSystem.IsWindows())
{
@@ -28,7 +28,7 @@ namespace Ryujinx.Memory
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
- return MemoryManagementUnix.Reserve(size);
+ return MemoryManagementUnix.Reserve(size, forJit);
}
else
{
@@ -36,7 +36,7 @@ namespace Ryujinx.Memory
}
}
- public static bool Commit(IntPtr address, ulong size)
+ public static bool Commit(IntPtr address, ulong size, bool forJit)
{
if (OperatingSystem.IsWindows())
{
@@ -44,7 +44,7 @@ namespace Ryujinx.Memory
}
else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS())
{
- return MemoryManagementUnix.Commit(address, size);
+ return MemoryManagementUnix.Commit(address, size, forJit);
}
else
{
diff --git a/Ryujinx.Memory/MemoryManagementUnix.cs b/Ryujinx.Memory/MemoryManagementUnix.cs
index df3fcea9..affcff92 100644
--- a/Ryujinx.Memory/MemoryManagementUnix.cs
+++ b/Ryujinx.Memory/MemoryManagementUnix.cs
@@ -13,17 +13,17 @@ namespace Ryujinx.Memory
{
private static readonly ConcurrentDictionary<IntPtr, ulong> _allocations = new ConcurrentDictionary<IntPtr, ulong>();
- public static IntPtr Allocate(ulong size)
+ public static IntPtr Allocate(ulong size, bool forJit)
{
- return AllocateInternal(size, MmapProts.PROT_READ | MmapProts.PROT_WRITE);
+ return AllocateInternal(size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, forJit);
}
- public static IntPtr Reserve(ulong size)
+ public static IntPtr Reserve(ulong size, bool forJit)
{
- return AllocateInternal(size, MmapProts.PROT_NONE);
+ return AllocateInternal(size, MmapProts.PROT_NONE, forJit);
}
- private static IntPtr AllocateInternal(ulong size, MmapProts prot, bool shared = false)
+ private static IntPtr AllocateInternal(ulong size, MmapProts prot, bool forJit, bool shared = false)
{
MmapFlags flags = MmapFlags.MAP_ANONYMOUS;
@@ -41,6 +41,16 @@ namespace Ryujinx.Memory
flags |= MmapFlags.MAP_NORESERVE;
}
+ if (OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit)
+ {
+ flags |= MmapFlags.MAP_JIT_DARWIN;
+
+ if (prot == (MmapProts.PROT_READ | MmapProts.PROT_WRITE))
+ {
+ prot |= MmapProts.PROT_EXEC;
+ }
+ }
+
IntPtr ptr = mmap(IntPtr.Zero, size, prot, flags, -1, 0);
if (ptr == new IntPtr(-1L))
@@ -57,9 +67,16 @@ namespace Ryujinx.Memory
return ptr;
}
- public static bool Commit(IntPtr address, ulong size)
+ public static bool Commit(IntPtr address, ulong size, bool forJit)
{
- return mprotect(address, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE) == 0;
+ MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE;
+
+ if (OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit)
+ {
+ prot |= MmapProts.PROT_EXEC;
+ }
+
+ return mprotect(address, size, prot) == 0;
}
public static bool Decommit(IntPtr address, ulong size)
diff --git a/Ryujinx.Memory/MemoryManagerUnixHelper.cs b/Ryujinx.Memory/MemoryManagerUnixHelper.cs
index 87a81a79..204f1ca4 100644
--- a/Ryujinx.Memory/MemoryManagerUnixHelper.cs
+++ b/Ryujinx.Memory/MemoryManagerUnixHelper.cs
@@ -22,7 +22,8 @@ namespace Ryujinx.Memory
MAP_ANONYMOUS = 4,
MAP_NORESERVE = 8,
MAP_FIXED = 16,
- MAP_UNLOCKED = 32
+ MAP_UNLOCKED = 32,
+ MAP_JIT_DARWIN = 0x800
}
[Flags]
@@ -45,7 +46,6 @@ namespace Ryujinx.Memory
private const int MAP_UNLOCKED_LINUX_GENERIC = 0x80000;
private const int MAP_NORESERVE_DARWIN = 0x40;
- private const int MAP_JIT_DARWIN = 0x800;
private const int MAP_ANONYMOUS_DARWIN = 0x1000;
public const int MADV_DONTNEED = 4;
@@ -151,10 +151,9 @@ namespace Ryujinx.Memory
}
}
- if (OperatingSystem.IsMacOSVersionAtLeast(10, 14))
+ if (flags.HasFlag(MmapFlags.MAP_JIT_DARWIN) && OperatingSystem.IsMacOSVersionAtLeast(10, 14))
{
- // Only to be used with the Hardened Runtime.
- // result |= MAP_JIT_DARWIN;
+ result |= (int)MmapFlags.MAP_JIT_DARWIN;
}
return result;