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
105
106
|
using ChocolArm64.Decoder;
using ChocolArm64.Instruction;
using ChocolArm64.Translation;
using System.Collections.Generic;
using System.Reflection.Emit;
namespace ChocolArm64
{
public class ATranslator
{
public AThread Thread { get; private set; }
private Dictionary<long, ATranslatedSub> CachedSubs;
private bool KeepRunning;
public ATranslator(AThread Parent)
{
this.Thread = Parent;
CachedSubs = new Dictionary<long, ATranslatedSub>();
KeepRunning = true;
}
public void StopExecution() => KeepRunning = false;
public void ExecuteSubroutine(long Position)
{
do
{
if (CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) && !Sub.NeedsReJit)
{
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
}
else
{
Position = TranslateSubroutine(Position).Execute(Thread.ThreadState, Thread.Memory);
}
}
while (Position != 0 && KeepRunning);
}
internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
{
if (OpCode.Emitter != AInstEmit.Bl)
{
Sub = null;
return false;
}
return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
}
internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
{
return CachedSubs.TryGetValue(Position, out Sub);
}
public bool HasCachedSub(long Position)
{
return CachedSubs.ContainsKey(Position);
}
private ATranslatedSub TranslateSubroutine(long Position)
{
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Position);
AILEmitterCtx Context = new AILEmitterCtx(
this,
Cfg.Graph,
Cfg.Root);
if (Context.CurrBlock.Position != Position)
{
Context.Emit(OpCodes.Br, Context.GetLabel(Position));
}
do
{
Context.EmitOpCode();
}
while (Context.AdvanceOpCode());
//Mark all methods that calls this method for ReJiting,
//since we can now call it directly which is faster.
foreach (ATranslatedSub TS in CachedSubs.Values)
{
if (TS.SubCalls.Contains(Position))
{
TS.MarkForReJit();
}
}
ATranslatedSub Subroutine = Context.GetSubroutine();
if (!CachedSubs.TryAdd(Position, Subroutine))
{
CachedSubs[Position] = Subroutine;
}
return Subroutine;
}
}
}
|