Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion DotNetTests/DotNetTests.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestConsoleApp1", "TestConsoleApp1\TestConsoleApp1.csproj", "{5D532D6A-6C85-43B9-A563-4438E61FAE9C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestConsoleApp1", "TestConsoleApp1\TestConsoleApp1.csproj", "{5D532D6A-6C85-43B9-A563-4438E61FAE9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CppSharpTest", "CppSharpTest\CppSharpTest.csproj", "{F35FBA80-045A-4E1B-84D9-1227EA741E93}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand All @@ -15,6 +17,10 @@ Global
{5D532D6A-6C85-43B9-A563-4438E61FAE9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D532D6A-6C85-43B9-A563-4438E61FAE9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D532D6A-6C85-43B9-A563-4438E61FAE9C}.Release|Any CPU.Build.0 = Release|Any CPU
{F35FBA80-045A-4E1B-84D9-1227EA741E93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F35FBA80-045A-4E1B-84D9-1227EA741E93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F35FBA80-045A-4E1B-84D9-1227EA741E93}.Release|Any CPU.ActiveCfg = Debug|Any CPU
{F35FBA80-045A-4E1B-84D9-1227EA741E93}.Release|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
32 changes: 32 additions & 0 deletions DotNetTests/TestConsoleApp1/BinaryTextConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace TestConsoleApp1
{
internal class BinaryTextConverter
{
public static int Main_(string[] args)
{
var input =
"11000010 10111111 01010001 01110101 01101001 11000011 10101001 01101110 01100101 01110011 00100000 01110011 01101111 01101101 01101111 01110011 00111111 00100000 11000010 10111111 01010001 01110101 11000011 10101001 00100000 01101000 01100001 01100011 01100101 01101101 01101111 01110011 00100000 01100001 01110001 01110101 11000011 10101101 00111111 00100000 01000001 01101100 01100111 01101111 00100000 01100101 01110011 01110100 11000011 10100001 00100000 01110011 01110101 01100011 01100101 01100100 01101001 01100101 01101110 01100100 01101111 00101100 00100000 01101110 01101111 00100000 01110011 01100001 01100010 01100101 01101101 01101111 01110011 00100000 01101101 01110101 01111001 00100000 01100010 01101001 01100101 01101110 00100000 01110001 01110101 11000011 10101001 00101100 00100000 01101110 01101001 00100000 01110000 01101111 01110010 00100000 01110001 01110101 11000011 10101001 00101100 00100000 01110000 01100101 01110010 01101111 00100000 01110011 11000011 10101101 00100000 01110001 01110101 01100101 00100000 01101100 01101111 00100000 01110011 01100001 01100010 01110010 01100101 01101101 01101111 01110011 00100000 01101101 01110101 01111001 00100000 01110000 01110010 01101111 01101110 01110100 01101111 00101110 00100000 01010101 01101110 01100001 00100000 01110000 01110010 01100101 01100111 01110101 01101110 01110100 01100001 00111010 00100000 11000010 10111111 01110001 01110101 11000011 10101001 00100000 01110011 01110101 01100011 01100101 01100100 01100101 00100000 01110011 01101001 00100000 01100101 01101110 01110100 01110010 01100001 01110011 00100000 01100001 00100000 01101100 01100001 00100000 01110000 11000011 10100001 01100111 01101001 01101110 01100001 00100000 01100100 01100101 00100000 01001101 01100001 01101110 01100110 01110010 01100101 01100100 00111111 01010011 01110100 01100001 01111001 00100000 01010100 01110101 01101110 01100101 01100100 00101100 00100000 01100011 01101111 01101101 01101111 00100000 01100100 01101001 01100011 01100101 01101110 00100000 01100101 01101100 01101100 01101111 01110011";

foreach(var part in input.Split(' '))
{
Console.Write(ConvertToChar(part));
}

string ConvertToChar(string s)
{
var hex = Convert.ToInt32(s, 2);
var c = (char)hex;
return c.ToString();
}

return 0;
}
}
}
234 changes: 234 additions & 0 deletions DotNetTests/TestConsoleApp1/FrozenSegments/Allocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;

#if NET8_0_OR_GREATER

#nullable enable
namespace TestConsoleApp1.FrozenSegments;

public unsafe class BumpPointerNativeAllocator : IDisposable
{
private readonly IntPtr _segment;
private readonly long _limit;

private bool _isDisposed;
private long _start;
private long _address;
private long _allocated;

List<WeakReference<string>> _externalRefs = new List<WeakReference<string>>();


public BumpPointerNativeAllocator(nint size)
{
_isDisposed = false;
_address = (IntPtr)NativeMemory.AlignedAlloc((nuint)size, 8);
_start = _address;
_segment = RegisterFrozenSegment((IntPtr)_address, size);

var segment = (Heap_segment*)_segment;
_allocated = _address;
segment->allocated = (nint)_allocated;

_limit = _address + size;
}

~BumpPointerNativeAllocator()
{
Dispose();
}

public void Dispose()
{
if (_isDisposed)
{
return;
}

_isDisposed = true;
GC.SuppressFinalize(this);
UnregisterFrozenSegment(_segment);
NativeMemory.AlignedFree((void*)_start);
_address = 0;
}

public long Available => _limit - _address;

public long Alive => _externalRefs.Count(x => x.TryGetTarget(out _));

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int SizeOf<T>()
{
var mt = typeof(T).TypeHandle.Value;
var methodTable = *(MethodTable*)mt;

return methodTable.BaseSize;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains(object? obj)
{
if(obj is null)
{
return false;
}

var ptr = *(nint*)&obj;
return _start <= ptr && ptr < _limit;
}

public T AllocateObject<T>() where T : class
{
var mt = typeof(T).TypeHandle.Value;
var methodTable = *(MethodTable*)mt;

var ptr = ReserveMemory(methodTable.BaseSize, true);

// Write the header
*ptr = 0;
ptr++;

// Write the mt
*ptr = mt;

return *(T*)&ptr;
}

public ref T AllocateStruct<T>() where T : struct
{
var mt = typeof(T).TypeHandle.Value;
var methodTable = *(MethodTable*)mt;

var ptr = ReserveMemory(methodTable.BaseSize, true);

return ref Unsafe.AsRef<T>(ptr);
}

public string AllocateString(ReadOnlySpan<char> data)
{
var mt = typeof(string).TypeHandle.Value;
var methodTable = *(MethodTable*)mt;

var size = methodTable.BaseSize + (data.Length + 1) * sizeof(char);

// Align up the size
size = (size + IntPtr.Size - 1) & ~(IntPtr.Size - 1);

var ptr = ReserveMemory(size, false);

// Write the header
*ptr = 0;
ptr++;

// Write the MT
*ptr = mt;

var dataPtr = (byte*)(ptr + 1);

// Write the length
*(int*)dataPtr = data.Length;

// Write the chars
var destination = new Span<char>(dataPtr + sizeof(int), data.Length + 1);

data.CopyTo(destination);
destination[^1] = '\0';

var res = *(string*)&ptr;

_externalRefs.Add(new WeakReference<string>(res));

return res;
}

public T[] AllocateArray<T>(int length, bool clear = false)
{
var arrayMt = typeof(T[]).TypeHandle.Value;
var arrayMethodTable = *(MethodTable*)arrayMt;

var arraySize = arrayMethodTable.BaseSize + length * arrayMethodTable.ComponentSize;

var ptr = ReserveMemory(arraySize, clear);

// Write the header
*ptr = 0;
ptr++;

// Write the MT
*ptr = arrayMt;

// Write the length
*(ptr + 1) = length;

return (T[])*(Array*)&ptr;
}

static ReflectionHelpers.FuncWrapper<IntPtr, IntPtr, IntPtr> _register = new ReflectionHelpers.FuncWrapper<IntPtr, IntPtr, IntPtr>("System.GC::_RegisterFrozenSegment(System.IntPtr,System.IntPtr)");
private static IntPtr RegisterFrozenSegment(IntPtr sectionAddress, nint sectionSize)
{
return (IntPtr)typeof(GC).GetMethod("_RegisterFrozenSegment", BindingFlags.NonPublic | BindingFlags.Static)!.Invoke(null, [sectionAddress, sectionSize])!;
}

static ReflectionHelpers.ActionWrapper<IntPtr> _unregister = new ReflectionHelpers.ActionWrapper<IntPtr>("System.GC::_UnregisterFrozenSegment(System.IntPtr)");
private static void UnregisterFrozenSegment(IntPtr segment)
{
typeof(GC).GetMethod("_UnregisterFrozenSegment", BindingFlags.NonPublic | BindingFlags.Static)!.Invoke(null, [segment]);
}

private nint* ReserveMemory(int size, bool clear)
{
ObjectDisposedException.ThrowIf(_address == 0, typeof(BumpPointerNativeAllocator));

if (_address + size > _limit)
{
throw new OutOfMemoryException();
}

var objectAddress = Interlocked.Add(ref _address, size);

if (objectAddress > _limit)
{
throw new OutOfMemoryException();
}

if (clear)
{
NativeMemory.Clear((void*)objectAddress, (nuint)size);
}

var segment = (Heap_segment*)_segment;
Interlocked.Add(ref _allocated, size);
segment->allocated = (nint)_allocated;


return (nint*)(objectAddress - size);
}


[StructLayout(LayoutKind.Sequential)]
public struct Heap_segment
{
public nint allocated;
public nint committed;
public nint reserved;
public nint used;
public nint mem;
}

[StructLayout(LayoutKind.Explicit)]
public struct MethodTable
{
[FieldOffset(0)]
public ushort ComponentSize;

[FieldOffset(4)]
public int BaseSize;
}
}

#endif
Loading