diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs index 7b5f2ca81..e480985b1 100644 --- a/src/ARMeilleure/Translation/Cache/JitCache.cs +++ b/src/ARMeilleure/Translation/Cache/JitCache.cs @@ -24,7 +24,7 @@ namespace ARMeilleure.Translation.Cache private static JitCacheInvalidation _jitCacheInvalidator; - private static CacheMemoryAllocator _cacheAllocator; + private static List _cacheAllocators = []; private static readonly List _cacheEntries = []; @@ -40,37 +40,48 @@ namespace ARMeilleure.Translation.Cache public static void Initialize(IJitMemoryAllocator allocator) { - if (_initialized) - { - return; - } - lock (_lock) { if (_initialized) { - return; + if (OperatingSystem.IsWindows()) + { + JitUnwindWindows.RemoveFunctionTableHandler( + _jitRegions[0].Pointer); + } + + for (int i = 0; i < _jitRegions.Count; i++) + { + _jitRegions[i].Dispose(); + } + + _jitRegions.Clear(); + _cacheAllocators.Clear(); } + else + { + _initialized = true; + } + + _activeRegionIndex = 0; ReservedRegion firstRegion = new(allocator, CacheSize); _jitRegions.Add(firstRegion); - _activeRegionIndex = 0; + + CacheMemoryAllocator firstCacheAllocator = new(CacheSize); + _cacheAllocators.Add(firstCacheAllocator); if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS()) { _jitCacheInvalidator = new JitCacheInvalidation(allocator); } - _cacheAllocator = new CacheMemoryAllocator(CacheSize); - if (OperatingSystem.IsWindows()) { JitUnwindWindows.InstallFunctionTableHandler( firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize) ); } - - _initialized = true; } } @@ -136,7 +147,7 @@ namespace ARMeilleure.Translation.Cache if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset) { - _cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size)); + _cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size)); _cacheEntries.RemoveAt(entryIndex); } @@ -167,30 +178,24 @@ namespace ARMeilleure.Translation.Cache { codeSize = AlignCodeSize(codeSize); - for (int i = _activeRegionIndex; i < _jitRegions.Count; i++) + int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize); + + if (allocOffset >= 0) { - int allocOffset = _cacheAllocator.Allocate(codeSize); - - if (allocOffset >= 0) - { - _jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); - _activeRegionIndex = i; - return allocOffset; - } + _jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); + return allocOffset; } int exhaustedRegion = _activeRegionIndex; ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize); _jitRegions.Add(newRegion); _activeRegionIndex = _jitRegions.Count - 1; - - int newRegionNumber = _activeRegionIndex; - Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((long)(newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation)."); - - _cacheAllocator = new CacheMemoryAllocator(CacheSize); + Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation)."); - int allocOffsetNew = _cacheAllocator.Allocate(codeSize); + _cacheAllocators.Add(new CacheMemoryAllocator(CacheSize)); + + int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize); if (allocOffsetNew < 0) { throw new OutOfMemoryException("Failed to allocate in new Cache Region!"); diff --git a/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs b/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs index 01b2aa8ed..15a1051fa 100644 --- a/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs +++ b/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs @@ -52,6 +52,11 @@ namespace ARMeilleure.Translation.Cache nint context, [MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll); + [LibraryImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static unsafe partial bool RtlDeleteFunctionTable( + ulong tableIdentifier); + private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback; private static int _sizeOfRuntimeFunction; @@ -91,6 +96,23 @@ namespace ARMeilleure.Translation.Cache } } + public static void RemoveFunctionTableHandler(nint codeCachePointer) + { + ulong codeCachePtr = (ulong)codeCachePointer.ToInt64(); + + bool result; + + unsafe + { + result = RtlDeleteFunctionTable(codeCachePtr | 3); + } + + if (!result) + { + throw new InvalidOperationException("Failure removing function table callback."); + } + } + private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context) { int offset = (int)((long)controlPc - context.ToInt64()); diff --git a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs index 32ed6de39..881f6d556 100644 --- a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs +++ b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs @@ -200,7 +200,7 @@ namespace Ryujinx.Ava.UI.Controls if (backupDir.Exists) { cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache")); - cacheFiles.AddRange(mainDir.EnumerateFiles("*.info")); + cacheFiles.AddRange(backupDir.EnumerateFiles("*.info")); } if (cacheFiles.Count > 0)