diff options
| author | LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> | 2020-12-17 20:32:09 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-12-17 20:32:09 +0100 |
| commit | b5c215111de665ef8d18b38405ac55e17996e30e (patch) | |
| tree | 3fd285d43f466dbe10b80510b20b2076391555b4 /ARMeilleure/Translation/PTC/PtcJumpTable.cs | |
| parent | 10aa11ce13291cf2ea2aeb751838c65c45fdc0ba (diff) | |
PPTC Follow-up. (#1712)
* Added support for offline invalidation, via PPTC, of low cq translations replaced by high cq translations; both on a single run and between runs.
Added invalidation of .cache files in the event of reuse on a different user operating system.
Added .info and .cache files invalidation in case of a failed stream decompression.
Nits.
* InternalVersion = 1712;
* Nits.
* Address comment.
* Get rid of BinaryFormatter.
Nits.
* Move Ptc.LoadTranslations().
Nits.
* Nits.
* Fixed corner cases (in case backup copies have to be used). Added save logs.
* Not core fixes.
* Complement to the previous commit. Added load logs. Removed BinaryFormatter leftovers.
* Add LoadTranslations log.
* Nits.
* Removed the search and management of LowCq overlapping functions.
* Final increment of .info and .cache flags.
* Nit.
* GetIndirectFunctionAddress(): Validate that writing actually takes place in dynamic table memory range (and not elsewhere).
* Fix Ptc.UpdateInfo() due to rebase.
* Nit for retrigger Checks.
* Nit for retrigger Checks.
Diffstat (limited to 'ARMeilleure/Translation/PTC/PtcJumpTable.cs')
| -rw-r--r-- | ARMeilleure/Translation/PTC/PtcJumpTable.cs | 281 |
1 files changed, 237 insertions, 44 deletions
diff --git a/ARMeilleure/Translation/PTC/PtcJumpTable.cs b/ARMeilleure/Translation/PTC/PtcJumpTable.cs index e4af68d6..d52d0874 100644 --- a/ARMeilleure/Translation/PTC/PtcJumpTable.cs +++ b/ARMeilleure/Translation/PTC/PtcJumpTable.cs @@ -2,15 +2,15 @@ using ARMeilleure.Translation.Cache; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; using System.Runtime.InteropServices; namespace ARMeilleure.Translation.PTC { - [Serializable] class PtcJumpTable { - [Serializable] - private struct TableEntry<TAddress> + public struct TableEntry<TAddress> { public int EntryIndex; public long GuestAddress; @@ -24,82 +24,270 @@ namespace ARMeilleure.Translation.PTC } } - private enum DirectHostAddress + public enum DirectHostAddress { - CallStub, - TailCallStub, - Host + CallStub = 0, + TailCallStub = 1, + Host = 2 } - private enum IndirectHostAddress + public enum IndirectHostAddress { - CallStub, - TailCallStub + CallStub = 0, + TailCallStub = 1 } private readonly List<TableEntry<DirectHostAddress>> _jumpTable; private readonly List<TableEntry<IndirectHostAddress>> _dynamicTable; - private readonly List<ulong> _targets; - private readonly Dictionary<ulong, List<int>> _dependants; - private readonly Dictionary<ulong, List<int>> _owners; - - public List<ulong> Targets => _targets; - public Dictionary<ulong, List<int>> Dependants => _dependants; - public Dictionary<ulong, List<int>> Owners => _owners; + 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>>(); + 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(MemoryStream stream) + { + using (BinaryReader reader = new BinaryReader(stream, EncodingCache.UTF8NoBOM, true)) + { + var jumpTable = new List<TableEntry<DirectHostAddress>>(); + + int jumpTableCount = reader.ReadInt32(); + + for (int i = 0; i < jumpTableCount; i++) + { + int entryIndex = reader.ReadInt32(); + long guestAddress = reader.ReadInt64(); + DirectHostAddress hostAddress = (DirectHostAddress)reader.ReadInt32(); + + jumpTable.Add(new TableEntry<DirectHostAddress>(entryIndex, guestAddress, hostAddress)); + } + + var dynamicTable = new List<TableEntry<IndirectHostAddress>>(); + + int dynamicTableCount = reader.ReadInt32(); + + for (int i = 0; i < dynamicTableCount; i++) + { + int entryIndex = reader.ReadInt32(); + long guestAddress = reader.ReadInt64(); + IndirectHostAddress hostAddress = (IndirectHostAddress)reader.ReadInt32(); + + dynamicTable.Add(new TableEntry<IndirectHostAddress>(entryIndex, guestAddress, hostAddress)); + } + + var targets = new List<ulong>(); + + int targetsCount = reader.ReadInt32(); + + for (int i = 0; i < targetsCount; i++) + { + ulong address = reader.ReadUInt64(); + + targets.Add(address); + } + + var dependants = new Dictionary<ulong, List<int>>(); + + int dependantsCount = reader.ReadInt32(); + + for (int i = 0; i < dependantsCount; i++) + { + ulong address = reader.ReadUInt64(); + + var entries = new List<int>(); + + int entriesCount = reader.ReadInt32(); + + for (int j = 0; j < entriesCount; j++) + { + int entry = reader.ReadInt32(); + + entries.Add(entry); + } + + dependants.Add(address, entries); + } + + var owners = new Dictionary<ulong, List<int>>(); + + int ownersCount = reader.ReadInt32(); + + for (int i = 0; i < ownersCount; i++) + { + ulong address = reader.ReadUInt64(); + + var entries = new List<int>(); + + int entriesCount = reader.ReadInt32(); + + for (int j = 0; j < entriesCount; j++) + { + int entry = reader.ReadInt32(); + + entries.Add(entry); + } + + owners.Add(address, entries); + } + + return new PtcJumpTable(jumpTable, dynamicTable, targets, dependants, owners); + } + } + + public static void Serialize(MemoryStream stream, PtcJumpTable ptcJumpTable) + { + using (BinaryWriter writer = new BinaryWriter(stream, EncodingCache.UTF8NoBOM, true)) + { + writer.Write((int)ptcJumpTable._jumpTable.Count); + + foreach (var tableEntry in ptcJumpTable._jumpTable) + { + writer.Write((int)tableEntry.EntryIndex); + writer.Write((long)tableEntry.GuestAddress); + writer.Write((int)tableEntry.HostAddress); + } + + writer.Write((int)ptcJumpTable._dynamicTable.Count); + + foreach (var tableEntry in ptcJumpTable._dynamicTable) + { + writer.Write((int)tableEntry.EntryIndex); + writer.Write((long)tableEntry.GuestAddress); + writer.Write((int)tableEntry.HostAddress); + } + + writer.Write((int)ptcJumpTable.Targets.Count); + + foreach (ulong address in ptcJumpTable.Targets) + { + writer.Write((ulong)address); + } + + writer.Write((int)ptcJumpTable.Dependants.Count); + + foreach (var kv in ptcJumpTable.Dependants) + { + writer.Write((ulong)kv.Key); // address + + writer.Write((int)kv.Value.Count); + + foreach (int entry in kv.Value) + { + writer.Write((int)entry); + } + } + + writer.Write((int)ptcJumpTable.Owners.Count); + + foreach (var kv in ptcJumpTable.Owners) + { + writer.Write((ulong)kv.Key); // address + + writer.Write((int)kv.Value.Count); + + foreach (int entry in kv.Value) + { + writer.Write((int)entry); + } + } + } } public void Initialize(JumpTable jumpTable) { - _targets.Clear(); + Targets.Clear(); foreach (ulong guestAddress in jumpTable.Targets.Keys) { - _targets.Add(guestAddress); + Targets.Add(guestAddress); } - _dependants.Clear(); + Dependants.Clear(); - foreach (var item in jumpTable.Dependants) + foreach (var kv in jumpTable.Dependants) { - _dependants.Add(item.Key, new List<int>(item.Value)); + Dependants.Add(kv.Key, new List<int>(kv.Value)); } - _owners.Clear(); + Owners.Clear(); - foreach (var item in jumpTable.Owners) + foreach (var kv in jumpTable.Owners) { - _owners.Add(item.Key, new List<int>(item.Value)); + Owners.Add(kv.Key, new List<int>(kv.Value)); } } + // For future use. + 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 Clear() { _jumpTable.Clear(); _dynamicTable.Clear(); - _targets.Clear(); - _dependants.Clear(); - _owners.Clear(); + Targets.Clear(); + Dependants.Clear(); + Owners.Clear(); } public void WriteJumpTable(JumpTable jumpTable, ConcurrentDictionary<ulong, TranslatedFunction> funcs) { - // Writes internal state to jump table in-memory, after PTC was loaded. + // Writes internal state to jump table in-memory, after PtcJumpTable was deserialized. - foreach (var item in _jumpTable) + foreach (var tableEntry in _jumpTable) { - long guestAddress = item.GuestAddress; - DirectHostAddress directHostAddress = item.HostAddress; + long guestAddress = tableEntry.GuestAddress; + DirectHostAddress directHostAddress = tableEntry.HostAddress; long hostAddress; @@ -119,7 +307,12 @@ namespace ARMeilleure.Translation.PTC } else { - throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})"); + if (!PtcProfiler.ProfiledFuncs.TryGetValue((ulong)guestAddress, out var value) || !value.highCq) + { + throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})"); + } + + hostAddress = 0L; } } else @@ -127,7 +320,7 @@ namespace ARMeilleure.Translation.PTC throw new InvalidOperationException(nameof(directHostAddress)); } - int entry = item.EntryIndex; + int entry = tableEntry.EntryIndex; jumpTable.Table.SetEntry(entry); jumpTable.ExpandIfNeededJumpTable(entry); @@ -141,17 +334,17 @@ namespace ARMeilleure.Translation.PTC public void WriteDynamicTable(JumpTable jumpTable) { - // Writes internal state to jump table in-memory, after PTC was loaded. + // Writes internal state to jump table in-memory, after PtcJumpTable was deserialized. if (JumpTable.DynamicTableElems > 1) { throw new NotSupportedException(); } - foreach (var item in _dynamicTable) + foreach (var tableEntry in _dynamicTable) { - long guestAddress = item.GuestAddress; - IndirectHostAddress indirectHostAddress = item.HostAddress; + long guestAddress = tableEntry.GuestAddress; + IndirectHostAddress indirectHostAddress = tableEntry.HostAddress; long hostAddress; @@ -168,7 +361,7 @@ namespace ARMeilleure.Translation.PTC throw new InvalidOperationException(nameof(indirectHostAddress)); } - int entry = item.EntryIndex; + int entry = tableEntry.EntryIndex; jumpTable.DynTable.SetEntry(entry); jumpTable.ExpandIfNeededDynamicTable(entry); @@ -182,7 +375,7 @@ namespace ARMeilleure.Translation.PTC public void ReadJumpTable(JumpTable jumpTable) { - // Reads in-memory jump table state and store internally for PTC serialization. + // Reads in-memory jump table state and store internally for PtcJumpTable serialization. _jumpTable.Clear(); @@ -216,7 +409,7 @@ namespace ARMeilleure.Translation.PTC public void ReadDynamicTable(JumpTable jumpTable) { - // Reads in-memory jump table state and store internally for PTC serialization. + // Reads in-memory jump table state and store internally for PtcJumpTable serialization. if (JumpTable.DynamicTableElems > 1) { |
