From 52cf1418743950fde932e92fcf9655d5c392d9d7 Mon Sep 17 00:00:00 2001
From: Mary <mary@mary.zone>
Date: Sat, 3 Jun 2023 10:23:51 +0200
Subject: [PATCH] Armeilleure: Fix support for Windows on ARM64 (#5202)

* Armeilleure: Fix support for Windows on ARM64

Tested on Windows DevKit 2023.

* Address gdkchan's comments
---
 src/ARMeilleure/Translation/Cache/JitCache.cs | 22 ++++++++++++++++---
 .../Translation/Cache/JitCacheInvalidation.cs |  4 ++--
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs
index f496a8e9..daa2eeac 100644
--- a/src/ARMeilleure/Translation/Cache/JitCache.cs
+++ b/src/ARMeilleure/Translation/Cache/JitCache.cs
@@ -6,10 +6,11 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Runtime.InteropServices;
+using System.Runtime.Versioning;
 
 namespace ARMeilleure.Translation.Cache
 {
-    static class JitCache
+    static partial class JitCache
     {
         private const int PageSize = 4 * 1024;
         private const int PageMask = PageSize - 1;
@@ -27,6 +28,10 @@ namespace ARMeilleure.Translation.Cache
         private static readonly object _lock = new object();
         private static bool _initialized;
 
+        [SupportedOSPlatform("windows")]
+        [LibraryImport("kernel32.dll", SetLastError = true)]
+        public static partial IntPtr FlushInstructionCache(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize);
+
         public static void Initialize(IJitMemoryAllocator allocator)
         {
             if (_initialized) return;
@@ -36,7 +41,11 @@ namespace ARMeilleure.Translation.Cache
                 if (_initialized) return;
 
                 _jitRegion = new ReservedRegion(allocator, CacheSize);
-                _jitCacheInvalidator = new JitCacheInvalidation(allocator);
+
+                if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
+                {
+                    _jitCacheInvalidator = new JitCacheInvalidation(allocator);
+                }
 
                 _cacheAllocator = new CacheMemoryAllocator(CacheSize);
 
@@ -77,7 +86,14 @@ namespace ARMeilleure.Translation.Cache
                     Marshal.Copy(code, 0, funcPtr, code.Length);
                     ReprotectAsExecutable(funcOffset, code.Length);
 
-                    _jitCacheInvalidator.Invalidate(funcPtr, (ulong)code.Length);
+                    if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
+                    {
+                        FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (UIntPtr)code.Length);
+                    }
+                    else
+                    {
+                        _jitCacheInvalidator?.Invalidate(funcPtr, (ulong)code.Length);
+                    }
                 }
 
                 Add(funcOffset, code.Length, func.UnwindInfo);
diff --git a/src/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs b/src/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
index ec2ae73b..57f7bf12 100644
--- a/src/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
+++ b/src/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
@@ -47,8 +47,8 @@ namespace ARMeilleure.Translation.Cache
 
         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)
+            // On macOS and Windows, a different path is used to write to the JIT cache, which does the invalidation.
+            if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
             {
                 ulong size = (ulong)_invalidationCode.Length * sizeof(int);
                 ulong mask = (ulong)ReservedRegion.DefaultGranularity - 1;