diff options
Diffstat (limited to 'ChocolArm64/ATranslatedSub.cs')
| -rw-r--r-- | ChocolArm64/ATranslatedSub.cs | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/ChocolArm64/ATranslatedSub.cs b/ChocolArm64/ATranslatedSub.cs new file mode 100644 index 00000000..71a6793a --- /dev/null +++ b/ChocolArm64/ATranslatedSub.cs @@ -0,0 +1,104 @@ +using ChocolArm64.Memory; +using ChocolArm64.State; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; + +namespace ChocolArm64 +{ + class ATranslatedSub + { + private delegate long AA64Subroutine(AThreadState Register, AMemory Memory); + + private AA64Subroutine ExecDelegate; + + private bool HasDelegate; + + public static Type[] FixedArgTypes { get; private set; } + + public static int StateArgIdx { get; private set; } + public static int MemoryArgIdx { get; private set; } + + public DynamicMethod Method { get; private set; } + + public HashSet<long> SubCalls { get; private set; } + + public List<ARegister> Params { get; private set; } + + public bool NeedsReJit { get; private set; } + + public ATranslatedSub() + { + SubCalls = new HashSet<long>(); + } + + public ATranslatedSub(DynamicMethod Method, List<ARegister> Params) : this() + { + if (Params == null) + { + throw new ArgumentNullException(nameof(Params)); + } + + this.Method = Method; + this.Params = Params; + } + + 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; + } + } + } + + public long Execute(AThreadState ThreadState, AMemory Memory) + { + if (!HasDelegate) + { + 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)); + + HasDelegate = true; + } + + return ExecDelegate(ThreadState, Memory); + } + + public void MarkForReJit() => NeedsReJit = true; + } +}
\ No newline at end of file |
