TranslatedSub.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. using ChocolArm64.Memory;
  2. using ChocolArm64.State;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Reflection.Emit;
  9. namespace ChocolArm64
  10. {
  11. class TranslatedSub
  12. {
  13. private delegate long Aa64Subroutine(CpuThreadState register, MemoryManager memory);
  14. private const int MinCallCountForReJit = 250;
  15. private Aa64Subroutine _execDelegate;
  16. public static int StateArgIdx { get; private set; }
  17. public static int MemoryArgIdx { get; private set; }
  18. public static Type[] FixedArgTypes { get; private set; }
  19. public DynamicMethod Method { get; private set; }
  20. public ReadOnlyCollection<Register> SubArgs { get; private set; }
  21. private HashSet<long> _callers;
  22. private TranslatedSubType _type;
  23. private int _callCount;
  24. private bool _needsReJit;
  25. public TranslatedSub(DynamicMethod method, List<Register> subArgs)
  26. {
  27. Method = method ?? throw new ArgumentNullException(nameof(method));;
  28. SubArgs = subArgs?.AsReadOnly() ?? throw new ArgumentNullException(nameof(subArgs));
  29. _callers = new HashSet<long>();
  30. PrepareDelegate();
  31. }
  32. static TranslatedSub()
  33. {
  34. MethodInfo mthdInfo = typeof(Aa64Subroutine).GetMethod("Invoke");
  35. ParameterInfo[] Params = mthdInfo.GetParameters();
  36. FixedArgTypes = new Type[Params.Length];
  37. for (int index = 0; index < Params.Length; index++)
  38. {
  39. Type paramType = Params[index].ParameterType;
  40. FixedArgTypes[index] = paramType;
  41. if (paramType == typeof(CpuThreadState))
  42. {
  43. StateArgIdx = index;
  44. }
  45. else if (paramType == typeof(MemoryManager))
  46. {
  47. MemoryArgIdx = index;
  48. }
  49. }
  50. }
  51. private void PrepareDelegate()
  52. {
  53. string name = $"{Method.Name}_Dispatch";
  54. DynamicMethod mthd = new DynamicMethod(name, typeof(long), FixedArgTypes);
  55. ILGenerator generator = mthd.GetILGenerator();
  56. generator.EmitLdargSeq(FixedArgTypes.Length);
  57. foreach (Register reg in SubArgs)
  58. {
  59. generator.EmitLdarg(StateArgIdx);
  60. generator.Emit(OpCodes.Ldfld, reg.GetField());
  61. }
  62. generator.Emit(OpCodes.Call, Method);
  63. generator.Emit(OpCodes.Ret);
  64. _execDelegate = (Aa64Subroutine)mthd.CreateDelegate(typeof(Aa64Subroutine));
  65. }
  66. public bool ShouldReJit()
  67. {
  68. if (_needsReJit && _callCount < MinCallCountForReJit)
  69. {
  70. _callCount++;
  71. return false;
  72. }
  73. return _needsReJit;
  74. }
  75. public long Execute(CpuThreadState threadState, MemoryManager memory)
  76. {
  77. return _execDelegate(threadState, memory);
  78. }
  79. public void AddCaller(long position)
  80. {
  81. lock (_callers)
  82. {
  83. _callers.Add(position);
  84. }
  85. }
  86. public long[] GetCallerPositions()
  87. {
  88. lock (_callers)
  89. {
  90. return _callers.ToArray();
  91. }
  92. }
  93. public void SetType(TranslatedSubType type)
  94. {
  95. _type = type;
  96. if (type == TranslatedSubType.SubTier0)
  97. {
  98. _needsReJit = true;
  99. }
  100. }
  101. public void MarkForReJit() => _needsReJit = true;
  102. }
  103. }