aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Translation/PTC
diff options
context:
space:
mode:
authorFICTURE7 <FICTURE7@gmail.com>2021-05-30 01:06:28 +0400
committerGitHub <noreply@github.com>2021-05-29 18:06:28 -0300
commit9d7627af6484e090ebbc3209bc7301f0bdf47d24 (patch)
tree057637c1b6d9de6fd80ea271cb93667cfb43abf3 /ARMeilleure/Translation/PTC
parentf3b0b4831c323a20393aa0388f947317354372b7 (diff)
Add multi-level function table (#2228)
* Add AddressTable<T> * Use AddressTable<T> for dispatch * Remove JumpTable & co. * Add fallback for out of range addresses * Add PPTC support * Add documentation to `AddressTable<T>` * Make AddressTable<T> configurable * Fix table walk * Fix IsMapped check * Remove CountTableCapacity * Add PPTC support for fast path * Rename IsMapped to IsValid * Remove stale comment * Change format of address in exception message * Add TranslatorStubs * Split DispatchStub Avoids recompilation of stubs during tests. * Add hint for 64bit or 32bit * Add documentation to `Symbol` * Add documentation to `TranslatorStubs` Make `TranslatorStubs` disposable as well. * Add documentation to `SymbolType` * Add `AddressTableEventSource` to monitor function table size Add an EventSource which measures the amount of unmanaged bytes allocated by AddressTable<T> instances. dotnet-counters monitor -n Ryujinx --counters ARMeilleure * Add `AllowLcqInFunctionTable` optimization toggle This is to reduce the impact this change has on the test duration. Before everytime a test was ran, the FunctionTable would be initialized and populated so that the newly compiled test would get registered to it. * Implement unmanaged dispatcher Uses the DispatchStub to dispatch into the next translation, which allows execution to stay in unmanaged for longer and skips a ConcurrentDictionary look up when the target translation has been registered to the FunctionTable. * Remove redundant null check * Tune levels of FunctionTable Uses 5 levels instead of 4 and change unit of AddressTableEventSource from KB to MB. * Use 64-bit function table Improves codegen for direct branches: mov qword [rax+0x408],0x10603560 - mov rcx,sub_10603560_OFFSET - mov ecx,[rcx] - mov ecx,ecx - mov rdx,JIT_CACHE_BASE - add rdx,rcx + mov rcx,sub_10603560 + mov rdx,[rcx] mov rcx,rax Improves codegen for dispatch stub: and rax,byte +0x1f - mov eax,[rcx+rax*4] - mov eax,eax - mov rcx,JIT_CACHE_BASE - lea rax,[rcx+rax] + mov rax,[rcx+rax*8] mov rcx,rbx * Remove `JitCacheSymbol` & `JitCache.Offset` * Turn `Translator.Translate` into an instance method We do not have to add more parameter to this method and related ones as new structures are added & needed for translation. * Add symbol only when PTC is enabled Address LDj3SNuD's feedback * Change `NativeContext.Running` to a 32-bit integer * Fix PageTable symbol for host mapped
Diffstat (limited to 'ARMeilleure/Translation/PTC')
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs140
-rw-r--r--ARMeilleure/Translation/PTC/PtcInfo.cs3
-rw-r--r--ARMeilleure/Translation/PTC/PtcJumpTable.cs350
-rw-r--r--ARMeilleure/Translation/PTC/RelocEntry.cs10
-rw-r--r--ARMeilleure/Translation/PTC/Symbol.cs100
-rw-r--r--ARMeilleure/Translation/PTC/SymbolType.cs28
6 files changed, 183 insertions, 448 deletions
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index ed4a003d..9f07ca01 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 = 2289; //! To be incremented manually for each change to the ARMeilleure project.
+ private const uint InternalVersion = 2228; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
@@ -36,10 +36,9 @@ namespace ARMeilleure.Translation.PTC
private const string TitleIdTextDefault = "0000000000000000";
private const string DisplayVersionDefault = "0";
- 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.
+ internal static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
+ internal static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
+ internal static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
private const byte FillingByte = 0x00;
private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
@@ -59,8 +58,6 @@ namespace ARMeilleure.Translation.PTC
private static bool _disposed;
- internal static PtcJumpTable PtcJumpTable { get; private set; }
-
internal static string TitleIdText { get; private set; }
internal static string DisplayVersion { get; private set; }
@@ -89,8 +86,6 @@ namespace ARMeilleure.Translation.PTC
_disposed = false;
- PtcJumpTable = new PtcJumpTable();
-
TitleIdText = TitleIdTextDefault;
DisplayVersion = DisplayVersionDefault;
@@ -348,20 +343,8 @@ namespace ARMeilleure.Translation.PTC
return false;
}
- ReadOnlySpan<byte> ptcJumpTableBytes = new(stream.PositionPointer, innerHeader.PtcJumpTableLength);
- stream.Seek(innerHeader.PtcJumpTableLength, SeekOrigin.Current);
-
Debug.Assert(stream.Position == stream.Length);
- Hash128 ptcJumpTableHash = XXHash128.ComputeHash(ptcJumpTableBytes);
-
- if (innerHeader.PtcJumpTableHash != ptcJumpTableHash)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
_infosStream.Write(infosBytes);
@@ -375,8 +358,6 @@ namespace ARMeilleure.Translation.PTC
_unwindInfosStream.Write(unwindInfosBytes);
stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current);
- PtcJumpTable = PtcJumpTable.Deserialize(stream);
-
Debug.Assert(stream.Position == stream.Length);
}
}
@@ -422,7 +403,6 @@ namespace ARMeilleure.Translation.PTC
finally
{
ResetCarriersIfNeeded();
- PtcJumpTable.ClearIfNeeded();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
}
@@ -442,7 +422,6 @@ namespace ARMeilleure.Translation.PTC
innerHeader.CodesLength = _codesList.Length();
innerHeader.RelocsLength = (int)_relocsStream.Length;
innerHeader.UnwindInfosLength = (int)_unwindInfosStream.Length;
- innerHeader.PtcJumpTableLength = PtcJumpTable.GetSerializeSize(PtcJumpTable);
OuterHeader outerHeader = new OuterHeader();
@@ -459,8 +438,7 @@ namespace ARMeilleure.Translation.PTC
innerHeader.InfosLength +
innerHeader.CodesLength +
innerHeader.RelocsLength +
- innerHeader.UnwindInfosLength +
- innerHeader.PtcJumpTableLength;
+ innerHeader.UnwindInfosLength;
outerHeader.SetHeaderHash();
@@ -486,16 +464,12 @@ namespace ARMeilleure.Translation.PTC
ReadOnlySpan<byte> unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength);
_unwindInfosStream.WriteTo(stream);
- ReadOnlySpan<byte> ptcJumpTableBytes = new(stream.PositionPointer, innerHeader.PtcJumpTableLength);
- PtcJumpTable.Serialize(stream, PtcJumpTable);
-
Debug.Assert(stream.Position == stream.Length);
innerHeader.InfosHash = XXHash128.ComputeHash(infosBytes);
innerHeader.CodesHash = XXHash128.ComputeHash(codesBytes);
innerHeader.RelocsHash = XXHash128.ComputeHash(relocsBytes);
innerHeader.UnwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes);
- innerHeader.PtcJumpTableHash = XXHash128.ComputeHash(ptcJumpTableBytes);
innerHeader.SetHeaderHash();
@@ -505,7 +479,6 @@ namespace ARMeilleure.Translation.PTC
translatedFuncsCount = GetEntriesCount();
ResetCarriersIfNeeded();
- PtcJumpTable.ClearIfNeeded();
using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true))
@@ -545,11 +518,7 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void LoadTranslations(
- ConcurrentDictionary<ulong, TranslatedFunction> funcs,
- IMemoryManager memory,
- JumpTable jumpTable,
- EntryTable<uint> countTable)
+ internal static void LoadTranslations(Translator translator)
{
if (AreCarriersEmpty())
{
@@ -580,7 +549,7 @@ namespace ARMeilleure.Translation.PTC
continue;
}
- bool isEntryChanged = infoEntry.Hash != ComputeHash(memory, infoEntry.Address, infoEntry.GuestSize);
+ bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
if (isEntryChanged || (!infoEntry.HighCq && PtcProfiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
{
@@ -594,8 +563,6 @@ namespace ARMeilleure.Translation.PTC
if (isEntryChanged)
{
- PtcJumpTable.Clean(infoEntry.Address);
-
Logger.Info?.Print(LogClass.Ptc, $"Invalidated translated function (address: 0x{infoEntry.Address:X16})");
}
@@ -610,14 +577,16 @@ namespace ARMeilleure.Translation.PTC
{
RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
- PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter);
+ PatchCode(translator, code, relocEntries, out callCounter);
}
UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
TranslatedFunction func = FastTranslate(code, callCounter, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq);
- bool isAddressUnique = funcs.TryAdd(infoEntry.Address, func);
+ translator.RegisterFunction(infoEntry.Address, func);
+
+ bool isAddressUnique = translator.Functions.TryAdd(infoEntry.Address, func);
Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique.");
}
@@ -630,12 +599,7 @@ namespace ARMeilleure.Translation.PTC
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);
-
- PtcJumpTable.WriteJumpTable(jumpTable, funcs);
- PtcJumpTable.WriteDynamicTable(jumpTable);
-
- Logger.Info?.Print(LogClass.Ptc, $"{funcs.Count} translated functions loaded");
+ Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded");
}
private static int GetEntriesCount()
@@ -676,56 +640,63 @@ namespace ARMeilleure.Translation.PTC
for (int i = 0; i < relocEntriesCount; i++)
{
int position = relocsReader.ReadInt32();
- int index = relocsReader.ReadInt32();
+ SymbolType type = (SymbolType)relocsReader.ReadByte();
+ ulong value = relocsReader.ReadUInt64();
- relocEntries[i] = new RelocEntry(position, index);
+ relocEntries[i] = new RelocEntry(position, new Symbol(type, value));
}
return relocEntries;
}
- private static void PatchCode(
- Span<byte> code,
- RelocEntry[] relocEntries,
- IntPtr pageTablePointer,
- JumpTable jumpTable,
- EntryTable<uint> countTable,
- out Counter<uint> callCounter)
+ private static void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
{
callCounter = null;
foreach (RelocEntry relocEntry in relocEntries)
{
- ulong imm;
+ IntPtr? imm = null;
+ Symbol symbol = relocEntry.Symbol;
- if (relocEntry.Index == PageTablePointerIndex)
+ if (symbol.Type == SymbolType.FunctionTable)
{
- imm = (ulong)pageTablePointer.ToInt64();
+ ulong guestAddress = symbol.Value;
+
+ if (translator.FunctionTable.IsValid(guestAddress))
+ {
+ unsafe { imm = (IntPtr)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress)); }
+ }
}
- else if (relocEntry.Index == JumpPointerIndex)
+ else if (symbol.Type == SymbolType.DelegateTable)
{
- imm = (ulong)jumpTable.JumpPointer.ToInt64();
+ int index = (int)symbol.Value;
+
+ if (Delegates.TryGetDelegateFuncPtrByIndex(index, out IntPtr funcPtr))
+ {
+ imm = funcPtr;
+ }
}
- else if (relocEntry.Index == DynamicPointerIndex)
+ else if (symbol == PageTableSymbol)
{
- imm = (ulong)jumpTable.DynamicPointer.ToInt64();
+ imm = translator.Memory.PageTablePointer;
}
- else if (relocEntry.Index == CountTableIndex)
+ else if (symbol == CountTableSymbol)
{
- callCounter = new Counter<uint>(countTable);
+ callCounter = new Counter<uint>(translator.CountTable);
- unsafe { imm = (ulong)Unsafe.AsPointer(ref callCounter.Value); }
+ unsafe { imm = (IntPtr)Unsafe.AsPointer(ref callCounter.Value); }
}
- else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr))
+ else if (symbol == DispatchStubSymbol)
{
- imm = (ulong)funcPtr.ToInt64();
+ imm = translator.Stubs.DispatchStub;
}
- else
+
+ if (imm == null)
{
throw new Exception($"Unexpected reloc entry {relocEntry}.");
}
- BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm);
+ BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), (ulong)imm.Value);
}
}
@@ -798,13 +769,9 @@ namespace ARMeilleure.Translation.PTC
}
}
- internal static void MakeAndSaveTranslations(
- ConcurrentDictionary<ulong, TranslatedFunction> funcs,
- IMemoryManager memory,
- JumpTable jumpTable,
- EntryTable<uint> countTable)
+ internal static void MakeAndSaveTranslations(Translator translator)
{
- var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(funcs);
+ var profiledFuncsToTranslate = PtcProfiler.GetProfiledFuncsToTranslate(translator.Functions);
_translateCount = 0;
_translateTotalCount = profiledFuncsToTranslate.Count;
@@ -814,7 +781,6 @@ namespace ARMeilleure.Translation.PTC
if (_translateTotalCount == 0 || degreeOfParallelism == 0)
{
ResetCarriersIfNeeded();
- PtcJumpTable.ClearIfNeeded();
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
@@ -844,19 +810,16 @@ namespace ARMeilleure.Translation.PTC
Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
- TranslatedFunction func = Translator.Translate(memory, jumpTable, countTable, address, item.funcProfile.Mode, item.funcProfile.HighCq);
+ TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
- bool isAddressUnique = funcs.TryAdd(address, func);
+ bool isAddressUnique = translator.Functions.TryAdd(address, func);
Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique.");
- if (func.HighCq)
- {
- jumpTable.RegisterFunction(address, func);
- }
-
Interlocked.Increment(ref _translateCount);
+ translator.RegisterFunction(address, func);
+
if (State != PtcState.Enabled)
{
break;
@@ -888,11 +851,6 @@ namespace ARMeilleure.Translation.PTC
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}");
- PtcJumpTable.Initialize(jumpTable);
-
- PtcJumpTable.ReadJumpTable(jumpTable);
- PtcJumpTable.ReadDynamicTable(jumpTable);
-
Thread preSaveThread = new Thread(PreSave);
preSaveThread.IsBackground = true;
preSaveThread.Start();
@@ -1022,13 +980,11 @@ namespace ARMeilleure.Translation.PTC
public long CodesLength;
public int RelocsLength;
public int UnwindInfosLength;
- public int PtcJumpTableLength;
public Hash128 InfosHash;
public Hash128 CodesHash;
public Hash128 RelocsHash;
public Hash128 UnwindInfosHash;
- public Hash128 PtcJumpTableHash;
public Hash128 HeaderHash;
diff --git a/ARMeilleure/Translation/PTC/PtcInfo.cs b/ARMeilleure/Translation/PTC/PtcInfo.cs
index 920469c7..b28b2dc1 100644
--- a/ARMeilleure/Translation/PTC/PtcInfo.cs
+++ b/ARMeilleure/Translation/PTC/PtcInfo.cs
@@ -30,7 +30,8 @@ namespace ARMeilleure.Translation.PTC
public void WriteRelocEntry(RelocEntry relocEntry)
{
_relocWriter.Write((int)relocEntry.Position);
- _relocWriter.Write((int)relocEntry.Index);
+ _relocWriter.Write((byte)relocEntry.Symbol.Type);
+ _relocWriter.Write((ulong)relocEntry.Symbol.Value);
RelocEntriesCount++;
}
diff --git a/ARMeilleure/Translation/PTC/PtcJumpTable.cs b/ARMeilleure/Translation/PTC/PtcJumpTable.cs
deleted file mode 100644
index 67719623..00000000
--- a/ARMeilleure/Translation/PTC/PtcJumpTable.cs
+++ /dev/null
@@ -1,350 +0,0 @@
-using ARMeilleure.Translation.Cache;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-
-using static ARMeilleure.Translation.PTC.PtcFormatter;
-
-namespace ARMeilleure.Translation.PTC
-{
- class PtcJumpTable
- {
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 16*/)]
- public struct TableEntry<TAddress>
- {
- public int EntryIndex;
- public long GuestAddress;
- public TAddress HostAddress;
-
- public TableEntry(int entryIndex, long guestAddress, TAddress hostAddress)
- {
- EntryIndex = entryIndex;
- GuestAddress = guestAddress;
- HostAddress = hostAddress;
- }
- }
-
- public enum DirectHostAddress : int
- {
- CallStub = 0,
- TailCallStub = 1,
- Host = 2
- }
-
- public enum IndirectHostAddress : int
- {
- CallStub = 0,
- TailCallStub = 1
- }
-
- private readonly List<TableEntry<DirectHostAddress>> _jumpTable;
- private readonly List<TableEntry<IndirectHostAddress>> _dynamicTable;
-
- public List<ulong> Targets { get; }
- public Dictionary<ulong, List<int>> Dependants { get; }
- public Dictionary<ulong, List<int>> Owners { get; }
-
- public PtcJumpTable()
- {
- _jumpTable = new List<TableEntry<DirectHostAddress>>();
- _dynamicTable = new List<TableEntry<IndirectHostAddress>>();
-
- Targets = new List<ulong>();
- Dependants = new Dictionary<ulong, List<int>>();
- Owners = new Dictionary<ulong, List<int>>();
- }
-
- public PtcJumpTable(
- List<TableEntry<DirectHostAddress>> jumpTable, List<TableEntry<IndirectHostAddress>> dynamicTable,
- List<ulong> targets, Dictionary<ulong, List<int>> dependants, Dictionary<ulong, List<int>> owners)
- {
- _jumpTable = jumpTable;
- _dynamicTable = dynamicTable;
-
- Targets = targets;
- Dependants = dependants;
- Owners = owners;
- }
-
- public static PtcJumpTable Deserialize(Stream stream)
- {
- var jumpTable = DeserializeList<TableEntry<DirectHostAddress>>(stream);
- var dynamicTable = DeserializeList<TableEntry<IndirectHostAddress>>(stream);
-
- var targets = DeserializeList<ulong>(stream);
- var dependants = DeserializeDictionary<ulong, List<int>>(stream, (stream) => DeserializeList<int>(stream));
- var owners = DeserializeDictionary<ulong, List<int>>(stream, (stream) => DeserializeList<int>(stream));
-
- return new PtcJumpTable(jumpTable, dynamicTable, targets, dependants, owners);
- }
-
- public static int GetSerializeSize(PtcJumpTable ptcJumpTable)
- {
- int size = 0;
-
- size += GetSerializeSizeList(ptcJumpTable._jumpTable);
- size += GetSerializeSizeList(ptcJumpTable._dynamicTable);
-
- size += GetSerializeSizeList(ptcJumpTable.Targets);
- size += GetSerializeSizeDictionary(ptcJumpTable.Dependants, (list) => GetSerializeSizeList(list));
- size += GetSerializeSizeDictionary(ptcJumpTable.Owners, (list) => GetSerializeSizeList(list));
-
- return size;
- }
-
- public static void Serialize(Stream stream, PtcJumpTable ptcJumpTable)
- {
- SerializeList(stream, ptcJumpTable._jumpTable);
- SerializeList(stream, ptcJumpTable._dynamicTable);
-
- SerializeList(stream, ptcJumpTable.Targets);
- SerializeDictionary(stream, ptcJumpTable.Dependants, (stream, list) => SerializeList(stream, list));
- SerializeDictionary(stream, ptcJumpTable.Owners, (stream, list) => SerializeList(stream, list));
- }
-
- public void Initialize(JumpTable jumpTable)
- {
- Targets.Clear();
-
- foreach (ulong guestAddress in jumpTable.Targets.Keys)
- {
- Targets.Add(guestAddress);
- }
-
- Dependants.Clear();
-
- foreach (var kv in jumpTable.Dependants)
- {
- Dependants.Add(kv.Key, new List<int>(kv.Value));
- }
-
- Owners.Clear();
-
- foreach (var kv in jumpTable.Owners)
- {
- Owners.Add(kv.Key, new List<int>(kv.Value));
- }
- }
-
- public void Clean(ulong guestAddress)
- {
- if (Owners.TryGetValue(guestAddress, out List<int> entries))
- {
- foreach (int entry in entries)
- {
- if ((entry & JumpTable.DynamicEntryTag) == 0)
- {
- int removed = _jumpTable.RemoveAll(tableEntry => tableEntry.EntryIndex == entry);
-
- Debug.Assert(removed == 1);
- }
- else
- {
- if (JumpTable.DynamicTableElems > 1)
- {
- throw new NotSupportedException();
- }
-
- int removed = _dynamicTable.RemoveAll(tableEntry => tableEntry.EntryIndex == (entry & ~JumpTable.DynamicEntryTag));
-
- Debug.Assert(removed == 1);
- }
- }
- }
-
- Targets.Remove(guestAddress);
- Dependants.Remove(guestAddress);
- Owners.Remove(guestAddress);
- }
-
- public void ClearIfNeeded()
- {
- if (_jumpTable.Count == 0 && _dynamicTable.Count == 0 &&
- Targets.Count == 0 && Dependants.Count == 0 && Owners.Count == 0)
- {
- return;
- }
-
- _jumpTable.Clear();
- _jumpTable.TrimExcess();
- _dynamicTable.Clear();
- _dynamicTable.TrimExcess();
-
- Targets.Clear();
- Targets.TrimExcess();
- Dependants.Clear();
- Dependants.TrimExcess();
- Owners.Clear();
- Owners.TrimExcess();
- }
-
- public void WriteJumpTable(JumpTable jumpTable, ConcurrentDictionary<ulong, TranslatedFunction> funcs)
- {
- // Writes internal state to jump table in-memory, after PtcJumpTable was deserialized.
-
- foreach (var tableEntry in _jumpTable)
- {
- long guestAddress = tableEntry.GuestAddress;
- DirectHostAddress directHostAddress = tableEntry.HostAddress;
-
- long hostAddress;
-
- if (directHostAddress == DirectHostAddress.CallStub)
- {
- hostAddress = DirectCallStubs.DirectCallStub(false).ToInt64();
- }
- else if (directHostAddress == DirectHostAddress.TailCallStub)
- {
- hostAddress = DirectCallStubs.DirectCallStub(true).ToInt64();
- }
- else if (directHostAddress == DirectHostAddress.Host)
- {
- if (funcs.TryGetValue((ulong)guestAddress, out TranslatedFunction func))
- {
- hostAddress = func.FuncPtr.ToInt64();
- }
- else
- {
- if (!PtcProfiler.ProfiledFuncs.TryGetValue((ulong)guestAddress, out var value) || !value.HighCq)
- {
- throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})");
- }
-
- hostAddress = 0L;
- }
- }
- else
- {
- throw new InvalidOperationException(nameof(directHostAddress));
- }
-
- int entry = tableEntry.EntryIndex;
-
- jumpTable.Table.SetEntry(entry);
- jumpTable.ExpandIfNeededJumpTable(entry);
-
- IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry);
-
- Marshal.WriteInt64(addr, 0, guestAddress);
- Marshal.WriteInt64(addr, 8, hostAddress);
- }
- }
-
- public void WriteDynamicTable(JumpTable jumpTable)
- {
- // Writes internal state to jump table in-memory, after PtcJumpTable was deserialized.
-
- if (JumpTable.DynamicTableElems > 1)
- {
- throw new NotSupportedException();
- }
-
- foreach (var tableEntry in _dynamicTable)
- {
- long guestAddress = tableEntry.GuestAddress;
- IndirectHostAddress indirectHostAddress = tableEntry.HostAddress;
-
- long hostAddress;
-
- if (indirectHostAddress == IndirectHostAddress.CallStub)
- {
- hostAddress = DirectCallStubs.IndirectCallStub(false).ToInt64();
- }
- else if (indirectHostAddress == IndirectHostAddress.TailCallStub)
- {
- hostAddress = DirectCallStubs.IndirectCallStub(true).ToInt64();
- }
- else
- {
- throw new InvalidOperationException(nameof(indirectHostAddress));
- }
-
- int entry = tableEntry.EntryIndex;
-
- jumpTable.DynTable.SetEntry(entry);
- jumpTable.ExpandIfNeededDynamicTable(entry);
-
- IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry);
-
- Marshal.WriteInt64(addr, 0, guestAddress);
- Marshal.WriteInt64(addr, 8, hostAddress);
- }
- }
-
- public void ReadJumpTable(JumpTable jumpTable)
- {
- // Reads in-memory jump table state and store internally for PtcJumpTable serialization.
-
- _jumpTable.Clear();
-
- IEnumerable<int> entries = jumpTable.Table.GetEntries();
-
- foreach (int entry in entries)
- {
- IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry);
-
- long guestAddress = Marshal.ReadInt64(addr, 0);
- long hostAddress = Marshal.ReadInt64(addr, 8);
-
- DirectHostAddress directHostAddress;
-
- if (hostAddress == DirectCallStubs.DirectCallStub(false).ToInt64())
- {
- directHostAddress = DirectHostAddress.CallStub;
- }
- else if (hostAddress == DirectCallStubs.DirectCallStub(true).ToInt64())
- {
- directHostAddress = DirectHostAddress.TailCallStub;
- }
- else
- {
- directHostAddress = DirectHostAddress.Host;
- }
-
- _jumpTable.Add(new TableEntry<DirectHostAddress>(entry, guestAddress, directHostAddress));
- }
- }
-
- public void ReadDynamicTable(JumpTable jumpTable)
- {
- // Reads in-memory jump table state and store internally for PtcJumpTable serialization.
-
- if (JumpTable.DynamicTableElems > 1)
- {
- throw new NotSupportedException();
- }
-
- _dynamicTable.Clear();
-
- IEnumerable<int> entries = jumpTable.DynTable.GetEntries();
-
- foreach (int entry in entries)
- {
- IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry);
-
- long guestAddress = Marshal.ReadInt64(addr, 0);
- long hostAddress = Marshal.ReadInt64(addr, 8);
-
- IndirectHostAddress indirectHostAddress;
-
- if (hostAddress == DirectCallStubs.IndirectCallStub(false).ToInt64())
- {
- indirectHostAddress = IndirectHostAddress.CallStub;
- }
- else if (hostAddress == DirectCallStubs.IndirectCallStub(true).ToInt64())
- {
- indirectHostAddress = IndirectHostAddress.TailCallStub;
- }
- else
- {
- throw new InvalidOperationException($"({nameof(hostAddress)} = 0x{hostAddress:X16})");
- }
-
- _dynamicTable.Add(new TableEntry<IndirectHostAddress>(entry, guestAddress, indirectHostAddress));
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/RelocEntry.cs b/ARMeilleure/Translation/PTC/RelocEntry.cs
index 52d73db8..545612d0 100644
--- a/ARMeilleure/Translation/PTC/RelocEntry.cs
+++ b/ARMeilleure/Translation/PTC/RelocEntry.cs
@@ -2,20 +2,20 @@ namespace ARMeilleure.Translation.PTC
{
struct RelocEntry
{
- public const int Stride = 8; // Bytes.
+ public const int Stride = 13; // Bytes.
public int Position;
- public int Index;
+ public Symbol Symbol;
- public RelocEntry(int position, int index)
+ public RelocEntry(int position, Symbol symbol)
{
Position = position;
- Index = index;
+ Symbol = symbol;
}
public override string ToString()
{
- return $"({nameof(Position)} = {Position}, {nameof(Index)} = {Index})";
+ return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/Symbol.cs b/ARMeilleure/Translation/PTC/Symbol.cs
new file mode 100644
index 00000000..f9d67742
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/Symbol.cs
@@ -0,0 +1,100 @@
+using System;
+
+namespace ARMeilleure.Translation.PTC
+{
+ /// <summary>
+ /// Represents a symbol.
+ /// </summary>
+ struct Symbol
+ {
+ private readonly ulong _value;
+
+ /// <summary>
+ /// Gets the <see cref="SymbolType"/> of the <see cref="Symbol"/>.
+ /// </summary>
+ public SymbolType Type { get; }
+
+ /// <summary>
+ /// Gets the value of the <see cref="Symbol"/>.
+ /// </summary>
+ /// <exception cref="InvalidOperationException"><see cref="Type"/> is <see cref="SymbolType.None"/></exception>
+ public ulong Value
+ {
+ get
+ {
+ if (Type == SymbolType.None)
+ {
+ ThrowSymbolNone();
+ }
+
+ return _value;
+ }
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Symbol"/> structure with the specified <see cref="SymbolType"/> and value.
+ /// </summary>
+ /// <param name="type">Type of symbol</param>
+ /// <param name="value">Value of symbol</param>
+ public Symbol(SymbolType type, ulong value)
+ {
+ (Type, _value) = (type, value);
+ }
+
+ /// <summary>
+ /// Determines if the specified <see cref="Symbol"/> instances are equal.
+ /// </summary>
+ /// <param name="a">First instance</param>
+ /// <param name="b">Second instance</param>
+ /// <returns><see langword="true"/> if equal; otherwise <see langword="false"/></returns>
+ public static bool operator ==(Symbol a, Symbol b)
+ {
+ return a.Equals(b);
+ }
+
+ /// <summary>
+ /// Determines if the specified <see cref="Symbol"/> instances are not equal.
+ /// </summary>
+ /// <param name="a">First instance</param>
+ /// <param name="b">Second instance</param>
+ /// <returns><see langword="true"/> if not equal; otherwise <see langword="false"/></returns>
+ /// <inheritdoc/>
+ public static bool operator !=(Symbol a, Symbol b)
+ {
+ return !(a == b);
+ }
+
+ /// <summary>
+ /// Determines if the specified <see cref="Symbol"/> is equal to this <see cref="Symbol"/> instance.
+ /// </summary>
+ /// <param name="other">Other <see cref="Symbol"/> instance</param>
+ /// <returns><see langword="true"/> if equal; otherwise <see langword="false"/></returns>
+ public bool Equals(Symbol other)
+ {
+ return other.Type == Type && other._value == _value;
+ }
+
+ /// <inheritdoc/>
+ public override bool Equals(object obj)
+ {
+ return obj is Symbol sym && Equals(sym);
+ }
+
+ /// <inheritdoc/>
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(Type, _value);
+ }
+
+ /// <inheritdoc/>
+ public override string ToString()
+ {
+ return $"{Type}:{_value}";
+ }
+
+ private static void ThrowSymbolNone()
+ {
+ throw new InvalidOperationException("Symbol refers to nothing.");
+ }
+ }
+}
diff --git a/ARMeilleure/Translation/PTC/SymbolType.cs b/ARMeilleure/Translation/PTC/SymbolType.cs
new file mode 100644
index 00000000..cd7b6c1c
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/SymbolType.cs
@@ -0,0 +1,28 @@
+namespace ARMeilleure.Translation.PTC
+{
+ /// <summary>
+ /// Types of <see cref="Symbol"/>.
+ /// </summary>
+ enum SymbolType : byte
+ {
+ /// <summary>
+ /// Refers to nothing, i.e no symbol.
+ /// </summary>
+ None,
+
+ /// <summary>
+ /// Refers to an entry in <see cref="Delegates"/>.
+ /// </summary>
+ DelegateTable,
+
+ /// <summary>
+ /// Refers to an entry in <see cref="Translator.FunctionTable"/>.
+ /// </summary>
+ FunctionTable,
+
+ /// <summary>
+ /// Refers to a special symbol which is handled by <see cref="Ptc.PatchCode"/>.
+ /// </summary>
+ Special
+ }
+}