diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2023-01-10 19:16:59 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-10 19:16:59 -0300 |
| commit | 5e0f8e873857ce3ca3f532aff0936beb28e412c8 (patch) | |
| tree | 576e5110c076b7d1f4d94e608ee21493f5b48879 /ARMeilleure/Translation/Cache | |
| parent | d16288a2a87f0979df30ba69d4fe10660177b6ac (diff) | |
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
Diffstat (limited to 'ARMeilleure/Translation/Cache')
| -rw-r--r-- | ARMeilleure/Translation/Cache/JitCache.cs | 26 | ||||
| -rw-r--r-- | ARMeilleure/Translation/Cache/JitCacheInvalidation.cs | 79 |
2 files changed, 99 insertions, 6 deletions
diff --git a/ARMeilleure/Translation/Cache/JitCache.cs b/ARMeilleure/Translation/Cache/JitCache.cs index 24affa34..f496a8e9 100644 --- a/ARMeilleure/Translation/Cache/JitCache.cs +++ b/ARMeilleure/Translation/Cache/JitCache.cs @@ -1,6 +1,7 @@ using ARMeilleure.CodeGen; using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.Memory; +using ARMeilleure.Native; using System; using System.Collections.Generic; using System.Diagnostics; @@ -17,6 +18,7 @@ namespace ARMeilleure.Translation.Cache private const int CacheSize = 2047 * 1024 * 1024; private static ReservedRegion _jitRegion; + private static JitCacheInvalidation _jitCacheInvalidator; private static CacheMemoryAllocator _cacheAllocator; @@ -25,8 +27,6 @@ namespace ARMeilleure.Translation.Cache private static readonly object _lock = new object(); private static bool _initialized; - public static IntPtr Base => _jitRegion.Pointer; - public static void Initialize(IJitMemoryAllocator allocator) { if (_initialized) return; @@ -36,6 +36,7 @@ namespace ARMeilleure.Translation.Cache if (_initialized) return; _jitRegion = new ReservedRegion(allocator, CacheSize); + _jitCacheInvalidator = new JitCacheInvalidation(allocator); _cacheAllocator = new CacheMemoryAllocator(CacheSize); @@ -60,11 +61,24 @@ namespace ARMeilleure.Translation.Cache IntPtr funcPtr = _jitRegion.Pointer + funcOffset; - ReprotectAsWritable(funcOffset, code.Length); - - Marshal.Copy(code, 0, funcPtr, code.Length); + if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + unsafe + { + fixed (byte *codePtr = code) + { + JitSupportDarwin.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length); + } + } + } + else + { + ReprotectAsWritable(funcOffset, code.Length); + Marshal.Copy(code, 0, funcPtr, code.Length); + ReprotectAsExecutable(funcOffset, code.Length); - ReprotectAsExecutable(funcOffset, code.Length); + _jitCacheInvalidator.Invalidate(funcPtr, (ulong)code.Length); + } Add(funcOffset, code.Length, func.UnwindInfo); diff --git a/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs b/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs new file mode 100644 index 00000000..ec2ae73b --- /dev/null +++ b/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs @@ -0,0 +1,79 @@ +using ARMeilleure.Memory; +using System; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Translation.Cache +{ + class JitCacheInvalidation + { + private static int[] _invalidationCode = new int[] + { + unchecked((int)0xd53b0022), // mrs x2, ctr_el0 + unchecked((int)0xd3504c44), // ubfx x4, x2, #16, #4 + unchecked((int)0x52800083), // mov w3, #0x4 + unchecked((int)0x12000c45), // and w5, w2, #0xf + unchecked((int)0x1ac42064), // lsl w4, w3, w4 + unchecked((int)0x51000482), // sub w2, w4, #0x1 + unchecked((int)0x8a220002), // bic x2, x0, x2 + unchecked((int)0x1ac52063), // lsl w3, w3, w5 + unchecked((int)0xeb01005f), // cmp x2, x1 + unchecked((int)0x93407c84), // sxtw x4, w4 + unchecked((int)0x540000a2), // b.cs 3c <do_ic_clear> + unchecked((int)0xd50b7b22), // dc cvau, x2 + unchecked((int)0x8b040042), // add x2, x2, x4 + unchecked((int)0xeb02003f), // cmp x1, x2 + unchecked((int)0x54ffffa8), // b.hi 2c <dc_clear_loop> + unchecked((int)0xd5033b9f), // dsb ish + unchecked((int)0x51000462), // sub w2, w3, #0x1 + unchecked((int)0x93407c63), // sxtw x3, w3 + unchecked((int)0x8a220000), // bic x0, x0, x2 + unchecked((int)0xeb00003f), // cmp x1, x0 + unchecked((int)0x540000a9), // b.ls 64 <exit> + unchecked((int)0xd50b7520), // ic ivau, x0 + unchecked((int)0x8b030000), // add x0, x0, x3 + unchecked((int)0xeb00003f), // cmp x1, x0 + unchecked((int)0x54ffffa8), // b.hi 54 <ic_clear_loop> + unchecked((int)0xd5033b9f), // dsb ish + unchecked((int)0xd5033fdf), // isb + unchecked((int)0xd65f03c0), // ret + }; + + private delegate void InvalidateCache(ulong start, ulong end); + + private InvalidateCache _invalidateCache; + private ReservedRegion _invalidateCacheCodeRegion; + + private readonly bool _needsInvalidation; + + public JitCacheInvalidation(IJitMemoryAllocator allocator) + { + // On macOS, a different path is used to write to the JIT cache, which does the invalidation. + if (!OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + ulong size = (ulong)_invalidationCode.Length * sizeof(int); + ulong mask = (ulong)ReservedRegion.DefaultGranularity - 1; + + size = (size + mask) & ~mask; + + _invalidateCacheCodeRegion = new ReservedRegion(allocator, size); + _invalidateCacheCodeRegion.ExpandIfNeeded(size); + + Marshal.Copy(_invalidationCode, 0, _invalidateCacheCodeRegion.Pointer, _invalidationCode.Length); + + _invalidateCacheCodeRegion.Block.MapAsRx(0, size); + + _invalidateCache = Marshal.GetDelegateForFunctionPointer<InvalidateCache>(_invalidateCacheCodeRegion.Pointer); + + _needsInvalidation = true; + } + } + + public void Invalidate(IntPtr basePointer, ulong size) + { + if (_needsInvalidation) + { + _invalidateCache((ulong)basePointer, (ulong)basePointer + size); + } + } + } +}
\ No newline at end of file |
