From a731ab3a2aad56e6ceb8b4e2444a61353246295c Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Thu, 8 Aug 2019 15:56:22 -0300
Subject: Add a new JIT compiler for CPU code (#693)

* Start of the ARMeilleure project

* Refactoring around the old IRAdapter, now renamed to PreAllocator

* Optimize the LowestBitSet method

* Add CLZ support and fix CLS implementation

* Add missing Equals and GetHashCode overrides on some structs, misc small tweaks

* Implement the ByteSwap IR instruction, and some refactoring on the assembler

* Implement the DivideUI IR instruction and fix 64-bits IDIV

* Correct constant operand type on CSINC

* Move division instructions implementation to InstEmitDiv

* Fix destination type for the ConditionalSelect IR instruction

* Implement UMULH and SMULH, with new IR instructions

* Fix some issues with shift instructions

* Fix constant types for BFM instructions

* Fix up new tests using the new V128 struct

* Update tests

* Move DIV tests to a separate file

* Add support for calls, and some instructions that depends on them

* Start adding support for SIMD & FP types, along with some of the related ARM instructions

* Fix some typos and the divide instruction with FP operands

* Fix wrong method call on Clz_V

* Implement ARM FP & SIMD move instructions, Saddlv_V, and misc. fixes

* Implement SIMD logical instructions and more misc. fixes

* Fix PSRAD x86 instruction encoding, TRN, UABD and UABDL implementations

* Implement float conversion instruction, merge in LDj3SNuD fixes, and some other misc. fixes

* Implement SIMD shift instruction and fix Dup_V

* Add SCVTF and UCVTF (vector, fixed-point) variants to the opcode table

* Fix check with tolerance on tester

* Implement FP & SIMD comparison instructions, and some fixes

* Update FCVT (Scalar) encoding on the table to support the Half-float variants

* Support passing V128 structs, some cleanup on the register allocator, merge LDj3SNuD fixes

* Use old memory access methods, made a start on SIMD memory insts support, some fixes

* Fix float constant passed to functions, save and restore non-volatile XMM registers, other fixes

* Fix arguments count with struct return values, other fixes

* More instructions

* Misc. fixes and integrate LDj3SNuD fixes

* Update tests

* Add a faster linear scan allocator, unwinding support on windows, and other changes

* Update Ryujinx.HLE

* Update Ryujinx.Graphics

* Fix V128 return pointer passing, RCX is clobbered

* Update Ryujinx.Tests

* Update ITimeZoneService

* Stop using GetFunctionPointer as that can't be called from native code, misc. fixes and tweaks

* Use generic GetFunctionPointerForDelegate method and other tweaks

* Some refactoring on the code generator, assert on invalid operations and use a separate enum for intrinsics

* Remove some unused code on the assembler

* Fix REX.W prefix regression on float conversion instructions, add some sort of profiler

* Add hardware capability detection

* Fix regression on Sha1h and revert Fcm** changes

* Add SSE2-only paths on vector extract and insert, some refactoring on the pre-allocator

* Fix silly mistake introduced on last commit on CpuId

* Generate inline stack probes when the stack allocation is too large

* Initial support for the System-V ABI

* Support multiple destination operands

* Fix SSE2 VectorInsert8 path, and other fixes

* Change placement of XMM callee save and restore code to match other compilers

* Rename Dest to Destination and Inst to Instruction

* Fix a regression related to calls and the V128 type

* Add an extra space on comments to match code style

* Some refactoring

* Fix vector insert FP32 SSE2 path

* Port over the ARM32 instructions

* Avoid memory protection races on JIT Cache

* Another fix on VectorInsert FP32 (thanks to LDj3SNuD

* Float operands don't need to use the same register when VEX is supported

* Add a new register allocator, higher quality code for hot code (tier up), and other tweaks

* Some nits, small improvements on the pre allocator

* CpuThreadState is gone

* Allow changing CPU emulators with a config entry

* Add runtime identifiers on the ARMeilleure project

* Allow switching between CPUs through a config entry (pt. 2)

* Change win10-x64 to win-x64 on projects

* Update the Ryujinx project to use ARMeilleure

* Ensure that the selected register is valid on the hybrid allocator

* Allow exiting on returns to 0 (should fix test regression)

* Remove register assignments for most used variables on the hybrid allocator

* Do not use fixed registers as spill temp

* Add missing namespace and remove unneeded using

* Address PR feedback

* Fix types, etc

* Enable AssumeStrictAbiCompliance by default

* Ensure that Spill and Fill don't load or store any more than necessary
---
 ARMeilleure/Memory/MemoryManagementWindows.cs | 156 ++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)
 create mode 100644 ARMeilleure/Memory/MemoryManagementWindows.cs

(limited to 'ARMeilleure/Memory/MemoryManagementWindows.cs')

diff --git a/ARMeilleure/Memory/MemoryManagementWindows.cs b/ARMeilleure/Memory/MemoryManagementWindows.cs
new file mode 100644
index 00000000..c1a84c95
--- /dev/null
+++ b/ARMeilleure/Memory/MemoryManagementWindows.cs
@@ -0,0 +1,156 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Memory
+{
+    static class MemoryManagementWindows
+    {
+        [Flags]
+        private enum AllocationType : uint
+        {
+            Commit     = 0x1000,
+            Reserve    = 0x2000,
+            Decommit   = 0x4000,
+            Release    = 0x8000,
+            Reset      = 0x80000,
+            Physical   = 0x400000,
+            TopDown    = 0x100000,
+            WriteWatch = 0x200000,
+            LargePages = 0x20000000
+        }
+
+        [Flags]
+        private enum MemoryProtection : uint
+        {
+            NoAccess                 = 0x01,
+            ReadOnly                 = 0x02,
+            ReadWrite                = 0x04,
+            WriteCopy                = 0x08,
+            Execute                  = 0x10,
+            ExecuteRead              = 0x20,
+            ExecuteReadWrite         = 0x40,
+            ExecuteWriteCopy         = 0x80,
+            GuardModifierflag        = 0x100,
+            NoCacheModifierflag      = 0x200,
+            WriteCombineModifierflag = 0x400
+        }
+
+        private enum WriteWatchFlags : uint
+        {
+            None  = 0,
+            Reset = 1
+        }
+
+        [DllImport("kernel32.dll")]
+        private static extern IntPtr VirtualAlloc(
+            IntPtr           lpAddress,
+            IntPtr           dwSize,
+            AllocationType   flAllocationType,
+            MemoryProtection flProtect);
+
+        [DllImport("kernel32.dll")]
+        private static extern bool VirtualProtect(
+            IntPtr               lpAddress,
+            IntPtr               dwSize,
+            MemoryProtection     flNewProtect,
+            out MemoryProtection lpflOldProtect);
+
+        [DllImport("kernel32.dll")]
+        private static extern bool VirtualFree(
+            IntPtr         lpAddress,
+            IntPtr         dwSize,
+            AllocationType dwFreeType);
+
+        [DllImport("kernel32.dll")]
+        private static extern int GetWriteWatch(
+            WriteWatchFlags dwFlags,
+            IntPtr          lpBaseAddress,
+            IntPtr          dwRegionSize,
+            IntPtr[]        lpAddresses,
+            ref ulong       lpdwCount,
+            out uint        lpdwGranularity);
+
+        public static IntPtr Allocate(IntPtr size)
+        {
+            const AllocationType flags =
+                AllocationType.Reserve |
+                AllocationType.Commit;
+
+            IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite);
+
+            if (ptr == IntPtr.Zero)
+            {
+                throw new OutOfMemoryException();
+            }
+
+            return ptr;
+        }
+
+        public static IntPtr AllocateWriteTracked(IntPtr size)
+        {
+            const AllocationType flags =
+                AllocationType.Reserve |
+                AllocationType.Commit  |
+                AllocationType.WriteWatch;
+
+            IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite);
+
+            if (ptr == IntPtr.Zero)
+            {
+                throw new OutOfMemoryException();
+            }
+
+            return ptr;
+        }
+
+        public static bool Reprotect(IntPtr address, IntPtr size, Memory.MemoryProtection protection)
+        {
+            MemoryProtection prot = GetProtection(protection);
+
+            return VirtualProtect(address, size, prot, out _);
+        }
+
+        private static MemoryProtection GetProtection(Memory.MemoryProtection protection)
+        {
+            switch (protection)
+            {
+                case Memory.MemoryProtection.None:             return MemoryProtection.NoAccess;
+                case Memory.MemoryProtection.Read:             return MemoryProtection.ReadOnly;
+                case Memory.MemoryProtection.ReadAndWrite:     return MemoryProtection.ReadWrite;
+                case Memory.MemoryProtection.ReadAndExecute:   return MemoryProtection.ExecuteRead;
+                case Memory.MemoryProtection.ReadWriteExecute: return MemoryProtection.ExecuteReadWrite;
+                case Memory.MemoryProtection.Execute:          return MemoryProtection.Execute;
+
+                default: throw new ArgumentException($"Invalid permission \"{protection}\".");
+            }
+        }
+
+        public static bool Free(IntPtr address)
+        {
+            return VirtualFree(address, IntPtr.Zero, AllocationType.Release);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool GetModifiedPages(
+            IntPtr    address,
+            IntPtr    size,
+            IntPtr[]  addresses,
+            out ulong count)
+        {
+            ulong pagesCount = (ulong)addresses.Length;
+
+            int result = GetWriteWatch(
+                WriteWatchFlags.Reset,
+                address,
+                size,
+                addresses,
+                ref pagesCount,
+                out uint granularity);
+
+            count = pagesCount;
+
+            return result == 0;
+        }
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2