diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs index 94d4554835..92fd247836 100644 --- a/ARMeilleure/CodeGen/X86/Assembler.cs +++ b/ARMeilleure/CodeGen/X86/Assembler.cs @@ -882,7 +882,7 @@ namespace ARMeilleure.CodeGen.X86 } else if (dest != null && dest.Kind == OperandKind.Register && info.OpRImm64 != BadOp) { - string name = source.Name; + int? index = source.Index; int rexPrefix = GetRexPrefix(dest, source, type, rrm: false); @@ -893,9 +893,9 @@ namespace ARMeilleure.CodeGen.X86 WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111))); - if (_aotInfo != null && name != null) + if (_aotInfo != null && index != null) { - _aotInfo.WriteRelocEntry(new RelocEntry((int)_stream.Position, name)); + _aotInfo.WriteRelocEntry(new RelocEntry((int)_stream.Position, (int)index)); } WriteUInt64(imm); diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs index 8186c3c2a5..982446e50b 100644 --- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs +++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs @@ -290,9 +290,9 @@ namespace ARMeilleure.Instructions private static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblFallbackPath) { - string name = nameof(MemoryManager.PageTable); - - Operand pte = Const(context.Memory.PageTable.ToInt64(), Aot.Enabled, name); + Operand pte = Aot.Enabled + ? Const(context.Memory.PageTable.ToInt64(), true, Aot.PageTableIndex) + : Const(context.Memory.PageTable.ToInt64()); int bit = MemoryManager.PageBits; diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs index a98e2d53b2..a3a2c5ccc8 100644 --- a/ARMeilleure/IntermediateRepresentation/Operand.cs +++ b/ARMeilleure/IntermediateRepresentation/Operand.cs @@ -13,7 +13,7 @@ namespace ARMeilleure.IntermediateRepresentation public bool DisableCF { get; private set; } - public string Name { get; private set; } + public int? Index { get; private set; } public LinkedList Assignments { get; } public LinkedList Uses { get; } @@ -40,13 +40,13 @@ namespace ARMeilleure.IntermediateRepresentation Value = (uint)value; } - public Operand(long value, bool disableCF = false, string name = null) : this(OperandKind.Constant, OperandType.I64) + public Operand(long value, bool disableCF = false, int? index = null) : this(OperandKind.Constant, OperandType.I64) { Value = (ulong)value; DisableCF = disableCF; - Name = name; + Index = index; } public Operand(ulong value) : this(OperandKind.Constant, OperandType.I64) diff --git a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs index 9d6f00c335..6dd0246e86 100644 --- a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs +++ b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs @@ -22,9 +22,9 @@ namespace ARMeilleure.IntermediateRepresentation return new Operand(value); } - public static Operand Const(long value, bool disableCF = false, string name = null) + public static Operand Const(long value, bool disableCF = false, int? index = null) { - return new Operand(value, disableCF, name); + return new Operand(value, disableCF, index); } public static Operand Const(ulong value) diff --git a/ARMeilleure/Translation/AOT/Aot.cs b/ARMeilleure/Translation/AOT/Aot.cs index bd32da64b8..151195e2f1 100644 --- a/ARMeilleure/Translation/AOT/Aot.cs +++ b/ARMeilleure/Translation/AOT/Aot.cs @@ -1,5 +1,4 @@ using ARMeilleure.CodeGen; -using ARMeilleure.Memory; using System; using System.Collections.Concurrent; using System.Diagnostics; @@ -13,6 +12,8 @@ namespace ARMeilleure.Translation.AOT { public static class Aot { + private const int InternalVersion = 0; + private const string BaseDir = "Ryujinx"; private const string TitleIdTextDefault = "0000000000000000"; @@ -22,6 +23,8 @@ namespace ARMeilleure.Translation.AOT internal const int MinCodeLengthToSave = 0x180; // Bytes. + internal const int PageTableIndex = -1; + private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest; private static readonly MemoryStream _infosStream; @@ -72,7 +75,7 @@ namespace ARMeilleure.Translation.AOT _disposed = false; } - public static void Init(string titleIdText, string displayVersion, bool enabled = true, bool readOnlyMode = false) + public static void Init(string titleIdText, string displayVersion, bool enabled, bool readOnlyMode) { if (String.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault) { @@ -140,31 +143,38 @@ namespace ARMeilleure.Translation.AOT { cacheStream.Seek((long)hashSize, SeekOrigin.Begin); - ReadHeader(cacheStream, out int infosLen, out int codesLen, out int relocsLen); + ReadHeader(cacheStream, out int cacheFileVersion, out int infosLen, out int codesLen, out int relocsLen); - if (infosLen % InfoEntry.Size == 0) + if (cacheFileVersion == (int)InternalVersion) { - byte[] infosBuf = new byte[infosLen]; - byte[] codesBuf = new byte[codesLen]; - byte[] relocsBuf = new byte[relocsLen]; - - cacheStream.Read(infosBuf, 0, infosLen); - cacheStream.Read(codesBuf, 0, codesLen); - cacheStream.Read(relocsBuf, 0, relocsLen); - - if (cacheStream.Position == cacheStream.Length) + if (infosLen % InfoEntry.Size == 0) { - try + byte[] infosBuf = new byte[infosLen]; + byte[] codesBuf = new byte[codesLen]; + byte[] relocsBuf = new byte[relocsLen]; + + cacheStream.Read(infosBuf, 0, infosLen); + cacheStream.Read(codesBuf, 0, codesLen); + cacheStream.Read(relocsBuf, 0, relocsLen); + + if (cacheStream.Position == cacheStream.Length) { - _infosStream. Write(infosBuf, 0, infosLen); - _codesStream. Write(codesBuf, 0, codesLen); - _relocsStream.Write(relocsBuf, 0, relocsLen); + try + { + _infosStream. Write(infosBuf, 0, infosLen); + _codesStream. Write(codesBuf, 0, codesLen); + _relocsStream.Write(relocsBuf, 0, relocsLen); + } + catch + { + _infosStream. SetLength(0L); + _codesStream. SetLength(0L); + _relocsStream.SetLength(0L); + } } - catch + else { - _infosStream. SetLength(0L); - _codesStream. SetLength(0L); - _relocsStream.SetLength(0L); + InvalidateCompressedCacheStream(compressedCacheStream); } } else @@ -216,12 +226,15 @@ namespace ARMeilleure.Translation.AOT private static void ReadHeader( MemoryStream cacheStream, + out int cacheFileVersion, out int infosLen, out int codesLen, out int relocsLen) { BinaryReader headerReader = new BinaryReader(cacheStream, EncodingCache.UTF8NoBOM, true); + cacheFileVersion = headerReader.ReadInt32(); + infosLen = headerReader.ReadInt32(); codesLen = headerReader.ReadInt32(); relocsLen = headerReader.ReadInt32(); @@ -303,6 +316,8 @@ namespace ARMeilleure.Translation.AOT { BinaryWriter headerWriter = new BinaryWriter(cacheStream, EncodingCache.UTF8NoBOM, true); + headerWriter.Write((int)InternalVersion); + headerWriter.Write((int)_infosStream. Length); // infosLen headerWriter.Write((int)_codesStream. Length); // codesLen headerWriter.Write((int)_relocsStream.Length); // relocsLen @@ -375,10 +390,10 @@ namespace ARMeilleure.Translation.AOT for (int i = 0; i < relocEntriesCount; i++) { - int position = relocReader.ReadInt32(); - string name = relocReader.ReadString(); + int position = relocReader.ReadInt32(); + int index = relocReader.ReadInt32(); - relocEntries[i] = new RelocEntry(position, name); + relocEntries[i] = new RelocEntry(position, index); } return relocEntries; @@ -390,11 +405,11 @@ namespace ARMeilleure.Translation.AOT { byte[] immBytes = new byte[8]; - if (relocEntry.Name == nameof(MemoryManager.PageTable)) + if (relocEntry.Index == PageTableIndex) { immBytes = BitConverter.GetBytes((ulong)pageTable.ToInt64()); } - else if (Delegates.TryGetDelegateFuncPtr(relocEntry.Name, out IntPtr funcPtr)) + else if (Delegates.TryGetDelegateFuncPtr(relocEntry.Index, out IntPtr funcPtr)) // By delegate index. { immBytes = BitConverter.GetBytes((ulong)funcPtr.ToInt64()); } diff --git a/ARMeilleure/Translation/AOT/AotInfo.cs b/ARMeilleure/Translation/AOT/AotInfo.cs index 7184f6efe0..28276af3d6 100644 --- a/ARMeilleure/Translation/AOT/AotInfo.cs +++ b/ARMeilleure/Translation/AOT/AotInfo.cs @@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.AOT public void WriteRelocEntry(RelocEntry relocEntry) { _relocWriter.Write(relocEntry.Position); - _relocWriter.Write(relocEntry.Name); + _relocWriter.Write(relocEntry.Index); RelocEntriesCount++; } diff --git a/ARMeilleure/Translation/AOT/RelocEntry.cs b/ARMeilleure/Translation/AOT/RelocEntry.cs index f83f6c8395..34835c9310 100644 --- a/ARMeilleure/Translation/AOT/RelocEntry.cs +++ b/ARMeilleure/Translation/AOT/RelocEntry.cs @@ -2,18 +2,18 @@ namespace ARMeilleure.Translation.AOT { struct RelocEntry { - public int Position; - public string Name; + public int Position; + public int Index; - public RelocEntry(int position, string name) + public RelocEntry(int position, int index) { Position = position; - Name = name; + Index = index; } public override string ToString() { - return $"({nameof(Position)} = {Position}, {nameof(Name)} = {Name})"; + return $"({nameof(Position)} = {Position}, {nameof(Index)} = {Index})"; } } } diff --git a/ARMeilleure/Translation/DelegateInfo.cs b/ARMeilleure/Translation/DelegateInfo.cs index f2dec35ad7..e68cfc1b76 100644 --- a/ARMeilleure/Translation/DelegateInfo.cs +++ b/ARMeilleure/Translation/DelegateInfo.cs @@ -1,5 +1,3 @@ -using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.State; using System; using System.Runtime.InteropServices; @@ -9,50 +7,13 @@ namespace ARMeilleure.Translation { private readonly Delegate _dlg; // Ensure that this delegate will not be garbage collected. - public IntPtr FuncPtr { get; } - public OperandType RetType { get; } + public IntPtr FuncPtr { get; } public DelegateInfo(Delegate dlg) { _dlg = dlg; FuncPtr = Marshal.GetFunctionPointerForDelegate(dlg); - RetType = GetOperandType(dlg.Method.ReturnType); - } - - private static OperandType GetOperandType(Type type) - { - if (type == typeof(bool) || type == typeof(byte) || - type == typeof(char) || type == typeof(short) || - type == typeof(int) || type == typeof(sbyte) || - type == typeof(ushort) || type == typeof(uint)) - { - return OperandType.I32; - } - else if (type == typeof(long) || type == typeof(ulong)) - { - return OperandType.I64; - } - else if (type == typeof(double)) - { - return OperandType.FP64; - } - else if (type == typeof(float)) - { - return OperandType.FP32; - } - else if (type == typeof(V128)) - { - return OperandType.V128; - } - else if (type == typeof(void)) - { - return OperandType.None; - } - else - { - throw new ArgumentException($"Invalid type \"{type.Name}\"."); - } } } } diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs index 23957d65ba..55bdc2515f 100644 --- a/ARMeilleure/Translation/Delegates.cs +++ b/ARMeilleure/Translation/Delegates.cs @@ -7,16 +7,11 @@ namespace ARMeilleure.Translation { static class Delegates { - public static bool TryGetDelegateFuncPtr(string key, out IntPtr funcPtr) + public static bool TryGetDelegateFuncPtr(int index, out IntPtr funcPtr) // By delegate index. { - if (key == null) + if (index >= 0 && index < _delegates.Count) { - throw new ArgumentNullException(nameof(key)); - } - - if (_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) - { - funcPtr = dlgInfo.FuncPtr; + funcPtr = _delegates.Values[index].FuncPtr; return true; } @@ -28,38 +23,61 @@ namespace ARMeilleure.Translation } } - public static DelegateInfo GetDelegateInfo(string key) + public static IntPtr GetDelegateFuncPtr(MethodInfo info) { - if (key == null) + if (info == null) { - throw new ArgumentNullException(nameof(key)); + throw new ArgumentNullException(nameof(info)); } + string key = GetKey(info); + if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) { throw new ArgumentException($"({nameof(key)} = {key})"); } - return dlgInfo; + return dlgInfo.FuncPtr; + } + + public static int GetDelegateIndex(MethodInfo info) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + string key = GetKey(info); + + int index = _delegates.IndexOfKey(key); + + if (index == -1) + { + throw new ArgumentException($"({nameof(key)} = {key})"); + } + + return index; } private static void SetDelegateInfo(MethodInfo info) { - string key = $"{info.DeclaringType.Name}.{info.Name}"; + string key = GetKey(info); Delegate dlg = DelegateHelpers.GetDelegate(info); - if (!_delegates.TryAdd(key, new DelegateInfo(dlg))) - { - throw new ArgumentException($"({nameof(key)} = {key})"); - } + _delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key) } - private static readonly Dictionary _delegates; + private static string GetKey(MethodInfo info) + { + return $"{info.DeclaringType.Name}.{info.Name}"; + } + + private static readonly SortedList _delegates; static Delegates() { - _delegates = new Dictionary(); + _delegates = new SortedList(); SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) })); SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Ceiling), new Type[] { typeof(double) })); diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs index 9baba0e6d3..e4a31e5afb 100644 --- a/ARMeilleure/Translation/EmitterContext.cs +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -1,4 +1,5 @@ using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; using System; using System.Collections.Generic; using System.Reflection; @@ -81,11 +82,55 @@ namespace ARMeilleure.Translation public Operand Call(MethodInfo info, params Operand[] callArgs) { - string name = $"{info.DeclaringType.Name}.{info.Name}"; + IntPtr funcPtr = Delegates.GetDelegateFuncPtr(info); - DelegateInfo dlgInfo = Delegates.GetDelegateInfo(name); + OperandType retType = GetOperandType(info.ReturnType); - return Call(Const(dlgInfo.FuncPtr.ToInt64(), Aot.Enabled, name), dlgInfo.RetType, callArgs); + if (Aot.Enabled) + { + int index = Delegates.GetDelegateIndex(info); + + return Call(Const(funcPtr.ToInt64(), true, index), retType, callArgs); + } + else + { + return Call(Const(funcPtr.ToInt64()), retType, callArgs); + } + } + + private static OperandType GetOperandType(Type type) + { + if (type == typeof(bool) || type == typeof(byte) || + type == typeof(char) || type == typeof(short) || + type == typeof(int) || type == typeof(sbyte) || + type == typeof(ushort) || type == typeof(uint)) + { + return OperandType.I32; + } + else if (type == typeof(long) || type == typeof(ulong)) + { + return OperandType.I64; + } + else if (type == typeof(double)) + { + return OperandType.FP64; + } + else if (type == typeof(float)) + { + return OperandType.FP32; + } + else if (type == typeof(V128)) + { + return OperandType.V128; + } + else if (type == typeof(void)) + { + return OperandType.None; + } + else + { + throw new ArgumentException($"Invalid type \"{type.Name}\"."); + } } public Operand Call(Operand address, OperandType returnType, params Operand[] callArgs) diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 50ddd58cc6..2b70de0412 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -584,7 +584,7 @@ namespace Ryujinx.HLE.HOS Logger.PrintInfo(LogClass.Loader, "AOT Init..."); - Aot.Init(TitleIdText, DisplayVersion); + Aot.Init(TitleIdText, DisplayVersion, enabled: true, readOnlyMode: false); ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray()); }