diff options
Diffstat (limited to 'ChocolArm64/TranslatedSub.cs')
| -rw-r--r-- | ChocolArm64/TranslatedSub.cs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/ChocolArm64/TranslatedSub.cs b/ChocolArm64/TranslatedSub.cs new file mode 100644 index 00000000..8b3ec3f0 --- /dev/null +++ b/ChocolArm64/TranslatedSub.cs @@ -0,0 +1,150 @@ +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 TranslatedSub + { + private delegate long Aa64Subroutine(CpuThreadState register, MemoryManager memory); + + private const int MinCallCountForReJit = 250; + + 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<Register> Params { get; private set; } + + private HashSet<long> _callers; + + private TranslatedSubType _type; + + private int _callCount; + + private bool _needsReJit; + + public TranslatedSub(DynamicMethod method, List<Register> Params) + { + if (method == null) + { + throw new ArgumentNullException(nameof(method)); + } + + if (Params == null) + { + throw new ArgumentNullException(nameof(Params)); + } + + Method = method; + this.Params = Params.AsReadOnly(); + + _callers = new HashSet<long>(); + + PrepareDelegate(); + } + + static TranslatedSub() + { + 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(CpuThreadState)) + { + StateArgIdx = index; + } + else if (paramType == typeof(MemoryManager)) + { + 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 (Register 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(CpuThreadState threadState, MemoryManager 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(TranslatedSubType type) + { + _type = type; + + if (type == TranslatedSubType.SubTier0) + { + _needsReJit = true; + } + } + + public void MarkForReJit() => _needsReJit = true; + } +}
\ No newline at end of file |
