diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2023-01-10 19:16:59 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-10 19:16:59 -0300 |
| commit | 5e0f8e873857ce3ca3f532aff0936beb28e412c8 (patch) | |
| tree | 576e5110c076b7d1f4d94e608ee21493f5b48879 /Ryujinx.Memory | |
| parent | d16288a2a87f0979df30ba69d4fe10660177b6ac (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.cs | 14 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryBlock.cs | 70 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryManagement.cs | 12 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryManagementUnix.cs | 31 | ||||
| -rw-r--r-- | Ryujinx.Memory/MemoryManagerUnixHelper.cs | 9 |
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; |
