Translator.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.Events;
  3. using ChocolArm64.Memory;
  4. using ChocolArm64.State;
  5. using ChocolArm64.Translation;
  6. using System;
  7. namespace ChocolArm64
  8. {
  9. public class Translator
  10. {
  11. private TranslatorCache _cache;
  12. public event EventHandler<CpuTraceEventArgs> CpuTrace;
  13. public bool EnableCpuTrace { get; set; }
  14. public Translator()
  15. {
  16. _cache = new TranslatorCache();
  17. }
  18. internal void ExecuteSubroutine(CpuThread thread, long position)
  19. {
  20. ExecuteSubroutine(thread.ThreadState, thread.Memory, position);
  21. }
  22. private void ExecuteSubroutine(CpuThreadState state, MemoryManager memory, long position)
  23. {
  24. do
  25. {
  26. if (EnableCpuTrace)
  27. {
  28. CpuTrace?.Invoke(this, new CpuTraceEventArgs(position));
  29. }
  30. if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
  31. {
  32. sub = TranslateTier0(memory, position, state.GetExecutionMode());
  33. }
  34. if (sub.ShouldReJit())
  35. {
  36. TranslateTier1(memory, position, state.GetExecutionMode());
  37. }
  38. position = sub.Execute(state, memory);
  39. }
  40. while (position != 0 && state.Running);
  41. }
  42. internal bool HasCachedSub(long position)
  43. {
  44. return _cache.HasSubroutine(position);
  45. }
  46. private TranslatedSub TranslateTier0(MemoryManager memory, long position, ExecutionMode mode)
  47. {
  48. Block block = Decoder.DecodeBasicBlock(memory, position, mode);
  49. ILEmitterCtx context = new ILEmitterCtx(_cache, block);
  50. string subName = GetSubroutineName(position);
  51. ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(context.GetILBlocks(), subName);
  52. TranslatedSub subroutine = ilMthdBuilder.GetSubroutine();
  53. subroutine.SetType(TranslatedSubType.SubTier0);
  54. _cache.AddOrUpdate(position, subroutine, block.OpCodes.Count);
  55. return subroutine;
  56. }
  57. private void TranslateTier1(MemoryManager memory, long position, ExecutionMode mode)
  58. {
  59. Block graph = Decoder.DecodeSubroutine(_cache, memory, position, mode);
  60. ILEmitterCtx context = new ILEmitterCtx(_cache, graph);
  61. ILBlock[] ilBlocks = context.GetILBlocks();
  62. string subName = GetSubroutineName(position);
  63. ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(ilBlocks, subName);
  64. TranslatedSub subroutine = ilMthdBuilder.GetSubroutine();
  65. subroutine.SetType(TranslatedSubType.SubTier1);
  66. int ilOpCount = 0;
  67. foreach (ILBlock ilBlock in ilBlocks)
  68. {
  69. ilOpCount += ilBlock.Count;
  70. }
  71. _cache.AddOrUpdate(position, subroutine, ilOpCount);
  72. //Mark all methods that calls this method for ReJiting,
  73. //since we can now call it directly which is faster.
  74. if (_cache.TryGetSubroutine(position, out TranslatedSub oldSub))
  75. {
  76. foreach (long callerPos in oldSub.GetCallerPositions())
  77. {
  78. if (_cache.TryGetSubroutine(position, out TranslatedSub callerSub))
  79. {
  80. callerSub.MarkForReJit();
  81. }
  82. }
  83. }
  84. }
  85. private string GetSubroutineName(long position)
  86. {
  87. return $"Sub{position:x16}";
  88. }
  89. }
  90. }