cleanup old jit functions
This commit is contained in:
parent
3b531de670
commit
68cee9db6d
4 changed files with 178 additions and 28 deletions
|
@ -17,7 +17,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
private static IntPtr _basePointer;
|
||||
|
||||
private static int _offset;
|
||||
private static JitCacheMemoryAllocator _allocator;
|
||||
|
||||
private static List<JitCacheEntry> _cacheEntries;
|
||||
|
||||
|
@ -27,14 +27,20 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
_basePointer = MemoryManagement.Allocate(CacheSize);
|
||||
|
||||
int startOffset = 0;
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
JitUnwindWindows.InstallFunctionTableHandler(_basePointer, CacheSize);
|
||||
|
||||
// The first page is used for the table based SEH structs.
|
||||
_offset = PageSize;
|
||||
startOffset = PageSize;
|
||||
}
|
||||
|
||||
ReprotectRange(startOffset, CacheSize - startOffset);
|
||||
|
||||
_allocator = new JitCacheMemoryAllocator(CacheSize, startOffset);
|
||||
|
||||
_cacheEntries = new List<JitCacheEntry>();
|
||||
|
||||
_lock = new object();
|
||||
|
@ -52,8 +58,6 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Marshal.Copy(code, 0, funcPtr, code.Length);
|
||||
|
||||
ReprotectRange(funcOffset, code.Length);
|
||||
|
||||
Add(new JitCacheEntry(funcOffset, code.Length, func.UnwindInfo));
|
||||
|
||||
return funcPtr;
|
||||
|
@ -76,16 +80,7 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
IntPtr funcPtr = _basePointer + pageStart;
|
||||
|
||||
MemoryManagement.Reprotect(funcPtr, (ulong)fullPagesSize, MemoryProtection.ReadAndExecute);
|
||||
}
|
||||
|
||||
int remaining = endOffs - pageEnd;
|
||||
|
||||
if (remaining != 0)
|
||||
{
|
||||
IntPtr funcPtr = _basePointer + pageEnd;
|
||||
|
||||
MemoryManagement.Reprotect(funcPtr, (ulong)remaining, MemoryProtection.ReadWriteExecute);
|
||||
MemoryManagement.Reprotect(funcPtr, (ulong)fullPagesSize, MemoryProtection.ReadWriteExecute);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,18 +88,28 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
codeSize = checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
||||
|
||||
int allocOffset = _offset;
|
||||
|
||||
_offset += codeSize;
|
||||
|
||||
if ((ulong)(uint)_offset > CacheSize)
|
||||
{
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
int allocOffset = _allocator.Allocate(codeSize);
|
||||
|
||||
return allocOffset;
|
||||
}
|
||||
|
||||
public static void Free(ulong address)
|
||||
{
|
||||
ulong offset = address - (ulong)_basePointer;
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (TryFind((int)offset, out JitCacheEntry entry))
|
||||
{
|
||||
_cacheEntries.Remove(entry);
|
||||
|
||||
int size = checked(entry.Size + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
||||
|
||||
_allocator.Free((int)entry.Offset, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Add(JitCacheEntry entry)
|
||||
{
|
||||
_cacheEntries.Add(entry);
|
||||
|
|
108
ARMeilleure/Translation/JitCacheMemoryAllocator.cs
Normal file
108
ARMeilleure/Translation/JitCacheMemoryAllocator.cs
Normal file
|
@ -0,0 +1,108 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
class JitCacheMemoryAllocator
|
||||
{
|
||||
private int _size;
|
||||
|
||||
private LinkedList<(int Start, int End)> _memoryRanges;
|
||||
|
||||
public JitCacheMemoryAllocator(int size, int startPosition)
|
||||
{
|
||||
_size = size;
|
||||
|
||||
_memoryRanges = new LinkedList<(int start, int end)>();
|
||||
|
||||
_memoryRanges.AddFirst((startPosition, startPosition - 1));
|
||||
}
|
||||
|
||||
public int Allocate(int size)
|
||||
{
|
||||
var node = _memoryRanges.First;
|
||||
|
||||
int offset;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (node.Value.End > (_size - 1) - size)
|
||||
{
|
||||
throw new OutOfMemoryException();
|
||||
}
|
||||
|
||||
if (node.Next == null)
|
||||
{
|
||||
offset = node.Value.End + 1;
|
||||
|
||||
node.Value = (node.Value.Start, node.Value.End + size);
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node.Next.Value.Start - node.Value.End <= 1)
|
||||
{
|
||||
node.Value = (node.Value.Start, node.Next.Value.End);
|
||||
|
||||
_memoryRanges.Remove(node.Next);
|
||||
}
|
||||
|
||||
if (node.Next.Value.Start - size > node.Value.End)
|
||||
{
|
||||
offset = node.Value.End + 1;
|
||||
|
||||
if (node.Next.Value.Start - offset == size)
|
||||
{
|
||||
node.Value = (node.Value.Start, node.Next.Value.End);
|
||||
|
||||
_memoryRanges.Remove(node.Next);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
node.Value = (node.Value.Start, offset + size - 1);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Free(int offset, int size)
|
||||
{
|
||||
if ((uint)offset >= (ulong)_size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
var node = _memoryRanges.First;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (node == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
if (offset <= node.Value.End)
|
||||
{
|
||||
int newRangeStart = offset + size;
|
||||
|
||||
_memoryRanges.AddAfter(node, (newRangeStart, node.Value.End));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
}
|
||||
|
||||
node.Value = (node.Value.Start, offset - 1);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,17 +1,24 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
class TranslatedFunction
|
||||
{
|
||||
public ulong Pointer => (ulong)Marshal.GetFunctionPointerForDelegate(_func);
|
||||
|
||||
public int EntryCount;
|
||||
|
||||
private const int MinCallsForRejit = 100;
|
||||
|
||||
private GuestFunction _func;
|
||||
|
||||
private bool _rejit;
|
||||
private int _callCount;
|
||||
private ulong _address;
|
||||
private bool _rejit;
|
||||
private int _callCount;
|
||||
|
||||
public TranslatedFunction(GuestFunction func, bool rejit)
|
||||
public TranslatedFunction(GuestFunction func, ulong address, bool rejit)
|
||||
{
|
||||
_func = func;
|
||||
_rejit = rejit;
|
||||
|
@ -19,7 +26,16 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public ulong Execute(State.ExecutionContext context)
|
||||
{
|
||||
return _func(context.NativeContextPtr);
|
||||
if (Interlocked.Increment(ref EntryCount) == 0)
|
||||
{
|
||||
return _address;
|
||||
}
|
||||
|
||||
var nextAddress = _func(context.NativeContextPtr);
|
||||
|
||||
Interlocked.Decrement(ref EntryCount);
|
||||
|
||||
return nextAddress;
|
||||
}
|
||||
|
||||
public bool ShouldRejit()
|
||||
|
|
|
@ -6,6 +6,7 @@ using ARMeilleure.Memory;
|
|||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
@ -20,6 +21,8 @@ namespace ARMeilleure.Translation
|
|||
|
||||
private ConcurrentDictionary<ulong, TranslatedFunction> _funcs;
|
||||
|
||||
private Queue<TranslatedFunction> _oldFunctions;
|
||||
|
||||
private PriorityQueue<RejitRequest> _backgroundQueue;
|
||||
|
||||
private AutoResetEvent _backgroundTranslatorEvent;
|
||||
|
@ -35,6 +38,8 @@ namespace ARMeilleure.Translation
|
|||
_backgroundQueue = new PriorityQueue<RejitRequest>(2);
|
||||
|
||||
_backgroundTranslatorEvent = new AutoResetEvent(false);
|
||||
|
||||
_oldFunctions = new Queue<TranslatedFunction>();
|
||||
}
|
||||
|
||||
private void TranslateQueuedSubs()
|
||||
|
@ -45,7 +50,23 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
TranslatedFunction func = Translate(request.Address, request.Mode, highCq: true);
|
||||
|
||||
_funcs.AddOrUpdate(request.Address, func, (key, oldFunc) => func);
|
||||
_funcs.AddOrUpdate(request.Address, func, (key, oldFunc) =>
|
||||
{
|
||||
_oldFunctions.Enqueue(oldFunc);
|
||||
|
||||
return func;
|
||||
});
|
||||
}
|
||||
else if (_oldFunctions.TryDequeue(out TranslatedFunction function))
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref function.EntryCount, -1, 0) != 0)
|
||||
{
|
||||
_oldFunctions.Enqueue(function);
|
||||
}
|
||||
else
|
||||
{
|
||||
JitCache.Free(function.Pointer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -161,7 +182,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
GuestFunction func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options);
|
||||
|
||||
return new TranslatedFunction(func, rejit: !highCq);
|
||||
return new TranslatedFunction(func, address, rejit: !highCq);
|
||||
}
|
||||
|
||||
private static ControlFlowGraph EmitAndGetCFG(ArmEmitterContext context, Block[] blocks)
|
||||
|
|
Loading…
Add table
Reference in a new issue