diff options
| author | LDj3SNuD <35856442+LDj3SNuD@users.noreply.github.com> | 2019-10-31 19:09:03 +0100 |
|---|---|---|
| committer | Ac_K <Acoustik666@gmail.com> | 2019-10-31 19:09:03 +0100 |
| commit | eee639d6ba544fa5dd9352426d55e91bc54e157d (patch) | |
| tree | 1df440ca57d8c1725e84f403fbeecddb8e508a3a /ChocolArm64/Translation | |
| parent | 35443bac5a16ced668d84e0a22c21ca9076b3924 (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.cs | 9 | ||||
| -rw-r--r-- | ChocolArm64/Translation/ILEmitterCtx.cs | 709 | ||||
| -rw-r--r-- | ChocolArm64/Translation/ILGeneratorEx.cs | 121 | ||||
| -rw-r--r-- | ChocolArm64/Translation/RegisterUsage.cs | 176 | ||||
| -rw-r--r-- | ChocolArm64/Translation/TranslatedSub.cs | 93 | ||||
| -rw-r--r-- | ChocolArm64/Translation/TranslatedSubBuilder.cs | 274 | ||||
| -rw-r--r-- | ChocolArm64/Translation/TranslationTier.cs | 11 | ||||
| -rw-r--r-- | ChocolArm64/Translation/Translator.cs | 252 | ||||
| -rw-r--r-- | ChocolArm64/Translation/TranslatorCache.cs | 196 | ||||
| -rw-r--r-- | ChocolArm64/Translation/TranslatorQueue.cs | 77 | ||||
| -rw-r--r-- | ChocolArm64/Translation/TranslatorQueueItem.cs | 27 |
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 |
