diff --git a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs index 6e58fa612..1b748f6a2 100644 --- a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs +++ b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs @@ -35,9 +35,9 @@ namespace ARMeilleure.IntermediateRepresentation return Operand().With(value); } - public static unsafe Operand Const(ref T reference) + public static unsafe Operand Const(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) diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index 1e8908bbc..d643086e3 100644 --- a/ARMeilleure/Translation/PTC/Ptc.cs +++ b/ARMeilleure/Translation/PTC/Ptc.cs @@ -39,6 +39,7 @@ namespace ARMeilleure.Translation.PTC internal const int PageTablePointerIndex = -1; // 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 CountTableIndex = -4; // Must be a negative value. private const byte FillingByte = 0x00; private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; @@ -539,7 +540,7 @@ namespace ARMeilleure.Translation.PTC } } - internal static void LoadTranslations(ConcurrentDictionary funcs, IMemoryManager memory, JumpTable jumpTable) + internal static void LoadTranslations(ConcurrentDictionary funcs, IMemoryManager memory, JumpTable jumpTable, EntryTable countTable) { if (AreCarriersEmpty()) { @@ -568,16 +569,23 @@ namespace ARMeilleure.Translation.PTC { byte[] code = ReadCode(index, infoEntry.CodeLength); + Counter callCounter = null; + if (infoEntry.RelocEntriesCount != 0) { 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); - 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); @@ -671,8 +679,10 @@ namespace ARMeilleure.Translation.PTC return relocEntries; } - private static void PatchCode(Span code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable) + private static bool PatchCode(Span code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable, EntryTable countTable, out Counter callCounter) { + callCounter = null; + foreach (RelocEntry relocEntry in relocEntries) { ulong imm; @@ -689,6 +699,16 @@ namespace ARMeilleure.Translation.PTC { 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)) { imm = (ulong)funcPtr.ToInt64(); @@ -700,6 +720,8 @@ namespace ARMeilleure.Translation.PTC BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm); } + + return true; } private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader) @@ -723,7 +745,7 @@ namespace ARMeilleure.Translation.PTC 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); @@ -731,7 +753,7 @@ namespace ARMeilleure.Translation.PTC GuestFunction gFunc = Marshal.GetDelegateForFunctionPointer(codePtr); - TranslatedFunction tFunc = new TranslatedFunction(gFunc, guestSize, highCq); + TranslatedFunction tFunc = new TranslatedFunction(gFunc, callCounter, guestSize, highCq); return tFunc; } diff --git a/ARMeilleure/Translation/TranslatedFunction.cs b/ARMeilleure/Translation/TranslatedFunction.cs index 8b0759289..c8adbe4cb 100644 --- a/ARMeilleure/Translation/TranslatedFunction.cs +++ b/ARMeilleure/Translation/TranslatedFunction.cs @@ -1,24 +1,22 @@ +using ARMeilleure.Common; using System; using System.Runtime.InteropServices; -using System.Threading; namespace ARMeilleure.Translation { class TranslatedFunction { - private const int MinCallsForRejit = 100; - 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 bool HighCq { 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; + CallCounter = callCounter; GuestSize = guestSize; HighCq = highCq; FuncPtr = Marshal.GetFunctionPointerForDelegate(func); @@ -28,15 +26,5 @@ namespace ARMeilleure.Translation { return _func(context.NativeContextPtr); } - - public bool ShouldRejit() - { - return !HighCq && Interlocked.Increment(ref _callCount) == MinCallsForRejit; - } - - public void ResetCallCount() - { - Interlocked.Exchange(ref _callCount, 0); - } } } \ No newline at end of file diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index 7eeeccc5d..50d363cd8 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -141,7 +141,7 @@ namespace ARMeilleure.Translation if (Ptc.State == PtcState.Enabled) { Debug.Assert(_funcs.Count == 0); - Ptc.LoadTranslations(_funcs, _memory, _jumpTable); + Ptc.LoadTranslations(_funcs, _memory, _jumpTable, CountTable); Ptc.MakeAndSaveTranslations(_funcs, _memory, _jumpTable, CountTable); } @@ -256,9 +256,11 @@ namespace ARMeilleure.Translation Logger.StartPass(PassName.Translation); + Counter counter = null; + if (!context.HighCq) { - EmitRejitCheck(context); + EmitRejitCheck(context, out counter); } EmitSynchronization(context); @@ -303,7 +305,7 @@ namespace ARMeilleure.Translation 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) @@ -413,9 +415,9 @@ namespace ARMeilleure.Translation 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; } @@ -424,8 +426,7 @@ namespace ARMeilleure.Translation Operand lblAdd = Label(); Operand lblEnd = Label(); - // TODO: PPTC. - Operand address = Const(ref context.CountTable.GetValue(index)); + Operand address = Const(ref counter.Value, Ptc.CountTableIndex); Operand count = context.Load8(address); context.BranchIf(lblAdd, count, Const(100), Comparison.LessUI); context.BranchIf(lblRejit, count, Const(100), Comparison.Equal); @@ -511,9 +512,9 @@ namespace ARMeilleure.Translation { 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 _);