diff --git a/ARMeilleure/Common/Counter.cs b/ARMeilleure/Common/Counter.cs
index 66ae1c70e..1ceba1762 100644
--- a/ARMeilleure/Common/Counter.cs
+++ b/ARMeilleure/Common/Counter.cs
@@ -18,10 +18,22 @@ namespace ARMeilleure.Common
///
/// instance
/// Index in the
- private Counter(EntryTable countTable, int index)
+ /// is
+ /// is unsupported
+ public Counter(EntryTable countTable)
{
- _countTable = countTable;
- _index = index;
+ if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) &&
+ typeof(T) != typeof(short) && typeof(T) != typeof(ushort) &&
+ typeof(T) != typeof(int) && typeof(T) != typeof(uint) &&
+ typeof(T) != typeof(long) && typeof(T) != typeof(ulong) &&
+ typeof(T) != typeof(nint) && typeof(T) != typeof(nuint) &&
+ typeof(T) != typeof(float) && typeof(T) != typeof(double))
+ {
+ throw new ArgumentException("Counter does not support the specified type.");
+ }
+
+ _countTable = countTable ?? throw new ArgumentNullException(nameof(countTable));
+ _index = countTable.Allocate();
}
///
@@ -67,48 +79,11 @@ namespace ARMeilleure.Common
}
///
- /// Frees resources used by instance.
+ /// Frees resources used by the instance.
///
~Counter()
{
Dispose(false);
}
-
- ///
- /// Tries to create a instance from the specified instance.
- ///
- /// from which to create the
- /// instance if success; otherwise
- /// if success; otherwise
- /// is
- /// is unsupported
- public static bool TryCreate(EntryTable countTable, out Counter counter)
- {
- if (countTable == null)
- {
- throw new ArgumentNullException(nameof(countTable));
- }
-
- if (typeof(T) != typeof(byte) && typeof(T) != typeof(sbyte) &&
- typeof(T) != typeof(short) && typeof(T) != typeof(ushort) &&
- typeof(T) != typeof(int) && typeof(T) != typeof(uint) &&
- typeof(T) != typeof(long) && typeof(T) != typeof(ulong) &&
- typeof(T) != typeof(nint) && typeof(T) != typeof(nuint) &&
- typeof(T) != typeof(float) && typeof(T) != typeof(double))
- {
- throw new ArgumentException("Counter does not support the specified type", nameof(countTable));
- }
-
- if (countTable.TryAllocate(out int index))
- {
- counter = new Counter(countTable, index);
-
- return true;
- }
-
- counter = null;
-
- return false;
- }
}
}
diff --git a/ARMeilleure/Common/EntryTable.cs b/ARMeilleure/Common/EntryTable.cs
index b8981496b..bb171dc67 100644
--- a/ARMeilleure/Common/EntryTable.cs
+++ b/ARMeilleure/Common/EntryTable.cs
@@ -1,43 +1,63 @@
using System;
+using System.Collections.Generic;
+using System.Numerics;
+using System.Runtime.InteropServices;
namespace ARMeilleure.Common
{
///
- /// Represents a fixed size table of the type , whose entries will remain at the same
+ /// Represents an expandable table of the type , whose entries will remain at the same
/// address through out the table's lifetime.
///
/// Type of the entry in the table
- class EntryTable where TEntry : unmanaged
+ class EntryTable : IDisposable where TEntry : unmanaged
{
+ private bool _disposed;
private int _freeHint;
- private readonly TEntry[] _table;
+ private readonly int _pageCapacity; // Number of entries per page.
+ private readonly int _pageLogCapacity;
+ private readonly Dictionary _pages;
private readonly BitMap _allocated;
///
- /// Initializes a new instance of the class with the specified capacity.
+ /// Initializes a new instance of the class with the desired page size.
///
- /// Capacity of the table
- /// is less than 0
- public EntryTable(int capacity)
+ /// Desired page size
+ /// is less than 0
+ /// 's size is zero
+ ///
+ /// The actual page size may be smaller or larger depending on the size of .
+ ///
+ public unsafe EntryTable(int pageSize = 4096)
{
- if (capacity < 0)
+ if (pageSize < 0)
{
- throw new ArgumentOutOfRangeException(nameof(capacity));
+ throw new ArgumentOutOfRangeException(nameof(pageSize), "Page size cannot be negative.");
+ }
+
+ if (sizeof(TEntry) == 0)
+ {
+ throw new ArgumentException("Size of TEntry cannot be zero.");
}
- _freeHint = 0;
_allocated = new BitMap();
- _table = GC.AllocateArray(capacity, pinned: true);
+ _pages = new Dictionary();
+ _pageLogCapacity = BitOperations.Log2((uint)(pageSize / sizeof(TEntry)));
+ _pageCapacity = 1 << _pageLogCapacity;
}
///
- /// Tries to allocate an entry in the . Returns if
- /// success; otherwise returns .
+ /// Allocates an entry in the .
///
- /// Index of entry allocated in the table
- /// if success; otherwise
- public bool TryAllocate(out int index)
+ /// Index of entry allocated in the table
+ /// instance was disposed
+ public int Allocate()
{
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(null);
+ }
+
lock (_allocated)
{
if (_allocated.IsSet(_freeHint))
@@ -45,32 +65,37 @@ namespace ARMeilleure.Common
_freeHint = _allocated.FindFirstUnset();
}
- if (_freeHint >= 0 && _freeHint < _table.Length)
- {
- index = _freeHint++;
+ int index = _freeHint++;
+ var page = GetPage(index);
- _allocated.Set(index);
+ _allocated.Set(index);
- GetValue(index) = default;
+ GetValue(page, index) = default;
- return true;
- }
+ return index;
}
-
- index = 0;
-
- return false;
}
///
/// Frees the entry at the specified .
///
/// Index of entry to free
+ /// instance was disposed
public void Free(int index)
{
+ if (_disposed)
+ {
+ throw new ObjectDisposedException(null);
+ }
+
lock (_allocated)
{
- _allocated.Clear(index);
+ if (_allocated.IsSet(index))
+ {
+ _allocated.Clear(index);
+
+ _freeHint = index;
+ }
}
}
@@ -78,25 +103,95 @@ namespace ARMeilleure.Common
/// Gets a reference to the entry at the specified allocated .
///
/// Index of the entry
- /// Reference to the entry at the specified index
+ /// Reference to the entry at the specified
+ /// instance was disposed
/// Entry at is not allocated
- /// is outside of the table
public ref TEntry GetValue(int index)
{
- if (index < 0 || index >= _table.Length)
+ if (_disposed)
{
- throw new ArgumentOutOfRangeException(nameof(index));
+ throw new ObjectDisposedException(null);
}
+ Span page;
+
lock (_allocated)
{
if (!_allocated.IsSet(index))
{
throw new ArgumentException("Entry at the specified index was not allocated", nameof(index));
}
+
+ page = GetPage(index);
}
- return ref _table[index];
+ return ref GetValue(page, index);
+ }
+
+ ///
+ /// Gets a reference to the entry at using the specified from the specified
+ /// .
+ ///
+ /// Page to use
+ /// Index to use
+ /// Reference to the entry
+ private ref TEntry GetValue(Span page, int index)
+ {
+ return ref page[index & (_pageCapacity - 1)];
+ }
+
+ ///
+ /// Gets the page for the specified .
+ ///
+ /// Index to use
+ /// Page for the specified
+ private unsafe Span GetPage(int index)
+ {
+ var pageIndex = (int)((uint)(index & ~(_pageCapacity - 1)) >> _pageLogCapacity);
+
+ if (!_pages.TryGetValue(pageIndex, out IntPtr page))
+ {
+ page = Marshal.AllocHGlobal(sizeof(TEntry) * _pageCapacity);
+
+ _pages.Add(pageIndex, page);
+ }
+
+ return new Span((void*)page, _pageCapacity);
+ }
+
+ ///
+ /// Releases all resources used by the instance.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases all unmanaged and optionally managed resources used by the
+ /// instance.
+ ///
+ /// to dispose managed resources also; otherwise just unmanaged resouces
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ foreach (var page in _pages.Values)
+ {
+ Marshal.FreeHGlobal(page);
+ }
+
+ _disposed = true;
+ }
+ }
+
+ ///
+ /// Frees resources used by the instance.
+ ///
+ ~EntryTable()
+ {
+ Dispose(false);
}
}
}
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index 25d9dc583..55a0f4d06 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -579,12 +579,7 @@ namespace ARMeilleure.Translation.PTC
{
RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
- if (!PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter))
- {
- SkipUnwindInfo(unwindInfosReader);
-
- continue;
- }
+ PatchCode(code, relocEntries, memory.PageTablePointer, jumpTable, countTable, out callCounter);
}
UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
@@ -683,7 +678,7 @@ namespace ARMeilleure.Translation.PTC
return relocEntries;
}
- private static bool PatchCode(
+ private static void PatchCode(
Span code,
RelocEntry[] relocEntries,
IntPtr pageTablePointer,
@@ -711,13 +706,9 @@ namespace ARMeilleure.Translation.PTC
}
else if (relocEntry.Index == CountTableIndex)
{
- // If we could not allocate an entry on the count table we dip.
- if (!Counter.TryCreate(countTable, out Counter counter))
- {
- return false;
- }
+ callCounter = new Counter(countTable);
- unsafe { imm = (ulong)Unsafe.AsPointer(ref counter.Value); }
+ unsafe { imm = (ulong)Unsafe.AsPointer(ref callCounter.Value); }
}
else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr))
{
@@ -730,8 +721,6 @@ namespace ARMeilleure.Translation.PTC
BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm);
}
-
- return true;
}
private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
index a8635c545..c5ccb89df 100644
--- a/ARMeilleure/Translation/Translator.cs
+++ b/ARMeilleure/Translation/Translator.cs
@@ -57,7 +57,7 @@ namespace ARMeilleure.Translation
_backgroundTranslatorEvent = new AutoResetEvent(false);
_backgroundTranslatorLock = new ReaderWriterLock();
- CountTable = new EntryTable(CountTableCapacity);
+ CountTable = new EntryTable();
JitCache.Initialize(allocator);
@@ -174,6 +174,8 @@ namespace ARMeilleure.Translation
_jumpTable.Dispose();
_jumpTable = null;
+ CountTable.Dispose();
+
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
}
}
@@ -393,14 +395,11 @@ namespace ARMeilleure.Translation
return context.GetControlFlowGraph();
}
- internal static void EmitRejitCheck(ArmEmitterContext context, out Counter counter)
+ internal static Counter EmitRejitCheck(ArmEmitterContext context, out Counter counter)
{
const int MinsCallForRejit = 100;
- if (!Counter.TryCreate(context.CountTable, out counter))
- {
- return;
- }
+ counter = new Counter(context.CountTable);
Operand lblEnd = Label();
@@ -413,6 +412,8 @@ namespace ARMeilleure.Translation
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress));
context.MarkLabel(lblEnd);
+
+ return counter;
}
internal static void EmitSynchronization(EmitterContext context)