mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-07-11 05:24:18 +00:00
mono-jit (#167)
- fix alignment issue with jitcache that could cause a crash.
- Reimplement sparse-jit to only use 1 layer.
- the old 2 layer approach basically only ever used 1 path due to the bottom-layer size, so doing a double look-up seemed wasteful.
- changed memory block allocation stategy to allocate based on requested code range instead of the possible address-space.
Co-authored-by: LotP1 <68976644+LotP1@users.noreply.github.com>
Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/167
This commit is contained in:
@@ -20,45 +20,21 @@ namespace ARMeilleure.Common
|
|||||||
new( 1, 6)
|
new( 1, 6)
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels64BitSparseTiny =
|
private static readonly AddressTableLevel[] _monoSparse64Bit =
|
||||||
[
|
[
|
||||||
new( 11, 28),
|
new( 2, 37)
|
||||||
new( 2, 9)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels32BitSparseTiny =
|
private static readonly AddressTableLevel[] _monoSparse32Bit =
|
||||||
[
|
[
|
||||||
new( 10, 22),
|
new( 1, 31)
|
||||||
new( 1, 9)
|
|
||||||
];
|
];
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels64BitSparseGiant =
|
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse)
|
||||||
[
|
|
||||||
new( 38, 1),
|
|
||||||
new( 2, 36)
|
|
||||||
];
|
|
||||||
|
|
||||||
private static readonly AddressTableLevel[] _levels32BitSparseGiant =
|
|
||||||
[
|
|
||||||
new( 31, 1),
|
|
||||||
new( 1, 30)
|
|
||||||
];
|
|
||||||
|
|
||||||
//high power will run worse on DDR3 systems and some DDR4 systems due to the higher ram utilization
|
|
||||||
//low power will never run worse than non-sparse, but for most systems it won't be necessary
|
|
||||||
//high power is always used, but I've left low power in here for future reference
|
|
||||||
public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse, bool lowPower = false)
|
|
||||||
{
|
{
|
||||||
if (sparse)
|
if (sparse)
|
||||||
{
|
{
|
||||||
if (lowPower)
|
return for64Bits ? _monoSparse64Bit : _monoSparse32Bit;
|
||||||
{
|
|
||||||
return for64Bits ? _levels64BitSparseTiny : _levels32BitSparseTiny;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return for64Bits ? _levels64BitSparseGiant : _levels32BitSparseGiant;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using ARMeilleure.IntermediateRepresentation;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using ARMeilleure.Translation.PTC;
|
using ARMeilleure.Translation.PTC;
|
||||||
|
using System.Linq;
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else if (table.Sparse)
|
else if (table.Sparse)
|
||||||
{
|
{
|
||||||
// Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels.
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 1 level.
|
||||||
// Deliberately attempts to avoid branches.
|
// Deliberately attempts to avoid branches.
|
||||||
|
|
||||||
Operand tableBase = !context.HasPtc ?
|
Operand tableBase = !context.HasPtc ?
|
||||||
@@ -247,18 +247,15 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
hostAddress = tableBase;
|
hostAddress = tableBase;
|
||||||
|
|
||||||
for (int i = 0; i < table.Levels.Length; i++)
|
AddressTableLevel level = table.Levels.Last();
|
||||||
{
|
int clearBits = 64 - (level.Index + level.Length);
|
||||||
AddressTableLevel level = table.Levels[i];
|
|
||||||
int clearBits = 64 - (level.Index + level.Length);
|
|
||||||
|
|
||||||
Operand index = context.ShiftLeft(
|
Operand index = context.ShiftLeft(
|
||||||
context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)),
|
context.ShiftRightUI(context.ShiftLeft(guestAddress, Const(clearBits)), Const(clearBits + level.Index)),
|
||||||
Const(3)
|
Const(3)
|
||||||
);
|
);
|
||||||
|
|
||||||
hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index));
|
hostAddress = context.Load(OperandType.I64, context.Add(hostAddress, index));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -129,7 +129,9 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
||||||
int regionEnd = ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
int regionEnd = endOffs % (int)CacheSize == 0
|
||||||
|
? (((int)CacheSize) + _pageMask) & ~_pageMask
|
||||||
|
: ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
||||||
|
|
||||||
GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
GetRegion(offset).Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
@@ -138,7 +140,9 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
{
|
{
|
||||||
int endOffs = offset + size;
|
int endOffs = offset + size;
|
||||||
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
int regionStart = (offset % (int)CacheSize) & ~_pageMask;
|
||||||
int regionEnd = ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
int regionEnd = endOffs % (int)CacheSize == 0
|
||||||
|
? (((int)CacheSize) + _pageMask) & ~_pageMask
|
||||||
|
: ((endOffs % (int)CacheSize) + _pageMask) & ~_pageMask;
|
||||||
|
|
||||||
GetRegion(offset).Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
GetRegion(offset).Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||||
|
|
||||||
private const uint InternalVersion = 7016; //! To be incremented manually for each change to the ARMeilleure project.
|
private const uint InternalVersion = 7018; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string ActualDir = "0";
|
private const string ActualDir = "0";
|
||||||
private const string BackupDir = "1";
|
private const string BackupDir = "1";
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ namespace ARMeilleure.Translation
|
|||||||
context.BranchIfTrue(lblFallback, masked);
|
context.BranchIfTrue(lblFallback, masked);
|
||||||
|
|
||||||
Operand index = default;
|
Operand index = default;
|
||||||
Operand page = Const((long)_functionTable.Base);
|
Operand page = Const(_functionTable.Base);
|
||||||
|
|
||||||
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
for (int i = 0; i < _functionTable.Levels.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,12 +81,13 @@ namespace ARMeilleure.Common
|
|||||||
|
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private TEntry** _table;
|
private TEntry** _table;
|
||||||
|
private TEntry* _sparseTable;
|
||||||
private readonly List<AddressTablePage> _pages;
|
private readonly List<AddressTablePage> _pages;
|
||||||
private TEntry _fill;
|
private TEntry _fill;
|
||||||
|
|
||||||
private readonly MemoryBlock _sparseFill;
|
private MemoryBlock _sparseFill;
|
||||||
private readonly SparseMemoryBlock _fillBottomLevel;
|
private SparseMemoryBlock _fillBottomLevel;
|
||||||
private readonly TEntry* _fillBottomLevelPtr;
|
private TEntry* _fillBottomLevelPtr;
|
||||||
|
|
||||||
private readonly List<TableSparseBlock> _sparseReserved;
|
private readonly List<TableSparseBlock> _sparseReserved;
|
||||||
private readonly ReaderWriterLockSlim _sparseLock;
|
private readonly ReaderWriterLockSlim _sparseLock;
|
||||||
@@ -122,16 +123,23 @@ namespace ARMeilleure.Common
|
|||||||
{
|
{
|
||||||
ObjectDisposedException.ThrowIf(_disposed, this);
|
ObjectDisposedException.ThrowIf(_disposed, this);
|
||||||
|
|
||||||
lock (_pages)
|
if (Sparse)
|
||||||
{
|
{
|
||||||
return (nint)GetRootPage();
|
return (nint)_sparseTable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock (_pages)
|
||||||
|
{
|
||||||
|
return (nint)GetRootPage();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new instance of the <see cref="AddressTable{TEntry}"/> class with the specified list of
|
/// Constructs a new instance of the <see cref="AddressTable{TEntry}"/> class with the specified list of
|
||||||
/// <see cref="Level"/>.
|
/// <see cref="AddressTableLevel"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="levels">Levels for the address table</param>
|
/// <param name="levels">Levels for the address table</param>
|
||||||
/// <param name="sparse">True if the bottom page should be sparsely mapped</param>
|
/// <param name="sparse">True if the bottom page should be sparsely mapped</param>
|
||||||
@@ -156,18 +164,8 @@ namespace ARMeilleure.Common
|
|||||||
if (sparse)
|
if (sparse)
|
||||||
{
|
{
|
||||||
// If the address table is sparse, allocate a fill block
|
// If the address table is sparse, allocate a fill block
|
||||||
|
|
||||||
_sparseFill = new MemoryBlock(268435456ul, MemoryAllocationFlags.Mirrorable); //low Power TC uses size: 65536ul
|
|
||||||
|
|
||||||
ulong bottomLevelSize = (1ul << levels.Last().Length) * (ulong)sizeof(TEntry);
|
|
||||||
|
|
||||||
_fillBottomLevel = new SparseMemoryBlock(bottomLevelSize, null, _sparseFill);
|
|
||||||
_fillBottomLevelPtr = (TEntry*)_fillBottomLevel.Block.Pointer;
|
|
||||||
|
|
||||||
_sparseReserved = [];
|
_sparseReserved = [];
|
||||||
_sparseLock = new ReaderWriterLockSlim();
|
_sparseLock = new ReaderWriterLockSlim();
|
||||||
|
|
||||||
_sparseBlockSize = bottomLevelSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,13 +207,24 @@ namespace ARMeilleure.Common
|
|||||||
public void SignalCodeRange(ulong address, ulong size)
|
public void SignalCodeRange(ulong address, ulong size)
|
||||||
{
|
{
|
||||||
AddressTableLevel bottom = Levels.Last();
|
AddressTableLevel bottom = Levels.Last();
|
||||||
ulong bottomLevelEntries = 1ul << bottom.Length;
|
|
||||||
|
|
||||||
ulong entryIndex = address >> bottom.Index;
|
|
||||||
ulong entries = size >> bottom.Index;
|
ulong entries = size >> bottom.Index;
|
||||||
entries += entryIndex - BitUtils.AlignDown(entryIndex, bottomLevelEntries);
|
|
||||||
|
|
||||||
_sparseBlockSize = Math.Max(_sparseBlockSize, BitUtils.AlignUp(entries, bottomLevelEntries) * (ulong)sizeof(TEntry));
|
if (Sparse)
|
||||||
|
{
|
||||||
|
ulong bottomLevelSize = (ulong)BitUtils.Pow2RoundUp((int)entries) * (ulong)sizeof(TEntry);
|
||||||
|
|
||||||
|
_sparseFill = new MemoryBlock(bottomLevelSize, MemoryAllocationFlags.Mirrorable);
|
||||||
|
|
||||||
|
_fillBottomLevel = new SparseMemoryBlock(bottomLevelSize, null, _sparseFill);
|
||||||
|
_fillBottomLevelPtr = (TEntry*)_fillBottomLevel.Block.Pointer;
|
||||||
|
|
||||||
|
_sparseBlockSize = bottomLevelSize;
|
||||||
|
|
||||||
|
_sparseTable = (TEntry*)Allocate((int)entries, Fill, leaf: true);
|
||||||
|
|
||||||
|
_sparseTable -= Levels.Last().GetValue(address);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -234,15 +243,26 @@ namespace ARMeilleure.Common
|
|||||||
throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address));
|
throw new ArgumentException($"Address 0x{address:X} is not mapped onto the table.", nameof(address));
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (_pages)
|
if (Sparse)
|
||||||
{
|
{
|
||||||
TEntry* page = GetPage(address);
|
long index = Levels.Last().GetValue(address);
|
||||||
|
|
||||||
long index = Levels[^1].GetValue(address);
|
EnsureMapped((nint)(_sparseTable + index));
|
||||||
|
|
||||||
EnsureMapped((nint)(page + index));
|
return ref _sparseTable[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lock (_pages)
|
||||||
|
{
|
||||||
|
TEntry* page = GetPage(address);
|
||||||
|
|
||||||
return ref page[index];
|
long index = Levels.Last().GetValue(address);
|
||||||
|
|
||||||
|
EnsureMapped((nint)(page + index));
|
||||||
|
|
||||||
|
return ref page[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Ryujinx.Cpu.LightningJit.CodeGen;
|
|||||||
using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
|
using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
@@ -189,7 +190,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
}
|
}
|
||||||
else if (inlineLookup)
|
else if (inlineLookup)
|
||||||
{
|
{
|
||||||
// Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels.
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 1 level.
|
||||||
|
|
||||||
Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress));
|
Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress));
|
||||||
|
|
||||||
@@ -203,18 +204,15 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
|||||||
// Index into the table.
|
// Index into the table.
|
||||||
asm.Mov(rn, tableBase);
|
asm.Mov(rn, tableBase);
|
||||||
|
|
||||||
for (int i = 0; i < funcTable.Levels.Length; i++)
|
AddressTableLevel level = funcTable.Levels.Last();
|
||||||
{
|
asm.Ubfx(indexReg, guestAddress, level.Index, level.Length);
|
||||||
AddressTableLevel level = funcTable.Levels[i];
|
asm.Lsl(indexReg, indexReg, Const(3));
|
||||||
asm.Ubfx(indexReg, guestAddress, level.Index, level.Length);
|
|
||||||
asm.Lsl(indexReg, indexReg, Const(3));
|
|
||||||
|
|
||||||
// Index into the page.
|
// Index into the page.
|
||||||
asm.Add(rn, rn, indexReg);
|
asm.Add(rn, rn, indexReg);
|
||||||
|
|
||||||
// Load the page address.
|
// Load the page address.
|
||||||
asm.LdrRiUn(rn, rn, 0);
|
asm.LdrRiUn(rn, rn, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if (tempGuestAddress != -1)
|
if (tempGuestAddress != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Ryujinx.Cpu.LightningJit.CodeGen;
|
|||||||
using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
|
using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -355,7 +356,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
}
|
}
|
||||||
else if (inlineLookup)
|
else if (inlineLookup)
|
||||||
{
|
{
|
||||||
// Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels.
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 1 level.
|
||||||
|
|
||||||
Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress));
|
Operand indexReg = Register(NextFreeRegister(tempRegister + 1, tempGuestAddress));
|
||||||
|
|
||||||
@@ -369,18 +370,15 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
|||||||
// Index into the table.
|
// Index into the table.
|
||||||
asm.Mov(rn, tableBase);
|
asm.Mov(rn, tableBase);
|
||||||
|
|
||||||
for (int i = 0; i < funcTable.Levels.Length; i++)
|
AddressTableLevel level = funcTable.Levels.Last();
|
||||||
{
|
asm.Ubfx(indexReg, guestAddress, level.Index, level.Length);
|
||||||
AddressTableLevel level = funcTable.Levels[i];
|
asm.Lsl(indexReg, indexReg, Const(3));
|
||||||
asm.Ubfx(indexReg, guestAddress, level.Index, level.Length);
|
|
||||||
asm.Lsl(indexReg, indexReg, Const(3));
|
|
||||||
|
|
||||||
// Index into the page.
|
// Index into the page.
|
||||||
asm.Add(rn, rn, indexReg);
|
asm.Add(rn, rn, indexReg);
|
||||||
|
|
||||||
// Load the page address.
|
// Load the page address.
|
||||||
asm.LdrRiUn(rn, rn, 0);
|
asm.LdrRiUn(rn, rn, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if (tempGuestAddress != -1)
|
if (tempGuestAddress != -1)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user