diff options
| author | FICTURE7 <FICTURE7@gmail.com> | 2021-05-30 01:06:28 +0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-29 18:06:28 -0300 |
| commit | 9d7627af6484e090ebbc3209bc7301f0bdf47d24 (patch) | |
| tree | 057637c1b6d9de6fd80ea271cb93667cfb43abf3 /ARMeilleure/Translation/PTC | |
| parent | f3b0b4831c323a20393aa0388f947317354372b7 (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.cs | 140 | ||||
| -rw-r--r-- | ARMeilleure/Translation/PTC/PtcInfo.cs | 3 | ||||
| -rw-r--r-- | ARMeilleure/Translation/PTC/PtcJumpTable.cs | 350 | ||||
| -rw-r--r-- | ARMeilleure/Translation/PTC/RelocEntry.cs | 10 | ||||
| -rw-r--r-- | ARMeilleure/Translation/PTC/Symbol.cs | 100 | ||||
| -rw-r--r-- | ARMeilleure/Translation/PTC/SymbolType.cs | 28 |
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 + } +} |
