Ryujinx/ChocolArm64/ATranslator.cs

106 lines
2.9 KiB
C#
Raw Normal View History

2018-02-04 23:08:20 +00:00
using ChocolArm64.Decoder;
using ChocolArm64.Instruction;
using ChocolArm64.Translation;
using System.Collections.Generic;
using System.Reflection.Emit;
namespace ChocolArm64
{
class ATranslator
2018-02-04 23:08:20 +00:00
{
public AThread Thread { get; private set; }
2018-02-18 04:57:33 +00:00
private Dictionary<long, ATranslatedSub> CachedSubs;
2018-02-04 23:08:20 +00:00
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)
{
2018-02-18 19:28:07 +00:00
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
2018-02-04 23:08:20 +00:00
}
else
{
2018-02-18 19:28:07 +00:00
Position = TranslateSubroutine(Position).Execute(Thread.ThreadState, Thread.Memory);
2018-02-04 23:08:20 +00:00
}
}
2018-02-18 19:28:07 +00:00
while (Position != 0 && KeepRunning);
2018-02-04 23:08:20 +00:00
}
public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
2018-02-04 23:08:20 +00:00
{
if (OpCode.Emitter != AInstEmit.Bl)
{
Sub = null;
return false;
}
return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
}
public bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
2018-02-04 23:08:20 +00:00
{
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;
}
}
}