e21ebbf666
* Add optimizations related to caller/callee saved registers, thread synchronization and disable tier 0 * Refactoring * Add a config entry to enable or disable the reg load/store opt. * Remove unnecessary register state stores for calls when the callee is know * Rename IoType to VarType * Enable tier 0 while fixing some perf issues related to tier 0 * Small tweak -- Compile before adding to the cache, to avoid lags * Add required config entry
104 lines
No EOL
2.9 KiB
C#
104 lines
No EOL
2.9 KiB
C#
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
|
|
{
|
|
//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.
|
|
private const int MinCallCountForOpt = 30;
|
|
|
|
public ArmSubroutine Delegate { get; private set; }
|
|
|
|
public static int StateArgIdx { get; }
|
|
public static int MemoryArgIdx { get; }
|
|
|
|
public static Type[] FixedArgTypes { get; }
|
|
|
|
public DynamicMethod Method { get; }
|
|
|
|
public TranslationTier Tier { get; }
|
|
|
|
public long IntNiRegsMask { get; }
|
|
public long VecNiRegsMask { get; }
|
|
|
|
private bool _isWorthOptimizing;
|
|
|
|
private int _callCount;
|
|
|
|
public TranslatedSub(
|
|
DynamicMethod method,
|
|
long intNiRegsMask,
|
|
long vecNiRegsMask,
|
|
TranslationTier tier,
|
|
bool isWorthOptimizing)
|
|
{
|
|
Method = method ?? throw new ArgumentNullException(nameof(method));;
|
|
IntNiRegsMask = intNiRegsMask;
|
|
VecNiRegsMask = vecNiRegsMask;
|
|
_isWorthOptimizing = isWorthOptimizing;
|
|
Tier = tier;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
public bool IsWorthOptimizing()
|
|
{
|
|
if (!_isWorthOptimizing)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_callCount++ < MinCallCountForOpt)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Only return true once, so that it is
|
|
//added to the queue only once.
|
|
_isWorthOptimizing = false;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
} |