Add PPTC support

This commit is contained in:
FICTURE7 2021-04-09 20:55:24 +04:00
parent 1803b9fef9
commit 4478a32114
4 changed files with 44 additions and 33 deletions

View file

@ -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)

View file

@ -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;
} }

View file

@ -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);
}
} }
} }

View file

@ -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 _);