| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Runtime.CompilerServices;
- using System.Threading;
- namespace ChocolArm64
- {
- class ATranslatorCache
- {
- //Maximum size of the cache, in bytes, measured in ARM code size.
- private const int MaxTotalSize = 4 * 1024 * 256;
- //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 ATranslatedSub Subroutine { get; private set; }
- public LinkedListNode<long> Node { get; private set; }
- public int CallCount { get; set; }
- public int Size { get; private set; }
- public int Timestamp { get; private set; }
- public CacheBucket(ATranslatedSub Subroutine, LinkedListNode<long> Node, int Size)
- {
- this.Subroutine = Subroutine;
- this.Size = Size;
- UpdateNode(Node);
- }
- public void UpdateNode(LinkedListNode<long> Node)
- {
- this.Node = Node;
- Timestamp = Environment.TickCount;
- }
- }
- private ConcurrentDictionary<long, CacheBucket> Cache;
- private LinkedList<long> SortedCache;
- private int TotalSize;
- public ATranslatorCache()
- {
- Cache = new ConcurrentDictionary<long, CacheBucket>();
- SortedCache = new LinkedList<long>();
- }
- public void AddOrUpdate(long Position, ATranslatedSub Subroutine, int Size)
- {
- ClearCacheIfNeeded();
- TotalSize += Size;
- lock (SortedCache)
- {
- 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 ATranslatedSub Subroutine)
- {
- if (Cache.TryGetValue(Position, out CacheBucket Bucket))
- {
- if (Bucket.CallCount++ > MinCallCountForUpdate)
- {
- if (Monitor.TryEnter(SortedCache))
- {
- try
- {
- Bucket.CallCount = 0;
- SortedCache.Remove(Bucket.Node);
- Bucket.UpdateNode(SortedCache.AddLast(Position));
- }
- finally
- {
- Monitor.Exit(SortedCache);
- }
- }
- }
- Subroutine = Bucket.Subroutine;
- return true;
- }
- Subroutine = default(ATranslatedSub);
- return false;
- }
- private void ClearCacheIfNeeded()
- {
- int Timestamp = Environment.TickCount;
- while (TotalSize > MaxTotalSize)
- {
- lock (SortedCache)
- {
- LinkedListNode<long> Node = SortedCache.First;
- if (Node == null)
- {
- break;
- }
- CacheBucket Bucket = Cache[Node.Value];
- int TimeDelta = RingDelta(Bucket.Timestamp, Timestamp);
- if ((uint)TimeDelta <= (uint)MinTimeDelta)
- {
- break;
- }
- if (Cache.TryRemove(Node.Value, out Bucket))
- {
- TotalSize -= Bucket.Size;
- SortedCache.Remove(Bucket.Node);
- }
- }
- }
- }
- private static int RingDelta(int Old, int New)
- {
- if ((uint)New < (uint)Old)
- {
- return New + (~Old + 1);
- }
- else
- {
- return New - Old;
- }
- }
- }
- }
|