mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-12-24 13:56:01 +00:00
Add PPTC support
This commit is contained in:
parent
1803b9fef9
commit
4478a32114
4 changed files with 44 additions and 33 deletions
|
@ -35,9 +35,9 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||||
return Operand().With(value);
|
return Operand().With(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe Operand Const<T>(ref T reference)
|
public static unsafe Operand Const<T>(ref T reference, int? index = null)
|
||||||
{
|
{
|
||||||
return Operand().With((ulong)Unsafe.AsPointer(ref reference));
|
return Operand().With((long)Unsafe.AsPointer(ref reference), index != null, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand ConstF(float value)
|
public static Operand ConstF(float value)
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
internal const int PageTablePointerIndex = -1; // Must be a negative value.
|
internal const int PageTablePointerIndex = -1; // Must be a negative value.
|
||||||
internal const int JumpPointerIndex = -2; // Must be a negative value.
|
internal const int JumpPointerIndex = -2; // Must be a negative value.
|
||||||
internal const int DynamicPointerIndex = -3; // Must be a negative value.
|
internal const int DynamicPointerIndex = -3; // Must be a negative value.
|
||||||
|
internal const int CountTableIndex = -4; // Must be a negative value.
|
||||||
|
|
||||||
private const byte FillingByte = 0x00;
|
private const byte FillingByte = 0x00;
|
||||||
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
|
||||||
|
@ -539,7 +540,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void LoadTranslations(ConcurrentDictionary<ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable)
|
internal static void LoadTranslations(ConcurrentDictionary<ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable, EntryTable<byte> countTable)
|
||||||
{
|
{
|
||||||
if (AreCarriersEmpty())
|
if (AreCarriersEmpty())
|
||||||
{
|
{
|
||||||
|
@ -568,16 +569,23 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
byte[] code = ReadCode(index, infoEntry.CodeLength);
|
byte[] code = ReadCode(index, infoEntry.CodeLength);
|
||||||
|
|
||||||
|
Counter callCounter = null;
|
||||||
|
|
||||||
if (infoEntry.RelocEntriesCount != 0)
|
if (infoEntry.RelocEntriesCount != 0)
|
||||||
{
|
{
|
||||||
RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
|
RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
|
||||||
|
|
||||||
PatchCode(code.AsSpan(), relocEntries, memory.PageTablePointer, jumpTable);
|
if (!PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter))
|
||||||
|
{
|
||||||
|
SkipUnwindInfo(unwindInfosReader);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
|
UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
|
||||||
|
|
||||||
TranslatedFunction func = FastTranslate(code, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq);
|
TranslatedFunction func = FastTranslate(code, callCounter, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq);
|
||||||
|
|
||||||
bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func);
|
bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func);
|
||||||
|
|
||||||
|
@ -671,8 +679,10 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return relocEntries;
|
return relocEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PatchCode(Span<byte> code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable)
|
private static bool PatchCode(Span<byte> code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable, EntryTable<byte> countTable, out Counter callCounter)
|
||||||
{
|
{
|
||||||
|
callCounter = null;
|
||||||
|
|
||||||
foreach (RelocEntry relocEntry in relocEntries)
|
foreach (RelocEntry relocEntry in relocEntries)
|
||||||
{
|
{
|
||||||
ulong imm;
|
ulong imm;
|
||||||
|
@ -689,6 +699,16 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
imm = (ulong)jumpTable.DynamicPointer.ToInt64();
|
imm = (ulong)jumpTable.DynamicPointer.ToInt64();
|
||||||
}
|
}
|
||||||
|
else if (relocEntry.Index == CountTableIndex)
|
||||||
|
{
|
||||||
|
// If we could not allocate an entry on the count table we dip.
|
||||||
|
if (!Counter.TryCreate(countTable, out Counter counter))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { imm = (ulong)Unsafe.AsPointer(ref counter.Value); }
|
||||||
|
}
|
||||||
else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr))
|
else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr))
|
||||||
{
|
{
|
||||||
imm = (ulong)funcPtr.ToInt64();
|
imm = (ulong)funcPtr.ToInt64();
|
||||||
|
@ -700,6 +720,8 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm);
|
BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
|
private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
|
||||||
|
@ -723,7 +745,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
return new UnwindInfo(pushEntries, prologueSize);
|
return new UnwindInfo(pushEntries, prologueSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TranslatedFunction FastTranslate(byte[] code, ulong guestSize, UnwindInfo unwindInfo, bool highCq)
|
private static TranslatedFunction FastTranslate(byte[] code, Counter callCounter, ulong guestSize, UnwindInfo unwindInfo, bool highCq)
|
||||||
{
|
{
|
||||||
CompiledFunction cFunc = new CompiledFunction(code, unwindInfo);
|
CompiledFunction cFunc = new CompiledFunction(code, unwindInfo);
|
||||||
|
|
||||||
|
@ -731,7 +753,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
|
|
||||||
GuestFunction gFunc = Marshal.GetDelegateForFunctionPointer<GuestFunction>(codePtr);
|
GuestFunction gFunc = Marshal.GetDelegateForFunctionPointer<GuestFunction>(codePtr);
|
||||||
|
|
||||||
TranslatedFunction tFunc = new TranslatedFunction(gFunc, guestSize, highCq);
|
TranslatedFunction tFunc = new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
|
||||||
|
|
||||||
return tFunc;
|
return tFunc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,22 @@
|
||||||
|
using ARMeilleure.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Translation
|
namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
class TranslatedFunction
|
class TranslatedFunction
|
||||||
{
|
{
|
||||||
private const int MinCallsForRejit = 100;
|
|
||||||
|
|
||||||
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
|
private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
|
||||||
|
|
||||||
private int _callCount;
|
public Counter CallCounter { get; }
|
||||||
|
|
||||||
public ulong GuestSize { get; }
|
public ulong GuestSize { get; }
|
||||||
public bool HighCq { get; }
|
public bool HighCq { get; }
|
||||||
public IntPtr FuncPtr { get; }
|
public IntPtr FuncPtr { get; }
|
||||||
|
|
||||||
public TranslatedFunction(GuestFunction func, ulong guestSize, bool highCq)
|
public TranslatedFunction(GuestFunction func, Counter callCounter, ulong guestSize, bool highCq)
|
||||||
{
|
{
|
||||||
_func = func;
|
_func = func;
|
||||||
|
CallCounter = callCounter;
|
||||||
GuestSize = guestSize;
|
GuestSize = guestSize;
|
||||||
HighCq = highCq;
|
HighCq = highCq;
|
||||||
FuncPtr = Marshal.GetFunctionPointerForDelegate(func);
|
FuncPtr = Marshal.GetFunctionPointerForDelegate(func);
|
||||||
|
@ -28,15 +26,5 @@ namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
return _func(context.NativeContextPtr);
|
return _func(context.NativeContextPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShouldRejit()
|
|
||||||
{
|
|
||||||
return !HighCq && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetCallCount()
|
|
||||||
{
|
|
||||||
Interlocked.Exchange(ref _callCount, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -141,7 +141,7 @@ namespace ARMeilleure.Translation
|
||||||
if (Ptc.State == PtcState.Enabled)
|
if (Ptc.State == PtcState.Enabled)
|
||||||
{
|
{
|
||||||
Debug.Assert(_funcs.Count == 0);
|
Debug.Assert(_funcs.Count == 0);
|
||||||
Ptc.LoadTranslations(_funcs, _memory, _jumpTable);
|
Ptc.LoadTranslations(_funcs, _memory, _jumpTable, CountTable);
|
||||||
Ptc.MakeAndSaveTranslations(_funcs, _memory, _jumpTable, CountTable);
|
Ptc.MakeAndSaveTranslations(_funcs, _memory, _jumpTable, CountTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,9 +256,11 @@ namespace ARMeilleure.Translation
|
||||||
|
|
||||||
Logger.StartPass(PassName.Translation);
|
Logger.StartPass(PassName.Translation);
|
||||||
|
|
||||||
|
Counter counter = null;
|
||||||
|
|
||||||
if (!context.HighCq)
|
if (!context.HighCq)
|
||||||
{
|
{
|
||||||
EmitRejitCheck(context);
|
EmitRejitCheck(context, out counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitSynchronization(context);
|
EmitSynchronization(context);
|
||||||
|
@ -303,7 +305,7 @@ namespace ARMeilleure.Translation
|
||||||
Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, highCq, ptcInfo);
|
Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, highCq, ptcInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TranslatedFunction(func, funcSize, highCq);
|
return new TranslatedFunction(func, counter, funcSize, highCq);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void PreparePool(int groupId = 0)
|
internal static void PreparePool(int groupId = 0)
|
||||||
|
@ -413,9 +415,9 @@ namespace ARMeilleure.Translation
|
||||||
return context.GetControlFlowGraph();
|
return context.GetControlFlowGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void EmitRejitCheck(ArmEmitterContext context)
|
internal static void EmitRejitCheck(ArmEmitterContext context, out Counter counter)
|
||||||
{
|
{
|
||||||
if (!context.CountTable.TryAllocate(out int index))
|
if (!Counter.TryCreate(context.CountTable, out counter))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -424,8 +426,7 @@ namespace ARMeilleure.Translation
|
||||||
Operand lblAdd = Label();
|
Operand lblAdd = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
// TODO: PPTC.
|
Operand address = Const(ref counter.Value, Ptc.CountTableIndex);
|
||||||
Operand address = Const(ref context.CountTable.GetValue(index));
|
|
||||||
Operand count = context.Load8(address);
|
Operand count = context.Load8(address);
|
||||||
context.BranchIf(lblAdd, count, Const(100), Comparison.LessUI);
|
context.BranchIf(lblAdd, count, Const(100), Comparison.LessUI);
|
||||||
context.BranchIf(lblRejit, count, Const(100), Comparison.Equal);
|
context.BranchIf(lblRejit, count, Const(100), Comparison.Equal);
|
||||||
|
@ -511,9 +512,9 @@ namespace ARMeilleure.Translation
|
||||||
{
|
{
|
||||||
while (_backgroundStack.TryPop(out var request))
|
while (_backgroundStack.TryPop(out var request))
|
||||||
{
|
{
|
||||||
if (_funcs.TryGetValue(request.Address, out var func))
|
if (_funcs.TryGetValue(request.Address, out var func) && func.CallCounter != null)
|
||||||
{
|
{
|
||||||
func.ResetCallCount();
|
Volatile.Write(ref func.CallCounter.Value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
_backgroundSet.TryRemove(request.Address, out _);
|
_backgroundSet.TryRemove(request.Address, out _);
|
||||||
|
|
Loading…
Reference in a new issue