aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/ATranslatedSub.cs
blob: 71a6793a2ae8bbb53b1e343da818ae26ca129a37 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
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;
    }
}