aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Translation/PTC/Ptc.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/Translation/PTC/Ptc.cs')
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs171
1 files changed, 100 insertions, 71 deletions
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index 32e0e7e8..1bb8659c 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -1,6 +1,7 @@
using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.CodeGen.X86;
+using ARMeilleure.Common;
using ARMeilleure.Memory;
using ARMeilleure.Translation.Cache;
using Ryujinx.Common;
@@ -27,7 +28,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
- private const uint InternalVersion = 2169; //! To be incremented manually for each change to the ARMeilleure project.
+ private const uint InternalVersion = 2285; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
@@ -38,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;
@@ -48,8 +50,6 @@ namespace ARMeilleure.Translation.PTC
private static MemoryStream _relocsStream;
private static MemoryStream _unwindInfosStream;
- private static BinaryWriter _infosWriter;
-
private static readonly ulong _outerHeaderMagic;
private static readonly ulong _innerHeaderMagic;
@@ -151,14 +151,10 @@ namespace ARMeilleure.Translation.PTC
_codesList = new List<byte[]>();
_relocsStream = new MemoryStream();
_unwindInfosStream = new MemoryStream();
-
- _infosWriter = new BinaryWriter(_infosStream, EncodingCache.UTF8NoBOM, true);
}
private static void DisposeCarriers()
{
- _infosWriter.Dispose();
-
_infosStream.Dispose();
_codesList.Clear();
_relocsStream.Dispose();
@@ -538,68 +534,89 @@ 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<uint> countTable)
{
if (AreCarriersEmpty())
{
return;
}
+ long infosStreamLength = _infosStream.Length;
+ long relocsStreamLength = _relocsStream.Length;
+ long unwindInfosStreamLength = _unwindInfosStream.Length;
+
_infosStream.Seek(0L, SeekOrigin.Begin);
_relocsStream.Seek(0L, SeekOrigin.Begin);
_unwindInfosStream.Seek(0L, SeekOrigin.Begin);
- using (BinaryReader infosReader = new(_infosStream, EncodingCache.UTF8NoBOM, true))
using (BinaryReader relocsReader = new(_relocsStream, EncodingCache.UTF8NoBOM, true))
using (BinaryReader unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true))
{
for (int index = 0; index < GetEntriesCount(); index++)
{
- InfoEntry infoEntry = ReadInfo(infosReader);
+ InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
if (infoEntry.Stubbed)
{
SkipCode(index, infoEntry.CodeLength);
SkipReloc(infoEntry.RelocEntriesCount);
SkipUnwindInfo(unwindInfosReader);
+
+ continue;
}
- else if (infoEntry.HighCq || !PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) || !value.HighCq)
+
+ bool isEntryChanged = infoEntry.Hash != ComputeHash(memory, infoEntry.Address, infoEntry.GuestSize);
+
+ if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
{
- byte[] code = ReadCode(index, infoEntry.CodeLength);
+ infoEntry.Stubbed = true;
+ infoEntry.CodeLength = 0;
+ UpdateInfo(infoEntry);
- if (infoEntry.RelocEntriesCount != 0)
+ StubCode(index);
+ StubReloc(infoEntry.RelocEntriesCount);
+ StubUnwindInfo(unwindInfosReader);
+
+ if (isEntryChanged)
{
- RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
+ PtcJumpTable.Clean(infoEntry.Address);
- PatchCode(code.AsSpan(), relocEntries, memory.PageTablePointer, jumpTable);
+ Logger.Info?.Print(LogClass.Ptc, $"Invalidated translated function (address: 0x{infoEntry.Address:X16})");
}
- UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
+ continue;
+ }
- TranslatedFunction func = FastTranslate(code, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq);
+ byte[] code = ReadCode(index, infoEntry.CodeLength);
- bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func);
+ Counter<uint> callCounter = null;
- Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique.");
- }
- else
+ if (infoEntry.RelocEntriesCount != 0)
{
- infoEntry.Stubbed = true;
- infoEntry.CodeLength = 0;
- UpdateInfo(infoEntry);
+ RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
- StubCode(index);
- StubReloc(infoEntry.RelocEntriesCount);
- StubUnwindInfo(unwindInfosReader);
+ PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter);
}
+
+ UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
+
+ TranslatedFunction func = FastTranslate(code, callCounter, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq);
+
+ bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func);
+
+ Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique.");
}
}
- if (_infosStream.Position < _infosStream.Length ||
- _relocsStream.Position < _relocsStream.Length ||
- _unwindInfosStream.Position < _unwindInfosStream.Length)
+ if (_infosStream.Length != infosStreamLength || _infosStream.Position != infosStreamLength ||
+ _relocsStream.Length != relocsStreamLength || _relocsStream.Position != relocsStreamLength ||
+ _unwindInfosStream.Length != unwindInfosStreamLength || _unwindInfosStream.Position != unwindInfosStreamLength)
{
- throw new Exception("Could not reach the end of one or more memory streams.");
+ throw new Exception("The length of a memory stream has changed, or its position has not reached or has exceeded its end.");
}
jumpTable.Initialize(PtcJumpTable, funcs);
@@ -615,20 +632,6 @@ namespace ARMeilleure.Translation.PTC
return _codesList.Count;
}
- private static InfoEntry ReadInfo(BinaryReader infosReader)
- {
- InfoEntry infoEntry = new InfoEntry();
-
- infoEntry.Address = infosReader.ReadUInt64();
- infoEntry.GuestSize = infosReader.ReadUInt64();
- infoEntry.HighCq = infosReader.ReadBoolean();
- infoEntry.Stubbed = infosReader.ReadBoolean();
- infoEntry.CodeLength = infosReader.ReadInt32();
- infoEntry.RelocEntriesCount = infosReader.ReadInt32();
-
- return infoEntry;
- }
-
[Conditional("DEBUG")]
private static void SkipCode(int index, int codeLength)
{
@@ -670,8 +673,16 @@ namespace ARMeilleure.Translation.PTC
return relocEntries;
}
- private static void PatchCode(Span<byte> code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable)
+ private static void PatchCode(
+ Span<byte> code,
+ RelocEntry[] relocEntries,
+ IntPtr pageTablePointer,
+ JumpTable jumpTable,
+ EntryTable<uint> countTable,
+ out Counter<uint> callCounter)
{
+ callCounter = null;
+
foreach (RelocEntry relocEntry in relocEntries)
{
ulong imm;
@@ -688,6 +699,12 @@ namespace ARMeilleure.Translation.PTC
{
imm = (ulong)jumpTable.DynamicPointer.ToInt64();
}
+ else if (relocEntry.Index == CountTableIndex)
+ {
+ callCounter = new Counter<uint>(countTable);
+
+ unsafe { imm = (ulong)Unsafe.AsPointer(ref callCounter.Value); }
+ }
else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr))
{
imm = (ulong)funcPtr.ToInt64();
@@ -722,7 +739,12 @@ 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<uint> callCounter,
+ ulong guestSize,
+ UnwindInfo unwindInfo,
+ bool highCq)
{
CompiledFunction cFunc = new CompiledFunction(code, unwindInfo);
@@ -730,22 +752,16 @@ namespace ARMeilleure.Translation.PTC
GuestFunction gFunc = Marshal.GetDelegateForFunctionPointer<GuestFunction>(codePtr);
- TranslatedFunction tFunc = new TranslatedFunction(gFunc, guestSize, highCq);
+ TranslatedFunction tFunc = new TranslatedFunction(gFunc, callCounter, guestSize, highCq);
return tFunc;
}
private static void UpdateInfo(InfoEntry infoEntry)
{
- _infosStream.Seek(-InfoEntry.Stride, SeekOrigin.Current);
-
- // WriteInfo.
- _infosWriter.Write((ulong)infoEntry.Address);
- _infosWriter.Write((ulong)infoEntry.GuestSize);
- _infosWriter.Write((bool)infoEntry.HighCq);
- _infosWriter.Write((bool)infoEntry.Stubbed);
- _infosWriter.Write((int)infoEntry.CodeLength);
- _infosWriter.Write((int)infoEntry.RelocEntriesCount);
+ _infosStream.Seek(-Unsafe.SizeOf<InfoEntry>(), SeekOrigin.Current);
+
+ SerializeStructure(_infosStream, infoEntry);
}
private static void StubCode(int index)
@@ -771,7 +787,11 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void MakeAndSaveTranslations(ConcurrentDictionary<ulong, TranslatedFunction> funcs, IMemoryManager memory, JumpTable jumpTable)
+ internal static void MakeAndSaveTranslations(
+ ConcurrentDictionary<ulong, TranslatedFunction> funcs,
+ IMemoryManager memory,
+ JumpTable jumpTable,
+ EntryTable<uint> countTable)
{
var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs);
@@ -813,7 +833,7 @@ namespace ARMeilleure.Translation.PTC
Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
- TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.mode, item.highCq);
+ TranslatedFunction func = Translator.Translate(memory, jumpTable, countTable, address, item.funcProfile.Mode, item.funcProfile.HighCq);
bool isAddressUnique = funcs.TryAdd(address, func);
@@ -888,17 +908,26 @@ namespace ARMeilleure.Translation.PTC
while (!endEvent.WaitOne(refreshRate));
}
- internal static void WriteInfoCodeRelocUnwindInfo(ulong address, ulong guestSize, bool highCq, PtcInfo ptcInfo)
+ internal static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
+ {
+ return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize))));
+ }
+
+ internal static void WriteInfoCodeRelocUnwindInfo(ulong address, ulong guestSize, Hash128 hash, bool highCq, PtcInfo ptcInfo)
{
lock (_lock)
{
- // WriteInfo.
- _infosWriter.Write((ulong)address); // InfoEntry.Address
- _infosWriter.Write((ulong)guestSize); // InfoEntry.GuestSize
- _infosWriter.Write((bool)highCq); // InfoEntry.HighCq
- _infosWriter.Write((bool)false); // InfoEntry.Stubbed
- _infosWriter.Write((int)ptcInfo.Code.Length); // InfoEntry.CodeLength
- _infosWriter.Write((int)ptcInfo.RelocEntriesCount); // InfoEntry.RelocEntriesCount
+ InfoEntry infoEntry = new InfoEntry();
+
+ infoEntry.Address = address;
+ infoEntry.GuestSize = guestSize;
+ infoEntry.Hash = hash;
+ infoEntry.HighCq = highCq;
+ infoEntry.Stubbed = false;
+ infoEntry.CodeLength = ptcInfo.Code.Length;
+ infoEntry.RelocEntriesCount = ptcInfo.RelocEntriesCount;
+
+ SerializeStructure(_infosStream, infoEntry);
WriteCode(ptcInfo.Code.AsSpan());
@@ -915,7 +944,7 @@ namespace ARMeilleure.Translation.PTC
_codesList.Add(code.ToArray());
}
- private static bool GetEndianness()
+ internal static bool GetEndianness()
{
return BitConverter.IsLittleEndian;
}
@@ -1001,12 +1030,12 @@ namespace ARMeilleure.Translation.PTC
}
}
+ [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 42*/)]
private struct InfoEntry
{
- public const int Stride = 26; // Bytes.
-
public ulong Address;
public ulong GuestSize;
+ public Hash128 Hash;
public bool HighCq;
public bool Stubbed;
public int CodeLength;
@@ -1058,4 +1087,4 @@ namespace ARMeilleure.Translation.PTC
}
}
}
-} \ No newline at end of file
+}