ATranslatorCache.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Runtime.CompilerServices;
  5. using System.Threading;
  6. namespace ChocolArm64
  7. {
  8. class ATranslatorCache
  9. {
  10. //Maximum size of the cache, in bytes, measured in ARM code size.
  11. private const int MaxTotalSize = 4 * 1024 * 256;
  12. //Minimum time required in milliseconds for a method to be eligible for deletion.
  13. private const int MinTimeDelta = 2 * 60000;
  14. //Minimum number of calls required to update the timestamp.
  15. private const int MinCallCountForUpdate = 250;
  16. private class CacheBucket
  17. {
  18. public ATranslatedSub Subroutine { get; private set; }
  19. public LinkedListNode<long> Node { get; private set; }
  20. public int CallCount { get; set; }
  21. public int Size { get; private set; }
  22. public int Timestamp { get; private set; }
  23. public CacheBucket(ATranslatedSub Subroutine, LinkedListNode<long> Node, int Size)
  24. {
  25. this.Subroutine = Subroutine;
  26. this.Size = Size;
  27. UpdateNode(Node);
  28. }
  29. public void UpdateNode(LinkedListNode<long> Node)
  30. {
  31. this.Node = Node;
  32. Timestamp = Environment.TickCount;
  33. }
  34. }
  35. private ConcurrentDictionary<long, CacheBucket> Cache;
  36. private LinkedList<long> SortedCache;
  37. private int TotalSize;
  38. public ATranslatorCache()
  39. {
  40. Cache = new ConcurrentDictionary<long, CacheBucket>();
  41. SortedCache = new LinkedList<long>();
  42. }
  43. public void AddOrUpdate(long Position, ATranslatedSub Subroutine, int Size)
  44. {
  45. ClearCacheIfNeeded();
  46. TotalSize += Size;
  47. lock (SortedCache)
  48. {
  49. LinkedListNode<long> Node = SortedCache.AddLast(Position);
  50. CacheBucket NewBucket = new CacheBucket(Subroutine, Node, Size);
  51. Cache.AddOrUpdate(Position, NewBucket, (Key, Bucket) =>
  52. {
  53. TotalSize -= Bucket.Size;
  54. SortedCache.Remove(Bucket.Node);
  55. return NewBucket;
  56. });
  57. }
  58. }
  59. public bool HasSubroutine(long Position)
  60. {
  61. return Cache.ContainsKey(Position);
  62. }
  63. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  64. public bool TryGetSubroutine(long Position, out ATranslatedSub Subroutine)
  65. {
  66. if (Cache.TryGetValue(Position, out CacheBucket Bucket))
  67. {
  68. if (Bucket.CallCount++ > MinCallCountForUpdate)
  69. {
  70. if (Monitor.TryEnter(SortedCache))
  71. {
  72. try
  73. {
  74. Bucket.CallCount = 0;
  75. SortedCache.Remove(Bucket.Node);
  76. Bucket.UpdateNode(SortedCache.AddLast(Position));
  77. }
  78. finally
  79. {
  80. Monitor.Exit(SortedCache);
  81. }
  82. }
  83. }
  84. Subroutine = Bucket.Subroutine;
  85. return true;
  86. }
  87. Subroutine = default(ATranslatedSub);
  88. return false;
  89. }
  90. private void ClearCacheIfNeeded()
  91. {
  92. int Timestamp = Environment.TickCount;
  93. while (TotalSize > MaxTotalSize)
  94. {
  95. lock (SortedCache)
  96. {
  97. LinkedListNode<long> Node = SortedCache.First;
  98. if (Node == null)
  99. {
  100. break;
  101. }
  102. CacheBucket Bucket = Cache[Node.Value];
  103. int TimeDelta = RingDelta(Bucket.Timestamp, Timestamp);
  104. if ((uint)TimeDelta <= (uint)MinTimeDelta)
  105. {
  106. break;
  107. }
  108. if (Cache.TryRemove(Node.Value, out Bucket))
  109. {
  110. TotalSize -= Bucket.Size;
  111. SortedCache.Remove(Bucket.Node);
  112. }
  113. }
  114. }
  115. }
  116. private static int RingDelta(int Old, int New)
  117. {
  118. if ((uint)New < (uint)Old)
  119. {
  120. return New + (~Old + 1);
  121. }
  122. else
  123. {
  124. return New - Old;
  125. }
  126. }
  127. }
  128. }