2019-02-04 22:26:05 +01:00
|
|
|
using ChocolArm64.Memory;
|
|
|
|
using ChocolArm64.State;
|
|
|
|
using System;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Reflection.Emit;
|
|
|
|
|
|
|
|
namespace ChocolArm64.Translation
|
|
|
|
{
|
|
|
|
delegate long ArmSubroutine(CpuThreadState state, MemoryManager memory);
|
|
|
|
|
|
|
|
class TranslatedSub
|
|
|
|
{
|
2019-07-02 04:39:22 +02:00
|
|
|
// This is the minimum amount of calls needed for the method
|
|
|
|
// to be retranslated with higher quality code. It's only worth
|
|
|
|
// doing that for hot code.
|
2019-02-28 03:03:31 +01:00
|
|
|
private const int MinCallCountForOpt = 30;
|
|
|
|
|
2019-02-04 22:26:05 +01:00
|
|
|
public ArmSubroutine Delegate { get; private set; }
|
|
|
|
|
2019-02-28 03:03:31 +01:00
|
|
|
public static int StateArgIdx { get; }
|
|
|
|
public static int MemoryArgIdx { get; }
|
|
|
|
|
|
|
|
public static Type[] FixedArgTypes { get; }
|
|
|
|
|
|
|
|
public DynamicMethod Method { get; }
|
|
|
|
|
|
|
|
public TranslationTier Tier { get; }
|
2019-02-04 22:26:05 +01:00
|
|
|
|
2019-04-26 06:55:12 +02:00
|
|
|
private bool _rejit;
|
2019-02-04 22:26:05 +01:00
|
|
|
|
2019-02-28 03:03:31 +01:00
|
|
|
private int _callCount;
|
2019-02-04 22:26:05 +01:00
|
|
|
|
2019-04-26 06:55:12 +02:00
|
|
|
public TranslatedSub(DynamicMethod method, TranslationTier tier, bool rejit)
|
2019-02-04 22:26:05 +01:00
|
|
|
{
|
2019-07-02 04:39:22 +02:00
|
|
|
Method = method ?? throw new ArgumentNullException(nameof(method));
|
2019-04-26 06:55:12 +02:00
|
|
|
Tier = tier;
|
|
|
|
_rejit = rejit;
|
2019-02-04 22:26:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static TranslatedSub()
|
|
|
|
{
|
|
|
|
MethodInfo mthdInfo = typeof(ArmSubroutine).GetMethod("Invoke");
|
|
|
|
|
|
|
|
ParameterInfo[] Params = mthdInfo.GetParameters();
|
|
|
|
|
|
|
|
FixedArgTypes = new Type[Params.Length];
|
|
|
|
|
|
|
|
for (int index = 0; index < Params.Length; index++)
|
|
|
|
{
|
|
|
|
Type argType = Params[index].ParameterType;
|
|
|
|
|
|
|
|
FixedArgTypes[index] = argType;
|
|
|
|
|
|
|
|
if (argType == typeof(CpuThreadState))
|
|
|
|
{
|
|
|
|
StateArgIdx = index;
|
|
|
|
}
|
|
|
|
else if (argType == typeof(MemoryManager))
|
|
|
|
{
|
|
|
|
MemoryArgIdx = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void PrepareMethod()
|
|
|
|
{
|
|
|
|
Delegate = (ArmSubroutine)Method.CreateDelegate(typeof(ArmSubroutine));
|
|
|
|
}
|
|
|
|
|
|
|
|
public long Execute(CpuThreadState threadState, MemoryManager memory)
|
|
|
|
{
|
|
|
|
return Delegate(threadState, memory);
|
|
|
|
}
|
2019-02-28 03:03:31 +01:00
|
|
|
|
2019-04-26 06:55:12 +02:00
|
|
|
public bool Rejit()
|
2019-02-28 03:03:31 +01:00
|
|
|
{
|
2019-07-02 04:39:22 +02:00
|
|
|
if (!_rejit)
|
2019-02-28 03:03:31 +01:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_callCount++ < MinCallCountForOpt)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-07-02 04:39:22 +02:00
|
|
|
// Only return true once, so that it is added to the queue only once.
|
2019-04-26 06:55:12 +02:00
|
|
|
_rejit = false;
|
2019-02-28 03:03:31 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2019-02-04 22:26:05 +01:00
|
|
|
}
|
|
|
|
}
|