mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-18 22:58:43 +02:00
150 lines
3.7 KiB
C#
150 lines
3.7 KiB
C#
using ChocolArm64.Memory;
|
|
using ChocolArm64.State;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
|
|
namespace ChocolArm64
|
|
{
|
|
class ATranslatedSub
|
|
{
|
|
private delegate long AA64Subroutine(AThreadState Register, AMemory Memory);
|
|
|
|
private AA64Subroutine ExecDelegate;
|
|
|
|
public static int StateArgIdx { get; private set; }
|
|
public static int MemoryArgIdx { get; private set; }
|
|
|
|
public static Type[] FixedArgTypes { get; private set; }
|
|
|
|
public DynamicMethod Method { get; private set; }
|
|
|
|
public ReadOnlyCollection<ARegister> Params { get; private set; }
|
|
|
|
private HashSet<long> Callers;
|
|
|
|
private ATranslatedSubType Type;
|
|
|
|
private int CallCount;
|
|
|
|
private bool NeedsReJit;
|
|
|
|
private int MinCallCountForReJit = 250;
|
|
|
|
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params)
|
|
{
|
|
if (Method == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(Method));
|
|
}
|
|
|
|
if (Params == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(Params));
|
|
}
|
|
|
|
this.Method = Method;
|
|
this.Params = Params.AsReadOnly();
|
|
|
|
Callers = new HashSet<long>();
|
|
|
|
PrepareDelegate();
|
|
}
|
|
|
|
static ATranslatedSub()
|
|
{
|
|
MethodInfo MthdInfo = typeof(AA64Subroutine).GetMethod("Invoke");
|
|
|
|
ParameterInfo[] Params = MthdInfo.GetParameters();
|
|
|
|
FixedArgTypes = new Type[Params.Length];
|
|
|
|
for (int Index = 0; Index < Params.Length; Index++)
|
|
{
|
|
Type ParamType = Params[Index].ParameterType;
|
|
|
|
FixedArgTypes[Index] = ParamType;
|
|
|
|
if (ParamType == typeof(AThreadState))
|
|
{
|
|
StateArgIdx = Index;
|
|
}
|
|
else if (ParamType == typeof(AMemory))
|
|
{
|
|
MemoryArgIdx = Index;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void PrepareDelegate()
|
|
{
|
|
string Name = $"{Method.Name}_Dispatch";
|
|
|
|
DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes);
|
|
|
|
ILGenerator Generator = Mthd.GetILGenerator();
|
|
|
|
Generator.EmitLdargSeq(FixedArgTypes.Length);
|
|
|
|
foreach (ARegister Reg in Params)
|
|
{
|
|
Generator.EmitLdarg(StateArgIdx);
|
|
|
|
Generator.Emit(OpCodes.Ldfld, Reg.GetField());
|
|
}
|
|
|
|
Generator.Emit(OpCodes.Call, Method);
|
|
Generator.Emit(OpCodes.Ret);
|
|
|
|
ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine));
|
|
}
|
|
|
|
public bool ShouldReJit()
|
|
{
|
|
if (NeedsReJit && CallCount < MinCallCountForReJit)
|
|
{
|
|
CallCount++;
|
|
|
|
return false;
|
|
}
|
|
|
|
return NeedsReJit;
|
|
}
|
|
|
|
public long Execute(AThreadState ThreadState, AMemory Memory)
|
|
{
|
|
return ExecDelegate(ThreadState, Memory);
|
|
}
|
|
|
|
public void AddCaller(long Position)
|
|
{
|
|
lock (Callers)
|
|
{
|
|
Callers.Add(Position);
|
|
}
|
|
}
|
|
|
|
public long[] GetCallerPositions()
|
|
{
|
|
lock (Callers)
|
|
{
|
|
return Callers.ToArray();
|
|
}
|
|
}
|
|
|
|
public void SetType(ATranslatedSubType Type)
|
|
{
|
|
this.Type = Type;
|
|
|
|
if (Type == ATranslatedSubType.SubTier0)
|
|
{
|
|
NeedsReJit = true;
|
|
}
|
|
}
|
|
|
|
public void MarkForReJit() => NeedsReJit = true;
|
|
}
|
|
} |