diff --git a/src/ARMeilleure/Common/AddressTableLevel.cs b/src/ARMeilleure/Common/AddressTableLevel.cs
new file mode 100644
index 000000000..6107726ee
--- /dev/null
+++ b/src/ARMeilleure/Common/AddressTableLevel.cs
@@ -0,0 +1,44 @@
+namespace ARMeilleure.Common
+{
+ ///
+ /// Represents a level in an .
+ ///
+ public readonly struct AddressTableLevel
+ {
+ ///
+ /// Gets the index of the in the guest address.
+ ///
+ public int Index { get; }
+
+ ///
+ /// Gets the length of the in the guest address.
+ ///
+ public int Length { get; }
+
+ ///
+ /// Gets the mask which masks the bits used by the .
+ ///
+ public ulong Mask => ((1ul << Length) - 1) << Index;
+
+ ///
+ /// Initializes a new instance of the structure with the specified
+ /// and .
+ ///
+ /// Index of the
+ /// Length of the
+ public AddressTableLevel(int index, int length)
+ {
+ (Index, Length) = (index, length);
+ }
+
+ ///
+ /// Gets the value of the from the specified guest .
+ ///
+ /// Guest address
+ /// Value of the from the specified guest
+ public int GetValue(ulong address)
+ {
+ return (int)((address & Mask) >> Index);
+ }
+ }
+}
diff --git a/src/ARMeilleure/Common/AddressTablePresets.cs b/src/ARMeilleure/Common/AddressTablePresets.cs
new file mode 100644
index 000000000..e7eaf62cd
--- /dev/null
+++ b/src/ARMeilleure/Common/AddressTablePresets.cs
@@ -0,0 +1,51 @@
+namespace ARMeilleure.Common
+{
+ public static class AddressTablePresets
+ {
+ private static readonly AddressTableLevel[] _levels64Bit =
+ new AddressTableLevel[]
+ {
+ new(31, 17),
+ new(23, 8),
+ new(15, 8),
+ new( 7, 8),
+ new( 2, 5),
+ };
+
+ private static readonly AddressTableLevel[] _levels32Bit =
+ new AddressTableLevel[]
+ {
+ new(31, 17),
+ new(23, 8),
+ new(15, 8),
+ new( 7, 8),
+ new( 1, 6),
+ };
+
+ private static readonly AddressTableLevel[] _levels64BitSparse =
+ new AddressTableLevel[]
+ {
+ new(23, 16),
+ new( 2, 21),
+ };
+
+ private static readonly AddressTableLevel[] _levels32BitSparse =
+ new AddressTableLevel[]
+ {
+ new(22, 10),
+ new( 1, 21),
+ };
+
+ public static AddressTableLevel[] GetArmPreset(bool for64Bits, bool sparse)
+ {
+ if (sparse)
+ {
+ return for64Bits ? _levels64BitSparse : _levels32BitSparse;
+ }
+ else
+ {
+ return for64Bits ? _levels64Bit : _levels32Bit;
+ }
+ }
+ }
+}
diff --git a/src/ARMeilleure/Common/Allocator.cs b/src/ARMeilleure/Common/Allocator.cs
index 6905a614f..de6a77ebe 100644
--- a/src/ARMeilleure/Common/Allocator.cs
+++ b/src/ARMeilleure/Common/Allocator.cs
@@ -2,7 +2,7 @@ using System;
namespace ARMeilleure.Common
{
- unsafe abstract class Allocator : IDisposable
+ public unsafe abstract class Allocator : IDisposable
{
public T* Allocate(ulong count = 1) where T : unmanaged
{
diff --git a/src/ARMeilleure/Common/IAddressTable.cs b/src/ARMeilleure/Common/IAddressTable.cs
new file mode 100644
index 000000000..4924b448b
--- /dev/null
+++ b/src/ARMeilleure/Common/IAddressTable.cs
@@ -0,0 +1,51 @@
+using System;
+
+namespace ARMeilleure.Common
+{
+ public interface IAddressTable : IDisposable where TEntry : unmanaged
+ {
+ ///
+ /// If true, the sparse 2-level table should be used to improve performance.
+ /// If false, the platform doesn't properly support it, or will be negatively impacted.
+ ///
+ static bool UseSparseTable { get; }
+
+ ///
+ /// Gets the bits used by the of the instance.
+ ///
+ ulong Mask { get; }
+
+ ///
+ /// Gets the s used by the instance.
+ ///
+ AddressTableLevel[] Levels { get; }
+
+ ///
+ /// Gets or sets the default fill value of newly created leaf pages.
+ ///
+ TEntry Fill { get; set; }
+
+ ///
+ /// Gets the base address of the .
+ ///
+ /// instance was disposed
+ IntPtr Base { get; }
+
+ ///
+ /// Determines if the specified is in the range of the
+ /// .
+ ///
+ /// Guest address
+ /// if is valid; otherwise
+ bool IsValid(ulong address);
+
+ ///
+ /// Gets a reference to the value at the specified guest .
+ ///
+ /// Guest address
+ /// Reference to the value at the specified guest
+ /// instance was disposed
+ /// is not mapped
+ ref TEntry GetValue(ulong address);
+ }
+}
diff --git a/src/ARMeilleure/Common/NativeAllocator.cs b/src/ARMeilleure/Common/NativeAllocator.cs
index 93c48adda..102e33ebe 100644
--- a/src/ARMeilleure/Common/NativeAllocator.cs
+++ b/src/ARMeilleure/Common/NativeAllocator.cs
@@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
namespace ARMeilleure.Common
{
- unsafe sealed class NativeAllocator : Allocator
+ public unsafe sealed class NativeAllocator : Allocator
{
public static NativeAllocator Instance { get; } = new();
diff --git a/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
index 2ec5bc1b3..896d372d1 100644
--- a/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
+++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs
@@ -8,7 +8,7 @@ namespace ARMeilleure.Signal
{
public static class NativeSignalHandlerGenerator
{
- public const int MaxTrackedRanges = 8;
+ public const int MaxTrackedRanges = 16;
private const int StructAddressOffset = 0;
private const int StructWriteOffset = 4;
diff --git a/src/ARMeilleure/Translation/ArmEmitterContext.cs b/src/ARMeilleure/Translation/ArmEmitterContext.cs
index e24074739..54cd97d53 100644
--- a/src/ARMeilleure/Translation/ArmEmitterContext.cs
+++ b/src/ARMeilleure/Translation/ArmEmitterContext.cs
@@ -46,7 +46,7 @@ namespace ARMeilleure.Translation
public IMemoryManager Memory { get; }
public EntryTable CountTable { get; }
- public AddressTable FunctionTable { get; }
+ public IAddressTable FunctionTable { get; }
public TranslatorStubs Stubs { get; }
public ulong EntryAddress { get; }
@@ -62,7 +62,7 @@ namespace ARMeilleure.Translation
public ArmEmitterContext(
IMemoryManager memory,
EntryTable countTable,
- AddressTable funcTable,
+ IAddressTable funcTable,
TranslatorStubs stubs,
ulong entryAddress,
bool highCq,
diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs
index 9a3d7cec5..45758059c 100644
--- a/src/ARMeilleure/Translation/Translator.cs
+++ b/src/ARMeilleure/Translation/Translator.cs
@@ -22,47 +22,13 @@ namespace ARMeilleure.Translation
{
public class Translator
{
- private static readonly AddressTable.Level[] _levels64Bit =
- new AddressTable.Level[]
- {
- new(31, 17),
- new(23, 8),
- new(15, 8),
- new( 7, 8),
- new( 2, 5),
- };
-
- private static readonly AddressTable.Level[] _levels32Bit =
- new AddressTable.Level[]
- {
- new(31, 17),
- new(23, 8),
- new(15, 8),
- new( 7, 8),
- new( 1, 6),
- };
-
- private static readonly AddressTable.Level[] _levels64BitSparse =
- new AddressTable.Level[]
- {
- new(23, 16),
- new( 2, 21),
- };
-
- private static readonly AddressTable.Level[] _levels32BitSparse =
- new AddressTable.Level[]
- {
- new(22, 10),
- new( 1, 21),
- };
-
private readonly IJitMemoryAllocator _allocator;
private readonly ConcurrentQueue> _oldFuncs;
private readonly Ptc _ptc;
internal TranslatorCache Functions { get; }
- internal AddressTable FunctionTable { get; }
+ internal IAddressTable FunctionTable { get; }
internal EntryTable CountTable { get; }
internal TranslatorStubs Stubs { get; }
internal TranslatorQueue Queue { get; }
@@ -71,7 +37,7 @@ namespace ARMeilleure.Translation
private Thread[] _backgroundTranslationThreads;
private volatile int _threadCount;
- public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits)
+ public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, IAddressTable functionTable)
{
_allocator = allocator;
Memory = memory;
@@ -84,22 +50,9 @@ namespace ARMeilleure.Translation
JitCache.Initialize(allocator);
- AddressTable.Level[] levels;
-
- bool useSparseTable = AddressTable.UseSparseTable;
-
- if (useSparseTable)
- {
- levels = for64Bits ? _levels64BitSparse : _levels32BitSparse;
- }
- else
- {
- levels = for64Bits ? _levels64Bit : _levels32Bit;
- }
-
CountTable = new EntryTable();
Functions = new TranslatorCache();
- FunctionTable = new AddressTable(levels, useSparseTable);
+ FunctionTable = functionTable;
Stubs = new TranslatorStubs(FunctionTable);
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
diff --git a/src/ARMeilleure/Translation/TranslatorStubs.cs b/src/ARMeilleure/Translation/TranslatorStubs.cs
index d80823a8b..379caa283 100644
--- a/src/ARMeilleure/Translation/TranslatorStubs.cs
+++ b/src/ARMeilleure/Translation/TranslatorStubs.cs
@@ -19,7 +19,7 @@ namespace ARMeilleure.Translation
private bool _disposed;
- private readonly AddressTable _functionTable;
+ private readonly IAddressTable _functionTable;
private readonly Lazy _dispatchStub;
private readonly Lazy _dispatchLoop;
private readonly Lazy _contextWrapper;
@@ -86,7 +86,7 @@ namespace ARMeilleure.Translation
///
/// Function table used to store pointers to the functions that the guest code will call
/// is null
- public TranslatorStubs(AddressTable functionTable)
+ public TranslatorStubs(IAddressTable functionTable)
{
ArgumentNullException.ThrowIfNull(functionTable);
diff --git a/src/ARMeilleure/Common/AddressTable.cs b/src/Ryujinx.Cpu/AddressTable.cs
similarity index 72%
rename from src/ARMeilleure/Common/AddressTable.cs
rename to src/Ryujinx.Cpu/AddressTable.cs
index ebe5dfb01..e8a0c423b 100644
--- a/src/ARMeilleure/Common/AddressTable.cs
+++ b/src/Ryujinx.Cpu/AddressTable.cs
@@ -1,10 +1,12 @@
-using ARMeilleure.Diagnostics;
+using Ryujinx.Common.Logging;
+using Ryujinx.Cpu.Signal;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
+using static Ryujinx.Cpu.MemoryEhMeilleure;
namespace ARMeilleure.Common
{
@@ -12,7 +14,7 @@ namespace ARMeilleure.Common
/// Represents a table of guest address to a value.
///
/// Type of the value
- public unsafe class AddressTable : IDisposable where TEntry : unmanaged
+ public unsafe class AddressTable : IAddressTable where TEntry : unmanaged
{
///
/// If true, the sparse 2-level table should be used to improve performance.
@@ -20,48 +22,6 @@ namespace ARMeilleure.Common
///
public static bool UseSparseTable => true;
- ///
- /// Represents a level in an .
- ///
- public readonly struct Level
- {
- ///
- /// Gets the index of the in the guest address.
- ///
- public int Index { get; }
-
- ///
- /// Gets the length of the in the guest address.
- ///
- public int Length { get; }
-
- ///
- /// Gets the mask which masks the bits used by the .
- ///
- public ulong Mask => ((1ul << Length) - 1) << Index;
-
- ///
- /// Initializes a new instance of the structure with the specified
- /// and .
- ///
- /// Index of the
- /// Length of the
- public Level(int index, int length)
- {
- (Index, Length) = (index, length);
- }
-
- ///
- /// Gets the value of the from the specified guest .
- ///
- /// Guest address
- /// Value of the from the specified guest
- public int GetValue(ulong address)
- {
- return (int)((address & Mask) >> Index);
- }
- }
-
private readonly struct AddressTablePage
{
public readonly bool IsSparse;
@@ -74,6 +34,50 @@ namespace ARMeilleure.Common
}
}
+ ///
+ /// A sparsely mapped block of memory with a signal handler to map pages as they're accessed.
+ ///
+ private readonly struct TableSparseBlock : IDisposable
+ {
+ public readonly SparseMemoryBlock Block;
+ public readonly TrackingEventDelegate TrackingEvent;
+
+ public TableSparseBlock(ulong size, Action ensureMapped, PageInitDelegate pageInit)
+ {
+ var block = new SparseMemoryBlock(size, pageInit, null);
+
+ TrackingEvent = (ulong address, ulong size, bool write) =>
+ {
+ Logger.Error?.PrintMsg(LogClass.Cpu, $"Triggered from exception");
+
+ ulong pointer = (ulong)block.Block.Pointer + address;
+
+ ensureMapped((IntPtr)pointer);
+
+ return pointer;
+ };
+
+ bool added = NativeSignalHandler.AddTrackedRegion(
+ (nuint)block.Block.Pointer,
+ (nuint)(block.Block.Pointer + (IntPtr)block.Block.Size),
+ Marshal.GetFunctionPointerForDelegate(TrackingEvent));
+
+ if (!added)
+ {
+ throw new InvalidOperationException("Number of allowed tracked regions exceeded.");
+ }
+
+ Block = block;
+ }
+
+ public void Dispose()
+ {
+ NativeSignalHandler.RemoveTrackedRegion((nuint)Block.Block.Pointer);
+
+ Block.Dispose();
+ }
+ }
+
private bool _disposed;
private TEntry** _table;
private readonly List _pages;
@@ -84,24 +88,19 @@ namespace ARMeilleure.Common
private readonly SparseMemoryBlock _fillBottomLevel;
private readonly TEntry* _fillBottomLevelPtr;
- private readonly List _sparseReserved;
+ private readonly List _sparseReserved;
private readonly ulong _sparseBlockSize;
private readonly ReaderWriterLockSlim _sparseLock;
+
private ulong _sparseReservedOffset;
- ///
- /// Gets the bits used by the of the instance.
- ///
+ ///
public ulong Mask { get; }
- ///
- /// Gets the s used by the instance.
- ///
- public Level[] Levels { get; }
+ ///
+ public AddressTableLevel[] Levels { get; }
- ///
- /// Gets or sets the default fill value of newly created leaf pages.
- ///
+ ///
public TEntry Fill
{
get
@@ -114,10 +113,7 @@ namespace ARMeilleure.Common
}
}
- ///
- /// Gets the base address of the .
- ///
- /// instance was disposed
+ ///
public IntPtr Base
{
get
@@ -139,7 +135,7 @@ namespace ARMeilleure.Common
/// True if the bottom page should be sparsely mapped
/// is null
/// Length of is less than 2
- public AddressTable(Level[] levels, bool sparse)
+ public AddressTable(AddressTableLevel[] levels, bool sparse)
{
ArgumentNullException.ThrowIfNull(levels);
@@ -171,13 +167,30 @@ namespace ARMeilleure.Common
_fillBottomLevel = new SparseMemoryBlock(bottomLevelSize, null, _sparseFill);
_fillBottomLevelPtr = (TEntry*)_fillBottomLevel.Block.Pointer;
- _sparseReserved = new List();
+ _sparseReserved = new List();
_sparseLock = new ReaderWriterLockSlim();
_sparseBlockSize = bottomLevelSize << 3;
}
}
+ ///
+ /// Create an instance for an ARM function table.
+ /// Selects the best table structure for A32/A64, taking into account whether sparse mapping is supported.
+ ///
+ /// True if the guest is A64, false otherwise
+ /// An for ARM function lookup
+ public static AddressTable CreateForArm(bool for64Bits)
+ {
+ bool sparse = UseSparseTable;
+
+ return new AddressTable(AddressTablePresets.GetArmPreset(for64Bits, sparse), sparse);
+ }
+
+ ///
+ /// Update the fill value for the bottom level of the table.
+ ///
+ /// New fill value
private void UpdateFill(TEntry fillValue)
{
if (_sparseFill != null)
@@ -189,24 +202,13 @@ namespace ARMeilleure.Common
_fill = fillValue;
}
- ///
- /// Determines if the specified is in the range of the
- /// .
- ///
- /// Guest address
- /// if is valid; otherwise
+ ///
public bool IsValid(ulong address)
{
return (address & ~Mask) == 0;
}
- ///
- /// Gets a reference to the value at the specified guest .
- ///
- /// Guest address
- /// Reference to the value at the specified guest
- /// instance was disposed
- /// is not mapped
+ ///
public ref TEntry GetValue(ulong address)
{
ObjectDisposedException.ThrowIf(_disposed, this);
@@ -239,12 +241,12 @@ namespace ARMeilleure.Common
for (int i = 0; i < Levels.Length - 1; i++)
{
- ref Level level = ref Levels[i];
+ ref AddressTableLevel level = ref Levels[i];
ref TEntry* nextPage = ref page[level.GetValue(address)];
if (nextPage == null || nextPage == _fillBottomLevelPtr)
{
- ref Level nextLevel = ref Levels[i + 1];
+ ref AddressTableLevel nextLevel = ref Levels[i + 1];
if (i == Levels.Length - 2)
{
@@ -273,8 +275,10 @@ namespace ARMeilleure.Common
try
{
- foreach (SparseMemoryBlock sparse in _sparseReserved)
+ foreach (TableSparseBlock reserved in _sparseReserved)
{
+ SparseMemoryBlock sparse = reserved.Block;
+
if (ptr >= sparse.Block.Pointer && ptr < sparse.Block.Pointer + (IntPtr)sparse.Block.Size)
{
sparse.EnsureMapped((ulong)(ptr - sparse.Block.Pointer));
@@ -290,6 +294,11 @@ namespace ARMeilleure.Common
}
}
+ ///
+ /// Get the fill value for a non-leaf level of the table.
+ ///
+ /// Level to get the fill value for
+ /// The fill value
private IntPtr GetFillValue(int level)
{
if (_fillBottomLevel != null && level == Levels.Length - 2)
@@ -316,9 +325,28 @@ namespace ARMeilleure.Common
return _table;
}
+ private int initedSize = 0;
+ private int reservedSize = 0;
+
+ ///
+ /// Initialize a leaf page with the fill value.
+ ///
+ /// Page to initialize
private void InitLeafPage(Span page)
{
MemoryMarshal.Cast(page).Fill(_fill);
+
+ initedSize += page.Length;
+
+ Ryujinx.Common.Logging.Logger.Info?.PrintMsg(LogClass.Cpu, $"Using memory {initedSize}/{reservedSize} bytes");
+ }
+
+ private void ReserveNewSparseBlock()
+ {
+ var block = new TableSparseBlock(_sparseBlockSize, EnsureMapped, InitLeafPage);
+
+ _sparseReserved.Add(block);
+ _sparseReservedOffset = 0;
}
///
@@ -333,6 +361,8 @@ namespace ARMeilleure.Common
{
var size = sizeof(T) * length;
+ reservedSize += size;
+
AddressTablePage page;
if (_sparse && leaf)
@@ -341,12 +371,10 @@ namespace ARMeilleure.Common
if (_sparseReserved.Count == 0 || _sparseReservedOffset == _sparseBlockSize)
{
- _sparseReserved.Add(new SparseMemoryBlock(_sparseBlockSize, InitLeafPage, _sparseFill));
-
- _sparseReservedOffset = 0;
+ ReserveNewSparseBlock();
}
- SparseMemoryBlock block = _sparseReserved.Last();
+ SparseMemoryBlock block = _sparseReserved.Last().Block;
page = new AddressTablePage(true, block.Block.Pointer + (IntPtr)_sparseReservedOffset);
@@ -365,7 +393,7 @@ namespace ARMeilleure.Common
_pages.Add(page);
- TranslatorEventSource.Log.AddressTableAllocated(size, leaf);
+ //TranslatorEventSource.Log.AddressTableAllocated(size, leaf);
return page.Address;
}
@@ -398,11 +426,13 @@ namespace ARMeilleure.Common
if (_sparse)
{
- foreach (SparseMemoryBlock block in _sparseReserved)
+ foreach (TableSparseBlock block in _sparseReserved)
{
block.Dispose();
}
+ _sparseReserved.Clear();
+
_fillBottomLevel.Dispose();
_sparseFill.Dispose();
_sparseLock.Dispose();
diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
index 9893c59b2..2b70b0239 100644
--- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
+++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Common;
using ARMeilleure.Memory;
using ARMeilleure.Translation;
using Ryujinx.Cpu.Signal;
@@ -9,11 +10,14 @@ namespace Ryujinx.Cpu.Jit
{
private readonly ITickSource _tickSource;
private readonly Translator _translator;
+ private readonly AddressTable _functionTable;
public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
{
_tickSource = tickSource;
- _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, for64Bit);
+ _functionTable = AddressTable.CreateForArm(for64Bit);
+
+ _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, _functionTable);
if (memory.Type.IsHostMappedOrTracked())
{
diff --git a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs
index b63636e39..2d4ca0fca 100644
--- a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs
+++ b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Common;
using ARMeilleure.Memory;
using Ryujinx.Cpu.Jit;
using Ryujinx.Cpu.LightningJit.State;
@@ -8,11 +9,15 @@ namespace Ryujinx.Cpu.LightningJit
{
private readonly ITickSource _tickSource;
private readonly Translator _translator;
+ private readonly AddressTable _functionTable;
public LightningJitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit)
{
_tickSource = tickSource;
- _translator = new Translator(memory, for64Bit);
+ _functionTable = AddressTable.CreateForArm(for64Bit);
+
+ _translator = new Translator(memory, _functionTable);
+
memory.UnmapEvent += UnmapHandler;
}
diff --git a/src/Ryujinx.Cpu/LightningJit/Translator.cs b/src/Ryujinx.Cpu/LightningJit/Translator.cs
index 19f883efa..bb12ac5fd 100644
--- a/src/Ryujinx.Cpu/LightningJit/Translator.cs
+++ b/src/Ryujinx.Cpu/LightningJit/Translator.cs
@@ -19,39 +19,6 @@ namespace Ryujinx.Cpu.LightningJit
// Should be enabled on platforms that enforce W^X.
private static bool IsNoWxPlatform => false;
- private static readonly AddressTable.Level[] _levels64Bit =
- new AddressTable.Level[]
- {
- new(31, 17),
- new(23, 8),
- new(15, 8),
- new( 7, 8),
- new( 2, 5),
- };
-
- private static readonly AddressTable.Level[] _levels32Bit =
- new AddressTable.Level[]
- {
- new(23, 9),
- new(15, 8),
- new( 7, 8),
- new( 1, 6),
- };
-
- private static readonly AddressTable.Level[] _levels64BitSparse =
- new AddressTable.Level[]
- {
- new(23, 16),
- new( 2, 21),
- };
-
- private static readonly AddressTable.Level[] _levels32BitSparse =
- new AddressTable.Level[]
- {
- new(22, 10),
- new( 1, 21),
- };
-
private readonly ConcurrentQueue> _oldFuncs;
private readonly NoWxCache _noWxCache;
private bool _disposed;
@@ -61,7 +28,7 @@ namespace Ryujinx.Cpu.LightningJit
internal TranslatorStubs Stubs { get; }
internal IMemoryManager Memory { get; }
- public Translator(IMemoryManager memory, bool for64Bits)
+ public Translator(IMemoryManager memory, AddressTable functionTable)
{
Memory = memory;
@@ -76,21 +43,8 @@ namespace Ryujinx.Cpu.LightningJit
JitCache.Initialize(new JitMemoryAllocator(forJit: true));
}
- bool useSparseTable = AddressTable.UseSparseTable;
-
- AddressTable.Level[] levels;
-
- if (useSparseTable)
- {
- levels = for64Bits ? _levels64BitSparse : _levels32BitSparse;
- }
- else
- {
- levels = for64Bits ? _levels64Bit : _levels32Bit;
- }
-
Functions = new TranslatorCache();
- FunctionTable = new AddressTable(levels, useSparseTable);
+ FunctionTable = functionTable;
Stubs = new TranslatorStubs(FunctionTable, _noWxCache);
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
diff --git a/src/Ryujinx.Memory/SparseMemoryBlock.cs b/src/Ryujinx.Memory/SparseMemoryBlock.cs
index 8c6dbea86..523685de1 100644
--- a/src/Ryujinx.Memory/SparseMemoryBlock.cs
+++ b/src/Ryujinx.Memory/SparseMemoryBlock.cs
@@ -2,6 +2,7 @@ using Ryujinx.Common;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
namespace Ryujinx.Memory
{
@@ -66,15 +67,15 @@ namespace Ryujinx.Memory
{
// Need to map some more memory.
- block = new MemoryBlock(MapGranularity, MemoryAllocationFlags.Mirrorable | MemoryAllocationFlags.NoMap);
+ block = new MemoryBlock(MapGranularity, MemoryAllocationFlags.Mirrorable);
_mappedBlocks.Add(block);
_mappedBlockUsage = 0;
}
+ _pageInit(block.GetSpan(_mappedBlockUsage, (int)_pageSize));
_reservedBlock.MapView(block, _mappedBlockUsage, pageOffset, _pageSize);
- _pageInit(_reservedBlock.GetSpan(pageOffset, (int)_pageSize));
_mappedBlockUsage += _pageSize;
}
@@ -87,7 +88,7 @@ namespace Ryujinx.Memory
ref ulong entry = ref _mappedPageBitmap[bitmapIndex];
ulong bit = 1UL << (pageIndex & 63);
- if ((entry & bit) == 0)
+ if ((Volatile.Read(ref entry) & bit) == 0)
{
// Not mapped.
@@ -95,11 +96,15 @@ namespace Ryujinx.Memory
{
// Check the bit while locked to make sure that this only happens once.
- if ((entry & bit) == 0)
+ ulong lockedEntry = Volatile.Read(ref entry);
+
+ if ((lockedEntry & bit) == 0)
{
MapPage(offset & ~(_pageSize - 1));
- entry |= bit;
+ lockedEntry |= bit;
+
+ Interlocked.Exchange(ref entry, lockedEntry);
}
}
}