aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Translation
diff options
context:
space:
mode:
authorLDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com>2019-10-31 19:09:03 +0100
committerAc_K <Acoustik666@gmail.com>2019-10-31 19:09:03 +0100
commiteee639d6ba544fa5dd9352426d55e91bc54e157d (patch)
tree1df440ca57d8c1725e84f403fbeecddb8e508a3a /ChocolArm64/Translation
parent35443bac5a16ced668d84e0a22c21ca9076b3924 (diff)
.NET Core 3.0 is here! (#784)
* .NET Core 3.0 is here! * Remove IMemoryManager.cs and its references. * Add T Math/F.FusedMultiplyAdd(T, T, T). Nits. * Nit. * Update appveyor.yml * Revert "Resolve Visual Studio build issues" This reverts commit 1772128ce0fc058e6280001aace3a77a7a96897b. * Update SvcTable.cs
Diffstat (limited to 'ChocolArm64/Translation')
-rw-r--r--ChocolArm64/Translation/CallType.cs9
-rw-r--r--ChocolArm64/Translation/ILEmitterCtx.cs709
-rw-r--r--ChocolArm64/Translation/ILGeneratorEx.cs121
-rw-r--r--ChocolArm64/Translation/RegisterUsage.cs176
-rw-r--r--ChocolArm64/Translation/TranslatedSub.cs93
-rw-r--r--ChocolArm64/Translation/TranslatedSubBuilder.cs274
-rw-r--r--ChocolArm64/Translation/TranslationTier.cs11
-rw-r--r--ChocolArm64/Translation/Translator.cs252
-rw-r--r--ChocolArm64/Translation/TranslatorCache.cs196
-rw-r--r--ChocolArm64/Translation/TranslatorQueue.cs77
-rw-r--r--ChocolArm64/Translation/TranslatorQueueItem.cs27
11 files changed, 0 insertions, 1945 deletions
diff --git a/ChocolArm64/Translation/CallType.cs b/ChocolArm64/Translation/CallType.cs
deleted file mode 100644
index 937ede76..00000000
--- a/ChocolArm64/Translation/CallType.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace ChocolArm64.Translation
-{
- enum CallType
- {
- Call,
- VirtualCall,
- VirtualJump
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs
deleted file mode 100644
index 0deb29b2..00000000
--- a/ChocolArm64/Translation/ILEmitterCtx.cs
+++ /dev/null
@@ -1,709 +0,0 @@
-using ChocolArm64.Decoders;
-using ChocolArm64.Instructions;
-using ChocolArm64.IntermediateRepresentation;
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace ChocolArm64.Translation
-{
- class ILEmitterCtx
- {
- public MemoryManager Memory { get; }
-
- private TranslatorCache _cache;
- private TranslatorQueue _queue;
-
- private Block _currBlock;
-
- public Block CurrBlock
- {
- get
- {
- return _currBlock;
- }
- set
- {
- _currBlock = value;
-
- ResetBlockState();
- }
- }
-
- public OpCode64 CurrOp { get; set; }
-
- public TranslationTier Tier { get; }
-
- public Aarch32Mode Mode { get; } = Aarch32Mode.User; //TODO
-
- public bool HasIndirectJump { get; set; }
-
- public bool HasSlowCall { get; set; }
-
- private Dictionary<long, ILLabel> _labels;
-
- private Dictionary<ILLabel, BasicBlock> _irLabels;
-
- private List<BasicBlock> _irBlocks;
-
- private BasicBlock _irBlock;
-
- private bool _needsNewBlock;
-
- private OpCode64 _optOpLastCompare;
- private OpCode64 _optOpLastFlagSet;
-
- // This is the index of the temporary register, used to store temporary
- // values needed by some functions, since IL doesn't have a swap instruction.
- // You can use any value here as long it doesn't conflict with the indices
- // for the other registers. Any value >= 64 or < 0 will do.
- private const int ReservedLocalsCount = 64;
-
- private const int RorTmpIndex = ReservedLocalsCount + 0;
- private const int CmpOptTmp1Index = ReservedLocalsCount + 1;
- private const int CmpOptTmp2Index = ReservedLocalsCount + 2;
- private const int IntGpTmp1Index = ReservedLocalsCount + 3;
- private const int IntGpTmp2Index = ReservedLocalsCount + 4;
- private const int UserIntTempStart = ReservedLocalsCount + 5;
-
- // Vectors are part of another "set" of locals.
- private const int VecGpTmp1Index = ReservedLocalsCount + 0;
- private const int VecGpTmp2Index = ReservedLocalsCount + 1;
- private const int VecGpTmp3Index = ReservedLocalsCount + 2;
- private const int UserVecTempStart = ReservedLocalsCount + 3;
-
- private static int _userIntTempCount;
- private static int _userVecTempCount;
-
- public ILEmitterCtx(
- MemoryManager memory,
- TranslatorCache cache,
- TranslatorQueue queue,
- TranslationTier tier)
- {
- Memory = memory ?? throw new ArgumentNullException(nameof(memory));
- _cache = cache ?? throw new ArgumentNullException(nameof(cache));
- _queue = queue ?? throw new ArgumentNullException(nameof(queue));
-
- Tier = tier;
-
- _labels = new Dictionary<long, ILLabel>();
-
- _irLabels = new Dictionary<ILLabel, BasicBlock>();
-
- _irBlocks = new List<BasicBlock>();
-
- NewNextBlock();
-
- EmitSynchronization();
-
- EmitLoadContext();
- }
-
- public static int GetIntTempIndex()
- {
- return UserIntTempStart + _userIntTempCount++;
- }
-
- public static int GetVecTempIndex()
- {
- return UserVecTempStart + _userVecTempCount++;
- }
-
- public BasicBlock[] GetBlocks()
- {
- return _irBlocks.ToArray();
- }
-
- public void EmitSynchronization()
- {
- EmitLdarg(TranslatedSub.StateArgIdx);
-
- EmitPrivateCall(typeof(CpuThreadState), nameof(CpuThreadState.Synchronize));
-
- EmitLdc_I4(0);
-
- ILLabel lblContinue = new ILLabel();
-
- Emit(OpCodes.Bne_Un_S, lblContinue);
-
- EmitLdc_I8(0);
-
- Emit(OpCodes.Ret);
-
- MarkLabel(lblContinue);
- }
-
- public void ResetBlockStateForPredicatedOp()
- {
- // Check if this is a predicated instruction that modifies flags,
- // in this case the value of the flags is unknown as we don't know
- // in advance if the instruction is going to be executed or not.
- // So, we reset the block state to prevent an invalid optimization.
- if (CurrOp == _optOpLastFlagSet)
- {
- ResetBlockState();
- }
- }
-
- private void ResetBlockState()
- {
- _optOpLastFlagSet = null;
- _optOpLastCompare = null;
- }
-
- public void TranslateAhead(long position, ExecutionMode mode = ExecutionMode.Aarch64)
- {
- if (_cache.TryGetSubroutine(position, out TranslatedSub sub) && sub.Tier != TranslationTier.Tier0)
- {
- return;
- }
-
- _queue.Enqueue(position, mode, TranslationTier.Tier1, isComplete: true);
- }
-
- public bool TryOptEmitSubroutineCall()
- {
- // Calls should always have a next block, unless
- // we're translating a single basic block.
- if (_currBlock.Next == null)
- {
- return false;
- }
-
- if (!(CurrOp is IOpCodeBImm op))
- {
- return false;
- }
-
- if (!_cache.TryGetSubroutine(op.Imm, out TranslatedSub sub) || sub.Tier != TranslationTier.Tier0)
- {
- return false;
- }
-
- EmitStoreContext();
-
- for (int index = 0; index < TranslatedSub.FixedArgTypes.Length; index++)
- {
- EmitLdarg(index);
- }
-
- EmitCall(sub.Method);
-
- return true;
- }
-
- public void TryOptMarkCondWithoutCmp()
- {
- _optOpLastCompare = CurrOp;
-
- InstEmitAluHelper.EmitAluLoadOpers(this);
-
- Stloc(CmpOptTmp2Index, RegisterType.Int);
- Stloc(CmpOptTmp1Index, RegisterType.Int);
- }
-
- private Dictionary<Condition, OpCode> _branchOps = new Dictionary<Condition, OpCode>()
- {
- { Condition.Eq, OpCodes.Beq },
- { Condition.Ne, OpCodes.Bne_Un },
- { Condition.GeUn, OpCodes.Bge_Un },
- { Condition.LtUn, OpCodes.Blt_Un },
- { Condition.GtUn, OpCodes.Bgt_Un },
- { Condition.LeUn, OpCodes.Ble_Un },
- { Condition.Ge, OpCodes.Bge },
- { Condition.Lt, OpCodes.Blt },
- { Condition.Gt, OpCodes.Bgt },
- { Condition.Le, OpCodes.Ble }
- };
-
- public void EmitCondBranch(ILLabel target, Condition cond)
- {
- if (_optOpLastCompare != null &&
- _optOpLastCompare == _optOpLastFlagSet && _branchOps.ContainsKey(cond))
- {
- if (_optOpLastCompare.Emitter == InstEmit.Subs)
- {
- Ldloc(CmpOptTmp1Index, RegisterType.Int, _optOpLastCompare.RegisterSize);
- Ldloc(CmpOptTmp2Index, RegisterType.Int, _optOpLastCompare.RegisterSize);
-
- Emit(_branchOps[cond], target);
-
- return;
- }
- else if (_optOpLastCompare.Emitter == InstEmit.Adds && cond != Condition.GeUn
- && cond != Condition.LtUn
- && cond != Condition.GtUn
- && cond != Condition.LeUn)
- {
- // There are several limitations that needs to be taken into account for CMN comparisons:
- // - The unsigned comparisons are not valid, as they depend on the
- // carry flag value, and they will have different values for addition and
- // subtraction. For addition, it's carry, and for subtraction, it's borrow.
- // So, we need to make sure we're not doing a unsigned compare for the CMN case.
- // - We can only do the optimization for the immediate variants,
- // because when the second operand value is exactly INT_MIN, we can't
- // negate the value as theres no positive counterpart.
- // Such invalid values can't be encoded on the immediate encodings.
- if (_optOpLastCompare is IOpCodeAluImm64 op)
- {
- Ldloc(CmpOptTmp1Index, RegisterType.Int, _optOpLastCompare.RegisterSize);
-
- if (_optOpLastCompare.RegisterSize == RegisterSize.Int32)
- {
- EmitLdc_I4((int)-op.Imm);
- }
- else
- {
- EmitLdc_I8(-op.Imm);
- }
-
- Emit(_branchOps[cond], target);
-
- return;
- }
- }
- }
-
- OpCode ilOp;
-
- int intCond = (int)cond;
-
- if (intCond < 14)
- {
- int condTrue = intCond >> 1;
-
- switch (condTrue)
- {
- case 0: EmitLdflg((int)PState.ZBit); break;
- case 1: EmitLdflg((int)PState.CBit); break;
- case 2: EmitLdflg((int)PState.NBit); break;
- case 3: EmitLdflg((int)PState.VBit); break;
-
- case 4:
- EmitLdflg((int)PState.CBit);
- EmitLdflg((int)PState.ZBit);
-
- Emit(OpCodes.Not);
- Emit(OpCodes.And);
- break;
-
- case 5:
- case 6:
- EmitLdflg((int)PState.NBit);
- EmitLdflg((int)PState.VBit);
-
- Emit(OpCodes.Ceq);
-
- if (condTrue == 6)
- {
- EmitLdflg((int)PState.ZBit);
-
- Emit(OpCodes.Not);
- Emit(OpCodes.And);
- }
- break;
- }
-
- ilOp = (intCond & 1) != 0 ? OpCodes.Brfalse : OpCodes.Brtrue;
- }
- else
- {
- ilOp = OpCodes.Br;
- }
-
- Emit(ilOp, target);
- }
-
- public void EmitCast(IntType intType)
- {
- switch (intType)
- {
- case IntType.UInt8: Emit(OpCodes.Conv_U1); break;
- case IntType.UInt16: Emit(OpCodes.Conv_U2); break;
- case IntType.UInt32: Emit(OpCodes.Conv_U4); break;
- case IntType.UInt64: Emit(OpCodes.Conv_U8); break;
- case IntType.Int8: Emit(OpCodes.Conv_I1); break;
- case IntType.Int16: Emit(OpCodes.Conv_I2); break;
- case IntType.Int32: Emit(OpCodes.Conv_I4); break;
- case IntType.Int64: Emit(OpCodes.Conv_I8); break;
- }
-
- bool sz64 = CurrOp.RegisterSize != RegisterSize.Int32;
-
- if (sz64 == (intType == IntType.UInt64 || intType == IntType.Int64))
- {
- return;
- }
-
- if (sz64)
- {
- Emit(intType >= IntType.Int8 ? OpCodes.Conv_I8 : OpCodes.Conv_U8);
- }
- else
- {
- Emit(OpCodes.Conv_U4);
- }
- }
-
- public void EmitLsl(int amount) => EmitILShift(amount, OpCodes.Shl);
- public void EmitLsr(int amount) => EmitILShift(amount, OpCodes.Shr_Un);
- public void EmitAsr(int amount) => EmitILShift(amount, OpCodes.Shr);
-
- private void EmitILShift(int amount, OpCode ilOp)
- {
- if (amount > 0)
- {
- EmitLdc_I4(amount);
-
- Emit(ilOp);
- }
- }
-
- public void EmitRor(int amount)
- {
- if (amount > 0)
- {
- Stloc(RorTmpIndex, RegisterType.Int);
- Ldloc(RorTmpIndex, RegisterType.Int);
-
- EmitLdc_I4(amount);
-
- Emit(OpCodes.Shr_Un);
-
- Ldloc(RorTmpIndex, RegisterType.Int);
-
- EmitLdc_I4(CurrOp.GetBitsCount() - amount);
-
- Emit(OpCodes.Shl);
- Emit(OpCodes.Or);
- }
- }
-
- public ILLabel GetLabel(long position)
- {
- if (!_labels.TryGetValue(position, out ILLabel output))
- {
- output = new ILLabel();
-
- _labels.Add(position, output);
- }
-
- return output;
- }
-
- public void MarkLabel(ILLabel label)
- {
- if (_irLabels.TryGetValue(label, out BasicBlock nextBlock))
- {
- nextBlock.Index = _irBlocks.Count;
-
- _irBlocks.Add(nextBlock);
-
- NextBlock(nextBlock);
- }
- else
- {
- NewNextBlock();
-
- _irLabels.Add(label, _irBlock);
- }
-
- AddOperation(Operation.MarkLabel(label));
- }
-
- public void Emit(OpCode ilOp)
- {
- AddOperation(Operation.IL(ilOp));
-
- if (ilOp == OpCodes.Ret)
- {
- NextBlock(null);
-
- _needsNewBlock = true;
- }
- }
-
- public void Emit(OpCode ilOp, ILLabel label)
- {
- AddOperation(Operation.ILBranch(ilOp, label));
-
- _needsNewBlock = true;
-
- if (!_irLabels.TryGetValue(label, out BasicBlock branchBlock))
- {
- branchBlock = new BasicBlock();
-
- _irLabels.Add(label, branchBlock);
- }
-
- _irBlock.Branch = branchBlock;
- }
-
- public void EmitLdfld(FieldInfo info)
- {
- AddOperation(Operation.LoadField(info));
- }
-
- public void EmitLdarg(int index)
- {
- AddOperation(Operation.LoadArgument(index));
- }
-
- public void EmitLdintzr(int index)
- {
- if (index != RegisterAlias.Zr)
- {
- EmitLdint(index);
- }
- else
- {
- EmitLdc_I(0);
- }
- }
-
- public void EmitStintzr(int index)
- {
- if (index != RegisterAlias.Zr)
- {
- EmitStint(index);
- }
- else
- {
- Emit(OpCodes.Pop);
- }
- }
-
- public void EmitLoadContext()
- {
- _needsNewBlock = true;
-
- AddOperation(Operation.LoadContext());
- }
-
- public void EmitStoreContext()
- {
- AddOperation(Operation.StoreContext());
- }
-
- public void EmitLdtmp() => EmitLdint(IntGpTmp1Index);
- public void EmitSttmp() => EmitStint(IntGpTmp1Index);
-
- public void EmitLdtmp2() => EmitLdint(IntGpTmp2Index);
- public void EmitSttmp2() => EmitStint(IntGpTmp2Index);
-
- public void EmitLdvectmp() => EmitLdvec(VecGpTmp1Index);
- public void EmitStvectmp() => EmitStvec(VecGpTmp1Index);
-
- public void EmitLdvectmp2() => EmitLdvec(VecGpTmp2Index);
- public void EmitStvectmp2() => EmitStvec(VecGpTmp2Index);
-
- public void EmitLdvectmp3() => EmitLdvec(VecGpTmp3Index);
- public void EmitStvectmp3() => EmitStvec(VecGpTmp3Index);
-
- public void EmitLdint(int index) => Ldloc(index, RegisterType.Int);
- public void EmitStint(int index) => Stloc(index, RegisterType.Int);
-
- public void EmitLdvec(int index) => Ldloc(index, RegisterType.Vector);
- public void EmitStvec(int index) => Stloc(index, RegisterType.Vector);
-
- public void EmitLdflg(int index) => Ldloc(index, RegisterType.Flag);
- public void EmitStflg(int index)
- {
- // Set this only if any of the NZCV flag bits were modified.
- // This is used to ensure that when emiting a direct IL branch
- // instruction for compare + branch sequences, we're not expecting
- // to use comparison values from an old instruction, when in fact
- // the flags were already overwritten by another instruction further along.
- if (index >= (int)PState.VBit)
- {
- _optOpLastFlagSet = CurrOp;
- }
-
- Stloc(index, RegisterType.Flag);
- }
-
- private void Ldloc(int index, RegisterType type)
- {
- AddOperation(Operation.LoadLocal(index, type, CurrOp.RegisterSize));
- }
-
- private void Ldloc(int index, RegisterType type, RegisterSize size)
- {
- AddOperation(Operation.LoadLocal(index, type, size));
- }
-
- private void Stloc(int index, RegisterType type)
- {
- AddOperation(Operation.StoreLocal(index, type, CurrOp.RegisterSize));
- }
-
- public void EmitCallPropGet(Type objType, string propName)
- {
- EmitCall(objType, $"get_{propName}");
- }
-
- public void EmitCallPropSet(Type objType, string propName)
- {
- EmitCall(objType, $"set_{propName}");
- }
-
- public void EmitCall(Type objType, string mthdName)
- {
- if (objType == null)
- {
- throw new ArgumentNullException(nameof(objType));
- }
-
- if (mthdName == null)
- {
- throw new ArgumentNullException(nameof(mthdName));
- }
-
- EmitCall(objType.GetMethod(mthdName));
- }
-
- public void EmitCallPrivatePropGet(Type objType, string propName)
- {
- EmitPrivateCall(objType, $"get_{propName}");
- }
-
- public void EmitCallPrivatePropSet(Type objType, string propName)
- {
- EmitPrivateCall(objType, $"set_{propName}");
- }
-
- public void EmitPrivateCall(Type objType, string mthdName)
- {
- if (objType == null)
- {
- throw new ArgumentNullException(nameof(objType));
- }
-
- if (mthdName == null)
- {
- throw new ArgumentNullException(nameof(mthdName));
- }
-
- EmitCall(objType.GetMethod(mthdName, BindingFlags.Instance | BindingFlags.NonPublic));
- }
-
- public void EmitCall(MethodInfo mthdInfo, bool isVirtual = false)
- {
- if (mthdInfo == null)
- {
- throw new ArgumentNullException(nameof(mthdInfo));
- }
-
- if (isVirtual)
- {
- AddOperation(Operation.CallVirtual(mthdInfo));
- }
- else
- {
- AddOperation(Operation.Call(mthdInfo));
- }
- }
-
- public void EmitLdc_I(long value)
- {
- if (CurrOp.RegisterSize == RegisterSize.Int32)
- {
- EmitLdc_I4((int)value);
- }
- else
- {
- EmitLdc_I8(value);
- }
- }
-
- public void EmitLdc_I4(int value)
- {
- AddOperation(Operation.LoadConstant(value));
- }
-
- public void EmitLdc_I8(long value)
- {
- AddOperation(Operation.LoadConstant(value));
- }
-
- public void EmitLdc_R4(float value)
- {
- AddOperation(Operation.LoadConstant(value));
- }
-
- public void EmitLdc_R8(double value)
- {
- AddOperation(Operation.LoadConstant(value));
- }
-
- public void EmitZnFlagCheck()
- {
- EmitZnCheck(OpCodes.Ceq, (int)PState.ZBit);
- EmitZnCheck(OpCodes.Clt, (int)PState.NBit);
- }
-
- private void EmitZnCheck(OpCode ilCmpOp, int flag)
- {
- Emit(OpCodes.Dup);
- Emit(OpCodes.Ldc_I4_0);
-
- if (CurrOp.RegisterSize != RegisterSize.Int32)
- {
- Emit(OpCodes.Conv_I8);
- }
-
- Emit(ilCmpOp);
-
- EmitStflg(flag);
- }
-
- private void AddOperation(Operation operation)
- {
- if (_needsNewBlock)
- {
- NewNextBlock();
- }
-
- _irBlock.Add(operation);
- }
-
- private void NewNextBlock()
- {
- BasicBlock block = new BasicBlock(_irBlocks.Count);
-
- _irBlocks.Add(block);
-
- NextBlock(block);
- }
-
- private void NextBlock(BasicBlock nextBlock)
- {
- if (_irBlock != null && !EndsWithUnconditional(_irBlock))
- {
- _irBlock.Next = nextBlock;
- }
-
- _irBlock = nextBlock;
-
- _needsNewBlock = false;
- }
-
- private static bool EndsWithUnconditional(BasicBlock block)
- {
- Operation lastOp = block.GetLastOp();
-
- if (lastOp == null || lastOp.Type != OperationType.ILBranch)
- {
- return false;
- }
-
- OpCode opCode = lastOp.GetArg<OpCode>(0);
-
- return opCode == OpCodes.Br || opCode == OpCodes.Br_S;
- }
- }
-}
diff --git a/ChocolArm64/Translation/ILGeneratorEx.cs b/ChocolArm64/Translation/ILGeneratorEx.cs
deleted file mode 100644
index 6b1512d2..00000000
--- a/ChocolArm64/Translation/ILGeneratorEx.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using System;
-
-namespace ChocolArm64
-{
- using System.Reflection.Emit;
-
- static class ILGeneratorEx
- {
- public static void EmitLdc_I4(this ILGenerator generator, int value)
- {
- switch (value)
- {
- case 0: generator.Emit(OpCodes.Ldc_I4_0); break;
- case 1: generator.Emit(OpCodes.Ldc_I4_1); break;
- case 2: generator.Emit(OpCodes.Ldc_I4_2); break;
- case 3: generator.Emit(OpCodes.Ldc_I4_3); break;
- case 4: generator.Emit(OpCodes.Ldc_I4_4); break;
- case 5: generator.Emit(OpCodes.Ldc_I4_5); break;
- case 6: generator.Emit(OpCodes.Ldc_I4_6); break;
- case 7: generator.Emit(OpCodes.Ldc_I4_7); break;
- case 8: generator.Emit(OpCodes.Ldc_I4_8); break;
- case -1: generator.Emit(OpCodes.Ldc_I4_M1); break;
- default: generator.Emit(OpCodes.Ldc_I4, value); break;
- }
- }
-
- public static void EmitLdarg(this ILGenerator generator, int index)
- {
- switch (index)
- {
- case 0: generator.Emit(OpCodes.Ldarg_0); break;
- case 1: generator.Emit(OpCodes.Ldarg_1); break;
- case 2: generator.Emit(OpCodes.Ldarg_2); break;
- case 3: generator.Emit(OpCodes.Ldarg_3); break;
-
- default:
- if ((uint)index <= byte.MaxValue)
- {
- generator.Emit(OpCodes.Ldarg_S, (byte)index);
- }
- else if ((uint)index < ushort.MaxValue)
- {
- generator.Emit(OpCodes.Ldarg, (short)index);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- break;
- }
- }
-
- public static void EmitStarg(this ILGenerator generator, int index)
- {
- if ((uint)index <= byte.MaxValue)
- {
- generator.Emit(OpCodes.Starg_S, (byte)index);
- }
- else if ((uint)index < ushort.MaxValue)
- {
- generator.Emit(OpCodes.Starg, (short)index);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- public static void EmitLdloc(this ILGenerator generator, int index)
- {
- switch (index)
- {
- case 0: generator.Emit(OpCodes.Ldloc_0); break;
- case 1: generator.Emit(OpCodes.Ldloc_1); break;
- case 2: generator.Emit(OpCodes.Ldloc_2); break;
- case 3: generator.Emit(OpCodes.Ldloc_3); break;
-
- default:
- if ((uint)index <= byte.MaxValue)
- {
- generator.Emit(OpCodes.Ldloc_S, (byte)index);
- }
- else if ((uint)index < ushort.MaxValue)
- {
- generator.Emit(OpCodes.Ldloc, (short)index);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- break;
- }
- }
-
- public static void EmitStloc(this ILGenerator generator, int index)
- {
- switch (index)
- {
- case 0: generator.Emit(OpCodes.Stloc_0); break;
- case 1: generator.Emit(OpCodes.Stloc_1); break;
- case 2: generator.Emit(OpCodes.Stloc_2); break;
- case 3: generator.Emit(OpCodes.Stloc_3); break;
-
- default:
- if ((uint)index <= byte.MaxValue)
- {
- generator.Emit(OpCodes.Stloc_S, (byte)index);
- }
- else if ((uint)index < ushort.MaxValue)
- {
- generator.Emit(OpCodes.Stloc, (short)index);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- break;
- }
- }
- }
-}
diff --git a/ChocolArm64/Translation/RegisterUsage.cs b/ChocolArm64/Translation/RegisterUsage.cs
deleted file mode 100644
index f88fa0cd..00000000
--- a/ChocolArm64/Translation/RegisterUsage.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-using ChocolArm64.IntermediateRepresentation;
-using ChocolArm64.State;
-using System.Collections.Generic;
-
-namespace ChocolArm64.Translation
-{
- class RegisterUsage
- {
- private const long CallerSavedIntRegistersMask = 0x7fL << 9;
- private const long PStateNzcvFlagsMask = 0xfL << 60;
-
- private const long CallerSavedVecRegistersMask = 0xffffL << 16;
-
- private RegisterMask[] _inputs;
- private RegisterMask[] _outputs;
-
- public RegisterUsage(BasicBlock entryBlock, int blocksCount)
- {
- _inputs = new RegisterMask[blocksCount];
- _outputs = new RegisterMask[blocksCount];
-
- HashSet<BasicBlock> visited = new HashSet<BasicBlock>();
-
- Stack<BasicBlock> blockStack = new Stack<BasicBlock>();
-
- List<BasicBlock> postOrderBlocks = new List<BasicBlock>(blocksCount);
-
- visited.Add(entryBlock);
-
- blockStack.Push(entryBlock);
-
- while (blockStack.TryPop(out BasicBlock block))
- {
- if (block.Next != null && visited.Add(block.Next))
- {
- blockStack.Push(block);
- blockStack.Push(block.Next);
- }
- else if (block.Branch != null && visited.Add(block.Branch))
- {
- blockStack.Push(block);
- blockStack.Push(block.Branch);
- }
- else
- {
- postOrderBlocks.Add(block);
- }
- }
-
- RegisterMask[] cmnOutputMasks = new RegisterMask[blocksCount];
-
- bool modified;
-
- bool firstPass = true;
-
- do
- {
- modified = false;
-
- for (int blkIndex = postOrderBlocks.Count - 1; blkIndex >= 0; blkIndex--)
- {
- BasicBlock block = postOrderBlocks[blkIndex];
-
- if (block.Predecessors.Count != 0 && !block.HasStateLoad)
- {
- BasicBlock predecessor = block.Predecessors[0];
-
- RegisterMask cmnOutputs = predecessor.RegOutputs | cmnOutputMasks[predecessor.Index];
-
- RegisterMask outputs = _outputs[predecessor.Index];
-
- for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
- {
- predecessor = block.Predecessors[pIndex];
-
- cmnOutputs &= predecessor.RegOutputs | cmnOutputMasks[predecessor.Index];
-
- outputs |= _outputs[predecessor.Index];
- }
-
- _inputs[block.Index] |= outputs & ~cmnOutputs;
-
- if (!firstPass)
- {
- cmnOutputs &= cmnOutputMasks[block.Index];
- }
-
- if (Exchange(cmnOutputMasks, block.Index, cmnOutputs))
- {
- modified = true;
- }
-
- outputs |= block.RegOutputs;
-
- if (Exchange(_outputs, block.Index, _outputs[block.Index] | outputs))
- {
- modified = true;
- }
- }
- else if (Exchange(_outputs, block.Index, block.RegOutputs))
- {
- modified = true;
- }
- }
-
- firstPass = false;
- }
- while (modified);
-
- do
- {
- modified = false;
-
- for (int blkIndex = 0; blkIndex < postOrderBlocks.Count; blkIndex++)
- {
- BasicBlock block = postOrderBlocks[blkIndex];
-
- RegisterMask inputs = block.RegInputs;
-
- if (block.Next != null)
- {
- inputs |= _inputs[block.Next.Index];
- }
-
- if (block.Branch != null)
- {
- inputs |= _inputs[block.Branch.Index];
- }
-
- inputs &= ~cmnOutputMasks[block.Index];
-
- if (Exchange(_inputs, block.Index, _inputs[block.Index] | inputs))
- {
- modified = true;
- }
- }
- }
- while (modified);
- }
-
- private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value)
- {
- RegisterMask oldValue = masks[blkIndex];
-
- masks[blkIndex] = value;
-
- return oldValue != value;
- }
-
- public RegisterMask GetInputs(BasicBlock entryBlock) => _inputs[entryBlock.Index];
-
- public RegisterMask GetOutputs(BasicBlock block) => _outputs[block.Index];
-
- public static long ClearCallerSavedIntRegs(long mask, ExecutionMode mode)
- {
- // TODO: ARM32 support.
- if (mode == ExecutionMode.Aarch64)
- {
- mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask);
- }
-
- return mask;
- }
-
- public static long ClearCallerSavedVecRegs(long mask, ExecutionMode mode)
- {
- // TODO: ARM32 support.
- if (mode == ExecutionMode.Aarch64)
- {
- mask &= ~CallerSavedVecRegistersMask;
- }
-
- return mask;
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/TranslatedSub.cs b/ChocolArm64/Translation/TranslatedSub.cs
deleted file mode 100644
index cf42e202..00000000
--- a/ChocolArm64/Translation/TranslatedSub.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using System;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace ChocolArm64.Translation
-{
- delegate long ArmSubroutine(CpuThreadState state, MemoryManager memory);
-
- class TranslatedSub
- {
- // This is the minimum amount of calls needed for the method
- // to be retranslated with higher quality code. It's only worth
- // doing that for hot code.
- private const int MinCallCountForOpt = 30;
-
- public ArmSubroutine Delegate { get; private set; }
-
- public static int StateArgIdx { get; }
- public static int MemoryArgIdx { get; }
-
- public static Type[] FixedArgTypes { get; }
-
- public DynamicMethod Method { get; }
-
- public TranslationTier Tier { get; }
-
- private bool _rejit;
-
- private int _callCount;
-
- public TranslatedSub(DynamicMethod method, TranslationTier tier, bool rejit)
- {
- Method = method ?? throw new ArgumentNullException(nameof(method));
- Tier = tier;
- _rejit = rejit;
- }
-
- static TranslatedSub()
- {
- MethodInfo mthdInfo = typeof(ArmSubroutine).GetMethod("Invoke");
-
- ParameterInfo[] Params = mthdInfo.GetParameters();
-
- FixedArgTypes = new Type[Params.Length];
-
- for (int index = 0; index < Params.Length; index++)
- {
- Type argType = Params[index].ParameterType;
-
- FixedArgTypes[index] = argType;
-
- if (argType == typeof(CpuThreadState))
- {
- StateArgIdx = index;
- }
- else if (argType == typeof(MemoryManager))
- {
- MemoryArgIdx = index;
- }
- }
- }
-
- public void PrepareMethod()
- {
- Delegate = (ArmSubroutine)Method.CreateDelegate(typeof(ArmSubroutine));
- }
-
- public long Execute(CpuThreadState threadState, MemoryManager memory)
- {
- return Delegate(threadState, memory);
- }
-
- public bool Rejit()
- {
- if (!_rejit)
- {
- return false;
- }
-
- if (_callCount++ < MinCallCountForOpt)
- {
- return false;
- }
-
- // Only return true once, so that it is added to the queue only once.
- _rejit = false;
-
- return true;
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/TranslatedSubBuilder.cs b/ChocolArm64/Translation/TranslatedSubBuilder.cs
deleted file mode 100644
index eb69d9ee..00000000
--- a/ChocolArm64/Translation/TranslatedSubBuilder.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-using ChocolArm64.IntermediateRepresentation;
-using ChocolArm64.State;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.Intrinsics;
-
-using static ChocolArm64.State.RegisterConsts;
-
-namespace ChocolArm64.Translation
-{
- class TranslatedSubBuilder
- {
- private ExecutionMode _mode;
-
- private bool _isComplete;
-
- private Dictionary<Register, int> _locals;
-
- private RegisterUsage _regUsage;
-
- public TranslatedSubBuilder(ExecutionMode mode, bool isComplete = false)
- {
- _mode = mode;
- _isComplete = isComplete;
- }
-
- public TranslatedSub Build(BasicBlock[] blocks, string name, TranslationTier tier, bool rejit = true)
- {
- _regUsage = new RegisterUsage(blocks[0], blocks.Length);
-
- DynamicMethod method = new DynamicMethod(name, typeof(long), TranslatedSub.FixedArgTypes);
-
- TranslatedSub subroutine = new TranslatedSub(method, tier, rejit);
-
- _locals = new Dictionary<Register, int>();
-
- Dictionary<ILLabel, Label> labels = new Dictionary<ILLabel, Label>();
-
- ILGenerator generator = method.GetILGenerator();
-
- Label GetLabel(ILLabel label)
- {
- if (!labels.TryGetValue(label, out Label ilLabel))
- {
- ilLabel = generator.DefineLabel();
-
- labels.Add(label, ilLabel);
- }
-
- return ilLabel;
- }
-
- foreach (BasicBlock block in blocks)
- {
- for (int index = 0; index < block.Count; index++)
- {
- Operation operation = block.GetOperation(index);
-
- switch (operation.Type)
- {
- case OperationType.Call:
- generator.Emit(OpCodes.Call, operation.GetArg<MethodInfo>(0));
- break;
-
- case OperationType.CallVirtual:
- generator.Emit(OpCodes.Callvirt, operation.GetArg<MethodInfo>(0));
- break;
-
- case OperationType.IL:
- generator.Emit(operation.GetArg<OpCode>(0));
- break;
-
- case OperationType.ILBranch:
- generator.Emit(operation.GetArg<OpCode>(0), GetLabel(operation.GetArg<ILLabel>(1)));
- break;
-
- case OperationType.LoadArgument:
- generator.EmitLdarg(operation.GetArg<int>(0));
- break;
-
- case OperationType.LoadConstant:
- EmitLoadConstant(generator, operation.GetArg(0));
- break;
-
- case OperationType.LoadContext:
- EmitLoadContext(generator, operation.Parent);
- break;
-
- case OperationType.LoadField:
- generator.Emit(OpCodes.Ldfld, operation.GetArg<FieldInfo>(0));
- break;
-
- case OperationType.LoadLocal:
- EmitLoadLocal(
- generator,
- operation.GetArg<int>(0),
- operation.GetArg<RegisterType>(1),
- operation.GetArg<RegisterSize>(2));
- break;
-
- case OperationType.MarkLabel:
- generator.MarkLabel(GetLabel(operation.GetArg<ILLabel>(0)));
- break;
-
- case OperationType.StoreContext:
- EmitStoreContext(generator, operation.Parent);
- break;
-
- case OperationType.StoreLocal:
- EmitStoreLocal(
- generator,
- operation.GetArg<int>(0),
- operation.GetArg<RegisterType>(1),
- operation.GetArg<RegisterSize>(2));
- break;
- }
- }
- }
-
- subroutine.PrepareMethod();
-
- return subroutine;
- }
-
- private static void EmitLoadConstant(ILGenerator generator, object value)
- {
- switch (value)
- {
- case int valI4: generator.EmitLdc_I4(valI4); break;
- case long valI8: generator.Emit(OpCodes.Ldc_I8, valI8); break;
- case float valR4: generator.Emit(OpCodes.Ldc_R4, valR4); break;
- case double valR8: generator.Emit(OpCodes.Ldc_R8, valR8); break;
- }
- }
-
- private void EmitLoadContext(ILGenerator generator, BasicBlock block)
- {
- RegisterMask inputs = _regUsage.GetInputs(block);
-
- long intInputs = inputs.IntMask;
- long vecInputs = inputs.VecMask;
-
- if (Optimizations.AssumeStrictAbiCompliance && _isComplete)
- {
- intInputs = RegisterUsage.ClearCallerSavedIntRegs(intInputs, _mode);
- vecInputs = RegisterUsage.ClearCallerSavedVecRegs(vecInputs, _mode);
- }
-
- LoadLocals(generator, intInputs, RegisterType.Int);
- LoadLocals(generator, vecInputs, RegisterType.Vector);
- }
-
- private void LoadLocals(ILGenerator generator, long inputs, RegisterType baseType)
- {
- for (int bit = 0; bit < 64; bit++)
- {
- long mask = 1L << bit;
-
- if ((inputs & mask) != 0)
- {
- Register reg = GetRegFromBit(bit, baseType);
-
- generator.EmitLdarg(TranslatedSub.StateArgIdx);
- generator.Emit(OpCodes.Ldfld, reg.GetField());
-
- generator.EmitStloc(GetLocalIndex(generator, reg));
- }
- }
- }
-
- private void EmitStoreContext(ILGenerator generator, BasicBlock block)
- {
- RegisterMask outputs = _regUsage.GetOutputs(block);
-
- long intOutputs = outputs.IntMask;
- long vecOutputs = outputs.VecMask;
-
- if (Optimizations.AssumeStrictAbiCompliance && _isComplete)
- {
- intOutputs = RegisterUsage.ClearCallerSavedIntRegs(intOutputs, _mode);
- vecOutputs = RegisterUsage.ClearCallerSavedVecRegs(vecOutputs, _mode);
- }
-
- StoreLocals(generator, intOutputs, RegisterType.Int);
- StoreLocals(generator, vecOutputs, RegisterType.Vector);
- }
-
- private void StoreLocals(ILGenerator generator, long outputs, RegisterType baseType)
- {
- for (int bit = 0; bit < 64; bit++)
- {
- long mask = 1L << bit;
-
- if ((outputs & mask) != 0)
- {
- Register reg = GetRegFromBit(bit, baseType);
-
- generator.EmitLdarg(TranslatedSub.StateArgIdx);
- generator.EmitLdloc(GetLocalIndex(generator, reg));
-
- generator.Emit(OpCodes.Stfld, reg.GetField());
- }
- }
- }
-
- private void EmitLoadLocal(ILGenerator generator, int index, RegisterType type, RegisterSize size)
- {
- Register reg = new Register(index, type);
-
- generator.EmitLdloc(GetLocalIndex(generator, reg));
-
- if (type == RegisterType.Int && size == RegisterSize.Int32)
- {
- generator.Emit(OpCodes.Conv_U4);
- }
- }
-
- private void EmitStoreLocal(ILGenerator generator, int index, RegisterType type, RegisterSize size)
- {
- Register reg = new Register(index, type);
-
- if (type == RegisterType.Int && size == RegisterSize.Int32)
- {
- generator.Emit(OpCodes.Conv_U8);
- }
-
- generator.EmitStloc(GetLocalIndex(generator, reg));
- }
-
- private int GetLocalIndex(ILGenerator generator, Register reg)
- {
- if (!_locals.TryGetValue(reg, out int index))
- {
- generator.DeclareLocal(GetFieldType(reg.Type));
-
- index = _locals.Count;
-
- _locals.Add(reg, index);
- }
-
- return index;
- }
-
- private static Type GetFieldType(RegisterType regType)
- {
- switch (regType)
- {
- case RegisterType.Flag: return typeof(bool);
- case RegisterType.Int: return typeof(ulong);
- case RegisterType.Vector: return typeof(Vector128<float>);
- }
-
- throw new ArgumentException(nameof(regType));
- }
-
- private static Register GetRegFromBit(int bit, RegisterType baseType)
- {
- if (bit < RegsCount)
- {
- return new Register(bit, baseType);
- }
- else if (baseType == RegisterType.Int)
- {
- return new Register(bit & RegsMask, RegisterType.Flag);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(bit));
- }
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/TranslationTier.cs b/ChocolArm64/Translation/TranslationTier.cs
deleted file mode 100644
index 13afd9c5..00000000
--- a/ChocolArm64/Translation/TranslationTier.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace ChocolArm64.Translation
-{
- enum TranslationTier
- {
- Tier0,
- Tier1,
- Tier2,
-
- Count
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/Translator.cs b/ChocolArm64/Translation/Translator.cs
deleted file mode 100644
index ab8f474a..00000000
--- a/ChocolArm64/Translation/Translator.cs
+++ /dev/null
@@ -1,252 +0,0 @@
-using ChocolArm64.Decoders;
-using ChocolArm64.Events;
-using ChocolArm64.IntermediateRepresentation;
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-using System;
-using System.Reflection.Emit;
-using System.Threading;
-
-namespace ChocolArm64.Translation
-{
- public class Translator : ARMeilleure.Translation.ITranslator
- {
- private MemoryManager _memory;
-
- private CpuThreadState _dummyThreadState;
-
- private TranslatorCache _cache;
- private TranslatorQueue _queue;
-
- private Thread _backgroundTranslator;
-
- public event EventHandler<CpuTraceEventArgs> CpuTrace;
-
- public bool EnableCpuTrace { get; set; }
-
- private volatile int _threadCount;
-
- public Translator(MemoryManager memory)
- {
- _memory = memory;
-
- _dummyThreadState = new CpuThreadState();
-
- _dummyThreadState.Running = false;
-
- _cache = new TranslatorCache();
- _queue = new TranslatorQueue();
- }
-
- public void Execute(ARMeilleure.State.IExecutionContext ctx, ulong address)
- {
- CpuThreadState state = (CpuThreadState)ctx;
-
- long position = (long)address;
-
- if (Interlocked.Increment(ref _threadCount) == 1)
- {
- _backgroundTranslator = new Thread(TranslateQueuedSubs);
- _backgroundTranslator.Start();
- }
-
- state.CurrentTranslator = this;
-
- do
- {
- if (EnableCpuTrace)
- {
- CpuTrace?.Invoke(this, new CpuTraceEventArgs(position));
- }
-
- if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
- {
- sub = TranslateLowCq(position, state.GetExecutionMode());
- }
-
- position = sub.Execute(state, _memory);
- }
- while (position != 0 && state.Running);
-
- state.CurrentTranslator = null;
-
- if (Interlocked.Decrement(ref _threadCount) == 0)
- {
- _queue.ForceSignal();
- }
- }
-
- internal ArmSubroutine GetOrTranslateSubroutine(CpuThreadState state, long position, CallType cs)
- {
- if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
- {
- sub = TranslateLowCq(position, state.GetExecutionMode());
- }
-
- if (sub.Rejit())
- {
- bool isComplete = cs == CallType.Call ||
- cs == CallType.VirtualCall;
-
- _queue.Enqueue(position, state.GetExecutionMode(), TranslationTier.Tier1, isComplete);
- }
-
- return sub.Delegate;
- }
-
- private void TranslateQueuedSubs()
- {
- while (_threadCount != 0)
- {
- if (_queue.TryDequeue(out TranslatorQueueItem item))
- {
- bool isCached = _cache.TryGetSubroutine(item.Position, out TranslatedSub sub);
-
- if (isCached && item.Tier <= sub.Tier)
- {
- continue;
- }
-
- if (item.Tier == TranslationTier.Tier0)
- {
- TranslateLowCq(item.Position, item.Mode);
- }
- else
- {
- TranslateHighCq(item.Position, item.Mode, item.IsComplete);
- }
- }
- else
- {
- _queue.WaitForItems();
- }
- }
- }
-
- private TranslatedSub TranslateLowCq(long position, ExecutionMode mode)
- {
- Block[] blocks = Decoder.DecodeBasicBlock(_memory, (ulong)position, mode);
-
- ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier0);
-
- BasicBlock[] bbs = EmitAndGetBlocks(context, blocks);
-
- TranslatedSubBuilder builder = new TranslatedSubBuilder(mode);
-
- string name = GetSubroutineName(position);
-
- TranslatedSub subroutine = builder.Build(bbs, name, TranslationTier.Tier0);
-
- return _cache.GetOrAdd(position, subroutine, GetOpsCount(bbs));
- }
-
- private TranslatedSub TranslateHighCq(long position, ExecutionMode mode, bool isComplete)
- {
- Block[] blocks = Decoder.DecodeSubroutine(_memory, (ulong)position, mode);
-
- ILEmitterCtx context = new ILEmitterCtx(_memory, _cache, _queue, TranslationTier.Tier1);
-
- if (blocks[0].Address != (ulong)position)
- {
- context.Emit(OpCodes.Br, context.GetLabel(position));
- }
-
- BasicBlock[] bbs = EmitAndGetBlocks(context, blocks);
-
- isComplete &= !context.HasIndirectJump;
-
- TranslatedSubBuilder builder = new TranslatedSubBuilder(mode, isComplete);
-
- string name = GetSubroutineName(position);
-
- TranslatedSub subroutine = builder.Build(bbs, name, TranslationTier.Tier1, context.HasSlowCall);
-
- ForceAheadOfTimeCompilation(subroutine);
-
- _cache.AddOrUpdate(position, subroutine, GetOpsCount(bbs));
-
- return subroutine;
- }
-
- private static BasicBlock[] EmitAndGetBlocks(ILEmitterCtx context, Block[] blocks)
- {
- for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
- {
- Block block = blocks[blkIndex];
-
- context.CurrBlock = block;
-
- context.MarkLabel(context.GetLabel((long)block.Address));
-
- for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++)
- {
- OpCode64 opCode = block.OpCodes[opcIndex];
-
- context.CurrOp = opCode;
-
- bool isLastOp = opcIndex == block.OpCodes.Count - 1;
-
- if (isLastOp && block.Branch != null && block.Branch.Address <= block.Address)
- {
- context.EmitSynchronization();
- }
-
- ILLabel lblPredicateSkip = null;
-
- if (opCode is OpCode32 op && op.Cond < Condition.Al)
- {
- lblPredicateSkip = new ILLabel();
-
- context.EmitCondBranch(lblPredicateSkip, op.Cond.Invert());
- }
-
- opCode.Emitter(context);
-
- if (lblPredicateSkip != null)
- {
- context.MarkLabel(lblPredicateSkip);
-
- context.ResetBlockStateForPredicatedOp();
-
- // If this is the last op on the block, and there's no "next" block
- // after this one, then we have to return right now, with the address
- // of the next instruction to be executed (in the case that the condition
- // is false, and the branch was not taken, as all basic blocks should end
- // with some kind of branch).
- if (isLastOp && block.Next == null)
- {
- context.EmitStoreContext();
- context.EmitLdc_I8(opCode.Position + opCode.OpCodeSizeInBytes);
-
- context.Emit(OpCodes.Ret);
- }
- }
- }
- }
-
- return context.GetBlocks();
- }
-
- private static string GetSubroutineName(long position)
- {
- return $"Sub{position:x16}";
- }
-
- private static int GetOpsCount(BasicBlock[] blocks)
- {
- int opCount = 0;
-
- foreach (BasicBlock block in blocks)
- {
- opCount += block.Count;
- }
-
- return opCount;
- }
-
- private void ForceAheadOfTimeCompilation(TranslatedSub subroutine)
- {
- subroutine.Execute(_dummyThreadState, null);
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/TranslatorCache.cs b/ChocolArm64/Translation/TranslatorCache.cs
deleted file mode 100644
index cf6510ad..00000000
--- a/ChocolArm64/Translation/TranslatorCache.cs
+++ /dev/null
@@ -1,196 +0,0 @@
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Threading;
-
-namespace ChocolArm64.Translation
-{
- class TranslatorCache
- {
- // Maximum size of the cache, the unit used is completely arbitrary.
- private const int MaxTotalSize = 0x800000;
-
- // Minimum time required in milliseconds for a method to be eligible for deletion.
- private const int MinTimeDelta = 2 * 60000;
-
- // Minimum number of calls required to update the timestamp.
- private const int MinCallCountForUpdate = 250;
-
- private class CacheBucket
- {
- public TranslatedSub Subroutine { get; private set; }
-
- public LinkedListNode<long> Node { get; private set; }
-
- public int CallCount { get; set; }
-
- public int Size { get; private set; }
-
- public long Timestamp { get; private set; }
-
- public CacheBucket(TranslatedSub subroutine, LinkedListNode<long> node, int size)
- {
- Subroutine = subroutine;
- Size = size;
-
- UpdateNode(node);
- }
-
- public void UpdateNode(LinkedListNode<long> node)
- {
- Node = node;
-
- Timestamp = GetTimestamp();
- }
- }
-
- private ConcurrentDictionary<long, CacheBucket> _cache;
-
- private LinkedList<long> _sortedCache;
-
- private int _totalSize;
-
- public TranslatorCache()
- {
- _cache = new ConcurrentDictionary<long, CacheBucket>();
-
- _sortedCache = new LinkedList<long>();
- }
-
- public TranslatedSub GetOrAdd(long position, TranslatedSub subroutine, int size)
- {
- ClearCacheIfNeeded();
-
- lock (_sortedCache)
- {
- LinkedListNode<long> node = _sortedCache.AddLast(position);
-
- CacheBucket bucket = new CacheBucket(subroutine, node, size);
-
- bucket = _cache.GetOrAdd(position, bucket);
-
- if (bucket.Node == node)
- {
- _totalSize += size;
- }
- else
- {
- _sortedCache.Remove(node);
- }
-
- return bucket.Subroutine;
- }
- }
-
- public void AddOrUpdate(long position, TranslatedSub subroutine, int size)
- {
- ClearCacheIfNeeded();
-
- lock (_sortedCache)
- {
- _totalSize += size;
-
- LinkedListNode<long> node = _sortedCache.AddLast(position);
-
- CacheBucket newBucket = new CacheBucket(subroutine, node, size);
-
- _cache.AddOrUpdate(position, newBucket, (key, bucket) =>
- {
- _totalSize -= bucket.Size;
-
- _sortedCache.Remove(bucket.Node);
-
- return newBucket;
- });
- }
- }
-
- public bool HasSubroutine(long position)
- {
- return _cache.ContainsKey(position);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool TryGetSubroutine(long position, out TranslatedSub subroutine)
- {
- if (_cache.TryGetValue(position, out CacheBucket bucket))
- {
- if (bucket.CallCount++ > MinCallCountForUpdate)
- {
- if (Monitor.TryEnter(_sortedCache))
- {
- try
- {
- // The bucket value on the dictionary may have changed between the
- // time we get the value from the dictionary, and we acquire the
- // lock. So we need to ensure we are working with the latest value,
- // we can do that by getting the value again, inside the lock.
- if (_cache.TryGetValue(position, out CacheBucket latestBucket))
- {
- latestBucket.CallCount = 0;
-
- _sortedCache.Remove(latestBucket.Node);
-
- latestBucket.UpdateNode(_sortedCache.AddLast(position));
- }
- }
- finally
- {
- Monitor.Exit(_sortedCache);
- }
- }
- }
-
- subroutine = bucket.Subroutine;
-
- return true;
- }
-
- subroutine = default(TranslatedSub);
-
- return false;
- }
-
- private void ClearCacheIfNeeded()
- {
- long timestamp = GetTimestamp();
-
- while (_totalSize > MaxTotalSize)
- {
- lock (_sortedCache)
- {
- LinkedListNode<long> node = _sortedCache.First;
-
- if (node == null)
- {
- break;
- }
-
- CacheBucket bucket = _cache[node.Value];
-
- long timeDelta = timestamp - bucket.Timestamp;
-
- if (timeDelta <= MinTimeDelta)
- {
- break;
- }
-
- if (_cache.TryRemove(node.Value, out bucket))
- {
- _totalSize -= bucket.Size;
-
- _sortedCache.Remove(bucket.Node);
- }
- }
- }
- }
-
- private static long GetTimestamp()
- {
- long timestamp = Stopwatch.GetTimestamp();
-
- return timestamp / (Stopwatch.Frequency / 1000);
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/TranslatorQueue.cs b/ChocolArm64/Translation/TranslatorQueue.cs
deleted file mode 100644
index 0f1d8474..00000000
--- a/ChocolArm64/Translation/TranslatorQueue.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using ChocolArm64.State;
-using System.Collections.Concurrent;
-using System.Threading;
-
-namespace ChocolArm64.Translation
-{
- class TranslatorQueue
- {
- private ConcurrentStack<TranslatorQueueItem>[] _translationQueue;
-
- private ManualResetEvent _queueDataReceivedEvent;
-
- private bool _signaled;
-
- public TranslatorQueue()
- {
- _translationQueue = new ConcurrentStack<TranslatorQueueItem>[(int)TranslationTier.Count];
-
- for (int prio = 0; prio < _translationQueue.Length; prio++)
- {
- _translationQueue[prio] = new ConcurrentStack<TranslatorQueueItem>();
- }
-
- _queueDataReceivedEvent = new ManualResetEvent(false);
- }
-
- public void Enqueue(long position, ExecutionMode mode, TranslationTier tier, bool isComplete)
- {
- TranslatorQueueItem item = new TranslatorQueueItem(position, mode, tier, isComplete);
-
- ConcurrentStack<TranslatorQueueItem> queue = _translationQueue[(int)tier];
-
- queue.Push(item);
-
- _queueDataReceivedEvent.Set();
- }
-
- public bool TryDequeue(out TranslatorQueueItem item)
- {
- for (int prio = 0; prio < _translationQueue.Length; prio++)
- {
- if (_translationQueue[prio].TryPop(out item))
- {
- return true;
- }
- }
-
- item = default(TranslatorQueueItem);
-
- return false;
- }
-
- public void WaitForItems()
- {
- _queueDataReceivedEvent.WaitOne();
-
- lock (_queueDataReceivedEvent)
- {
- if (!_signaled)
- {
- _queueDataReceivedEvent.Reset();
- }
- }
- }
-
- public void ForceSignal()
- {
- lock (_queueDataReceivedEvent)
- {
- _signaled = true;
-
- _queueDataReceivedEvent.Set();
- _queueDataReceivedEvent.Close();
- }
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Translation/TranslatorQueueItem.cs b/ChocolArm64/Translation/TranslatorQueueItem.cs
deleted file mode 100644
index dde2706d..00000000
--- a/ChocolArm64/Translation/TranslatorQueueItem.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using ChocolArm64.State;
-
-namespace ChocolArm64.Translation
-{
- struct TranslatorQueueItem
- {
- public long Position { get; }
-
- public ExecutionMode Mode { get; }
-
- public TranslationTier Tier { get; }
-
- public bool IsComplete { get; }
-
- public TranslatorQueueItem(
- long position,
- ExecutionMode mode,
- TranslationTier tier,
- bool isComplete = false)
- {
- Position = position;
- Mode = mode;
- Tier = tier;
- IsComplete = isComplete;
- }
- }
-} \ No newline at end of file