TranslatedSub.cs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. using ChocolArm64.Memory;
  2. using ChocolArm64.State;
  3. using System;
  4. using System.Reflection;
  5. using System.Reflection.Emit;
  6. namespace ChocolArm64.Translation
  7. {
  8. delegate long ArmSubroutine(CpuThreadState state, MemoryManager memory);
  9. class TranslatedSub
  10. {
  11. // This is the minimum amount of calls needed for the method
  12. // to be retranslated with higher quality code. It's only worth
  13. // doing that for hot code.
  14. private const int MinCallCountForOpt = 30;
  15. public ArmSubroutine Delegate { get; private set; }
  16. public static int StateArgIdx { get; }
  17. public static int MemoryArgIdx { get; }
  18. public static Type[] FixedArgTypes { get; }
  19. public DynamicMethod Method { get; }
  20. public TranslationTier Tier { get; }
  21. private bool _rejit;
  22. private int _callCount;
  23. public TranslatedSub(DynamicMethod method, TranslationTier tier, bool rejit)
  24. {
  25. Method = method ?? throw new ArgumentNullException(nameof(method));
  26. Tier = tier;
  27. _rejit = rejit;
  28. }
  29. static TranslatedSub()
  30. {
  31. MethodInfo mthdInfo = typeof(ArmSubroutine).GetMethod("Invoke");
  32. ParameterInfo[] Params = mthdInfo.GetParameters();
  33. FixedArgTypes = new Type[Params.Length];
  34. for (int index = 0; index < Params.Length; index++)
  35. {
  36. Type argType = Params[index].ParameterType;
  37. FixedArgTypes[index] = argType;
  38. if (argType == typeof(CpuThreadState))
  39. {
  40. StateArgIdx = index;
  41. }
  42. else if (argType == typeof(MemoryManager))
  43. {
  44. MemoryArgIdx = index;
  45. }
  46. }
  47. }
  48. public void PrepareMethod()
  49. {
  50. Delegate = (ArmSubroutine)Method.CreateDelegate(typeof(ArmSubroutine));
  51. }
  52. public long Execute(CpuThreadState threadState, MemoryManager memory)
  53. {
  54. return Delegate(threadState, memory);
  55. }
  56. public bool Rejit()
  57. {
  58. if (!_rejit)
  59. {
  60. return false;
  61. }
  62. if (_callCount++ < MinCallCountForOpt)
  63. {
  64. return false;
  65. }
  66. // Only return true once, so that it is added to the queue only once.
  67. _rejit = false;
  68. return true;
  69. }
  70. }
  71. }