diff --git a/src/ARMeilleure/Common/IAddressTable.cs b/src/ARMeilleure/Common/IAddressTable.cs index 5be934163..116ccdaad 100644 --- a/src/ARMeilleure/Common/IAddressTable.cs +++ b/src/ARMeilleure/Common/IAddressTable.cs @@ -5,12 +5,18 @@ namespace ARMeilleure.Common public interface IAddressTable : IDisposable where TEntry : unmanaged { /// - /// Gets the bits used by the of the instance. + /// True if the address table's bottom level is sparsely mapped. + /// This also ensures the second bottom level is filled with a dummy page rather than 0. + /// + bool Sparse { get; } + + /// + /// Gets the bits used by the of the instance. /// ulong Mask { get; } /// - /// Gets the s used by the instance. + /// Gets the s used by the instance. /// AddressTableLevel[] Levels { get; } @@ -27,7 +33,7 @@ namespace ARMeilleure.Common /// /// Determines if the specified is in the range of the - /// . + /// . /// /// Guest address /// if is valid; otherwise diff --git a/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs index 2a0355cc3..12f1dba18 100644 --- a/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs +++ b/src/ARMeilleure/Instructions/InstEmitFlowHelper.cs @@ -205,7 +205,7 @@ namespace ARMeilleure.Instructions hostAddress = context.Load(OperandType.I64, hostAddressAddr); } - else if (table.Levels.Length == 2) + else if (table.Sparse && table.Levels.Length == 2) { // Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels. // Deliberately attempts to avoid branches. diff --git a/src/Ryujinx.Cpu/AddressTable.cs b/src/Ryujinx.Cpu/AddressTable.cs index d2f03c801..ee53e925d 100644 --- a/src/Ryujinx.Cpu/AddressTable.cs +++ b/src/Ryujinx.Cpu/AddressTable.cs @@ -18,9 +18,19 @@ namespace ARMeilleure.Common /// Type of the value public unsafe class AddressTable : IAddressTable where TEntry : unmanaged { + /// + /// Represents a page of the address table. + /// private readonly struct AddressTablePage { + /// + /// True if the allocation belongs to a sparse block, false otherwise. + /// public readonly bool IsSparse; + + /// + /// Base address for the page. + /// public readonly IntPtr Address; public AddressTablePage(bool isSparse, IntPtr address) @@ -36,13 +46,13 @@ namespace ARMeilleure.Common private readonly struct TableSparseBlock : IDisposable { public readonly SparseMemoryBlock Block; - public readonly TrackingEventDelegate TrackingEvent; + private 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) => + _trackingEvent = (ulong address, ulong size, bool write) => { Logger.Error?.PrintMsg(LogClass.Cpu, $"Triggered from exception"); @@ -56,7 +66,7 @@ namespace ARMeilleure.Common bool added = NativeSignalHandler.AddTrackedRegion( (nuint)block.Block.Pointer, (nuint)(block.Block.Pointer + (IntPtr)block.Block.Size), - Marshal.GetFunctionPointerForDelegate(TrackingEvent)); + Marshal.GetFunctionPointerForDelegate(_trackingEvent)); if (!added) { @@ -79,7 +89,6 @@ namespace ARMeilleure.Common private readonly List _pages; private TEntry _fill; - private readonly bool _sparse; private readonly MemoryBlock _sparseFill; private readonly SparseMemoryBlock _fillBottomLevel; private readonly TEntry* _fillBottomLevelPtr; @@ -90,6 +99,8 @@ namespace ARMeilleure.Common private ulong _sparseBlockSize; private ulong _sparseReservedOffset; + public bool Sparse { get; } + /// public ulong Mask { get; } @@ -150,7 +161,7 @@ namespace ARMeilleure.Common Mask |= level.Mask; } - _sparse = sparse; + Sparse = sparse; if (sparse) { @@ -279,9 +290,13 @@ namespace ARMeilleure.Common return (TEntry*)page; } + /// + /// Ensure the given pointer is mapped in any overlapping sparse reservations. + /// + /// Pointer to be mapped private void EnsureMapped(IntPtr ptr) { - if (_sparse) + if (Sparse) { // Check sparse allocations to see if the pointer is in any of them. // Ensure the page is committed if there's a match. @@ -356,6 +371,10 @@ namespace ARMeilleure.Common Ryujinx.Common.Logging.Logger.Info?.PrintMsg(LogClass.Cpu, $"Using memory {initedSize}/{reservedSize} bytes"); } + /// + /// Reserve a new sparse block, and add it to the list. + /// + /// The new sparse block that was added private TableSparseBlock ReserveNewSparseBlock() { var block = new TableSparseBlock(_sparseBlockSize, EnsureMapped, InitLeafPage); @@ -382,7 +401,7 @@ namespace ARMeilleure.Common AddressTablePage page; - if (_sparse && leaf) + if (Sparse && leaf) { _sparseLock.EnterWriteLock(); @@ -450,7 +469,7 @@ namespace ARMeilleure.Common } } - if (_sparse) + if (Sparse) { foreach (TableSparseBlock block in _sparseReserved) { diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs index f0b18fcbf..b2192f3d4 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs @@ -142,7 +142,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 int tempRegister; int tempGuestAddress = -1; - bool inlineLookup = guestAddress.Kind != OperandKind.Constant && funcTable != null && funcTable.Levels.Length == 2; + bool inlineLookup = guestAddress.Kind != OperandKind.Constant && funcTable != null && funcTable.Sparse && funcTable.Levels.Length == 2; if (guestAddress.Kind == OperandKind.Constant) { diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs index dc8fc2c14..8fa95b8a5 100644 --- a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs @@ -307,7 +307,7 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 int tempRegister; int tempGuestAddress = -1; - bool inlineLookup = guestAddress.Kind != OperandKind.Constant && funcTable != null && funcTable.Levels.Length == 2; + bool inlineLookup = guestAddress.Kind != OperandKind.Constant && funcTable != null && funcTable.Sparse && funcTable.Levels.Length == 2; if (guestAddress.Kind == OperandKind.Constant) {