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
This commit is contained in:
parent
d16288a2a8
commit
5e0f8e8738
61 changed files with 10266 additions and 642 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue