internal static class Stub { public static void Construct(object obj, int value) { } }
public class UnmanagedObject<T> : IDisposable where T : UnmanagedObject<T> { internal IUnmanagedHeap<T> heap; #region IDisposable implementation void IDisposable.Dispose() { heap.Free(this); } #endregion }
public unsafe class UnmanagedHeap<TPoolItem> : IUnmanagedHeap<TPoolItem> where TPoolItem : UnmanagedObject<TPoolItem> { private readonly IntPtr *_freeObjects; private readonly IntPtr *_allObjects; private readonly int _totalSize, _capacity; private int _freeSize; private readonly void *_startingPointer; private readonly ConstructorInfo _ctor; public UnmanagedHeap(int capacity) { _freeSize = capacity; // Getting type size and total pool size var objectSize = GCEx.SizeOf<TPoolItem>(); _capacity = capacity; _totalSize = objectSize * capacity + capacity * IntPtr.Size * 2; _startingPointer = Marshal.AllocHGlobal(_totalSize).ToPointer(); var mTable = (MethodTableInfo*)typeof(TPoolItem).TypeHandle.Value.ToInt32(); _freeObjects = (IntPtr*)_startingPointer; _allObjects = (IntPtr*)((long)_startingPointer + IntPtr.Size * capacity); _startingPointer = (void*)((long)_startingPointer + 2 * IntPtr.Size * capacity); var pFake = typeof(Stub).GetMethod("Construct", BindingFlags.Static|BindingFlags.Public); var pCtor = _ctor = typeof(TPoolItem).GetConstructor(new []{typeof(int)}); MethodUtil.ReplaceMethod(pCtor, pFake, skip: true); for(int i = 0; i < capacity; i++) { var handler = (IntPtr *)((long)_startingPointer + (objectSize * i)); handler[1] = (IntPtr)mTable; var obj = EntityPtr.ToInstance<object>((IntPtr)handler); var reference = (TPoolItem)obj; reference.heap = this; _allObjects[i] = (IntPtr)(handler + 1); } Reset(); } public int TotalSize { get { return _totalSize; } } public TPoolItem Allocate() { _freeSize--; var obj = _freeObjects[_freeSize]; Stub.Construct(obj, 123); return EntityPtr.ToInstanceWithOffset<TPoolItem>(obj); } public void Free(TPoolItem obj) { _freeObjects[_freeSize] = EntityPtr.ToPointerWithOffset(obj); _freeSize++; } public void Reset() { WinApi.memcpy((IntPtr)_freeObjects, (IntPtr)_allObjects, _capacity * IntPtr.Size); _freeSize = _capacity; } object IUnmanagedHeapBase.Allocate() { return this.Allocate(); } void IUnmanagedHeapBase.Free(object obj) { this.Free((TPoolItem)obj); } public void Dispose() { Marshal.FreeHGlobal((IntPtr)_freeObjects); } }
var pFake = typeof(Stub).GetMethod("Construct", BindingFlags.Static|BindingFlags.Public); var pCtor = _ctor = typeof(TPoolItem).GetConstructor(new []{typeof(int)}); MethodUtil.ReplaceMethod(pCtor, pFake, skip: true);
public TPoolItem Allocate() { _freeSize--; var obj = _freeObjects[_freeSize]; Stub.Construct(obj, 123); return EntityPtr.ToInstanceWithOffset<TPoolItem>(obj); }
namespace UnmanagedPoolSample { class Program { /// <summary> /// Now cannot call default .ctor /// </summary> private class Quote : UnmanagedObject<Quote> { public Quote(int urr) { Console.WriteLine("Hello from object .ctor"); } public int GetCurrent() { return 100; } } static void Main(string[] args) { using (var pool = new UnmanagedHeap<Quote>(1000)) { using (var quote = pool.Allocate()) { Console.WriteLine("quote: {0}", quote.GetCurrent()); } } Console.ReadKey(); } } }
Source: https://habr.com/ru/post/247433/
All Articles