aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2021-05-13 20:05:15 +0200
committerGitHub <noreply@github.com>2021-05-13 20:05:15 +0200
commit57ea3f93a31d67d9f72ef5066aa19fe18f8f9f76 (patch)
tree1e488ca9f1ebf601548c13eb6b46f299387c6ca7 /ARMeilleure
parenta8022ca3a1c9c2f312855c7676454507031be644 (diff)
PPTC meets ExeFS Patching. (#1865)
* PPTC meets ExeFS Patching. * InternalVersion = 1865 * Ready! * Optimized the PtcProfiler Load/Save methods.
Diffstat (limited to 'ARMeilleure')
-rw-r--r--ARMeilleure/Memory/IMemoryManager.cs2
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs130
-rw-r--r--ARMeilleure/Translation/PTC/PtcFormatter.cs14
-rw-r--r--ARMeilleure/Translation/PTC/PtcJumpTable.cs1
-rw-r--r--ARMeilleure/Translation/PTC/PtcProfiler.cs188
-rw-r--r--ARMeilleure/Translation/Translator.cs5
6 files changed, 183 insertions, 157 deletions
diff --git a/ARMeilleure/Memory/IMemoryManager.cs b/ARMeilleure/Memory/IMemoryManager.cs
index 33153903..cacfc4ac 100644
--- a/ARMeilleure/Memory/IMemoryManager.cs
+++ b/ARMeilleure/Memory/IMemoryManager.cs
@@ -12,6 +12,8 @@ namespace ARMeilleure.Memory
T ReadTracked<T>(ulong va) where T : unmanaged;
void Write<T>(ulong va, T value) where T : unmanaged;
+ ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false);
+
ref T GetRef<T>(ulong va) where T : unmanaged;
bool IsMapped(ulong va);
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index 55a0f4d0..4b5f3173 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -28,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 = 2190; //! To be incremented manually for each change to the ARMeilleure project.
+ private const uint InternalVersion = 1866; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
@@ -50,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;
@@ -153,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();
@@ -551,63 +545,78 @@ namespace ARMeilleure.Translation.PTC
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);
- Counter<uint> callCounter = null;
+ StubCode(index);
+ StubReloc(infoEntry.RelocEntriesCount);
+ StubUnwindInfo(unwindInfosReader);
- if (infoEntry.RelocEntriesCount != 0)
+ if (isEntryChanged)
{
- RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
+ PtcJumpTable.Clean(infoEntry.Address);
- PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter);
+ Logger.Info?.Print(LogClass.Ptc, $"Invalidated translated function (address: 0x{infoEntry.Address:X16})");
}
- UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
+ continue;
+ }
- TranslatedFunction func = FastTranslate(code, callCounter, 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);
@@ -623,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)
{
@@ -764,15 +759,9 @@ namespace ARMeilleure.Translation.PTC
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)
@@ -844,7 +833,7 @@ namespace ARMeilleure.Translation.PTC
Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
- TranslatedFunction func = Translator.Translate(memory, jumpTable, countTable, 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);
@@ -919,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());
@@ -946,7 +944,7 @@ namespace ARMeilleure.Translation.PTC
_codesList.Add(code.ToArray());
}
- private static bool GetEndianness()
+ internal static bool GetEndianness()
{
return BitConverter.IsLittleEndian;
}
@@ -1032,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;
diff --git a/ARMeilleure/Translation/PTC/PtcFormatter.cs b/ARMeilleure/Translation/PTC/PtcFormatter.cs
index 753c01c8..2f7a9c21 100644
--- a/ARMeilleure/Translation/PTC/PtcFormatter.cs
+++ b/ARMeilleure/Translation/PTC/PtcFormatter.cs
@@ -50,7 +50,12 @@ namespace ARMeilleure.Translation.PTC
T structure = default(T);
Span<T> spanT = MemoryMarshal.CreateSpan(ref structure, 1);
- stream.Read(MemoryMarshal.AsBytes(spanT));
+ int bytesCount = stream.Read(MemoryMarshal.AsBytes(spanT));
+
+ if (bytesCount != Unsafe.SizeOf<T>())
+ {
+ throw new EndOfStreamException();
+ }
return structure;
}
@@ -130,7 +135,12 @@ namespace ARMeilleure.Translation.PTC
T[] item = new T[itemLength];
- stream.Read(MemoryMarshal.AsBytes(item.AsSpan()));
+ int bytesCount = stream.Read(MemoryMarshal.AsBytes(item.AsSpan()));
+
+ if (bytesCount != itemLength)
+ {
+ throw new EndOfStreamException();
+ }
list.Add(item);
}
diff --git a/ARMeilleure/Translation/PTC/PtcJumpTable.cs b/ARMeilleure/Translation/PTC/PtcJumpTable.cs
index 40a30329..67719623 100644
--- a/ARMeilleure/Translation/PTC/PtcJumpTable.cs
+++ b/ARMeilleure/Translation/PTC/PtcJumpTable.cs
@@ -129,7 +129,6 @@ namespace ARMeilleure.Translation.PTC
}
}
- // For future use.
public void Clean(ulong guestAddress)
{
if (Owners.TryGetValue(guestAddress, out List<int> entries))
diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs
index d7b2b0f8..e31ff230 100644
--- a/ARMeilleure/Translation/PTC/PtcProfiler.cs
+++ b/ARMeilleure/Translation/PTC/PtcProfiler.cs
@@ -1,13 +1,15 @@
using ARMeilleure.State;
+using Ryujinx.Common;
using Ryujinx.Common.Logging;
using System;
+using System.Buffers.Binary;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using System.Security.Cryptography;
using System.Threading;
using static ARMeilleure.Translation.PTC.PtcFormatter;
@@ -16,9 +18,9 @@ namespace ARMeilleure.Translation.PTC
{
public static class PtcProfiler
{
- private const string HeaderMagic = "Phd";
+ private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
- private const uint InternalVersion = 1713; //! Not to be incremented manually for each change to the ARMeilleure project.
+ private const uint InternalVersion = 1866; //! Not to be incremented manually for each change to the ARMeilleure project.
private const int SaveInterval = 30; // Seconds.
@@ -26,13 +28,15 @@ namespace ARMeilleure.Translation.PTC
private static readonly System.Timers.Timer _timer;
+ private static readonly ulong _outerHeaderMagic;
+
private static readonly ManualResetEvent _waitEvent;
private static readonly object _lock;
private static bool _disposed;
- private static byte[] _lastHash;
+ private static Hash128 _lastHash;
internal static Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
@@ -46,6 +50,8 @@ namespace ARMeilleure.Translation.PTC
_timer = new System.Timers.Timer((double)SaveInterval * 1000d);
_timer.Elapsed += PreSave;
+ _outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
+
_waitEvent = new ManualResetEvent(true);
_lock = new object();
@@ -90,17 +96,15 @@ namespace ARMeilleure.Translation.PTC
return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
}
- internal static ConcurrentQueue<(ulong address, ExecutionMode mode, bool highCq)> GetProfiledFuncsToTranslate(ConcurrentDictionary<ulong, TranslatedFunction> funcs)
+ internal static ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(ConcurrentDictionary<ulong, TranslatedFunction> funcs)
{
- var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, ExecutionMode mode, bool highCq)>();
+ var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
foreach (var profiledFunc in ProfiledFuncs)
{
- ulong address = profiledFunc.Key;
-
- if (!funcs.ContainsKey(address))
+ if (!funcs.ContainsKey(profiledFunc.Key))
{
- profiledFuncsToTranslate.Enqueue((address, profiledFunc.Value.Mode, profiledFunc.Value.HighCq));
+ profiledFuncsToTranslate.Enqueue((profiledFunc.Key, profiledFunc.Value));
}
}
@@ -115,7 +119,7 @@ namespace ARMeilleure.Translation.PTC
internal static void PreLoad()
{
- _lastHash = Array.Empty<byte>();
+ _lastHash = default;
string fileNameActual = string.Concat(Ptc.CachePathActual, ".info");
string fileNameBackup = string.Concat(Ptc.CachePathBackup, ".info");
@@ -141,96 +145,82 @@ namespace ARMeilleure.Translation.PTC
private static bool Load(string fileName, bool isBackup)
{
- using (FileStream compressedStream = new FileStream(fileName, FileMode.Open))
- using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress, true))
- using (MemoryStream stream = new MemoryStream())
- using (MD5 md5 = MD5.Create())
+ using (FileStream compressedStream = new(fileName, FileMode.Open))
+ using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
{
- try
- {
- deflateStream.CopyTo(stream);
- }
- catch
+ OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
+
+ if (!outerHeader.IsHeaderValid())
{
InvalidateCompressedStream(compressedStream);
return false;
}
- int hashSize = md5.HashSize / 8;
-
- stream.Seek(0L, SeekOrigin.Begin);
-
- byte[] currentHash = new byte[hashSize];
- stream.Read(currentHash, 0, hashSize);
-
- byte[] expectedHash = md5.ComputeHash(stream);
-
- if (!CompareHash(currentHash, expectedHash))
+ if (outerHeader.Magic != _outerHeaderMagic)
{
InvalidateCompressedStream(compressedStream);
return false;
}
- stream.Seek((long)hashSize, SeekOrigin.Begin);
-
- Header header = ReadHeader(stream);
-
- if (header.Magic != HeaderMagic)
+ if (outerHeader.InfoFileVersion != InternalVersion)
{
InvalidateCompressedStream(compressedStream);
return false;
}
- if (header.InfoFileVersion != InternalVersion)
+ if (outerHeader.Endianness != Ptc.GetEndianness())
{
InvalidateCompressedStream(compressedStream);
return false;
}
- try
+ using (MemoryStream stream = new MemoryStream())
{
- ProfiledFuncs = Deserialize(stream);
- }
- catch
- {
- ProfiledFuncs = new Dictionary<ulong, FuncProfile>();
+ Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
- InvalidateCompressedStream(compressedStream);
+ try
+ {
+ deflateStream.CopyTo(stream);
+ }
+ catch
+ {
+ InvalidateCompressedStream(compressedStream);
- return false;
- }
+ return false;
+ }
- _lastHash = expectedHash;
- }
+ Debug.Assert(stream.Position == stream.Length);
- long fileSize = new FileInfo(fileName).Length;
+ stream.Seek(0L, SeekOrigin.Begin);
- Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
+ Hash128 expectedHash = DeserializeStructure<Hash128>(stream);
- return true;
- }
+ Hash128 actualHash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
- private static bool CompareHash(ReadOnlySpan<byte> currentHash, ReadOnlySpan<byte> expectedHash)
- {
- return currentHash.SequenceEqual(expectedHash);
- }
+ if (actualHash != expectedHash)
+ {
+ InvalidateCompressedStream(compressedStream);
- private static Header ReadHeader(Stream stream)
- {
- using (BinaryReader headerReader = new BinaryReader(stream, EncodingCache.UTF8NoBOM, true))
- {
- Header header = new Header();
+ return false;
+ }
- header.Magic = headerReader.ReadString();
+ ProfiledFuncs = Deserialize(stream);
- header.InfoFileVersion = headerReader.ReadUInt32();
+ Debug.Assert(stream.Position == stream.Length);
- return header;
+ _lastHash = actualHash;
+ }
}
+
+ long fileSize = new FileInfo(fileName).Length;
+
+ Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
+
+ return true;
}
private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream)
@@ -238,6 +228,11 @@ namespace ARMeilleure.Translation.PTC
return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
}
+ private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
+ {
+ return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position);
+ }
+
private static void InvalidateCompressedStream(FileStream compressedStream)
{
compressedStream.SetLength(0L);
@@ -266,14 +261,20 @@ namespace ARMeilleure.Translation.PTC
{
int profiledFuncsCount;
+ OuterHeader outerHeader = new OuterHeader();
+
+ outerHeader.Magic = _outerHeaderMagic;
+
+ outerHeader.InfoFileVersion = InternalVersion;
+ outerHeader.Endianness = Ptc.GetEndianness();
+
+ outerHeader.SetHeaderHash();
+
using (MemoryStream stream = new MemoryStream())
- using (MD5 md5 = MD5.Create())
{
- int hashSize = md5.HashSize / 8;
+ Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
- stream.Seek((long)hashSize, SeekOrigin.Begin);
-
- WriteHeader(stream);
+ stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
lock (_lock)
{
@@ -282,22 +283,26 @@ namespace ARMeilleure.Translation.PTC
profiledFuncsCount = ProfiledFuncs.Count;
}
- stream.Seek((long)hashSize, SeekOrigin.Begin);
- byte[] hash = md5.ComputeHash(stream);
+ Debug.Assert(stream.Position == stream.Length);
+
+ stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
+ Hash128 hash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
stream.Seek(0L, SeekOrigin.Begin);
- stream.Write(hash, 0, hashSize);
+ SerializeStructure(stream, hash);
- if (CompareHash(hash, _lastHash))
+ if (hash == _lastHash)
{
return;
}
- using (FileStream compressedStream = new FileStream(fileName, FileMode.OpenOrCreate))
- using (DeflateStream deflateStream = new DeflateStream(compressedStream, SaveCompressionLevel, true))
+ using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
+ using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true))
{
try
{
+ SerializeStructure(compressedStream, outerHeader);
+
stream.WriteTo(deflateStream);
_lastHash = hash;
@@ -306,7 +311,7 @@ namespace ARMeilleure.Translation.PTC
{
compressedStream.Position = 0L;
- _lastHash = Array.Empty<byte>();
+ _lastHash = default;
}
if (compressedStream.Position < compressedStream.Length)
@@ -324,26 +329,35 @@ namespace ARMeilleure.Translation.PTC
}
}
- private static void WriteHeader(Stream stream)
- {
- using (BinaryWriter headerWriter = new BinaryWriter(stream, EncodingCache.UTF8NoBOM, true))
- {
- headerWriter.Write((string)HeaderMagic); // Header.Magic
-
- headerWriter.Write((uint)InternalVersion); // Header.InfoFileVersion
- }
- }
-
private static void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
{
SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
}
- private struct Header
+ [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 29*/)]
+ private struct OuterHeader
{
- public string Magic;
+ public ulong Magic;
public uint InfoFileVersion;
+
+ public bool Endianness;
+
+ public Hash128 HeaderHash;
+
+ public void SetHeaderHash()
+ {
+ Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
+
+ HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>()));
+ }
+
+ public bool IsHeaderValid()
+ {
+ Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
+
+ return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>())) == HeaderHash;
+ }
}
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
index 9f88f17a..81af0681 100644
--- a/ARMeilleure/Translation/Translator.cs
+++ b/ARMeilleure/Translation/Translator.cs
@@ -7,6 +7,7 @@ using ARMeilleure.Memory;
using ARMeilleure.State;
using ARMeilleure.Translation.Cache;
using ARMeilleure.Translation.PTC;
+using Ryujinx.Common;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -282,7 +283,9 @@ namespace ARMeilleure.Translation
ResetPool(highCq ? 1 : 0);
- Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, highCq, ptcInfo);
+ Hash128 hash = Ptc.ComputeHash(memory, address, funcSize);
+
+ Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, hash, highCq, ptcInfo);
}
return new TranslatedFunction(func, counter, funcSize, highCq);