rjx-mirror/ChocolArm64/ATranslatedSub.cs

150 lines
3.7 KiB
C#
Raw Normal View History

2018-02-04 23:08:20 +00:00
using ChocolArm64.Memory;
using ChocolArm64.State;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
2018-02-04 23:08:20 +00:00
using System.Reflection;
using System.Reflection.Emit;
namespace ChocolArm64
{
class ATranslatedSub
{
2018-02-18 19:28:07 +00:00
private delegate long AA64Subroutine(AThreadState Register, AMemory Memory);
2018-02-04 23:08:20 +00:00
private const int MinCallCountForReJit = 250;
2018-02-04 23:08:20 +00:00
private AA64Subroutine ExecDelegate;
2018-02-18 19:28:07 +00:00
public static int StateArgIdx { get; private set; }
public static int MemoryArgIdx { get; private set; }
2018-02-04 23:08:20 +00:00
public static Type[] FixedArgTypes { get; private set; }
2018-02-04 23:08:20 +00:00
public DynamicMethod Method { get; private set; }
public ReadOnlyCollection<ARegister> Params { get; private set; }
2018-02-04 23:08:20 +00:00
private HashSet<long> Callers;
2018-02-04 23:08:20 +00:00
private ATranslatedSubType Type;
2018-02-04 23:08:20 +00:00
private int CallCount;
private bool NeedsReJit;
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params)
2018-02-04 23:08:20 +00:00
{
if (Method == null)
{
throw new ArgumentNullException(nameof(Method));
}
2018-02-04 23:08:20 +00:00
if (Params == null)
{
throw new ArgumentNullException(nameof(Params));
}
this.Method = Method;
this.Params = Params.AsReadOnly();
Callers = new HashSet<long>();
PrepareDelegate();
2018-02-04 23:08:20 +00:00
}
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;
2018-02-18 19:28:07 +00:00
if (ParamType == typeof(AThreadState))
2018-02-04 23:08:20 +00:00
{
2018-02-18 19:28:07 +00:00
StateArgIdx = Index;
2018-02-04 23:08:20 +00:00
}
else if (ParamType == typeof(AMemory))
{
MemoryArgIdx = Index;
}
}
}
private void PrepareDelegate()
2018-02-04 23:08:20 +00:00
{
string Name = $"{Method.Name}_Dispatch";
2018-02-04 23:08:20 +00:00
DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes);
2018-02-04 23:08:20 +00:00
ILGenerator Generator = Mthd.GetILGenerator();
2018-02-04 23:08:20 +00:00
Generator.EmitLdargSeq(FixedArgTypes.Length);
2018-02-04 23:08:20 +00:00
foreach (ARegister Reg in Params)
{
Generator.EmitLdarg(StateArgIdx);
2018-02-04 23:08:20 +00:00
Generator.Emit(OpCodes.Ldfld, Reg.GetField());
}
2018-02-04 23:08:20 +00:00
Generator.Emit(OpCodes.Call, Method);
Generator.Emit(OpCodes.Ret);
2018-02-04 23:08:20 +00:00
ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine));
}
2018-02-04 23:08:20 +00:00
public bool ShouldReJit()
{
if (NeedsReJit && CallCount < MinCallCountForReJit)
{
CallCount++;
return false;
2018-02-04 23:08:20 +00:00
}
return NeedsReJit;
}
public long Execute(AThreadState ThreadState, AMemory Memory)
{
2018-02-18 19:28:07 +00:00
return ExecDelegate(ThreadState, Memory);
2018-02-04 23:08:20 +00:00
}
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;
2018-02-04 23:08:20 +00:00
}
}