diff --git a/src/compile/bhl_front.csproj b/src/compile/bhl_front.csproj
index 763593ae..8c25911a 100644
--- a/src/compile/bhl_front.csproj
+++ b/src/compile/bhl_front.csproj
@@ -25,5 +25,6 @@
+
diff --git a/src/vm/bhl_runtime.csproj b/src/vm/bhl_runtime.csproj
index 047201a9..a593866d 100644
--- a/src/vm/bhl_runtime.csproj
+++ b/src/vm/bhl_runtime.csproj
@@ -7,4 +7,8 @@
netstandard2.1
true
+
+
+
+
diff --git a/src/vm/coro.cs b/src/vm/coro.cs
index 82e40fa2..253339b1 100644
--- a/src/vm/coro.cs
+++ b/src/vm/coro.cs
@@ -22,7 +22,7 @@ public interface IInspectableCoroutine
public abstract class Coroutine : ICoroutine
{
- internal VM.Pool pool;
+ internal Pool pool;
public abstract void Tick(VM.Frame frm, VM.ExecState exec, ref BHS status);
public virtual void Cleanup(VM.Frame frm, VM.ExecState exec) {}
@@ -33,7 +33,7 @@ public class CoroutinePool
//TODO: add debug inspection for concrete types
static class PoolHolder where T : Coroutine
{
- //alternative implemenation
+ //TODO: alternative implemenation, check if it's simpler and faster?
//[ThreadStatic]
//static public VM.Pool _pool;
//static public VM.Pool pool {
@@ -44,10 +44,10 @@ static class PoolHolder where T : Coroutine
// }
//}
- public static System.Threading.ThreadLocal> pool =
- new System.Threading.ThreadLocal>(() =>
+ public static System.Threading.ThreadLocal> pool =
+ new System.Threading.ThreadLocal>(() =>
{
- return new VM.Pool();
+ return new Pool();
});
}
diff --git a/src/vm/extensions.cs b/src/vm/extensions.cs
index eafbd542..bac332d6 100644
--- a/src/vm/extensions.cs
+++ b/src/vm/extensions.cs
@@ -42,6 +42,32 @@ static public VM.Fiber Start(this VM vm, FuncSymbolScript fs, StackList arg
var addr = new VM.FuncAddr() { module = fs._module, fs = fs, ip = fs.ip_addr };
return vm.Start(addr, args.Count, args, opts);
}
+
+ static public void Alloc(this Pool pool, VM vm, int num)
+ {
+ for(int i=0;i pool)
+ {
+ string res = "=== Val POOL ===\n";
+ res += "busy:" + pool.BusyCount + " idle:" + pool.IdleCount + "\n";
+
+ var dvs = new Val[pool.stack.Count];
+ pool.stack.CopyTo(dvs, 0);
+ for(int i=dvs.Length;i-- > 0;)
+ {
+ var v = dvs[i];
+ res += v + " (refs:" + v._refs + ") " + v.GetHashCode() + "\n";
+ }
+
+ return res;
+ }
}
}
diff --git a/src/vm/util/blob.cs b/src/vm/util/blob.cs
new file mode 100644
index 00000000..0b8f662f
--- /dev/null
+++ b/src/vm/util/blob.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Buffers;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace bhl {
+
+public class Blob : IValRefcounted where T : unmanaged
+{
+ internal Pool> pool;
+
+ //NOTE: -1 means it's in released state,
+ // public only for quick inspection
+ internal int _refs;
+
+ public int refs => _refs;
+
+ internal byte[] data;
+
+ static int Size = Marshal.SizeOf();
+
+ static class PoolHolder where T1 : unmanaged
+ {
+ public static System.Threading.ThreadLocal>> pool =
+ new System.Threading.ThreadLocal>>(() =>
+ {
+ return new Pool>();
+ });
+ }
+
+ static public Blob New(ref T val)
+ {
+ var pool = PoolHolder.pool.Value;
+
+ Blob blob = null;
+ if(pool.stack.Count == 0)
+ {
+ ++pool.miss;
+ blob = new Blob();
+ }
+ else
+ {
+ ++pool.hits;
+ blob = pool.stack.Pop();
+ }
+
+ var data = ArrayPool.Shared.Rent(Size);
+
+ ref var valRef = ref Unsafe.As(ref data[0]);
+ valRef = val;
+
+ blob._refs = 1;
+ blob.data = data;
+ blob.pool = pool;
+
+ return blob;
+ }
+
+ public ref T Value => ref Unsafe.As(ref data[0]);
+
+ public void Retain()
+ {
+ if(_refs == -1)
+ throw new Exception("Invalid state(-1)");
+ ++_refs;
+ }
+
+ public void Release()
+ {
+ if(_refs == -1)
+ throw new Exception("Invalid state(-1)");
+ if(_refs == 0)
+ throw new Exception("Double free(0)");
+
+ --_refs;
+ if(_refs == 0)
+ Del(this);
+ }
+
+ static void Del(Blob blob)
+ {
+ if(blob._refs != 0)
+ throw new Exception("Freeing invalid object, refs " + blob._refs);
+
+ blob._refs = -1;
+ ArrayPool.Shared.Return(blob.data);
+
+ blob.pool.stack.Push(blob);
+ }
+}
+
+}
diff --git a/src/vm/util/pool.cs b/src/vm/util/pool.cs
new file mode 100644
index 00000000..a97b4420
--- /dev/null
+++ b/src/vm/util/pool.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+namespace bhl {
+
+ public class Pool where T : class
+ {
+ internal Stack stack = new Stack();
+ internal int hits;
+ internal int miss;
+
+ public int HitCount {
+ get { return hits; }
+ }
+
+ public int MissCount {
+ get { return miss; }
+ }
+
+ public int IdleCount {
+ get { return stack.Count; }
+ }
+
+ public int BusyCount {
+ get { return miss - IdleCount; }
+ }
+}
+
+}
diff --git a/src/vm/util/refc_list.cs b/src/vm/util/refc_list.cs
index be38fee9..fe46af18 100644
--- a/src/vm/util/refc_list.cs
+++ b/src/vm/util/refc_list.cs
@@ -3,9 +3,9 @@
namespace bhl {
- public class RefcList : List, IValRefcounted, IDisposable
- {
- internal VM.Pool> pool;
+public class RefcList : List, IValRefcounted, IDisposable
+{
+ internal Pool> pool;
//NOTE: -1 means it's in released state,
// public only for quick inspection
@@ -15,10 +15,10 @@ public class RefcList : List, IValRefcounted, IDisposable
static class PoolHolder
{
- public static System.Threading.ThreadLocal>> pool =
- new System.Threading.ThreadLocal>>(() =>
+ public static System.Threading.ThreadLocal>> pool =
+ new System.Threading.ThreadLocal>>(() =>
{
- return new VM.Pool>();
+ return new Pool>();
});
}
diff --git a/src/vm/util/val_list_adapter.cs b/src/vm/util/val_list_adapter.cs
index b6007b64..c76b21c2 100644
--- a/src/vm/util/val_list_adapter.cs
+++ b/src/vm/util/val_list_adapter.cs
@@ -8,7 +8,7 @@ namespace bhl {
//TODO: writing is not implemented
public class ValList : IList, IValRefcounted, IDisposable
{
- internal VM.Pool> pool;
+ internal Pool> pool;
Func val2native;
@@ -26,10 +26,10 @@ public class ValList : IList, IValRefcounted, IDisposable
static class PoolHolder
{
- public static System.Threading.ThreadLocal>> pool =
- new System.Threading.ThreadLocal>>(() =>
+ public static System.Threading.ThreadLocal>> pool =
+ new System.Threading.ThreadLocal>>(() =>
{
- return new VM.Pool>();
+ return new Pool>();
});
}
diff --git a/src/vm/vm.pool.cs b/src/vm/vm.pool.cs
index cfafbefa..0d5fcd6a 100644
--- a/src/vm/vm.pool.cs
+++ b/src/vm/vm.pool.cs
@@ -1,62 +1,9 @@
-using System.Collections.Generic;
namespace bhl {
public partial class VM : INamedResolver
{
- public class Pool where T : class
- {
- internal Stack stack = new Stack();
- internal int hits;
- internal int miss;
-
- public int HitCount {
- get { return hits; }
- }
-
- public int MissCount {
- get { return miss; }
- }
-
- public int IdleCount {
- get { return stack.Count; }
- }
-
- public int BusyCount {
- get { return miss - IdleCount; }
- }
- }
-
- public class ValPool : Pool
- {
- public void Alloc(VM vm, int num)
- {
- for(int i=0;i 0;)
- {
- var v = dvs[i];
- res += v + " (refs:" + v._refs + ") " + v.GetHashCode() + "\n";
- }
-
- return res;
- }
- }
-
- public ValPool vals_pool = new ValPool();
+ public Pool vals_pool = new Pool();
public Pool vlsts_pool = new Pool();
public Pool vmaps_pool = new Pool();
public Pool frames_pool = new Pool();
diff --git a/tests/test_blobs.cs b/tests/test_blobs.cs
new file mode 100644
index 00000000..105af191
--- /dev/null
+++ b/tests/test_blobs.cs
@@ -0,0 +1,32 @@
+using bhl;
+using Xunit;
+
+public class TestBlobs : BHL_TestBase
+{
+ public struct StructBlob
+ {
+ public int x;
+ public int y;
+ public int z;
+ }
+
+ [Fact]
+ public void TestBlob()
+ {
+ var val = new StructBlob();
+ val.x = 1;
+ val.y = 10;
+ val.z = 100;
+
+ var blob = Blob.New(ref val);
+
+ AssertEqual(1, blob.Value.x);
+ AssertEqual(10, blob.Value.y);
+ AssertEqual(100, blob.Value.z);
+
+ blob.Value.y = 30;
+ AssertEqual(30, blob.Value.y);
+
+ blob.Release();
+ }
+}