Ryujinx/ARMeilleure/Instructions/NativeInterface.cs
LDj3SNuD 5e724cf24e
Add Profiled Persistent Translation Cache. (#769)
* Delete DelegateTypes.cs

* Delete DelegateCache.cs

* Add files via upload

* Update Horizon.cs

* Update Program.cs

* Update MainWindow.cs

* Update Aot.cs

* Update RelocEntry.cs

* Update Translator.cs

* Update MemoryManager.cs

* Update InstEmitMemoryHelper.cs

* Update Delegates.cs

* Nit.

* Nit.

* Nit.

* 10 fewer MSIL bytes for us

* Add comment. Nits.

* Update Translator.cs

* Update Aot.cs

* Nits.

* Opt..

* Opt..

* Opt..

* Opt..

* Allow to change compression level.

* Update MemoryManager.cs

* Update Translator.cs

* Manage corner cases during the save phase. Nits.

* Update Aot.cs

* Translator response tweak for Aot disabled. Nit.

* Nit.

* Nits.

* Create DelegateHelpers.cs

* Update Delegates.cs

* Nit.

* Nit.

* Nits.

* Fix due to #784.

* Fixes due to #757 & #841.

* Fix due to #846.

* Fix due to #847.

* Use MethodInfo for managed method calls.

Use IR methods instead of managed methods about Max/Min (S/U).
Follow-ups & Nits.

* Add missing exception messages.

Reintroduce slow path for Fmov_Vi.
Implement slow path for Fmov_Si.

* Switch to the new folder structure.

Nits.

* Impl. index-based relocation information. Impl. cache file version field.

* Nit.

* Address gdkchan comments.

Mainly:
- fixed cache file corruption issue on exit; - exposed a way to disable AOT on the GUI.

* Address AcK77 comment.

* Address Thealexbarney, jduncanator & emmauss comments.

Header magic, CpuId (FI) & Aot -> Ptc.

* Adaptation to the new application reloading system.

Improvements to the call system of managed methods.
Follow-ups.
Nits.

* Get the same boot times as on master when PTC is disabled.

* Profiled Aot.

* A32 support (#897).

* #975 support (1 of 2).

* #975 support (2 of 2).

* Rebase fix & nits.

* Some fixes and nits (still one bug left).

* One fix & nits.

* Tests fix (by gdk) & nits.

* Support translations not only in high quality and rejit.

Nits.

* Added possibility to skip translations and continue execution, using `ESC` key.

* Update SettingsWindow.cs

* Update GLRenderer.cs

* Update Ptc.cs

* Disabled Profiled PTC by default as requested in the past by gdk.

* Fix rejit bug. Increased number of parallel translations. Add stack unwinding stuffs support (1 of 2).

Nits.

* Add stack unwinding stuffs support (2 of 2). Tuned number of parallel translations.

* Restored the ability to assemble jumps with 8-bit offset when Profiled PTC is disabled or during profiling.

Modifications due to rebase.
Nits.

* Limited profiling of the functions to be translated to the addresses belonging to the range of static objects only.

* Nits.

* Nits.

* Update Delegates.cs

* Nit.

* Update InstEmitSimdArithmetic.cs

* Address riperiperi comments.

* Fixed the issue of unjustifiably longer boot times at the second boot than at the first boot, measured at the same time or reference point and with the same number of translated functions.

* Implemented a simple redundant load/save mechanism.

Halved the value of Decoder.MaxInstsPerFunction more appropriate for the current performance of the Translator.
Replaced by Logger.PrintError to Logger.PrintDebug in TexturePool.cs about the supposed invalid texture format to avoid the spawn of the log.
Nits.

* Nit.

Improved Logger.PrintError in TexturePool.cs to avoid log spawn.
Added missing code for FZ handling (in output) for fp max/min instructions (slow paths).

* Add configuration migration for PTC

Co-authored-by: Thog <me@thog.eu>
2020-06-16 20:28:02 +02:00

457 lines
13 KiB
C#

using ARMeilleure.Memory;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace ARMeilleure.Instructions
{
static class NativeInterface
{
private const int ErgSizeLog2 = 4;
private class ThreadContext
{
public State.ExecutionContext Context { get; }
public IMemoryManager Memory { get; }
public Translator Translator { get; }
public ulong ExclusiveAddress { get; set; }
public ulong ExclusiveValueLow { get; set; }
public ulong ExclusiveValueHigh { get; set; }
public ThreadContext(State.ExecutionContext context, IMemoryManager memory, Translator translator)
{
Context = context;
Memory = memory;
Translator = translator;
ExclusiveAddress = ulong.MaxValue;
}
}
[ThreadStatic]
private static ThreadContext _context;
public static void RegisterThread(State.ExecutionContext context, IMemoryManager memory, Translator translator)
{
_context = new ThreadContext(context, memory, translator);
}
public static void UnregisterThread()
{
_context = null;
}
public static void Break(ulong address, int imm)
{
Statistics.PauseTimer();
GetContext().OnBreak(address, imm);
Statistics.ResumeTimer();
}
public static void SupervisorCall(ulong address, int imm)
{
Statistics.PauseTimer();
GetContext().OnSupervisorCall(address, imm);
Statistics.ResumeTimer();
}
public static void Undefined(ulong address, int opCode)
{
Statistics.PauseTimer();
GetContext().OnUndefined(address, opCode);
Statistics.ResumeTimer();
}
#region "System registers"
public static ulong GetCtrEl0()
{
return (ulong)GetContext().CtrEl0;
}
public static ulong GetDczidEl0()
{
return (ulong)GetContext().DczidEl0;
}
public static ulong GetFpcr()
{
return (ulong)GetContext().Fpcr;
}
public static ulong GetFpsr()
{
return (ulong)GetContext().Fpsr;
}
public static uint GetFpscr()
{
var context = GetContext();
uint result = (uint)(context.Fpsr & FPSR.A32Mask) | (uint)(context.Fpcr & FPCR.A32Mask);
result |= context.GetFPstateFlag(FPState.NFlag) ? (1u << 31) : 0;
result |= context.GetFPstateFlag(FPState.ZFlag) ? (1u << 30) : 0;
result |= context.GetFPstateFlag(FPState.CFlag) ? (1u << 29) : 0;
result |= context.GetFPstateFlag(FPState.VFlag) ? (1u << 28) : 0;
return result;
}
public static ulong GetTpidrEl0()
{
return (ulong)GetContext().TpidrEl0;
}
public static uint GetTpidrEl032()
{
return (uint)GetContext().TpidrEl0;
}
public static ulong GetTpidr()
{
return (ulong)GetContext().Tpidr;
}
public static uint GetTpidr32()
{
return (uint)GetContext().Tpidr;
}
public static ulong GetCntfrqEl0()
{
return GetContext().CntfrqEl0;
}
public static ulong GetCntpctEl0()
{
return GetContext().CntpctEl0;
}
public static ulong GetCntvctEl0()
{
return GetContext().CntvctEl0;
}
public static void SetFpcr(ulong value)
{
GetContext().Fpcr = (FPCR)value;
}
public static void SetFpsr(ulong value)
{
GetContext().Fpsr = (FPSR)value;
}
public static void SetFpscr(uint value)
{
var context = GetContext();
context.SetFPstateFlag(FPState.NFlag, (value & (1u << 31)) != 0);
context.SetFPstateFlag(FPState.ZFlag, (value & (1u << 30)) != 0);
context.SetFPstateFlag(FPState.CFlag, (value & (1u << 29)) != 0);
context.SetFPstateFlag(FPState.VFlag, (value & (1u << 28)) != 0);
context.Fpsr = FPSR.A32Mask & (FPSR)value;
context.Fpcr = FPCR.A32Mask & (FPCR)value;
}
public static void SetTpidrEl0(ulong value)
{
GetContext().TpidrEl0 = (long)value;
}
public static void SetTpidrEl032(uint value)
{
GetContext().TpidrEl0 = (long)value;
}
#endregion
#region "Read"
public static byte ReadByte(ulong address)
{
return GetMemoryManager().Read<byte>(address);
}
public static ushort ReadUInt16(ulong address)
{
return GetMemoryManager().Read<ushort>(address);
}
public static uint ReadUInt32(ulong address)
{
return GetMemoryManager().Read<uint>(address);
}
public static ulong ReadUInt64(ulong address)
{
return GetMemoryManager().Read<ulong>(address);
}
public static V128 ReadVector128(ulong address)
{
return GetMemoryManager().Read<V128>(address);
}
#endregion
#region "Read exclusive"
public static byte ReadByteExclusive(ulong address)
{
byte value = _context.Memory.Read<byte>(address);
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
_context.ExclusiveValueLow = value;
_context.ExclusiveValueHigh = 0;
return value;
}
public static ushort ReadUInt16Exclusive(ulong address)
{
ushort value = _context.Memory.Read<ushort>(address);
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
_context.ExclusiveValueLow = value;
_context.ExclusiveValueHigh = 0;
return value;
}
public static uint ReadUInt32Exclusive(ulong address)
{
uint value = _context.Memory.Read<uint>(address);
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
_context.ExclusiveValueLow = value;
_context.ExclusiveValueHigh = 0;
return value;
}
public static ulong ReadUInt64Exclusive(ulong address)
{
ulong value = _context.Memory.Read<ulong>(address);
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
_context.ExclusiveValueLow = value;
_context.ExclusiveValueHigh = 0;
return value;
}
public static V128 ReadVector128Exclusive(ulong address)
{
V128 value = MemoryManagerPal.AtomicLoad128(ref _context.Memory.GetRef<V128>(address));
_context.ExclusiveAddress = GetMaskedExclusiveAddress(address);
_context.ExclusiveValueLow = value.Extract<ulong>(0);
_context.ExclusiveValueHigh = value.Extract<ulong>(1);
return value;
}
#endregion
#region "Write"
public static void WriteByte(ulong address, byte value)
{
GetMemoryManager().Write(address, value);
}
public static void WriteUInt16(ulong address, ushort value)
{
GetMemoryManager().Write(address, value);
}
public static void WriteUInt32(ulong address, uint value)
{
GetMemoryManager().Write(address, value);
}
public static void WriteUInt64(ulong address, ulong value)
{
GetMemoryManager().Write(address, value);
}
public static void WriteVector128(ulong address, V128 value)
{
GetMemoryManager().Write(address, value);
}
#endregion
#region "Write exclusive"
public static int WriteByteExclusive(ulong address, byte value)
{
bool success = _context.ExclusiveAddress == GetMaskedExclusiveAddress(address);
if (success)
{
ref int valueRef = ref _context.Memory.GetRefNoChecks<int>(address);
int currentValue = valueRef;
byte expected = (byte)_context.ExclusiveValueLow;
int expected32 = (currentValue & ~byte.MaxValue) | expected;
int desired32 = (currentValue & ~byte.MaxValue) | value;
success = Interlocked.CompareExchange(ref valueRef, desired32, expected32) == expected32;
if (success)
{
ClearExclusive();
}
}
return success ? 0 : 1;
}
public static int WriteUInt16Exclusive(ulong address, ushort value)
{
bool success = _context.ExclusiveAddress == GetMaskedExclusiveAddress(address);
if (success)
{
ref int valueRef = ref _context.Memory.GetRefNoChecks<int>(address);
int currentValue = valueRef;
ushort expected = (ushort)_context.ExclusiveValueLow;
int expected32 = (currentValue & ~ushort.MaxValue) | expected;
int desired32 = (currentValue & ~ushort.MaxValue) | value;
success = Interlocked.CompareExchange(ref valueRef, desired32, expected32) == expected32;
if (success)
{
ClearExclusive();
}
}
return success ? 0 : 1;
}
public static int WriteUInt32Exclusive(ulong address, uint value)
{
bool success = _context.ExclusiveAddress == GetMaskedExclusiveAddress(address);
if (success)
{
ref int valueRef = ref _context.Memory.GetRef<int>(address);
success = Interlocked.CompareExchange(ref valueRef, (int)value, (int)_context.ExclusiveValueLow) == (int)_context.ExclusiveValueLow;
if (success)
{
ClearExclusive();
}
}
return success ? 0 : 1;
}
public static int WriteUInt64Exclusive(ulong address, ulong value)
{
bool success = _context.ExclusiveAddress == GetMaskedExclusiveAddress(address);
if (success)
{
ref long valueRef = ref _context.Memory.GetRef<long>(address);
success = Interlocked.CompareExchange(ref valueRef, (long)value, (long)_context.ExclusiveValueLow) == (long)_context.ExclusiveValueLow;
if (success)
{
ClearExclusive();
}
}
return success ? 0 : 1;
}
public static int WriteVector128Exclusive(ulong address, V128 value)
{
bool success = _context.ExclusiveAddress == GetMaskedExclusiveAddress(address);
if (success)
{
V128 expected = new V128(_context.ExclusiveValueLow, _context.ExclusiveValueHigh);
ref V128 location = ref _context.Memory.GetRef<V128>(address);
success = MemoryManagerPal.CompareAndSwap128(ref location, expected, value) == expected;
if (success)
{
ClearExclusive();
}
}
return success ? 0 : 1;
}
#endregion
private static ulong GetMaskedExclusiveAddress(ulong address)
{
return address & ~((4UL << ErgSizeLog2) - 1);
}
public static ulong GetFunctionAddress(ulong address)
{
TranslatedFunction function = _context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
return (ulong)function.FuncPtr.ToInt64();
}
public static ulong GetIndirectFunctionAddress(ulong address, ulong entryAddress)
{
TranslatedFunction function = _context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
ulong ptr = (ulong)function.FuncPtr.ToInt64();
if (function.HighCq)
{
// Rewrite the host function address in the table to point to the highCq function.
Marshal.WriteInt64((IntPtr)entryAddress, 8, (long)ptr);
}
return ptr;
}
public static void ClearExclusive()
{
_context.ExclusiveAddress = ulong.MaxValue;
}
public static bool CheckSynchronization()
{
Statistics.PauseTimer();
var context = GetContext();
context.CheckInterrupt();
Statistics.ResumeTimer();
return context.Running;
}
public static State.ExecutionContext GetContext()
{
return _context.Context;
}
public static IMemoryManager GetMemoryManager()
{
return _context.Memory;
}
}
}